From dc1a89d3ff8937afc58a4f90a6c935d11aa859ab Mon Sep 17 00:00:00 2001 From: vicanso Date: Thu, 25 Aug 2022 20:19:05 +0800 Subject: [PATCH] feat: support fill area of line chart --- .gitignore | 1 + chart_option.go | 2 + charts.go | 1 + examples/area_line_chart/main.go | 74 ++++++++++++++++++++++++++++++++ examples/charts/main.go | 31 +++++++++++++ line_chart.go | 22 +++++++++- 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 examples/area_line_chart/main.go diff --git a/.gitignore b/.gitignore index 4a7b0d9..57206ee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ *.svg tmp NotoSansSC.ttf +.vscode \ No newline at end of file diff --git a/chart_option.go b/chart_option.go index 58001bd..93b81ba 100644 --- a/chart_option.go +++ b/chart_option.go @@ -66,6 +66,8 @@ type ChartOption struct { SymbolShow *bool // The stroke width of line chart LineStrokeWidth float64 + // Fill the area of line chart + FillArea bool // The child charts Children []ChartOption } diff --git a/charts.go b/charts.go index 185e638..849f0c7 100644 --- a/charts.go +++ b/charts.go @@ -381,6 +381,7 @@ func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) { XAxis: opt.XAxis, SymbolShow: opt.SymbolShow, StrokeWidth: opt.LineStrokeWidth, + FillArea: opt.FillArea, }).render(renderResult, lineSeriesList) return err }) diff --git a/examples/area_line_chart/main.go b/examples/area_line_chart/main.go new file mode 100644 index 0000000..7a84df0 --- /dev/null +++ b/examples/area_line_chart/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/vicanso/go-charts/v2" +) + +func writeFile(buf []byte) error { + tmpPath := "./tmp" + err := os.MkdirAll(tmpPath, 0700) + if err != nil { + return err + } + + file := filepath.Join(tmpPath, "area-line-chart.png") + err = ioutil.WriteFile(file, buf, 0600) + if err != nil { + return err + } + return nil +} + +func main() { + values := [][]float64{ + { + 120, + 132, + 101, + 134, + 90, + 230, + 210, + }, + } + p, err := charts.LineRender( + values, + charts.TitleTextOptionFunc("Line"), + charts.XAxisDataOptionFunc([]string{ + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun", + }), + charts.LegendLabelsOptionFunc([]string{ + "Email", + }, "50"), + func(opt *charts.ChartOption) { + opt.Legend.Padding = charts.Box{ + Top: 5, + Bottom: 10, + } + opt.FillArea = true + }, + ) + + 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/examples/charts/main.go b/examples/charts/main.go index 7b14919..c3bb486 100644 --- a/examples/charts/main.go +++ b/examples/charts/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "fmt" "net/http" "strconv" @@ -261,6 +262,35 @@ func indexHandler(w http.ResponseWriter, req *http.Request) { }, }, }, + { + Title: charts.TitleOption{ + Text: "Line Area", + }, + Legend: charts.NewLegendOption([]string{ + "Email", + }), + XAxis: charts.NewXAxisOption([]string{ + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun", + }), + SeriesList: []charts.Series{ + charts.NewSeriesFromValues([]float64{ + 120, + 132, + 101, + 134, + 90, + 230, + 210, + }), + }, + FillArea: true, + }, // 柱状图 { Title: charts.TitleOption{ @@ -1935,5 +1965,6 @@ func echartsHandler(w http.ResponseWriter, req *http.Request) { func main() { http.HandleFunc("/", indexHandler) http.HandleFunc("/echarts", echartsHandler) + fmt.Println("http://127.0.0.1:3012/") http.ListenAndServe(":3012", nil) } diff --git a/line_chart.go b/line_chart.go index 3942d70..0b44cdf 100644 --- a/line_chart.go +++ b/line_chart.go @@ -64,6 +64,8 @@ type LineChartOption struct { SymbolShow *bool // The stroke width of line StrokeWidth float64 + // Fill the area of line + FillArea bool // background is filled backgroundIsFilled bool } @@ -109,7 +111,6 @@ func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) ( StrokeWidth: strokeWidth, } - seriesPainter.SetDrawingStyle(drawingStyle) yRange := result.axisRanges[series.AxisIndex] points := make([]Point, 0) for i, item := range series.Data { @@ -120,6 +121,25 @@ func (l *lineChart) render(result *defaultRenderResult, seriesList SeriesList) ( } points = append(points, p) } + // 如果需要填充区域 + if opt.FillArea { + areaPoints := make([]Point, len(points)) + copy(areaPoints, points) + bottomY := yRange.getRestHeight(yRange.min) + areaPoints = append(areaPoints, Point{ + X: areaPoints[len(areaPoints)-1].X, + Y: bottomY, + }, Point{ + X: areaPoints[0].X, + Y: bottomY, + }, areaPoints[0]) + seriesPainter.SetDrawingStyle(Style{ + FillColor: seriesColor.WithAlpha(200), + }) + seriesPainter.FillArea(areaPoints) + } + seriesPainter.SetDrawingStyle(drawingStyle) + // 画线 seriesPainter.LineStroke(points)