feat: support radius for pie chart
This commit is contained in:
parent
e07cb90607
commit
524eb79a8e
12 changed files with 376 additions and 66 deletions
3
axis.go
3
axis.go
|
|
@ -277,6 +277,9 @@ func (a *axis) axisTick(opt *axisRenderOption) {
|
|||
height := d.Box.Height()
|
||||
data := *a.data
|
||||
tickCount := len(data)
|
||||
if tickCount == 0 {
|
||||
return
|
||||
}
|
||||
if !opt.boundaryGap {
|
||||
tickCount--
|
||||
}
|
||||
|
|
|
|||
25
bar_chart.go
25
bar_chart.go
|
|
@ -53,6 +53,10 @@ func barChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
barMaxHeight := yRange.Size
|
||||
theme := NewTheme(opt.Theme)
|
||||
|
||||
seriesNames := opt.Legend.Data
|
||||
|
||||
r := d.Render
|
||||
|
||||
for i, series := range opt.SeriesList {
|
||||
for j, item := range series.Data {
|
||||
x0, _ := xRange.GetRange(j)
|
||||
|
|
@ -63,6 +67,10 @@ func barChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
}
|
||||
|
||||
h := int(yRange.getHeight(item.Value))
|
||||
fillColor := theme.GetSeriesColor(i)
|
||||
if !item.Style.FillColor.IsZero() {
|
||||
fillColor = item.Style.FillColor
|
||||
}
|
||||
|
||||
d.Bar(chart.Box{
|
||||
Top: barMaxHeight - h,
|
||||
|
|
@ -70,8 +78,23 @@ func barChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
Right: x + barWidth,
|
||||
Bottom: barMaxHeight - 1,
|
||||
}, BarStyle{
|
||||
FillColor: theme.GetSeriesColor(i),
|
||||
FillColor: fillColor,
|
||||
})
|
||||
if !series.Label.Show {
|
||||
continue
|
||||
}
|
||||
text := NewValueLabelFormater(seriesNames, series.Label.Formatter)(i, item.Value, -1)
|
||||
labelStyle := chart.Style{
|
||||
FontColor: theme.GetTextColor(),
|
||||
FontSize: 10,
|
||||
Font: opt.Font,
|
||||
}
|
||||
if !series.Label.Color.IsZero() {
|
||||
labelStyle.FontColor = series.Label.Color
|
||||
}
|
||||
labelStyle.GetTextOptions().WriteToRenderer(r)
|
||||
textBox := r.MeasureText(text)
|
||||
d.text(text, x+(barWidth-textBox.Width())>>1, barMaxHeight-h-5)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
102
chart.go
102
chart.go
|
|
@ -26,7 +26,6 @@ import (
|
|||
"errors"
|
||||
"math"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/golang/freetype/truetype"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||
|
|
@ -38,23 +37,11 @@ const (
|
|||
ChartTypePie = "pie"
|
||||
)
|
||||
|
||||
type SeriesData struct {
|
||||
Value float64
|
||||
Style chart.Style
|
||||
}
|
||||
type Point struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
type Series struct {
|
||||
index int
|
||||
Type string
|
||||
Data []SeriesData
|
||||
YAxisIndex int
|
||||
Style chart.Style
|
||||
}
|
||||
|
||||
type ChartOption struct {
|
||||
Font *truetype.Font
|
||||
Theme string
|
||||
|
|
@ -68,6 +55,7 @@ type ChartOption struct {
|
|||
Padding chart.Box
|
||||
SeriesList []Series
|
||||
BackgroundColor drawing.Color
|
||||
Children []ChartOption
|
||||
}
|
||||
|
||||
func (o *ChartOption) FillDefault(theme string) {
|
||||
|
|
@ -115,6 +103,13 @@ func (o *ChartOption) FillDefault(theme string) {
|
|||
if o.Legend.Left == "" {
|
||||
o.Legend.Left = PositionCenter
|
||||
}
|
||||
if len(o.Legend.Data) == 0 {
|
||||
names := make([]string, len(o.SeriesList))
|
||||
for index, item := range o.SeriesList {
|
||||
names[index] = item.Name
|
||||
}
|
||||
o.Legend.Data = names
|
||||
}
|
||||
if o.Legend.Style.Font == nil {
|
||||
o.Legend.Style.Font = o.Font
|
||||
}
|
||||
|
|
@ -165,20 +160,19 @@ func (o *ChartOption) getYRange(axisIndex int) Range {
|
|||
if o.YAxis.Max != nil {
|
||||
max = *o.YAxis.Max
|
||||
}
|
||||
divideCount := 6
|
||||
// y轴分设置默认划分为6块
|
||||
r := NewRange(min, max, 6)
|
||||
return r
|
||||
r := NewRange(min, max, divideCount)
|
||||
|
||||
// 由于NewRange会重新计算min max
|
||||
if o.YAxis.Min != nil {
|
||||
r.Min = min
|
||||
}
|
||||
if o.YAxis.Max != nil {
|
||||
r.Max = max
|
||||
}
|
||||
|
||||
func (r Range) Values() []string {
|
||||
offset := (r.Max - r.Min) / float64(r.divideCount)
|
||||
values := make([]string, 0)
|
||||
for i := 0; i <= r.divideCount; i++ {
|
||||
v := r.Min + float64(i)*offset
|
||||
value := humanize.CommafWithDigits(v, 2)
|
||||
values = append(values, value)
|
||||
}
|
||||
return values
|
||||
return r
|
||||
}
|
||||
|
||||
type basicRenderResult struct {
|
||||
|
|
@ -188,7 +182,7 @@ type basicRenderResult struct {
|
|||
titleBox chart.Box
|
||||
}
|
||||
|
||||
func ChartRender(opt ChartOption) (*Draw, error) {
|
||||
func Render(opt ChartOption) (*Draw, error) {
|
||||
if len(opt.SeriesList) == 0 {
|
||||
return nil, errors.New("series can not be nil")
|
||||
}
|
||||
|
|
@ -207,7 +201,7 @@ func ChartRender(opt ChartOption) (*Draw, error) {
|
|||
lineSeries = append(lineSeries, item)
|
||||
}
|
||||
}
|
||||
// 如果指定了pie,则以pie的形式处理,不支持多类型图表
|
||||
// 如果指定了pie,则以pie的形式处理,pie不支持多类型图表
|
||||
// pie不需要axis
|
||||
if isPieChart {
|
||||
opt.XAxis.Hidden = true
|
||||
|
|
@ -217,21 +211,56 @@ func ChartRender(opt ChartOption) (*Draw, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isPieChart {
|
||||
return pieChartRender(opt, result)
|
||||
fns := []func() error{
|
||||
// pie render
|
||||
func() error {
|
||||
if !isPieChart {
|
||||
return nil
|
||||
}
|
||||
_, err := pieChartRender(opt, result)
|
||||
return err
|
||||
},
|
||||
// bar render
|
||||
func() error {
|
||||
// 如果是pie或者无bar类型的series
|
||||
if isPieChart || len(barSeries) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(barSeries) != 0 {
|
||||
o := opt
|
||||
o.SeriesList = barSeries
|
||||
_, err = barChartRender(o, result)
|
||||
_, err := barChartRender(o, result)
|
||||
return err
|
||||
},
|
||||
// line render
|
||||
func() error {
|
||||
// 如果是pie或者无line类型的series
|
||||
if isPieChart || len(lineSeries) == 0 {
|
||||
return nil
|
||||
}
|
||||
o := opt
|
||||
o.SeriesList = lineSeries
|
||||
_, err := lineChartRender(o, result)
|
||||
return err
|
||||
},
|
||||
// legend需要在顶层,因此最后render
|
||||
func() error {
|
||||
_, err := NewLegend(result.d, opt.Legend).Render()
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
for _, fn := range fns {
|
||||
err = fn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(lineSeries) != 0 {
|
||||
o := opt
|
||||
o.SeriesList = lineSeries
|
||||
_, err = lineChartRender(o, result)
|
||||
for _, child := range opt.Children {
|
||||
child.Parent = result.d
|
||||
if len(child.Theme) == 0 {
|
||||
child.Theme = opt.Theme
|
||||
}
|
||||
_, err = Render(child)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -263,11 +292,6 @@ func chartBasicRender(opt *ChartOption) (*basicRenderResult, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
_, err = NewLegend(d, opt.Legend).Render()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xAxisHeight := 0
|
||||
var xRange *Range
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
package charts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
|
|
@ -253,7 +252,6 @@ func TestDraw(t *testing.T) {
|
|||
tt.fn(d)
|
||||
data, err := d.Bytes()
|
||||
assert.Nil(err)
|
||||
fmt.Println(string(data))
|
||||
assert.Equal(tt.result, string(data))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,16 +40,36 @@ func lineChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seriesNames := opt.Legend.Data
|
||||
|
||||
r := d.Render
|
||||
yRange := result.yRange
|
||||
xRange := result.xRange
|
||||
for i, series := range opt.SeriesList {
|
||||
points := make([]Point, 0)
|
||||
for j, item := range series.Data {
|
||||
y := yRange.getRestHeight(item.Value)
|
||||
x := xRange.getWidth(float64(j))
|
||||
points = append(points, Point{
|
||||
Y: y,
|
||||
X: xRange.getWidth(float64(j)),
|
||||
X: x,
|
||||
})
|
||||
if !series.Label.Show {
|
||||
continue
|
||||
}
|
||||
text := NewValueLabelFormater(seriesNames, series.Label.Formatter)(i, item.Value, -1)
|
||||
labelStyle := chart.Style{
|
||||
FontColor: theme.GetTextColor(),
|
||||
FontSize: 10,
|
||||
Font: opt.Font,
|
||||
}
|
||||
if !series.Label.Color.IsZero() {
|
||||
labelStyle.FontColor = series.Label.Color
|
||||
}
|
||||
labelStyle.GetTextOptions().WriteToRenderer(r)
|
||||
textBox := r.MeasureText(text)
|
||||
d.text(text, x-textBox.Width()>>1, y-5)
|
||||
}
|
||||
index := series.index
|
||||
if index == 0 {
|
||||
index = i
|
||||
|
|
@ -67,7 +87,6 @@ func lineChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error)
|
|||
DotFillColor: dotFillColor,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return result.d, nil
|
||||
}
|
||||
|
|
|
|||
35
pie_chart.go
35
pie_chart.go
|
|
@ -24,8 +24,8 @@ package charts
|
|||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
)
|
||||
|
||||
|
|
@ -53,7 +53,11 @@ func pieChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
|
||||
values := make([]float64, len(opt.SeriesList))
|
||||
total := float64(0)
|
||||
radiusValue := ""
|
||||
for index, series := range opt.SeriesList {
|
||||
if len(series.Radius) != 0 {
|
||||
radiusValue = series.Radius
|
||||
}
|
||||
value := float64(0)
|
||||
for _, item := range series.Data {
|
||||
value += item.Value
|
||||
|
|
@ -69,9 +73,23 @@ func pieChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
cy := box.Height() >> 1
|
||||
|
||||
diameter := chart.MinInt(box.Width(), box.Height())
|
||||
radius := float64(diameter) * defaultRadiusPercent
|
||||
|
||||
var radius float64
|
||||
if len(radiusValue) != 0 {
|
||||
v := convertPercent(radiusValue)
|
||||
if v != -1 {
|
||||
radius = float64(diameter) * v
|
||||
} else {
|
||||
radius, _ = strconv.ParseFloat(radiusValue, 64)
|
||||
}
|
||||
}
|
||||
if radius <= 0 {
|
||||
radius = float64(diameter) * defaultRadiusPercent
|
||||
}
|
||||
labelRadius := radius + 20
|
||||
|
||||
seriesNames := opt.Legend.Data
|
||||
|
||||
if len(values) == 1 {
|
||||
getPieStyle(theme, 0).WriteToRenderer(r)
|
||||
d.moveTo(cx, cy)
|
||||
|
|
@ -79,6 +97,7 @@ func pieChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
} else {
|
||||
currentValue := float64(0)
|
||||
for index, v := range values {
|
||||
|
||||
pieStyle := getPieStyle(theme, index)
|
||||
pieStyle.WriteToRenderer(r)
|
||||
d.moveTo(cx, cy)
|
||||
|
|
@ -91,6 +110,13 @@ func pieChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
r.Close()
|
||||
r.FillStroke()
|
||||
|
||||
series := opt.SeriesList[index]
|
||||
// 是否显示label
|
||||
showLabel := series.Label.Show
|
||||
if !showLabel {
|
||||
continue
|
||||
}
|
||||
|
||||
// label的角度为饼块中间
|
||||
angle := start + delta/2
|
||||
startx := cx + int(radius*math.Cos(angle))
|
||||
|
|
@ -113,8 +139,11 @@ func pieChartRender(opt ChartOption, result *basicRenderResult) (*Draw, error) {
|
|||
FontSize: 10,
|
||||
Font: opt.Font,
|
||||
}
|
||||
if !series.Label.Color.IsZero() {
|
||||
textStyle.FontColor = series.Label.Color
|
||||
}
|
||||
textStyle.GetTextOptions().WriteToRenderer(r)
|
||||
text := humanize.FtoaWithDigits(percent*100, 2) + "%"
|
||||
text := NewPieLabelFormatter(seriesNames, series.Label.Formatter)(index, v, percent)
|
||||
textBox := r.MeasureText(text)
|
||||
textMargin := 3
|
||||
x := endx + textMargin
|
||||
|
|
|
|||
13
range.go
13
range.go
|
|
@ -24,6 +24,8 @@ package charts
|
|||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
type Range struct {
|
||||
|
|
@ -62,6 +64,17 @@ func NewRange(min, max float64, divideCount int) Range {
|
|||
}
|
||||
}
|
||||
|
||||
func (r Range) Values() []string {
|
||||
offset := (r.Max - r.Min) / float64(r.divideCount)
|
||||
values := make([]string, 0)
|
||||
for i := 0; i <= r.divideCount; i++ {
|
||||
v := r.Min + float64(i)*offset
|
||||
value := humanize.CommafWithDigits(v, 2)
|
||||
values = append(values, value)
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func (r *Range) getHeight(value float64) int {
|
||||
v := (value - r.Min) / (r.Max - r.Min)
|
||||
return int(v * float64(r.Size))
|
||||
|
|
|
|||
108
series.go
Normal file
108
series.go
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2022 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 (
|
||||
"strings"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
"github.com/wcharczuk/go-chart/v2/drawing"
|
||||
)
|
||||
|
||||
type SeriesData struct {
|
||||
Value float64
|
||||
Style chart.Style
|
||||
}
|
||||
|
||||
func NewSeriesFromValues(values []float64, chartType ...string) Series {
|
||||
s := Series{
|
||||
Data: NewSeriesDataFromValues(values),
|
||||
}
|
||||
if len(chartType) != 0 {
|
||||
s.Type = chartType[0]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func NewSeriesDataFromValues(values []float64) []SeriesData {
|
||||
data := make([]SeriesData, len(values))
|
||||
for index, value := range values {
|
||||
data[index] = SeriesData{
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type SeriesLabel struct {
|
||||
Formatter string
|
||||
Color drawing.Color
|
||||
Show bool
|
||||
}
|
||||
type Series struct {
|
||||
index int
|
||||
Type string
|
||||
Data []SeriesData
|
||||
YAxisIndex int
|
||||
Style chart.Style
|
||||
Label SeriesLabel
|
||||
Name string
|
||||
// Radius of Pie chart, e.g.: 40%
|
||||
Radius string
|
||||
}
|
||||
|
||||
type LabelFormatter func(index int, value float64, percent float64) string
|
||||
|
||||
func NewPieLabelFormatter(seriesNames []string, layout string) LabelFormatter {
|
||||
if len(layout) == 0 {
|
||||
layout = "{b}: {d}"
|
||||
}
|
||||
return NewLabelFormatter(seriesNames, layout)
|
||||
}
|
||||
|
||||
func NewValueLabelFormater(seriesNames []string, layout string) LabelFormatter {
|
||||
if len(layout) == 0 {
|
||||
layout = "{c}"
|
||||
}
|
||||
return NewLabelFormatter(seriesNames, layout)
|
||||
}
|
||||
|
||||
func NewLabelFormatter(seriesNames []string, layout string) LabelFormatter {
|
||||
return func(index int, value, percent float64) string {
|
||||
// 如果无percent的则设置为<0
|
||||
percentText := ""
|
||||
if percent >= 0 {
|
||||
percentText = humanize.FtoaWithDigits(percent*100, 2) + "%"
|
||||
}
|
||||
valueText := humanize.FtoaWithDigits(value, 2)
|
||||
name := ""
|
||||
if len(seriesNames) > index {
|
||||
name = seriesNames[index]
|
||||
}
|
||||
text := strings.ReplaceAll(layout, "{c}", valueText)
|
||||
text = strings.ReplaceAll(text, "{d}", percentText)
|
||||
text = strings.ReplaceAll(text, "{b}", name)
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@
|
|||
package charts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -138,7 +137,6 @@ func TestDrawTitle(t *testing.T) {
|
|||
data, err := d.Bytes()
|
||||
assert.Nil(err)
|
||||
assert.NotEmpty(data)
|
||||
fmt.Println(string(data))
|
||||
assert.Equal(tt.result, string(data))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
util.go
5
util.go
|
|
@ -104,3 +104,8 @@ func isFalse(flag *bool) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func toFloatPoint(f float64) *float64 {
|
||||
v := f
|
||||
return &v
|
||||
}
|
||||
|
|
|
|||
3
yaxis.go
3
yaxis.go
|
|
@ -27,8 +27,11 @@ import (
|
|||
)
|
||||
|
||||
type YAxisOption struct {
|
||||
// The minimun value of axis.
|
||||
Min *float64
|
||||
// The maximum value of axis.
|
||||
Max *float64
|
||||
// Hidden y axis
|
||||
Hidden bool
|
||||
}
|
||||
|
||||
|
|
|
|||
87
yaxis_test.go
Normal file
87
yaxis_test.go
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2022 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 (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
)
|
||||
|
||||
func TestDrawYAxis(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
newDraw := func() *Draw {
|
||||
d, _ := NewDraw(DrawOption{
|
||||
Width: 400,
|
||||
Height: 300,
|
||||
})
|
||||
return d
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
newDraw func() *Draw
|
||||
newOption func() *ChartOption
|
||||
xAxisHeight int
|
||||
result string
|
||||
}{
|
||||
{
|
||||
newDraw: newDraw,
|
||||
newOption: func() *ChartOption {
|
||||
return &ChartOption{
|
||||
YAxis: YAxisOption{
|
||||
Max: toFloatPoint(20),
|
||||
},
|
||||
SeriesList: []Series{
|
||||
{
|
||||
Data: []SeriesData{
|
||||
{
|
||||
Value: 1,
|
||||
},
|
||||
{
|
||||
Value: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
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 50 10\nL 50 290\" style=\"stroke-width:1;stroke:none;fill:none\"/><path d=\"M 50 10\nL 390 10\" style=\"stroke-width:1;stroke:rgba(224,230,242,1.0);fill:none\"/><path d=\"M 50 57\nL 390 57\" style=\"stroke-width:1;stroke:rgba(224,230,242,1.0);fill:none\"/><path d=\"M 50 104\nL 390 104\" style=\"stroke-width:1;stroke:rgba(224,230,242,1.0);fill:none\"/><path d=\"M 50 151\nL 390 151\" style=\"stroke-width:1;stroke:rgba(224,230,242,1.0);fill:none\"/><path d=\"M 50 198\nL 390 198\" style=\"stroke-width:1;stroke:rgba(224,230,242,1.0);fill:none\"/><path d=\"M 50 244\nL 390 244\" style=\"stroke-width:1;stroke:rgba(224,230,242,1.0);fill:none\"/><text x=\"36\" y=\"294\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">0</text><text x=\"18\" y=\"248\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">3.33</text><text x=\"18\" y=\"202\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">6.66</text><text x=\"29\" y=\"155\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">10</text><text x=\"11\" y=\"108\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">13.33</text><text x=\"11\" y=\"61\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">16.66</text><text x=\"29\" y=\"14\" style=\"stroke-width:0;stroke:none;fill:rgba(110,112,121,1.0);font-size:12.8px;font-family:'Roboto Medium',sans-serif\">20</text></svg>",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
d := tt.newDraw()
|
||||
r, err := drawYAxis(d, tt.newOption(), tt.xAxisHeight, chart.NewBox(10, 10, 10, 10))
|
||||
assert.Nil(err)
|
||||
assert.Equal(&Range{
|
||||
divideCount: 6,
|
||||
Max: 20,
|
||||
Size: 280,
|
||||
}, r)
|
||||
|
||||
data, err := d.Bytes()
|
||||
assert.Nil(err)
|
||||
assert.Equal(tt.result, string(data))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue