From 21b831a1b19a5ef74474bd9d32068193f56593b6 Mon Sep 17 00:00:00 2001 From: Jamie Isaacs Date: Sun, 3 Mar 2019 03:33:50 -0800 Subject: [PATCH] Add stacked bar chart value labels (#60) --- _examples/stacked_bar_labels/main.go | 221 ++++++++++++++++++++++++ _examples/stacked_bar_labels/output.png | Bin 0 -> 25482 bytes stacked_bar_chart.go | 44 +++++ 3 files changed, 265 insertions(+) create mode 100644 _examples/stacked_bar_labels/main.go create mode 100644 _examples/stacked_bar_labels/output.png diff --git a/_examples/stacked_bar_labels/main.go b/_examples/stacked_bar_labels/main.go new file mode 100644 index 0000000..a04e77b --- /dev/null +++ b/_examples/stacked_bar_labels/main.go @@ -0,0 +1,221 @@ +package main + +import ( + "os" + + "github.com/wcharczuk/go-chart" + "github.com/wcharczuk/go-chart/drawing" +) + +func main() { + chart.DefaultBackgroundColor = chart.ColorTransparent + chart.DefaultCanvasColor = chart.ColorTransparent + + barWidth := 120 + + var ( + colorWhite = drawing.Color{R: 241, G: 241, B: 241, A: 255} + colorMariner = drawing.Color{R: 60, G: 100, B: 148, A: 255} + colorLightSteelBlue = drawing.Color{R: 182, G: 195, B: 220, A: 255} + colorPoloBlue = drawing.Color{R: 126, G: 155, B: 200, A: 255} + colorSteelBlue = drawing.Color{R: 73, G: 120, B: 177, A: 255} + ) + + stackedBarChart := chart.StackedBarChart{ + Title: "Quarterly Sales", + TitleStyle: chart.StyleShow(), + Background: chart.Style{ + Padding: chart.Box{ + Top: 100, + }, + }, + Width: 810, + Height: 500, + XAxis: chart.StyleShow(), + YAxis: chart.StyleShow(), + BarSpacing: 50, + Bars: []chart.StackedBar{ + { + Name: "Q1", + Width: barWidth, + Values: []chart.Value{ + { + Label: "32K", + Value: 32, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorMariner, + FontColor: colorWhite, + }, + }, + { + Label: "46K", + Value: 46, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorLightSteelBlue, + FontColor: colorWhite, + }, + }, + { + Label: "48K", + Value: 48, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorPoloBlue, + FontColor: colorWhite, + }, + }, + { + Label: "42K", + Value: 42, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorSteelBlue, + FontColor: colorWhite, + }, + }, + }, + }, + { + Name: "Q2", + Width: barWidth, + Values: []chart.Value{ + { + Label: "45K", + Value: 45, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorMariner, + FontColor: colorWhite, + }, + }, + { + Label: "60K", + Value: 60, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorLightSteelBlue, + FontColor: colorWhite, + }, + }, + { + Label: "62K", + Value: 62, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorPoloBlue, + FontColor: colorWhite, + }, + }, + { + Label: "53K", + Value: 53, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorSteelBlue, + FontColor: colorWhite, + }, + }, + }, + }, + { + Name: "Q3", + Width: barWidth, + Values: []chart.Value{ + { + Label: "54K", + Value: 54, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorMariner, + FontColor: colorWhite, + }, + }, + { + Label: "58K", + Value: 58, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorLightSteelBlue, + FontColor: colorWhite, + }, + }, + { + Label: "55K", + Value: 55, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorPoloBlue, + FontColor: colorWhite, + }, + }, + { + Label: "47K", + Value: 47, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorSteelBlue, + FontColor: colorWhite, + }, + }, + }, + }, + { + Name: "Q4", + Width: barWidth, + Values: []chart.Value{ + { + Label: "46K", + Value: 46, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorMariner, + FontColor: colorWhite, + }, + }, + { + Label: "70K", + Value: 70, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorLightSteelBlue, + FontColor: colorWhite, + }, + }, + { + Label: "74K", + Value: 74, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorPoloBlue, + FontColor: colorWhite, + }, + }, + { + Label: "60K", + Value: 60, + Style: chart.Style{ + StrokeWidth: .01, + FillColor: colorSteelBlue, + FontColor: colorWhite, + }, + }, + }, + }, + }, + } + + pngFile, err := os.Create("output.png") + if err != nil { + panic(err) + } + + if err := stackedBarChart.Render(chart.PNG, pngFile); err != nil { + panic(err) + } + + if err := pngFile.Close(); err != nil { + panic(err) + } +} diff --git a/_examples/stacked_bar_labels/output.png b/_examples/stacked_bar_labels/output.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f7e9750fdc38249d2c6d58a59eb52968a8c0f0 GIT binary patch literal 25482 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 YZ1#2pRmQzFk6Y4Gf2dZZV)y#L06tYG!2kdN literal 0 HcmV?d00001 diff --git a/stacked_bar_chart.go b/stacked_bar_chart.go index 06db425..a7740cd 100644 --- a/stacked_bar_chart.go +++ b/stacked_bar_chart.go @@ -158,6 +158,33 @@ func (sbc StackedBarChart) drawBar(r Renderer, canvasBox Box, xoffset int, bar S yoffset += barHeight } + // draw the labels + yoffset = canvasBox.Top + var lx, ly int + for index, bv := range normalizedBarComponents { + barHeight := int(math.Ceil(bv.Value * float64(canvasBox.Height()))) + + if len(bv.Label) > 0 { + lx = bxl + ((bxr - bxl) / 2) + ly = yoffset + (barHeight / 2) + + bv.Style.InheritFrom(sbc.styleDefaultsStackedBarValue(index)).WriteToRenderer(r) + tb := r.MeasureText(bv.Label) + lx = lx - (tb.Width() >> 1) + ly = ly + (tb.Height() >> 1) + + if lx < 0 { + lx = 0 + } + if ly < 0 { + lx = 0 + } + + r.Text(bv.Label, lx, ly) + } + yoffset += barHeight + } + return bxr } @@ -329,6 +356,9 @@ func (sbc StackedBarChart) styleDefaultsStackedBarValue(index int) Style { StrokeColor: sbc.GetColorPalette().GetSeriesColor(index), StrokeWidth: 3.0, FillColor: sbc.GetColorPalette().GetSeriesColor(index), + FontSize: sbc.getScaledFontSize(), + FontColor: sbc.GetColorPalette().TextColor(), + Font: sbc.GetFont(), } } @@ -343,6 +373,20 @@ func (sbc StackedBarChart) styleDefaultsTitle() Style { }) } +func (sbc StackedBarChart) getScaledFontSize() float64 { + effectiveDimension := util.Math.MinInt(sbc.GetWidth(), sbc.GetHeight()) + if effectiveDimension >= 2048 { + return 48.0 + } else if effectiveDimension >= 1024 { + return 24.0 + } else if effectiveDimension > 512 { + return 18.0 + } else if effectiveDimension > 256 { + return 12.0 + } + return 10.0 +} + func (sbc StackedBarChart) getTitleFontSize() float64 { effectiveDimension := MinInt(sbc.GetWidth(), sbc.GetHeight()) if effectiveDimension >= 2048 {