you can now specify tick values and labels manually.

This commit is contained in:
Will Charczuk 2016-07-08 09:17:28 -07:00
parent 65c3f62ac5
commit afc220e25c
3 changed files with 55 additions and 49 deletions

View File

@ -172,7 +172,7 @@ func (c Chart) initRanges(canvasBox Box) (xrange Range, yrange Range) {
if xrange.Formatter == nil {
xrange.Formatter = s.GetXFormatter()
}
if yrange.Format == nil {
if yrange.Formatter == nil {
yrange.Formatter = s.GetYFormatter()
}
}
@ -187,6 +187,9 @@ func (c Chart) initRanges(canvasBox Box) (xrange Range, yrange Range) {
if c.XRange.Formatter != nil {
xrange.Formatter = c.XRange.Formatter
}
if c.XRange.Ticks != nil {
xrange.Ticks = c.XRange.Ticks
}
xrange.Domain = canvasBox.Width
if c.YRange.IsZero() {
@ -199,6 +202,9 @@ func (c Chart) initRanges(canvasBox Box) (xrange Range, yrange Range) {
if c.YRange.Formatter != nil {
yrange.Formatter = c.YRange.Formatter
}
if c.YRange.Ticks != nil {
yrange.Ticks = c.YRange.Ticks
}
yrange.Domain = canvasBox.Height
return
@ -244,68 +250,69 @@ func (c Chart) drawAxes(r Renderer, canvasBox Box, xrange, yrange Range) {
}
}
func (c Chart) generateRangeTicks(r Range, tickCount int, offset float64) []Tick {
var ticks []Tick
rangeTicks := Slices(tickCount, r.Max-r.Min)
for _, rv := range rangeTicks {
ticks = append(ticks, Tick{
RangeValue: rv + offset,
Label: r.Format(rv + offset),
})
}
return ticks
}
func (c Chart) drawYAxisLabels(r Renderer, canvasBox Box, yrange Range) {
tickFontSize := c.Axes.GetFontSize(DefaultAxisFontSize)
asw := c.getAxisWidth()
tx := canvasBox.Right + DefaultFinalLabelDeltaWidth + asw
r.SetFontColor(c.Axes.GetFontColor(DefaultAxisColor))
r.SetFontSize(tickFontSize)
minimumTickHeight := tickFontSize + DefaultMinimumTickVerticalSpacing
tickCount := int(math.Floor(float64(yrange.Domain) / float64(minimumTickHeight)))
ticks := yrange.Ticks
if ticks == nil {
minimumTickHeight := tickFontSize + DefaultMinimumTickVerticalSpacing
tickCount := int(math.Floor(float64(yrange.Domain) / float64(minimumTickHeight)))
if tickCount > DefaultMaxTickCount {
tickCount = DefaultMaxTickCount
if tickCount > DefaultMaxTickCount {
tickCount = DefaultMaxTickCount
}
ticks = c.generateRangeTicks(yrange, tickCount, yrange.Min)
}
rangeTicks := Slices(tickCount, yrange.Max-yrange.Min)
domainTicks := Slices(tickCount, float64(yrange.Domain))
asw := c.getAxisWidth()
tx := canvasBox.Right + DefaultFinalLabelDeltaWidth + asw
count := len(rangeTicks)
if len(domainTicks) < count {
count = len(domainTicks) //guard against mismatched array sizes.
}
for index := 0; index < count; index++ {
v := rangeTicks[index] + yrange.Min
y := domainTicks[index]
ty := canvasBox.Bottom - int(y)
r.Text(yrange.Format(v), tx, ty)
for _, t := range ticks {
v := t.RangeValue
y := yrange.Translate(v)
ty := int(y)
r.Text(t.Label, tx, ty)
}
}
func (c Chart) drawXAxisLabels(r Renderer, canvasBox Box, xrange Range) {
tickFontSize := c.Axes.GetFontSize(DefaultAxisFontSize)
ty := canvasBox.Bottom + DefaultXAxisMargin + int(tickFontSize)
r.SetFontColor(c.Axes.GetFontColor(DefaultAxisColor))
r.SetFontSize(tickFontSize)
maxLabelWidth := 60
ticks := xrange.Ticks
if ticks == nil {
maxLabelWidth := 60
minimumTickWidth := maxLabelWidth + DefaultMinimumTickHorizontalSpacing
tickCount := int(math.Floor(float64(xrange.Domain) / float64(minimumTickWidth)))
minimumTickWidth := maxLabelWidth + DefaultMinimumTickHorizontalSpacing
tickCount := int(math.Floor(float64(xrange.Domain) / float64(minimumTickWidth)))
if tickCount > DefaultMaxTickCount {
tickCount = DefaultMaxTickCount
if tickCount > DefaultMaxTickCount {
tickCount = DefaultMaxTickCount
}
ticks = c.generateRangeTicks(xrange, tickCount, xrange.Min)
}
rangeTicks := Slices(tickCount, xrange.Max-xrange.Min)
domainTicks := Slices(tickCount, float64(xrange.Domain))
ty := canvasBox.Bottom + DefaultXAxisMargin + int(tickFontSize)
count := len(rangeTicks)
if len(domainTicks) < count {
count = len(domainTicks) //guard against mismatched array sizes.
}
for index := 0; index < count; index++ {
v := rangeTicks[index] + xrange.Min
x := domainTicks[index]
for _, t := range ticks {
v := t.RangeValue
x := xrange.Translate(v)
tx := canvasBox.Left + int(x)
r.Text(xrange.Format(v), tx, ty)
r.Text(t.Label, tx, ty)
}
}

View File

@ -7,11 +7,18 @@ import (
"github.com/blendlabs/go-util"
)
// Tick represents a label on an axis.
type Tick struct {
RangeValue float64
Label string
}
// Range represents a continuous range,
type Range struct {
Min float64
Max float64
Domain int
Ticks []Tick
Formatter Formatter
}

View File

@ -1,10 +1,8 @@
package main
import (
"fmt"
"log"
"github.com/blendlabs/go-util"
"github.com/wcharczuk/go-chart"
"github.com/wcharczuk/go-web"
)
@ -29,12 +27,6 @@ func main() {
YRange: chart.Range{
Min: 0.0,
Max: 7.0,
Formatter: func(v interface{}) string {
if typed, isTyped := v.(float64); isTyped {
return fmt.Sprintf("%.4f", typed)
}
return util.StringEmpty
},
},
FinalValueLabel: chart.Style{
Show: true,