diff --git a/.gitignore b/.gitignore index cb43a6a..2ac8a25 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ -*.png \ No newline at end of file +*.png +*.svg \ No newline at end of file diff --git a/bar_series.go b/bar_series.go index 72f4cb1..b730099 100644 --- a/bar_series.go +++ b/bar_series.go @@ -47,29 +47,26 @@ type BarSeries struct { CustomStyles []BarSeriesCustomStyle } +type barSeriesWidthValues struct { + columnWidth int + columnMargin int + margin int + barWidth int +} + func (bs BarSeries) GetBarStyle(index, pointIndex int) chart.Style { + // 指定样式 for _, item := range bs.CustomStyles { if item.Index == index && item.PointIndex == pointIndex { return item.Style } } + // 其它非指定样式 return chart.Style{} } -func (bs BarSeries) Render(r chart.Renderer, canvasBox chart.Box, xrange, yrange chart.Range, defaults chart.Style) { - if bs.Len() == 0 || bs.Count <= 0 { - return - } - style := bs.Style.InheritFrom(defaults) - style.FillColor = style.StrokeColor - if !style.ShouldDrawStroke() { - return - } - - cb := canvasBox.Bottom - cl := canvasBox.Left - - columnWidth := canvasBox.Width() / bs.Len() +func (bs BarSeries) getWidthValues(width int) barSeriesWidthValues { + columnWidth := width / bs.Len() // 块间隔 columnMargin := columnWidth / 10 minColumnMargin := 2 @@ -92,6 +89,27 @@ func (bs BarSeries) Render(r chart.Renderer, canvasBox chart.Box, xrange, yrange // 重新计息columnMargin columnMargin = (columnWidth - allBarMarginWidth - (bs.Count * barWidth)) / 2 } + return barSeriesWidthValues{ + columnWidth: columnWidth, + columnMargin: columnMargin, + margin: margin, + barWidth: barWidth, + } +} + +func (bs BarSeries) Render(r chart.Renderer, canvasBox chart.Box, xrange, yrange chart.Range, defaults chart.Style) { + if bs.Len() == 0 || bs.Count <= 0 { + return + } + style := bs.Style.InheritFrom(defaults) + style.FillColor = style.StrokeColor + if !style.ShouldDrawStroke() { + return + } + + cb := canvasBox.Bottom + cl := canvasBox.Left + widthValues := bs.getWidthValues(canvasBox.Width()) for i := 0; i < bs.Len(); i++ { vx, vy := bs.GetValues(i) @@ -104,15 +122,15 @@ func (bs BarSeries) Render(r chart.Renderer, canvasBox chart.Box, xrange, yrange x := cl + xrange.Translate(vx) // 由于bar是居中展示,因此需要往前移一个显示块 - x += (-columnWidth + columnMargin) + x += (-widthValues.columnWidth + widthValues.columnMargin) // 计算是第几个bar,位置右偏 - x += bs.Index * (margin + barWidth) + x += bs.Index * (widthValues.margin + widthValues.barWidth) y := cb - yrange.Translate(vy) chart.Draw.Box(r, chart.Box{ Left: x, Top: y, - Right: x + barWidth, + Right: x + widthValues.barWidth, Bottom: canvasBox.Bottom - 1, }, cloneStyle) } diff --git a/bar_series_test.go b/bar_series_test.go new file mode 100644 index 0000000..6343c06 --- /dev/null +++ b/bar_series_test.go @@ -0,0 +1,165 @@ +// MIT License + +// Copyright (c) 2021 Tree Xie + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package charts + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" +) + +func TestBarSeries(t *testing.T) { + assert := assert.New(t) + + customStyle := chart.Style{ + StrokeColor: drawing.ColorBlue, + } + bs := BarSeries{ + CustomStyles: []BarSeriesCustomStyle{ + { + PointIndex: 1, + Style: customStyle, + }, + }, + } + + assert.Equal(customStyle, bs.GetBarStyle(0, 1)) + + assert.True(bs.GetBarStyle(1, 0).IsZero()) +} + +func TestBarSeriesGetWidthValues(t *testing.T) { + assert := assert.New(t) + + bs := BarSeries{ + Count: 1, + BaseSeries: BaseSeries{ + XValues: []float64{ + 1, + 2, + 3, + }, + }, + } + widthValues := bs.getWidthValues(300) + assert.Equal(barSeriesWidthValues{ + columnWidth: 100, + columnMargin: 10, + margin: 10, + barWidth: 80, + }, widthValues) + + bs.Margin = 5 + widthValues = bs.getWidthValues(300) + assert.Equal(barSeriesWidthValues{ + columnWidth: 100, + columnMargin: 10, + margin: 5, + barWidth: 80, + }, widthValues) + + bs.BarWidth = 60 + widthValues = bs.getWidthValues(300) + assert.Equal(barSeriesWidthValues{ + columnWidth: 100, + columnMargin: 20, + margin: 5, + barWidth: 60, + }, widthValues) + +} + +func TestBarSeriesRender(t *testing.T) { + assert := assert.New(t) + + width := 800 + height := 400 + + r, err := chart.SVG(width, height) + assert.Nil(err) + + bs := BarSeries{ + Count: 1, + CustomStyles: []BarSeriesCustomStyle{ + { + Index: 0, + PointIndex: 1, + Style: chart.Style{ + StrokeColor: SeriesColorsLight[1], + }, + }, + }, + BaseSeries: BaseSeries{ + TickPosition: chart.TickPositionBetweenTicks, + Style: chart.Style{ + StrokeColor: SeriesColorsLight[0], + StrokeWidth: 1, + }, + XValues: []float64{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + }, + YValues: []float64{ + // 第一个点为占位点 + 0, + 120, + 200, + 150, + 80, + 70, + 110, + 130, + }, + }, + } + xrange := &chart.ContinuousRange{ + Min: 0, + Max: 7, + Domain: 753, + } + yrange := &chart.ContinuousRange{ + Min: 70, + Max: 200, + Domain: 362, + } + bs.Render(r, chart.Box{ + Top: 11, + Left: 42, + Right: 795, + Bottom: 373, + }, xrange, yrange, chart.Style{}) + + buffer := bytes.Buffer{} + err = r.Save(&buffer) + assert.Nil(err) + assert.Equal("\\n", buffer.String()) +}