go-chart/tick.go

118 lines
2.6 KiB
Go
Raw Permalink Normal View History

2016-07-10 10:11:47 +02:00
package chart
2017-01-10 22:50:17 +01:00
import (
"fmt"
"math"
"strings"
util "git.fireandbrimst.one/aw/go-chart/util"
2017-01-10 22:50:17 +01:00
)
2016-07-13 20:50:22 +02:00
2016-07-24 00:35:49 +02:00
// TicksProvider is a type that provides ticks.
type TicksProvider interface {
2016-08-01 01:54:09 +02:00
GetTicks(r Renderer, defaults Style, vf ValueFormatter) []Tick
2016-07-11 08:06:14 +02:00
}
2016-07-10 10:11:47 +02:00
// Tick represents a label on an axis.
type Tick struct {
Value float64
Label string
}
// Ticks is an array of ticks.
type Ticks []Tick
// Len returns the length of the ticks set.
func (t Ticks) Len() int {
return len(t)
}
// Swap swaps two elements.
func (t Ticks) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}
// Less returns if i's value is less than j's value.
func (t Ticks) Less(i, j int) bool {
return t[i].Value < t[j].Value
}
2016-07-24 00:35:49 +02:00
2017-01-10 22:50:17 +01:00
// String returns a string representation of the set of ticks.
func (t Ticks) String() string {
var values []string
for i, tick := range t {
values = append(values, fmt.Sprintf("[%d: %s]", i, tick.Label))
}
return strings.Join(values, ", ")
}
2016-07-30 21:57:18 +02:00
// GenerateContinuousTicks generates a set of ticks.
func GenerateContinuousTicks(r Renderer, ra Range, isVertical bool, style Style, vf ValueFormatter) []Tick {
2016-08-06 01:55:55 +02:00
if vf == nil {
2017-04-26 08:35:07 +02:00
vf = FloatValueFormatter
2016-08-06 01:55:55 +02:00
}
2016-07-24 00:35:49 +02:00
var ticks []Tick
min, max := ra.GetMin(), ra.GetMax()
2017-01-10 22:50:17 +01:00
if ra.IsDescending() {
ticks = append(ticks, Tick{
Value: max,
Label: vf(max),
})
} else {
ticks = append(ticks, Tick{
Value: min,
Label: vf(min),
})
}
2016-07-30 21:57:18 +02:00
minLabel := vf(min)
style.GetTextOptions().WriteToRenderer(r)
labelBox := r.MeasureText(minLabel)
2017-01-10 02:57:45 +01:00
var tickSize float64
2016-07-30 21:57:18 +02:00
if isVertical {
2017-01-10 02:57:45 +01:00
tickSize = float64(labelBox.Height() + DefaultMinimumTickVerticalSpacing)
2016-07-30 21:57:18 +02:00
} else {
2017-01-10 02:57:45 +01:00
tickSize = float64(labelBox.Width() + DefaultMinimumTickHorizontalSpacing)
2016-07-24 00:35:49 +02:00
}
2016-07-30 21:57:18 +02:00
2017-01-10 02:57:45 +01:00
domain := float64(ra.GetDomain())
domainRemainder := domain - (tickSize * 2)
2016-07-30 21:57:18 +02:00
intermediateTickCount := int(math.Floor(float64(domainRemainder) / float64(tickSize)))
2017-01-10 02:57:45 +01:00
rangeDelta := math.Abs(max - min)
2016-07-30 21:57:18 +02:00
tickStep := rangeDelta / float64(intermediateTickCount)
roundTo := util.Math.GetRoundToForDelta(rangeDelta) / 10
intermediateTickCount = util.Math.MinInt(intermediateTickCount, DefaultTickCountSanityCheck)
2016-07-30 21:57:18 +02:00
for x := 1; x < intermediateTickCount; x++ {
2017-01-10 22:50:17 +01:00
var tickValue float64
if ra.IsDescending() {
tickValue = max - util.Math.RoundUp(tickStep*float64(x), roundTo)
2017-01-10 22:50:17 +01:00
} else {
tickValue = min + util.Math.RoundUp(tickStep*float64(x), roundTo)
2017-01-10 22:50:17 +01:00
}
ticks = append(ticks, Tick{
2016-07-30 21:57:18 +02:00
Value: tickValue,
Label: vf(tickValue),
})
}
2016-07-24 00:35:49 +02:00
2017-01-10 22:50:17 +01:00
if ra.IsDescending() {
ticks = append(ticks, Tick{
Value: min,
Label: vf(min),
})
} else {
ticks = append(ticks, Tick{
Value: max,
Label: vf(max),
})
}
2016-07-24 00:35:49 +02:00
2016-07-30 21:57:18 +02:00
return ticks
2016-07-24 00:35:49 +02:00
}