diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ce56fe7..61449a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,12 +14,13 @@ jobs: strategy: matrix: go: - - '1.22' - - '1.21' - - '1.20' - '1.19' - '1.18' - '1.17' + - '1.16' + - '1.15' + - '1.14' + - '1.13' steps: - name: Go ${{ matrix.go }} test diff --git a/README.md b/README.md index 0650395..1e4ea8b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # go-charts -Clone from https://github.com/vicanso/go-charts - [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/vicanso/go-charts/blob/master/LICENSE) [![Build Status](https://github.com/vicanso/go-charts/workflows/Test/badge.svg)](https://github.com/vicanso/go-charts/actions) @@ -35,7 +33,7 @@ More examples can be found in the [./examples/](./examples/) directory. package main import ( - charts "git.smarteching.com/zeni/go-charts/v2" + charts "github.com/vicanso/go-charts/v2" ) func main() { @@ -101,7 +99,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -176,7 +174,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -233,7 +231,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -288,7 +286,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -346,7 +344,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -386,7 +384,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -451,7 +449,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { diff --git a/README_zh.md b/README_zh.md index 3f35b97..c31cf77 100644 --- a/README_zh.md +++ b/README_zh.md @@ -32,7 +32,7 @@ package main import ( - charts "git.smarteching.com/zeni/go-charts/v2" + charts "github.com/vicanso/go-charts/v2" ) func main() { @@ -98,7 +98,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -173,7 +173,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -230,7 +230,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -285,7 +285,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -343,7 +343,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -383,7 +383,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { @@ -447,7 +447,7 @@ func main() { package main import ( - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func main() { diff --git a/alias.go b/alias.go index edf0dec..a96f50b 100644 --- a/alias.go +++ b/alias.go @@ -23,8 +23,8 @@ package charts import ( - "git.smarteching.com/zeni/go-chart/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) type Box = chart.Box diff --git a/axis.go b/axis.go index 55fa219..578813c 100644 --- a/axis.go +++ b/axis.go @@ -26,7 +26,7 @@ import ( "strings" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type axisPainter struct { @@ -63,8 +63,6 @@ type AxisOption struct { StrokeWidth float64 // The length of the axis tick TickLength int - // The first axis - FirstAxis int // The margin value of label LabelMargin int // The font size of label @@ -77,11 +75,7 @@ type AxisOption struct { SplitLineShow bool // The color of split line SplitLineColor Color - // The text rotation of label - TextRotation float64 - // The offset of label - LabelOffset Box - Unit int + Unit int } func (a *axisPainter) Render() (Box, error) { @@ -159,15 +153,7 @@ func (a *axisPainter) Render() (Box, error) { } top.SetDrawingStyle(style).OverrideTextStyle(style) - isTextRotation := opt.TextRotation != 0 - - if isTextRotation { - top.SetTextRotation(opt.TextRotation) - } textMaxWidth, textMaxHeight := top.MeasureTextMaxWidthHeight(data) - if isTextRotation { - top.ClearTextRotation() - } // 增加30px来计算文本展示区域 textFillWidth := float64(textMaxWidth + 20) @@ -257,7 +243,6 @@ func (a *axisPainter) Render() (Box, error) { Length: tickLength, Unit: unit, Orient: orient, - First: opt.FirstAxis, }) p.LineStroke([]Point{ { @@ -276,14 +261,11 @@ func (a *axisPainter) Render() (Box, error) { Top: labelPaddingTop, Right: labelPaddingRight, })).MultiText(MultiTextOption{ - First: opt.FirstAxis, - Align: textAlign, - TextList: data, - Orient: orient, - Unit: unit, - Position: labelPosition, - TextRotation: opt.TextRotation, - Offset: opt.LabelOffset, + Align: textAlign, + TextList: data, + Orient: orient, + Unit: unit, + Position: labelPosition, }) // 显示辅助线 if opt.SplitLineShow { diff --git a/axis_test.go b/axis_test.go index 85e18ca..d0cff41 100644 --- a/axis_test.go +++ b/axis_test.go @@ -26,7 +26,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestAxis(t *testing.T) { diff --git a/bar_chart.go b/bar_chart.go index 043e044..19c1664 100644 --- a/bar_chart.go +++ b/bar_chart.go @@ -23,10 +23,8 @@ package charts import ( - "math" - "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type barChart struct { @@ -63,8 +61,6 @@ type BarChartOption struct { // The legend option Legend LegendOption BarWidth int - // Margin of bar - BarMargin int } func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (Box, error) { @@ -90,9 +86,6 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B margin = 5 barMargin = 3 } - if opt.BarMargin > 0 { - barMargin = opt.BarMargin - } seriesCount := len(seriesList) // 总的宽度-两个margin-(总数-1)的barMargin barWidth := (width - 2*margin - barMargin*(seriesCount-1)) / seriesCount @@ -147,25 +140,14 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B } top := barMaxHeight - h - if series.RoundRadius <= 0 { - seriesPainter.OverrideDrawingStyle(Style{ - FillColor: fillColor, - }).Rect(chart.Box{ - Top: top, - Left: x, - Right: x + barWidth, - Bottom: barMaxHeight - 1, - }) - } else { - seriesPainter.OverrideDrawingStyle(Style{ - FillColor: fillColor, - }).RoundedRect(chart.Box{ - Top: top, - Left: x, - Right: x + barWidth, - Bottom: barMaxHeight - 1, - }, series.RoundRadius) - } + seriesPainter.OverrideDrawingStyle(Style{ + FillColor: fillColor, + }).Rect(chart.Box{ + Top: top, + Left: x, + Right: x + barWidth, + Bottom: barMaxHeight - 1, + }) // 用于生成marker point points[j] = Point{ // 居中的位置 @@ -182,30 +164,11 @@ func (b *barChart) render(result *defaultRenderResult, seriesList SeriesList) (B if labelPainter == nil { continue } - y := barMaxHeight - h - radians := float64(0) - fontColor := series.Label.Color - if series.Label.Position == PositionBottom { - y = barMaxHeight - radians = -math.Pi / 2 - if fontColor.IsZero() { - if isLightColor(fillColor) { - fontColor = defaultLightFontColor - } else { - fontColor = defaultDarkFontColor - } - } - } labelPainter.Add(LabelValue{ Index: index, Value: item.Value, X: x + barWidth>>1, - Y: y, - // 旋转 - Radians: radians, - FontColor: fontColor, - Offset: series.Label.Offset, - FontSize: series.Label.FontSize, + Y: barMaxHeight - h, }) } diff --git a/bar_chart_test.go b/bar_chart_test.go index 654c320..e1522d6 100644 --- a/bar_chart_test.go +++ b/bar_chart_test.go @@ -104,76 +104,6 @@ func TestBarChart(t *testing.T) { }, result: "\\n24020016012080400FebMayAugNov24.9723.225.676.7135.6162.232.6206.43.32.65.9926.428.770.7175.6182.248.718.862.3", }, - { - render: func(p *Painter) ([]byte, error) { - seriesList := NewSeriesListDataFromValues([][]float64{ - { - 2.0, - 4.9, - 7.0, - 23.2, - 25.6, - 76.7, - 135.6, - 162.2, - 32.6, - 20.0, - 6.4, - 3.3, - }, - { - 2.6, - 5.9, - 9.0, - 26.4, - 28.7, - 70.7, - 175.6, - 182.2, - 48.7, - 18.8, - 6.0, - 2.3, - }, - }) - for index := range seriesList { - seriesList[index].Label.Show = true - seriesList[index].RoundRadius = 5 - } - _, err := NewBarChart(p, BarChartOption{ - Padding: Box{ - Left: 10, - Top: 10, - Right: 10, - Bottom: 10, - }, - SeriesList: seriesList, - XAxis: NewXAxisOption([]string{ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - }), - YAxisOptions: NewYAxisOptions([]string{ - "Rainfall", - "Evaporation", - }), - }).Render() - if err != nil { - return nil, err - } - return p.Bytes() - }, - result: "\\n24020016012080400FebMayAugNov24.9723.225.676.7135.6162.232.6206.43.32.65.9926.428.770.7175.6182.248.718.862.3", - }, } for _, tt := range tests { diff --git a/chart_option.go b/chart_option.go index d80a383..d4605a1 100644 --- a/chart_option.go +++ b/chart_option.go @@ -26,6 +26,7 @@ import ( "sort" "github.com/golang/freetype/truetype" + "github.com/wcharczuk/go-chart/v2" ) type ChartOption struct { @@ -67,14 +68,10 @@ type ChartOption struct { LineStrokeWidth float64 // The bar with of bar chart BarWidth int - // The margin of each bar - BarMargin int // The bar height of horizontal bar chart BarHeight int // Fill the area of line chart FillArea bool - // background fill (alpha) opacity - Opacity uint8 // The child charts Children []ChartOption // The value formatter @@ -273,7 +270,7 @@ func (o *ChartOption) fillDefault() { o.font, _ = GetFont(o.FontFamily) if o.font == nil { - o.font, _ = GetDefaultFont() + o.font, _ = chart.GetDefaultFont() } else { // 如果指定了字体,则设置主题的字体 t.SetFont(o.font) @@ -387,11 +384,8 @@ func TableOptionRender(opt TableChartOption) (*Painter, error) { if opt.Width <= 0 { opt.Width = defaultChartWidth } - if opt.FontFamily != "" { - opt.Font, _ = GetFont(opt.FontFamily) - } if opt.Font == nil { - opt.Font, _ = GetDefaultFont() + opt.Font, _ = chart.GetDefaultFont() } p, err := NewPainter(PainterOptions{ diff --git a/chart_option_test.go b/chart_option_test.go index c354b26..6f331b3 100644 --- a/chart_option_test.go +++ b/chart_option_test.go @@ -26,7 +26,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestChartOption(t *testing.T) { @@ -277,7 +277,7 @@ func TestBarRender(t *testing.T) { assert.Nil(err) data, err := p.Bytes() assert.Nil(err) - assert.Equal("\\nRainfallEvaporation24020016012080400FebMayAugNov162.22182.22.341.6248.07", string(data)) + assert.Equal("\\nRainfallEvaporation24020016012080400FebMayAugNov162.22182.22.341.6248.07", string(data)) } func TestHorizontalBarRender(t *testing.T) { diff --git a/charts.go b/charts.go index 31df11c..d6745d3 100644 --- a/charts.go +++ b/charts.go @@ -27,7 +27,7 @@ import ( "math" "sort" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) const labelFontSize = 10 @@ -215,16 +215,7 @@ func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, e yAxisOption.Data = r.Values() } else { yAxisOption.isCategoryAxis = true - // 由于x轴为value部分,因此计算其label单独处理 - opt.XAxis.Data = NewRange(AxisRangeOption{ - Painter: p, - Min: min, - Max: max, - // 高度需要减去x轴的高度 - Size: rangeHeight, - // 分隔数量 - DivideCount: defaultAxisDivideCount, - }).Values() + opt.XAxis.Data = r.Values() opt.XAxis.isValueAxis = true } reverseStringSlice(yAxisOption.Data) @@ -375,11 +366,10 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) { if len(barSeriesList) != 0 { handler.Add(func() error { _, err := NewBarChart(p, BarChartOption{ - Theme: opt.theme, - Font: opt.font, - XAxis: opt.XAxis, - BarWidth: opt.BarWidth, - BarMargin: opt.BarMargin, + Theme: opt.theme, + Font: opt.font, + XAxis: opt.XAxis, + BarWidth: opt.BarWidth, }).render(renderResult, barSeriesList) return err }) @@ -392,7 +382,6 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) { Theme: opt.theme, Font: opt.font, BarHeight: opt.BarHeight, - BarMargin: opt.BarMargin, YAxisOptions: opt.YAxisOptions, }).render(renderResult, horizontalBarSeriesList) return err @@ -420,7 +409,6 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) { SymbolShow: opt.SymbolShow, StrokeWidth: opt.LineStrokeWidth, FillArea: opt.FillArea, - Opacity: opt.Opacity, }).render(renderResult, lineSeriesList) return err }) diff --git a/charts_test.go b/charts_test.go index bd581e9..da75ee5 100644 --- a/charts_test.go +++ b/charts_test.go @@ -26,7 +26,7 @@ import ( "errors" "testing" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) func BenchmarkMultiChartPNGRender(b *testing.B) { diff --git a/echarts.go b/echarts.go index aaef1f1..fbe9a36 100644 --- a/echarts.go +++ b/echarts.go @@ -29,7 +29,7 @@ import ( "regexp" "strconv" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) func convertToArray(data []byte) []byte { @@ -344,11 +344,6 @@ func (esList EChartsSeriesList) ToSeriesList() SeriesList { Data: NewSeriesDataFromValues(dataItem.Value.values), Max: item.Max, Min: item.Min, - Label: SeriesLabel{ - Color: parseColor(item.Label.Color), - Show: item.Label.Show, - Distance: item.Label.Distance, - }, }) } continue diff --git a/echarts_test.go b/echarts_test.go index 2077278..5c2dbad 100644 --- a/echarts_test.go +++ b/echarts_test.go @@ -27,7 +27,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestConvertToArray(t *testing.T) { @@ -578,5 +578,5 @@ func TestRenderEChartsToSVG(t *testing.T) { ] }`) assert.Nil(err) - assert.Equal("\\nRainfallEvaporationRainfall vs EvaporationFake Data24020016012080400FebMayAugNov162.22182.22.341.6248.07", string(data)) + assert.Equal("\\nRainfallEvaporationRainfall vs EvaporationFake Data24020016012080400FebMayAugNov162.22182.22.341.6248.07", string(data)) } diff --git a/examples/area_line_chart/main.go b/examples/area_line_chart/main.go index 57ca1e9..7a84df0 100644 --- a/examples/area_line_chart/main.go +++ b/examples/area_line_chart/main.go @@ -1,10 +1,11 @@ package main import ( + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -15,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "area-line-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } diff --git a/examples/bar_chart/main.go b/examples/bar_chart/main.go index 91c9f81..c559a76 100644 --- a/examples/bar_chart/main.go +++ b/examples/bar_chart/main.go @@ -1,10 +1,11 @@ package main import ( + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -15,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "bar-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } diff --git a/examples/charts/main.go b/examples/charts/main.go index 81bc4f2..c3bb486 100644 --- a/examples/charts/main.go +++ b/examples/charts/main.go @@ -6,7 +6,7 @@ import ( "net/http" "strconv" - charts "git.smarteching.com/zeni/go-charts/v2" + charts "github.com/vicanso/go-charts/v2" ) var html = ` @@ -355,10 +355,6 @@ func indexHandler(w http.ResponseWriter, req *http.Request) { Value: 180, }, }, - Label: charts.SeriesLabel{ - Show: true, - Position: charts.PositionBottom, - }, }, }, }, diff --git a/examples/chinese/main.go b/examples/chinese/main.go index 601f54e..9068a08 100644 --- a/examples/chinese/main.go +++ b/examples/chinese/main.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -16,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "chinese-line-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } @@ -34,8 +34,6 @@ func main() { if err != nil { panic(err) } - font, _ := charts.GetFont("noto") - charts.SetDefaultFont(font) values := [][]float64{ { @@ -87,6 +85,7 @@ func main() { p, err := charts.LineRender( values, charts.TitleTextOptionFunc("测试"), + charts.FontFamilyOptionFunc("noto"), charts.XAxisDataOptionFunc([]string{ "星期一", "星期二", diff --git a/examples/funnel_chart/main.go b/examples/funnel_chart/main.go index 653f834..8f21db6 100644 --- a/examples/funnel_chart/main.go +++ b/examples/funnel_chart/main.go @@ -1,10 +1,11 @@ package main import ( + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -15,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "funnel-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } @@ -29,8 +30,6 @@ func main() { 60, 40, 20, - 10, - 0, } p, err := charts.FunnelRender( values, @@ -41,8 +40,6 @@ func main() { "Visit", "Inquiry", "Order", - "Pay", - "Cancel", }), ) if err != nil { diff --git a/examples/horizontal_bar_chart/main.go b/examples/horizontal_bar_chart/main.go index f5d8497..a0f5bda 100644 --- a/examples/horizontal_bar_chart/main.go +++ b/examples/horizontal_bar_chart/main.go @@ -1,10 +1,11 @@ package main import ( + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -15,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "horizontal-bar-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } @@ -25,22 +26,22 @@ func writeFile(buf []byte) error { func main() { values := [][]float64{ { - 10, - 30, - 50, - 70, - 90, - 110, - 130, + 8203, + 18203, + 23489, + 29034, + 104970, + 131744, + 630230, }, { - 20, - 40, - 60, - 80, - 100, - 120, - 140, + 9325, + 19325, + 23438, + 31000, + 121594, + 134141, + 681807, }, } p, err := charts.HorizontalBarRender( @@ -65,9 +66,6 @@ func main() { "China", "World", }), - func(opt *charts.ChartOption) { - opt.SeriesList[0].RoundRadius = 5 - }, ) if err != nil { panic(err) diff --git a/examples/line_chart/main.go b/examples/line_chart/main.go index baee8a3..c1478a6 100644 --- a/examples/line_chart/main.go +++ b/examples/line_chart/main.go @@ -2,10 +2,11 @@ package main import ( "fmt" + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -16,7 +17,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "line-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } @@ -96,11 +97,6 @@ func main() { Top: 5, Bottom: 10, } - opt.YAxisOptions = []charts.YAxisOption{ - { - SplitLineShow: charts.FalseFlag(), - }, - } opt.SymbolShow = charts.FalseFlag() opt.LineStrokeWidth = 1 opt.ValueFormatter = func(f float64) string { diff --git a/examples/painter/main.go b/examples/painter/main.go index 1b842b3..3c31ce4 100644 --- a/examples/painter/main.go +++ b/examples/painter/main.go @@ -1,11 +1,12 @@ package main import ( + "io/ioutil" "os" "path/filepath" - charts "git.smarteching.com/zeni/go-charts/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + charts "github.com/vicanso/go-charts/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) func writeFile(buf []byte) error { @@ -16,7 +17,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "painter.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } diff --git a/examples/pie_chart/main.go b/examples/pie_chart/main.go index 5d70438..3721ed1 100644 --- a/examples/pie_chart/main.go +++ b/examples/pie_chart/main.go @@ -1,10 +1,11 @@ package main import ( + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -15,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "pie-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } diff --git a/examples/radar_chart/main.go b/examples/radar_chart/main.go index e7053af..51f7409 100644 --- a/examples/radar_chart/main.go +++ b/examples/radar_chart/main.go @@ -1,10 +1,11 @@ package main import ( + "io/ioutil" "os" "path/filepath" - "git.smarteching.com/zeni/go-charts/v2" + "github.com/vicanso/go-charts/v2" ) func writeFile(buf []byte) error { @@ -15,7 +16,7 @@ func writeFile(buf []byte) error { } file := filepath.Join(tmpPath, "radar-chart.png") - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } diff --git a/examples/table/main.go b/examples/table/main.go index de994eb..2701ec1 100644 --- a/examples/table/main.go +++ b/examples/table/main.go @@ -1,13 +1,14 @@ package main import ( + "io/ioutil" "os" "path/filepath" "strconv" "strings" - "git.smarteching.com/zeni/go-charts/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/vicanso/go-charts/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) func writeFile(buf []byte, filename string) error { @@ -18,7 +19,7 @@ func writeFile(buf []byte, filename string) error { } file := filepath.Join(tmpPath, filename) - err = os.WriteFile(file, buf, 0600) + err = ioutil.WriteFile(file, buf, 0600) if err != nil { return err } diff --git a/examples/time_line_chart/main.go b/examples/time_line_chart/main.go deleted file mode 100644 index c6c93bf..0000000 --- a/examples/time_line_chart/main.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "crypto/rand" - "fmt" - "math/big" - "os" - "path/filepath" - "time" - - "git.smarteching.com/zeni/go-charts/v2" -) - -func writeFile(buf []byte) error { - tmpPath := "./tmp" - err := os.MkdirAll(tmpPath, 0700) - if err != nil { - return err - } - - file := filepath.Join(tmpPath, "time-line-chart.png") - err = os.WriteFile(file, buf, 0600) - if err != nil { - return err - } - return nil -} - -func main() { - xAxisValue := []string{} - values := []float64{} - now := time.Now() - firstAxis := 0 - for i := 0; i < 300; i++ { - // 设置首个axis为xx:00的时间点 - if firstAxis == 0 && now.Minute() == 0 { - firstAxis = i - } - xAxisValue = append(xAxisValue, now.Format("15:04")) - now = now.Add(time.Minute) - value, _ := rand.Int(rand.Reader, big.NewInt(100)) - values = append(values, float64(value.Int64())) - } - p, err := charts.LineRender( - [][]float64{ - values, - }, - charts.TitleTextOptionFunc("Line"), - charts.XAxisDataOptionFunc(xAxisValue, charts.FalseFlag()), - charts.LegendLabelsOptionFunc([]string{ - "Demo", - }, "50"), - func(opt *charts.ChartOption) { - opt.XAxis.FirstAxis = firstAxis - // 必须要比计算得来的最小值更大(每60分钟) - opt.XAxis.SplitNumber = 60 - opt.Legend.Padding = charts.Box{ - Top: 5, - Bottom: 10, - } - opt.SymbolShow = charts.FalseFlag() - opt.LineStrokeWidth = 1 - opt.ValueFormatter = func(f float64) string { - return fmt.Sprintf("%.0f", f) - } - }, - ) - - if err != nil { - panic(err) - } - - buf, err := p.Bytes() - if err != nil { - panic(err) - } - err = writeFile(buf) - if err != nil { - panic(err) - } -} diff --git a/font.go b/font.go index 828654e..c40b51e 100644 --- a/font.go +++ b/font.go @@ -27,18 +27,14 @@ import ( "sync" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2/roboto" + "github.com/wcharczuk/go-chart/v2/roboto" ) var fonts = sync.Map{} var ErrFontNotExists = errors.New("font is not exists") -var defaultFontFamily = "defaultFontFamily" func init() { - name := "roboto" - _ = InstallFont(name, roboto.Roboto) - font, _ := GetFont(name) - SetDefaultFont(font) + _ = InstallFont("roboto", roboto.Roboto) } // InstallFont installs the font for charts @@ -51,19 +47,6 @@ func InstallFont(fontFamily string, data []byte) error { return nil } -// GetDefaultFont get default font -func GetDefaultFont() (*truetype.Font, error) { - return GetFont(defaultFontFamily) -} - -// SetDefaultFont set default font -func SetDefaultFont(font *truetype.Font) { - if font == nil { - return - } - fonts.Store(defaultFontFamily, font) -} - // GetFont get the font by font family func GetFont(fontFamily string) (*truetype.Font, error) { value, ok := fonts.Load(fontFamily) diff --git a/font_test.go b/font_test.go index e0c56b2..9dc731c 100644 --- a/font_test.go +++ b/font_test.go @@ -26,7 +26,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/roboto" + "github.com/wcharczuk/go-chart/v2/roboto" ) func TestInstallFont(t *testing.T) { diff --git a/funnel_chart.go b/funnel_chart.go index d4a8bdd..719853a 100644 --- a/funnel_chart.go +++ b/funnel_chart.go @@ -23,6 +23,9 @@ package charts import ( + "fmt" + + "github.com/dustin/go-humanize" "github.com/golang/freetype/truetype" ) @@ -92,23 +95,13 @@ func (f *funnelChart) render(result *defaultRenderResult, seriesList SeriesList) y := 0 widthList := make([]int, len(seriesList)) textList := make([]string, len(seriesList)) - seriesNames := seriesList.Names() - offset := max - min for index, item := range seriesList { value := item.Data[0].Value - // 最大最小值一致则为100% - widthPercent := 100.0 - if offset != 0 { - widthPercent = (value - min) / offset - } + widthPercent := (value - min) / (max - min) w := int(widthPercent * float64(width)) widthList[index] = w - // 如果最大值为0,则占比100% - percent := 1.0 - if max != 0 { - percent = value / max - } - textList[index] = NewFunnelLabelFormatter(seriesNames, item.Label.Formatter)(index, value, percent) + p := humanize.CommafWithDigits(value/max*100, 2) + "%" + textList[index] = fmt.Sprintf("%s(%s)", item.Name, p) } for index, w := range widthList { diff --git a/go.mod b/go.mod index 76a47b6..de0bb9c 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,17 @@ -module git.smarteching.com/zeni/go-charts/v2 +module github.com/vicanso/go-charts/v2 -go 1.24.1 +go 1.17 require ( - git.smarteching.com/zeni/go-chart/v2 v2.1.4 - github.com/dustin/go-humanize v1.0.1 + github.com/dustin/go-humanize v1.0.0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.8.0 + github.com/wcharczuk/go-chart/v2 v2.1.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/image v0.21.0 // indirect + golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3e1a48a..e0b1547 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,27 @@ -git.smarteching.com/zeni/go-chart/v2 v2.1.4 h1:pF06+F6eqJLIG8uMiTVPR5TygPGMjM/FHMzTxmu5V/Q= -git.smarteching.com/zeni/go-chart/v2 v2.1.4/go.mod h1:b3ueW9h3pGGXyhkormZAvilHaG4+mQti+bMNPdQBeOQ= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= -golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I= +github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/grid_test.go b/grid_test.go index fa9c3a6..3110a2b 100644 --- a/grid_test.go +++ b/grid_test.go @@ -26,7 +26,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestGrid(t *testing.T) { diff --git a/horizontal_bar_chart.go b/horizontal_bar_chart.go index ed091c9..58c6e19 100644 --- a/horizontal_bar_chart.go +++ b/horizontal_bar_chart.go @@ -24,7 +24,7 @@ package charts import ( "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type horizontalBarChart struct { @@ -50,8 +50,6 @@ type HorizontalBarChartOption struct { // The legend option Legend LegendOption BarHeight int - // Margin of bar - BarMargin int } // NewHorizontalBarChart returns a horizontal bar chart renderer @@ -83,9 +81,6 @@ func (h *horizontalBarChart) render(result *defaultRenderResult, seriesList Seri margin = 5 barMargin = 3 } - if opt.BarMargin > 0 { - barMargin = opt.BarMargin - } seriesCount := len(seriesList) // 总的高度-两个margin-(总数-1)的barMargin barHeight := (height - 2*margin - barMargin*(seriesCount-1)) / seriesCount @@ -104,25 +99,11 @@ func (h *horizontalBarChart) render(result *defaultRenderResult, seriesList Seri DivideCount: defaultAxisDivideCount, Size: seriesPainter.Width(), }) - seriesNames := seriesList.Names() - rendererList := []Renderer{} for index := range seriesList { series := seriesList[index] seriesColor := theme.GetSeriesColor(series.index) divideValues := yRange.AutoDivide() - - var labelPainter *SeriesLabelPainter - if series.Label.Show { - labelPainter = NewSeriesLabelPainter(SeriesLabelPainterParams{ - P: seriesPainter, - SeriesNames: seriesNames, - Label: series.Label, - Theme: opt.Theme, - Font: opt.Font, - }) - rendererList = append(rendererList, labelPainter) - } for j, item := range series.Data { if j >= yRange.divideCount { continue @@ -141,57 +122,16 @@ func (h *horizontalBarChart) render(result *defaultRenderResult, seriesList Seri fillColor = item.Style.FillColor } right := w - if series.RoundRadius <= 0 { - seriesPainter.OverrideDrawingStyle(Style{ - FillColor: fillColor, - }).Rect(chart.Box{ - Top: y, - Left: 0, - Right: right, - Bottom: y + barHeight, - }) - } else { - seriesPainter.OverrideDrawingStyle(Style{ - FillColor: fillColor, - }).RoundedRect(chart.Box{ - Top: y, - Left: 0, - Right: right, - Bottom: y + barHeight, - }, series.RoundRadius) - } - - // 如果label不需要展示,则返回 - if labelPainter == nil { - continue - } - labelValue := LabelValue{ - Orient: OrientHorizontal, - Index: index, - Value: item.Value, - X: right, - Y: y + barHeight>>1, - Offset: series.Label.Offset, - FontColor: series.Label.Color, - FontSize: series.Label.FontSize, - } - if series.Label.Position == PositionLeft { - labelValue.X = 0 - if labelValue.FontColor.IsZero() { - if isLightColor(fillColor) { - labelValue.FontColor = defaultLightFontColor - } else { - labelValue.FontColor = defaultDarkFontColor - } - } - } - labelPainter.Add(labelValue) + seriesPainter.OverrideDrawingStyle(Style{ + FillColor: fillColor, + }).Rect(chart.Box{ + Top: y, + Left: 0, + Right: right, + Bottom: y + barHeight, + }) } } - err := doRender(rendererList...) - if err != nil { - return BoxZero, err - } return p.box, nil } diff --git a/line_chart.go b/line_chart.go index fb1d16a..26f94a4 100644 --- a/line_chart.go +++ b/line_chart.go @@ -26,7 +26,7 @@ import ( "math" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) type lineChart struct { @@ -70,8 +70,6 @@ type LineChartOption struct { FillArea bool // background is filled backgroundIsFilled bool - // background fill (alpha) opacity - Opacity uint8 } func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) (Box, error) { @@ -115,9 +113,6 @@ func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) ( StrokeColor: seriesColor, StrokeWidth: strokeWidth, } - if len(series.Style.StrokeDashArray) > 0 { - drawingStyle.StrokeDashArray = series.Style.StrokeDashArray - } yRange := result.axisRanges[series.AxisIndex] points := make([]Point, 0) @@ -152,8 +147,6 @@ func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) ( Value: item.Value, X: p.X, Y: p.Y, - // 字体大小 - FontSize: series.Label.FontSize, }) } // 如果需要填充区域 @@ -161,10 +154,6 @@ func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) ( areaPoints := make([]Point, len(points)) copy(areaPoints, points) bottomY := yRange.getRestHeight(yRange.min) - var opacity uint8 = 200 - if opt.Opacity != 0 { - opacity = opt.Opacity - } areaPoints = append(areaPoints, Point{ X: areaPoints[len(areaPoints)-1].X, Y: bottomY, @@ -173,7 +162,7 @@ func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) ( Y: bottomY, }, areaPoints[0]) seriesPainter.SetDrawingStyle(Style{ - FillColor: seriesColor.WithAlpha(opacity), + FillColor: seriesColor.WithAlpha(200), }) seriesPainter.FillArea(areaPoints) } diff --git a/mark_line.go b/mark_line.go index bc850bb..af1062d 100644 --- a/mark_line.go +++ b/mark_line.go @@ -24,6 +24,7 @@ package charts import ( "github.com/golang/freetype/truetype" + "github.com/wcharczuk/go-chart/v2" ) // NewMarkLine returns a series mark line @@ -74,7 +75,7 @@ func (m *markLinePainter) Render() (Box, error) { } font := opt.Font if font == nil { - font, _ = GetDefaultFont() + font, _ = chart.GetDefaultFont() } summary := s.Summary() for _, markLine := range s.MarkLine.Data { diff --git a/mark_line_test.go b/mark_line_test.go index 0448cda..00d19ef 100644 --- a/mark_line_test.go +++ b/mark_line_test.go @@ -26,7 +26,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestMarkLine(t *testing.T) { diff --git a/mark_point.go b/mark_point.go index fd8a88b..f6c93f3 100644 --- a/mark_point.go +++ b/mark_point.go @@ -24,6 +24,7 @@ package charts import ( "github.com/golang/freetype/truetype" + "github.com/wcharczuk/go-chart/v2/drawing" ) // NewMarkPoint returns a series mark point @@ -77,15 +78,16 @@ func (m *markPointPainter) Render() (Box, error) { symbolSize = 30 } textStyle := Style{ + FontColor: drawing.Color{ + R: 238, + G: 238, + B: 238, + A: 255, + }, FontSize: labelFontSize, StrokeWidth: 1, Font: opt.Font, } - if isLightColor(opt.FillColor) { - textStyle.FontColor = defaultLightFontColor - } else { - textStyle.FontColor = defaultDarkFontColor - } painter.OverrideDrawingStyle(Style{ FillColor: opt.FillColor, }).OverrideTextStyle(textStyle) diff --git a/mark_point_test.go b/mark_point_test.go index 298345b..ffa01a7 100644 --- a/mark_point_test.go +++ b/mark_point_test.go @@ -26,7 +26,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestMarkPoint(t *testing.T) { diff --git a/painter.go b/painter.go index bee646f..efd5045 100644 --- a/painter.go +++ b/painter.go @@ -28,7 +28,7 @@ import ( "math" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type ValueFormatter func(float64) string @@ -59,8 +59,6 @@ type PainterOptions struct { type PainterOption func(*Painter) type TicksOption struct { - // the first tick - First int Length int Orient string Count int @@ -73,11 +71,6 @@ type MultiTextOption struct { Unit int Position string Align string - // The text rotation of label - TextRotation float64 - Offset Box - // The first text index - First int } type GridOption struct { @@ -156,7 +149,7 @@ func NewPainter(opts PainterOptions, opt ...PainterOption) (*Painter, error) { } font := opts.Font if font == nil { - f, err := GetDefaultFont() + f, err := chart.GetDefaultFont() if err != nil { return nil, err } @@ -565,19 +558,6 @@ func (p *Painter) Text(body string, x, y int) *Painter { return p } -func (p *Painter) TextRotation(body string, x, y int, radians float64) { - p.render.SetTextRotation(radians) - p.render.Text(body, x+p.box.Left, y+p.box.Top) - p.render.ClearTextRotation() -} - -func (p *Painter) SetTextRotation(radians float64) { - p.render.SetTextRotation(radians) -} -func (p *Painter) ClearTextRotation() { - p.render.ClearTextRotation() -} - func (p *Painter) TextFit(body string, x, y, width int, textAligns ...string) chart.Box { style := p.style textWarp := style.TextWrap @@ -620,7 +600,6 @@ func (p *Painter) Ticks(opt TicksOption) *Painter { return p } count := opt.Count - first := opt.First width := p.Width() height := p.Height() unit := 1 @@ -635,10 +614,7 @@ func (p *Painter) Ticks(opt TicksOption) *Painter { values = autoDivide(width, count) } for index, value := range values { - if index < first { - continue - } - if (index-first)%unit != 0 { + if index%unit != 0 { continue } if isVertical { @@ -693,19 +669,10 @@ func (p *Painter) MultiText(opt MultiTextOption) *Painter { } else { values = autoDivide(width, count) } - isTextRotation := opt.TextRotation != 0 - offset := opt.Offset for index, text := range opt.TextList { - if index < opt.First { + if opt.Unit != 0 && index%opt.Unit != showIndex { continue } - if opt.Unit != 0 && (index-opt.First)%opt.Unit != showIndex { - continue - } - if isTextRotation { - p.ClearTextRotation() - p.SetTextRotation(opt.TextRotation) - } box := p.MeasureText(text) start := values[index] if positionCenter { @@ -726,13 +693,8 @@ func (p *Painter) MultiText(opt MultiTextOption) *Painter { } else { x = start - box.Width()>>1 } - x += offset.Left - y += offset.Top p.Text(text, x, y) } - if isTextRotation { - p.ClearTextRotation() - } return p } @@ -803,48 +765,6 @@ func (p *Painter) Rect(box Box) *Painter { return p } -func (p *Painter) RoundedRect(box Box, radius int) *Painter { - r := (box.Right - box.Left) / 2 - if radius > r { - radius = r - } - rx := float64(radius) - ry := float64(radius) - p.MoveTo(box.Left+radius, box.Top) - p.LineTo(box.Right-radius, box.Top) - - cx := box.Right - radius - cy := box.Top + radius - // right top - p.ArcTo(cx, cy, rx, ry, -math.Pi/2, math.Pi/2) - - p.LineTo(box.Right, box.Bottom-radius) - - // right bottom - cx = box.Right - radius - cy = box.Bottom - radius - p.ArcTo(cx, cy, rx, ry, 0.0, math.Pi/2) - - p.LineTo(box.Left+radius, box.Bottom) - - // left bottom - cx = box.Left + radius - cy = box.Bottom - radius - p.ArcTo(cx, cy, rx, ry, math.Pi/2, math.Pi/2) - - p.LineTo(box.Left, box.Top+radius) - - // left top - cx = box.Left + radius - cy = box.Top + radius - p.ArcTo(cx, cy, rx, ry, math.Pi, math.Pi/2) - - p.Close() - p.FillStroke() - p.Fill() - return p -} - func (p *Painter) LegendLineDot(box Box) *Painter { width := box.Width() height := box.Height() @@ -860,7 +780,3 @@ func (p *Painter) LegendLineDot(box Box) *Painter { p.FillStroke() return p } - -func (p *Painter) GetRenderer() chart.Renderer { - return p.render -} diff --git a/painter_test.go b/painter_test.go index 07c4113..96e41ef 100644 --- a/painter_test.go +++ b/painter_test.go @@ -28,8 +28,8 @@ import ( "github.com/golang/freetype/truetype" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestPainterOption(t *testing.T) { @@ -343,29 +343,6 @@ func TestPainter(t *testing.T) { } } -func TestRoundedRect(t *testing.T) { - assert := assert.New(t) - p, err := NewPainter(PainterOptions{ - Width: 400, - Height: 300, - Type: ChartOutputSVG, - }) - assert.Nil(err) - p.OverrideDrawingStyle(Style{ - FillColor: drawing.ColorWhite, - StrokeWidth: 1, - StrokeColor: drawing.ColorWhite, - }).RoundedRect(Box{ - Left: 10, - Right: 30, - Bottom: 150, - Top: 10, - }, 5) - buf, err := p.Bytes() - assert.Nil(err) - assert.Equal("\\n", string(buf)) -} - func TestPainterTextFit(t *testing.T) { assert := assert.New(t) p, err := NewPainter(PainterOptions{ @@ -374,7 +351,7 @@ func TestPainterTextFit(t *testing.T) { Type: ChartOutputSVG, }) assert.Nil(err) - f, _ := GetDefaultFont() + f, _ := chart.GetDefaultFont() style := Style{ FontSize: 12, FontColor: chart.ColorBlack, diff --git a/pie_chart.go b/pie_chart.go index 5c04ed8..0075ffc 100644 --- a/pie_chart.go +++ b/pie_chart.go @@ -27,7 +27,7 @@ import ( "math" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type pieChart struct { @@ -63,96 +63,6 @@ func NewPieChart(p *Painter, opt PieChartOption) *pieChart { } } -type sector struct { - value float64 - percent float64 - cx int - cy int - rx float64 - ry float64 - start float64 - delta float64 - offset int - quadrant int - lineStartX int - lineStartY int - lineBranchX int - lineBranchY int - lineEndX int - lineEndY int - showLabel bool - label string - series Series - color Color -} - -func NewSector(cx int, cy int, radius float64, labelRadius float64, value float64, currentValue float64, totalValue float64, labelLineLength int, label string, series Series, color Color) sector { - s := sector{} - s.value = value - s.percent = value / totalValue - s.cx = cx - s.cy = cy - s.rx = radius - s.ry = radius - p := (currentValue + value/2) / totalValue - if p < 0.25 { - s.quadrant = 1 - } else if p < 0.5 { - s.quadrant = 4 - } else if p < 0.75 { - s.quadrant = 3 - } else { - s.quadrant = 2 - } - s.start = chart.PercentToRadians(currentValue/totalValue) - math.Pi/2 - s.delta = chart.PercentToRadians(value / totalValue) - angle := s.start + s.delta/2 - s.lineStartX = cx + int(radius*math.Cos(angle)) - s.lineStartY = cy + int(radius*math.Sin(angle)) - s.lineBranchX = cx + int(labelRadius*math.Cos(angle)) - s.lineBranchY = cy + int(labelRadius*math.Sin(angle)) - s.offset = labelLineLength - if s.lineBranchX <= cx { - s.offset *= -1 - } - s.lineEndX = s.lineBranchX + s.offset - s.lineEndY = s.lineBranchY - s.series = series - s.color = color - s.showLabel = series.Label.Show - s.label = NewPieLabelFormatter([]string{label}, series.Label.Formatter)(0, s.value, s.percent) - return s -} - -func (s *sector) calculateY(prevY int) int { - for i := 0; i <= s.cy; i++ { - if s.quadrant <= 2 { - if (prevY - s.lineBranchY) > labelFontSize+5 { - break - } - s.lineBranchY -= 1 - } else { - if (s.lineBranchY - prevY) > labelFontSize+5 { - break - } - s.lineBranchY += 1 - } - } - s.lineEndY = s.lineBranchY - return s.lineBranchY -} - -func (s *sector) calculateTextXY(textBox Box) (x int, y int) { - textMargin := 3 - x = s.lineEndX + textMargin - y = s.lineEndY + textBox.Height()>>1 - 1 - if s.offset < 0 { - textWidth := textBox.Width() - x = s.lineEndX - textWidth - textMargin - } - return -} - func (p *pieChart) render(result *defaultRenderResult, seriesList SeriesList) (Box, error) { opt := p.opt values := make([]float64, len(seriesList)) @@ -191,103 +101,79 @@ func (p *pieChart) render(result *defaultRenderResult, seriesList SeriesList) (B theme := opt.Theme currentValue := float64(0) - - var quadrant1, quadrant2, quadrant3, quadrant4 []sector + prevEndX := 0 + prevEndY := 0 for index, v := range values { - series := seriesList[index] - color := theme.GetSeriesColor(index) - if index == len(values)-1 { - if color == theme.GetSeriesColor(0) { - color = theme.GetSeriesColor(1) - } - } - s := NewSector(cx, cy, radius, labelRadius, v, currentValue, total, labelLineWidth, seriesNames[index], series, color) - switch quadrant := s.quadrant; quadrant { - case 1: - quadrant1 = append([]sector{s}, quadrant1...) - case 2: - quadrant2 = append(quadrant2, s) - case 3: - quadrant3 = append([]sector{s}, quadrant3...) - case 4: - quadrant4 = append(quadrant4, s) - } - currentValue += v - } - sectors := append(quadrant1, quadrant4...) - sectors = append(sectors, quadrant3...) - sectors = append(sectors, quadrant2...) - - currentQuadrant := 0 - prevY := 0 - maxY := 0 - minY := 0 - for _, s := range sectors { seriesPainter.OverrideDrawingStyle(Style{ StrokeWidth: 1, - StrokeColor: s.color, - FillColor: s.color, + StrokeColor: theme.GetSeriesColor(index), + FillColor: theme.GetSeriesColor(index), }) - seriesPainter.MoveTo(s.cx, s.cy) - seriesPainter.ArcTo(s.cx, s.cy, s.rx, s.ry, s.start, s.delta).LineTo(s.cx, s.cy).Close().FillStroke() - if !s.showLabel { + seriesPainter.MoveTo(cx, cy) + start := chart.PercentToRadians(currentValue/total) - math.Pi/2 + currentValue += v + percent := (v / total) + delta := chart.PercentToRadians(percent) + seriesPainter.ArcTo(cx, cy, radius, radius, start, delta). + LineTo(cx, cy). + Close(). + FillStroke() + + series := seriesList[index] + // 是否显示label + showLabel := series.Label.Show + if !showLabel { continue } - if currentQuadrant != s.quadrant { - if s.quadrant == 1 { - minY = cy * 2 - maxY = 0 - prevY = cy * 2 - } - if s.quadrant == 2 { - if currentQuadrant != 3 { - prevY = s.lineEndY - } else { - prevY = minY - } - } - if s.quadrant == 3 { - if currentQuadrant != 4 { - prevY = s.lineEndY - } else { - minY = cy * 2 - maxY = 0 - prevY = 0 - } - } - if s.quadrant == 4 { - if currentQuadrant != 1 { - prevY = s.lineEndY - } else { - prevY = maxY - } - } - currentQuadrant = s.quadrant + + // label的角度为饼块中间 + angle := start + delta/2 + startx := cx + int(radius*math.Cos(angle)) + starty := cy + int(radius*math.Sin(angle)) + + endx := cx + int(labelRadius*math.Cos(angle)) + endy := cy + int(labelRadius*math.Sin(angle)) + // 计算是否有重叠,如果有则调整y坐标位置 + if index != 0 && + math.Abs(float64(endx-prevEndX)) < labelFontSize && + math.Abs(float64(endy-prevEndY)) < labelFontSize { + endy -= (labelFontSize << 1) } - prevY = s.calculateY(prevY) - if prevY > maxY { - maxY = prevY + prevEndX = endx + prevEndY = endy + + seriesPainter.MoveTo(startx, starty) + seriesPainter.LineTo(endx, endy) + offset := labelLineWidth + if endx < cx { + offset *= -1 } - if prevY < minY { - minY = prevY - } - seriesPainter.MoveTo(s.lineStartX, s.lineStartY) - seriesPainter.LineTo(s.lineBranchX, s.lineBranchY) - seriesPainter.MoveTo(s.lineBranchX, s.lineBranchY) - seriesPainter.LineTo(s.lineEndX, s.lineEndY) + seriesPainter.MoveTo(endx, endy) + endx += offset + seriesPainter.LineTo(endx, endy) seriesPainter.Stroke() + textStyle := Style{ FontColor: theme.GetTextColor(), FontSize: labelFontSize, Font: opt.Font, } - if !s.series.Label.Color.IsZero() { - textStyle.FontColor = s.series.Label.Color + if !series.Label.Color.IsZero() { + textStyle.FontColor = series.Label.Color } seriesPainter.OverrideTextStyle(textStyle) - x, y := s.calculateTextXY(seriesPainter.MeasureText(s.label)) - seriesPainter.Text(s.label, x, y) + text := NewPieLabelFormatter(seriesNames, series.Label.Formatter)(index, v, percent) + textBox := seriesPainter.MeasureText(text) + textMargin := 3 + x := endx + textMargin + y := endy + textBox.Height()>>1 - 1 + if offset < 0 { + textWidth := textBox.Width() + x = endx - textWidth - textMargin + } + seriesPainter.Text(text, x, y) } + return p.p.box, nil } diff --git a/pie_chart_test.go b/pie_chart_test.go index 3795d32..c373a7e 100644 --- a/pie_chart_test.go +++ b/pie_chart_test.go @@ -23,7 +23,6 @@ package charts import ( - "strconv" "testing" "github.com/stretchr/testify/assert" @@ -99,435 +98,3 @@ func TestPieChart(t *testing.T) { assert.Equal(tt.result, string(data)) } } - -func TestPieChartWithLabelsValuesSortedDescending(t *testing.T) { - assert := assert.New(t) - - tests := []struct { - render func(*Painter) ([]byte, error) - result string - }{ - { - render: func(p *Painter) ([]byte, error) { - values := []float64{ - 84358845, - 68070697, - 58850717, - 48059777, - 36753736, - 19051562, - 17947406, - 11754004, - 10827529, - 10521556, - 10467366, - 10394055, - 9597085, - 9104772, - 6447710, - 5932654, - 5563970, - 5428792, - 5194336, - 3850894, - 2857279, - 2116792, - 1883008, - 1373101, - 920701, - 660809, - 542051, - } - _, err := NewPieChart(p, PieChartOption{ - SeriesList: NewPieSeriesList(values, PieSeriesOption{ - Label: SeriesLabel{ - Show: true, - Formatter: "{b} ({c} ≅ {d})", - }, - Radius: "200", - }), - Title: TitleOption{ - Text: "European Union member states by population", - Left: PositionRight, - }, - Padding: Box{ - Top: 20, - Right: 20, - Bottom: 20, - Left: 20, - }, - Legend: LegendOption{ - Data: []string{ - "Germany", - "France", - "Italy", - "Spain", - "Poland", - "Romania", - "Netherlands", - "Belgium", - "Czech Republic", - "Sweden", - "Portugal", - "Greece", - "Hungary", - "Austria", - "Bulgaria", - "Denmark", - "Finland", - "Slovakia", - "Ireland", - "Croatia", - "Lithuania", - "Slovenia", - "Latvia", - "Estonia", - "Cyprus", - "Luxembourg", - "Malta", - }, - Show: FalseFlag(), - }, - }).Render() - if err != nil { - return nil, err - } - return p.Bytes() - }, - result: "\\nEuropean Union member states by populationGermany (84358845 ≅ 18.8%)France (68070697 ≅ 15.17%)Italy (58850717 ≅ 13.12%)Netherlands (17947406 ≅ 4%)Romania (19051562 ≅ 4.24%)Poland (36753736 ≅ 8.19%)Spain (48059777 ≅ 10.71%)Belgium (11754004 ≅ 2.62%)Czech Republic (10827529 ≅ 2.41%)Sweden (10521556 ≅ 2.34%)Portugal (10467366 ≅ 2.33%)Greece (10394055 ≅ 2.31%)Hungary (9597085 ≅ 2.13%)Austria (9104772 ≅ 2.02%)Bulgaria (6447710 ≅ 1.43%)Denmark (5932654 ≅ 1.32%)Finland (5563970 ≅ 1.24%)Slovakia (5428792 ≅ 1.21%)Ireland (5194336 ≅ 1.15%)Croatia (3850894 ≅ 0.85%)Lithuania (2857279 ≅ 0.63%)Slovenia (2116792 ≅ 0.47%)Latvia (1883008 ≅ 0.41%)Estonia (1373101 ≅ 0.3%)Cyprus (920701 ≅ 0.2%)Luxembourg (660809 ≅ 0.14%)Malta (542051 ≅ 0.12%)", - }, - } - for _, tt := range tests { - p, err := NewPainter(PainterOptions{ - Type: ChartOutputSVG, - Width: 1000, - Height: 800, - }, PainterThemeOption(defaultTheme)) - assert.Nil(err) - data, err := tt.render(p.Child(PainterPaddingOption(Box{ - Left: 20, - Top: 20, - Right: 20, - Bottom: 20, - }))) - assert.Nil(err) - assert.Equal(tt.result, string(data)) - } -} - -func TestPieChartWithLabelsValuesUnsorted(t *testing.T) { - assert := assert.New(t) - - tests := []struct { - render func(*Painter) ([]byte, error) - result string - }{ - { - render: func(p *Painter) ([]byte, error) { - values := []float64{ - 9104772, - 11754004, - 6447710, - 3850894, - 920701, - 10827529, - 5932654, - 1373101, - 5563970, - 68070697, - 84358845, - 10394055, - 9597085, - 5194336, - 58850717, - 1883008, - 2857279, - 660809, - 542051, - 17947406, - 36753736, - 10467366, - 19051562, - 5428792, - 2116792, - 48059777, - 10521556, - } - _, err := NewPieChart(p, PieChartOption{ - SeriesList: NewPieSeriesList(values, PieSeriesOption{ - Label: SeriesLabel{ - Show: true, - Formatter: "{b} ({c} ≅ {d})", - }, - Radius: "200", - }), - Title: TitleOption{ - Text: "European Union member states by population", - Left: PositionRight, - }, - Padding: Box{ - Top: 20, - Right: 20, - Bottom: 20, - Left: 20, - }, - Legend: LegendOption{ - Data: []string{ - "Austria", - "Belgium", - "Bulgaria", - "Croatia", - "Cyprus", - "Czech Republic", - "Denmark", - "Estonia", - "Finland", - "France", - "Germany", - "Greece", - "Hungary", - "Ireland", - "Italy", - "Latvia", - "Lithuania", - "Luxembourg", - "Malta", - "Netherlands", - "Poland", - "Portugal", - "Romania", - "Slovakia", - "Slovenia", - "Spain", - "Sweden", - }, - Show: FalseFlag(), - }, - }).Render() - if err != nil { - return nil, err - } - return p.Bytes() - }, - result: "\\nEuropean Union member states by populationFrance (68070697 ≅ 15.17%)Finland (5563970 ≅ 1.24%)Estonia (1373101 ≅ 0.3%)Denmark (5932654 ≅ 1.32%)Czech Republic (10827529 ≅ 2.41%)Cyprus (920701 ≅ 0.2%)Croatia (3850894 ≅ 0.85%)Bulgaria (6447710 ≅ 1.43%)Belgium (11754004 ≅ 2.62%)Austria (9104772 ≅ 2.02%)Germany (84358845 ≅ 18.8%)Greece (10394055 ≅ 2.31%)Hungary (9597085 ≅ 2.13%)Poland (36753736 ≅ 8.19%)Netherlands (17947406 ≅ 4%)Malta (542051 ≅ 0.12%)Luxembourg (660809 ≅ 0.14%)Lithuania (2857279 ≅ 0.63%)Latvia (1883008 ≅ 0.41%)Italy (58850717 ≅ 13.12%)Ireland (5194336 ≅ 1.15%)Portugal (10467366 ≅ 2.33%)Romania (19051562 ≅ 4.24%)Slovakia (5428792 ≅ 1.21%)Slovenia (2116792 ≅ 0.47%)Spain (48059777 ≅ 10.71%)Sweden (10521556 ≅ 2.34%)", - }, - } - for _, tt := range tests { - p, err := NewPainter(PainterOptions{ - Type: ChartOutputSVG, - Width: 1000, - Height: 800, - }, PainterThemeOption(defaultTheme)) - assert.Nil(err) - data, err := tt.render(p.Child(PainterPaddingOption(Box{ - Left: 20, - Top: 20, - Right: 20, - Bottom: 20, - }))) - assert.Nil(err) - assert.Equal(tt.result, string(data)) - } -} - -func TestPieChartWith100Labels(t *testing.T) { - assert := assert.New(t) - - tests := []struct { - render func(*Painter) ([]byte, error) - result string - }{ - { - render: func(p *Painter) ([]byte, error) { - var values []float64 - var labels []string - for i := 1; i <= 100; i++ { - values = append(values, float64(1)) - labels = append(labels, "Label "+strconv.Itoa(i)) - } - _, err := NewPieChart(p, PieChartOption{ - SeriesList: NewPieSeriesList(values, PieSeriesOption{ - Label: SeriesLabel{ - Show: true, - }, - Radius: "200", - }), - Title: TitleOption{ - Text: "Test with 100 labels", - Left: PositionRight, - }, - Padding: Box{ - Top: 20, - Right: 20, - Bottom: 20, - Left: 20, - }, - Legend: LegendOption{ - Data: labels, - Show: FalseFlag(), - }, - }).Render() - if err != nil { - return nil, err - } - return p.Bytes() - }, - result: "\\nTest with 100 labelsLabel 25: 1%Label 24: 1%Label 23: 1%Label 22: 1%Label 21: 1%Label 20: 1%Label 19: 1%Label 18: 1%Label 17: 1%Label 16: 1%Label 15: 1%Label 14: 1%Label 13: 1%Label 12: 1%Label 11: 1%Label 10: 1%Label 9: 1%Label 8: 1%Label 7: 1%Label 6: 1%Label 5: 1%Label 4: 1%Label 3: 1%Label 2: 1%Label 1: 1%Label 26: 1%Label 27: 1%Label 28: 1%Label 29: 1%Label 30: 1%Label 31: 1%Label 32: 1%Label 33: 1%Label 34: 1%Label 35: 1%Label 36: 1%Label 37: 1%Label 38: 1%Label 39: 1%Label 40: 1%Label 41: 1%Label 42: 1%Label 43: 1%Label 44: 1%Label 45: 1%Label 46: 1%Label 47: 1%Label 48: 1%Label 49: 1%Label 50: 1%Label 75: 1%Label 74: 1%Label 73: 1%Label 72: 1%Label 71: 1%Label 70: 1%Label 69: 1%Label 68: 1%Label 67: 1%Label 66: 1%Label 65: 1%Label 64: 1%Label 63: 1%Label 62: 1%Label 61: 1%Label 60: 1%Label 59: 1%Label 58: 1%Label 57: 1%Label 56: 1%Label 55: 1%Label 54: 1%Label 53: 1%Label 52: 1%Label 51: 1%Label 76: 1%Label 77: 1%Label 78: 1%Label 79: 1%Label 80: 1%Label 81: 1%Label 82: 1%Label 83: 1%Label 84: 1%Label 85: 1%Label 86: 1%Label 87: 1%Label 88: 1%Label 89: 1%Label 90: 1%Label 91: 1%Label 92: 1%Label 93: 1%Label 94: 1%Label 95: 1%Label 96: 1%Label 97: 1%Label 98: 1%Label 99: 1%Label 100: 1%", - }, - } - for _, tt := range tests { - p, err := NewPainter(PainterOptions{ - Type: ChartOutputSVG, - Width: 1000, - Height: 900, - }, PainterThemeOption(defaultTheme)) - assert.Nil(err) - data, err := tt.render(p.Child(PainterPaddingOption(Box{ - Left: 20, - Top: 20, - Right: 20, - Bottom: 20, - }))) - assert.Nil(err) - assert.Equal(tt.result, string(data)) - } -} - -func TestPieChartFixLabelPos72586(t *testing.T) { - assert := assert.New(t) - - tests := []struct { - render func(*Painter) ([]byte, error) - result string - }{ - { - render: func(p *Painter) ([]byte, error) { - values := []float64{ - 397594, - 185596, - 149086, - 144258, - 120194, - 117514, - 99412, - 91135, - 87282, - 76790, - 72586, - 58818, - 58270, - 56306, - 55486, - 54792, - 53746, - 51460, - 41242, - 39476, - 37414, - 36644, - 33784, - 32788, - 32566, - 29608, - 29558, - 29384, - 28166, - 26998, - 26948, - 26054, - 25804, - 25730, - 24438, - 23782, - 22896, - 21404, - 428978, - } - _, err := NewPieChart(p, PieChartOption{ - SeriesList: NewPieSeriesList(values, PieSeriesOption{ - Label: SeriesLabel{ - Show: true, - Formatter: "{b} ({c} ≅ {d})", - }, - Radius: "150", - }), - Title: TitleOption{ - Text: "Fix label K (72586)", - Left: PositionRight, - }, - Padding: Box{ - Top: 20, - Right: 20, - Bottom: 20, - Left: 20, - }, - Legend: LegendOption{ - Data: []string{ - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "AA", - "AB", - "AC", - "AD", - "AE", - "AF", - "AG", - "AH", - "AI", - "AJ", - "AK", - "AL", - "AM", - }, - Show: FalseFlag(), - }, - }).Render() - if err != nil { - return nil, err - } - return p.Bytes() - }, - result: "\\nFix label K (72586)C (149086 ≅ 5.04%)B (185596 ≅ 6.28%)A (397594 ≅ 13.45%)D (144258 ≅ 4.88%)E (120194 ≅ 4.06%)F (117514 ≅ 3.97%)G (99412 ≅ 3.36%)H (91135 ≅ 3.08%)I (87282 ≅ 2.95%)J (76790 ≅ 2.59%)Z (29608 ≅ 1%)Y (32566 ≅ 1.1%)X (32788 ≅ 1.1%)W (33784 ≅ 1.14%)V (36644 ≅ 1.24%)U (37414 ≅ 1.26%)T (39476 ≅ 1.33%)S (41242 ≅ 1.39%)R (51460 ≅ 1.74%)Q (53746 ≅ 1.81%)P (54792 ≅ 1.85%)O (55486 ≅ 1.87%)N (56306 ≅ 1.9%)M (58270 ≅ 1.97%)L (58818 ≅ 1.99%)K (72586 ≅ 2.45%)AA (29558 ≅ 1%)AB (29384 ≅ 0.99%)AC (28166 ≅ 0.95%)AD (26998 ≅ 0.91%)AE (26948 ≅ 0.91%)AF (26054 ≅ 0.88%)AG (25804 ≅ 0.87%)AH (25730 ≅ 0.87%)AI (24438 ≅ 0.82%)AJ (23782 ≅ 0.8%)AK (22896 ≅ 0.77%)AL (21404 ≅ 0.72%)AM (428978 ≅ 14.52%)", - }, - } - for _, tt := range tests { - p, err := NewPainter(PainterOptions{ - Type: ChartOutputSVG, - Width: 1150, - Height: 550, - }, PainterThemeOption(defaultTheme)) - assert.Nil(err) - data, err := tt.render(p.Child(PainterPaddingOption(Box{ - Left: 20, - Top: 20, - Right: 20, - Bottom: 20, - }))) - assert.Nil(err) - assert.Equal(tt.result, string(data)) - } -} diff --git a/radar_chart.go b/radar_chart.go index cf18135..429850d 100644 --- a/radar_chart.go +++ b/radar_chart.go @@ -25,10 +25,9 @@ package charts import ( "errors" - "github.com/dustin/go-humanize" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) type radarChart struct { @@ -231,15 +230,9 @@ func (r *radarChart) render(result *defaultRenderResult, seriesList SeriesList) StrokeColor: color, FillColor: dotFillColor, }) - for index, point := range linePoints { + for _, point := range linePoints { seriesPainter.Circle(dotWith, point.X, point.Y) seriesPainter.FillStroke() - if series.Label.Show && index < len(series.Data) { - value := humanize.FtoaWithDigits(series.Data[index].Value, 2) - b := seriesPainter.MeasureText(value) - seriesPainter.Text(value, point.X-b.Width()/2, point.Y) - } - } } diff --git a/range.go b/range.go index ec64c2d..51d3332 100644 --- a/range.go +++ b/range.go @@ -121,9 +121,6 @@ func (r axisRange) Values() []string { } func (r *axisRange) getHeight(value float64) int { - if r.max <= r.min { - return 0 - } v := (value - r.min) / (r.max - r.min) return int(v * float64(r.size)) } diff --git a/series.go b/series.go index da50e64..7bd6834 100644 --- a/series.go +++ b/series.go @@ -26,7 +26,7 @@ import ( "strings" "github.com/dustin/go-humanize" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type SeriesData struct { @@ -79,12 +79,6 @@ type SeriesLabel struct { Show bool // Distance to the host graphic element. Distance int - // The position of label - Position string - // The offset of label's position - Offset Box - // The font size of label - FontSize float64 } const ( @@ -126,8 +120,6 @@ type Series struct { Name string // Radius for Pie chart, e.g.: 40%, default is "40%" Radius string - // Round for bar chart - RoundRadius int // Mark point for series MarkPoint SeriesMarkPoint // Make line for series @@ -281,14 +273,6 @@ func NewPieLabelFormatter(seriesNames []string, layout string) LabelFormatter { return NewLabelFormatter(seriesNames, layout) } -// NewFunnelLabelFormatter returns a funner label formatter -func NewFunnelLabelFormatter(seriesNames []string, layout string) LabelFormatter { - if len(layout) == 0 { - layout = "{b}({d})" - } - return NewLabelFormatter(seriesNames, layout) -} - // NewValueLabelFormatter returns a value formatter func NewValueLabelFormatter(seriesNames []string, layout string) LabelFormatter { if len(layout) == 0 { diff --git a/series_label.go b/series_label.go index af873fc..57bd1bf 100644 --- a/series_label.go +++ b/series_label.go @@ -24,7 +24,7 @@ package charts import ( "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" + "github.com/wcharczuk/go-chart/v2" ) type labelRenderValue struct { @@ -32,8 +32,6 @@ type labelRenderValue struct { Style Style X int Y int - // 旋转 - Radians float64 } type LabelValue struct { @@ -41,14 +39,6 @@ type LabelValue struct { Value float64 X int Y int - // 旋转 - Radians float64 - // 字体颜色 - FontColor Color - // 字体大小 - FontSize float64 - Orient string - Offset Box } type SeriesLabelPainter struct { @@ -91,58 +81,27 @@ func (o *SeriesLabelPainter) Add(value LabelValue) { FontSize: labelFontSize, Font: o.font, } - if value.FontSize != 0 { - labelStyle.FontSize = value.FontSize - } - if !value.FontColor.IsZero() { - label.Color = value.FontColor - } if !label.Color.IsZero() { labelStyle.FontColor = label.Color } - p := o.p - p.OverrideDrawingStyle(labelStyle) - rotated := value.Radians != 0 - if rotated { - p.SetTextRotation(value.Radians) - } - textBox := p.MeasureText(text) + o.p.OverrideDrawingStyle(labelStyle) + textBox := o.p.MeasureText(text) renderValue := labelRenderValue{ - Text: text, - Style: labelStyle, - X: value.X, - Y: value.Y, - Radians: value.Radians, + Text: text, + Style: labelStyle, + X: value.X - textBox.Width()>>1, + Y: value.Y - distance, } - if value.Orient != OrientHorizontal { - renderValue.X -= textBox.Width() >> 1 - renderValue.Y -= distance - } else { - renderValue.X += distance - renderValue.Y += textBox.Height() >> 1 - renderValue.Y -= 2 + if textBox.Width()%2 != 0 { + renderValue.X++ } - if rotated { - renderValue.X = value.X + textBox.Width()>>1 - 1 - p.ClearTextRotation() - } else { - if textBox.Width()%2 != 0 { - renderValue.X++ - } - } - renderValue.X += value.Offset.Left - renderValue.Y += value.Offset.Top o.values = append(o.values, renderValue) } func (o *SeriesLabelPainter) Render() (Box, error) { for _, item := range o.values { o.p.OverrideTextStyle(item.Style) - if item.Radians != 0 { - o.p.TextRotation(item.Text, item.X, item.Y, item.Radians) - } else { - o.p.Text(item.Text, item.X, item.Y) - } + o.p.Text(item.Text, item.X, item.Y) } return chart.BoxZero, nil } diff --git a/table.go b/table.go index 3e6f273..86ef569 100644 --- a/table.go +++ b/table.go @@ -26,8 +26,8 @@ import ( "errors" "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) type tableChart struct { diff --git a/theme.go b/theme.go index 85016a5..8068687 100644 --- a/theme.go +++ b/theme.go @@ -24,7 +24,8 @@ package charts import ( "github.com/golang/freetype/truetype" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) const ThemeDark = "dark" @@ -76,19 +77,6 @@ const defaultFontSize = 12.0 var defaultTheme ColorPalette -var defaultLightFontColor = drawing.Color{ - R: 70, - G: 70, - B: 70, - A: 255, -} -var defaultDarkFontColor = drawing.Color{ - R: 238, - G: 238, - B: 238, - A: 255, -} - func init() { echartSeriesColors := []Color{ parseColor("#5470c6"), @@ -323,7 +311,7 @@ func (t *themeColorPalette) GetFont() *truetype.Font { if t.font != nil { return t.font } - f, _ := GetDefaultFont() + f, _ := chart.GetDefaultFont() return f } diff --git a/util.go b/util.go index 87ff31c..f8a451e 100644 --- a/util.go +++ b/util.go @@ -29,8 +29,8 @@ import ( "strings" "github.com/dustin/go-humanize" - "git.smarteching.com/zeni/go-chart/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TrueFlag() *bool { @@ -262,10 +262,3 @@ func getPolygonPoints(center Point, radius float64, sides int) []Point { } return points } - -func isLightColor(c Color) bool { - r := float64(c.R) * float64(c.R) * 0.299 - g := float64(c.G) * float64(c.G) * 0.587 - b := float64(c.B) * float64(c.B) * 0.114 - return math.Sqrt(r+g+b) > 127.5 -} diff --git a/util_test.go b/util_test.go index 5770776..7c2ab2f 100644 --- a/util_test.go +++ b/util_test.go @@ -26,8 +26,8 @@ import ( "testing" "github.com/stretchr/testify/assert" - "git.smarteching.com/zeni/go-chart/v2" - "git.smarteching.com/zeni/go-chart/v2/drawing" + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" ) func TestGetDefaultInt(t *testing.T) { @@ -189,35 +189,3 @@ func TestParseColor(t *testing.T) { A: 250, }, c) } - -func TestIsLightColor(t *testing.T) { - assert := assert.New(t) - - assert.True(isLightColor(drawing.Color{ - R: 255, - G: 255, - B: 255, - })) - assert.True(isLightColor(drawing.Color{ - R: 145, - G: 204, - B: 117, - })) - - assert.False(isLightColor(drawing.Color{ - R: 88, - G: 112, - B: 198, - })) - - assert.False(isLightColor(drawing.Color{ - R: 0, - G: 0, - B: 0, - })) - assert.False(isLightColor(drawing.Color{ - R: 16, - G: 12, - B: 42, - })) -} diff --git a/xaxis.go b/xaxis.go index 61698d7..00636a5 100644 --- a/xaxis.go +++ b/xaxis.go @@ -47,13 +47,7 @@ type XAxisOption struct { // The line color of axis StrokeColor Color // The color of label - FontColor Color - // The text rotation of label - TextRotation float64 - // The first axis - FirstAxis int - // The offset of label - LabelOffset Box + FontColor Color isValueAxis bool } @@ -87,9 +81,6 @@ func (opt *XAxisOption) ToAxisOption() AxisOption { FontColor: opt.FontColor, Show: opt.Show, SplitLineColor: opt.Theme.GetAxisSplitLineColor(), - TextRotation: opt.TextRotation, - LabelOffset: opt.LabelOffset, - FirstAxis: opt.FirstAxis, } if opt.isValueAxis { axisOpt.SplitLineShow = true diff --git a/yaxis.go b/yaxis.go index e58b7a6..bece2cc 100644 --- a/yaxis.go +++ b/yaxis.go @@ -50,8 +50,6 @@ type YAxisOption struct { DivideCount int Unit int isCategoryAxis bool - // The flag for show axis split line, set this to true will show axis split line - SplitLineShow *bool } // NewYAxisOptions returns a y axis option @@ -102,9 +100,6 @@ func (opt *YAxisOption) ToAxisOption(p *Painter) AxisOption { axisOpt.StrokeWidth = 1 axisOpt.SplitLineShow = false } - if opt.SplitLineShow != nil { - axisOpt.SplitLineShow = *opt.SplitLineShow - } return axisOpt }