test: add series and legend test
This commit is contained in:
parent
acc758cb9a
commit
a128a2513c
7 changed files with 398 additions and 77 deletions
|
|
@ -72,6 +72,7 @@ func TestBarSeriesGetWidthValues(t *testing.T) {
|
||||||
barWidth: 80,
|
barWidth: 80,
|
||||||
}, widthValues)
|
}, widthValues)
|
||||||
|
|
||||||
|
// 指定margin
|
||||||
bs.Margin = 5
|
bs.Margin = 5
|
||||||
widthValues = bs.getWidthValues(300)
|
widthValues = bs.getWidthValues(300)
|
||||||
assert.Equal(barSeriesWidthValues{
|
assert.Equal(barSeriesWidthValues{
|
||||||
|
|
@ -81,6 +82,7 @@ func TestBarSeriesGetWidthValues(t *testing.T) {
|
||||||
barWidth: 80,
|
barWidth: 80,
|
||||||
}, widthValues)
|
}, widthValues)
|
||||||
|
|
||||||
|
// 指定bar的宽度
|
||||||
bs.BarWidth = 60
|
bs.BarWidth = 60
|
||||||
widthValues = bs.getWidthValues(300)
|
widthValues = bs.getWidthValues(300)
|
||||||
assert.Equal(barSeriesWidthValues{
|
assert.Equal(barSeriesWidthValues{
|
||||||
|
|
@ -89,7 +91,6 @@ func TestBarSeriesGetWidthValues(t *testing.T) {
|
||||||
margin: 5,
|
margin: 5,
|
||||||
barWidth: 60,
|
barWidth: 60,
|
||||||
}, widthValues)
|
}, widthValues)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBarSeriesRender(t *testing.T) {
|
func TestBarSeriesRender(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -51,55 +51,55 @@ type BaseSeries struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the time series.
|
// GetName returns the name of the time series.
|
||||||
func (cs BaseSeries) GetName() string {
|
func (bs BaseSeries) GetName() string {
|
||||||
return cs.Name
|
return bs.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStyle returns the line style.
|
// GetStyle returns the line style.
|
||||||
func (cs BaseSeries) GetStyle() chart.Style {
|
func (bs BaseSeries) GetStyle() chart.Style {
|
||||||
return cs.Style
|
return bs.Style
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the number of elements in the series.
|
// Len returns the number of elements in the series.
|
||||||
func (cs BaseSeries) Len() int {
|
func (bs BaseSeries) Len() int {
|
||||||
offset := 0
|
offset := 0
|
||||||
if cs.TickPosition == chart.TickPositionBetweenTicks {
|
if bs.TickPosition == chart.TickPositionBetweenTicks {
|
||||||
offset = -1
|
offset = -1
|
||||||
}
|
}
|
||||||
return len(cs.XValues) + offset
|
return len(bs.XValues) + offset
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValues gets the x,y values at a given index.
|
// GetValues gets the x,y values at a given index.
|
||||||
func (cs BaseSeries) GetValues(index int) (float64, float64) {
|
func (bs BaseSeries) GetValues(index int) (float64, float64) {
|
||||||
if cs.TickPosition == chart.TickPositionBetweenTicks {
|
if bs.TickPosition == chart.TickPositionBetweenTicks {
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
return cs.XValues[index], cs.YValues[index]
|
return bs.XValues[index], bs.YValues[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFirstValues gets the first x,y values.
|
// GetFirstValues gets the first x,y values.
|
||||||
func (cs BaseSeries) GetFirstValues() (float64, float64) {
|
func (bs BaseSeries) GetFirstValues() (float64, float64) {
|
||||||
index := 0
|
index := 0
|
||||||
if cs.TickPosition == chart.TickPositionBetweenTicks {
|
if bs.TickPosition == chart.TickPositionBetweenTicks {
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
return cs.XValues[index], cs.YValues[index]
|
return bs.XValues[index], bs.YValues[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLastValues gets the last x,y values.
|
// GetLastValues gets the last x,y values.
|
||||||
func (cs BaseSeries) GetLastValues() (float64, float64) {
|
func (bs BaseSeries) GetLastValues() (float64, float64) {
|
||||||
return cs.XValues[len(cs.XValues)-1], cs.YValues[len(cs.YValues)-1]
|
return bs.XValues[len(bs.XValues)-1], bs.YValues[len(bs.YValues)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValueFormatters returns value formatter defaults for the series.
|
// GetValueFormatters returns value formatter defaults for the series.
|
||||||
func (cs BaseSeries) GetValueFormatters() (x, y chart.ValueFormatter) {
|
func (bs BaseSeries) GetValueFormatters() (x, y chart.ValueFormatter) {
|
||||||
if cs.XValueFormatter != nil {
|
if bs.XValueFormatter != nil {
|
||||||
x = cs.XValueFormatter
|
x = bs.XValueFormatter
|
||||||
} else {
|
} else {
|
||||||
x = chart.FloatValueFormatter
|
x = chart.FloatValueFormatter
|
||||||
}
|
}
|
||||||
if cs.YValueFormatter != nil {
|
if bs.YValueFormatter != nil {
|
||||||
y = cs.YValueFormatter
|
y = bs.YValueFormatter
|
||||||
} else {
|
} else {
|
||||||
y = chart.FloatValueFormatter
|
y = chart.FloatValueFormatter
|
||||||
}
|
}
|
||||||
|
|
@ -107,26 +107,26 @@ func (cs BaseSeries) GetValueFormatters() (x, y chart.ValueFormatter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetYAxis returns which YAxis the series draws on.
|
// GetYAxis returns which YAxis the series draws on.
|
||||||
func (cs BaseSeries) GetYAxis() chart.YAxisType {
|
func (bs BaseSeries) GetYAxis() chart.YAxisType {
|
||||||
return cs.YAxis
|
return bs.YAxis
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders the series.
|
// Render renders the series.
|
||||||
func (cs BaseSeries) Render(r chart.Renderer, canvasBox chart.Box, xrange, yrange chart.Range, defaults chart.Style) {
|
func (bs BaseSeries) Render(r chart.Renderer, canvasBox chart.Box, xrange, yrange chart.Range, defaults chart.Style) {
|
||||||
fmt.Println("should be override the function")
|
fmt.Println("should be override the function")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the series.
|
// Validate validates the series.
|
||||||
func (cs BaseSeries) Validate() error {
|
func (bs BaseSeries) Validate() error {
|
||||||
if len(cs.XValues) == 0 {
|
if len(bs.XValues) == 0 {
|
||||||
return fmt.Errorf("continuous series; must have xvalues set")
|
return fmt.Errorf("continuous series; must have xvalues set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cs.YValues) == 0 {
|
if len(bs.YValues) == 0 {
|
||||||
return fmt.Errorf("continuous series; must have yvalues set")
|
return fmt.Errorf("continuous series; must have yvalues set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cs.XValues) != len(cs.YValues) {
|
if len(bs.XValues) != len(bs.YValues) {
|
||||||
return fmt.Errorf("continuous series; must have same length xvalues as yvalues")
|
return fmt.Errorf("continuous series; must have same length xvalues as yvalues")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
94
base_series_test.go
Normal file
94
base_series_test.go
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
// 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 (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBaseSeries(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
bs := BaseSeries{
|
||||||
|
XValues: []float64{
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
},
|
||||||
|
YValues: []float64{
|
||||||
|
10,
|
||||||
|
20,
|
||||||
|
30,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(3, bs.Len())
|
||||||
|
bs.TickPosition = chart.TickPositionBetweenTicks
|
||||||
|
assert.Equal(2, bs.Len())
|
||||||
|
|
||||||
|
bs.TickPosition = chart.TickPositionUnset
|
||||||
|
x, y := bs.GetValues(1)
|
||||||
|
assert.Equal(float64(2), x)
|
||||||
|
assert.Equal(float64(20), y)
|
||||||
|
bs.TickPosition = chart.TickPositionBetweenTicks
|
||||||
|
x, y = bs.GetValues(1)
|
||||||
|
assert.Equal(float64(3), x)
|
||||||
|
assert.Equal(float64(30), y)
|
||||||
|
|
||||||
|
bs.TickPosition = chart.TickPositionUnset
|
||||||
|
x, y = bs.GetFirstValues()
|
||||||
|
assert.Equal(float64(1), x)
|
||||||
|
assert.Equal(float64(10), y)
|
||||||
|
bs.TickPosition = chart.TickPositionBetweenTicks
|
||||||
|
x, y = bs.GetFirstValues()
|
||||||
|
assert.Equal(float64(2), x)
|
||||||
|
assert.Equal(float64(20), y)
|
||||||
|
|
||||||
|
bs.TickPosition = chart.TickPositionUnset
|
||||||
|
x, y = bs.GetLastValues()
|
||||||
|
assert.Equal(float64(3), x)
|
||||||
|
assert.Equal(float64(30), y)
|
||||||
|
bs.TickPosition = chart.TickPositionBetweenTicks
|
||||||
|
x, y = bs.GetLastValues()
|
||||||
|
assert.Equal(float64(3), x)
|
||||||
|
assert.Equal(float64(30), y)
|
||||||
|
|
||||||
|
xFormater, yFormater := bs.GetValueFormatters()
|
||||||
|
assert.Equal(reflect.ValueOf(chart.FloatValueFormatter).Pointer(), reflect.ValueOf(xFormater).Pointer())
|
||||||
|
assert.Equal(reflect.ValueOf(chart.FloatValueFormatter).Pointer(), reflect.ValueOf(yFormater).Pointer())
|
||||||
|
formater := func(v interface{}) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
bs.XValueFormatter = formater
|
||||||
|
bs.YValueFormatter = formater
|
||||||
|
xFormater, yFormater = bs.GetValueFormatters()
|
||||||
|
assert.Equal(reflect.ValueOf(formater).Pointer(), reflect.ValueOf(xFormater).Pointer())
|
||||||
|
assert.Equal(reflect.ValueOf(formater).Pointer(), reflect.ValueOf(yFormater).Pointer())
|
||||||
|
|
||||||
|
assert.Equal(chart.YAxisPrimary, bs.GetYAxis())
|
||||||
|
|
||||||
|
assert.Nil(bs.Validate())
|
||||||
|
}
|
||||||
111
charts.go
111
charts.go
|
|
@ -70,10 +70,10 @@ type Graph interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Options) validate() error {
|
func (o *Options) validate() error {
|
||||||
xAxisCount := len(o.XAxis.Data)
|
|
||||||
if len(o.Series) == 0 {
|
if len(o.Series) == 0 {
|
||||||
return errors.New("series can not be empty")
|
return errors.New("series can not be empty")
|
||||||
}
|
}
|
||||||
|
xAxisCount := len(o.XAxis.Data)
|
||||||
|
|
||||||
for _, item := range o.Series {
|
for _, item := range o.Series {
|
||||||
if item.Type != SeriesPie && len(item.Data) != xAxisCount {
|
if item.Type != SeriesPie && len(item.Data) != xAxisCount {
|
||||||
|
|
@ -83,6 +83,29 @@ func (o *Options) validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Options) getWidth() int {
|
||||||
|
width := o.Width
|
||||||
|
if width <= 0 {
|
||||||
|
width = DefaultChartWidth
|
||||||
|
}
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) getHeight() int {
|
||||||
|
height := o.Height
|
||||||
|
if height <= 0 {
|
||||||
|
height = DefaultChartHeight
|
||||||
|
}
|
||||||
|
return height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) getBackground() chart.Style {
|
||||||
|
bg := chart.Style{
|
||||||
|
Padding: o.Padding,
|
||||||
|
}
|
||||||
|
return bg
|
||||||
|
}
|
||||||
|
|
||||||
func render(g Graph, rp chart.RendererProvider) ([]byte, error) {
|
func render(g Graph, rp chart.RendererProvider) ([]byte, error) {
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
err := g.Render(rp, &buf)
|
err := g.Render(rp, &buf)
|
||||||
|
|
@ -99,46 +122,32 @@ func ToPNG(g Graph) ([]byte, error) {
|
||||||
func ToSVG(g Graph) ([]byte, error) {
|
func ToSVG(g Graph) ([]byte, error) {
|
||||||
return render(g, chart.SVG)
|
return render(g, chart.SVG)
|
||||||
}
|
}
|
||||||
func New(opt Options) (Graph, error) {
|
|
||||||
err := opt.validate()
|
func newPieChart(opt Options) *chart.PieChart {
|
||||||
if err != nil {
|
values := make(chart.Values, len(opt.Series))
|
||||||
return nil, err
|
for index, item := range opt.Series {
|
||||||
}
|
values[index] = chart.Value{
|
||||||
tickPosition := opt.TickPosition
|
Value: item.Data[0].Value,
|
||||||
width := opt.Width
|
Label: item.Name,
|
||||||
if width <= 0 {
|
|
||||||
width = DefaultChartWidth
|
|
||||||
}
|
|
||||||
height := opt.Height
|
|
||||||
if height <= 0 {
|
|
||||||
height = DefaultChartHeight
|
|
||||||
}
|
|
||||||
bg := chart.Style{
|
|
||||||
Padding: opt.Padding,
|
|
||||||
}
|
|
||||||
if opt.Series[0].Type == SeriesPie {
|
|
||||||
values := make(chart.Values, len(opt.Series))
|
|
||||||
for index, item := range opt.Series {
|
|
||||||
values[index] = chart.Value{
|
|
||||||
Value: item.Data[0].Value,
|
|
||||||
Label: item.Name,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g := &chart.PieChart{
|
}
|
||||||
Background: bg,
|
return &chart.PieChart{
|
||||||
Title: opt.Title.Text,
|
Background: opt.getBackground(),
|
||||||
TitleStyle: opt.Title.Style,
|
Title: opt.Title.Text,
|
||||||
Width: width,
|
TitleStyle: opt.Title.Style,
|
||||||
Height: height,
|
Width: opt.getWidth(),
|
||||||
Values: values,
|
Height: opt.getHeight(),
|
||||||
ColorPalette: &PieThemeColorPalette{
|
Values: values,
|
||||||
ThemeColorPalette: ThemeColorPalette{
|
ColorPalette: &PieThemeColorPalette{
|
||||||
Theme: opt.Theme,
|
ThemeColorPalette: ThemeColorPalette{
|
||||||
},
|
Theme: opt.Theme,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
return g, nil
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChart(opt Options) *chart.Chart {
|
||||||
|
tickPosition := opt.TickPosition
|
||||||
|
|
||||||
xAxis, xValues := GetXAxisAndValues(opt.XAxis, tickPosition, opt.Theme)
|
xAxis, xValues := GetXAxisAndValues(opt.XAxis, tickPosition, opt.Theme)
|
||||||
|
|
||||||
|
|
@ -164,16 +173,16 @@ func New(opt Options) (Graph, error) {
|
||||||
yAxisOption = opt.YAxisOptions[1]
|
yAxisOption = opt.YAxisOptions[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
g := &chart.Chart{
|
c := &chart.Chart{
|
||||||
Log: opt.Log,
|
Log: opt.Log,
|
||||||
Background: bg,
|
Background: opt.getBackground(),
|
||||||
ColorPalette: &ThemeColorPalette{
|
ColorPalette: &ThemeColorPalette{
|
||||||
Theme: opt.Theme,
|
Theme: opt.Theme,
|
||||||
},
|
},
|
||||||
Title: opt.Title.Text,
|
Title: opt.Title.Text,
|
||||||
TitleStyle: opt.Title.Style,
|
TitleStyle: opt.Title.Style,
|
||||||
Width: width,
|
Width: opt.getWidth(),
|
||||||
Height: height,
|
Height: opt.getHeight(),
|
||||||
XAxis: xAxis,
|
XAxis: xAxis,
|
||||||
YAxis: GetYAxis(opt.Theme, yAxisOption),
|
YAxis: GetYAxis(opt.Theme, yAxisOption),
|
||||||
YAxisSecondary: GetSecondaryYAxis(opt.Theme, secondaryYAxisOption),
|
YAxisSecondary: GetSecondaryYAxis(opt.Theme, secondaryYAxisOption),
|
||||||
|
|
@ -182,8 +191,8 @@ func New(opt Options) (Graph, error) {
|
||||||
|
|
||||||
// 设置secondary的样式
|
// 设置secondary的样式
|
||||||
if legendSize != 0 {
|
if legendSize != 0 {
|
||||||
g.Elements = []chart.Renderable{
|
c.Elements = []chart.Renderable{
|
||||||
LegendCustomize(g, LegendOption{
|
LegendCustomize(c.Series, LegendOption{
|
||||||
Theme: opt.Theme,
|
Theme: opt.Theme,
|
||||||
TextPosition: LegendTextPositionRight,
|
TextPosition: LegendTextPositionRight,
|
||||||
IconDraw: DefaultLegendIconDraw,
|
IconDraw: DefaultLegendIconDraw,
|
||||||
|
|
@ -192,5 +201,17 @@ func New(opt Options) (Graph, error) {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return g, nil
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(opt Options) (Graph, error) {
|
||||||
|
err := opt.validate()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if opt.Series[0].Type == SeriesPie {
|
||||||
|
return newPieChart(opt), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return newChart(opt), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
143
charts_test.go
Normal file
143
charts_test.go
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
// 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 (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/wcharczuk/go-chart/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChartsOptions(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
o := Options{}
|
||||||
|
|
||||||
|
assert.Equal(errors.New("series can not be empty"), o.validate())
|
||||||
|
|
||||||
|
o.Series = []Series{
|
||||||
|
{
|
||||||
|
Data: []SeriesData{
|
||||||
|
{
|
||||||
|
Value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(errors.New("series and xAxis is not matched"), o.validate())
|
||||||
|
o.XAxis.Data = []string{
|
||||||
|
"1",
|
||||||
|
}
|
||||||
|
assert.Nil(o.validate())
|
||||||
|
|
||||||
|
assert.Equal(DefaultChartWidth, o.getWidth())
|
||||||
|
o.Width = 10
|
||||||
|
assert.Equal(10, o.getWidth())
|
||||||
|
|
||||||
|
assert.Equal(DefaultChartHeight, o.getHeight())
|
||||||
|
o.Height = 10
|
||||||
|
assert.Equal(10, o.getHeight())
|
||||||
|
|
||||||
|
padding := chart.NewBox(10, 10, 10, 10)
|
||||||
|
o.Padding = padding
|
||||||
|
assert.Equal(padding, o.getBackground().Padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewPieChart(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
data := []Series{
|
||||||
|
{
|
||||||
|
Data: []SeriesData{
|
||||||
|
{
|
||||||
|
Value: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Name: "chrome",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Data: []SeriesData{
|
||||||
|
{
|
||||||
|
Value: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Name: "edge",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pie := newPieChart(Options{
|
||||||
|
Series: data,
|
||||||
|
})
|
||||||
|
for index, item := range pie.Values {
|
||||||
|
assert.Equal(data[index].Name, item.Label)
|
||||||
|
assert.Equal(data[index].Data[0].Value, item.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewChart(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
data := []Series{
|
||||||
|
{
|
||||||
|
Data: []SeriesData{
|
||||||
|
{
|
||||||
|
Value: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Name: "chrome",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Data: []SeriesData{
|
||||||
|
{
|
||||||
|
Value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Name: "edge",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c := newChart(Options{
|
||||||
|
Series: data,
|
||||||
|
})
|
||||||
|
assert.Empty(c.Elements)
|
||||||
|
for index, series := range c.Series {
|
||||||
|
assert.Equal(data[index].Name, series.GetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
c = newChart(Options{
|
||||||
|
Legend: Legend{
|
||||||
|
Data: []string{
|
||||||
|
"chrome",
|
||||||
|
"edge",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.Equal(1, len(c.Elements))
|
||||||
|
}
|
||||||
|
|
@ -59,8 +59,8 @@ func DefaultLegendIconDraw(r chart.Renderer, opt LegendIconDrawOption) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.SetStrokeColor(opt.Style.GetStrokeColor())
|
r.SetStrokeColor(opt.Style.GetStrokeColor())
|
||||||
stokeWidth := opt.Style.GetStrokeWidth()
|
strokeWidth := opt.Style.GetStrokeWidth()
|
||||||
r.SetStrokeWidth(stokeWidth)
|
r.SetStrokeWidth(strokeWidth)
|
||||||
height := opt.Box.Bottom - opt.Box.Top
|
height := opt.Box.Bottom - opt.Box.Top
|
||||||
ly := opt.Box.Top - (height / 2) + 2
|
ly := opt.Box.Top - (height / 2) + 2
|
||||||
r.MoveTo(opt.Box.Left, ly)
|
r.MoveTo(opt.Box.Left, ly)
|
||||||
|
|
@ -71,7 +71,7 @@ func DefaultLegendIconDraw(r chart.Renderer, opt LegendIconDrawOption) {
|
||||||
r.FillStroke()
|
r.FillStroke()
|
||||||
}
|
}
|
||||||
|
|
||||||
func LegendCustomize(c *chart.Chart, opt LegendOption) chart.Renderable {
|
func LegendCustomize(series []chart.Series, opt LegendOption) chart.Renderable {
|
||||||
return func(r chart.Renderer, cb chart.Box, chartDefaults chart.Style) {
|
return func(r chart.Renderer, cb chart.Box, chartDefaults chart.Style) {
|
||||||
legendDefaults := chart.Style{
|
legendDefaults := chart.Style{
|
||||||
FontColor: getTextColor(opt.Theme),
|
FontColor: getTextColor(opt.Theme),
|
||||||
|
|
@ -87,7 +87,7 @@ func LegendCustomize(c *chart.Chart, opt LegendOption) chart.Renderable {
|
||||||
|
|
||||||
var labels []string
|
var labels []string
|
||||||
var lines []chart.Style
|
var lines []chart.Style
|
||||||
for _, s := range c.Series {
|
for _, s := range series {
|
||||||
if !s.GetStyle().Hidden {
|
if !s.GetStyle().Hidden {
|
||||||
if _, isAnnotationSeries := s.(chart.AnnotationSeries); !isAnnotationSeries {
|
if _, isAnnotationSeries := s.(chart.AnnotationSeries); !isAnnotationSeries {
|
||||||
labels = append(labels, s.GetName())
|
labels = append(labels, s.GetName())
|
||||||
|
|
|
||||||
62
legend_test.go
Normal file
62
legend_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLegendCustomize(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
series := GetSeries([]Series{
|
||||||
|
{
|
||||||
|
Name: "chrome",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "edge",
|
||||||
|
},
|
||||||
|
}, chart.TickPositionBetweenTicks, "")
|
||||||
|
r, err := chart.SVG(800, 600)
|
||||||
|
assert.Nil(err)
|
||||||
|
fn := LegendCustomize(series, LegendOption{
|
||||||
|
TextPosition: LegendTextPositionRight,
|
||||||
|
IconDraw: DefaultLegendIconDraw,
|
||||||
|
Align: LegendAlignLeft,
|
||||||
|
Padding: chart.Box{
|
||||||
|
Left: 100,
|
||||||
|
Top: 100,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
fn(r, chart.NewBox(11, 47, 784, 373), chart.Style{
|
||||||
|
Font: chart.StyleTextDefaults().Font,
|
||||||
|
})
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
err = r.Save(&buf)
|
||||||
|
assert.Nil(err)
|
||||||
|
assert.Equal("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"800\" height=\"600\">\\n<path d=\"M 100 100\nL 208 100\nL 208 110\nL 100 110\nL 100 100\" style=\"stroke-width:0;stroke:rgba(51,51,51,1.0);fill:none\"/><path d=\"M 100 107\nL 125 107\" style=\"stroke-width:2;stroke:rgba(84,112,198,1.0);fill:none\"/><circle cx=\"112\" cy=\"107\" r=\"5\" style=\"stroke-width:2;stroke:rgba(84,112,198,1.0);fill:rgba(255,255,255,1.0)\"/><path d=\"\" style=\"stroke-width:2;stroke:rgba(84,112,198,1.0);fill:rgba(255,255,255,1.0)\"/><text x=\"130\" y=\"110\" style=\"stroke-width:0;stroke:none;fill:rgba(51,51,51,1.0);font-size:10.2px;font-family:'Roboto Medium',sans-serif\">chrome</text><path d=\"M 185 107\nL 210 107\" style=\"stroke-width:2;stroke:rgba(145,204,117,1.0);fill:rgba(255,255,255,1.0)\"/><circle cx=\"197\" cy=\"107\" r=\"5\" style=\"stroke-width:2;stroke:rgba(145,204,117,1.0);fill:rgba(255,255,255,1.0)\"/><path d=\"\" style=\"stroke-width:2;stroke:rgba(145,204,117,1.0);fill:rgba(255,255,255,1.0)\"/><text x=\"215\" y=\"110\" style=\"stroke-width:0;stroke:none;fill:rgba(51,51,51,1.0);font-size:10.2px;font-family:'Roboto Medium',sans-serif\">edge</text></svg>", buf.String())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue