forked from wcharczuk/go-chart
-
Notifications
You must be signed in to change notification settings - Fork 1
/
tick.go
115 lines (96 loc) · 2.48 KB
/
tick.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package chart
import (
"fmt"
"math"
"strings"
)
// TicksProvider is a type that provides ticks.
type TicksProvider interface {
GetTicks(r Renderer, defaults Style, vf ValueFormatter) []Tick
}
// 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
}
// 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, ", ")
}
// GenerateContinuousTicks generates a set of ticks.
func GenerateContinuousTicks(r Renderer, ra Range, isVertical bool, style Style, vf ValueFormatter) []Tick {
if vf == nil {
vf = FloatValueFormatter
}
var ticks []Tick
min, max := ra.GetMin(), ra.GetMax()
if ra.IsDescending() {
ticks = append(ticks, Tick{
Value: max,
Label: vf(max),
})
} else {
ticks = append(ticks, Tick{
Value: min,
Label: vf(min),
})
}
minLabel := vf(min)
style.GetTextOptions().WriteToRenderer(r)
labelBox := r.MeasureText(minLabel)
var tickSize float64
if isVertical {
tickSize = float64(labelBox.Height() + DefaultMinimumTickVerticalSpacing)
} else {
tickSize = float64(labelBox.Width() + DefaultMinimumTickHorizontalSpacing)
}
domain := float64(ra.GetDomain())
domainRemainder := domain - (tickSize * 2)
intermediateTickCount := int(math.Floor(float64(domainRemainder) / float64(tickSize)))
rangeDelta := math.Abs(max - min)
tickStep := rangeDelta / float64(intermediateTickCount)
roundTo := GetRoundToForDelta(rangeDelta) / 10
intermediateTickCount = MinInt(intermediateTickCount, DefaultTickCountSanityCheck)
for x := 1; x < intermediateTickCount; x++ {
var tickValue float64
if ra.IsDescending() {
tickValue = max - RoundUp(tickStep*float64(x), roundTo)
} else {
tickValue = min + RoundUp(tickStep*float64(x), roundTo)
}
ticks = append(ticks, Tick{
Value: tickValue,
Label: vf(tickValue),
})
}
if ra.IsDescending() {
ticks = append(ticks, Tick{
Value: min,
Label: vf(min),
})
} else {
ticks = append(ticks, Tick{
Value: max,
Label: vf(max),
})
}
return ticks
}