diff --git a/.gitignore b/.gitignore index 66fd13c..cb43a6a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ # Dependency directories (remove the comment below to include it) # vendor/ +*.png \ No newline at end of file diff --git a/axis.go b/axis.go new file mode 100644 index 0000000..50e9f22 --- /dev/null +++ b/axis.go @@ -0,0 +1,100 @@ +// 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 ( + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" +) + +type ( + // AxisData string + XAxis struct { + // 'value' 数值轴,适用于连续数据。 + // 'category' 类目轴,适用于离散的类目数据。为该类型时类目数据可自动从 series.data 或 dataset.source 中取,或者可通过 xAxis.data 设置类目数据。 + // 'time' 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,在刻度计算上也有所不同,例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。 + // 'log' 对数轴。适用于对数数据。 + Type string + Data []string + } +) + +const axisStrokeWidth = 1 + +func GetXAxisAndValues(xAxis XAxis, theme string) (chart.XAxis, []float64) { + xValues := make([]float64, len(xAxis.Data)) + ticks := make([]chart.Tick, len(xAxis.Data)) + for index, key := range xAxis.Data { + f := float64(index) + xValues[index] = f + ticks[index] = chart.Tick{ + Value: f, + Label: key, + } + } + // TODO + if theme == ThemeDark { + return chart.XAxis{ + Ticks: ticks, + }, xValues + } + return chart.XAxis{ + Ticks: ticks, + Style: chart.Style{ + FontColor: AxisColorLight, + StrokeColor: AxisColorLight, + StrokeWidth: axisStrokeWidth, + }, + }, xValues +} + +func GetYAxis(theme string) chart.YAxis { + // TODO + if theme == ThemeDark { + return chart.YAxis{} + } + strokeColor := drawing.Color{ + R: 224, + G: 230, + B: 241, + A: 255, + } + return chart.YAxis{ + + AxisType: chart.YAxisSecondary, + GridMajorStyle: chart.Style{ + StrokeColor: strokeColor, + StrokeWidth: axisStrokeWidth, + }, + GridMinorStyle: chart.Style{ + StrokeColor: strokeColor, + StrokeWidth: axisStrokeWidth, + }, + Style: chart.Style{ + FontColor: AxisColorLight, + // alpha 0,隐藏 + StrokeColor: hiddenColor, + StrokeWidth: axisStrokeWidth, + }, + } +} diff --git a/charts.go b/charts.go new file mode 100644 index 0000000..89fe750 --- /dev/null +++ b/charts.go @@ -0,0 +1,112 @@ +// 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" + + "github.com/wcharczuk/go-chart/v2" +) + +type ( + Title struct { + Text string + } + Legend struct { + Data []string + } + Option struct { + Width int + Height int + Theme string + XAxis XAxis + // YAxis Axis + Series []Series + Title Title + Legend Legend + } +) + +const ( + ThemeLight = "light" + ThemeDark = "dark" +) + +func render(c *chart.Chart, rp chart.RendererProvider) ([]byte, error) { + buf := bytes.Buffer{} + err := c.Render(rp, &buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func ToPNG(c *chart.Chart) ([]byte, error) { + return render(c, chart.PNG) +} + +func ToSVG(c *chart.Chart) ([]byte, error) { + return render(c, chart.SVG) +} + +func New(opt Option) *chart.Chart { + xAxis, xValues := GetXAxisAndValues(opt.XAxis, opt.Theme) + + legendSize := len(opt.Legend.Data) + for index, item := range opt.Series { + if len(item.XValues) == 0 { + opt.Series[index].XValues = xValues + } + if index < legendSize && opt.Series[index].Name == "" { + opt.Series[index].Name = opt.Legend.Data[index] + } + } + + c := &chart.Chart{ + Title: opt.Title.Text, + Width: opt.Width, + Height: opt.Height, + XAxis: xAxis, + YAxis: GetYAxis(opt.Theme), + Series: GetSeries(opt.Series, opt.Theme), + } + if legendSize != 0 { + c.Elements = []chart.Renderable{ + chart.LegendThin(c, chart.Style{ + FillColor: hiddenColor, + // FillColor: drawing.ColorWhite, + // FontColor: DefaultTextColor, + FontSize: 8.0, + StrokeColor: hiddenColor, + // StrokeWidth: DefaultAxisLineWidth, + // Padding: Box{ + // Top: 2, + // Left: 7, + // Right: 7, + // Bottom: 5, + // }, + }), + } + } + return c +} diff --git a/series.go b/series.go new file mode 100644 index 0000000..c3c0385 --- /dev/null +++ b/series.go @@ -0,0 +1,64 @@ +// 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 ( + "github.com/wcharczuk/go-chart/v2" + "github.com/wcharczuk/go-chart/v2/drawing" +) + +type Series struct { + Type string + Name string + Data []float64 + XValues []float64 +} + +const lineStrokeWidth = 2 +const dotWith = 2 + +func getSeriesColor(theme string, index int) drawing.Color { + // TODO + if theme == ThemeDark { + } + return SeriesColorsLight[index%len(SeriesColorsLight)] +} + +func GetSeries(series []Series, theme string) []chart.Series { + arr := make([]chart.Series, len(series)) + for index, item := range series { + // TODO 判断类型 + arr[index] = chart.ContinuousSeries{ + Name: item.Name, + XValues: item.XValues, + Style: chart.Style{ + StrokeWidth: lineStrokeWidth, + StrokeColor: getSeriesColor(theme, index), + DotColor: getSeriesColor(theme, index), + DotWidth: dotWith, + }, + YValues: item.Data, + } + } + return arr +} diff --git a/theme.go b/theme.go new file mode 100644 index 0000000..4d86a64 --- /dev/null +++ b/theme.go @@ -0,0 +1,67 @@ +// 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 "github.com/wcharczuk/go-chart/v2/drawing" + +var hiddenColor = drawing.Color{R: 110, G: 112, B: 121, A: 0} + +var AxisColorLight = drawing.Color{ + R: 110, + G: 112, + B: 121, + A: 255, +} + +var SeriesColorsLight = []drawing.Color{ + { + R: 84, + G: 112, + B: 198, + A: 255, + }, + { + R: 145, + G: 204, + B: 117, + A: 255, + }, + { + R: 250, + G: 200, + B: 88, + A: 255, + }, + { + R: 238, + G: 102, + B: 102, + A: 255, + }, + { + R: 115, + G: 192, + B: 222, + A: 255, + }, +}