diff --git a/charts.go b/charts.go index 591ebea..6a2f5f2 100644 --- a/charts.go +++ b/charts.go @@ -27,16 +27,92 @@ type Renderer interface { } type defaultRenderOption struct { - Theme ColorPalette - Padding Box + Theme ColorPalette + Padding Box + SeriesList SeriesList + // The y axis option + YAxisOptions []YAxisOption + // The x axis option + XAxis XAxisOption } -func defaultRender(p *Painter, opt defaultRenderOption) *Painter { +type defaultRenderResult struct { + axisRanges map[int]axisRange + p *Painter +} + +func defaultRender(p *Painter, opt defaultRenderOption) (*defaultRenderResult, error) { p.SetBackground(p.Width(), p.Height(), opt.Theme.GetBackgroundColor()) if !opt.Padding.IsZero() { p = p.Child(PainterPaddingOption(opt.Padding)) } - return p + result := defaultRenderResult{ + axisRanges: make(map[int]axisRange), + } + + // 计算图表对应的轴有哪些 + axisIndexList := make([]int, 0) + for _, series := range opt.SeriesList { + if containsInt(axisIndexList, series.AxisIndex) { + continue + } + axisIndexList = append(axisIndexList, series.index) + } + // 高度需要减去x轴的高度 + rangeHeight := p.Height() - defaultXAxisHeight + rangeWidth := 0 + + // 计算对应的axis range + for _, index := range axisIndexList { + max, min := opt.SeriesList.GetMaxMin(index) + r := NewRange(AxisRangeOption{ + Min: min, + Max: max, + // 高度需要减去x轴的高度 + Size: rangeHeight, + // 分隔数量 + DivideCount: defaultAxisDivideCount, + }) + result.axisRanges[index] = r + yAxisOption := YAxisOption{} + if len(opt.YAxisOptions) > index { + yAxisOption = opt.YAxisOptions[index] + } + if yAxisOption.Theme == nil { + yAxisOption.Theme = opt.Theme + } + yAxisOption.Data = r.Values() + reverseStringSlice(yAxisOption.Data) + // TODO生成其它位置既yAxis + yAxis := NewLeftYAxis(p, yAxisOption) + yAxisBox, err := yAxis.Render() + if err != nil { + return nil, err + } + rangeWidth += yAxisBox.Width() + } + + if opt.XAxis.Theme == nil { + opt.XAxis.Theme = opt.Theme + } + xAxis := NewBottomXAxis(p.Child(PainterPaddingOption(Box{ + Left: rangeWidth, + })), opt.XAxis) + _, err := xAxis.Render() + if err != nil { + return nil, err + } + + // // 生成Y轴 + // for _, yAxisOption := range opt.YAxisOptions { + + // } + + result.p = p.Child(PainterPaddingOption(Box{ + Bottom: rangeHeight, + Left: rangeWidth, + })) + return &result, nil } func doRender(renderers ...Renderer) error { diff --git a/line_chart.go b/line_chart.go index 9640087..3d93341 100644 --- a/line_chart.go +++ b/line_chart.go @@ -50,53 +50,28 @@ type LineChartOption struct { // The padding of line chart Padding Box // The y axis option - YAxis YAxisOption + YAxisOptions []YAxisOption } func (l *lineChart) Render() (Box, error) { p := l.p opt := l.opt - p = defaultRender(p, defaultRenderOption{ - Theme: opt.Theme, - Padding: opt.Padding, - }) - seriesList := opt.SeriesList seriesList.init() - // 过滤前先计算最大最小值 - max, min := seriesList.GetMaxMin() - - seriesList = seriesList.Filter(ChartTypeLine) - - // Y轴 - yr := NewRange(AxisRangeOption{ - Min: min, - Max: max, - // 高度需要减去x轴的高度 - Size: p.Height() - defaultXAxisHeight, - DivideCount: defaultAxisDivideCount, + renderResult, err := defaultRender(p, defaultRenderOption{ + Theme: opt.Theme, + Padding: opt.Padding, + SeriesList: seriesList, + XAxis: opt.XAxis, + YAxisOptions: opt.YAxisOptions, }) - if opt.YAxis.Theme == nil { - opt.YAxis.Theme = opt.Theme - } - opt.YAxis.Data = yr.Values() - reverseStringSlice(opt.YAxis.Data) - yAxis := NewLeftYAxis(p, opt.YAxis) - yAxisBox, err := yAxis.Render() if err != nil { return chart.BoxZero, err } - seriesPainter := p.Child(PainterPaddingOption(Box{ - Bottom: defaultXAxisHeight, - Left: yAxisBox.Width(), - })) - if opt.XAxis.Theme == nil { - opt.XAxis.Theme = opt.Theme - } - xAxis := NewBottomXAxis(p.Child(PainterPaddingOption(Box{ - Left: yAxisBox.Width(), - })), opt.XAxis) + seriesList = seriesList.Filter(ChartTypeLine) + + seriesPainter := renderResult.p xDivideValues := autoDivide(seriesPainter.Width(), len(opt.XAxis.Data)) xValues := make([]int, len(xDivideValues)-1) @@ -110,6 +85,7 @@ func (l *lineChart) Render() (Box, error) { StrokeWidth: 2, FillColor: seriesColor, }) + yr := renderResult.axisRanges[series.AxisIndex] points := make([]Point, 0) for i, item := range series.Data { h := yr.getRestHeight(item.Value) @@ -123,12 +99,5 @@ func (l *lineChart) Render() (Box, error) { seriesPainter.Dots(points) } - err = doRender( - xAxis, - ) - if err != nil { - return chart.BoxZero, err - } - return p.box, nil } diff --git a/series.go b/series.go index 07bd5d9..2888f30 100644 --- a/series.go +++ b/series.go @@ -99,8 +99,8 @@ type Series struct { // The data list of series Data []SeriesData // The Y axis index, it should be 0 or 1. - // Default value is 1 - YAxisIndex int + // Default value is 0 + AxisIndex int // The style for series Style chart.Style // The label for series @@ -143,10 +143,13 @@ func (sl SeriesList) Filter(chartType string) SeriesList { } // GetMaxMin get max and min value of series list -func (sl SeriesList) GetMaxMin() (float64, float64) { +func (sl SeriesList) GetMaxMin(axisIndex int) (float64, float64) { min := math.MaxFloat64 max := -math.MaxFloat64 for _, series := range sl { + if series.AxisIndex != axisIndex { + continue + } for _, item := range series.Data { if item.Value > max { max = item.Value