refactor: auto count the split number for x axis

This commit is contained in:
vicanso 2022-02-06 09:55:27 +08:00
parent 3219ce521b
commit c01f4001f1
6 changed files with 134 additions and 58 deletions

76
axis.go
View file

@ -23,15 +23,18 @@
package charts package charts
import ( import (
"math"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
"github.com/wcharczuk/go-chart/v2" "github.com/wcharczuk/go-chart/v2"
"github.com/wcharczuk/go-chart/v2/drawing" "github.com/wcharczuk/go-chart/v2/drawing"
) )
type AxisStyle struct { type AxisOption struct {
BoundaryGap *bool BoundaryGap *bool
Show *bool Show *bool
Position string Position string
SplitNumber int
ClassName string ClassName string
StrokeColor drawing.Color StrokeColor drawing.Color
StrokeWidth float64 StrokeWidth float64
@ -48,10 +51,10 @@ type AxisStyle struct {
type axis struct { type axis struct {
d *Draw d *Draw
data *AxisDataList data *AxisDataList
style *AxisStyle style *AxisOption
} }
func NewAxis(d *Draw, data AxisDataList, style AxisStyle) *axis { func NewAxis(d *Draw, data AxisDataList, style AxisOption) *axis {
return &axis{ return &axis{
d: d, d: d,
data: &data, data: &data,
@ -60,15 +63,15 @@ func NewAxis(d *Draw, data AxisDataList, style AxisStyle) *axis {
} }
func (as *AxisStyle) GetLabelMargin() int { func (as *AxisOption) GetLabelMargin() int {
return getDefaultInt(as.LabelMargin, 8) return getDefaultInt(as.LabelMargin, 8)
} }
func (as *AxisStyle) GetTickLength() int { func (as *AxisOption) GetTickLength() int {
return getDefaultInt(as.TickLength, 5) return getDefaultInt(as.TickLength, 5)
} }
func (as *AxisStyle) Style(f *truetype.Font) chart.Style { func (as *AxisOption) Style(f *truetype.Font) chart.Style {
s := chart.Style{ s := chart.Style{
ClassName: as.ClassName, ClassName: as.ClassName,
StrokeColor: as.StrokeColor, StrokeColor: as.StrokeColor,
@ -99,10 +102,12 @@ func (l AxisDataList) TextList() []string {
return textList return textList
} }
type axisOption struct { type axisRenderOption struct {
textMaxWith int textMaxWith int
textMaxHeight int textMaxHeight int
boundaryGap bool boundaryGap bool
unitCount int
modValue int
} }
func NewAxisDataListFromStringList(textList []string) AxisDataList { func NewAxisDataListFromStringList(textList []string) AxisDataList {
@ -115,7 +120,7 @@ func NewAxisDataListFromStringList(textList []string) AxisDataList {
return list return list
} }
func (a *axis) axisLabel(opt *axisOption) { func (a *axis) axisLabel(opt *axisRenderOption) {
style := a.style style := a.style
data := *a.data data := *a.data
d := a.d d := a.d
@ -131,11 +136,14 @@ func (a *axis) axisLabel(opt *axisOption) {
height := d.Box.Height() height := d.Box.Height()
textList := data.TextList() textList := data.TextList()
count := len(textList) count := len(textList)
boundaryGap := opt.boundaryGap boundaryGap := opt.boundaryGap
if !boundaryGap { if !boundaryGap {
count-- count--
} }
unitCount := opt.unitCount
modValue := opt.modValue
labelMargin := style.GetLabelMargin() labelMargin := style.GetLabelMargin()
// 轴线 // 轴线
@ -176,6 +184,9 @@ func (a *axis) axisLabel(opt *axisOption) {
} }
values := autoDivide(width, count) values := autoDivide(width, count)
for index, text := range data.TextList() { for index, text := range data.TextList() {
if unitCount != 0 && index%unitCount != modValue {
continue
}
x := values[index] x := values[index]
leftOffset := 0 leftOffset := 0
b := r.MeasureText(text) b := r.MeasureText(text)
@ -191,7 +202,7 @@ func (a *axis) axisLabel(opt *axisOption) {
} }
} }
func (a *axis) axisLine(opt *axisOption) { func (a *axis) axisLine(opt *axisRenderOption) {
d := a.d d := a.d
r := d.Render r := d.Render
style := a.style style := a.style
@ -239,7 +250,7 @@ func (a *axis) axisLine(opt *axisOption) {
r.FillStroke() r.FillStroke()
} }
func (a *axis) axisTick(opt *axisOption) { func (a *axis) axisTick(opt *axisRenderOption) {
d := a.d d := a.d
r := d.Render r := d.Render
@ -259,6 +270,7 @@ func (a *axis) axisTick(opt *axisOption) {
if isFalse(style.TickShow) { if isFalse(style.TickShow) {
tickShow = false tickShow = false
} }
unitCount := opt.unitCount
tickLengthValue := style.GetTickLength() tickLengthValue := style.GetTickLength()
labelHeight := labelMargin + opt.textMaxHeight labelHeight := labelMargin + opt.textMaxHeight
@ -308,7 +320,10 @@ func (a *axis) axisTick(opt *axisOption) {
y0 = labelHeight y0 = labelHeight
} }
if tickShow { if tickShow {
for _, v := range values { for index, v := range values {
if index%unitCount != 0 {
continue
}
x := v x := v
y := y0 y := y0
d.moveTo(x, y-tickLengthValue) d.moveTo(x, y-tickLengthValue)
@ -326,7 +341,10 @@ func (a *axis) axisTick(opt *axisOption) {
splitLineHeight = height - labelHeight splitLineHeight = height - labelHeight
} }
for _, v := range values { for index, v := range values {
if index%unitCount != 0 {
continue
}
x := v x := v
y := y0 y := y0
@ -368,7 +386,7 @@ func (a *axis) Render() {
return return
} }
textMaxWidth, textMaxHeight := a.axisMeasureTextMaxWidthHeight() textMaxWidth, textMaxHeight := a.axisMeasureTextMaxWidthHeight()
opt := &axisOption{ opt := &axisRenderOption{
textMaxWith: textMaxWidth, textMaxWith: textMaxWidth,
textMaxHeight: textMaxHeight, textMaxHeight: textMaxHeight,
boundaryGap: true, boundaryGap: true,
@ -377,6 +395,38 @@ func (a *axis) Render() {
opt.boundaryGap = false opt.boundaryGap = false
} }
unitCount := chart.MaxInt(style.SplitNumber, 1)
width := a.d.Box.Width()
textList := a.data.TextList()
count := len(textList)
position := style.Position
switch position {
case PositionLeft:
fallthrough
case PositionRight:
default:
maxCount := width / (opt.textMaxWith + 10)
// 可以显示所有
if maxCount >= count {
unitCount = 1
} else if maxCount < count/unitCount {
unitCount = int(math.Ceil(float64(count) / float64(maxCount)))
}
}
boundaryGap := opt.boundaryGap
modValue := 0
if boundaryGap && unitCount > 1 {
// 如果是居中unit count需要设置为奇数
if unitCount%2 == 0 {
unitCount++
}
modValue = unitCount / 2
}
opt.modValue = modValue
opt.unitCount = unitCount
// 坐标轴线 // 坐标轴线
a.axisLine(opt) a.axisLine(opt)
a.axisTick(opt) a.axisTick(opt)

View file

@ -31,10 +31,10 @@ import (
"github.com/wcharczuk/go-chart/v2/drawing" "github.com/wcharczuk/go-chart/v2/drawing"
) )
func TestAxisStyle(t *testing.T) { func TestAxisOption(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
as := AxisStyle{} as := AxisOption{}
assert.Equal(8, as.GetLabelMargin()) assert.Equal(8, as.GetLabelMargin())
as.LabelMargin = 10 as.LabelMargin = 10
@ -64,7 +64,7 @@ func TestAxisDataList(t *testing.T) {
func TestAxis(t *testing.T) { func TestAxis(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
data := NewAxisDataListFromStringList([]string{ axisData := NewAxisDataListFromStringList([]string{
"Mon", "Mon",
"Tue", "Tue",
"Wed", "Wed",
@ -73,8 +73,8 @@ func TestAxis(t *testing.T) {
"Sat", "Sat",
"Sun", "Sun",
}) })
getDefaultStyle := func() AxisStyle { getDefaultOption := func() AxisOption {
return AxisStyle{ return AxisOption{
StrokeColor: drawing.ColorBlack, StrokeColor: drawing.ColorBlack,
StrokeWidth: 1, StrokeWidth: 1,
FontColor: drawing.ColorBlack, FontColor: drawing.ColorBlack,
@ -85,14 +85,15 @@ func TestAxis(t *testing.T) {
} }
} }
tests := []struct { tests := []struct {
newStyle func() AxisStyle newOption func() AxisOption
result string newData func() AxisDataList
result string
}{ }{
// 文本按起始位置展示 // 文本按起始位置展示
// axis位于bottom // axis位于bottom
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.BoundaryGap = FalseFlag() opt.BoundaryGap = FalseFlag()
return opt return opt
}, },
@ -101,8 +102,8 @@ func TestAxis(t *testing.T) {
// 文本居中展示 // 文本居中展示
// axis位于bottom // axis位于bottom
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
return opt return opt
}, },
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"400\" height=\"300\">\\n<path d=\"M 5 270\nL 395 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 270\nL 5 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 61 270\nL 61 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 117 270\nL 117 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 173 270\nL 173 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 229 270\nL 229 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 285 270\nL 285 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 340 270\nL 340 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 395 270\nL 395 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 5\nL 5 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 61 5\nL 61 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 117 5\nL 117 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 173 5\nL 173 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 229 5\nL 229 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 285 5\nL 285 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 340 5\nL 340 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 395 5\nL 395 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><text x=\"20\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Mon</text><text x=\"78\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Tue</text><text x=\"132\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Wed</text><text x=\"190\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Thu</text><text x=\"249\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Fri</text><text x=\"303\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sat</text><text x=\"356\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sun</text></svg>", result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"400\" height=\"300\">\\n<path d=\"M 5 270\nL 395 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 270\nL 5 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 61 270\nL 61 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 117 270\nL 117 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 173 270\nL 173 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 229 270\nL 229 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 285 270\nL 285 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 340 270\nL 340 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 395 270\nL 395 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 5\nL 5 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 61 5\nL 61 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 117 5\nL 117 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 173 5\nL 173 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 229 5\nL 229 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 285 5\nL 285 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 340 5\nL 340 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 395 5\nL 395 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><text x=\"20\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Mon</text><text x=\"78\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Tue</text><text x=\"132\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Wed</text><text x=\"190\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Thu</text><text x=\"249\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Fri</text><text x=\"303\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sat</text><text x=\"356\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sun</text></svg>",
@ -110,8 +111,8 @@ func TestAxis(t *testing.T) {
// 文本按起始位置展示 // 文本按起始位置展示
// axis位于top // axis位于top
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.Position = PositionTop opt.Position = PositionTop
opt.BoundaryGap = FalseFlag() opt.BoundaryGap = FalseFlag()
return opt return opt
@ -121,8 +122,8 @@ func TestAxis(t *testing.T) {
// 文本居中展示 // 文本居中展示
// axis位于top // axis位于top
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.Position = PositionTop opt.Position = PositionTop
return opt return opt
}, },
@ -131,8 +132,8 @@ func TestAxis(t *testing.T) {
// 文本按起始位置展示 // 文本按起始位置展示
// axis位于left // axis位于left
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.Position = PositionLeft opt.Position = PositionLeft
opt.BoundaryGap = FalseFlag() opt.BoundaryGap = FalseFlag()
return opt return opt
@ -142,8 +143,8 @@ func TestAxis(t *testing.T) {
// 文本居中展示 // 文本居中展示
// axis位于left // axis位于left
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.Position = PositionLeft opt.Position = PositionLeft
return opt return opt
}, },
@ -152,8 +153,8 @@ func TestAxis(t *testing.T) {
// 文本按起始位置展示 // 文本按起始位置展示
// axis位于right // axis位于right
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.Position = PositionRight opt.Position = PositionRight
opt.BoundaryGap = FalseFlag() opt.BoundaryGap = FalseFlag()
return opt return opt
@ -163,13 +164,47 @@ func TestAxis(t *testing.T) {
// 文本居中展示 // 文本居中展示
// axis位于right // axis位于right
{ {
newStyle: func() AxisStyle { newOption: func() AxisOption {
opt := getDefaultStyle() opt := getDefaultOption()
opt.Position = PositionRight opt.Position = PositionRight
return opt return opt
}, },
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"400\" height=\"300\">\\n<path d=\"M 361 5\nL 361 295\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 5\nL 366 5\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 47\nL 366 47\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 89\nL 366 89\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 131\nL 366 131\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 172\nL 366 172\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 213\nL 366 213\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 254\nL 366 254\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 295\nL 366 295\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 5\nL 360 5\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 47\nL 360 47\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 89\nL 360 89\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 131\nL 360 131\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 172\nL 360 172\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 213\nL 360 213\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 254\nL 360 254\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><text x=\"369\" y=\"280\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Mon</text><text x=\"369\" y=\"239\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Tue</text><text x=\"369\" y=\"198\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Wed</text><text x=\"369\" y=\"157\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Thu</text><text x=\"369\" y=\"115\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Fri</text><text x=\"369\" y=\"73\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sat</text><text x=\"369\" y=\"31\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sun</text></svg>", result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"400\" height=\"300\">\\n<path d=\"M 361 5\nL 361 295\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 5\nL 366 5\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 47\nL 366 47\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 89\nL 366 89\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 131\nL 366 131\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 172\nL 366 172\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 213\nL 366 213\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 254\nL 366 254\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 361 295\nL 366 295\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 5\nL 360 5\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 47\nL 360 47\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 89\nL 360 89\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 131\nL 360 131\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 172\nL 360 172\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 213\nL 360 213\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 5 254\nL 360 254\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><text x=\"369\" y=\"280\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Mon</text><text x=\"369\" y=\"239\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Tue</text><text x=\"369\" y=\"198\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Wed</text><text x=\"369\" y=\"157\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Thu</text><text x=\"369\" y=\"115\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Fri</text><text x=\"369\" y=\"73\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sat</text><text x=\"369\" y=\"31\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">Sun</text></svg>",
}, },
// text较多仅展示部分
{
newOption: func() AxisOption {
opt := getDefaultOption()
opt.Position = PositionBottom
return opt
},
newData: func() AxisDataList {
return NewAxisDataListFromStringList([]string{
"01-01",
"01-02",
"01-03",
"01-04",
"01-05",
"01-06",
"01-07",
"01-08",
"01-09",
"01-10",
"01-11",
"01-12",
"01-13",
"01-14",
"01-15",
"01-16",
"01-17",
"01-18",
"01-19",
"01-20",
"01-21",
})
},
result: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"400\" height=\"300\">\\n<path d=\"M 5 270\nL 395 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 270\nL 5 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 62 270\nL 62 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 119 270\nL 119 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 176 270\nL 176 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 233 270\nL 233 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 287 270\nL 287 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 341 270\nL 341 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 395 270\nL 395 275\" style=\"stroke-width:1;stroke:rgba(0,0,0,1.0);fill:none\"/><path d=\"M 5 5\nL 5 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 62 5\nL 62 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 119 5\nL 119 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 176 5\nL 176 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 233 5\nL 233 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 287 5\nL 287 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 341 5\nL 341 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><path d=\"M 395 5\nL 395 270\" style=\"stroke-width:1;stroke:rgba(0,0,0,0.2);fill:none\"/><text x=\"16\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-02</text><text x=\"73\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-05</text><text x=\"130\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-08</text><text x=\"187\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-11</text><text x=\"243\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-14</text><text x=\"297\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-17</text><text x=\"351\" y=\"287\" style=\"stroke-width:0;stroke:none;fill:rgba(0,0,0,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">01-20</text></svg>",
},
} }
for _, tt := range tests { for _, tt := range tests {
d, err := NewDraw(DrawOption{ d, err := NewDraw(DrawOption{
@ -182,7 +217,11 @@ func TestAxis(t *testing.T) {
Bottom: 5, Bottom: 5,
})) }))
assert.Nil(err) assert.Nil(err)
style := tt.newStyle() style := tt.newOption()
data := axisData
if tt.newData != nil {
data = tt.newData()
}
NewAxis(d, data, style).Render() NewAxis(d, data, style).Render()
result, err := d.Bytes() result, err := d.Bytes()
@ -204,14 +243,14 @@ func TestMeasureAxis(t *testing.T) {
"Sun", "Sun",
}) })
f, _ := chart.GetDefaultFont() f, _ := chart.GetDefaultFont()
width := NewAxis(d, data, AxisStyle{ width := NewAxis(d, data, AxisOption{
FontSize: 12, FontSize: 12,
Font: f, Font: f,
Position: PositionLeft, Position: PositionLeft,
}).measureAxis() }).measureAxis()
assert.Equal(44, width) assert.Equal(44, width)
height := NewAxis(d, data, AxisStyle{ height := NewAxis(d, data, AxisOption{
FontSize: 12, FontSize: 12,
Font: f, Font: f,
Position: PositionTop, Position: PositionTop,

13
util.go
View file

@ -62,15 +62,6 @@ func autoDivide(max, size int) []int {
values[size] = max values[size] = max
return values return values
} }
func maxInt(values ...int) int {
result := 0
for _, v := range values {
if v > result {
result = v
}
}
return result
}
// measureTextMaxWidthHeight returns maxWidth and maxHeight of text list // measureTextMaxWidthHeight returns maxWidth and maxHeight of text list
func measureTextMaxWidthHeight(textList []string, r chart.Renderer) (int, int) { func measureTextMaxWidthHeight(textList []string, r chart.Renderer) (int, int) {
@ -78,8 +69,8 @@ func measureTextMaxWidthHeight(textList []string, r chart.Renderer) (int, int) {
maxHeight := 0 maxHeight := 0
for _, text := range textList { for _, text := range textList {
box := r.MeasureText(text) box := r.MeasureText(text)
maxWidth = maxInt(maxWidth, box.Width()) maxWidth = chart.MaxInt(maxWidth, box.Width())
maxHeight = maxInt(maxHeight, box.Height()) maxHeight = chart.MaxInt(maxHeight, box.Height())
} }
return maxWidth, maxHeight return maxWidth, maxHeight
} }

View file

@ -51,12 +51,6 @@ func TestAutoDivide(t *testing.T) {
}, autoDivide(600, 7)) }, autoDivide(600, 7))
} }
func TestMaxInt(t *testing.T) {
assert := assert.New(t)
assert.Equal(5, maxInt(1, 3, 5, 2))
}
func TestMeasureTextMaxWidthHeight(t *testing.T) { func TestMeasureTextMaxWidthHeight(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
r, err := chart.SVG(400, 300) r, err := chart.SVG(400, 300)

View file

@ -29,6 +29,7 @@ type XAxisOption struct {
Data []string Data []string
Theme string Theme string
Hidden bool Hidden bool
SplitNumber int
// TODO split number // TODO split number
} }
@ -47,11 +48,12 @@ func drawXAxis(p *Draw, opt *XAxisOption) (int, *Range, error) {
} }
theme := NewTheme(opt.Theme) theme := NewTheme(opt.Theme)
data := NewAxisDataListFromStringList(opt.Data) data := NewAxisDataListFromStringList(opt.Data)
style := AxisStyle{ style := AxisOption{
BoundaryGap: opt.BoundaryGap, BoundaryGap: opt.BoundaryGap,
StrokeColor: theme.GetAxisStrokeColor(), StrokeColor: theme.GetAxisStrokeColor(),
FontColor: theme.GetAxisStrokeColor(), FontColor: theme.GetAxisStrokeColor(),
StrokeWidth: 1, StrokeWidth: 1,
SplitNumber: opt.SplitNumber,
} }
boundary := true boundary := true

View file

@ -38,7 +38,7 @@ func drawYAxis(p *Draw, opt *ChartOption, xAxisHeight int, padding chart.Box) (*
theme := NewTheme(opt.Theme) theme := NewTheme(opt.Theme)
yRange := opt.getYRange(0) yRange := opt.getYRange(0)
data := NewAxisDataListFromStringList(yRange.Values()) data := NewAxisDataListFromStringList(yRange.Values())
style := AxisStyle{ style := AxisOption{
Position: PositionLeft, Position: PositionLeft,
BoundaryGap: FalseFlag(), BoundaryGap: FalseFlag(),
FontColor: theme.GetAxisStrokeColor(), FontColor: theme.GetAxisStrokeColor(),