you can now specify tick values and labels manually.
This commit is contained in:
parent
65c3f62ac5
commit
afc220e25c
3 changed files with 55 additions and 49 deletions
89
chart.go
89
chart.go
|
@ -172,7 +172,7 @@ func (c Chart) initRanges(canvasBox Box) (xrange Range, yrange Range) {
|
||||||
if xrange.Formatter == nil {
|
if xrange.Formatter == nil {
|
||||||
xrange.Formatter = s.GetXFormatter()
|
xrange.Formatter = s.GetXFormatter()
|
||||||
}
|
}
|
||||||
if yrange.Format == nil {
|
if yrange.Formatter == nil {
|
||||||
yrange.Formatter = s.GetYFormatter()
|
yrange.Formatter = s.GetYFormatter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,9 @@ func (c Chart) initRanges(canvasBox Box) (xrange Range, yrange Range) {
|
||||||
if c.XRange.Formatter != nil {
|
if c.XRange.Formatter != nil {
|
||||||
xrange.Formatter = c.XRange.Formatter
|
xrange.Formatter = c.XRange.Formatter
|
||||||
}
|
}
|
||||||
|
if c.XRange.Ticks != nil {
|
||||||
|
xrange.Ticks = c.XRange.Ticks
|
||||||
|
}
|
||||||
xrange.Domain = canvasBox.Width
|
xrange.Domain = canvasBox.Width
|
||||||
|
|
||||||
if c.YRange.IsZero() {
|
if c.YRange.IsZero() {
|
||||||
|
@ -199,6 +202,9 @@ func (c Chart) initRanges(canvasBox Box) (xrange Range, yrange Range) {
|
||||||
if c.YRange.Formatter != nil {
|
if c.YRange.Formatter != nil {
|
||||||
yrange.Formatter = c.YRange.Formatter
|
yrange.Formatter = c.YRange.Formatter
|
||||||
}
|
}
|
||||||
|
if c.YRange.Ticks != nil {
|
||||||
|
yrange.Ticks = c.YRange.Ticks
|
||||||
|
}
|
||||||
yrange.Domain = canvasBox.Height
|
yrange.Domain = canvasBox.Height
|
||||||
|
|
||||||
return
|
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) {
|
func (c Chart) drawYAxisLabels(r Renderer, canvasBox Box, yrange Range) {
|
||||||
tickFontSize := c.Axes.GetFontSize(DefaultAxisFontSize)
|
tickFontSize := c.Axes.GetFontSize(DefaultAxisFontSize)
|
||||||
|
asw := c.getAxisWidth()
|
||||||
|
tx := canvasBox.Right + DefaultFinalLabelDeltaWidth + asw
|
||||||
|
|
||||||
r.SetFontColor(c.Axes.GetFontColor(DefaultAxisColor))
|
r.SetFontColor(c.Axes.GetFontColor(DefaultAxisColor))
|
||||||
r.SetFontSize(tickFontSize)
|
r.SetFontSize(tickFontSize)
|
||||||
|
|
||||||
minimumTickHeight := tickFontSize + DefaultMinimumTickVerticalSpacing
|
ticks := yrange.Ticks
|
||||||
tickCount := int(math.Floor(float64(yrange.Domain) / float64(minimumTickHeight)))
|
if ticks == nil {
|
||||||
|
minimumTickHeight := tickFontSize + DefaultMinimumTickVerticalSpacing
|
||||||
|
tickCount := int(math.Floor(float64(yrange.Domain) / float64(minimumTickHeight)))
|
||||||
|
|
||||||
if tickCount > DefaultMaxTickCount {
|
if tickCount > DefaultMaxTickCount {
|
||||||
tickCount = DefaultMaxTickCount
|
tickCount = DefaultMaxTickCount
|
||||||
|
}
|
||||||
|
ticks = c.generateRangeTicks(yrange, tickCount, yrange.Min)
|
||||||
}
|
}
|
||||||
|
|
||||||
rangeTicks := Slices(tickCount, yrange.Max-yrange.Min)
|
for _, t := range ticks {
|
||||||
domainTicks := Slices(tickCount, float64(yrange.Domain))
|
v := t.RangeValue
|
||||||
|
y := yrange.Translate(v)
|
||||||
asw := c.getAxisWidth()
|
ty := int(y)
|
||||||
tx := canvasBox.Right + DefaultFinalLabelDeltaWidth + asw
|
r.Text(t.Label, tx, ty)
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chart) drawXAxisLabels(r Renderer, canvasBox Box, xrange Range) {
|
func (c Chart) drawXAxisLabels(r Renderer, canvasBox Box, xrange Range) {
|
||||||
tickFontSize := c.Axes.GetFontSize(DefaultAxisFontSize)
|
tickFontSize := c.Axes.GetFontSize(DefaultAxisFontSize)
|
||||||
|
ty := canvasBox.Bottom + DefaultXAxisMargin + int(tickFontSize)
|
||||||
|
|
||||||
r.SetFontColor(c.Axes.GetFontColor(DefaultAxisColor))
|
r.SetFontColor(c.Axes.GetFontColor(DefaultAxisColor))
|
||||||
r.SetFontSize(tickFontSize)
|
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
|
if tickCount > DefaultMaxTickCount {
|
||||||
tickCount := int(math.Floor(float64(xrange.Domain) / float64(minimumTickWidth)))
|
tickCount = DefaultMaxTickCount
|
||||||
|
}
|
||||||
if tickCount > DefaultMaxTickCount {
|
ticks = c.generateRangeTicks(xrange, tickCount, xrange.Min)
|
||||||
tickCount = DefaultMaxTickCount
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rangeTicks := Slices(tickCount, xrange.Max-xrange.Min)
|
for _, t := range ticks {
|
||||||
domainTicks := Slices(tickCount, float64(xrange.Domain))
|
v := t.RangeValue
|
||||||
|
x := xrange.Translate(v)
|
||||||
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]
|
|
||||||
tx := canvasBox.Left + int(x)
|
tx := canvasBox.Left + int(x)
|
||||||
r.Text(xrange.Format(v), tx, ty)
|
r.Text(t.Label, tx, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
range.go
7
range.go
|
@ -7,11 +7,18 @@ import (
|
||||||
"github.com/blendlabs/go-util"
|
"github.com/blendlabs/go-util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Tick represents a label on an axis.
|
||||||
|
type Tick struct {
|
||||||
|
RangeValue float64
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
|
||||||
// Range represents a continuous range,
|
// Range represents a continuous range,
|
||||||
type Range struct {
|
type Range struct {
|
||||||
Min float64
|
Min float64
|
||||||
Max float64
|
Max float64
|
||||||
Domain int
|
Domain int
|
||||||
|
Ticks []Tick
|
||||||
Formatter Formatter
|
Formatter Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/blendlabs/go-util"
|
|
||||||
"github.com/wcharczuk/go-chart"
|
"github.com/wcharczuk/go-chart"
|
||||||
"github.com/wcharczuk/go-web"
|
"github.com/wcharczuk/go-web"
|
||||||
)
|
)
|
||||||
|
@ -29,12 +27,6 @@ func main() {
|
||||||
YRange: chart.Range{
|
YRange: chart.Range{
|
||||||
Min: 0.0,
|
Min: 0.0,
|
||||||
Max: 7.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{
|
FinalValueLabel: chart.Style{
|
||||||
Show: true,
|
Show: true,
|
||||||
|
|
Loading…
Reference in a new issue