* Add stacked bar chart value labels (#60)
* Add horizontal render option to stacked bar chart (#39)
* Pulling 100% inside the canvasBox to remain visible.
* Use correct margins for YAxis.TextHorizontalAlign: chart.TextHorizontalAlignRight
* Fixed Show to Hidden due to 5f42a580a9
This commit is contained in:
parent
3a7bc55431
commit
962b9abdec
7 changed files with 688 additions and 8 deletions
222
_examples/horizontal_stacked_bar/main.go
Normal file
222
_examples/horizontal_stacked_bar/main.go
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
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 := 80
|
||||||
|
|
||||||
|
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: 75,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
XAxis: chart.StyleShow(),
|
||||||
|
YAxis: chart.StyleShow(),
|
||||||
|
BarSpacing: 40,
|
||||||
|
IsHorizontal: true,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
BIN
_examples/horizontal_stacked_bar/output.png
Normal file
BIN
_examples/horizontal_stacked_bar/output.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
221
_examples/stacked_bar_labels/main.go
Normal file
221
_examples/stacked_bar_labels/main.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
BIN
_examples/stacked_bar_labels/output.png
Normal file
BIN
_examples/stacked_bar_labels/output.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
6
draw.go
6
draw.go
|
@ -296,8 +296,10 @@ func (d draw) TextWithin(r Renderer, text string, box Box, style Style) {
|
||||||
switch style.GetTextVerticalAlign() {
|
switch style.GetTextVerticalAlign() {
|
||||||
case TextVerticalAlignBottom, TextVerticalAlignBaseline: // i have to build better baseline handling into measure text
|
case TextVerticalAlignBottom, TextVerticalAlignBaseline: // i have to build better baseline handling into measure text
|
||||||
y = y - linesBox.Height()
|
y = y - linesBox.Height()
|
||||||
case TextVerticalAlignMiddle, TextVerticalAlignMiddleBaseline:
|
case TextVerticalAlignMiddle:
|
||||||
y = (y - linesBox.Height()) >> 1
|
y = y + (box.Height() >> 1) - (linesBox.Height() >> 1)
|
||||||
|
case TextVerticalAlignMiddleBaseline:
|
||||||
|
y = y + (box.Height() >> 1) - linesBox.Height()
|
||||||
}
|
}
|
||||||
|
|
||||||
var tx, ty int
|
var tx, ty int
|
||||||
|
|
|
@ -46,6 +46,8 @@ type StackedBarChart struct {
|
||||||
Font *truetype.Font
|
Font *truetype.Font
|
||||||
defaultFont *truetype.Font
|
defaultFont *truetype.Font
|
||||||
|
|
||||||
|
IsHorizontal bool
|
||||||
|
|
||||||
Bars []StackedBar
|
Bars []StackedBar
|
||||||
Elements []Renderable
|
Elements []Renderable
|
||||||
}
|
}
|
||||||
|
@ -113,11 +115,20 @@ func (sbc StackedBarChart) Render(rp RendererProvider, w io.Writer) error {
|
||||||
}
|
}
|
||||||
r.SetDPI(sbc.GetDPI(DefaultDPI))
|
r.SetDPI(sbc.GetDPI(DefaultDPI))
|
||||||
|
|
||||||
canvasBox := sbc.getAdjustedCanvasBox(r, sbc.getDefaultCanvasBox())
|
var canvasBox Box
|
||||||
sbc.drawCanvas(r, canvasBox)
|
if sbc.IsHorizontal {
|
||||||
sbc.drawBars(r, canvasBox)
|
canvasBox = sbc.getHorizontalAdjustedCanvasBox(r, sbc.getDefaultCanvasBox())
|
||||||
sbc.drawXAxis(r, canvasBox)
|
sbc.drawCanvas(r, canvasBox)
|
||||||
sbc.drawYAxis(r, canvasBox)
|
sbc.drawHorizontalBars(r, canvasBox)
|
||||||
|
sbc.drawHorizontalXAxis(r, canvasBox)
|
||||||
|
sbc.drawHorizontalYAxis(r, canvasBox)
|
||||||
|
} else {
|
||||||
|
canvasBox = sbc.getAdjustedCanvasBox(r, sbc.getDefaultCanvasBox())
|
||||||
|
sbc.drawCanvas(r, canvasBox)
|
||||||
|
sbc.drawBars(r, canvasBox)
|
||||||
|
sbc.drawXAxis(r, canvasBox)
|
||||||
|
sbc.drawYAxis(r, canvasBox)
|
||||||
|
}
|
||||||
|
|
||||||
sbc.drawTitle(r)
|
sbc.drawTitle(r)
|
||||||
for _, a := range sbc.Elements {
|
for _, a := range sbc.Elements {
|
||||||
|
@ -139,6 +150,14 @@ func (sbc StackedBarChart) drawBars(r Renderer, canvasBox Box) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) drawHorizontalBars(r Renderer, canvasBox Box) {
|
||||||
|
yOffset := canvasBox.Top
|
||||||
|
for _, bar := range sbc.Bars {
|
||||||
|
sbc.drawHorizontalBar(r, canvasBox, yOffset, bar)
|
||||||
|
yOffset += sbc.GetBarSpacing() + bar.GetWidth()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sbc StackedBarChart) drawBar(r Renderer, canvasBox Box, xoffset int, bar StackedBar) int {
|
func (sbc StackedBarChart) drawBar(r Renderer, canvasBox Box, xoffset int, bar StackedBar) int {
|
||||||
barSpacing2 := sbc.GetBarSpacing() >> 1
|
barSpacing2 := sbc.GetBarSpacing() >> 1
|
||||||
bxl := xoffset + barSpacing2
|
bxl := xoffset + barSpacing2
|
||||||
|
@ -158,9 +177,85 @@ func (sbc StackedBarChart) drawBar(r Renderer, canvasBox Box, xoffset int, bar S
|
||||||
yoffset += barHeight
|
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
|
return bxr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) drawHorizontalBar(r Renderer, canvasBox Box, yoffset int, bar StackedBar) {
|
||||||
|
halfBarSpacing := sbc.GetBarSpacing() >> 1
|
||||||
|
|
||||||
|
boxTop := yoffset + halfBarSpacing
|
||||||
|
boxBottom := boxTop + bar.GetWidth()
|
||||||
|
|
||||||
|
normalizedBarComponents := Values(bar.Values).Normalize()
|
||||||
|
|
||||||
|
xOffset := canvasBox.Right
|
||||||
|
for index, bv := range normalizedBarComponents {
|
||||||
|
barHeight := int(math.Ceil(bv.Value * float64(canvasBox.Width())))
|
||||||
|
barBox := Box{
|
||||||
|
Top: boxTop,
|
||||||
|
Left: MinInt(xOffset-barHeight, canvasBox.Left+DefaultStrokeWidth),
|
||||||
|
Right: xOffset,
|
||||||
|
Bottom: boxBottom,
|
||||||
|
}
|
||||||
|
Draw.Box(r, barBox, bv.Style.InheritFrom(sbc.styleDefaultsStackedBarValue(index)))
|
||||||
|
xOffset -= barHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the labels
|
||||||
|
xOffset = canvasBox.Right
|
||||||
|
var lx, ly int
|
||||||
|
for index, bv := range normalizedBarComponents {
|
||||||
|
barHeight := int(math.Ceil(bv.Value * float64(canvasBox.Width())))
|
||||||
|
|
||||||
|
if len(bv.Label) > 0 {
|
||||||
|
lx = xOffset - (barHeight / 2)
|
||||||
|
ly = boxTop + ((boxBottom - boxTop) / 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)
|
||||||
|
}
|
||||||
|
xOffset -= barHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sbc StackedBarChart) drawXAxis(r Renderer, canvasBox Box) {
|
func (sbc StackedBarChart) drawXAxis(r Renderer, canvasBox Box) {
|
||||||
if !sbc.XAxis.Hidden {
|
if !sbc.XAxis.Hidden {
|
||||||
axisStyle := sbc.XAxis.InheritFrom(sbc.styleDefaultsAxes())
|
axisStyle := sbc.XAxis.InheritFrom(sbc.styleDefaultsAxes())
|
||||||
|
@ -195,6 +290,42 @@ func (sbc StackedBarChart) drawXAxis(r Renderer, canvasBox Box) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) drawHorizontalXAxis(r Renderer, canvasBox Box) {
|
||||||
|
if !sbc.XAxis.Hidden {
|
||||||
|
axisStyle := sbc.XAxis.InheritFrom(sbc.styleDefaultsAxes())
|
||||||
|
axisStyle.WriteToRenderer(r)
|
||||||
|
r.MoveTo(canvasBox.Left, canvasBox.Bottom)
|
||||||
|
r.LineTo(canvasBox.Right, canvasBox.Bottom)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
r.MoveTo(canvasBox.Left, canvasBox.Bottom)
|
||||||
|
r.LineTo(canvasBox.Left, canvasBox.Bottom+DefaultVerticalTickHeight)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
ticks := LinearRangeWithStep(0.0, 1.0, 0.2)
|
||||||
|
for _, t := range ticks {
|
||||||
|
axisStyle.GetStrokeOptions().WriteToRenderer(r)
|
||||||
|
tx := canvasBox.Left + int(t*float64(canvasBox.Width()))
|
||||||
|
r.MoveTo(tx, canvasBox.Bottom)
|
||||||
|
r.LineTo(tx, canvasBox.Bottom+DefaultVerticalTickHeight)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
axisStyle.GetTextOptions().WriteToRenderer(r)
|
||||||
|
text := fmt.Sprintf("%0.0f%%", t*100)
|
||||||
|
|
||||||
|
textBox := r.MeasureText(text)
|
||||||
|
textX := tx - (textBox.Width() >> 1)
|
||||||
|
textY := canvasBox.Bottom + DefaultXAxisMargin + 10
|
||||||
|
|
||||||
|
if t == 1 {
|
||||||
|
textX = canvasBox.Right - textBox.Width()
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw.Text(r, text, textX, textY, axisStyle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sbc StackedBarChart) drawYAxis(r Renderer, canvasBox Box) {
|
func (sbc StackedBarChart) drawYAxis(r Renderer, canvasBox Box) {
|
||||||
if !sbc.YAxis.Hidden {
|
if !sbc.YAxis.Hidden {
|
||||||
axisStyle := sbc.YAxis.InheritFrom(sbc.styleDefaultsAxes())
|
axisStyle := sbc.YAxis.InheritFrom(sbc.styleDefaultsAxes())
|
||||||
|
@ -221,7 +352,39 @@ func (sbc StackedBarChart) drawYAxis(r Renderer, canvasBox Box) {
|
||||||
tb := r.MeasureText(text)
|
tb := r.MeasureText(text)
|
||||||
Draw.Text(r, text, canvasBox.Right+DefaultYAxisMargin+5, ty+(tb.Height()>>1), axisStyle)
|
Draw.Text(r, text, canvasBox.Right+DefaultYAxisMargin+5, ty+(tb.Height()>>1), axisStyle)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) drawHorizontalYAxis(r Renderer, canvasBox Box) {
|
||||||
|
if !sbc.YAxis.Hidden {
|
||||||
|
axisStyle := sbc.YAxis.InheritFrom(sbc.styleDefaultsHorizontalAxes())
|
||||||
|
axisStyle.WriteToRenderer(r)
|
||||||
|
|
||||||
|
r.MoveTo(canvasBox.Left, canvasBox.Bottom)
|
||||||
|
r.LineTo(canvasBox.Left, canvasBox.Top)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
r.MoveTo(canvasBox.Left, canvasBox.Bottom)
|
||||||
|
r.LineTo(canvasBox.Left-DefaultHorizontalTickWidth, canvasBox.Bottom)
|
||||||
|
r.Stroke()
|
||||||
|
|
||||||
|
cursor := canvasBox.Top
|
||||||
|
for _, bar := range sbc.Bars {
|
||||||
|
barLabelBox := Box{
|
||||||
|
Top: cursor,
|
||||||
|
Left: 0,
|
||||||
|
Right: canvasBox.Left - DefaultYAxisMargin,
|
||||||
|
Bottom: cursor + bar.GetWidth() + sbc.GetBarSpacing(),
|
||||||
|
}
|
||||||
|
if len(bar.Name) > 0 {
|
||||||
|
Draw.TextWithin(r, bar.Name, barLabelBox, axisStyle)
|
||||||
|
}
|
||||||
|
axisStyle.WriteToRenderer(r)
|
||||||
|
r.MoveTo(canvasBox.Left, barLabelBox.Bottom)
|
||||||
|
r.LineTo(canvasBox.Left-DefaultHorizontalTickWidth, barLabelBox.Bottom)
|
||||||
|
r.Stroke()
|
||||||
|
cursor += bar.GetWidth() + sbc.GetBarSpacing()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +474,48 @@ func (sbc StackedBarChart) getAdjustedCanvasBox(r Renderer, canvasBox Box) Box {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) getHorizontalAdjustedCanvasBox(r Renderer, canvasBox Box) Box {
|
||||||
|
var totalHeight int
|
||||||
|
for _, bar := range sbc.Bars {
|
||||||
|
totalHeight += bar.GetWidth() + sbc.GetBarSpacing()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sbc.YAxis.Hidden {
|
||||||
|
yAxisWidth := DefaultHorizontalTickWidth
|
||||||
|
|
||||||
|
axisStyle := sbc.YAxis.InheritFrom(sbc.styleDefaultsHorizontalAxes())
|
||||||
|
axisStyle.WriteToRenderer(r)
|
||||||
|
|
||||||
|
cursor := canvasBox.Top
|
||||||
|
for _, bar := range sbc.Bars {
|
||||||
|
if len(bar.Name) > 0 {
|
||||||
|
barLabelBox := Box{
|
||||||
|
Top: cursor,
|
||||||
|
Left: 0,
|
||||||
|
Right: canvasBox.Left + DefaultYAxisMargin,
|
||||||
|
Bottom: cursor + bar.GetWidth() + sbc.GetBarSpacing(),
|
||||||
|
}
|
||||||
|
lines := Text.WrapFit(r, bar.Name, barLabelBox.Width(), axisStyle)
|
||||||
|
linesBox := Text.MeasureLines(r, lines, axisStyle)
|
||||||
|
|
||||||
|
yAxisWidth = MaxInt(linesBox.Height()+(2*DefaultXAxisMargin), yAxisWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Box{
|
||||||
|
Top: canvasBox.Top,
|
||||||
|
Left: canvasBox.Left + yAxisWidth,
|
||||||
|
Right: canvasBox.Right,
|
||||||
|
Bottom: canvasBox.Top + totalHeight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Box{
|
||||||
|
Top: canvasBox.Top,
|
||||||
|
Left: canvasBox.Left,
|
||||||
|
Right: canvasBox.Right,
|
||||||
|
Bottom: canvasBox.Top + totalHeight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Box returns the chart bounds as a box.
|
// Box returns the chart bounds as a box.
|
||||||
func (sbc StackedBarChart) Box() Box {
|
func (sbc StackedBarChart) Box() Box {
|
||||||
dpr := sbc.Background.Padding.GetRight(10)
|
dpr := sbc.Background.Padding.GetRight(10)
|
||||||
|
@ -329,6 +534,9 @@ func (sbc StackedBarChart) styleDefaultsStackedBarValue(index int) Style {
|
||||||
StrokeColor: sbc.GetColorPalette().GetSeriesColor(index),
|
StrokeColor: sbc.GetColorPalette().GetSeriesColor(index),
|
||||||
StrokeWidth: 3.0,
|
StrokeWidth: 3.0,
|
||||||
FillColor: sbc.GetColorPalette().GetSeriesColor(index),
|
FillColor: sbc.GetColorPalette().GetSeriesColor(index),
|
||||||
|
FontSize: sbc.getScaledFontSize(),
|
||||||
|
FontColor: sbc.GetColorPalette().TextColor(),
|
||||||
|
Font: sbc.GetFont(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,6 +551,20 @@ func (sbc StackedBarChart) styleDefaultsTitle() Style {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) getScaledFontSize() float64 {
|
||||||
|
effectiveDimension := 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 {
|
func (sbc StackedBarChart) getTitleFontSize() float64 {
|
||||||
effectiveDimension := MinInt(sbc.GetWidth(), sbc.GetHeight())
|
effectiveDimension := MinInt(sbc.GetWidth(), sbc.GetHeight())
|
||||||
if effectiveDimension >= 2048 {
|
if effectiveDimension >= 2048 {
|
||||||
|
@ -368,6 +590,19 @@ func (sbc StackedBarChart) styleDefaultsAxes() Style {
|
||||||
TextWrap: TextWrapWord,
|
TextWrap: TextWrapWord,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sbc StackedBarChart) styleDefaultsHorizontalAxes() Style {
|
||||||
|
return Style{
|
||||||
|
StrokeColor: DefaultAxisColor,
|
||||||
|
Font: sbc.GetFont(),
|
||||||
|
FontSize: DefaultAxisFontSize,
|
||||||
|
FontColor: DefaultAxisColor,
|
||||||
|
TextHorizontalAlign: TextHorizontalAlignCenter,
|
||||||
|
TextVerticalAlign: TextVerticalAlignMiddle,
|
||||||
|
TextWrap: TextWrapWord,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sbc StackedBarChart) styleDefaultsElements() Style {
|
func (sbc StackedBarChart) styleDefaultsElements() Style {
|
||||||
return Style{
|
return Style{
|
||||||
Font: sbc.GetFont(),
|
Font: sbc.GetFont(),
|
||||||
|
|
2
text.go
2
text.go
|
@ -46,7 +46,7 @@ const (
|
||||||
TextVerticalAlignBottom TextVerticalAlign = 2
|
TextVerticalAlignBottom TextVerticalAlign = 2
|
||||||
// TextVerticalAlignMiddle aligns the text so that there is an equal amount of space above and below the top and bottom of the ligatures.
|
// TextVerticalAlignMiddle aligns the text so that there is an equal amount of space above and below the top and bottom of the ligatures.
|
||||||
TextVerticalAlignMiddle TextVerticalAlign = 3
|
TextVerticalAlignMiddle TextVerticalAlign = 3
|
||||||
// TextVerticalAlignMiddleBaseline aligns the text veritcally so that there is an equal number of pixels above and below the baseline of the string.
|
// TextVerticalAlignMiddleBaseline aligns the text vertically so that there is an equal number of pixels above and below the baseline of the string.
|
||||||
TextVerticalAlignMiddleBaseline TextVerticalAlign = 4
|
TextVerticalAlignMiddleBaseline TextVerticalAlign = 4
|
||||||
// TextVerticalAlignTop alignts the text so that the top of the ligatures are at y-pixel 0 in the container.
|
// TextVerticalAlignTop alignts the text so that the top of the ligatures are at y-pixel 0 in the container.
|
||||||
TextVerticalAlignTop TextVerticalAlign = 5
|
TextVerticalAlignTop TextVerticalAlign = 5
|
||||||
|
|
Loading…
Reference in a new issue