feat: implement legend type with fixed length line on the left side
fixes #185
This commit is contained in:
parent
c1468e8ae4
commit
bbad84f537
1 changed files with 118 additions and 0 deletions
118
legend.go
118
legend.go
|
@ -118,6 +118,124 @@ func Legend(c *Chart, userDefaults ...Style) Renderable {
|
|||
}
|
||||
}
|
||||
|
||||
// LegendLineLeft is a legend with the line drawn left to the legend text.
|
||||
func LegendLineLeft(c *Chart, userDefaults ...Style) Renderable {
|
||||
return func(r Renderer, cb Box, chartDefaults Style) {
|
||||
legendDefaults := Style{
|
||||
FillColor: drawing.ColorWhite,
|
||||
FontColor: DefaultTextColor,
|
||||
FontSize: 8.0,
|
||||
StrokeColor: DefaultAxisColor,
|
||||
StrokeWidth: DefaultAxisLineWidth,
|
||||
}
|
||||
|
||||
var legendStyle Style
|
||||
if len(userDefaults) > 0 {
|
||||
legendStyle = userDefaults[0].InheritFrom(chartDefaults.InheritFrom(legendDefaults))
|
||||
} else {
|
||||
legendStyle = chartDefaults.InheritFrom(legendDefaults)
|
||||
}
|
||||
|
||||
// DEFAULTS
|
||||
legendPadding := Box{
|
||||
Top: 5,
|
||||
Left: 5,
|
||||
Right: 5,
|
||||
Bottom: 5,
|
||||
}
|
||||
lineTextGap := 5
|
||||
lineLengthMinimum := 25
|
||||
|
||||
var labels []string
|
||||
var lines []Style
|
||||
for index, s := range c.Series {
|
||||
if !s.GetStyle().Hidden {
|
||||
if _, isAnnotationSeries := s.(AnnotationSeries); !isAnnotationSeries {
|
||||
labels = append(labels, s.GetName())
|
||||
lines = append(lines, s.GetStyle().InheritFrom(c.styleDefaultsSeries(index)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
legend := Box{
|
||||
Top: cb.Top,
|
||||
Left: cb.Left,
|
||||
// bottom and right will be sized by the legend content + relevant padding.
|
||||
}
|
||||
|
||||
legendContent := Box{
|
||||
Top: legend.Top + legendPadding.Top,
|
||||
Left: legend.Left + legendPadding.Left,
|
||||
Right: legend.Left + legendPadding.Left,
|
||||
Bottom: legend.Top + legendPadding.Top,
|
||||
}
|
||||
|
||||
legendStyle.GetTextOptions().WriteToRenderer(r)
|
||||
|
||||
// measure
|
||||
labelCount := 0
|
||||
for x := 0; x < len(labels); x++ {
|
||||
if len(labels[x]) > 0 {
|
||||
tb := r.MeasureText(labels[x])
|
||||
if labelCount > 0 {
|
||||
legendContent.Bottom += DefaultMinimumTickVerticalSpacing
|
||||
}
|
||||
legendContent.Bottom += tb.Height()
|
||||
right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
|
||||
legendContent.Right = MaxInt(legendContent.Right, right)
|
||||
labelCount++
|
||||
}
|
||||
}
|
||||
|
||||
legend = legend.Grow(legendContent)
|
||||
legend.Right = legendContent.Right + legendPadding.Right
|
||||
legend.Bottom = legendContent.Bottom + legendPadding.Bottom
|
||||
|
||||
Draw.Box(r, legend, legendStyle)
|
||||
|
||||
legendStyle.GetTextOptions().WriteToRenderer(r)
|
||||
|
||||
ycursor := legendContent.Top
|
||||
lx := legendContent.Left
|
||||
legendCount := 0
|
||||
var label string
|
||||
for x := 0; x < len(labels); x++ {
|
||||
label = labels[x]
|
||||
if len(label) > 0 {
|
||||
if legendCount > 0 {
|
||||
ycursor += DefaultMinimumTickVerticalSpacing
|
||||
}
|
||||
|
||||
// Calculate text dimensions
|
||||
tb := r.MeasureText(label)
|
||||
ty := ycursor + tb.Height()
|
||||
th2 := tb.Height() >> 1
|
||||
|
||||
// Calculate line x and y coordinates
|
||||
ly := ty - th2
|
||||
|
||||
// Calculate line ending x coordinate
|
||||
lx2 := lx + lineLengthMinimum
|
||||
|
||||
r.SetStrokeColor(lines[x].GetStrokeColor())
|
||||
r.SetStrokeWidth(lines[x].GetStrokeWidth())
|
||||
r.SetStrokeDashArray(lines[x].GetStrokeDashArray())
|
||||
|
||||
r.MoveTo(lx, ly)
|
||||
r.LineTo(lx2, ly)
|
||||
r.Stroke()
|
||||
|
||||
// Calculate Text starting coordinates
|
||||
textX := lx2 + lineTextGap
|
||||
r.Text(label, textX, ty)
|
||||
|
||||
ycursor += tb.Height()
|
||||
legendCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LegendThin is a legend that doesn't obscure the chart area.
|
||||
func LegendThin(c *Chart, userDefaults ...Style) Renderable {
|
||||
return func(r Renderer, cb Box, chartDefaults Style) {
|
||||
|
|
Loading…
Reference in a new issue