Files
MujicaUI/area_chart.go
T

75 lines
2.1 KiB
Go

package mujica
import (
"math"
"time"
"github.com/egoist/mygo/ui"
)
// AreaChartOptions configure an AreaChart.
type AreaChartOptions struct {
Frame ChartFrame
// X places point i at ascending X[i]; nil means i.
X []float64
// Times makes a time axis; set X or Times.
Times []time.Time
// Stacked piles visible series on each other.
Stacked bool
// Baseline is where areas start; zero by default.
Baseline float64
Format func(v float64) string
}
// AreaChart fills series to the baseline, or stacked.
func AreaChart(c *ui.Context, series []ChartSeries, opts AreaChartOptions) ChartResult {
n := chartCheckSeries(series)
ch := newChart(c, opts.Frame)
ax := chartMemo(ch, "x", [3]string{chartID(opts.X), chartID(opts.Times), chartID(series)}, func() chartX { return newChartX(n, opts.X, opts.Times) })
deps := struct {
id string
stacked bool
base float64
}{chartSeriesID(ch, series), opts.Stacked, opts.Baseline}
bands := chartMemo(ch, "bands", deps, func() [2][][]float64 { return areaBands(series, ch.hidden, opts.Stacked, opts.Baseline) })
lo, hi, ok := chartYRange(ch, series, false, bands[0])
if !ok {
n = 0
}
lo, hi = min(lo, opts.Baseline), max(hi, opts.Baseline)
return chartLines(ch, chartLineData{series: series, tops: bands[0], bases: bands[1], ax: ax, lo: lo, hi: hi, n: n, format: opts.Format})
}
// areaBands returns each series' top and bottom edges.
func areaBands(series []ChartSeries, hidden func(string) bool, stacked bool, base float64) [2][][]float64 {
var tops, bases [][]float64
var run []float64
if len(series) > 0 {
run = make([]float64, len(series[0].Values))
for i := range run {
run[i] = base
}
}
for _, s := range series {
top, bot := make([]float64, len(s.Values)), make([]float64, len(s.Values))
for i, v := range s.Values {
bot[i], top[i] = base, v
if stacked {
bot[i], top[i] = run[i], run[i]+v
}
if stacked && !math.IsNaN(v) && !hidden(s.Name) {
run[i] += v
}
}
tops, bases = append(tops, top), append(bases, bot)
}
return [2][][]float64{tops, bases}
}
func chartBool(b bool) float64 {
if b {
return 1
}
return 0
}