diff --git a/axis.go b/axis.go
index ba0604e..eb0327f 100644
--- a/axis.go
+++ b/axis.go
@@ -23,15 +23,18 @@
package charts
import (
+ "math"
+
"github.com/golang/freetype/truetype"
"github.com/wcharczuk/go-chart/v2"
"github.com/wcharczuk/go-chart/v2/drawing"
)
-type AxisStyle struct {
+type AxisOption struct {
BoundaryGap *bool
Show *bool
Position string
+ SplitNumber int
ClassName string
StrokeColor drawing.Color
StrokeWidth float64
@@ -48,10 +51,10 @@ type AxisStyle struct {
type axis struct {
d *Draw
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{
d: d,
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)
}
-func (as *AxisStyle) GetTickLength() int {
+func (as *AxisOption) GetTickLength() int {
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{
ClassName: as.ClassName,
StrokeColor: as.StrokeColor,
@@ -99,10 +102,12 @@ func (l AxisDataList) TextList() []string {
return textList
}
-type axisOption struct {
+type axisRenderOption struct {
textMaxWith int
textMaxHeight int
boundaryGap bool
+ unitCount int
+ modValue int
}
func NewAxisDataListFromStringList(textList []string) AxisDataList {
@@ -115,7 +120,7 @@ func NewAxisDataListFromStringList(textList []string) AxisDataList {
return list
}
-func (a *axis) axisLabel(opt *axisOption) {
+func (a *axis) axisLabel(opt *axisRenderOption) {
style := a.style
data := *a.data
d := a.d
@@ -131,11 +136,14 @@ func (a *axis) axisLabel(opt *axisOption) {
height := d.Box.Height()
textList := data.TextList()
count := len(textList)
+
boundaryGap := opt.boundaryGap
if !boundaryGap {
count--
}
+ unitCount := opt.unitCount
+ modValue := opt.modValue
labelMargin := style.GetLabelMargin()
// 轴线
@@ -176,6 +184,9 @@ func (a *axis) axisLabel(opt *axisOption) {
}
values := autoDivide(width, count)
for index, text := range data.TextList() {
+ if unitCount != 0 && index%unitCount != modValue {
+ continue
+ }
x := values[index]
leftOffset := 0
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
r := d.Render
style := a.style
@@ -239,7 +250,7 @@ func (a *axis) axisLine(opt *axisOption) {
r.FillStroke()
}
-func (a *axis) axisTick(opt *axisOption) {
+func (a *axis) axisTick(opt *axisRenderOption) {
d := a.d
r := d.Render
@@ -259,6 +270,7 @@ func (a *axis) axisTick(opt *axisOption) {
if isFalse(style.TickShow) {
tickShow = false
}
+ unitCount := opt.unitCount
tickLengthValue := style.GetTickLength()
labelHeight := labelMargin + opt.textMaxHeight
@@ -308,7 +320,10 @@ func (a *axis) axisTick(opt *axisOption) {
y0 = labelHeight
}
if tickShow {
- for _, v := range values {
+ for index, v := range values {
+ if index%unitCount != 0 {
+ continue
+ }
x := v
y := y0
d.moveTo(x, y-tickLengthValue)
@@ -326,7 +341,10 @@ func (a *axis) axisTick(opt *axisOption) {
splitLineHeight = height - labelHeight
}
- for _, v := range values {
+ for index, v := range values {
+ if index%unitCount != 0 {
+ continue
+ }
x := v
y := y0
@@ -368,7 +386,7 @@ func (a *axis) Render() {
return
}
textMaxWidth, textMaxHeight := a.axisMeasureTextMaxWidthHeight()
- opt := &axisOption{
+ opt := &axisRenderOption{
textMaxWith: textMaxWidth,
textMaxHeight: textMaxHeight,
boundaryGap: true,
@@ -377,6 +395,38 @@ func (a *axis) Render() {
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.axisTick(opt)
diff --git a/axis_test.go b/axis_test.go
index e8efccd..a6a7690 100644
--- a/axis_test.go
+++ b/axis_test.go
@@ -31,10 +31,10 @@ import (
"github.com/wcharczuk/go-chart/v2/drawing"
)
-func TestAxisStyle(t *testing.T) {
+func TestAxisOption(t *testing.T) {
assert := assert.New(t)
- as := AxisStyle{}
+ as := AxisOption{}
assert.Equal(8, as.GetLabelMargin())
as.LabelMargin = 10
@@ -64,7 +64,7 @@ func TestAxisDataList(t *testing.T) {
func TestAxis(t *testing.T) {
assert := assert.New(t)
- data := NewAxisDataListFromStringList([]string{
+ axisData := NewAxisDataListFromStringList([]string{
"Mon",
"Tue",
"Wed",
@@ -73,8 +73,8 @@ func TestAxis(t *testing.T) {
"Sat",
"Sun",
})
- getDefaultStyle := func() AxisStyle {
- return AxisStyle{
+ getDefaultOption := func() AxisOption {
+ return AxisOption{
StrokeColor: drawing.ColorBlack,
StrokeWidth: 1,
FontColor: drawing.ColorBlack,
@@ -85,14 +85,15 @@ func TestAxis(t *testing.T) {
}
}
tests := []struct {
- newStyle func() AxisStyle
- result string
+ newOption func() AxisOption
+ newData func() AxisDataList
+ result string
}{
// 文本按起始位置展示
// axis位于bottom
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.BoundaryGap = FalseFlag()
return opt
},
@@ -101,8 +102,8 @@ func TestAxis(t *testing.T) {
// 文本居中展示
// axis位于bottom
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
return opt
},
result: "",
@@ -110,8 +111,8 @@ func TestAxis(t *testing.T) {
// 文本按起始位置展示
// axis位于top
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.Position = PositionTop
opt.BoundaryGap = FalseFlag()
return opt
@@ -121,8 +122,8 @@ func TestAxis(t *testing.T) {
// 文本居中展示
// axis位于top
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.Position = PositionTop
return opt
},
@@ -131,8 +132,8 @@ func TestAxis(t *testing.T) {
// 文本按起始位置展示
// axis位于left
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.Position = PositionLeft
opt.BoundaryGap = FalseFlag()
return opt
@@ -142,8 +143,8 @@ func TestAxis(t *testing.T) {
// 文本居中展示
// axis位于left
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.Position = PositionLeft
return opt
},
@@ -152,8 +153,8 @@ func TestAxis(t *testing.T) {
// 文本按起始位置展示
// axis位于right
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.Position = PositionRight
opt.BoundaryGap = FalseFlag()
return opt
@@ -163,13 +164,47 @@ func TestAxis(t *testing.T) {
// 文本居中展示
// axis位于right
{
- newStyle: func() AxisStyle {
- opt := getDefaultStyle()
+ newOption: func() AxisOption {
+ opt := getDefaultOption()
opt.Position = PositionRight
return opt
},
result: "",
},
+ // 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: "",
+ },
}
for _, tt := range tests {
d, err := NewDraw(DrawOption{
@@ -182,7 +217,11 @@ func TestAxis(t *testing.T) {
Bottom: 5,
}))
assert.Nil(err)
- style := tt.newStyle()
+ style := tt.newOption()
+ data := axisData
+ if tt.newData != nil {
+ data = tt.newData()
+ }
NewAxis(d, data, style).Render()
result, err := d.Bytes()
@@ -204,14 +243,14 @@ func TestMeasureAxis(t *testing.T) {
"Sun",
})
f, _ := chart.GetDefaultFont()
- width := NewAxis(d, data, AxisStyle{
+ width := NewAxis(d, data, AxisOption{
FontSize: 12,
Font: f,
Position: PositionLeft,
}).measureAxis()
assert.Equal(44, width)
- height := NewAxis(d, data, AxisStyle{
+ height := NewAxis(d, data, AxisOption{
FontSize: 12,
Font: f,
Position: PositionTop,
diff --git a/util.go b/util.go
index c9c817f..10fcb18 100644
--- a/util.go
+++ b/util.go
@@ -62,15 +62,6 @@ func autoDivide(max, size int) []int {
values[size] = max
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
func measureTextMaxWidthHeight(textList []string, r chart.Renderer) (int, int) {
@@ -78,8 +69,8 @@ func measureTextMaxWidthHeight(textList []string, r chart.Renderer) (int, int) {
maxHeight := 0
for _, text := range textList {
box := r.MeasureText(text)
- maxWidth = maxInt(maxWidth, box.Width())
- maxHeight = maxInt(maxHeight, box.Height())
+ maxWidth = chart.MaxInt(maxWidth, box.Width())
+ maxHeight = chart.MaxInt(maxHeight, box.Height())
}
return maxWidth, maxHeight
}
diff --git a/util_test.go b/util_test.go
index 983efbc..3d155ed 100644
--- a/util_test.go
+++ b/util_test.go
@@ -51,12 +51,6 @@ func TestAutoDivide(t *testing.T) {
}, 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) {
assert := assert.New(t)
r, err := chart.SVG(400, 300)
diff --git a/xaxis.go b/xaxis.go
index 5993796..0383c73 100644
--- a/xaxis.go
+++ b/xaxis.go
@@ -29,6 +29,7 @@ type XAxisOption struct {
Data []string
Theme string
Hidden bool
+ SplitNumber int
// TODO split number
}
@@ -47,11 +48,12 @@ func drawXAxis(p *Draw, opt *XAxisOption) (int, *Range, error) {
}
theme := NewTheme(opt.Theme)
data := NewAxisDataListFromStringList(opt.Data)
- style := AxisStyle{
+ style := AxisOption{
BoundaryGap: opt.BoundaryGap,
StrokeColor: theme.GetAxisStrokeColor(),
FontColor: theme.GetAxisStrokeColor(),
StrokeWidth: 1,
+ SplitNumber: opt.SplitNumber,
}
boundary := true
diff --git a/yaxis.go b/yaxis.go
index 6b8af4c..79ed299 100644
--- a/yaxis.go
+++ b/yaxis.go
@@ -38,7 +38,7 @@ func drawYAxis(p *Draw, opt *ChartOption, xAxisHeight int, padding chart.Box) (*
theme := NewTheme(opt.Theme)
yRange := opt.getYRange(0)
data := NewAxisDataListFromStringList(yRange.Values())
- style := AxisStyle{
+ style := AxisOption{
Position: PositionLeft,
BoundaryGap: FalseFlag(),
FontColor: theme.GetAxisStrokeColor(),