From efee19c7d4c3e914d7fee7e12983b861364e91c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 14:34:31 -0400 Subject: [PATCH] Charts I: components 101-120 --- area_chart.go | 74 +++++ area_chart_test.go | 54 ++++ bar_chart.go | 185 ++++++++++++ bar_chart_test.go | 90 ++++++ box_plot.go | 160 +++++++++++ box_plot_test.go | 59 ++++ bullet_chart.go | 149 ++++++++++ bullet_chart_test.go | 69 +++++ calendar_heatmap.go | 139 +++++++++ calendar_heatmap_test.go | 95 +++++++ chart_frame.go | 260 +++++++++++++++++ chart_frame_test.go | 108 +++++++ chart_series.go | 206 ++++++++++++++ chart_tree.go | 171 ++++++++++++ data_table.go | 2 +- docs/components/101-line-chart.md | 54 ++++ docs/components/102-area-chart.md | 54 ++++ docs/components/103-bar-chart.md | 52 ++++ docs/components/104-pie-chart.md | 50 ++++ docs/components/105-scatter-chart.md | 52 ++++ docs/components/106-radar-chart.md | 49 ++++ docs/components/107-heatmap-chart.md | 48 ++++ docs/components/108-calendar-heatmap.md | 50 ++++ docs/components/109-histogram.md | 50 ++++ docs/components/110-box-plot.md | 47 ++++ docs/components/111-waterfall-chart.md | 52 ++++ docs/components/112-funnel-chart.md | 47 ++++ docs/components/113-bullet-chart.md | 51 ++++ docs/components/114-sparkline.md | 48 ++++ docs/components/115-gauge.md | 51 ++++ docs/components/116-treemap.md | 53 ++++ docs/components/117-sunburst.md | 53 ++++ docs/components/118-sankey-chart.md | 49 ++++ docs/components/119-network-graph.md | 51 ++++ docs/components/120-realtime-chart.md | 53 ++++ example_charts1_test.go | 221 +++++++++++++++ examples/gallery/pages_charts1.go | 76 ++++- examples/gallery/pages_charts1_code.go | 174 ++++++++++++ examples/gallery/pages_charts1_flow.go | 137 +++++++++ examples/gallery/pages_charts1_series.go | 197 +++++++++++++ examples/gallery/pages_charts1_stats.go | 171 ++++++++++++ examples/gallery/pages_charts1_test.go | 71 +++++ funnel_chart.go | 85 ++++++ funnel_chart_test.go | 54 ++++ gauge.go | 154 ++++++++++ gauge_test.go | 75 +++++ heatmap_chart.go | 123 ++++++++ heatmap_chart_test.go | 68 +++++ histogram.go | 157 +++++++++++ histogram_test.go | 76 +++++ internal/chart.go | 264 ++++++++++++++++++ internal/chart_test.go | 101 +++++++ line_chart.go | 159 +++++++++++ line_chart_test.go | 194 +++++++++++++ list.go | 2 +- messages_charts1.go | 30 ++ network_graph.go | 263 +++++++++++++++++ network_graph_test.go | 101 +++++++ pie_chart.go | 146 ++++++++++ pie_chart_test.go | 82 ++++++ radar_chart.go | 141 ++++++++++ radar_chart_test.go | 71 +++++ realtime_chart.go | 121 ++++++++ realtime_chart_test.go | 86 ++++++ sankey_chart.go | 235 ++++++++++++++++ sankey_chart_test.go | 81 ++++++ scatter_chart.go | 162 +++++++++++ scatter_chart_test.go | 82 ++++++ sparkline.go | 170 +++++++++++ sparkline_test.go | 78 ++++++ sunburst.go | 155 ++++++++++ sunburst_test.go | 64 +++++ testdata/snapshots/darwin/area_chart-dark.png | Bin 0 -> 18845 bytes .../snapshots/darwin/area_chart-light.png | Bin 0 -> 18427 bytes testdata/snapshots/darwin/bar_chart-dark.png | Bin 0 -> 19288 bytes testdata/snapshots/darwin/bar_chart-light.png | Bin 0 -> 18661 bytes testdata/snapshots/darwin/box_plot-dark.png | Bin 0 -> 12335 bytes testdata/snapshots/darwin/box_plot-light.png | Bin 0 -> 11813 bytes .../snapshots/darwin/bullet_chart-dark.png | Bin 0 -> 11624 bytes .../snapshots/darwin/bullet_chart-light.png | Bin 0 -> 11159 bytes .../darwin/calendar_heatmap-dark.png | Bin 0 -> 18785 bytes .../darwin/calendar_heatmap-light.png | Bin 0 -> 18469 bytes .../snapshots/darwin/funnel_chart-dark.png | Bin 0 -> 17621 bytes .../snapshots/darwin/funnel_chart-light.png | Bin 0 -> 16706 bytes testdata/snapshots/darwin/gauge-dark.png | Bin 0 -> 30567 bytes testdata/snapshots/darwin/gauge-light.png | Bin 0 -> 30341 bytes .../snapshots/darwin/heatmap_chart-dark.png | Bin 0 -> 16948 bytes .../snapshots/darwin/heatmap_chart-light.png | Bin 0 -> 16409 bytes testdata/snapshots/darwin/histogram-dark.png | Bin 0 -> 13217 bytes testdata/snapshots/darwin/histogram-light.png | Bin 0 -> 12658 bytes testdata/snapshots/darwin/line_chart-dark.png | Bin 0 -> 23341 bytes .../snapshots/darwin/line_chart-light.png | Bin 0 -> 22386 bytes .../snapshots/darwin/network_graph-dark.png | Bin 0 -> 15448 bytes .../snapshots/darwin/network_graph-light.png | Bin 0 -> 14812 bytes testdata/snapshots/darwin/pie_chart-dark.png | Bin 0 -> 41218 bytes testdata/snapshots/darwin/pie_chart-light.png | Bin 0 -> 41206 bytes .../snapshots/darwin/radar_chart-dark.png | Bin 0 -> 30389 bytes .../snapshots/darwin/radar_chart-light.png | Bin 0 -> 29501 bytes .../snapshots/darwin/realtime_chart-dark.png | Bin 0 -> 29105 bytes .../snapshots/darwin/realtime_chart-light.png | Bin 0 -> 28010 bytes .../snapshots/darwin/sankey_chart-dark.png | Bin 0 -> 13436 bytes .../snapshots/darwin/sankey_chart-light.png | Bin 0 -> 13005 bytes .../snapshots/darwin/scatter_chart-dark.png | Bin 0 -> 13704 bytes .../snapshots/darwin/scatter_chart-light.png | Bin 0 -> 13140 bytes testdata/snapshots/darwin/sparkline-dark.png | Bin 0 -> 2981 bytes testdata/snapshots/darwin/sparkline-light.png | Bin 0 -> 2901 bytes testdata/snapshots/darwin/sunburst-dark.png | Bin 0 -> 27106 bytes testdata/snapshots/darwin/sunburst-light.png | Bin 0 -> 26863 bytes testdata/snapshots/darwin/treemap-dark.png | Bin 0 -> 15168 bytes testdata/snapshots/darwin/treemap-light.png | Bin 0 -> 15103 bytes .../snapshots/darwin/waterfall_chart-dark.png | Bin 0 -> 13251 bytes .../darwin/waterfall_chart-light.png | Bin 0 -> 12729 bytes treemap.go | 98 +++++++ treemap_test.go | 89 ++++++ waterfall_chart.go | 125 +++++++++ waterfall_chart_test.go | 54 ++++ 116 files changed, 7825 insertions(+), 3 deletions(-) create mode 100644 area_chart.go create mode 100644 area_chart_test.go create mode 100644 bar_chart.go create mode 100644 bar_chart_test.go create mode 100644 box_plot.go create mode 100644 box_plot_test.go create mode 100644 bullet_chart.go create mode 100644 bullet_chart_test.go create mode 100644 calendar_heatmap.go create mode 100644 calendar_heatmap_test.go create mode 100644 chart_frame.go create mode 100644 chart_frame_test.go create mode 100644 chart_series.go create mode 100644 chart_tree.go create mode 100644 docs/components/101-line-chart.md create mode 100644 docs/components/102-area-chart.md create mode 100644 docs/components/103-bar-chart.md create mode 100644 docs/components/104-pie-chart.md create mode 100644 docs/components/105-scatter-chart.md create mode 100644 docs/components/106-radar-chart.md create mode 100644 docs/components/107-heatmap-chart.md create mode 100644 docs/components/108-calendar-heatmap.md create mode 100644 docs/components/109-histogram.md create mode 100644 docs/components/110-box-plot.md create mode 100644 docs/components/111-waterfall-chart.md create mode 100644 docs/components/112-funnel-chart.md create mode 100644 docs/components/113-bullet-chart.md create mode 100644 docs/components/114-sparkline.md create mode 100644 docs/components/115-gauge.md create mode 100644 docs/components/116-treemap.md create mode 100644 docs/components/117-sunburst.md create mode 100644 docs/components/118-sankey-chart.md create mode 100644 docs/components/119-network-graph.md create mode 100644 docs/components/120-realtime-chart.md create mode 100644 example_charts1_test.go create mode 100644 examples/gallery/pages_charts1_code.go create mode 100644 examples/gallery/pages_charts1_flow.go create mode 100644 examples/gallery/pages_charts1_series.go create mode 100644 examples/gallery/pages_charts1_stats.go create mode 100644 examples/gallery/pages_charts1_test.go create mode 100644 funnel_chart.go create mode 100644 funnel_chart_test.go create mode 100644 gauge.go create mode 100644 gauge_test.go create mode 100644 heatmap_chart.go create mode 100644 heatmap_chart_test.go create mode 100644 histogram.go create mode 100644 histogram_test.go create mode 100644 internal/chart.go create mode 100644 internal/chart_test.go create mode 100644 line_chart.go create mode 100644 line_chart_test.go create mode 100644 messages_charts1.go create mode 100644 network_graph.go create mode 100644 network_graph_test.go create mode 100644 pie_chart.go create mode 100644 pie_chart_test.go create mode 100644 radar_chart.go create mode 100644 radar_chart_test.go create mode 100644 realtime_chart.go create mode 100644 realtime_chart_test.go create mode 100644 sankey_chart.go create mode 100644 sankey_chart_test.go create mode 100644 scatter_chart.go create mode 100644 scatter_chart_test.go create mode 100644 sparkline.go create mode 100644 sparkline_test.go create mode 100644 sunburst.go create mode 100644 sunburst_test.go create mode 100644 testdata/snapshots/darwin/area_chart-dark.png create mode 100644 testdata/snapshots/darwin/area_chart-light.png create mode 100644 testdata/snapshots/darwin/bar_chart-dark.png create mode 100644 testdata/snapshots/darwin/bar_chart-light.png create mode 100644 testdata/snapshots/darwin/box_plot-dark.png create mode 100644 testdata/snapshots/darwin/box_plot-light.png create mode 100644 testdata/snapshots/darwin/bullet_chart-dark.png create mode 100644 testdata/snapshots/darwin/bullet_chart-light.png create mode 100644 testdata/snapshots/darwin/calendar_heatmap-dark.png create mode 100644 testdata/snapshots/darwin/calendar_heatmap-light.png create mode 100644 testdata/snapshots/darwin/funnel_chart-dark.png create mode 100644 testdata/snapshots/darwin/funnel_chart-light.png create mode 100644 testdata/snapshots/darwin/gauge-dark.png create mode 100644 testdata/snapshots/darwin/gauge-light.png create mode 100644 testdata/snapshots/darwin/heatmap_chart-dark.png create mode 100644 testdata/snapshots/darwin/heatmap_chart-light.png create mode 100644 testdata/snapshots/darwin/histogram-dark.png create mode 100644 testdata/snapshots/darwin/histogram-light.png create mode 100644 testdata/snapshots/darwin/line_chart-dark.png create mode 100644 testdata/snapshots/darwin/line_chart-light.png create mode 100644 testdata/snapshots/darwin/network_graph-dark.png create mode 100644 testdata/snapshots/darwin/network_graph-light.png create mode 100644 testdata/snapshots/darwin/pie_chart-dark.png create mode 100644 testdata/snapshots/darwin/pie_chart-light.png create mode 100644 testdata/snapshots/darwin/radar_chart-dark.png create mode 100644 testdata/snapshots/darwin/radar_chart-light.png create mode 100644 testdata/snapshots/darwin/realtime_chart-dark.png create mode 100644 testdata/snapshots/darwin/realtime_chart-light.png create mode 100644 testdata/snapshots/darwin/sankey_chart-dark.png create mode 100644 testdata/snapshots/darwin/sankey_chart-light.png create mode 100644 testdata/snapshots/darwin/scatter_chart-dark.png create mode 100644 testdata/snapshots/darwin/scatter_chart-light.png create mode 100644 testdata/snapshots/darwin/sparkline-dark.png create mode 100644 testdata/snapshots/darwin/sparkline-light.png create mode 100644 testdata/snapshots/darwin/sunburst-dark.png create mode 100644 testdata/snapshots/darwin/sunburst-light.png create mode 100644 testdata/snapshots/darwin/treemap-dark.png create mode 100644 testdata/snapshots/darwin/treemap-light.png create mode 100644 testdata/snapshots/darwin/waterfall_chart-dark.png create mode 100644 testdata/snapshots/darwin/waterfall_chart-light.png create mode 100644 treemap.go create mode 100644 treemap_test.go create mode 100644 waterfall_chart.go create mode 100644 waterfall_chart_test.go diff --git a/area_chart.go b/area_chart.go new file mode 100644 index 0000000..739085d --- /dev/null +++ b/area_chart.go @@ -0,0 +1,74 @@ +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 +} diff --git a/area_chart_test.go b/area_chart_test.go new file mode 100644 index 0000000..04db044 --- /dev/null +++ b/area_chart_test.go @@ -0,0 +1,54 @@ +package mujica + +import ( + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestAreaBands(t *testing.T) { + series := []ChartSeries{{Name: "a", Values: []float64{1, math.NaN(), 3}}, {Name: "b", Values: []float64{2, 2, 2}}} + none := func(string) bool { return false } + st := areaBands(series, none, true, 10) + if st[0][0][0] != 11 || st[1][1][0] != 11 || st[0][1][0] != 13 || !math.IsNaN(st[0][0][1]) || st[0][1][1] != 12 { + t.Fatalf("stacked %v", st) + } + hideA := func(s string) bool { return s == "a" } + st = areaBands(series, hideA, true, 0) + if st[0][1][2] != 2 || st[1][1][2] != 0 { + t.Fatalf("hidden series still stacked: %v", st) + } + flat := areaBands(series, none, false, -1) + if flat[0][0][2] != 3 || flat[1][0][2] != -1 || flat[1][1][2] != -1 { + t.Fatalf("baseline %v", flat) + } +} + +func TestAreaChartStackedReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return AreaChart(c, lineSeries(), AreaChartOptions{Frame: ChartFrame{Label: "Nave"}, Stacked: true, Baseline: 1}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Nave") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "0 · Pews 3 · Candles 5" { + t.Fatalf("readout shows the series values, not the stack: %q", got) + } + b := h.res.Element.Bounds() + tt.Move(b.X+52+(b.W-64)*0.5, b.Y+b.H/2) + if got := chartReadout(tt); got != "2 · Pews no value · Candles 6" || h.res.Point != 2 { + t.Fatalf("hover %q", got) + } +} + +func TestAreaChartSnapshot(t *testing.T) { + snapshot(t, "area_chart", 520, 340, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + AreaChart(c, []ChartSeries{ + {Name: "Matins", Values: []float64{3, 4, 6, 5, 7, 8}}, + {Name: "Vespers", Values: []float64{2, 3, 2, 4, 3, 5}}, + }, AreaChartOptions{Frame: ChartFrame{Label: "Attendance"}, Stacked: true}) + }) + }) +} diff --git a/bar_chart.go b/bar_chart.go new file mode 100644 index 0000000..7989ad2 --- /dev/null +++ b/bar_chart.go @@ -0,0 +1,185 @@ +package mujica + +import ( + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// BarChartOptions configure a BarChart. +type BarChartOptions struct { + Frame ChartFrame + // Horizontal lays categories down the side and bars across. + Horizontal bool + // Stacked piles series into one bar per category. + Stacked bool + // Labels writes each bar's value at its end. + Labels bool + Format func(v float64) string +} + +type barMark struct{ cat, series int } + +// BarChart draws grouped or stacked bars; NaN draws none. +func BarChart(c *ui.Context, categories []string, series []ChartSeries, opts BarChartOptions) ChartResult { + if n := chartCheckSeries(series); n != len(categories) && len(series) > 0 { + panic("mujica: BarChart series length differs from categories") + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + keys := make([]chartKey, len(series)) + var vis []int + for i, s := range series { + keys[i] = chartKey{Name: s.Name, Color: pal[i%len(pal)], Shape: i} + if !ch.hidden(s.Name) { + vis = append(vis, i) + } + } + // Bars stacked or not; lo and hi always include zero. + type layout struct { + marks []barMark + from []float64 + lo, hi float64 + } + lay := chartMemo(ch, "bars", [2]any{chartSeriesID(ch, series), opts.Stacked}, func() layout { + var l layout + for ci := range categories { + pos, neg := 0.0, 0.0 + for _, si := range vis { + v := series[si].Values[ci] + if math.IsNaN(v) { + continue + } + from := 0.0 + if opts.Stacked && v >= 0 { + from, pos = pos, pos+v + } else if opts.Stacked { + from, neg = neg, neg+v + } + l.marks, l.from = append(l.marks, barMark{ci, si}), append(l.from, from) + l.lo, l.hi = min(l.lo, from, from+v), max(l.hi, from, from+v) + } + } + return l + }) + var lo, hi, step float64 + var ticks []float64 + if len(lay.marks) > 0 { + lo, hi = lay.lo, lay.hi + if opts.Labels { + // Headroom keeps value labels inside the plot. + pad := (hi - lo) * 0.15 + lo, hi = lo-pad*chartBool(lo < 0), hi+pad*chartBool(hi > 0) + } + lo, hi, step = internal.Nice(lo, hi, 4) + ticks = internal.Ticks(lo, hi, step) + } + geom := func(r ui.Rect) (ui.Rect, internal.Band, internal.Linear) { + if opts.Horizontal { + plot := chartInset(r, 96, 26) + return plot, internal.Band{N: len(categories), R0: plot.Y, R1: plot.Y + plot.H, Pad: 0.3}, + internal.Linear{D0: lo, D1: hi, R0: float64(plot.X), R1: float64(plot.X + plot.W)} + } + plot := chartInset(r, 52, 26) + return plot, internal.Band{N: len(categories), R0: plot.X, R1: plot.X + plot.W, Pad: 0.3}, + internal.Linear{D0: lo, D1: hi, R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + } + // rect is bar i's box in plot space. + rect := func(band internal.Band, vs internal.Linear, i int) ui.Rect { + m := lay.marks[i] + at, w := band.Start(m.cat), band.Width() + if !opts.Stacked && len(vis) > 0 { + slot := 0 + for j, si := range vis { + if si == m.series { + slot = j + } + } + w /= float32(len(vis)) + at += w * float32(slot) + } + a, b := vs.Map(lay.from[i]), vs.Map(lay.from[i]+series[m.series].Values[m.cat]) + a, b = min(a, b), max(a, b) + if opts.Horizontal { + return ui.Rect{X: a, Y: at, W: max(b-a, 1), H: w} + } + return ui.Rect{X: at, Y: a, W: w, H: max(b-a, 1)} + } + value := func(i int) float64 { m := lay.marks[i]; return series[m.series].Values[m.cat] } + spec := chartSpec{n: len(lay.marks), keys: keys, toggle: len(series) > 1} + spec.readout = func(i int) string { + m := lay.marks[i] + return categories[m.cat] + " · " + series[m.series].Name + " " + chartValue(c, value(i), opts.Format) + } + spec.pick = func(r ui.Rect, x, y float32) int { + _, band, vs := geom(r) + for i := range lay.marks { + b := rect(band, vs, i) + // Thin bars still take a 6 DIP target. + if (ui.Rect{X: b.X - 3, Y: b.Y - 3, W: b.W + 6, H: b.H + 6}).Contains(x, y) { + return i + } + } + return -1 + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, band, vs := geom(r) + label := func(v float64) string { return internal.FormatTick(v, step) } + var pos []float32 + for i := range categories { + pos = append(pos, band.Center(i)) + } + zero := vs.Map(0) + if opts.Horizontal { + for _, t := range ticks { + x := internal.Snap(p, vs.Map(t)) + p.Line(x, plot.Y, x, plot.Y+plot.H, 1, k.Border) + chartText(p, label(t), x, plot.Y+plot.H+6, size, k.TextMuted, 0.5, 0) + } + for i, y := range pos { + chartText(p, categories[i], plot.X-8, y, size, k.TextMuted, 1, 0.5) + } + p.Line(internal.Snap(p, zero), plot.Y, internal.Snap(p, zero), plot.Y+plot.H, 1, k.ControlBorder) + } else { + internal.AxisY(p, plot, vs, ticks, label, size, k) + internal.AxisX(p, plot, pos, categories, size, k) + internal.Rule(p, plot.X, plot.X+plot.W, zero, k.ControlBorder) + } + for i, m := range lay.marks { + b := rect(band, vs, i) + col := keys[m.series].Color + p.Fill(b, col, 1) + if i == active { + p.Stroke(ui.Rect{X: b.X - 2, Y: b.Y - 2, W: b.W + 4, H: b.H + 4}, k.Text, 2, 1.5) + } + // The series shape marks the bar besides its color. + if min(b.W, b.H) >= 10 && max(b.W, b.H) >= 14 { + internal.Marker(p, m.series, b.X+b.W/2, b.Y+b.H/2, min(b.W, b.H, 14)*0.6, k.Surface) + } + if opts.Labels && !opts.Stacked { + barLabel(p, chartValue(c, value(i), opts.Format), b, value(i) < 0, opts.Horizontal, size, k.Text) + } + } + } + res, _ := ch.build(spec) + return res +} + +// barLabel writes a value just past the bar's far end. +func barLabel(p *ui.Painter, s string, b ui.Rect, neg, horizontal bool, size float32, col ui.Color) { + switch { + case horizontal && neg: + chartText(p, s, b.X-4, b.Y+b.H/2, size, col, 1, 0.5) + case horizontal: + chartText(p, s, b.X+b.W+4, b.Y+b.H/2, size, col, 0, 0.5) + case neg: + chartText(p, s, b.X+b.W/2, b.Y+b.H+2, size, col, 0.5, 0) + default: + chartText(p, s, b.X+b.W/2, b.Y-2, size, col, 0.5, 1) + } +} diff --git a/bar_chart_test.go b/bar_chart_test.go new file mode 100644 index 0000000..dfde4b0 --- /dev/null +++ b/bar_chart_test.go @@ -0,0 +1,90 @@ +package mujica + +import ( + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +var barCats = []string{"Nave", "Choir", "Crypt"} + +func barSeries() []ChartSeries { + return []ChartSeries{ + {Name: "Gold", Values: []float64{4, -2, 3}}, + {Name: "Silver", Values: []float64{2, 5, math.NaN()}}, + } +} + +func TestBarChartKeyboardPerBar(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return BarChart(c, barCats, barSeries(), BarChartOptions{Frame: ChartFrame{Label: "Tithes"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Tithes") + want := []string{"Nave · Gold 4", "Nave · Silver 2", "Choir · Gold -2", "Choir · Silver 5", "Crypt · Gold 3"} + for i, w := range want { + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != w { + t.Fatalf("bar %d readout %q, want %q", i, got, w) + } + } + tt.Key(0, ui.KeyRight) + if h.res.Point != 4 { + t.Fatalf("stepped past the missing bar: %d", h.res.Point) + } +} + +func TestBarChartHoverStackedHorizontal(t *testing.T) { + for _, o := range []BarChartOptions{{Stacked: true}, {Horizontal: true, Labels: true}, {Horizontal: true, Stacked: true}} { + o.Frame = ChartFrame{Label: "Tithes"} + h := &chartHarness{build: func(c *ui.Context) ChartResult { return BarChart(c, barCats, barSeries(), o) }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Tithes") + found := map[string]bool{} + b := h.res.Element.Bounds() + for y := b.Y + 30; y < b.Y+b.H-40; y += 4 { + for x := b.X + 60; x < b.X+b.W-16; x += 8 { + tt.Move(x, y) + if h.res.Point >= 0 { + found[chartReadout(tt)] = true + } + } + } + if len(found) != 5 || !found["Choir · Gold -2"] { + t.Fatalf("%+v: hover found %v", o, found) + } + } +} + +func TestBarChartBadAndEmpty(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for mismatched categories") + } + }() + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return BarChart(c, barCats, nil, BarChartOptions{Frame: ChartFrame{Label: "Tithes"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + if !tt.HasText("No data") { + t.Fatalf("empty: %q", tt.Texts()) + } + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + BarChart(c, barCats[:2], barSeries(), BarChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestBarChartSnapshot(t *testing.T) { + snapshot(t, "bar_chart", 640, 320, func(c *ui.Context) { + ui.Row(c).Padding(16).Gap(16).Children(func() { + ui.Column(c).Width(296).Children(func() { + BarChart(c, barCats, barSeries(), BarChartOptions{Frame: ChartFrame{Label: "Grouped", Height: 220}, Labels: true}) + }) + ui.Column(c).Width(296).Children(func() { + BarChart(c, barCats, barSeries(), BarChartOptions{Frame: ChartFrame{Label: "Stacked", Height: 220}, Horizontal: true, Stacked: true}) + }) + }) + }) +} diff --git a/box_plot.go b/box_plot.go new file mode 100644 index 0000000..518ad02 --- /dev/null +++ b/box_plot.go @@ -0,0 +1,160 @@ +package mujica + +import ( + "fmt" + "math" + "slices" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// BoxGroup is one named sample of a BoxPlot. +type BoxGroup struct { + Name string + Values []float64 +} + +// BoxPlotOptions configure a BoxPlot. +type BoxPlotOptions struct { + Frame ChartFrame + Format func(v float64) string +} + +// boxStats are quartiles, whisker ends and outliers. +type boxStats struct { + q1, median, q3, lo, hi float64 + outliers []float64 + n int +} + +// boxSummary summarizes finite values; n is 0 without any. +func boxSummary(values []float64) boxStats { + var v []float64 + for _, x := range values { + if !math.IsNaN(x) && !math.IsInf(x, 0) { + v = append(v, x) + } + } + if len(v) == 0 { + return boxStats{} + } + slices.Sort(v) + q := func(p float64) float64 { + at := p * float64(len(v)-1) + i := int(at) + if i+1 >= len(v) { + return v[i] + } + return v[i] + (at-float64(i))*(v[i+1]-v[i]) + } + s := boxStats{q1: q(0.25), median: q(0.5), q3: q(0.75), n: len(v)} + fence := 1.5 * (s.q3 - s.q1) + s.lo, s.hi = s.q1, s.q3 + for _, x := range v { + if x < s.q1-fence || x > s.q3+fence { + s.outliers = append(s.outliers, x) + continue + } + s.lo, s.hi = min(s.lo, x), max(s.hi, x) + } + return s +} + +// BoxPlot compares groups by quartile box, whiskers and outlier points. +func BoxPlot(c *ui.Context, groups []BoxGroup, opts BoxPlotOptions) ChartResult { + ch := newChart(c, opts.Frame) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + ids := "" + for _, g := range groups { + if g.Name == "" { + panic("mujica: BoxPlot groups need names") + } + ids += chartID(g.Values) + ";" + } + stats := chartMemo(ch, "stats", ids, func() []boxStats { + out := make([]boxStats, len(groups)) + for i, g := range groups { + out[i] = boxSummary(g.Values) + } + return out + }) + lo, hi, n := math.Inf(1), math.Inf(-1), 0 + for _, s := range stats { + if s.n > 0 { + n++ + lo, hi = min(lo, s.lo, slices.Min(append([]float64{s.lo}, s.outliers...))), max(hi, s.hi, slices.Max(append([]float64{s.hi}, s.outliers...))) + } + } + var step float64 + if n > 0 { + lo, hi, step = internal.Nice(lo, hi, 4) + } else { + groups = nil + } + val := func(v float64) string { return chartValue(c, v, opts.Format) } + geom := func(r ui.Rect) (ui.Rect, internal.Band, internal.Linear) { + plot := chartInset(r, 52, 26) + return plot, internal.Band{N: len(groups), R0: plot.X, R1: plot.X + plot.W, Pad: 0.45}, + internal.Linear{D0: lo, D1: hi, R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + } + spec := chartSpec{n: len(groups)} + spec.readout = func(i int) string { + s := stats[i] + if s.n == 0 { + return groups[i].Name + " · " + msg(c, "chart.missing") + } + return fmt.Sprintf(msg(c, "box_plot.readout"), groups[i].Name, val(s.median), val(s.q1), val(s.q3), val(s.lo), val(s.hi), len(s.outliers)) + } + spec.pick = func(r ui.Rect, x, y float32) int { + plot, band, _ := geom(r) + if !plot.Contains(x, y) { + return -1 + } + return min(len(groups)-1, int((x-plot.X)/band.Step())) + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, band, ys := geom(r) + internal.AxisY(p, plot, ys, internal.Ticks(lo, hi, step), func(v float64) string { return internal.FormatTick(v, step) }, size, k) + var xs []float32 + var names []string + for i, g := range groups { + xs, names = append(xs, band.Center(i)), append(names, g.Name) + } + internal.AxisX(p, plot, xs, names, size, k) + for i, s := range stats { + if s.n == 0 { + continue + } + col := pal[i%len(pal)] + x, w := band.Start(i), band.Width() + cx := internal.Snap(p, x+w/2) + whisker := func(a, b float64) { + var path ui.Path + path.MoveTo(cx, ys.Map(a)).LineTo(cx, ys.Map(b)) + p.StrokePath(&path, 1.5, k.TextMuted) + p.Line(cx-w/4, ys.Map(b), cx+w/4, ys.Map(b), 1.5, k.TextMuted) + } + whisker(s.q3, s.hi) + whisker(s.q1, s.lo) + box := ui.Rect{X: x, Y: ys.Map(s.q3), W: w, H: max(ys.Map(s.q1)-ys.Map(s.q3), 1)} + p.Fill(box, col.Alpha(0.22), 2) + p.Stroke(box, col, 2, 1.5) + p.Line(x, ys.Map(s.median), x+w, ys.Map(s.median), 2.5, k.Text) + for _, o := range s.outliers { + var dot ui.Path + dot.Circle(cx, internal.Snap(p, ys.Map(o)), 3.5) + p.StrokePath(&dot, 1.5, col) + } + if i == active { + p.Stroke(ui.Rect{X: x - 6, Y: plot.Y, W: w + 12, H: plot.H}, k.Text, 3, 1.5) + } + } + } + res, _ := ch.build(spec) + return res +} diff --git a/box_plot_test.go b/box_plot_test.go new file mode 100644 index 0000000..34b3bfd --- /dev/null +++ b/box_plot_test.go @@ -0,0 +1,59 @@ +package mujica + +import ( + "fmt" + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +var boxGroups = []BoxGroup{ + {Name: "Choir", Values: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 40}}, + {Name: "Nave", Values: []float64{4, 5, 5, 6, 7, math.NaN()}}, +} + +func TestBoxSummary(t *testing.T) { + s := boxSummary(boxGroups[0].Values) + if s.q1 != 3.25 || s.median != 5.5 || s.q3 != 7.75 || s.lo != 1 || s.hi != 9 || fmt.Sprint(s.outliers) != "[40]" || s.n != 10 { + t.Fatalf("summary %+v", s) + } + if s := boxSummary([]float64{math.NaN()}); s.n != 0 { + t.Fatal("NaN counted") + } +} + +func TestBoxPlotReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return BoxPlot(c, boxGroups, BoxPlotOptions{Frame: ChartFrame{Label: "Hymns"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Hymns") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Choir · median 5.5 · quartiles 3.25–7.75 · whiskers 1–9 · 1 outliers" { + t.Fatalf("readout %q", got) + } + b := h.res.Element.Bounds() + tt.Key(0, ui.KeyEscape) + tt.Move(b.X+52+(b.W-64)*0.75, b.Y+100) + if got := chartReadout(tt); got != "Nave · median 5 · quartiles 5–6 · whiskers 4–7 · 0 outliers" { + t.Fatalf("hover %q", got) + } +} + +func TestBoxPlotEmpty(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return BoxPlot(c, []BoxGroup{{Name: "a"}}, BoxPlotOptions{Frame: ChartFrame{Label: "Hymns"}}) + }} + if tt := ui.NewTester(h.view, 520, 420); !tt.HasText("No data") { + t.Fatalf("empty: %q", tt.Texts()) + } +} + +func TestBoxPlotSnapshot(t *testing.T) { + snapshot(t, "box_plot", 520, 320, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + BoxPlot(c, append(boxGroups, BoxGroup{Name: "Crypt", Values: []float64{12, 14, 15, 18, 22, 25}}), BoxPlotOptions{Frame: ChartFrame{Label: "Hymns"}}) + }) + }) +} diff --git a/bullet_chart.go b/bullet_chart.go new file mode 100644 index 0000000..7dbd32e --- /dev/null +++ b/bullet_chart.go @@ -0,0 +1,149 @@ +package mujica + +import ( + "fmt" + "math" + "slices" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// BulletChartOptions configure a BulletChart; Frame.Height 0 means 72 DIPs. +type BulletChartOptions struct { + Frame ChartFrame + // Target, when set, draws a cross line at the goal. + Target *float64 + // Bands are the ascending upper ends of the qualitative ranges. + Bands []float64 + // Max ends the scale; 0 means automatic. + Max float64 + Vertical bool + Format func(v float64) string +} + +// BulletChart shows a value against a target and ranges. +func BulletChart(c *ui.Context, value float64, opts BulletChartOptions) ChartResult { + if math.IsNaN(value) || value < 0 || opts.Max < 0 || !slices.IsSorted(opts.Bands) || len(opts.Bands) > 0 && opts.Bands[0] <= 0 { + panic("mujica: BulletChart needs a value ≥ 0, Max ≥ 0 and positive ascending Bands") + } + if opts.Frame.Height == 0 { + opts.Frame.Height = 72 + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + size := FontSize(c, theme.CaptionSize) + top := opts.Max + if top == 0 { + top = value + if opts.Target != nil { + top = max(top, *opts.Target) + } + if len(opts.Bands) > 0 { + top = max(top, opts.Bands[len(opts.Bands)-1]) + } + _, top, _ = internal.Nice(0, max(top, 1e-9), 4) + } + _, _, step := internal.Nice(0, top, 4) + val := func(v float64) string { return chartValue(c, v, opts.Format) } + marks := []string{msg(c, "bullet_chart.actual") + " " + val(value)} + if opts.Target != nil { + marks = append(marks, msg(c, "bullet_chart.target")+" "+val(*opts.Target)) + } + for i, b := range opts.Bands { + lo := 0.0 + if i > 0 { + lo = opts.Bands[i-1] + } + marks = append(marks, fmt.Sprintf(msg(c, "bullet_chart.band"), i+1, val(lo), val(b))) + } + // geom returns the plot and its value scale. + geom := func(r ui.Rect) (ui.Rect, internal.Linear) { + if opts.Vertical { + plot := ui.Rect{X: r.X + r.W/2 - 14, Y: r.Y + 8, W: 28, H: r.H - 16} + return plot, internal.Linear{D0: 0, D1: top, R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + } + plot := ui.Rect{X: r.X + 8, Y: r.Y + 6, W: r.W - 24, H: max(r.H-30, 12)} + return plot, internal.Linear{D0: 0, D1: top, R0: float64(plot.X), R1: float64(plot.X + plot.W)} + } + span := func(plot ui.Rect, s internal.Linear, a, b, inset float32) ui.Rect { + if opts.Vertical { + return ui.Rect{X: plot.X + inset, Y: s.Map(float64(b)), W: plot.W - 2*inset, H: s.Map(float64(a)) - s.Map(float64(b))} + } + return ui.Rect{X: s.Map(float64(a)), Y: plot.Y + inset, W: s.Map(float64(b)) - s.Map(float64(a)), H: plot.H - 2*inset} + } + spec := chartSpec{n: len(marks)} + spec.readout = func(i int) string { return marks[i] } + spec.pick = func(r ui.Rect, x, y float32) int { + plot, s := geom(r) + if !plot.Contains(x, y) { + return -1 + } + at := x + if opts.Vertical { + at = y + } + v := s.Invert(at) + if opts.Target != nil && math.Abs(float64(s.Map(*opts.Target)-at)) < 4 { + return 1 + } + if span(plot, s, 0, float32(min(value, top)), bulletInset(plot, opts.Vertical)).Contains(x, y) { + return 0 + } + for i, b := range opts.Bands { + if v <= b { + return len(marks) - len(opts.Bands) + i + } + } + return -1 + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, s := geom(r) + inset := bulletInset(plot, opts.Vertical) + prev := 0.0 + for i, b := range opts.Bands { + shade := k.SurfaceHover.Mix(k.Border, float32(len(opts.Bands)-1-i)/float32(max(len(opts.Bands)-1, 1))) + p.Fill(span(plot, s, float32(prev), float32(min(b, top)), 0), shade, 0) + if active == len(marks)-len(opts.Bands)+i { + p.Stroke(span(plot, s, float32(prev), float32(min(b, top)), 0), k.Text, 0, 1.5) + } + prev = b + } + bar := span(plot, s, 0, float32(min(value, top)), inset) + p.Fill(bar, internal.Palette(k)[0], 0) + if active == 0 { + p.Stroke(ui.Rect{X: bar.X - 2, Y: bar.Y - 2, W: bar.W + 4, H: bar.H + 4}, k.Text, 1, 1.5) + } + if opts.Target != nil { + t := internal.Snap(p, s.Map(min(*opts.Target, top))) + w := float32(2.5) + if active == 1 { + w = 4 + } + if opts.Vertical { + p.Line(plot.X+2, t, plot.X+plot.W-2, t, w, k.Text) + } else { + p.Line(t, plot.Y+2, t, plot.Y+plot.H-2, w, k.Text) + } + } + for _, tk := range internal.Ticks(0, top, step) { + if opts.Vertical { + chartText(p, internal.FormatTick(tk, step), plot.X+plot.W+6, s.Map(tk), size, k.TextMuted, 0, 0.5) + } else { + chartText(p, internal.FormatTick(tk, step), s.Map(tk), plot.Y+plot.H+4, size, k.TextMuted, 0.5, 0) + } + } + } + res, _ := ch.build(spec) + return res +} + +// bulletInset is a third of the band's thickness. +func bulletInset(plot ui.Rect, vertical bool) float32 { + if vertical { + return plot.W / 3 + } + return plot.H / 3 +} diff --git a/bullet_chart_test.go b/bullet_chart_test.go new file mode 100644 index 0000000..1d8ba54 --- /dev/null +++ b/bullet_chart_test.go @@ -0,0 +1,69 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestBulletChartReadout(t *testing.T) { + target := 250.0 + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return BulletChart(c, 270, BulletChartOptions{Frame: ChartFrame{Label: "Alms"}, Target: &target, Bands: []float64{150, 225, 300}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Alms") + want := []string{"Actual 270", "Target 250", "Range 1: 0–150", "Range 2: 150–225", "Range 3: 225–300"} + for i, w := range want { + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != w { + t.Fatalf("mark %d %q, want %q", i, got, w) + } + } + tt.Key(0, ui.KeyEscape) + b := h.res.Element.Bounds() + plotW := b.W - 24 + tt.Move(b.X+8+plotW*0.1, b.Y+6+21) // band 1, inside the value bar + if got := chartReadout(tt); got != "Actual 270" { + t.Fatalf("hover bar %q", got) + } + tt.Move(b.X+8+plotW*0.1, b.Y+8) // band 1, above the bar + if got := chartReadout(tt); got != "Range 1: 0–150" { + t.Fatalf("hover band %q", got) + } +} + +func TestBulletChartVerticalAndBad(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return BulletChart(c, 40, BulletChartOptions{Frame: ChartFrame{Label: "Alms", Height: 200}, Vertical: true, Max: 100}) + }} + tt := ui.NewTester(h.view, 520, 420) + b := h.res.Element.Bounds() + tt.Move(b.X+b.W/2, b.Y+8+184*0.8) // low on the scale: inside the bar + if got := chartReadout(tt); got != "Actual 40" { + t.Fatalf("vertical hover %q", got) + } + defer func() { + if recover() == nil { + t.Fatal("no panic for unsorted bands") + } + }() + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + BulletChart(c, 1, BulletChartOptions{Frame: ChartFrame{Label: "x"}, Bands: []float64{5, 2}}) + }, 300, 300) +} + +func TestBulletChartSnapshot(t *testing.T) { + target := 250.0 + snapshot(t, "bullet_chart", 520, 300, func(c *ui.Context) { + ui.Row(c).Padding(16).Gap(16).Children(func() { + ui.Column(c).Width(360).Children(func() { + BulletChart(c, 270, BulletChartOptions{Frame: ChartFrame{Label: "Alms"}, Target: &target, Bands: []float64{150, 225, 300}}) + }) + ui.Column(c).Width(100).Children(func() { + BulletChart(c, 40, BulletChartOptions{Frame: ChartFrame{Label: "Oil", Height: 200}, Vertical: true, Target: &[]float64{70}[0], Bands: []float64{50, 80, 100}}) + }) + }) + }) +} diff --git a/calendar_heatmap.go b/calendar_heatmap.go new file mode 100644 index 0000000..1b3e542 --- /dev/null +++ b/calendar_heatmap.go @@ -0,0 +1,139 @@ +package mujica + +import ( + "log/slog" + "strconv" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/internal" + "mujicaui/theme" +) + +// CalendarHeatmapOptions configure a CalendarHeatmap. +type CalendarHeatmapOptions struct { + Frame ChartFrame + // WeekStart picks each column's first weekday; zero follows the locale. + WeekStart WeekStart + Format func(v float64) string +} + +// CalendarHeatmap colors each day of *year, a column per week. +func CalendarHeatmap(c *ui.Context, year *int, values map[Date]float64, opts CalendarHeatmapOptions) ChartResult { + if *year < 1 || *year > 9999 { + panic("mujica: CalendarHeatmap year out of range") + } + k := Tokens(c) + u := Density(c).Unit() + size := FontSize(c, theme.CaptionSize) + first := Date{Year: *year, Month: time.January, Day: 1} + days := first.AddMonths(12).civil().Sub(first.civil()).Hours() / 24 + n := int(days) + lead := (int(first.Weekday()) - int(calendarFirstWeekday(c, opts.WeekStart)) + 7) % 7 + weeks := (lead + n + 6) / 7 + top := 0.0 + for i := range n { + if v, ok := values[first.AddDays(i)]; ok { + top = max(top, v) + } + } + // level is a day's color step, 0 to 4. + level := func(i int) int { + v, ok := values[first.AddDays(i)] + if !ok || v <= 0 || top <= 0 { + return 0 + } + return 1 + min(3, int(v/top*4)) + } + var res ChartResult + wrap := ui.Column(c).Gap(u * 2).MinWidth(0) + wrap.Children(func() { + ui.Row(c).Gap(u).AlignItems(ui.Center).Children(func() { + prev := iconAction(c, icons.Must("chevron-left"), msg(c, "calendar_heatmap.prev")).Disabled(*year <= 1) + ui.Text(c, strconv.Itoa(*year)).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).Width(64).TextAlign(ui.Center) + next := iconAction(c, icons.Must("chevron-right"), msg(c, "calendar_heatmap.next")).Disabled(*year >= 9999) + if prev.Clicked() && !prev.IsDisabled() { + *year-- + res.value = true + } + if next.Clicked() && !next.IsDisabled() { + *year++ + res.value = true + } + }) + ch := newChart(c, opts.Frame) + geom := func(r ui.Rect) (x, y, step float32) { + step = min((r.W-36)/float32(weeks), (r.H-48)/7) + return r.X + 32, r.Y + 18, step + } + cell := func(r ui.Rect, i int) ui.Rect { + x, y, step := geom(r) + at := lead + i + return ui.Rect{X: x + float32(at/7)*step, Y: y + float32(at%7)*step, W: step - 2, H: step - 2} + } + spec := chartSpec{n: n} + spec.readout = func(i int) string { + d := first.AddDays(i) + v, ok := values[d] + s := d.String() + " · " + if !ok { + return s + msg(c, "chart.missing") + } + return s + chartValue(c, v, opts.Format) + } + spec.move = func(i int, key ui.Key) int { + step := map[ui.Key]int{ui.KeyLeft: -7, ui.KeyRight: 7, ui.KeyUp: -1, ui.KeyDown: 1}[key] + return max(0, min(n-1, i+step)) + } + spec.pick = func(r ui.Rect, x, y float32) int { + x0, y0, step := geom(r) + col, row := int((x-x0)/step), int((y-y0)/step) + i := col*7 + row - lead + if x < x0 || y < y0 || row > 6 || i < 0 || i >= n { + return -1 + } + return i + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + x0, y0, step := geom(r) + for i := range n { + b := cell(r, i) + if lv := level(i); lv == 0 { + p.Fill(b, k.SurfaceHover, 2) + } else { + p.Fill(b, internal.Ramp(k, float64(lv)/4), 2) + } + if d := first.AddDays(i); d.Day == 1 { + chartText(p, d.Format("Jan"), b.X, y0-4, size, k.TextMuted, 0, 1) + } + if i == active { + p.Stroke(ui.Rect{X: b.X - 2, Y: b.Y - 2, W: b.W + 4, H: b.H + 4}, k.Text, 3, 2) + } + } + for row := 0; row < 7; row += 2 { + wd := time.Weekday((int(calendarFirstWeekday(c, opts.WeekStart)) + row) % 7) + chartText(p, wd.String()[:3], x0-4, y0+float32(row)*step+step/2, size, k.TextMuted, 1, 0.5) + } + ly := y0 + 7*step + 8 + w, _ := chartText(p, msg(c, "calendar_heatmap.less"), x0, ly, size, k.TextMuted, 0, 0) + for lv := range 5 { + sw := ui.Rect{X: x0 + w + 6 + float32(lv)*(step+2), Y: ly + 2, W: step - 2, H: step - 2} + if lv == 0 { + p.Fill(sw, k.SurfaceHover, 2) + } else { + p.Fill(sw, internal.Ramp(k, float64(lv)/4), 2) + } + } + chartText(p, msg(c, "calendar_heatmap.more"), x0+w+12+5*(step+2), ly, size, k.TextMuted, 0, 0) + } + res2, _ := ch.build(spec) + res.Point, res.changed, res.retry = res2.Point, res2.changed, res2.retry + }) + if res.value { + slog.Debug("mujica: calendar_heatmap year", "year", *year) + } + res.Element = wrap + return res +} diff --git a/calendar_heatmap_test.go b/calendar_heatmap_test.go new file mode 100644 index 0000000..6c417e2 --- /dev/null +++ b/calendar_heatmap_test.go @@ -0,0 +1,95 @@ +package mujica + +import ( + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +func calendarValues() map[Date]float64 { + m := map[Date]float64{} + d := Date{Year: 2026, Month: time.January, Day: 1} + for i := range 365 { + if i%3 == 0 { + m[d.AddDays(i)] = float64(i % 11) + } + } + return m +} + +func TestCalendarHeatmapKeysAndYear(t *testing.T) { + year := 2026 + values := 0 + start := WeekStartMonday + h := &chartHarness{build: func(c *ui.Context) ChartResult { + r := CalendarHeatmap(c, &year, calendarValues(), CalendarHeatmapOptions{Frame: ChartFrame{Label: "Prayers"}, WeekStart: start}) + if r.ValueChanged() { + values++ + } + return r + }} + tt := ui.NewTester(h.view, 560, 420) + tabTo(t, tt, "Prayers") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "2026-01-01 · 0" { + t.Fatalf("first day %q", got) + } + tt.Key(0, ui.KeyRight) // a week later + tt.Key(0, ui.KeyDown) // a day later + if got := chartReadout(tt); got != "2026-01-09 · no value" { + t.Fatalf("week and day %q", got) + } + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); got != "2026-12-31 · no value" { + t.Fatalf("End %q", got) + } + if err := tt.Click("Next year"); err != nil { + t.Fatal(err) + } + if year != 2027 || values != 1 || !tt.HasText("2027") { + t.Fatalf("year %d events %d", year, values) + } +} + +func TestCalendarHeatmapWeekStartHover(t *testing.T) { + year := 2026 // 1 January 2026 is a Thursday + for _, tc := range []struct { + start WeekStart + row int + }{{WeekStartSunday, 4}, {WeekStartMonday, 3}} { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return CalendarHeatmap(c, &year, calendarValues(), CalendarHeatmapOptions{Frame: ChartFrame{Label: "Prayers"}, WeekStart: tc.start}) + }} + tt := ui.NewTester(h.view, 560, 420) + b := h.res.Element.Bounds() + plotY := b.Y + b.H - 20 - 8 - 240 // above the readout line and gap + step := min((b.W-36)/53, float32(240-48)/7) + tt.Move(b.X+32+step/2, plotY+18+float32(tc.row)*step+step/2) + if got := chartReadout(tt); got != "2026-01-01 · 0" { + t.Fatalf("start %d: row %d reads %q", tc.start, tc.row, got) + } + } +} + +func TestCalendarHeatmapBadYear(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic") + } + }() + year := 0 + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + CalendarHeatmap(c, &year, nil, CalendarHeatmapOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestCalendarHeatmapSnapshot(t *testing.T) { + snapshot(t, "calendar_heatmap", 600, 260, func(c *ui.Context) { + year := 2026 + ui.Column(c).Padding(16).Children(func() { + CalendarHeatmap(c, &year, calendarValues(), CalendarHeatmapOptions{Frame: ChartFrame{Label: "Prayers", Height: 150}, WeekStart: WeekStartMonday}) + }) + }) +} diff --git a/chart_frame.go b/chart_frame.go new file mode 100644 index 0000000..9fdad75 --- /dev/null +++ b/chart_frame.go @@ -0,0 +1,260 @@ +package mujica + +import ( + "log/slog" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// ChartFrame is what every chart shares. +type ChartFrame struct { + // Label names the chart for assistive technology; required. + Label string + // Height is the plot height in DIPs; 0 means 240. + Height float32 + // Status shows loading or failure in the plot's place. + Status DataStatus + Error string + // Empty replaces the built-in "No data" text. + Empty string +} + +// ChartResult is a built chart and this frame's events. +type ChartResult struct { + Element *ui.Element + // Point is the hovered or focused mark, -1 for none. + Point int + changed, retry bool + toggled string + value bool +} + +// Changed reports that the readout moved to another mark. +func (r ChartResult) Changed() bool { return r.changed } + +// Retried reports a click on a failed load's retry. +func (r ChartResult) Retried() bool { return r.retry } + +// ValueChanged reports a changed selection, path, year or pause. +func (r ChartResult) ValueChanged() bool { return r.value } + +// Toggled returns the legend series switched in this frame. +func (r ChartResult) Toggled() (string, bool) { return r.toggled, r.toggled != "" } + +// chartKey is a legend entry: name, color and shape. +type chartKey struct { + Name string + Color ui.Color + Shape int +} + +// chartSpec is one chart's drawing and behavior. +type chartSpec struct { + // n counts the marks keys step through; 0 is empty. + n int + keys []chartKey + // toggle lets legend entries hide and show series. + toggle bool + draw func(p *ui.Painter, r ui.Rect, active int) + // pick returns the mark at (x, y), or -1. + pick func(r ui.Rect, x, y float32) int + readout func(i int) string + // move steps from mark i; nil steps in order. + move func(i int, key ui.Key) int + // activate runs on Enter, Space or a click. + activate func(i int) +} + +type chartState struct { + focus, last int + hidden map[string]bool +} + +// chart is a chart being built. +type chart struct { + c *ui.Context + frame ChartFrame + st *chartState + res ChartResult +} + +// newChart starts a chart; ask it which series are hidden. +func newChart(c *ui.Context, frame ChartFrame) *chart { + if frame.Label == "" || frame.Height < 0 { + panic("mujica: chart needs a Label and a non-negative Height") + } + if frame.Height == 0 { + frame.Height = 240 + } + ch := &chart{c: c, frame: frame} + ch.res.Element = ui.Column(c).Gap(Density(c).Unit() * 2).MinWidth(0) + ch.st = ui.Local(ch.res.Element, "mujica.chart", func() chartState { return chartState{focus: -1, last: -1, hidden: map[string]bool{}} }) + return ch +} + +// hidden reports whether the legend switched series name off. +func (ch *chart) hidden(name string) bool { return ch.st.hidden[name] } + +// build lays out legend, plot and readout; returns the plot. +func (ch *chart) build(spec chartSpec) (ChartResult, *ui.Element) { + c, k, st := ch.c, Tokens(ch.c), ch.st + u := Density(c).Unit() + var plot *ui.Element + ch.res.Element.Children(func() { + if len(spec.keys) > 0 { + ch.legend(spec) + } + box := ui.Box(c).Height(ch.frame.Height).FillWidth().MinWidth(0) + if ch.frame.Status == DataLoading || ch.frame.Status == DataFailed || spec.n == 0 { + st.focus = -1 + box.Children(func() { + ui.Column(c).Fill().Children(func() { + ch.res.retry = dataPlaceholder(c, ch.frame.Status, ch.frame.Error, ch.frame.Empty, msg(c, "chart.empty")) + }) + }) + ch.res.Point = -1 + ui.Box(c).Height(u * 5) + return + } + plot = box.Focusable().Label(ch.frame.Label).Role(ui.RoleGroup) + internal.Ring(plot, k.Focus, theme.ControlRadius) + st.focus = min(st.focus, spec.n-1) + ch.input(plot, spec) + active := -1 + if x, y, over := plot.PointerPosition(); over && !plot.IsDisabled() { + b := plot.Bounds() + active = spec.pick(ui.Rect{W: b.W, H: b.H}, x, y) + } + if active < 0 && plot.Focused() { + active = st.focus + } + ch.res.Point = active + plot.Draw(func(p *ui.Painter, r ui.Rect) { spec.draw(p, r, active) }) + text, col := msg(c, "chart.hint"), k.TextMuted + if active >= 0 { + text, col = spec.readout(active), k.Text + } + ui.Text(c, text).FontSize(FontSize(c, theme.CaptionSize)).TextColor(col).Role(ui.RoleStatus).SingleLine().Height(u * 5) + }) + ch.res.changed = ch.res.Point != st.last + st.last = ch.res.Point + return ch.res, plot +} + +// input moves the keyboard mark, and takes clicks on marks. +func (ch *chart) input(plot *ui.Element, spec chartSpec) { + st := ch.st + if plot.IsDisabled() { + return + } + to := st.focus + for _, key := range []ui.Key{ui.KeyLeft, ui.KeyRight, ui.KeyUp, ui.KeyDown} { + if !plot.Shortcut(0, key) { + continue + } + switch { + case st.focus < 0: + to = 0 + case spec.move != nil: + to = spec.move(st.focus, key) + case key == ui.KeyLeft || key == ui.KeyUp: + to = max(st.focus-1, 0) + default: + to = min(st.focus+1, spec.n-1) + } + } + if plot.Shortcut(0, ui.KeyHome) { + to = 0 + } + if plot.Shortcut(0, ui.KeyEnd) { + to = spec.n - 1 + } + if plot.Shortcut(0, ui.KeyEscape) { + to = -1 + } + if to != st.focus { + st.focus = to + if to >= 0 { + ch.c.Announce(spec.readout(to)) + } + slog.Debug("mujica: chart focus", "label", ch.frame.Label, "mark", to) + } + act := st.focus >= 0 && (plot.Shortcut(0, ui.KeyEnter) || plot.Shortcut(0, ui.KeySpace)) + if plot.Clicked() { + plot.Focus() + x, y, _ := plot.PointerPosition() + b := plot.Bounds() + if i := spec.pick(ui.Rect{W: b.W, H: b.H}, x, y); i >= 0 { + st.focus, act = i, true + } + } + if act && spec.activate != nil { + spec.activate(st.focus) + } +} + +// legend shows the series keys; toggling ones are check boxes. +func (ch *chart) legend(spec chartSpec) { + c, k, st := ch.c, Tokens(ch.c), ch.st + u := Density(c).Unit() + ui.Row(c).Wrap().Gap(u * 3).Children(func() { + for _, key := range spec.keys { + ui.Row(c).Key(key.Name).Children(func() { + on := !st.hidden[key.Name] + var e *ui.Element + if spec.toggle { + e = ui.CheckboxBase(c, &on).Disabled(ch.res.Element.IsDisabled()).Label(key.Name) + internal.Ring(e, k.Focus, theme.ControlRadius) + if e.Changed() && !e.IsDisabled() { + st.hidden[key.Name] = !on + ch.res.toggled = key.Name + slog.Debug("mujica: chart toggle", "series", key.Name, "visible", on) + } + } else { + e = ui.Row(c) + } + e.MinHeight(theme.MinHitSize).Gap(u*2).AlignItems(ui.Center).Padding(0, u).Radius(theme.ControlRadius) + col := key.Color + if !on { + col = k.TextMuted + } + e.Children(func() { + ui.Box(c).Size(12, 12).Shrink(0).Draw(func(p *ui.Painter, r ui.Rect) { + if on { + internal.Marker(p, key.Shape, r.X+6, r.Y+6, 10, col) + } else { + p.Stroke(r, col, 2, 1) + } + }) + t := ui.Text(c, key.Name).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.Text) + if !on { + t.Strikethrough().TextColor(k.TextMuted) + } + }) + }) + } + }) +} + +// chartText draws s anchored at (x, y) by ax, ay. +func chartText(p *ui.Painter, s string, x, y, size float32, col ui.Color, ax, ay float32) (w, h float32) { + w, h = p.MeasureText(0, ui.Span{Text: s, Size: size}) + p.Text(x-w*ax, y-h*ay, s, size, col) + return w, h +} + +// chartInset is r less room for axis labels. +func chartInset(r ui.Rect, left, bottom float32) ui.Rect { + return ui.Rect{X: r.X + left, Y: r.Y + 8, W: max(r.W-left-12, 1), H: max(r.H-bottom-8, 1)} +} + +// chartInk is Text or Surface, whichever reads better on bg. +func chartInk(k theme.Tokens, bg ui.Color) ui.Color { + if theme.Contrast(k.Text, bg) >= theme.Contrast(k.Surface, bg) { + return k.Text + } + return k.Surface +} diff --git a/chart_frame_test.go b/chart_frame_test.go new file mode 100644 index 0000000..a678038 --- /dev/null +++ b/chart_frame_test.go @@ -0,0 +1,108 @@ +package mujica + +import ( + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +// chartBuilders builds every Charts I component with a small data set. +func chartBuilders() map[string]func(c *ui.Context) ChartResult { + year := 2026 + var path, path2 []string + var sel []ScatterKey + var graph NetworkGraphState + var rt RealtimeChartState + buf := NewRealtimeBuffer(10, "a") + buf.Append(rtStart, 1) + buf.Append(rtStart.Add(time.Second), 2) + target := 3.0 + f := ChartFrame{Label: "Under test"} + return map[string]func(c *ui.Context) ChartResult{ + "line": func(c *ui.Context) ChartResult { return LineChart(c, lineSeries(), LineChartOptions{Frame: f}) }, + "area": func(c *ui.Context) ChartResult { return AreaChart(c, lineSeries(), AreaChartOptions{Frame: f}) }, + "bar": func(c *ui.Context) ChartResult { return BarChart(c, barCats, barSeries(), BarChartOptions{Frame: f}) }, + "pie": func(c *ui.Context) ChartResult { return PieChart(c, pieSlices, PieChartOptions{Frame: f}) }, + "scat": func(c *ui.Context) ChartResult { + return ScatterChart(c, &sel, scatterGroups, ScatterChartOptions{Frame: f}) + }, + "radar": func(c *ui.Context) ChartResult { + return RadarChart(c, radarAxes, radarSeries(), RadarChartOptions{Frame: f}) + }, + "heat": func(c *ui.Context) ChartResult { + return HeatmapChart(c, heatRows, heatCols, heatValues(), HeatmapChartOptions{Frame: f}) + }, + "cal": func(c *ui.Context) ChartResult { + return CalendarHeatmap(c, &year, calendarValues(), CalendarHeatmapOptions{Frame: f}) + }, + "hist": func(c *ui.Context) ChartResult { return Histogram(c, []float64{1, 2, 3}, HistogramOptions{Frame: f}) }, + "box": func(c *ui.Context) ChartResult { return BoxPlot(c, boxGroups, BoxPlotOptions{Frame: f}) }, + "fall": func(c *ui.Context) ChartResult { + return WaterfallChart(c, waterfallSteps, WaterfallChartOptions{Frame: f}) + }, + "funnel": func(c *ui.Context) ChartResult { return FunnelChart(c, funnelStages, FunnelChartOptions{Frame: f}) }, + "bullet": func(c *ui.Context) ChartResult { + return BulletChart(c, 2, BulletChartOptions{Frame: f, Target: &target, Bands: []float64{1, 4}}) + }, + "spark": func(c *ui.Context) ChartResult { return Sparkline(c, sparkValues, SparklineOptions{Frame: f}) }, + "gauge": func(c *ui.Context) ChartResult { + return Gauge(c, 72, GaugeOptions{Frame: f, Max: 100, Segments: gaugeSegments}) + }, + "tree": func(c *ui.Context) ChartResult { return Treemap(c, &path, chartTree(), TreemapOptions{Frame: f}) }, + "sun": func(c *ui.Context) ChartResult { return Sunburst(c, &path2, chartTree(), SunburstOptions{Frame: f}) }, + "sankey": func(c *ui.Context) ChartResult { + return SankeyChart(c, sankeyNodes, sankeyLinks, SankeyChartOptions{Frame: f}) + }, + "graph": func(c *ui.Context) ChartResult { + return NetworkGraph(c, &graph, graphNodes, graphEdges, NetworkGraphOptions{Frame: f}) + }, + "rt": func(c *ui.Context) ChartResult { + return RealtimeChart(c, &rt, buf, RealtimeChartOptions{Frame: f, Window: time.Minute}) + }, + } +} + +func TestChartsIgnoreInputWhenDisabled(t *testing.T) { + for name, build := range chartBuilders() { + values := 0 + h := &chartHarness{disabled: true, build: func(c *ui.Context) ChartResult { + r := build(c) + if r.ValueChanged() || r.Retried() { + values++ + } + if _, ok := r.Toggled(); ok { + values++ + } + return r + }} + tt := ui.NewTester(h.view, 560, 480) + for range 6 { + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyEnter) + tt.Key(0, ui.KeySpace) + } + b := h.res.Element.Bounds() + tt.Click("Under test") + tt.ClickAt(b.X+b.W/2, b.Y+b.H/2) + if h.res.Point != -1 || values != 0 { + t.Errorf("%s: disabled chart took input: point %d, events %d", name, h.res.Point, values) + } + } +} + +func TestChartsEnterAtFirstMark(t *testing.T) { + for name, build := range chartBuilders() { + h := &chartHarness{build: build} + tt := ui.NewTester(h.view, 560, 480) + tabTo(t, tt, "Under test") + tt.Key(0, ui.KeyRight) + if h.res.Point != 0 || chartReadout(tt) == msg2(tt) { + t.Errorf("%s: first arrow read point %d", name, h.res.Point) + } + } +} + +// msg2 is the hint line, read back to tell it from a readout. +func msg2(*ui.Tester) string { return "Focus the chart and use the arrow keys to read values" } diff --git a/chart_series.go b/chart_series.go new file mode 100644 index 0000000..2e992bc --- /dev/null +++ b/chart_series.go @@ -0,0 +1,206 @@ +package mujica + +import ( + "fmt" + "math" + "sort" + "strconv" + "strings" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" +) + +// ChartSeries is named values; NaN marks a missing one. +type ChartSeries struct { + Name string + Values []float64 +} + +type chartMemoEntry struct { + deps any + val any +} + +// chartMemo recomputes f only when the comparable deps change. +func chartMemo[T any](ch *chart, name string, deps any, f func() T) T { + m := ui.Local(ch.res.Element, "mujica.memo."+name, func() chartMemoEntry { return chartMemoEntry{} }) + if m.val == nil || m.deps != deps { + m.deps, m.val = deps, f() + } + return m.val.(T) +} + +// chartID identifies a slice by first element and length. +func chartID[T any](s []T) string { + if len(s) == 0 { + return "0" + } + return fmt.Sprintf("%p:%d", &s[0], len(s)) +} + +// chartSeriesID identifies series data and the hidden set together. +func chartSeriesID(ch *chart, series []ChartSeries) string { + var b strings.Builder + for _, s := range series { + fmt.Fprintf(&b, "%s|%s|%v;", s.Name, chartID(s.Values), ch.hidden(s.Name)) + } + return b.String() +} + +// chartCheckSeries panics on duplicate names or unequal lengths. +func chartCheckSeries(series []ChartSeries) int { + if len(series) == 0 { + return 0 + } + n := len(series[0].Values) + seen := map[string]bool{} + for _, s := range series { + if s.Name == "" || seen[s.Name] || len(s.Values) != n { + panic("mujica: chart series need unique names and equal lengths: " + s.Name) + } + seen[s.Name] = true + } + return n +} + +// chartX is an ascending axis of numbers, times or indices. +type chartX struct { + vals []float64 + times bool + // d0 and d1, when d1 > d0, fix the domain. + d0, d1 float64 +} + +func newChartX(n int, x []float64, times []time.Time) chartX { + switch { + case x != nil && times != nil: + panic("mujica: chart takes X or Times, not both") + case x != nil && len(x) != n, times != nil && len(times) != n: + panic("mujica: chart X or Times length differs from the series") + } + a := chartX{vals: x, times: times != nil} + if times != nil { + a.vals = make([]float64, n) + for i, t := range times { + a.vals[i] = float64(t.UnixNano()) / 1e9 + } + } + if a.vals == nil { + a.vals = make([]float64, n) + for i := range a.vals { + a.vals[i] = float64(i) + } + } + if !sort.Float64sAreSorted(a.vals) { + panic("mujica: chart X or Times must ascend") + } + return a +} + +func (a chartX) scale(plot ui.Rect) internal.Linear { + d0, d1 := a.vals[0], a.vals[len(a.vals)-1] + if a.d1 > a.d0 { + d0, d1 = a.d0, a.d1 + } + return internal.Linear{D0: d0, D1: d1, R0: float64(plot.X), R1: float64(plot.X + plot.W)} +} + +func (a chartX) label(i int) string { + if a.times { + return chartTime(a.vals[i]).Format("2006-01-02 15:04:05") + } + return strconv.FormatFloat(a.vals[i], 'g', 6, 64) +} + +// ticks returns tick positions and labels along plot. +func (a chartX) ticks(plot ui.Rect) ([]float32, []string) { + s := a.scale(plot) + n := max(2, int(plot.W/90)) + var xs []float32 + var labels []string + if a.times { + ts, layout := internal.TimeTicks(chartTime(s.D0), chartTime(s.D1), n) + for _, t := range ts { + xs = append(xs, s.Map(float64(t.UnixNano())/1e9)) + labels = append(labels, t.Format(layout)) + } + return xs, labels + } + lo, hi, step := internal.Nice(s.D0, s.D1, n) + for _, t := range internal.Ticks(lo, hi, step) { + if t >= s.D0 && t <= s.D1 { + xs = append(xs, s.Map(t)) + labels = append(labels, internal.FormatTick(t, step)) + } + } + return xs, labels +} + +// nearest returns the index whose x is closest to v. +func (a chartX) nearest(v float64) int { + i := sort.SearchFloat64s(a.vals, v) + if i == len(a.vals) || i > 0 && v-a.vals[i-1] < a.vals[i]-v { + i-- + } + return i +} + +func chartTime(sec float64) time.Time { + return time.Unix(0, int64(math.Round(sec*1e9))).UTC() +} + +// chartYDomain spans visible finite values, optionally with zero. +func chartYDomain(series []ChartSeries, hidden func(string) bool, withZero bool) (lo, hi float64, ok bool) { + lo, hi = math.Inf(1), math.Inf(-1) + for _, s := range series { + if hidden(s.Name) { + continue + } + for _, v := range s.Values { + if !math.IsNaN(v) { + lo, hi = min(lo, v), max(hi, v) + } + } + } + if math.IsInf(lo, 1) { + return 0, 0, false + } + if withZero { + lo, hi = min(lo, 0), max(hi, 0) + } + return lo, hi, true +} + +// chartValue formats v, or names a missing value. +func chartValue(c *ui.Context, v float64, format func(float64) string) string { + if math.IsNaN(v) { + return msg(c, "chart.missing") + } + if format != nil { + return format(v) + } + return strconv.FormatFloat(v, 'g', 6, 64) +} + +// chartRuns calls f per finite run, thinned to pixel columns. +func chartRuns(vals []float64, x func(i int) float32, f func(idx []int)) { + for i := 0; i < len(vals); { + if math.IsNaN(vals[i]) { + i++ + continue + } + j := i + for j < len(vals) && !math.IsNaN(vals[j]) { + j++ + } + run := internal.Columns(j-i, func(k int) float32 { return x(i + k) }, func(k int) float64 { return vals[i+k] }) + for k := range run { + run[k] += i + } + f(run) + i = j + } +} diff --git a/chart_tree.go b/chart_tree.go new file mode 100644 index 0000000..4f51d5a --- /dev/null +++ b/chart_tree.go @@ -0,0 +1,171 @@ +package mujica + +import ( + "log/slog" + "math" + "slices" + "strings" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/internal" + "mujicaui/theme" +) + +// ChartNode is a hierarchy node; branches sum their leaves. +type ChartNode struct { + Name string + Value float64 + Children []ChartNode +} + +// total is the node's value, or its children's sum. +func (n ChartNode) total() float64 { + if len(n.Children) == 0 { + return n.Value + } + s := 0.0 + for _, ch := range n.Children { + s += ch.total() + } + return s +} + +// chartCheckTree panics on unnamed, duplicate-sibling or negative nodes. +func chartCheckTree(n ChartNode) { + if n.Name == "" || n.Value < 0 || math.IsNaN(n.Value) || math.IsInf(n.Value, 0) { + panic("mujica: chart nodes need a name and a finite value ≥ 0") + } + seen := map[string]bool{} + for _, ch := range n.Children { + if seen[ch.Name] { + panic("mujica: chart node has two children named " + ch.Name) + } + seen[ch.Name] = true + chartCheckTree(ch) + } +} + +// chartDescend returns the node at path, panicking if unknown. +func chartDescend(root ChartNode, path []string) ChartNode { + n := root + for _, name := range path { + i := slices.IndexFunc(n.Children, func(ch ChartNode) bool { return ch.Name == name }) + if i < 0 { + panic("mujica: chart path has no node " + name) + } + n = n.Children[i] + } + return n +} + +// chartPath shows Back and the breadcrumb; reports a move up. +func chartPath(c *ui.Context, root string, path *[]string, disabled bool) bool { + k := Tokens(c) + u := Density(c).Unit() + moved := false + ui.Row(c).Gap(u).AlignItems(ui.Center).Wrap().Children(func() { + back := iconAction(c, icons.Must("chevron-left"), msg(c, "chart.back")).Disabled(disabled || len(*path) == 0) + if back.Clicked() && !back.IsDisabled() { + *path, moved = (*path)[:len(*path)-1], true + } + names := append([]string{root}, *path...) + for i, name := range names { + if i > 0 { + ui.Text(c, "›").TextColor(k.TextMuted) + } + if i == len(names)-1 { + ui.Text(c, name).FontWeight(600).SingleLine() + continue + } + crumb := ui.ButtonBase(c).MinHeight(theme.MinHitSize).Padding(0, u).Radius(theme.ControlRadius).Disabled(disabled).TextColor(k.AccentText) + internal.Ring(crumb, k.Focus, theme.ControlRadius) + crumb.Children(func() { ui.Text(c, name).Underline().SingleLine() }) + if crumb.Clicked() && !crumb.IsDisabled() { + *path, moved = slices.Clone((*path)[:i]), true + } + } + }) + if moved { + slog.Debug("mujica: chart path", "path", strings.Join(*path, "/")) + } + return moved +} + +// chartFit shortens s with an ellipsis to fit w. +func chartFit(p *ui.Painter, s string, w, size float32) string { + r := []rune(s) + for len(r) > 0 { + t := string(r) + if len(r) < len([]rune(s)) { + t += "…" + } + if tw, _ := p.MeasureText(0, ui.Span{Text: t, Size: size}); tw <= w { + return t + } + r = r[:len(r)-1] + } + return "" +} + +// squarify tiles descending values into near-square rectangles. +func squarify(values []float64, r ui.Rect) []ui.Rect { + out := make([]ui.Rect, len(values)) + total := 0.0 + for _, v := range values { + total += v + } + if total <= 0 { + return out + } + scale := float64(r.W*r.H) / total + for i := 0; i < len(values); { + side := float64(min(r.W, r.H)) + j, best := i+1, math.Inf(1) + for ; j <= len(values); j++ { + worst := squarifyWorst(values[i:j], side, scale) + if worst > best { + break + } + best = worst + } + j-- + row := 0.0 + for _, v := range values[i:j] { + row += v * scale + } + thick := float32(row / side) + at := float32(0) + for k := i; k < j; k++ { + l := float32(values[k]*scale) / thick + if r.W >= r.H { + out[k] = ui.Rect{X: r.X, Y: r.Y + at, W: thick, H: l} + } else { + out[k] = ui.Rect{X: r.X + at, Y: r.Y, W: l, H: thick} + } + at += l + } + if r.W >= r.H { + r.X, r.W = r.X+thick, r.W-thick + } else { + r.Y, r.H = r.Y+thick, r.H-thick + } + i = j + } + return out +} + +// squarifyWorst is a row's worst aspect ratio along side. +func squarifyWorst(row []float64, side, scale float64) float64 { + sum, lo, hi := 0.0, math.Inf(1), 0.0 + for _, v := range row { + a := v * scale + sum, lo, hi = sum+a, min(lo, a), max(hi, a) + } + if lo == 0 { + return math.Inf(1) + } + s2 := side * side + return max(s2*hi/(sum*sum), sum*sum/(s2*lo)) +} diff --git a/data_table.go b/data_table.go index b5ea36c..9d36c5e 100644 --- a/data_table.go +++ b/data_table.go @@ -98,7 +98,7 @@ func (v DataTableView) Submitted() bool { return v.submitted } // SortChanged reports a header click or menu choice that changed State.Sort. func (v DataTableView) SortChanged() bool { return v.sorted } -// Retried reports a click on the retry action of a failed load. +// Retried reports a click on a failed load's retry. func (v DataTableView) Retried() bool { return v.retry } const dataTableMarkID = "mujica.select" diff --git a/docs/components/101-line-chart.md b/docs/components/101-line-chart.md new file mode 100644 index 0000000..aefc23b --- /dev/null +++ b/docs/components/101-line-chart.md @@ -0,0 +1,54 @@ +# 101 LineChart 折线图 + +## 用途 + +多序列折线图:数值或时间横轴,缺值(NaN)处断开,悬停与键盘读数,图例勾选框控制序列显隐。大数据按像素列抽稀绘制,10 万点保持流畅。 + +## 最小示例 + +```go +series := []mujica.ChartSeries{ + {Name: "Pews", Values: []float64{3, 5, math.NaN(), 4, 8}}, + {Name: "Candles", Values: []float64{5, 2, 6, 7, 1}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.LineChart(c, series, mujica.LineChartOptions{Frame: mujica.ChartFrame{Label: "Chapel"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func LineChart(c *ui.Context, series []ChartSeries, opts LineChartOptions) ChartResult`;`ChartSeries{Name, Values}`,各序列等长且名称唯一。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `X` | `[]float64` | nil | 点 i 的横坐标,须递增;nil 时为下标。 | +| `Times` | `[]time.Time` | nil | 时间轴;与 `X` 二选一,须递增。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数中的数值格式。 | + +## 状态 + +默认、悬停或键盘读数(竖线 + 各序列放大标记)、隐藏序列(图例划线、空心标记)、加载、失败、无数据(全部为缺值时)。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`Toggled()` 返回本帧被切换显隐的序列名。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):在数据点之间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 +- 图例勾选框:Space 切换序列显隐。 + +## 限制 + +- 数据切片以首元素地址与长度识别;原地修改数据后请传入新切片,缓存的坐标范围才会更新。 +- 每条序列除颜色外还有不同形状的标记(圆、方、菱形、三角),密集时按间隔绘制。 diff --git a/docs/components/102-area-chart.md b/docs/components/102-area-chart.md new file mode 100644 index 0000000..bf747b7 --- /dev/null +++ b/docs/components/102-area-chart.md @@ -0,0 +1,54 @@ +# 102 AreaChart 面积图 + +## 用途 + +面积图:单序列填充到基线,或多序列堆叠;基线可配置;悬停与键盘读数显示各序列原值(不是堆叠后的值)。 + +## 最小示例 + +```go +series := []mujica.ChartSeries{ + {Name: "Matins", Values: []float64{3, 4, 6, 5}}, + {Name: "Vespers", Values: []float64{2, 3, 2, 4}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.AreaChart(c, series, mujica.AreaChartOptions{Frame: mujica.ChartFrame{Label: "Attendance"}, Stacked: true}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func AreaChart(c *ui.Context, series []ChartSeries, opts AreaChartOptions) ChartResult`。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `X`, `Times` | | nil | 同 LineChart。 | +| `Stacked` | `bool` | false | 可见序列依次堆叠;隐藏序列不参与堆叠。 | +| `Baseline` | `float64` | `0` | 面积的起始值;坐标轴总包含基线。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`Toggled()` 同 LineChart。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):在数据点之间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 缺值处面积断开;堆叠时缺值按 0 计入后续序列。 +- 填充为半透明的序列色,边线保持实色以满足 3:1 对比。 diff --git a/docs/components/103-bar-chart.md b/docs/components/103-bar-chart.md new file mode 100644 index 0000000..d162090 --- /dev/null +++ b/docs/components/103-bar-chart.md @@ -0,0 +1,52 @@ +# 103 BarChart 柱状图 + +## 用途 + +柱状图:纵向或横向,分组或堆叠,支持负值与柱端数值标签,键盘逐柱读数。 + +## 最小示例 + +```go +categories := []string{"Nave", "Choir", "Crypt"} +series := []mujica.ChartSeries{{Name: "Gold", Values: []float64{4, -2, 3}}, {Name: "Silver", Values: []float64{2, 5, 1}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BarChart(c, categories, series, mujica.BarChartOptions{Frame: mujica.ChartFrame{Label: "Tithes"}, Labels: true}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func BarChart(c *ui.Context, categories []string, series []ChartSeries, opts BarChartOptions) ChartResult`;每条序列的值与类别一一对应,NaN 不画柱。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Horizontal` | `bool` | false | 类别在纵轴,柱横向延伸。 | +| `Stacked` | `bool` | false | 每个类别一根柱,正值向上、负值向下堆叠。 | +| `Labels` | `bool` | false | 在柱端写出数值(堆叠时不写)。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 选中柱以描边标出,柱内有序列形状标记。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;多序列时 `Toggled()` 报告图例切换。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):逐柱移动(按类别、再按序列),读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 极细的柱仍有 6 DIP 的悬停范围。 +- 类别标签过密时会跳过重叠的标签,读数仍包含完整类别名。 diff --git a/docs/components/104-pie-chart.md b/docs/components/104-pie-chart.md new file mode 100644 index 0000000..a2e760c --- /dev/null +++ b/docs/components/104-pie-chart.md @@ -0,0 +1,50 @@ +# 104 PieChart 饼图 + +## 用途 + +饼图与环形图:扇区按占比绘制并标注百分比;过窄的扇区可合并为“其他”;环形图中心显示总计。 + +## 最小示例 + +```go +slices := []mujica.ChartSlice{{Label: "Wax", Value: 50}, {Label: "Oil", Value: 30}, {Label: "Salt", Value: 4}, {Label: "Ash", Value: 3}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PieChart(c, slices, mujica.PieChartOptions{Frame: mujica.ChartFrame{Label: "Stores"}, Donut: true, MinAngle: 20}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func PieChart(c *ui.Context, slices []ChartSlice, opts PieChartOptions) ChartResult`;`ChartSlice{Label, Value}`,值须为有限且 ≥ 0。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Donut` | `bool` | false | 环形图,中心写总计。 | +| `MinAngle` | `float64` | `0` | 小于该角度(度)的扇区达到两个及以上时合并为“其他”;须在 [0, 360)。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 当前扇区向外凸出。总计为 0 时显示无数据。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):在数据点之间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 只有一个窄扇区时不合并,以免“其他”只代表一项。 +- 扇区内的形状标记与百分比文字按对比度自动选用正文色或表面色。 diff --git a/docs/components/105-scatter-chart.md b/docs/components/105-scatter-chart.md new file mode 100644 index 0000000..baf1af2 --- /dev/null +++ b/docs/components/105-scatter-chart.md @@ -0,0 +1,52 @@ +# 105 ScatterChart 散点图 + +## 用途 + +散点图:按分组着色并配不同形状,点大小可映射为气泡,拖动框选或用键盘选中点。 + +## 最小示例 + +```go +var selected []mujica.ScatterKey +groups := []mujica.ScatterGroup{{Name: "Monks", Points: []mujica.ScatterPoint{{X: 1, Y: 2, Size: 4}, {X: 3, Y: 5, Size: 9}}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.ScatterChart(c, &selected, groups, mujica.ScatterChartOptions{Frame: mujica.ChartFrame{Label: "Choir"}, Bubbles: true}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func ScatterChart(c *ui.Context, selected *[]ScatterKey, groups []ScatterGroup, opts ScatterChartOptions) ChartResult`;`ScatterGroup{Name, Points []ScatterPoint{X, Y, Size}}`,`ScatterKey{Group, Point}` 标识一个点。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Bubbles` | `bool` | false | 按 `Size` 映射点面积(直径 4–18 DIP)。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 选中的点外加圆环,读数注明“已选”。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`ValueChanged()` 表示 `*selected` 被框选或键盘改变;多组时 `Toggled()` 报告图例切换。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):在数据点之间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 +- Enter/Space:选中或取消当前点。 +- 在绘图区拖动:框选,替换现有选择。 + +## 限制 + +- 框选替换选择,不支持按住修饰键追加。 +- 点数较多时逐点绘制,没有抽稀。 diff --git a/docs/components/106-radar-chart.md b/docs/components/106-radar-chart.md new file mode 100644 index 0000000..35a017e --- /dev/null +++ b/docs/components/106-radar-chart.md @@ -0,0 +1,49 @@ +# 106 RadarChart 雷达图 + +## 用途 + +雷达图:三个及以上维度,多序列多边形,刻度环,按维度悬停或键盘读数。 + +## 最小示例 + +```go +axes := []string{"Voice", "Latin", "Chant", "Organ"} +series := []mujica.ChartSeries{{Name: "Agnès", Values: []float64{8, 6, 9, 4}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RadarChart(c, axes, series, mujica.RadarChartOptions{Frame: mujica.ChartFrame{Label: "Skills"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func RadarChart(c *ui.Context, axes []string, series []ChartSeries, opts RadarChartOptions) ChartResult`;每条序列每个维度一个值,值须 ≥ 0。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Max` | `float64` | 自动取整 | 外环代表的值;0 按数据向上取整。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 当前维度的轴线加粗、标签变为正文色。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;多序列时 `Toggled()` 报告图例切换。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):按维度移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 缺值按 0 画在中心,读数显示“无数值”。 diff --git a/docs/components/107-heatmap-chart.md b/docs/components/107-heatmap-chart.md new file mode 100644 index 0000000..b931ea2 --- /dev/null +++ b/docs/components/107-heatmap-chart.md @@ -0,0 +1,48 @@ +# 107 HeatmapChart 热力图 + +## 用途 + +二维矩阵热力图:按值分五级着色,右侧色阶图例标出最小与最大值;单元格读数;空值单元格为虚线框。 + +## 最小示例 + +```go +rows, cols := []string{"Mon", "Tue"}, []string{"Matins", "Lauds", "Vespers"} +values := [][]float64{{1, 4, 9}, {3, math.NaN(), 7}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.HeatmapChart(c, rows, cols, values, mujica.HeatmapChartOptions{Frame: mujica.ChartFrame{Label: "Hours"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func HeatmapChart(c *ui.Context, rows, cols []string, values [][]float64, opts HeatmapChartOptions) ChartResult`;`values[行][列]`,NaN 为空值。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 单元格与读数格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 单元格足够大时直接写出数值,不只依赖颜色。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦热力图。 +- ←/→:同一行左右移动;↑/↓:同一列上下移动;第一次按键进入左上角。 +- Home/End:第一个/最后一个单元格;Escape:清除读数。 + +## 限制 + +- 颜色分五级,不做连续渐变。 diff --git a/docs/components/108-calendar-heatmap.md b/docs/components/108-calendar-heatmap.md new file mode 100644 index 0000000..26f6a30 --- /dev/null +++ b/docs/components/108-calendar-heatmap.md @@ -0,0 +1,50 @@ +# 108 CalendarHeatmap 日历热力图 + +## 用途 + +按日的贡献图:一列一周,按当年最大值分四级着色;年份切换;周起始可配置;逐日读数。 + +## 最小示例 + +```go +year := 2026 +values := map[mujica.Date]float64{{Year: 2026, Month: time.March, Day: 4}: 5} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.CalendarHeatmap(c, &year, values, mujica.CalendarHeatmapOptions{Frame: mujica.ChartFrame{Label: "Prayers"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func CalendarHeatmap(c *ui.Context, year *int, values map[Date]float64, opts CalendarHeatmapOptions) ChartResult`;`*year` 须在 1–9999。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `WeekStart` | `WeekStart` | 跟随语言 | 每列第一行是星期几。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数格式。 | + +## 状态 + +默认、无记录日(浅色格)、四级色阶、悬停或键盘读数(描边)、加载、失败。下方图例从“少”到“多”。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`ValueChanged()` 表示上一年/下一年按钮改变了 `*year`。 + +## 键盘操作 + +- Tab:年份按钮,再到日历。 +- ←/→:前后一周;↑/↓:前后一天;Home/End:全年第一天与最后一天。 +- 上一年/下一年按钮:Enter/Space。 + +## 限制 + +- 方格较小,只作读数目标,不是独立操作,因此不要求 28 DIP 命中区。 +- 值 ≤ 0 视为无记录。 diff --git a/docs/components/109-histogram.md b/docs/components/109-histogram.md new file mode 100644 index 0000000..3817d33 --- /dev/null +++ b/docs/components/109-histogram.md @@ -0,0 +1,50 @@ +# 109 Histogram 直方图 + +## 用途 + +分箱计数直方图:箱数或箱宽可配置,可切换为累计模式;分箱只在数据或参数变化时计算一次。 + +## 最小示例 + +```go +values := []float64{1, 2, 2, 3, 4, 5, 9, 10} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Histogram(c, values, mujica.HistogramOptions{Frame: mujica.ChartFrame{Label: "Ages"}, BinWidth: 5}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func Histogram(c *ui.Context, values []float64, opts HistogramOptions) ChartResult`;NaN 与无穷值被忽略。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Bins` | `int` | Sturges 规则 | 箱数;负数 panic。 | +| `BinWidth` | `float64` | 0 | 箱宽;设定时优先于 `Bins`,箱边取箱宽的整数倍。超过 10000 箱 panic。 | +| `Cumulative` | `bool` | false | 每箱计入不超过其上界的全部值。 | +| `Format` | `func(float64) string` | 按箱宽取精度 | 箱边格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):逐箱移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 按箱数分箱时最后一箱包含上界,读数用 `]` 表示。 diff --git a/docs/components/110-box-plot.md b/docs/components/110-box-plot.md new file mode 100644 index 0000000..bd80246 --- /dev/null +++ b/docs/components/110-box-plot.md @@ -0,0 +1,47 @@ +# 110 BoxPlot 箱线图 + +## 用途 + +箱线图:四分位箱、中位线、1.5 倍四分距内的须线与离群点,多组对比。统计只在数据变化时计算。 + +## 最小示例 + +```go +groups := []mujica.BoxGroup{{Name: "Choir", Values: []float64{1, 2, 3, 4, 5, 40}}, {Name: "Nave", Values: []float64{4, 5, 6, 7}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BoxPlot(c, groups, mujica.BoxPlotOptions{Frame: mujica.ChartFrame{Label: "Hymns"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func BoxPlot(c *ui.Context, groups []BoxGroup, opts BoxPlotOptions) ChartResult`;`BoxGroup{Name, Values}`,名称必填。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 离群点画为空心圆。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):按组移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 四分位数用线性插值计算。 diff --git a/docs/components/111-waterfall-chart.md b/docs/components/111-waterfall-chart.md new file mode 100644 index 0000000..2dfb8c9 --- /dev/null +++ b/docs/components/111-waterfall-chart.md @@ -0,0 +1,52 @@ +# 111 WaterfallChart 瀑布图 + +## 用途 + +瀑布图:增减项累计,小计与总计柱显示累计值;增加为 Success 色并配 ▲,减少为 Danger 色并配 ▼,合计为中性色配 ■,柱端写出带符号的数值。 + +## 最小示例 + +```go +steps := []mujica.WaterfallStep{ + {Label: "Tithes", Value: 12}, + {Label: "Repairs", Value: -5}, + {Label: "Year", Kind: mujica.WaterfallTotal}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.WaterfallChart(c, steps, mujica.WaterfallChartOptions{Frame: mujica.ChartFrame{Label: "Ledger"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func WaterfallChart(c *ui.Context, steps []WaterfallStep, opts WaterfallChartOptions) ChartResult`;`WaterfallStep{Label, Value, Kind}`。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `steps[i].Kind` | `WaterfallKind` | `WaterfallDelta` | `WaterfallDelta` 累加;`WaterfallSubtotal`、`WaterfallTotal` 显示当前累计,`Value` 须为 0。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):逐柱移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 小计与总计都显示到该步为止的累计值,不清零。 diff --git a/docs/components/112-funnel-chart.md b/docs/components/112-funnel-chart.md new file mode 100644 index 0000000..436180c --- /dev/null +++ b/docs/components/112-funnel-chart.md @@ -0,0 +1,47 @@ +# 112 FunnelChart 漏斗图 + +## 用途 + +漏斗图:阶段宽度与值成比例,右侧写出值与相对上一阶段的转化率;读数同时给出相对首阶段的比例。 + +## 最小示例 + +```go +stages := []mujica.ChartSlice{{Label: "Visitors", Value: 1000}, {Label: "Novices", Value: 400}, {Label: "Vows", Value: 100}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.FunnelChart(c, stages, mujica.FunnelChartOptions{Frame: mujica.ChartFrame{Label: "Order"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func FunnelChart(c *ui.Context, stages []ChartSlice, opts FunnelChartOptions) ChartResult`;值须为有限且 ≥ 0。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 全部为 0 时显示无数据。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):逐阶段移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 上一阶段为 0 时转化率显示“—”。 diff --git a/docs/components/113-bullet-chart.md b/docs/components/113-bullet-chart.md new file mode 100644 index 0000000..aab7ffa --- /dev/null +++ b/docs/components/113-bullet-chart.md @@ -0,0 +1,51 @@ +# 113 BulletChart 子弹图 + +## 用途 + +子弹图:实际值的细条、目标值的垂直线与定性区间带,可横向或纵向。 + +## 最小示例 + +```go +target := 250.0 +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BulletChart(c, 270, mujica.BulletChartOptions{Frame: mujica.ChartFrame{Label: "Alms"}, Target: &target, Bands: []float64{150, 225, 300}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func BulletChart(c *ui.Context, value float64, opts BulletChartOptions) ChartResult`;值须 ≥ 0。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `72` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Target` | `*float64` | nil | 目标值,画为与刻度垂直的粗线。 | +| `Bands` | `[]float64` | nil | 各区间的上界,须为正且递增。 | +| `Max` | `float64` | 自动取整 | 刻度终点;0 按值、目标与区间取整。 | +| `Vertical` | `bool` | false | 纵向摆放。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 区间由浅到深的中性色带表示,读数写出区间范围。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):依次读实际值、目标值与各区间,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 超出 `Max` 的值画到刻度终点,读数仍为原值。 diff --git a/docs/components/114-sparkline.md b/docs/components/114-sparkline.md new file mode 100644 index 0000000..7ff932f --- /dev/null +++ b/docs/components/114-sparkline.md @@ -0,0 +1,48 @@ +# 114 Sparkline 迷你图 + +## 用途 + +行内迷你图:折线、柱形或面积,无坐标轴;末值以菱形标记并在右侧写出数值;聚焦后可逐点读数。 + +## 最小示例 + +```go +values := []float64{3, 5, 4, 7, 6, 9} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Sparkline(c, values, mujica.SparklineOptions{Frame: mujica.ChartFrame{Label: "Bells"}, Kind: mujica.SparklineArea}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func Sparkline(c *ui.Context, values []float64, opts SparklineOptions) ChartResult`;NaN 为缺值。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `28` | 迷你图高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Kind` | `SparklineKind` | `SparklineLine` | `SparklineLine`、`SparklineBar` 或 `SparklineArea`。 | +| `Width` | `float32` | `96` | 迷你图宽度(DIP)。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 右侧数值格式。 | + +## 状态 + +默认(显示末值)、悬停或键盘读数(右侧数值变为当前点,点外加圆环)、加载(小型加载标记)、失败(错误文字与重试图标)、无数据。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦迷你图。 +- ←/→:逐点移动;Home/End:首尾;Escape:恢复显示末值。 + +## 限制 + +- 不显示图例与提示行,以便放在表格行或文字中。 diff --git a/docs/components/115-gauge.md b/docs/components/115-gauge.md new file mode 100644 index 0000000..64360d8 --- /dev/null +++ b/docs/components/115-gauge.md @@ -0,0 +1,51 @@ +# 115 Gauge 仪表盘 + +## 用途 + +仪表盘:半圆或整圆表盘,按阈值分段着色,指针指向当前值,下方写出数值、单位和所在分段的名称,不只靠颜色表达区间。 + +## 最小示例 + +```go +segments := []mujica.GaugeSegment{{To: 60, Label: "Calm", Tone: mujica.GaugeGood}, {To: 100, Label: "Crowded", Tone: mujica.GaugeDanger}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Gauge(c, 72, mujica.GaugeOptions{Frame: mujica.ChartFrame{Label: "Nave"}, Max: 100, Unit: "%", Segments: segments}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func Gauge(c *ui.Context, value float64, opts GaugeOptions) ChartResult`;值须在 `Min`–`Max` 之间。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `200` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Min`, `Max` | `float64` | 必须 `Min < Max` | 刻度范围。 | +| `Segments` | `[]GaugeSegment` | nil | 分段 `{To, Label, Tone}`,上界递增且最后一段止于 `Max`;`Tone` 为 `GaugeNeutral`、`GaugeGood`、`GaugeWarning`、`GaugeDanger`。 | +| `Unit` | `string` | 空 | 数值后的单位。 | +| `Full` | `bool` | false | 整圆表盘,从底部顺时针一周。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 当前分段加宽显示。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):依次读当前值与各分段,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 不做指针动画,值变化时直接切换。 diff --git a/docs/components/116-treemap.md b/docs/components/116-treemap.md new file mode 100644 index 0000000..e2347b4 --- /dev/null +++ b/docs/components/116-treemap.md @@ -0,0 +1,53 @@ +# 116 Treemap 矩形树图 + +## 用途 + +层级矩形树图:按大小平铺当前节点的子项(squarify 布局),点击或回车下钻有子项的矩形,返回按钮与面包屑回到上层;标签按面积显示并截断。 + +## 最小示例 + +```go +var path []string +root := mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, +}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Treemap(c, &path, root, mujica.TreemapOptions{Frame: mujica.ChartFrame{Label: "Rooms"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func Treemap(c *ui.Context, path *[]string, root ChartNode, opts TreemapOptions) ChartResult`;`ChartNode{Name, Value, Children}`,叶子的 `Value` 为大小,分支为子项之和;`*path` 是从根的子项起的名称路径。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 当前矩形内描边。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`ValueChanged()` 表示下钻、返回或点击面包屑改变了 `*path`。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):按大小顺序在矩形间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 +- Enter/Space:下钻;Backspace:返回上一层;返回按钮与面包屑可用 Tab 到达。 + +## 限制 + +- 名称为空、兄弟同名或值为负时 panic;`*path` 指向不存在的节点时 panic。 +- 只显示当前节点的一层子项。 diff --git a/docs/components/117-sunburst.md b/docs/components/117-sunburst.md new file mode 100644 index 0000000..908abbb --- /dev/null +++ b/docs/components/117-sunburst.md @@ -0,0 +1,53 @@ +# 117 Sunburst 旭日图 + +## 用途 + +层级环形图:中心是当前节点及总计,外圈依次是各层后代;点击或回车下钻,路径面包屑与返回按钮回到上层。 + +## 最小示例 + +```go +var path []string +root := mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, +}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Sunburst(c, &path, root, mujica.SunburstOptions{Frame: mujica.ChartFrame{Label: "Rooms"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func Sunburst(c *ui.Context, path *[]string, root ChartNode, opts SunburstOptions) ChartResult`;数据结构同 Treemap。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Depth` | `int` | `3` | 显示的层数;负数 panic。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 外层颜色向表面色淡化,但保持 3:1 对比。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`ValueChanged()` 表示 `*path` 改变。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):按深度优先顺序在扇区间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 +- Enter/Space:下钻到当前扇区;Backspace:返回上一层。 + +## 限制 + +- 弧长不足时不写标签,名称在读数中完整给出。 diff --git a/docs/components/118-sankey-chart.md b/docs/components/118-sankey-chart.md new file mode 100644 index 0000000..f3568a3 --- /dev/null +++ b/docs/components/118-sankey-chart.md @@ -0,0 +1,49 @@ +# 118 SankeyChart 桑基图 + +## 用途 + +桑基图:节点按最长路径分列,列内顺序与传入顺序一致(稳定);流量带宽度与值成比例;悬停或键盘读到节点或流量时,高亮经过它的全部路径。 + +## 最小示例 + +```go +nodes := []mujica.SankeyNode{{ID: "tithe", Label: "Tithes"}, {ID: "fund", Label: "Fund"}, {ID: "roof", Label: "Roof"}} +links := []mujica.SankeyLink{{From: "tithe", To: "fund", Value: 60}, {From: "fund", To: "roof", Value: 50}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.SankeyChart(c, nodes, links, mujica.SankeyChartOptions{Frame: mujica.ChartFrame{Label: "Money"}}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func SankeyChart(c *ui.Context, nodes []SankeyNode, links []SankeyLink, opts SankeyChartOptions) ChartResult`;`SankeyNode{ID, Label}`,`SankeyLink{From, To, Value}`。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 数值格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 高亮时其余流量淡化。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):先按节点、再按流量移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 + +## 限制 + +- 链接成环、端点未知或值不为正时 panic。 +- 布局只在节点或链接切片变化时计算。 diff --git a/docs/components/119-network-graph.md b/docs/components/119-network-graph.md new file mode 100644 index 0000000..5677d5e --- /dev/null +++ b/docs/components/119-network-graph.md @@ -0,0 +1,51 @@ +# 119 NetworkGraph 网络图 + +## 用途 + +网络图:节点与边,使用调用方给定的坐标或简单的力导布局;拖动节点、拖动空白处平移、滚轮或 +/- 缩放。 + +## 最小示例 + +```go +var state mujica.NetworkGraphState +nodes := []mujica.GraphNode{{ID: "a", Label: "Abbot"}, {ID: "b", Label: "Prior"}, {ID: "c", Label: "Novice"}} +edges := []mujica.GraphEdge{{From: "a", To: "b"}, {From: "b", To: "c"}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.NetworkGraph(c, &state, nodes, edges, mujica.NetworkGraphOptions{Frame: mujica.ChartFrame{Label: "House"}, Force: true}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func NetworkGraph(c *ui.Context, s *NetworkGraphState, nodes []GraphNode, edges []GraphEdge, opts NetworkGraphOptions) ChartResult`;`GraphNode{ID, Label, X, Y}`,`GraphEdge{From, To}`。`NetworkGraphState` 保存拖动后的位置与视图:`Position(id)`、`Zoom()`、`ResetView()`。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Force` | `bool` | false | 用力导模拟布局(固定 300 步,结果确定);最多 500 个节点。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 当前节点外加圆环,相连的边加粗。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试。 + +## 键盘操作 + +- Tab:聚焦绘图区(图例勾选框在其前)。 +- ←/→(以及 ↑/↓):在节点间移动,读数显示在图表下方并向读屏软件播报;第一次按键进入第一个点。 +- Home/End:第一个/最后一个点;Escape:清除读数。 +- Shift+方向键:移动当前节点;+/-:缩放;0:复位视图。 + +## 限制 + +- 布局只在节点或边的切片变化时重新计算,拖动不会重新适配视图。 +- 不支持边标签与有向箭头。 diff --git a/docs/components/120-realtime-chart.md b/docs/components/120-realtime-chart.md new file mode 100644 index 0000000..edb1c70 --- /dev/null +++ b/docs/components/120-realtime-chart.md @@ -0,0 +1,53 @@ +# 120 RealtimeChart 实时图表 + +## 用途 + +实时折线图:调用方向 `RealtimeBuffer` 追加数据后刷新,图表显示截至最新数据的固定时间窗口;可暂停视图;组件自身不设计时器,隐藏或空闲时不重绘。 + +## 最小示例 + +```go +buf := mujica.NewRealtimeBuffer(600, "Bell") +start := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC) +for i := range 60 { + buf.Append(start.Add(time.Duration(i)*time.Second), float64(i%7)) +} +var state mujica.RealtimeChartState +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RealtimeChart(c, &state, buf, mujica.RealtimeChartOptions{Frame: mujica.ChartFrame{Label: "Sound"}, Window: 30 * time.Second}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +`func RealtimeChart(c *ui.Context, s *RealtimeChartState, buf *RealtimeBuffer, opts RealtimeChartOptions) ChartResult`;`NewRealtimeBuffer(capacity, names...)` 保存最近 `capacity` 个样本,`Append(t, values...)` 每个序列一个值且时间不倒退。 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `Frame.Label` | `string` | 必填 | 图表的无障碍名称;为空 panic。 | +| `Frame.Height` | `float32` | `240` | 绘图区高度(DIP);负数 panic。 | +| `Frame.Status` | `DataStatus` | `DataReady` | `DataLoading` 显示加载标记,`DataFailed` 显示错误与“重试”;占位与图表同尺寸。 | +| `Frame.Error` | `string` | 内置“加载失败” | 失败时的具体说明。 | +| `Frame.Empty` | `string` | 内置“暂无数据” | 无数据时的说明。 | +| `Window` | `time.Duration` | 必填 | 显示的时间窗口,止于最新样本(暂停时止于暂停那一刻)。 | +| `Format` | `func(float64) string` | 6 位有效数字 | 读数格式。 | + +## 状态 + +默认、悬停读数、键盘读数(焦点环 + 当前点加粗或描边)、加载、失败(可重试)、无数据。图表区始终保持同样尺寸。 暂停时按钮显示“继续”,新数据继续进入缓冲区但不改变视图。 + +## 事件 + +返回 `ChartResult`:`Point` 为当前读数点(无则 -1);`Changed()` 读数点变化;`Retried()` 点击了重试;`ValueChanged()` 表示暂停或继续;`Toggled()` 报告图例切换。 + +## 键盘操作 + +- Tab:暂停按钮、图例、图表。 +- 图表读数键同 LineChart;暂停按钮:Enter/Space。 + +## 限制 + +- 数据追加在后台时,请通过 `Window.Update` 回到界面线程追加并刷新。 +- 缓冲区按块丢弃旧样本,最多占用两倍容量。 diff --git a/example_charts1_test.go b/example_charts1_test.go new file mode 100644 index 0000000..90433bb --- /dev/null +++ b/example_charts1_test.go @@ -0,0 +1,221 @@ +package mujica_test + +import ( + "math" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +func ExampleLineChart() { + series := []mujica.ChartSeries{ + {Name: "Pews", Values: []float64{3, 5, math.NaN(), 4, 8}}, + {Name: "Candles", Values: []float64{5, 2, 6, 7, 1}}, + } + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.LineChart(c, series, mujica.LineChartOptions{Frame: mujica.ChartFrame{Label: "Chapel"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleAreaChart() { + series := []mujica.ChartSeries{ + {Name: "Matins", Values: []float64{3, 4, 6, 5}}, + {Name: "Vespers", Values: []float64{2, 3, 2, 4}}, + } + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.AreaChart(c, series, mujica.AreaChartOptions{Frame: mujica.ChartFrame{Label: "Attendance"}, Stacked: true}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleBarChart() { + categories := []string{"Nave", "Choir", "Crypt"} + series := []mujica.ChartSeries{{Name: "Gold", Values: []float64{4, -2, 3}}, {Name: "Silver", Values: []float64{2, 5, 1}}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BarChart(c, categories, series, mujica.BarChartOptions{Frame: mujica.ChartFrame{Label: "Tithes"}, Labels: true}) + } + ui.Render(view, 400, 300, 1) +} + +func ExamplePieChart() { + slices := []mujica.ChartSlice{{Label: "Wax", Value: 50}, {Label: "Oil", Value: 30}, {Label: "Salt", Value: 4}, {Label: "Ash", Value: 3}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PieChart(c, slices, mujica.PieChartOptions{Frame: mujica.ChartFrame{Label: "Stores"}, Donut: true, MinAngle: 20}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleScatterChart() { + var selected []mujica.ScatterKey + groups := []mujica.ScatterGroup{{Name: "Monks", Points: []mujica.ScatterPoint{{X: 1, Y: 2, Size: 4}, {X: 3, Y: 5, Size: 9}}}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.ScatterChart(c, &selected, groups, mujica.ScatterChartOptions{Frame: mujica.ChartFrame{Label: "Choir"}, Bubbles: true}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleRadarChart() { + axes := []string{"Voice", "Latin", "Chant", "Organ"} + series := []mujica.ChartSeries{{Name: "Agnès", Values: []float64{8, 6, 9, 4}}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RadarChart(c, axes, series, mujica.RadarChartOptions{Frame: mujica.ChartFrame{Label: "Skills"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleHeatmapChart() { + rows, cols := []string{"Mon", "Tue"}, []string{"Matins", "Lauds", "Vespers"} + values := [][]float64{{1, 4, 9}, {3, math.NaN(), 7}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.HeatmapChart(c, rows, cols, values, mujica.HeatmapChartOptions{Frame: mujica.ChartFrame{Label: "Hours"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleCalendarHeatmap() { + year := 2026 + values := map[mujica.Date]float64{{Year: 2026, Month: time.March, Day: 4}: 5} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.CalendarHeatmap(c, &year, values, mujica.CalendarHeatmapOptions{Frame: mujica.ChartFrame{Label: "Prayers"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleHistogram() { + values := []float64{1, 2, 2, 3, 4, 5, 9, 10} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Histogram(c, values, mujica.HistogramOptions{Frame: mujica.ChartFrame{Label: "Ages"}, BinWidth: 5}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleBoxPlot() { + groups := []mujica.BoxGroup{{Name: "Choir", Values: []float64{1, 2, 3, 4, 5, 40}}, {Name: "Nave", Values: []float64{4, 5, 6, 7}}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BoxPlot(c, groups, mujica.BoxPlotOptions{Frame: mujica.ChartFrame{Label: "Hymns"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleWaterfallChart() { + steps := []mujica.WaterfallStep{ + {Label: "Tithes", Value: 12}, + {Label: "Repairs", Value: -5}, + {Label: "Year", Kind: mujica.WaterfallTotal}, + } + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.WaterfallChart(c, steps, mujica.WaterfallChartOptions{Frame: mujica.ChartFrame{Label: "Ledger"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleFunnelChart() { + stages := []mujica.ChartSlice{{Label: "Visitors", Value: 1000}, {Label: "Novices", Value: 400}, {Label: "Vows", Value: 100}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.FunnelChart(c, stages, mujica.FunnelChartOptions{Frame: mujica.ChartFrame{Label: "Order"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleBulletChart() { + target := 250.0 + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BulletChart(c, 270, mujica.BulletChartOptions{Frame: mujica.ChartFrame{Label: "Alms"}, Target: &target, Bands: []float64{150, 225, 300}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleSparkline() { + values := []float64{3, 5, 4, 7, 6, 9} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Sparkline(c, values, mujica.SparklineOptions{Frame: mujica.ChartFrame{Label: "Bells"}, Kind: mujica.SparklineArea}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleGauge() { + segments := []mujica.GaugeSegment{{To: 60, Label: "Calm", Tone: mujica.GaugeGood}, {To: 100, Label: "Crowded", Tone: mujica.GaugeDanger}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Gauge(c, 72, mujica.GaugeOptions{Frame: mujica.ChartFrame{Label: "Nave"}, Max: 100, Unit: "%", Segments: segments}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleTreemap() { + var path []string + root := mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, + }} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Treemap(c, &path, root, mujica.TreemapOptions{Frame: mujica.ChartFrame{Label: "Rooms"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleSunburst() { + var path []string + root := mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, + }} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Sunburst(c, &path, root, mujica.SunburstOptions{Frame: mujica.ChartFrame{Label: "Rooms"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleSankeyChart() { + nodes := []mujica.SankeyNode{{ID: "tithe", Label: "Tithes"}, {ID: "fund", Label: "Fund"}, {ID: "roof", Label: "Roof"}} + links := []mujica.SankeyLink{{From: "tithe", To: "fund", Value: 60}, {From: "fund", To: "roof", Value: 50}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.SankeyChart(c, nodes, links, mujica.SankeyChartOptions{Frame: mujica.ChartFrame{Label: "Money"}}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleNetworkGraph() { + var state mujica.NetworkGraphState + nodes := []mujica.GraphNode{{ID: "a", Label: "Abbot"}, {ID: "b", Label: "Prior"}, {ID: "c", Label: "Novice"}} + edges := []mujica.GraphEdge{{From: "a", To: "b"}, {From: "b", To: "c"}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.NetworkGraph(c, &state, nodes, edges, mujica.NetworkGraphOptions{Frame: mujica.ChartFrame{Label: "House"}, Force: true}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleRealtimeChart() { + buf := mujica.NewRealtimeBuffer(600, "Bell") + start := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC) + for i := range 60 { + buf.Append(start.Add(time.Duration(i)*time.Second), float64(i%7)) + } + var state mujica.RealtimeChartState + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RealtimeChart(c, &state, buf, mujica.RealtimeChartOptions{Frame: mujica.ChartFrame{Label: "Sound"}, Window: 30 * time.Second}) + } + ui.Render(view, 400, 300, 1) +} diff --git a/examples/gallery/pages_charts1.go b/examples/gallery/pages_charts1.go index 77aacff..f7cb1dd 100644 --- a/examples/gallery/pages_charts1.go +++ b/examples/gallery/pages_charts1.go @@ -1,3 +1,77 @@ package main -var charts1Pages = []page{} +import ( + "fmt" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" + "mujicaui/theme" +) + +const c1Category = "Charts I" + +const c1Keys = "Tab focuses the chart (legend check boxes first); arrows move between points and the readout is announced; Home/End jump; Escape clears." + +var charts1Pages = []page{ + {ID: "101", Name: "LineChart", ZhName: "折线图", Category: c1Category, Demo: c1LineDemo, Code: c1LineCode, Keys: c1Keys + " Space on a legend entry hides or shows its series."}, + {ID: "102", Name: "AreaChart", ZhName: "面积图", Category: c1Category, Demo: c1AreaDemo, Code: c1AreaCode, Keys: c1Keys}, + {ID: "103", Name: "BarChart", ZhName: "柱状图", Category: c1Category, Demo: c1BarDemo, Code: c1BarCode, Keys: c1Keys + " Arrows step bar by bar."}, + {ID: "104", Name: "PieChart", ZhName: "饼图", Category: c1Category, Demo: c1PieDemo, Code: c1PieCode, Keys: c1Keys}, + {ID: "105", Name: "ScatterChart", ZhName: "散点图", Category: c1Category, Demo: c1ScatterDemo, Code: c1ScatterCode, Keys: c1Keys + " Enter or Space selects the point; drag a box to select."}, + {ID: "106", Name: "RadarChart", ZhName: "雷达图", Category: c1Category, Demo: c1RadarDemo, Code: c1RadarCode, Keys: c1Keys}, + {ID: "107", Name: "HeatmapChart", ZhName: "热力图", Category: c1Category, Demo: c1HeatDemo, Code: c1HeatCode, Keys: "Tab focuses the map; Left/Right move along a row, Up/Down along a column; Home/End jump; Escape clears."}, + {ID: "108", Name: "CalendarHeatmap", ZhName: "日历热力图", Category: c1Category, Demo: c1CalendarDemo, Code: c1CalendarCode, Keys: "Left/Right move a week, Up/Down a day; Home/End jump to the year's ends; the year buttons take Enter or Space."}, + {ID: "109", Name: "Histogram", ZhName: "直方图", Category: c1Category, Demo: c1HistogramDemo, Code: c1HistogramCode, Keys: c1Keys + " Arrows step bin by bin."}, + {ID: "110", Name: "BoxPlot", ZhName: "箱线图", Category: c1Category, Demo: c1BoxDemo, Code: c1BoxCode, Keys: c1Keys + " Arrows step group by group."}, + {ID: "111", Name: "WaterfallChart", ZhName: "瀑布图", Category: c1Category, Demo: c1WaterfallDemo, Code: c1WaterfallCode, Keys: c1Keys}, + {ID: "112", Name: "FunnelChart", ZhName: "漏斗图", Category: c1Category, Demo: c1FunnelDemo, Code: c1FunnelCode, Keys: c1Keys + " Arrows step stage by stage."}, + {ID: "113", Name: "BulletChart", ZhName: "子弹图", Category: c1Category, Demo: c1BulletDemo, Code: c1BulletCode, Keys: c1Keys + " Arrows read the value, the target, then each range."}, + {ID: "114", Name: "Sparkline", ZhName: "迷你图", Category: c1Category, Demo: c1SparkDemo, Code: c1SparkCode, Keys: "Tab focuses the sparkline; Left/Right read points; Home/End jump; Escape shows the last value again."}, + {ID: "115", Name: "Gauge", ZhName: "仪表盘", Category: c1Category, Demo: c1GaugeDemo, Code: c1GaugeCode, Keys: c1Keys + " Arrows read the value, then each segment."}, + {ID: "116", Name: "Treemap", ZhName: "矩形树图", Category: c1Category, Demo: c1TreemapDemo, Code: c1TreemapCode, Keys: c1Keys + " Enter or Space drills into a branch; Backspace goes back; Back and the breadcrumb take Tab."}, + {ID: "117", Name: "Sunburst", ZhName: "旭日图", Category: c1Category, Demo: c1SunburstDemo, Code: c1SunburstCode, Keys: c1Keys + " Enter or Space drills in; Backspace goes back."}, + {ID: "118", Name: "SankeyChart", ZhName: "桑基图", Category: c1Category, Demo: c1SankeyDemo, Code: c1SankeyCode, Keys: c1Keys + " Reading a node or link highlights every path through it."}, + {ID: "119", Name: "NetworkGraph", ZhName: "网络图", Category: c1Category, Demo: c1NetworkDemo, Code: c1NetworkCode, Keys: c1Keys + " Shift+arrows move the node; +/- zoom; 0 resets the view; drag nodes or the background."}, + {ID: "120", Name: "RealtimeChart", ZhName: "实时图表", Category: c1Category, Demo: c1RealtimeDemo, Code: c1RealtimeCode, Keys: "Tab reaches Pause, the legend and the chart; chart keys as in LineChart."}, +} + +var c1Statuses = []string{"Ready", "Loading", "Failed", "Empty"} + +// c1Frame shows the status picker and returns the frame. +func c1Frame(c *ui.Context, label string, status *string) (mujica.ChartFrame, bool) { + ui.Select(c, status, c1Statuses).Width(160).AlignSelf(ui.Start) + f := mujica.ChartFrame{Label: label} + switch *status { + case "Loading": + f.Status = mujica.DataLoading + case "Failed": + f.Status, f.Error = mujica.DataFailed, "The archive did not answer" + } + return f, *status != "Empty" +} + +// c1Section lays out a title, controls, then the chart. +func c1Section(c *ui.Context, title string, controls, body func()) { + ui.Column(c).Gap(12).Children(func() { + ui.Text(c, title).Font(theme.SerifFont).FontSize(mujica.FontSize(c, theme.H3Size)) + ui.Row(c).Gap(16).Wrap().AlignItems(ui.Center).Children(controls) + ui.Column(c).Width(560).Children(body) + }) +} + +// c1Log records a chart's events in the gallery log. +func c1Log(log func(string), name string, r mujica.ChartResult) { + if r.Changed() { + log(fmt.Sprintf("%s: point %d", name, r.Point)) + } + if s, ok := r.Toggled(); ok { + log(name + ": toggled " + s) + } + if r.ValueChanged() { + log(name + ": value changed") + } + if r.Retried() { + log(name + ": retry") + } +} diff --git a/examples/gallery/pages_charts1_code.go b/examples/gallery/pages_charts1_code.go new file mode 100644 index 0000000..8548a47 --- /dev/null +++ b/examples/gallery/pages_charts1_code.go @@ -0,0 +1,174 @@ +package main + +// Snippets are the bodies of the Examples in example_charts1_test.go. + +const c1LineCode = `series := []mujica.ChartSeries{ + {Name: "Pews", Values: []float64{3, 5, math.NaN(), 4, 8}}, + {Name: "Candles", Values: []float64{5, 2, 6, 7, 1}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.LineChart(c, series, mujica.LineChartOptions{Frame: mujica.ChartFrame{Label: "Chapel"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1AreaCode = `series := []mujica.ChartSeries{ + {Name: "Matins", Values: []float64{3, 4, 6, 5}}, + {Name: "Vespers", Values: []float64{2, 3, 2, 4}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.AreaChart(c, series, mujica.AreaChartOptions{Frame: mujica.ChartFrame{Label: "Attendance"}, Stacked: true}) +} +ui.Render(view, 400, 300, 1)` + +const c1BarCode = `categories := []string{"Nave", "Choir", "Crypt"} +series := []mujica.ChartSeries{{Name: "Gold", Values: []float64{4, -2, 3}}, {Name: "Silver", Values: []float64{2, 5, 1}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BarChart(c, categories, series, mujica.BarChartOptions{Frame: mujica.ChartFrame{Label: "Tithes"}, Labels: true}) +} +ui.Render(view, 400, 300, 1)` + +const c1PieCode = `slices := []mujica.ChartSlice{{Label: "Wax", Value: 50}, {Label: "Oil", Value: 30}, {Label: "Salt", Value: 4}, {Label: "Ash", Value: 3}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PieChart(c, slices, mujica.PieChartOptions{Frame: mujica.ChartFrame{Label: "Stores"}, Donut: true, MinAngle: 20}) +} +ui.Render(view, 400, 300, 1)` + +const c1ScatterCode = `var selected []mujica.ScatterKey +groups := []mujica.ScatterGroup{{Name: "Monks", Points: []mujica.ScatterPoint{{X: 1, Y: 2, Size: 4}, {X: 3, Y: 5, Size: 9}}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.ScatterChart(c, &selected, groups, mujica.ScatterChartOptions{Frame: mujica.ChartFrame{Label: "Choir"}, Bubbles: true}) +} +ui.Render(view, 400, 300, 1)` + +const c1RadarCode = `axes := []string{"Voice", "Latin", "Chant", "Organ"} +series := []mujica.ChartSeries{{Name: "Agnès", Values: []float64{8, 6, 9, 4}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RadarChart(c, axes, series, mujica.RadarChartOptions{Frame: mujica.ChartFrame{Label: "Skills"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1HeatCode = `rows, cols := []string{"Mon", "Tue"}, []string{"Matins", "Lauds", "Vespers"} +values := [][]float64{{1, 4, 9}, {3, math.NaN(), 7}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.HeatmapChart(c, rows, cols, values, mujica.HeatmapChartOptions{Frame: mujica.ChartFrame{Label: "Hours"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1CalendarCode = `year := 2026 +values := map[mujica.Date]float64{{Year: 2026, Month: time.March, Day: 4}: 5} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.CalendarHeatmap(c, &year, values, mujica.CalendarHeatmapOptions{Frame: mujica.ChartFrame{Label: "Prayers"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1HistogramCode = `values := []float64{1, 2, 2, 3, 4, 5, 9, 10} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Histogram(c, values, mujica.HistogramOptions{Frame: mujica.ChartFrame{Label: "Ages"}, BinWidth: 5}) +} +ui.Render(view, 400, 300, 1)` + +const c1BoxCode = `groups := []mujica.BoxGroup{{Name: "Choir", Values: []float64{1, 2, 3, 4, 5, 40}}, {Name: "Nave", Values: []float64{4, 5, 6, 7}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BoxPlot(c, groups, mujica.BoxPlotOptions{Frame: mujica.ChartFrame{Label: "Hymns"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1WaterfallCode = `steps := []mujica.WaterfallStep{ + {Label: "Tithes", Value: 12}, + {Label: "Repairs", Value: -5}, + {Label: "Year", Kind: mujica.WaterfallTotal}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.WaterfallChart(c, steps, mujica.WaterfallChartOptions{Frame: mujica.ChartFrame{Label: "Ledger"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1FunnelCode = `stages := []mujica.ChartSlice{{Label: "Visitors", Value: 1000}, {Label: "Novices", Value: 400}, {Label: "Vows", Value: 100}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.FunnelChart(c, stages, mujica.FunnelChartOptions{Frame: mujica.ChartFrame{Label: "Order"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1BulletCode = `target := 250.0 +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BulletChart(c, 270, mujica.BulletChartOptions{Frame: mujica.ChartFrame{Label: "Alms"}, Target: &target, Bands: []float64{150, 225, 300}}) +} +ui.Render(view, 400, 300, 1)` + +const c1SparkCode = `values := []float64{3, 5, 4, 7, 6, 9} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Sparkline(c, values, mujica.SparklineOptions{Frame: mujica.ChartFrame{Label: "Bells"}, Kind: mujica.SparklineArea}) +} +ui.Render(view, 400, 300, 1)` + +const c1GaugeCode = `segments := []mujica.GaugeSegment{{To: 60, Label: "Calm", Tone: mujica.GaugeGood}, {To: 100, Label: "Crowded", Tone: mujica.GaugeDanger}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Gauge(c, 72, mujica.GaugeOptions{Frame: mujica.ChartFrame{Label: "Nave"}, Max: 100, Unit: "%", Segments: segments}) +} +ui.Render(view, 400, 300, 1)` + +const c1TreemapCode = `var path []string +root := mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, +}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Treemap(c, &path, root, mujica.TreemapOptions{Frame: mujica.ChartFrame{Label: "Rooms"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1SunburstCode = `var path []string +root := mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, +}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Sunburst(c, &path, root, mujica.SunburstOptions{Frame: mujica.ChartFrame{Label: "Rooms"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1SankeyCode = `nodes := []mujica.SankeyNode{{ID: "tithe", Label: "Tithes"}, {ID: "fund", Label: "Fund"}, {ID: "roof", Label: "Roof"}} +links := []mujica.SankeyLink{{From: "tithe", To: "fund", Value: 60}, {From: "fund", To: "roof", Value: 50}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.SankeyChart(c, nodes, links, mujica.SankeyChartOptions{Frame: mujica.ChartFrame{Label: "Money"}}) +} +ui.Render(view, 400, 300, 1)` + +const c1NetworkCode = `var state mujica.NetworkGraphState +nodes := []mujica.GraphNode{{ID: "a", Label: "Abbot"}, {ID: "b", Label: "Prior"}, {ID: "c", Label: "Novice"}} +edges := []mujica.GraphEdge{{From: "a", To: "b"}, {From: "b", To: "c"}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.NetworkGraph(c, &state, nodes, edges, mujica.NetworkGraphOptions{Frame: mujica.ChartFrame{Label: "House"}, Force: true}) +} +ui.Render(view, 400, 300, 1)` + +const c1RealtimeCode = `buf := mujica.NewRealtimeBuffer(600, "Bell") +start := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC) +for i := range 60 { + buf.Append(start.Add(time.Duration(i)*time.Second), float64(i%7)) +} +var state mujica.RealtimeChartState +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RealtimeChart(c, &state, buf, mujica.RealtimeChartOptions{Frame: mujica.ChartFrame{Label: "Sound"}, Window: 30 * time.Second}) +} +ui.Render(view, 400, 300, 1)` diff --git a/examples/gallery/pages_charts1_flow.go b/examples/gallery/pages_charts1_flow.go new file mode 100644 index 0000000..02161ff --- /dev/null +++ b/examples/gallery/pages_charts1_flow.go @@ -0,0 +1,137 @@ +package main + +import ( + "fmt" + "math" + "strings" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +var c1Abbey = mujica.ChartNode{Name: "Abbey", Children: []mujica.ChartNode{ + {Name: "Library", Children: []mujica.ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}, {Name: "Letters", Value: 8}}}, + {Name: "Kitchen", Value: 25}, + {Name: "Garden", Children: []mujica.ChartNode{{Name: "Herbs", Value: 12}, {Name: "Vines", Value: 8}}}, + {Name: "Chapel", Children: []mujica.ChartNode{{Name: "Nave", Value: 18}, {Name: "Crypt", Value: 6}}}, +}} + +func c1TreemapDemo(c *ui.Context, log func(string)) { + type state struct { + status string + path []string + } + s := ui.Local(c.Root(), "116", func() state { return state{status: "Ready"} }) + c1Section(c, "Treemap", func() {}, func() { + frame, show := c1Frame(c, "Rooms", &s.status) + root := c1Abbey + if !show { + root = mujica.ChartNode{Name: "Abbey"} + s.path = nil + } + r := mujica.Treemap(c, &s.path, root, mujica.TreemapOptions{Frame: frame}) + c1Log(log, "Treemap", r) + if r.ValueChanged() { + log("Treemap: path /" + strings.Join(s.path, "/")) + } + }) +} + +func c1SunburstDemo(c *ui.Context, log func(string)) { + type state struct { + status string + path []string + depth float64 + } + s := ui.Local(c.Root(), "117", func() state { return state{status: "Ready", depth: 2} }) + c1Section(c, "Sunburst", func() { + ui.Text(c, fmt.Sprintf("%.0f rings", s.depth)) + ui.StepSlider(c, &s.depth, 1, 3, 1).Width(120) + }, func() { + frame, show := c1Frame(c, "Rooms", &s.status) + frame.Height = 300 + root := c1Abbey + if !show { + root = mujica.ChartNode{Name: "Abbey"} + s.path = nil + } + r := mujica.Sunburst(c, &s.path, root, mujica.SunburstOptions{Frame: frame, Depth: int(s.depth)}) + c1Log(log, "Sunburst", r) + if r.ValueChanged() { + log("Sunburst: path /" + strings.Join(s.path, "/")) + } + }) +} + +func c1SankeyDemo(c *ui.Context, log func(string)) { + type state struct{ status string } + s := ui.Local(c.Root(), "118", func() state { return state{status: "Ready"} }) + c1Section(c, "SankeyChart", func() {}, func() { + frame, show := c1Frame(c, "Money", &s.status) + nodes := []mujica.SankeyNode{{ID: "tithe", Label: "Tithes"}, {ID: "alms", Label: "Alms"}, {ID: "fund", Label: "Fund"}, {ID: "roof", Label: "Roof"}, {ID: "bread", Label: "Bread"}, {ID: "bells", Label: "Bells"}} + links := []mujica.SankeyLink{{From: "tithe", To: "fund", Value: 60}, {From: "alms", To: "fund", Value: 30}, {From: "alms", To: "bread", Value: 10}, {From: "fund", To: "roof", Value: 50}, {From: "fund", To: "bells", Value: 40}} + if !show { + links = nil + } + c1Log(log, "SankeyChart", mujica.SankeyChart(c, nodes, links, mujica.SankeyChartOptions{Frame: frame})) + }) +} + +func c1NetworkDemo(c *ui.Context, log func(string)) { + type state struct { + status string + force bool + graph mujica.NetworkGraphState + } + s := ui.Local(c.Root(), "119", func() state { return state{status: "Ready", force: true} }) + c1Section(c, "NetworkGraph", func() { + ui.Checkbox(c, &s.force, "Force layout") + if mujica.Button(c, "Reset view", mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() { + s.graph.ResetView() + log("NetworkGraph: reset view") + } + }, func() { + frame, show := c1Frame(c, "House", &s.status) + nodes := []mujica.GraphNode{{ID: "a", Label: "Abbot", X: 0, Y: 0}, {ID: "b", Label: "Prior", X: 10, Y: 0}, {ID: "c", Label: "Cellarer", X: 10, Y: 10}, {ID: "d", Label: "Novice", X: 0, Y: 10}, {ID: "e", Label: "Cantor", X: 5, Y: 5}} + edges := []mujica.GraphEdge{{From: "a", To: "b"}, {From: "a", To: "c"}, {From: "c", To: "d"}, {From: "b", To: "e"}, {From: "e", To: "d"}} + if !show { + nodes, edges = nil, nil + } + c1Log(log, "NetworkGraph", mujica.NetworkGraph(c, &s.graph, nodes, edges, mujica.NetworkGraphOptions{Frame: frame, Force: s.force})) + }) +} + +func c1RealtimeDemo(c *ui.Context, log func(string)) { + type state struct { + status string + feed bool + buf *mujica.RealtimeBuffer + next time.Time + tick int + view mujica.RealtimeChartState + } + s := ui.Local(c.Root(), "120", func() state { + return state{status: "Ready", feed: true, buf: mujica.NewRealtimeBuffer(600, "Bell", "Organ")} + }) + // The demo appends a sample every 500 ms while feeding. + if s.feed && !c.Now().Before(s.next) { + t := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC).Add(time.Duration(s.tick) * 500 * time.Millisecond) + x := float64(s.tick) + s.buf.Append(t, 5+3*math.Sin(x/6), 4+2*math.Sin(x/4+1)) + s.tick++ + s.next = c.Now().Add(500 * time.Millisecond) + } + if s.feed { + c.After(s.next.Sub(c.Now())) + } + c1Section(c, "RealtimeChart", func() { ui.Checkbox(c, &s.feed, "Feed data") }, func() { + frame, _ := c1Frame(c, "Sound", &s.status) + r := mujica.RealtimeChart(c, &s.view, s.buf, mujica.RealtimeChartOptions{Frame: frame, Window: 20 * time.Second}) + c1Log(log, "RealtimeChart", r) + if r.ValueChanged() { + log(fmt.Sprintf("RealtimeChart: paused=%v", s.view.Paused)) + } + }) +} diff --git a/examples/gallery/pages_charts1_series.go b/examples/gallery/pages_charts1_series.go new file mode 100644 index 0000000..6716f57 --- /dev/null +++ b/examples/gallery/pages_charts1_series.go @@ -0,0 +1,197 @@ +package main + +import ( + "fmt" + "math" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +func c1Series(gap bool) []mujica.ChartSeries { + a := []float64{3, 5, 4, 6, 8, 7, 9, 11} + if gap { + a = []float64{3, 5, math.NaN(), 6, 8, 7, 9, 11} + } + return []mujica.ChartSeries{ + {Name: "Matins", Values: a}, + {Name: "Vespers", Values: []float64{2, 3, 5, 4, 6, 9, 8, 7}}, + {Name: "Compline", Values: []float64{1, 2, 2, 3, 2, 4, 5, 4}}, + } +} + +func c1LineDemo(c *ui.Context, log func(string)) { + type state struct { + status string + gap, time bool + big bool + } + s := ui.Local(c.Root(), "101", func() state { return state{status: "Ready", gap: true} }) + c1Section(c, "LineChart", func() { + ui.Checkbox(c, &s.gap, "Missing value") + ui.Checkbox(c, &s.time, "Time axis") + ui.Checkbox(c, &s.big, "100,000 points") + }, func() { + frame, show := c1Frame(c, "Attendance", &s.status) + series, opts := c1Series(s.gap), mujica.LineChartOptions{Frame: frame} + if s.big { + series = []mujica.ChartSeries{{Name: "Wave", Values: c1Wave()}} + } + if s.time { + t0 := time.Date(2026, 10, 5, 6, 0, 0, 0, time.UTC) + opts.Times = make([]time.Time, len(series[0].Values)) + for i := range opts.Times { + opts.Times[i] = t0.Add(time.Duration(i) * time.Hour) + } + } + if !show { + series = nil + opts.Times = nil + } + c1Log(log, "LineChart", mujica.LineChart(c, series, opts)) + }) +} + +var c1WaveData []float64 + +// c1Wave is 100,000 points, made once. +func c1Wave() []float64 { + if c1WaveData == nil { + c1WaveData = make([]float64, 100_000) + for i := range c1WaveData { + c1WaveData[i] = math.Sin(float64(i)/900) + 0.3*math.Sin(float64(i)/37) + } + } + return c1WaveData +} + +func c1AreaDemo(c *ui.Context, log func(string)) { + type state struct { + status string + stacked bool + base float64 + } + s := ui.Local(c.Root(), "102", func() state { return state{status: "Ready", stacked: true} }) + c1Section(c, "AreaChart", func() { + ui.Checkbox(c, &s.stacked, "Stacked") + ui.Text(c, fmt.Sprintf("Baseline %.0f", s.base)) + ui.StepSlider(c, &s.base, -4, 4, 1).Width(140) + }, func() { + frame, show := c1Frame(c, "Attendance", &s.status) + series := c1Series(false) + if !show { + series = nil + } + c1Log(log, "AreaChart", mujica.AreaChart(c, series, mujica.AreaChartOptions{Frame: frame, Stacked: s.stacked, Baseline: s.base})) + }) +} + +func c1BarDemo(c *ui.Context, log func(string)) { + type state struct { + status string + horizontal, stacked, labels bool + } + s := ui.Local(c.Root(), "103", func() state { return state{status: "Ready", labels: true} }) + c1Section(c, "BarChart", func() { + ui.Checkbox(c, &s.horizontal, "Horizontal") + ui.Checkbox(c, &s.stacked, "Stacked") + ui.Checkbox(c, &s.labels, "Labels") + }, func() { + frame, show := c1Frame(c, "Tithes", &s.status) + cats := []string{"Nave", "Choir", "Crypt", "Bells"} + series := []mujica.ChartSeries{{Name: "Gold", Values: []float64{4, -2, 3, 5}}, {Name: "Silver", Values: []float64{2, 5, 1, -1}}} + if !show { + series = nil + } + c1Log(log, "BarChart", mujica.BarChart(c, cats, series, mujica.BarChartOptions{Frame: frame, Horizontal: s.horizontal, Stacked: s.stacked, Labels: s.labels})) + }) +} + +func c1PieDemo(c *ui.Context, log func(string)) { + type state struct { + status string + donut bool + min float64 + } + s := ui.Local(c.Root(), "104", func() state { return state{status: "Ready", donut: true, min: 20} }) + c1Section(c, "PieChart", func() { + ui.Checkbox(c, &s.donut, "Donut") + ui.Text(c, fmt.Sprintf("Merge under %.0f°", s.min)) + ui.StepSlider(c, &s.min, 0, 40, 5).Width(140) + }, func() { + frame, show := c1Frame(c, "Stores", &s.status) + slices := []mujica.ChartSlice{{Label: "Wax", Value: 50}, {Label: "Oil", Value: 30}, {Label: "Myrrh", Value: 12}, {Label: "Salt", Value: 4}, {Label: "Ash", Value: 4}} + if !show { + slices = nil + } + c1Log(log, "PieChart", mujica.PieChart(c, slices, mujica.PieChartOptions{Frame: frame, Donut: s.donut, MinAngle: s.min})) + }) +} + +func c1ScatterDemo(c *ui.Context, log func(string)) { + type state struct { + status string + bubbles bool + selected []mujica.ScatterKey + } + s := ui.Local(c.Root(), "105", func() state { return state{status: "Ready", bubbles: true} }) + c1Section(c, "ScatterChart", func() { + ui.Checkbox(c, &s.bubbles, "Bubbles") + ui.Text(c, fmt.Sprintf("%d selected", len(s.selected))) + }, func() { + frame, show := c1Frame(c, "Choir", &s.status) + groups := []mujica.ScatterGroup{ + {Name: "Monks", Points: []mujica.ScatterPoint{{X: 1, Y: 2, Size: 4}, {X: 3, Y: 5, Size: 9}, {X: 6, Y: 4, Size: 1}, {X: 7, Y: 8, Size: 6}}}, + {Name: "Nuns", Points: []mujica.ScatterPoint{{X: 2, Y: 7, Size: 16}, {X: 8, Y: 9, Size: 2}, {X: 5, Y: 2, Size: 8}}}, + } + if !show { + groups = nil + } + r := mujica.ScatterChart(c, &s.selected, groups, mujica.ScatterChartOptions{Frame: frame, Bubbles: s.bubbles}) + c1Log(log, "ScatterChart", r) + if r.ValueChanged() { + log(fmt.Sprintf("ScatterChart: %d selected", len(s.selected))) + } + }) +} + +func c1RadarDemo(c *ui.Context, log func(string)) { + type state struct{ status string } + s := ui.Local(c.Root(), "106", func() state { return state{status: "Ready"} }) + c1Section(c, "RadarChart", func() {}, func() { + frame, show := c1Frame(c, "Skills", &s.status) + series := []mujica.ChartSeries{{Name: "Agnès", Values: []float64{8, 6, 9, 4, 7}}, {Name: "Clare", Values: []float64{5, 9, 6, 8, 3}}} + if !show { + series = nil + } + c1Log(log, "RadarChart", mujica.RadarChart(c, []string{"Voice", "Latin", "Chant", "Organ", "Bells"}, series, mujica.RadarChartOptions{Frame: frame})) + }) +} + +func c1HeatDemo(c *ui.Context, log func(string)) { + type state struct { + status string + gaps bool + } + s := ui.Local(c.Root(), "107", func() state { return state{status: "Ready", gaps: true} }) + c1Section(c, "HeatmapChart", func() { ui.Checkbox(c, &s.gaps, "Empty cells") }, func() { + frame, show := c1Frame(c, "Hours", &s.status) + rows, cols := []string{"Mon", "Tue", "Wed", "Thu"}, []string{"Matins", "Lauds", "Terce", "Vespers", "Compline"} + values := make([][]float64, len(rows)) + for r := range rows { + values[r] = make([]float64, len(cols)) + for col := range cols { + values[r][col] = float64((r*7 + col*5) % 11) + if s.gaps && (r+col)%6 == 1 { + values[r][col] = math.NaN() + } + } + } + if !show { + rows, values = nil, nil + } + c1Log(log, "HeatmapChart", mujica.HeatmapChart(c, rows, cols, values, mujica.HeatmapChartOptions{Frame: frame})) + }) +} diff --git a/examples/gallery/pages_charts1_stats.go b/examples/gallery/pages_charts1_stats.go new file mode 100644 index 0000000..3cb2c1e --- /dev/null +++ b/examples/gallery/pages_charts1_stats.go @@ -0,0 +1,171 @@ +package main + +import ( + "fmt" + "math" + "strconv" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +func c1CalendarDemo(c *ui.Context, log func(string)) { + type state struct { + status, start string + year int + } + s := ui.Local(c.Root(), "108", func() state { return state{status: "Ready", start: "Monday", year: 2026} }) + c1Section(c, "CalendarHeatmap", func() { ui.Select(c, &s.start, []string{"Locale", "Sunday", "Monday", "Saturday"}) }, func() { + frame, show := c1Frame(c, "Prayers", &s.status) + frame.Height = 160 + values := map[mujica.Date]float64{} + if show { + d := mujica.Date{Year: s.year, Month: time.January, Day: 1} + for i := range 366 { + if (i*37)%5 != 0 { + values[d.AddDays(i)] = float64((i * 13) % 9) + } + } + } + start := map[string]mujica.WeekStart{"Locale": mujica.WeekStartLocale, "Sunday": mujica.WeekStartSunday, "Monday": mujica.WeekStartMonday, "Saturday": mujica.WeekStartSaturday}[s.start] + r := mujica.CalendarHeatmap(c, &s.year, values, mujica.CalendarHeatmapOptions{Frame: frame, WeekStart: start}) + c1Log(log, "CalendarHeatmap", r) + if r.ValueChanged() { + log("CalendarHeatmap: year " + strconv.Itoa(s.year)) + } + }) +} + +func c1HistogramDemo(c *ui.Context, log func(string)) { + type state struct { + status string + bins float64 + cumulative bool + values []float64 + } + s := ui.Local(c.Root(), "109", func() state { + v := make([]float64, 500) + for i := range v { + v[i] = 50 + 12*math.Sin(float64(i)*1.7)*math.Cos(float64(i)*0.31) + } + return state{status: "Ready", bins: 10, values: v} + }) + c1Section(c, "Histogram", func() { + ui.Text(c, fmt.Sprintf("%.0f bins", s.bins)) + ui.StepSlider(c, &s.bins, 3, 30, 1).Width(140) + ui.Checkbox(c, &s.cumulative, "Cumulative") + }, func() { + frame, show := c1Frame(c, "Ages", &s.status) + values := s.values + if !show { + values = nil + } + c1Log(log, "Histogram", mujica.Histogram(c, values, mujica.HistogramOptions{Frame: frame, Bins: int(s.bins), Cumulative: s.cumulative})) + }) +} + +func c1BoxDemo(c *ui.Context, log func(string)) { + type state struct{ status string } + s := ui.Local(c.Root(), "110", func() state { return state{status: "Ready"} }) + c1Section(c, "BoxPlot", func() {}, func() { + frame, show := c1Frame(c, "Hymns", &s.status) + groups := []mujica.BoxGroup{ + {Name: "Choir", Values: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 24}}, + {Name: "Nave", Values: []float64{4, 5, 5, 6, 7, 8}}, + {Name: "Crypt", Values: []float64{12, 14, 15, 18, 22, 25}}, + } + if !show { + groups = nil + } + c1Log(log, "BoxPlot", mujica.BoxPlot(c, groups, mujica.BoxPlotOptions{Frame: frame})) + }) +} + +func c1WaterfallDemo(c *ui.Context, log func(string)) { + type state struct{ status string } + s := ui.Local(c.Root(), "111", func() state { return state{status: "Ready"} }) + c1Section(c, "WaterfallChart", func() {}, func() { + frame, show := c1Frame(c, "Ledger", &s.status) + steps := []mujica.WaterfallStep{ + {Label: "Tithes", Value: 12}, {Label: "Repairs", Value: -5}, {Label: "Q1", Kind: mujica.WaterfallSubtotal}, + {Label: "Alms", Value: 4}, {Label: "Bread", Value: -2}, {Label: "Year", Kind: mujica.WaterfallTotal}, + } + if !show { + steps = nil + } + c1Log(log, "WaterfallChart", mujica.WaterfallChart(c, steps, mujica.WaterfallChartOptions{Frame: frame})) + }) +} + +func c1FunnelDemo(c *ui.Context, log func(string)) { + type state struct{ status string } + s := ui.Local(c.Root(), "112", func() state { return state{status: "Ready"} }) + c1Section(c, "FunnelChart", func() {}, func() { + frame, show := c1Frame(c, "Order", &s.status) + stages := []mujica.ChartSlice{{Label: "Visitors", Value: 1000}, {Label: "Novices", Value: 400}, {Label: "Vows", Value: 100}, {Label: "Priors", Value: 12}} + if !show { + stages = nil + } + c1Log(log, "FunnelChart", mujica.FunnelChart(c, stages, mujica.FunnelChartOptions{Frame: frame})) + }) +} + +func c1BulletDemo(c *ui.Context, log func(string)) { + type state struct { + status string + value, target float64 + vertical bool + } + s := ui.Local(c.Root(), "113", func() state { return state{status: "Ready", value: 270, target: 250} }) + c1Section(c, "BulletChart", func() { + ui.Text(c, fmt.Sprintf("Value %.0f", s.value)) + ui.StepSlider(c, &s.value, 0, 300, 10).Width(140) + ui.Checkbox(c, &s.vertical, "Vertical") + }, func() { + frame, _ := c1Frame(c, "Alms", &s.status) + if s.vertical { + frame.Height = 200 + } + target := s.target + c1Log(log, "BulletChart", mujica.BulletChart(c, s.value, mujica.BulletChartOptions{Frame: frame, Target: &target, Bands: []float64{150, 225, 300}, Vertical: s.vertical})) + }) +} + +func c1SparkDemo(c *ui.Context, log func(string)) { + type state struct{ status string } + s := ui.Local(c.Root(), "114", func() state { return state{status: "Ready"} }) + c1Section(c, "Sparkline", func() {}, func() { + frame, show := c1Frame(c, "Bells", &s.status) + values := []float64{3, 5, 4, math.NaN(), 7, 6, 9, 8, 11} + if !show { + values = nil + } + ui.Row(c).Gap(24).Wrap().Children(func() { + for _, k := range []mujica.SparklineKind{mujica.SparklineLine, mujica.SparklineBar, mujica.SparklineArea} { + f := frame + f.Label = fmt.Sprintf("Bells %d", k+1) + c1Log(log, f.Label, mujica.Sparkline(c, values, mujica.SparklineOptions{Frame: f, Kind: k})) + } + }) + }) +} + +func c1GaugeDemo(c *ui.Context, log func(string)) { + type state struct { + status string + value float64 + full bool + } + s := ui.Local(c.Root(), "115", func() state { return state{status: "Ready", value: 72} }) + c1Section(c, "Gauge", func() { + ui.Text(c, fmt.Sprintf("Value %.0f", s.value)) + ui.StepSlider(c, &s.value, 0, 100, 1).Width(140) + ui.Checkbox(c, &s.full, "Full circle") + }, func() { + frame, _ := c1Frame(c, "Nave", &s.status) + segments := []mujica.GaugeSegment{{To: 60, Label: "Calm", Tone: mujica.GaugeGood}, {To: 85, Label: "Busy", Tone: mujica.GaugeWarning}, {To: 100, Label: "Crowded", Tone: mujica.GaugeDanger}} + c1Log(log, "Gauge", mujica.Gauge(c, s.value, mujica.GaugeOptions{Frame: frame, Max: 100, Unit: "%", Segments: segments, Full: s.full})) + }) +} diff --git a/examples/gallery/pages_charts1_test.go b/examples/gallery/pages_charts1_test.go new file mode 100644 index 0000000..af673ca --- /dev/null +++ b/examples/gallery/pages_charts1_test.go @@ -0,0 +1,71 @@ +package main + +import ( + "slices" + "strings" + "testing" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +// c1Demo runs page id's demo with an event log. +func c1Demo(t *testing.T, id string) (*ui.Tester, *[]string) { + t.Helper() + i := slices.IndexFunc(charts1Pages, func(p page) bool { return p.ID == id }) + if i < 0 { + t.Fatalf("no page %s", id) + } + events := &[]string{} + tt := ui.NewTester(func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + ui.Scroll(c).Fill().Padding(24).Children(func() { + charts1Pages[i].Demo(c, func(s string) { *events = append(*events, s) }) + }) + }, 900, 760) + tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) + return tt, events +} + +// c1Labels names each demo's chart for the keys. +var c1Labels = map[string]string{ + "101": "Attendance", "102": "Attendance", "103": "Tithes", "104": "Stores", "105": "Choir", "106": "Skills", + "107": "Hours", "108": "Prayers", "109": "Ages", "110": "Hymns", "111": "Ledger", "112": "Order", "113": "Alms", + "114": "Bells 1", "115": "Nave", "116": "Rooms", "117": "Rooms", "118": "Money", "119": "House", "120": "Sound", +} + +func TestCharts1DemosLogReadouts(t *testing.T) { + for _, p := range charts1Pages { + if p.Category != "Charts I" || p.Code == "" || p.Keys == "" { + t.Fatalf("%s: incomplete page", p.ID) + } + tt, events := c1Demo(t, p.ID) + tabUntil(t, tt, c1Labels[p.ID]) + tt.Key(0, ui.KeyRight) + if len(*events) == 0 || !strings.HasSuffix((*events)[len(*events)-1], "point 0") { + t.Errorf("%s: keyboard readout not logged: %q", p.ID, *events) + } + } +} + +func TestCharts1TreemapDrillLogs(t *testing.T) { + tt, events := c1Demo(t, "116") + tabUntil(t, tt, "Rooms") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyEnter) + if !slices.Contains(*events, "Treemap: path /Library") { + t.Fatalf("drill not logged: %q", *events) + } +} + +func tabUntil(t *testing.T, tt *ui.Tester, label string) { + t.Helper() + for range 40 { + if tt.Focused(label) { + return + } + tt.Key(0, ui.KeyTab) + } + t.Fatalf("Tab never reached %q", label) +} diff --git a/funnel_chart.go b/funnel_chart.go new file mode 100644 index 0000000..afac694 --- /dev/null +++ b/funnel_chart.go @@ -0,0 +1,85 @@ +package mujica + +import ( + "fmt" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// FunnelChartOptions configure a FunnelChart. +type FunnelChartOptions struct { + Frame ChartFrame + Format func(v float64) string +} + +// FunnelChart narrows by stage, labeled with conversion rates. +func FunnelChart(c *ui.Context, stages []ChartSlice, opts FunnelChartOptions) ChartResult { + top := 0.0 + for _, s := range stages { + if s.Label == "" || s.Value < 0 || math.IsNaN(s.Value) || math.IsInf(s.Value, 0) { + panic("mujica: FunnelChart stages need a label and a finite value ≥ 0") + } + top = max(top, s.Value) + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + col := internal.Palette(k)[0] + size := FontSize(c, theme.CaptionSize) + n := len(stages) + if top == 0 { + n = 0 + } + pct := func(a, b float64) string { + if b == 0 { + return "—" + } + return fmt.Sprintf("%.1f%%", 100*a/b) + } + rate := func(i int) string { + if i == 0 { + return pct(stages[0].Value, stages[0].Value) + } + return pct(stages[i].Value, stages[i-1].Value) + } + geom := func(r ui.Rect) (ui.Rect, internal.Band) { + plot := ui.Rect{X: r.X + 8, Y: r.Y + 4, W: r.W * 0.58, H: r.H - 8} + return plot, internal.Band{N: len(stages), R0: plot.Y, R1: plot.Y + plot.H, Pad: 0.08} + } + spec := chartSpec{n: n} + spec.readout = func(i int) string { + s := stages[i] + return fmt.Sprintf(msg(c, "funnel_chart.readout"), s.Label, chartValue(c, s.Value, opts.Format), rate(i), pct(s.Value, stages[0].Value)) + } + spec.pick = func(r ui.Rect, x, y float32) int { + plot, band := geom(r) + if y < plot.Y || y >= plot.Y+plot.H || x < r.X || x > r.X+r.W { + return -1 + } + return min(len(stages)-1, int((y-plot.Y)/band.Step())) + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, band := geom(r) + cx := plot.X + plot.W/2 + width := func(i int) float32 { return max(plot.W*float32(stages[min(i, len(stages)-1)].Value/top), 2) } + for i, s := range stages { + y0, y1 := band.Start(i), band.Start(i)+band.Width() + w0, w1 := width(i), width(i+1) + var shape ui.Path + shape.MoveTo(cx-w0/2, y0).LineTo(cx+w0/2, y0).LineTo(cx+w1/2, y1).LineTo(cx-w1/2, y1).Close() + p.FillPath(&shape, col) + if i == active { + p.StrokePath(&shape, 2, k.Text) + } + ly := (y0 + y1) / 2 + lx := plot.X + plot.W + 16 + chartText(p, s.Label+" · "+chartValue(c, s.Value, opts.Format), lx, ly, size, k.Text, 0, 1) + chartText(p, rate(i), lx, ly+2, size, k.TextMuted, 0, 0) + } + } + res, _ := ch.build(spec) + return res +} diff --git a/funnel_chart_test.go b/funnel_chart_test.go new file mode 100644 index 0000000..d3dbfa6 --- /dev/null +++ b/funnel_chart_test.go @@ -0,0 +1,54 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +var funnelStages = []ChartSlice{{"Visitors", 1000}, {"Novices", 400}, {"Vows", 100}, {"Abbots", 0}} + +func TestFunnelChartReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return FunnelChart(c, funnelStages, FunnelChartOptions{Frame: ChartFrame{Label: "Order"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Order") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Novices · 400 · 40.0% of the stage before · 40.0% of the first" { + t.Fatalf("readout %q", got) + } + tt.Key(0, ui.KeyEscape) + b := h.res.Element.Bounds() + tt.Move(b.X+b.W/3, b.Y+4+232*0.6) // third stage band + if got := chartReadout(tt); got != "Vows · 100 · 25.0% of the stage before · 10.0% of the first" { + t.Fatalf("hover %q", got) + } +} + +func TestFunnelChartBadAndEmpty(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return FunnelChart(c, []ChartSlice{{"a", 0}}, FunnelChartOptions{Frame: ChartFrame{Label: "Order"}}) + }} + if tt := ui.NewTester(h.view, 520, 420); !tt.HasText("No data") { + t.Fatal("all-zero funnel is not empty") + } + defer func() { + if recover() == nil { + t.Fatal("no panic for a negative stage") + } + }() + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + FunnelChart(c, []ChartSlice{{"a", -1}}, FunnelChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestFunnelChartSnapshot(t *testing.T) { + snapshot(t, "funnel_chart", 520, 300, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + FunnelChart(c, funnelStages[:3], FunnelChartOptions{Frame: ChartFrame{Label: "Order", Height: 220}}) + }) + }) +} diff --git a/gauge.go b/gauge.go new file mode 100644 index 0000000..21915df --- /dev/null +++ b/gauge.go @@ -0,0 +1,154 @@ +package mujica + +import ( + "fmt" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// GaugeTone colors a Gauge segment; its label still names it. +type GaugeTone int + +const ( + GaugeNeutral GaugeTone = iota + GaugeGood + GaugeWarning + GaugeDanger +) + +// GaugeSegment is a named dial range up to To. +type GaugeSegment struct { + To float64 + Label string + Tone GaugeTone +} + +// GaugeOptions configure a Gauge; Frame.Height 0 means 200 DIPs. +type GaugeOptions struct { + Frame ChartFrame + Min, Max float64 + // Segments split Min..Max ascending; the last ends at Max. + Segments []GaugeSegment + Unit string + // Full draws a whole circle instead of a half. + Full bool + Format func(v float64) string +} + +// Gauge points a needle at value on named segments. +func Gauge(c *ui.Context, value float64, opts GaugeOptions) ChartResult { + if !(opts.Max > opts.Min) || math.IsNaN(value) || value < opts.Min || value > opts.Max { + panic("mujica: Gauge needs Min < Max and a value between them") + } + prev := opts.Min + for i, s := range opts.Segments { + if s.To <= prev || s.Label == "" || i == len(opts.Segments)-1 && s.To != opts.Max { + panic("mujica: Gauge segments need labels and ascending ends finishing at Max") + } + prev = s.To + } + if opts.Frame.Height == 0 { + opts.Frame.Height = 200 + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + size := FontSize(c, theme.CaptionSize) + tone := func(t GaugeTone) ui.Color { + return map[GaugeTone]ui.Color{GaugeNeutral: internal.Palette(k)[5], GaugeGood: k.Success, GaugeWarning: k.Warning, GaugeDanger: k.Danger}[t] + } + val := func(v float64) string { return chartValue(c, v, opts.Format) } + seg := -1 + for i, s := range opts.Segments { + if value <= s.To && seg < 0 { + seg = i + } + } + a0, a1 := -math.Pi/2, math.Pi/2 + if opts.Full { + a0, a1 = -math.Pi, math.Pi + } + angle := func(v float64) float64 { return a0 + (a1-a0)*(v-opts.Min)/(opts.Max-opts.Min) } + geom := func(r ui.Rect) (cx, cy, rad float32) { + if opts.Full { + rad = min(r.W, r.H)/2 - 12 + return r.X + r.W/2, r.Y + r.H/2, rad + } + rad = min(r.W/2-12, r.H-36) + return r.X + r.W/2, r.Y + 8 + rad, rad + } + reading := val(value) + " " + opts.Unit + if seg >= 0 { + reading += " · " + opts.Segments[seg].Label + } + spec := chartSpec{n: 1 + len(opts.Segments)} + spec.readout = func(i int) string { + if i == 0 { + return reading + } + s, from := opts.Segments[i-1], opts.Min + if i > 1 { + from = opts.Segments[i-2].To + } + return fmt.Sprintf("%s: %s–%s", s.Label, val(from), val(s.To)) + } + spec.pick = func(r ui.Rect, x, y float32) int { + cx, cy, rad := geom(r) + d := float32(math.Hypot(float64(x-cx), float64(y-cy))) + if d < rad*0.45 { + return 0 + } + if d > rad+6 { + return -1 + } + a := math.Atan2(float64(x-cx), float64(cy-y)) + from := a0 + for i, s := range opts.Segments { + if a >= from && a <= angle(s.To) { + return i + 1 + } + from = angle(s.To) + } + return -1 + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + cx, cy, rad := geom(r) + from := a0 + if len(opts.Segments) == 0 { + p.FillPath(internal.Sector(cx, cy, rad*0.78, rad, a0, a1), k.SurfaceHover) + } + for i, s := range opts.Segments { + to := angle(s.To) + grow := float32(0) + if active == i+1 { + grow = 4 + } + p.FillPath(internal.Sector(cx, cy, rad*0.78-grow, rad+grow, from, to), tone(s.Tone)) + p.StrokePath(internal.Sector(cx, cy, rad*0.78-grow, rad+grow, from, to), 1.5, k.Surface) + lx, ly := internal.Polar(cx, cy, rad+10, to) + if i < len(opts.Segments)-1 { + chartText(p, val(s.To), lx, ly, size, k.TextMuted, 0.5, 1) + } + from = to + } + nx, ny := internal.Polar(cx, cy, rad*0.9, angle(value)) + var needle ui.Path + needle.MoveTo(cx, cy).LineTo(internal.Snap(p, nx), internal.Snap(p, ny)) + w := float32(3) + if active == 0 { + w = 4.5 + } + p.StrokePath(&needle, w, k.Text) + p.FillPath(internal.Diamond(cx, cy, 12), k.Text) + ty := cy + 34 + chartText(p, val(value)+" "+opts.Unit, cx, ty, FontSize(c, theme.H3Size), k.Text, 0.5, 1) + if seg >= 0 { + chartText(p, opts.Segments[seg].Label, cx, ty+2, size, k.TextMuted, 0.5, 0) + } + } + res, _ := ch.build(spec) + return res +} diff --git a/gauge_test.go b/gauge_test.go new file mode 100644 index 0000000..5f87b6a --- /dev/null +++ b/gauge_test.go @@ -0,0 +1,75 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +var gaugeSegments = []GaugeSegment{{60, "Calm", GaugeGood}, {85, "Busy", GaugeWarning}, {100, "Crowded", GaugeDanger}} + +func TestGaugeReadoutNamesSegment(t *testing.T) { + full := false + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return Gauge(c, 72, GaugeOptions{Frame: ChartFrame{Label: "Nave"}, Max: 100, Unit: "%", Segments: gaugeSegments, Full: full}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Nave") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "72 % · Busy" { + t.Fatalf("value %q", got) + } + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); got != "Crowded: 85–100" { + t.Fatalf("last segment %q", got) + } + tt.Key(0, ui.KeyEscape) + for _, full = range []bool{false, true} { + tt.Frame() + b := h.res.Element.Bounds() + cx := b.X + b.W/2 + var cy, rad float32 + if full { + rad = 200/2 - 12 + cy = b.Y + 100 + } else { + rad = min(b.W/2-12, 200-36) + cy = b.Y + 8 + rad + } + tt.Move(cx-rad*0.7, cy-rad*0.6) // the left of the dial: the first segment + if got := chartReadout(tt); got != "Calm: 0–60" { + t.Fatalf("full=%v hover %q", full, got) + } + } +} + +func TestGaugeBad(t *testing.T) { + for name, o := range map[string]GaugeOptions{ + "range": {Max: 0}, + "segments": {Max: 100, Segments: []GaugeSegment{{50, "a", 0}, {40, "b", 0}}}, + "end": {Max: 100, Segments: []GaugeSegment{{50, "a", 0}}}, + } { + func() { + defer func() { + if recover() == nil { + t.Errorf("%s: no panic", name) + } + }() + o.Frame.Label = "x" + ui.NewTester(func(c *ui.Context) { Use(c, Settings{}); Gauge(c, 0, o) }, 300, 300) + }() + } +} + +func TestGaugeSnapshot(t *testing.T) { + snapshot(t, "gauge", 560, 300, func(c *ui.Context) { + ui.Row(c).Padding(16).Gap(16).Children(func() { + ui.Column(c).Width(256).Children(func() { + Gauge(c, 72, GaugeOptions{Frame: ChartFrame{Label: "Half"}, Max: 100, Unit: "%", Segments: gaugeSegments}) + }) + ui.Column(c).Width(256).Children(func() { + Gauge(c, 30, GaugeOptions{Frame: ChartFrame{Label: "Full"}, Max: 100, Unit: "%", Segments: gaugeSegments, Full: true}) + }) + }) + }) +} diff --git a/heatmap_chart.go b/heatmap_chart.go new file mode 100644 index 0000000..321dbf0 --- /dev/null +++ b/heatmap_chart.go @@ -0,0 +1,123 @@ +package mujica + +import ( + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// HeatmapChartOptions configure a HeatmapChart. +type HeatmapChartOptions struct { + Frame ChartFrame + Format func(v float64) string +} + +// heatSteps is the number of color steps. +const heatSteps = 5 + +// HeatmapChart colors a matrix by value; NaN cells are dashed. +func HeatmapChart(c *ui.Context, rows, cols []string, values [][]float64, opts HeatmapChartOptions) ChartResult { + if len(values) != len(rows) { + panic("mujica: HeatmapChart needs one value row per row label") + } + lo, hi := math.Inf(1), math.Inf(-1) + for _, r := range values { + if len(r) != len(cols) { + panic("mujica: HeatmapChart needs one value per column label") + } + for _, v := range r { + if !math.IsNaN(v) { + lo, hi = min(lo, v), max(hi, v) + } + } + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + size := FontSize(c, theme.CaptionSize) + n := len(rows) * len(cols) + if math.IsInf(lo, 1) { + n = 0 + } + // level is v's color step, 0 to heatSteps-1. + level := func(v float64) int { + if hi == lo { + return heatSteps - 1 + } + return min(heatSteps-1, int((v-lo)/(hi-lo)*heatSteps)) + } + geom := func(r ui.Rect) (ui.Rect, internal.Band, internal.Band) { + plot := ui.Rect{X: r.X + 72, Y: r.Y + 4, W: max(r.W-72-64, 1), H: max(r.H-28, 1)} + return plot, internal.Band{N: len(cols), R0: plot.X, R1: plot.X + plot.W, Pad: 0.06}, internal.Band{N: len(rows), R0: plot.Y, R1: plot.Y + plot.H, Pad: 0.06} + } + cell := func(xb, yb internal.Band, i int) ui.Rect { + return ui.Rect{X: xb.Start(i % len(cols)), Y: yb.Start(i / len(cols)), W: xb.Width(), H: yb.Width()} + } + spec := chartSpec{n: n} + spec.readout = func(i int) string { + return rows[i/len(cols)] + " · " + cols[i%len(cols)] + " · " + chartValue(c, values[i/len(cols)][i%len(cols)], opts.Format) + } + spec.move = func(i int, key ui.Key) int { + r, col := i/len(cols), i%len(cols) + switch key { + case ui.KeyLeft: + col = max(col-1, 0) + case ui.KeyRight: + col = min(col+1, len(cols)-1) + case ui.KeyUp: + r = max(r-1, 0) + default: + r = min(r+1, len(rows)-1) + } + return r*len(cols) + col + } + spec.pick = func(r ui.Rect, x, y float32) int { + plot, xb, yb := geom(r) + if !plot.Contains(x, y) { + return -1 + } + col := min(len(cols)-1, int((x-plot.X)/xb.Step())) + row := min(len(rows)-1, int((y-plot.Y)/yb.Step())) + return row*len(cols) + col + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, xb, yb := geom(r) + for i := range len(rows) * len(cols) { + b := cell(xb, yb, i) + v := values[i/len(cols)][i%len(cols)] + if math.IsNaN(v) { + p.StrokeDashed(b, k.ControlBorder, 2, 1) + } else { + bg := internal.Ramp(k, (float64(level(v))+0.5)/heatSteps) + p.Fill(b, bg, 2) + if b.W >= 30 && b.H >= 18 { + chartText(p, chartValue(c, v, opts.Format), b.X+b.W/2, b.Y+b.H/2, size, chartInk(k, bg), 0.5, 0.5) + } + } + if i == active { + p.Stroke(ui.Rect{X: b.X - 2, Y: b.Y - 2, W: b.W + 4, H: b.H + 4}, k.Text, 3, 2) + } + } + for i, name := range rows { + chartText(p, name, plot.X-8, yb.Center(i), size, k.TextMuted, 1, 0.5) + } + for i, name := range cols { + chartText(p, name, xb.Center(i), plot.Y+plot.H+4, size, k.TextMuted, 0.5, 0) + } + heatLegend(p, ui.Rect{X: plot.X + plot.W + 16, Y: plot.Y, W: 14, H: plot.H}, lo, hi, size, k, opts.Format, c) + } + res, _ := ch.build(spec) + return res +} + +// heatLegend stacks the color steps with the range at ends. +func heatLegend(p *ui.Painter, r ui.Rect, lo, hi float64, size float32, k theme.Tokens, format func(float64) string, c *ui.Context) { + h := min(r.H, 120) / heatSteps + for i := range heatSteps { + p.Fill(ui.Rect{X: r.X, Y: r.Y + float32(heatSteps-1-i)*h, W: r.W, H: h - 1}, internal.Ramp(k, (float64(i)+0.5)/heatSteps), 1) + } + chartText(p, chartValue(c, hi, format), r.X+r.W+4, r.Y, size, k.TextMuted, 0, 0) + chartText(p, chartValue(c, lo, format), r.X+r.W+4, r.Y+h*heatSteps, size, k.TextMuted, 0, 1) +} diff --git a/heatmap_chart_test.go b/heatmap_chart_test.go new file mode 100644 index 0000000..4b6b10d --- /dev/null +++ b/heatmap_chart_test.go @@ -0,0 +1,68 @@ +package mujica + +import ( + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +var heatRows = []string{"Mon", "Tue", "Wed"} +var heatCols = []string{"Matins", "Lauds", "Vespers", "Compline"} + +func heatValues() [][]float64 { + return [][]float64{{1, 4, 9, 2}, {3, math.NaN(), 7, 5}, {8, 6, 0, 3}} +} + +func TestHeatmapChartKeyboard2D(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return HeatmapChart(c, heatRows, heatCols, heatValues(), HeatmapChartOptions{Frame: ChartFrame{Label: "Hours"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Hours") + tt.Key(0, ui.KeyRight) // enters at the first cell + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyDown) + if got := chartReadout(tt); got != "Tue · Lauds · no value" { + t.Fatalf("readout %q", got) + } + tt.Key(0, ui.KeyDown) + tt.Key(0, ui.KeyDown) + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); got != "Wed · Compline · 3" { + t.Fatalf("End %q", got) + } +} + +func TestHeatmapChartHover(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return HeatmapChart(c, heatRows, heatCols, heatValues(), HeatmapChartOptions{Frame: ChartFrame{Label: "Hours"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + b := h.res.Element.Bounds() + plotW := b.W - 72 - 64 + tt.Move(b.X+72+plotW*0.6, b.Y+4+212*0.2) // third column, first row + if got := chartReadout(tt); got != "Mon · Vespers · 9" { + t.Fatalf("hover %q", got) + } +} + +func TestHeatmapChartBad(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for a short row") + } + }() + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + HeatmapChart(c, heatRows[:1], heatCols, [][]float64{{1}}, HeatmapChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestHeatmapChartSnapshot(t *testing.T) { + snapshot(t, "heatmap_chart", 520, 300, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + HeatmapChart(c, heatRows, heatCols, heatValues(), HeatmapChartOptions{Frame: ChartFrame{Label: "Hours", Height: 220}}) + }) + }) +} diff --git a/histogram.go b/histogram.go new file mode 100644 index 0000000..b36e96d --- /dev/null +++ b/histogram.go @@ -0,0 +1,157 @@ +package mujica + +import ( + "fmt" + "math" + "strings" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// HistogramOptions configure a Histogram. +type HistogramOptions struct { + Frame ChartFrame + // Bins is the bin count; 0 uses Sturges' rule. + Bins int + BinWidth float64 + // Cumulative counts every value up to each bin's upper edge. + Cumulative bool + Format func(v float64) string +} + +// histogramMaxBins bounds the bins a width may make. +const histogramMaxBins = 10_000 + +type histBins struct { + start, width float64 + counts []int +} + +// histogramBin counts finite values into equal bins. +func histogramBin(values []float64, bins int, width float64, cumulative bool) histBins { + lo, hi := math.Inf(1), math.Inf(-1) + n := 0 + for _, v := range values { + if !math.IsNaN(v) && !math.IsInf(v, 0) { + lo, hi, n = min(lo, v), max(hi, v), n+1 + } + } + if n == 0 { + return histBins{} + } + var b histBins + switch { + case width > 0: + b.start, b.width = math.Floor(lo/width)*width, width + bins = max(1, int(math.Ceil((hi-b.start)/width-1e-9))) + if hi == b.start+float64(bins)*width { + bins++ + } + default: + if bins == 0 { + bins = int(math.Ceil(math.Log2(float64(n)))) + 1 + } + b.start, b.width = lo, (hi-lo)/float64(bins) + if b.width == 0 { + b.width = 1 + } + } + if bins > histogramMaxBins { + panic("mujica: Histogram would make more than 10000 bins") + } + b.counts = make([]int, bins) + for _, v := range values { + if math.IsNaN(v) || math.IsInf(v, 0) { + continue + } + b.counts[min(bins-1, int((v-b.start)/b.width))]++ + } + if cumulative { + for i := 1; i < bins; i++ { + b.counts[i] += b.counts[i-1] + } + } + return b +} + +// Histogram counts values into equal bins drawn as bars. +func Histogram(c *ui.Context, values []float64, opts HistogramOptions) ChartResult { + if opts.Bins < 0 || opts.BinWidth < 0 || math.IsNaN(opts.BinWidth) { + panic("mujica: Histogram Bins and BinWidth must be ≥ 0") + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + col := internal.Palette(k)[0] + size := FontSize(c, theme.CaptionSize) + b := chartMemo(ch, "bins", [4]any{chartID(values), opts.Bins, opts.BinWidth, opts.Cumulative}, func() histBins { + return histogramBin(values, opts.Bins, opts.BinWidth, opts.Cumulative) + }) + top := 0 + for _, n := range b.counts { + top = max(top, n) + } + var ys internal.Linear + var hi, step float64 + if top > 0 { + _, hi, step = internal.Nice(0, float64(top), 4) + step = max(step, 1) + } + // edge writes bin edge i at a given precision. + edge := func(i int, fine float64) string { + v := b.start + float64(i)*b.width + if opts.Format != nil { + return opts.Format(v) + } + s := internal.FormatTick(v, b.width/fine) + if strings.Contains(s, ".") { + s = strings.TrimRight(strings.TrimRight(s, "0"), ".") + } + return s + } + geom := func(r ui.Rect) (ui.Rect, internal.Band) { + plot := chartInset(r, 52, 26) + ys = internal.Linear{D0: 0, D1: hi, R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + return plot, internal.Band{N: len(b.counts), R0: plot.X, R1: plot.X + plot.W, Pad: 0.06} + } + spec := chartSpec{n: len(b.counts)} + spec.readout = func(i int) string { + if opts.Cumulative { + return fmt.Sprintf("≤ %s · %d", edge(i+1, 100), b.counts[i]) + } + closer := ")" + if i == len(b.counts)-1 && opts.BinWidth == 0 { + closer = "]" + } + return fmt.Sprintf("[%s, %s%s · %d", edge(i, 100), edge(i+1, 100), closer, b.counts[i]) + } + spec.pick = func(r ui.Rect, x, y float32) int { + plot, band := geom(r) + if !plot.Contains(x, y) { + return -1 + } + return min(len(b.counts)-1, int((x-plot.X)/band.Step())) + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, band := geom(r) + internal.AxisY(p, plot, ys, internal.Ticks(0, hi, step), func(v float64) string { return internal.FormatTick(v, step) }, size, k) + var xs []float32 + var labels []string + for i := 0; i <= len(b.counts); i++ { + xs, labels = append(xs, plot.X+band.Step()*float32(i)), append(labels, edge(i, 1)) + } + internal.AxisX(p, plot, xs, labels, size, k) + for i, n := range b.counts { + y := ys.Map(float64(n)) + bar := ui.Rect{X: band.Start(i), Y: y, W: band.Width(), H: plot.Y + plot.H - y} + p.Fill(bar, col, 1) + if i == active { + p.Stroke(ui.Rect{X: bar.X - 2, Y: bar.Y - 2, W: bar.W + 4, H: bar.H + 4}, k.Text, 2, 1.5) + } + } + } + res, _ := ch.build(spec) + return res +} diff --git a/histogram_test.go b/histogram_test.go new file mode 100644 index 0000000..514bbdd --- /dev/null +++ b/histogram_test.go @@ -0,0 +1,76 @@ +package mujica + +import ( + "fmt" + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestHistogramBin(t *testing.T) { + vals := []float64{1, 2, 2, 3, 4, 5, 9, 10, math.NaN()} + if got := histogramBin(vals, 3, 0, false); fmt.Sprint(got.counts) != "[4 2 2]" || got.start != 1 || got.width != 3 { + t.Fatalf("3 bins %+v", got) + } + if got := histogramBin(vals, 0, 5, false); fmt.Sprint(got.counts) != "[5 2 1]" || got.start != 0 { + t.Fatalf("width 5 %+v", got) + } + if got := histogramBin(vals, 0, 5, true); fmt.Sprint(got.counts) != "[5 7 8]" { + t.Fatalf("cumulative %+v", got) + } + if got := histogramBin(vals, 0, 0, false); len(got.counts) != 4 { + t.Fatalf("Sturges for 8 values: %d bins", len(got.counts)) + } + if got := histogramBin([]float64{math.NaN()}, 3, 0, false); got.counts != nil { + t.Fatal("no finite values made bins") + } +} + +func TestHistogramReadoutAndModes(t *testing.T) { + opts := HistogramOptions{Frame: ChartFrame{Label: "Ages"}, BinWidth: 5} + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return Histogram(c, []float64{1, 2, 2, 3, 4, 5, 9, 10}, opts) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Ages") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "[0, 5) · 5" { + t.Fatalf("first bin %q", got) + } + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); got != "[10, 15) · 1" { + t.Fatalf("last bin %q", got) + } + opts.Cumulative = true + tt.Frame() + if got := chartReadout(tt); got != "≤ 15 · 8" { + t.Fatalf("cumulative %q", got) + } +} + +func TestHistogramBad(t *testing.T) { + for _, o := range []HistogramOptions{{Bins: -1}, {BinWidth: 1e-9}} { + func() { + defer func() { + if recover() == nil { + t.Errorf("%+v: no panic", o) + } + }() + o.Frame.Label = "x" + ui.NewTester(func(c *ui.Context) { Use(c, Settings{}); Histogram(c, []float64{0, 1}, o) }, 300, 300) + }() + } +} + +func TestHistogramSnapshot(t *testing.T) { + vals := make([]float64, 400) + for i := range vals { + vals[i] = 50 + 15*math.Sin(float64(i)*1.7)*math.Cos(float64(i)*0.3) + } + snapshot(t, "histogram", 520, 320, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + Histogram(c, vals, HistogramOptions{Frame: ChartFrame{Label: "Ages"}, Bins: 12}) + }) + }) +} diff --git a/internal/chart.go b/internal/chart.go new file mode 100644 index 0000000..30286b9 --- /dev/null +++ b/internal/chart.go @@ -0,0 +1,264 @@ +package internal + +import ( + "math" + "strconv" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// Linear maps domain D0..D1 onto pixels R0..R1. +type Linear struct{ D0, D1, R0, R1 float64 } + +// Map returns the pixel of v. +func (s Linear) Map(v float64) float32 { + if s.D1 == s.D0 { + return float32((s.R0 + s.R1) / 2) + } + return float32(s.R0 + (v-s.D0)/(s.D1-s.D0)*(s.R1-s.R0)) +} + +// Invert returns the value at pixel px. +func (s Linear) Invert(px float32) float64 { + if s.R1 == s.R0 { + return s.D0 + } + return s.D0 + (float64(px)-s.R0)/(s.R1-s.R0)*(s.D1-s.D0) +} + +// Nice widens lo..hi to round steps of about n ticks. +func Nice(lo, hi float64, n int) (nlo, nhi, step float64) { + if n < 1 || math.IsNaN(lo) || math.IsNaN(hi) || lo > hi { + panic("internal: bad Nice domain") + } + if lo == hi { + lo, hi = lo-1, hi+1 + } + raw := (hi - lo) / float64(n) + mag := math.Pow(10, math.Floor(math.Log10(raw))) + step = 10 * mag + for _, m := range []float64{1, 2, 5} { + if m*mag >= raw { + step = m * mag + break + } + } + return math.Floor(lo/step) * step, math.Ceil(hi/step) * step, step +} + +// Ticks lists the multiples of step from lo to hi. +func Ticks(lo, hi, step float64) []float64 { + var out []float64 + for i := math.Ceil(lo/step - 1e-9); i*step <= hi+step*1e-9; i++ { + out = append(out, i*step) + } + return out +} + +// FormatTick writes v with as many decimals as step needs. +func FormatTick(v, step float64) string { + d := max(0, int(-math.Floor(math.Log10(step)+1e-9))) + if math.Abs(v) < step*1e-9 { + v = 0 + } + return strconv.FormatFloat(v, 'f', d, 64) +} + +// timeSteps are the tick spacings a time axis chooses from. +var timeSteps = []struct { + d time.Duration + layout string +}{ + {time.Second, "15:04:05"}, {5 * time.Second, "15:04:05"}, {15 * time.Second, "15:04:05"}, {30 * time.Second, "15:04:05"}, + {time.Minute, "15:04"}, {5 * time.Minute, "15:04"}, {15 * time.Minute, "15:04"}, {30 * time.Minute, "15:04"}, + {time.Hour, "15:04"}, {3 * time.Hour, "15:04"}, {6 * time.Hour, "Jan 2 15:04"}, {12 * time.Hour, "Jan 2 15:04"}, + {24 * time.Hour, "Jan 2"}, {7 * 24 * time.Hour, "Jan 2"}, {30 * 24 * time.Hour, "Jan 2006"}, {365 * 24 * time.Hour, "2006"}, +} + +// TimeTicks returns about n round times and their layout. +func TimeTicks(lo, hi time.Time, n int) ([]time.Time, string) { + if n < 1 || hi.Before(lo) { + panic("internal: bad TimeTicks domain") + } + span := hi.Sub(lo) / time.Duration(n) + step := timeSteps[len(timeSteps)-1] + for _, s := range timeSteps { + if s.d >= span { + step = s + break + } + } + var out []time.Time + for t := lo.Truncate(step.d); !t.After(hi); t = t.Add(step.d) { + if !t.Before(lo) { + out = append(out, t) + } + } + return out, step.layout +} + +// Band splits R0..R1 into N bands, each Pad empty. +type Band struct { + N int + R0, R1 float32 + Pad float32 +} + +// Step is the room one band takes. +func (b Band) Step() float32 { return (b.R1 - b.R0) / float32(max(b.N, 1)) } + +// Width is a band's drawn width. +func (b Band) Width() float32 { return b.Step() * (1 - b.Pad) } + +// Start is where band i is drawn from. +func (b Band) Start(i int) float32 { return b.R0 + b.Step()*float32(i) + b.Step()*b.Pad/2 } + +// Center is the middle of band i. +func (b Band) Center(i int) float32 { return b.R0 + b.Step()*(float32(i)+0.5) } + +// Palette returns six series colors at 3:1 against Surface. +func Palette(k theme.Tokens) []ui.Color { + out := []ui.Color{k.AccentText, k.Info, k.Success, k.Warning, k.Ornament, k.TextMuted} + for i, col := range out { + for t := float32(0.1); theme.Contrast(col, k.Surface) < 3; t += 0.1 { + col = out[i].Mix(k.Text, t) + } + out[i] = col + } + return out +} + +// Ramp is the sequential color for t in 0..1. +func Ramp(k theme.Tokens, t float64) ui.Color { + return k.Surface.Mix(k.AccentText, float32(0.12+0.88*max(0, min(t, 1)))) +} + +// Marker draws series shape i centered at (cx, cy). +func Marker(p *ui.Painter, i int, cx, cy, size float32, col ui.Color) { + cx, cy = Snap(p, cx), Snap(p, cy) + h := size / 2 + var path ui.Path + switch i % 5 { + case 0: + path.Circle(cx, cy, h) + case 1: + h *= 0.85 + path.MoveTo(cx-h, cy-h).LineTo(cx+h, cy-h).LineTo(cx+h, cy+h).LineTo(cx-h, cy+h).Close() + case 2: + p.FillPath(Diamond(cx, cy, size*1.2), col) + return + case 3: + path.MoveTo(cx, cy-h).LineTo(cx+h, cy+h*0.8).LineTo(cx-h, cy+h*0.8).Close() + default: + path.MoveTo(cx-h, cy-h*0.8).LineTo(cx+h, cy-h*0.8).LineTo(cx, cy+h).Close() + } + p.FillPath(&path, col) +} + +// Arc appends a polyline from a0 to a1, clockwise radians. +func Arc(path *ui.Path, cx, cy, r float32, a0, a1 float64, move bool) { + n := max(2, int(math.Ceil(math.Abs(a1-a0)/(math.Pi/48)))) + for i := 0; i <= n; i++ { + x, y := Polar(cx, cy, r, a0+(a1-a0)*float64(i)/float64(n)) + if i == 0 && move { + path.MoveTo(x, y) + } else { + path.LineTo(x, y) + } + } +} + +// Polar returns the point r from center at angle a. +func Polar(cx, cy, r float32, a float64) (float32, float32) { + return cx + r*float32(math.Sin(a)), cy - r*float32(math.Cos(a)) +} + +// Sector returns a ring slice; zero r0 makes a wedge. +func Sector(cx, cy, r0, r1 float32, a0, a1 float64) *ui.Path { + var path ui.Path + Arc(&path, cx, cy, r1, a0, a1, true) + if r0 > 0 { + Arc(&path, cx, cy, r0, a1, a0, false) + } else { + path.LineTo(cx, cy) + } + path.Close() + return &path +} + +// Rule draws a pixel-aligned 1 DIP horizontal line at y. +func Rule(p *ui.Painter, x0, x1, y float32, c ui.Color) { + yy := ruleY(p, y) + p.Line(x0, yy, x1, yy, 1, c) +} + +// AxisY draws grid lines and tick labels left of plot. +func AxisY(p *ui.Painter, plot ui.Rect, s Linear, ticks []float64, label func(float64) string, size float32, k theme.Tokens) { + for _, t := range ticks { + y := s.Map(t) + Rule(p, plot.X, plot.X+plot.W, y, k.Border) + txt := label(t) + w, h := p.MeasureText(0, ui.Span{Text: txt, Size: size}) + p.Text(plot.X-w-6, y-h/2, txt, size, k.TextMuted) + } +} + +// AxisX draws a baseline and labels centered at xs. +func AxisX(p *ui.Painter, plot ui.Rect, xs []float32, labels []string, size float32, k theme.Tokens) { + Rule(p, plot.X, plot.X+plot.W, plot.Y+plot.H, k.ControlBorder) + right := float32(math.Inf(-1)) + for i, x := range xs { + w, _ := p.MeasureText(0, ui.Span{Text: labels[i], Size: size}) + at := min(max(x-w/2, plot.X-12), plot.X+plot.W+12-w) + // Labels that would overlap the last one drawn are skipped. + if at < right+6 { + continue + } + p.Text(at, plot.Y+plot.H+6, labels[i], size, k.TextMuted) + right = at + w + } +} + +// Nearest returns the closest point within reach, or -1. +func Nearest(n int, at func(i int) (float32, float32), x, y, reach float32, byX bool) int { + best, dist := -1, reach*reach + for i := range n { + px, py := at(i) + d := (px - x) * (px - x) + if !byX { + d += (py - y) * (py - y) + } + if d <= dist { + best, dist = i, d + } + } + return best +} + +// Columns keeps first, lowest, highest and last per pixel column. +func Columns(n int, x func(i int) float32, y func(i int) float64) []int { + var out []int + for i := 0; i < n; { + col := math.Floor(float64(x(i))) + lo, hi, j := i, i, i + for ; j < n && math.Floor(float64(x(j))) == col; j++ { + if y(j) < y(lo) { + lo = j + } + if y(j) > y(hi) { + hi = j + } + } + out = append(out, i) + for _, k := range []int{min(lo, hi), max(lo, hi), j - 1} { + if k != out[len(out)-1] { + out = append(out, k) + } + } + i = j + } + return out +} diff --git a/internal/chart_test.go b/internal/chart_test.go new file mode 100644 index 0000000..f8eca08 --- /dev/null +++ b/internal/chart_test.go @@ -0,0 +1,101 @@ +package internal + +import ( + "fmt" + "math" + "testing" + "time" + + "mujicaui/theme" +) + +func TestNiceAndTicks(t *testing.T) { + for _, tc := range []struct { + lo, hi float64 + n int + nlo, nhi, stp float64 + }{ + {0, 97, 5, 0, 100, 20}, + {-3.2, 7.9, 4, -5, 10, 5}, + {0.012, 0.087, 5, 0, 0.1, 0.02}, + {5, 5, 4, 4, 6, 0.5}, + } { + lo, hi, step := Nice(tc.lo, tc.hi, tc.n) + if math.Abs(lo-tc.nlo) > 1e-9 || math.Abs(hi-tc.nhi) > 1e-9 || math.Abs(step-tc.stp) > 1e-9 { + t.Errorf("Nice(%v, %v, %d) = %v %v %v", tc.lo, tc.hi, tc.n, lo, hi, step) + } + } + if got := fmt.Sprint(Ticks(-5, 10, 5)); got != "[-5 0 5 10]" { + t.Errorf("ticks %s", got) + } + if FormatTick(0.30000000000000004, 0.1) != "0.3" || FormatTick(1500, 500) != "1500" || FormatTick(-1e-17, 0.5) != "0.0" { + t.Error("FormatTick") + } +} + +func TestNicePanics(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for an inverted domain") + } + }() + Nice(2, 1, 4) +} + +func TestTimeTicks(t *testing.T) { + lo := time.Date(2026, 10, 5, 9, 7, 0, 0, time.UTC) + ticks, layout := TimeTicks(lo, lo.Add(2*time.Hour), 4) + if layout != "15:04" || len(ticks) != 4 || ticks[0].Format("15:04") != "09:30" || ticks[3].Format("15:04") != "11:00" { + t.Fatalf("ticks %v layout %s", ticks, layout) + } +} + +func TestLinearAndBand(t *testing.T) { + s := Linear{D0: 0, D1: 10, R0: 100, R1: 0} + if s.Map(5) != 50 || s.Invert(25) != 7.5 { + t.Fatal("Linear") + } + b := Band{N: 4, R0: 0, R1: 200, Pad: 0.5} + if b.Step() != 50 || b.Width() != 25 || b.Start(1) != 62.5 || b.Center(3) != 175 { + t.Fatal("Band") + } +} + +func TestPaletteContrast(t *testing.T) { + for _, k := range []theme.Tokens{theme.Light(), theme.Dark()} { + pal := Palette(k) + seen := map[[3]uint8]bool{} + for i, c := range pal { + if r := theme.Contrast(c, k.Surface); r < 3 { + t.Errorf("dark=%v color %d contrast %.2f", k.Dark, i, r) + } + seen[[3]uint8{c.R, c.G, c.B}] = true + } + if len(pal) != 6 || len(seen) != 6 { + t.Errorf("dark=%v palette not six distinct colors", k.Dark) + } + } +} + +func TestNearest(t *testing.T) { + pts := [][2]float32{{0, 0}, {10, 10}, {20, 0}} + at := func(i int) (float32, float32) { return pts[i][0], pts[i][1] } + if Nearest(3, at, 9, 2, 30, false) != 1 || Nearest(3, at, 18, 50, 30, true) != 2 || Nearest(3, at, 100, 100, 5, false) != -1 { + t.Fatal("Nearest") + } +} + +func TestColumnsBounded(t *testing.T) { + const n = 100_000 + x := func(i int) float32 { return float32(i) * 400 / n } + y := func(i int) float64 { return math.Sin(float64(i)) } + got := Columns(n, x, y) + if len(got) > 4*400+4 || got[0] != 0 || got[len(got)-1] != n-1 { + t.Fatalf("%d points kept, first %d last %d", len(got), got[0], got[len(got)-1]) + } + for i := 1; i < len(got); i++ { + if got[i] <= got[i-1] { + t.Fatal("indices out of order") + } + } +} diff --git a/line_chart.go b/line_chart.go new file mode 100644 index 0000000..44a09c2 --- /dev/null +++ b/line_chart.go @@ -0,0 +1,159 @@ +package mujica + +import ( + "math" + "strings" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// LineChartOptions configure a LineChart. +type LineChartOptions 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 + // Format writes readout values; nil uses six digits. + Format func(v float64) string +} + +// LineChart draws series as lines; NaN breaks them. +func LineChart(c *ui.Context, series []ChartSeries, opts LineChartOptions) 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) }) + lo, hi, ok := chartYRange(ch, series, false, nil) + if !ok { + n = 0 + } + tops := make([][]float64, len(series)) + for i, s := range series { + tops[i] = s.Values + } + return chartLines(ch, chartLineData{series: series, tops: tops, ax: ax, lo: lo, hi: hi, n: n, format: opts.Format}) +} + +// chartYRange is the memoized y domain of visible series. +func chartYRange(ch *chart, series []ChartSeries, zero bool, tops [][]float64) (lo, hi float64, ok bool) { + d := chartMemo(ch, "y", chartSeriesID(ch, series)+chartID(tops), func() [3]float64 { + src := series + if tops != nil { + src = make([]ChartSeries, len(series)) + for i, s := range series { + src[i] = ChartSeries{Name: s.Name, Values: tops[i]} + } + } + lo, hi, ok := chartYDomain(src, ch.hidden, zero) + if !ok { + return [3]float64{} + } + return [3]float64{lo, hi, 1} + }) + return d[0], d[1], d[2] == 1 +} + +// chartLineData is what line and area charts draw. +type chartLineData struct { + series []ChartSeries + tops, bases [][]float64 + ax chartX + lo, hi float64 + n int + format func(float64) string +} + +func chartLines(ch *chart, d chartLineData) ChartResult { + c, k := ch.c, Tokens(ch.c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + keys := make([]chartKey, len(d.series)) + for i, s := range d.series { + keys[i] = chartKey{Name: s.Name, Color: pal[i%len(pal)], Shape: i} + } + var ticks []float64 + var step float64 + lo, hi := d.lo, d.hi + if d.n > 0 { + lo, hi, step = internal.Nice(lo, hi, 4) + ticks = internal.Ticks(lo, hi, step) + } + geom := func(r ui.Rect) (ui.Rect, internal.Linear, internal.Linear) { + plot := chartInset(r, 52, 26) + return plot, d.ax.scale(plot), internal.Linear{D0: lo, D1: hi, R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + } + spec := chartSpec{n: d.n, keys: keys, toggle: true} + spec.pick = func(r ui.Rect, x, y float32) int { + plot, xs, _ := geom(r) + if !(ui.Rect{X: plot.X - 6, Y: plot.Y, W: plot.W + 12, H: plot.H}).Contains(x, y) { + return -1 + } + return d.ax.nearest(xs.Invert(x)) + } + spec.readout = func(i int) string { + parts := []string{d.ax.label(i)} + for _, s := range d.series { + if !ch.hidden(s.Name) { + parts = append(parts, s.Name+" "+chartValue(c, s.Values[i], d.format)) + } + } + return strings.Join(parts, " · ") + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, xs, ys := geom(r) + internal.AxisY(p, plot, ys, ticks, func(v float64) string { return internal.FormatTick(v, step) }, size, k) + tx, tl := d.ax.ticks(plot) + internal.AxisX(p, plot, tx, tl, size, k) + x := func(i int) float32 { return xs.Map(d.ax.vals[i]) } + pt := func(i int, v float64) (float32, float32) { return internal.Snap(p, x(i)), internal.Snap(p, ys.Map(v)) } + for si, s := range d.series { + if ch.hidden(s.Name) { + continue + } + col, top := keys[si].Color, d.tops[si] + chartRuns(top, x, func(idx []int) { + var line ui.Path + for j, i := range idx { + if j == 0 { + line.MoveTo(pt(i, top[i])) + } else { + line.LineTo(pt(i, top[i])) + } + } + if d.bases != nil { + fill := line + for j := len(idx) - 1; j >= 0; j-- { + fill.LineTo(pt(idx[j], max(lo, min(hi, d.bases[si][idx[j]])))) + } + fill.Close() + p.FillPath(&fill, col.Alpha(0.22)) + } + p.StrokePath(&line, 2, col) + }) + // Sparse markers name each series by shape, not only color. + every := max(1, int(float32(d.n)/max(plot.W/48, 1))) + for i := 0; i < d.n; i += every { + if !math.IsNaN(top[i]) { + internal.Marker(p, si, x(i), ys.Map(top[i]), 7, col) + } + } + } + if active < 0 { + return + } + ax0 := internal.Snap(p, x(active)) + p.Line(ax0, plot.Y, ax0, plot.Y+plot.H, 1, k.TextMuted) + for si, s := range d.series { + if v := d.tops[si][active]; !ch.hidden(s.Name) && !math.IsNaN(v) { + internal.Marker(p, si, ax0, ys.Map(v), 13, k.Surface) + internal.Marker(p, si, ax0, ys.Map(v), 9, keys[si].Color) + } + } + } + res, _ := ch.build(spec) + return res +} diff --git a/line_chart_test.go b/line_chart_test.go new file mode 100644 index 0000000..a933b4d --- /dev/null +++ b/line_chart_test.go @@ -0,0 +1,194 @@ +package mujica + +import ( + "math" + "strings" + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +type chartHarness struct { + res ChartResult + changes int + disabled bool + build func(c *ui.Context) ChartResult +} + +func (h *chartHarness) view(c *ui.Context) { + Use(c, Settings{Mode: Light}) + ui.Column(c).Padding(16).Width(480).Disabled(h.disabled).Children(func() { + h.res = h.build(c) + if h.res.Changed() { + h.changes++ + } + }) +} + +// chartReadout returns the readout line, the text after the plot. +func chartReadout(tt *ui.Tester) string { + texts := tt.Texts() + return texts[len(texts)-1] +} + +func lineSeries() []ChartSeries { + return []ChartSeries{ + {Name: "Pews", Values: []float64{3, 5, math.NaN(), 4, 8}}, + {Name: "Candles", Values: []float64{5, 2, 6, 7, 1}}, + } +} + +func TestLineChartKeyboardReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return LineChart(c, lineSeries(), LineChartOptions{Frame: ChartFrame{Label: "Chapel"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + if !strings.Contains(chartReadout(tt), "arrow keys") { + t.Fatalf("hint %q", chartReadout(tt)) + } + tabTo(t, tt, "Chapel") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "1 · Pews 5 · Candles 2" || h.res.Point != 1 || h.changes != 2 { + t.Fatalf("readout %q point %d", got, h.res.Point) + } + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "2 · Pews no value · Candles 6" { + t.Fatalf("gap readout %q", got) + } + if a := tt.Announcements(); len(a) == 0 || a[len(a)-1] != "2 · Pews no value · Candles 6" { + t.Fatalf("announcements %q", a) + } + tt.Key(0, ui.KeyEnd) + tt.Key(0, ui.KeyRight) + if h.res.Point != 4 { + t.Fatalf("End then Right: %d", h.res.Point) + } + tt.Key(0, ui.KeyEscape) + if h.res.Point != -1 { + t.Fatalf("Escape kept point %d", h.res.Point) + } +} + +func TestLineChartHoverAndToggle(t *testing.T) { + var toggled string + h := &chartHarness{build: func(c *ui.Context) ChartResult { + r := LineChart(c, lineSeries(), LineChartOptions{Frame: ChartFrame{Label: "Chapel"}, X: []float64{0, 10, 20, 30, 40}}) + if s, ok := r.Toggled(); ok { + toggled = s + } + return r + }} + tt := ui.NewTester(h.view, 520, 420) + b := h.res.Element.Bounds() + // The plot spans 52..W-12; x 30 is three quarters across. + px := b.X + 52 + (b.W-64)*0.75 + tt.Move(px, b.Y+b.H/2) + if got := chartReadout(tt); got != "30 · Pews 4 · Candles 7" { + t.Fatalf("hover readout %q", got) + } + if err := tt.Click("Candles"); err != nil { + t.Fatal(err) + } + tt.Move(px, b.Y+b.H/2) + if got := chartReadout(tt); got != "30 · Pews 4" || toggled != "Candles" { + t.Fatalf("hidden series still read: %q toggled %q", got, toggled) + } +} + +func TestLineChartTimeAxisAndStates(t *testing.T) { + t0 := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC) + times := []time.Time{t0, t0.Add(time.Hour), t0.Add(2 * time.Hour), t0.Add(3 * time.Hour), t0.Add(4 * time.Hour)} + status := DataReady + var series []ChartSeries + var heights []float32 + h := &chartHarness{build: func(c *ui.Context) ChartResult { + r := LineChart(c, series, LineChartOptions{Frame: ChartFrame{Label: "Chapel", Status: status}, Times: times[:len(series[0].Values)]}) + return r + }} + series = lineSeries() + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Chapel") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); !strings.HasPrefix(got, "2026-10-05 10:00:00 · ") { + t.Fatalf("time readout %q", got) + } + heights = append(heights, h.res.Element.Bounds().H) + for _, st := range []DataStatus{DataLoading, DataFailed} { + status = st + tt.Frame() + heights = append(heights, h.res.Element.Bounds().H) + } + if !tt.HasText("Retry") || heights[0] != heights[1] || heights[1] != heights[2] { + t.Fatalf("states changed size: %v", heights) + } + status, series = DataReady, []ChartSeries{{Name: "A", Values: []float64{math.NaN()}}} + tt.Frame() + if !tt.HasText("No data") { + t.Fatalf("all-missing chart: %q", tt.Texts()) + } +} + +func TestLineChartDisabledIgnoresKeys(t *testing.T) { + h := &chartHarness{disabled: true, build: func(c *ui.Context) ChartResult { + return LineChart(c, lineSeries(), LineChartOptions{Frame: ChartFrame{Label: "Chapel"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + for range 4 { + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyRight) + } + if h.res.Point != -1 { + t.Fatalf("disabled chart moved to %d", h.res.Point) + } +} + +func TestLineChartBadOptions(t *testing.T) { + for name, build := range map[string]func(c *ui.Context){ + "lengths": func(c *ui.Context) { + LineChart(c, []ChartSeries{{Name: "a", Values: []float64{1}}, {Name: "b"}}, LineChartOptions{Frame: ChartFrame{Label: "x"}}) + }, + "order": func(c *ui.Context) { + LineChart(c, lineSeries(), LineChartOptions{Frame: ChartFrame{Label: "x"}, X: []float64{0, 2, 1, 3, 4}}) + }, + "no label": func(c *ui.Context) { LineChart(c, lineSeries(), LineChartOptions{}) }, + "duplicate": func(c *ui.Context) { + LineChart(c, []ChartSeries{{Name: "a"}, {Name: "a"}}, LineChartOptions{Frame: ChartFrame{Label: "x"}}) + }, + } { + func() { + defer func() { + if recover() == nil { + t.Errorf("%s: no panic", name) + } + }() + ui.NewTester(func(c *ui.Context) { Use(c, Settings{}); build(c) }, 300, 300) + }() + } +} + +func TestLineChartLarge(t *testing.T) { + vals := make([]float64, 100_000) + for i := range vals { + vals[i] = math.Sin(float64(i) / 500) + } + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return LineChart(c, []ChartSeries{{Name: "Wave", Values: vals}}, LineChartOptions{Frame: ChartFrame{Label: "Tide"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Tide") + tt.Key(0, ui.KeyEnd) + if h.res.Point != 99_999 || !strings.HasPrefix(chartReadout(tt), "99999 · Wave ") { + t.Fatalf("End: %d %q", h.res.Point, chartReadout(tt)) + } +} + +func TestLineChartSnapshot(t *testing.T) { + snapshot(t, "line_chart", 520, 340, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + LineChart(c, lineSeries(), LineChartOptions{Frame: ChartFrame{Label: "Chapel", Height: 240}}) + }) + }) +} diff --git a/list.go b/list.go index 32205b0..439d023 100644 --- a/list.go +++ b/list.go @@ -75,7 +75,7 @@ func (v ListView) Changed() bool { return v.changed } // Submitted reports Enter or a double click on an item. func (v ListView) Submitted() bool { return v.submitted } -// Retried reports a click on the retry action of a failed load. +// Retried reports a click on a failed load's retry. func (v ListView) Retried() bool { return v.retry } // List shows n items, building only those in view, as rows or a grid. diff --git a/messages_charts1.go b/messages_charts1.go new file mode 100644 index 0000000..e207570 --- /dev/null +++ b/messages_charts1.go @@ -0,0 +1,30 @@ +package mujica + +func init() { + addMessages(map[string][2]string{ + "chart.empty": {"No data", "暂无数据"}, + "chart.hint": {"Focus the chart and use the arrow keys to read values", "聚焦图表后用方向键读取数值"}, + "chart.missing": {"no value", "无数值"}, + "pie_chart.other": {"Other", "其他"}, + "pie_chart.total": {"Total", "总计"}, + "scatter_chart.size": {"size", "大小"}, + "scatter_chart.selected": {"selected", "已选"}, + "calendar_heatmap.prev": {"Previous year", "上一年"}, + "calendar_heatmap.next": {"Next year", "下一年"}, + "calendar_heatmap.less": {"Less", "少"}, + "calendar_heatmap.more": {"More", "多"}, + "box_plot.readout": {"%s · median %s · quartiles %s–%s · whiskers %s–%s · %d outliers", "%s · 中位数 %s · 四分位 %s–%s · 须线 %s–%s · 离群点 %d 个"}, + "waterfall_chart.running": {"running total", "累计"}, + "funnel_chart.readout": {"%s · %s · %s of the stage before · %s of the first", "%s · %s · 较上一阶段 %s · 占首阶段 %s"}, + "bullet_chart.actual": {"Actual", "实际"}, + "bullet_chart.target": {"Target", "目标"}, + "bullet_chart.band": {"Range %d: %s–%s", "区间 %d:%s–%s"}, + "chart.back": {"Back", "返回"}, + "chart.opens": {"Enter opens", "回车展开"}, + "sankey_chart.in": {"in", "流入"}, + "sankey_chart.out": {"out", "流出"}, + "network_graph.readout": {"%s · %d links: %s", "%s · %d 条连线:%s"}, + "realtime_chart.pause": {"Pause", "暂停"}, + "realtime_chart.resume": {"Resume", "继续"}, + }) +} diff --git a/network_graph.go b/network_graph.go new file mode 100644 index 0000000..c9f368e --- /dev/null +++ b/network_graph.go @@ -0,0 +1,263 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + "strings" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// GraphNode is a node placed at X, Y unless forced. +type GraphNode struct { + ID, Label string + X, Y float64 +} + +// GraphEdge joins two nodes by ID. +type GraphEdge struct{ From, To string } + +// NetworkGraphOptions configure a NetworkGraph. +type NetworkGraphOptions struct { + Frame ChartFrame + // Force lays nodes out by a simple force simulation. + Force bool +} + +// NetworkGraphState holds node positions, zoom and pan. +type NetworkGraphState struct { + pos map[string][2]float64 + lo, hi [2]float64 + layout string + zoom float32 + panX float32 + panY float32 + drag string + dragging bool +} + +// Position returns where node id is, in layout units. +func (s *NetworkGraphState) Position(id string) (x, y float64, ok bool) { + p, ok := s.pos[id] + return p[0], p[1], ok +} + +// Zoom returns the view's scale, 1 when fitted. +func (s *NetworkGraphState) Zoom() float32 { return max(s.zoom, 0) } + +// ResetView fits the graph again. +func (s *NetworkGraphState) ResetView() { s.zoom, s.panX, s.panY = 1, 0, 0 } + +// networkForceLimit bounds the nodes the O(n²) force layout takes. +const networkForceLimit = 500 + +// NetworkGraph draws nodes and edges; drag, pan and zoom. +func NetworkGraph(c *ui.Context, s *NetworkGraphState, nodes []GraphNode, edges []GraphEdge, opts NetworkGraphOptions) ChartResult { + at := map[string]int{} + for i, n := range nodes { + if _, dup := at[n.ID]; dup || n.ID == "" || n.Label == "" { + panic("mujica: NetworkGraph nodes need unique IDs and labels") + } + at[n.ID] = i + } + links := make([][2]int, len(edges)) + for i, e := range edges { + f, okf := at[e.From] + t, okt := at[e.To] + if !okf || !okt { + panic("mujica: NetworkGraph edge ends must be node IDs") + } + links[i] = [2]int{f, t} + } + if opts.Force && len(nodes) > networkForceLimit { + panic("mujica: NetworkGraph Force takes at most 500 nodes") + } + if s.zoom == 0 { + s.zoom = 1 + } + if key := chartID(nodes) + chartID(edges) + fmt.Sprint(opts.Force); s.layout != key { + s.layout, s.pos = key, networkLayout(nodes, links, opts.Force) + // The view fits the layout; dragging does not refit. + s.lo, s.hi = [2]float64{math.Inf(1), math.Inf(1)}, [2]float64{math.Inf(-1), math.Inf(-1)} + for _, p := range s.pos { + s.lo, s.hi = [2]float64{min(s.lo[0], p[0]), min(s.lo[1], p[1])}, [2]float64{max(s.hi[0], p[0]), max(s.hi[1], p[1])} + } + slog.Debug("mujica: network_graph layout", "nodes", len(nodes)) + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + lo, hi := s.lo, s.hi + // screen maps a layout point into r, zoomed and panned. + screen := func(r ui.Rect, p [2]float64) (float32, float32) { + span := max(hi[0]-lo[0], hi[1]-lo[1], 1e-9) + fit := float64(min(r.W, r.H)-48) / span + cx, cy := (lo[0]+hi[0])/2, (lo[1]+hi[1])/2 + x := float32((p[0]-cx)*fit)*s.zoom + r.X + r.W/2 + s.panX + y := float32((p[1]-cy)*fit)*s.zoom + r.Y + r.H/2 + s.panY + return x, y + } + unit := func(r ui.Rect) float64 { + return max(hi[0]-lo[0], hi[1]-lo[1], 1e-9) / float64(min(r.W, r.H)-48) / float64(s.zoom) + } + pt := func(r ui.Rect, i int) (float32, float32) { return screen(r, s.pos[nodes[i].ID]) } + spec := chartSpec{n: len(nodes)} + spec.readout = func(i int) string { + var near []string + for _, l := range links { + switch i { + case l[0]: + near = append(near, nodes[l[1]].Label) + case l[1]: + near = append(near, nodes[l[0]].Label) + } + } + return fmt.Sprintf(msg(c, "network_graph.readout"), nodes[i].Label, len(near), strings.Join(near, ", ")) + } + spec.pick = func(r ui.Rect, x, y float32) int { + return internal.Nearest(len(nodes), func(i int) (float32, float32) { return pt(r, i) }, x, y, 12, false) + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + p.Clip(r, 0, func() { + for _, l := range links { + x0, y0 := pt(r, l[0]) + x1, y1 := pt(r, l[1]) + var line ui.Path + line.MoveTo(internal.Snap(p, x0), internal.Snap(p, y0)).LineTo(internal.Snap(p, x1), internal.Snap(p, y1)) + w, col := float32(1.25), k.ControlBorder + if active == l[0] || active == l[1] { + w, col = 2.5, k.Text + } + p.StrokePath(&line, w, col) + } + for i, n := range nodes { + x, y := pt(r, i) + internal.Marker(p, 0, x, y, 14, k.Surface) + internal.Marker(p, 0, x, y, 11, pal[i%len(pal)]) + if i == active { + var ring ui.Path + ring.Circle(internal.Snap(p, x), internal.Snap(p, y), 10) + p.StrokePath(&ring, 2, k.Text) + } + chartText(p, n.Label, x, y+9, size, k.Text, 0.5, 0) + } + }) + } + res, plot := ch.build(spec) + if plot == nil || plot.IsDisabled() { + return res + } + hit := func(x, y float32) string { + b := plot.Bounds() + if i := spec.pick(ui.Rect{W: b.W, H: b.H}, x, y); i >= 0 { + return nodes[i].ID + } + return "" + } + networkInput(plot, s, ch.st.focus, nodes, unit, hit) + return res +} + +// networkInput drags, pans, zooms and moves the focused node. +func networkInput(plot *ui.Element, s *NetworkGraphState, focus int, nodes []GraphNode, unit func(ui.Rect) float64, hit func(x, y float32) string) { + b := plot.Bounds() + r := ui.Rect{W: b.W, H: b.H} + move := func(id string, dx, dy float32) { + p := s.pos[id] + s.pos[id] = [2]float64{p[0] + float64(dx)*unit(r), p[1] + float64(dy)*unit(r)} + } + zoom := func(f float32) { s.zoom = max(0.25, min(8, s.zoom*f)) } + if dx, dy, held := plot.Dragged(); held { + if !s.dragging { + x, y, _ := plot.PointerPosition() + s.dragging, s.drag = true, hit(x, y) + } + if s.drag != "" { + move(s.drag, dx, dy) + } else { + s.panX, s.panY = s.panX+dx, s.panY+dy + } + } else if s.dragging { + s.dragging = false + slog.Debug("mujica: network_graph drag", "node", s.drag) + } + plot.HandleInput(func(ev ui.InputEvent) bool { + if ev.Kind != ui.InputScroll || ev.DY == 0 || plot.IsDisabled() { + return false + } + if ev.DY < 0 { + zoom(1.2) + } else { + zoom(1 / 1.2) + } + return true + }) + switch { + case plot.Shortcut(0, ui.KeyEqual), plot.Shortcut(ui.Shift, ui.KeyEqual): + zoom(1.2) + case plot.Shortcut(0, ui.KeyMinus): + zoom(1 / 1.2) + case plot.Shortcut(0, ui.Key0): + s.ResetView() + } + if focus < 0 || focus >= len(nodes) { + return + } + for key, d := range map[ui.Key][2]float32{ui.KeyLeft: {-12, 0}, ui.KeyRight: {12, 0}, ui.KeyUp: {0, -12}, ui.KeyDown: {0, 12}} { + if plot.Shortcut(ui.Shift, key) { + move(nodes[focus].ID, d[0], d[1]) + } + } +} + +// networkLayout uses X, Y, or fixed force steps. +func networkLayout(nodes []GraphNode, links [][2]int, force bool) map[string][2]float64 { + pos := make([][2]float64, len(nodes)) + for i, n := range nodes { + pos[i] = [2]float64{n.X, n.Y} + if force { + a := 2 * math.Pi * float64(i) / float64(len(nodes)) + pos[i] = [2]float64{math.Cos(a), math.Sin(a)} + } + } + if force && len(nodes) > 1 { + ideal := math.Sqrt(4.0 / float64(len(nodes))) + for step := range 300 { + heat := 0.1 * (1 - float64(step)/300) + move := make([][2]float64, len(nodes)) + for i := range pos { + for j := range pos { + if i == j { + continue + } + dx, dy := pos[i][0]-pos[j][0], pos[i][1]-pos[j][1] + d := max(math.Hypot(dx, dy), 1e-6) + f := ideal * ideal / d + move[i][0], move[i][1] = move[i][0]+dx/d*f, move[i][1]+dy/d*f + } + } + for _, l := range links { + dx, dy := pos[l[0]][0]-pos[l[1]][0], pos[l[0]][1]-pos[l[1]][1] + d := max(math.Hypot(dx, dy), 1e-6) + f := d * d / ideal + move[l[0]][0], move[l[0]][1] = move[l[0]][0]-dx/d*f, move[l[0]][1]-dy/d*f + move[l[1]][0], move[l[1]][1] = move[l[1]][0]+dx/d*f, move[l[1]][1]+dy/d*f + } + for i, m := range move { + d := max(math.Hypot(m[0], m[1]), 1e-9) + pos[i][0] += m[0] / d * min(d, heat) + pos[i][1] += m[1] / d * min(d, heat) + } + } + } + out := make(map[string][2]float64, len(nodes)) + for i, n := range nodes { + out[n.ID] = pos[i] + } + return out +} diff --git a/network_graph_test.go b/network_graph_test.go new file mode 100644 index 0000000..7b45133 --- /dev/null +++ b/network_graph_test.go @@ -0,0 +1,101 @@ +package mujica + +import ( + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +var graphNodes = []GraphNode{{"a", "Abbot", 0, 0}, {"b", "Prior", 10, 0}, {"c", "Cellarer", 10, 10}, {"d", "Novice", 0, 10}} +var graphEdges = []GraphEdge{{"a", "b"}, {"a", "c"}, {"c", "d"}} + +func TestNetworkGraphReadoutAndKeys(t *testing.T) { + var s NetworkGraphState + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return NetworkGraph(c, &s, graphNodes, graphEdges, NetworkGraphOptions{Frame: ChartFrame{Label: "House"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "House") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Abbot · 2 links: Prior, Cellarer" { + t.Fatalf("readout %q", got) + } + x0, y0, _ := s.Position("a") + tt.Key(ui.Shift, ui.KeyRight) + if x, y, _ := s.Position("a"); x <= x0 || y != y0 { + t.Fatalf("Shift+Right left the node at %v,%v", x, y) + } + tt.Key(0, ui.KeyEqual) + if s.Zoom() < 1.19 { + t.Fatalf("zoom %v", s.Zoom()) + } + tt.Key(0, ui.Key0) + if s.Zoom() != 1 { + t.Fatalf("reset zoom %v", s.Zoom()) + } +} + +func TestNetworkGraphDragNodeAndPan(t *testing.T) { + var s NetworkGraphState + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return NetworkGraph(c, &s, graphNodes, graphEdges, NetworkGraphOptions{Frame: ChartFrame{Label: "House"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + b := h.res.Element.Bounds() + // The 10×10 layout fits 240-48 DIPs, centered in the plot. + cx, cy := b.X+b.W/2, b.Y+120 + ax, ay := cx-96, cy-96 + tt.Press(ax, ay) + tt.Move(ax+20, ay) + tt.Move(ax+48, ay) + tt.Release(ax+48, ay) + if x, y, _ := s.Position("a"); math.Abs(x-2.5) > 0.2 || math.Abs(y) > 0.01 { + t.Fatalf("dragged node to %v,%v", x, y) + } + tt.Press(cx, cy) // the empty middle pans + tt.Move(cx+30, cy+10) + tt.Release(cx+30, cy+10) + if x, _, _ := s.Position("b"); x != 10 { + t.Fatalf("panning moved a node: %v", x) + } + if got := s.panX; got != 30 { + t.Fatalf("pan %v", got) + } +} + +func TestNetworkGraphForceLayout(t *testing.T) { + pos := networkLayout(graphNodes, [][2]int{{0, 1}, {0, 2}, {2, 3}}, true) + again := networkLayout(graphNodes, [][2]int{{0, 1}, {0, 2}, {2, 3}}, true) + for id, p := range pos { + if again[id] != p || math.IsNaN(p[0]) { + t.Fatalf("layout not deterministic for %s", id) + } + } + d := func(a, b string) float64 { return math.Hypot(pos[a][0]-pos[b][0], pos[a][1]-pos[b][1]) } + if d("c", "d") >= d("b", "d") { + t.Fatalf("linked nodes not closer: %v vs %v", d("c", "d"), d("b", "d")) + } +} + +func TestNetworkGraphBad(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for an unknown edge end") + } + }() + var s NetworkGraphState + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + NetworkGraph(c, &s, graphNodes, []GraphEdge{{"a", "z"}}, NetworkGraphOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestNetworkGraphSnapshot(t *testing.T) { + snapshot(t, "network_graph", 520, 320, func(c *ui.Context) { + var s NetworkGraphState + ui.Column(c).Padding(16).Children(func() { + NetworkGraph(c, &s, graphNodes, append(graphEdges, GraphEdge{"b", "d"}, GraphEdge{"b", "c"}), NetworkGraphOptions{Frame: ChartFrame{Label: "House"}, Force: true}) + }) + }) +} diff --git a/pie_chart.go b/pie_chart.go new file mode 100644 index 0000000..7024b6b --- /dev/null +++ b/pie_chart.go @@ -0,0 +1,146 @@ +package mujica + +import ( + "fmt" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// ChartSlice is one share of a PieChart or FunnelChart. +type ChartSlice struct { + Label string + Value float64 +} + +// PieChartOptions configure a PieChart. +type PieChartOptions struct { + Frame ChartFrame + // Donut cuts out the middle and writes the total there. + Donut bool + // MinAngle merges two or more narrower slices into Other. + MinAngle float64 + Format func(v float64) string +} + +// PieChart shows shares as slices labeled with percents. +func PieChart(c *ui.Context, slices []ChartSlice, opts PieChartOptions) ChartResult { + if opts.MinAngle < 0 || opts.MinAngle >= 360 { + panic("mujica: PieChart MinAngle must be in [0, 360)") + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + parts := chartMemo(ch, "parts", [2]any{chartID(slices), opts.MinAngle}, func() []ChartSlice { + return pieMerge(slices, opts.MinAngle, msg(c, "pie_chart.other")) + }) + total := 0.0 + for _, s := range parts { + total += s.Value + } + n := len(parts) + if total == 0 { + n = 0 + } + keys := make([]chartKey, len(parts)) + for i, s := range parts { + keys[i] = chartKey{Name: s.Label, Color: pal[i%len(pal)], Shape: i} + } + // angle returns slice i's start and end, clockwise. + angle := func(i int) (float64, float64) { + a := 0.0 + for j := range i { + a += parts[j].Value + } + return 2 * math.Pi * a / total, 2 * math.Pi * (a + parts[i].Value) / total + } + geom := func(r ui.Rect) (cx, cy, r0, r1 float32) { + r1 = min(r.W, r.H)/2 - 8 + if opts.Donut { + r0 = r1 * 0.58 + } + return r.X + r.W/2, r.Y + r.H/2, r0, r1 + } + share := func(i int) string { return fmt.Sprintf("%.1f%%", 100*parts[i].Value/total) } + spec := chartSpec{n: n, keys: keys} + spec.readout = func(i int) string { + return parts[i].Label + " · " + chartValue(c, parts[i].Value, opts.Format) + " · " + share(i) + } + spec.pick = func(r ui.Rect, x, y float32) int { + cx, cy, r0, r1 := geom(r) + d := float32(math.Hypot(float64(x-cx), float64(y-cy))) + if d < r0 || d > r1 { + return -1 + } + a := math.Atan2(float64(x-cx), float64(cy-y)) + if a < 0 { + a += 2 * math.Pi + } + for i := range parts { + if a0, a1 := angle(i); a >= a0 && a < a1 { + return i + } + } + return -1 + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + cx, cy, r0, r1 := geom(r) + for i := range parts { + a0, a1 := angle(i) + if a1 <= a0 { + continue + } + grow := float32(0) + if i == active { + grow = 6 + } + p.FillPath(internal.Sector(cx, cy, r0, r1+grow, a0, a1), keys[i].Color) + p.StrokePath(internal.Sector(cx, cy, r0, r1+grow, a0, a1), 1.5, k.Surface) + // Wide slices carry their shape and percent. + if a1-a0 > 0.38 { + mx, my := internal.Polar(cx, cy, (r0+r1)/2+float32(chartBool(r0 == 0))*r1*0.12, (a0+a1)/2) + ink := chartInk(k, keys[i].Color) + internal.Marker(p, i, mx, my-8, 9, ink) + chartText(p, share(i), mx, my+2, size, ink, 0.5, 0) + } + } + if opts.Donut { + chartText(p, chartValue(c, total, opts.Format), cx, cy, FontSize(c, theme.H3Size), k.Text, 0.5, 0.75) + chartText(p, msg(c, "pie_chart.total"), cx, cy+4, size, k.TextMuted, 0.5, 0) + } + } + res, _ := ch.build(spec) + return res +} + +// pieMerge folds two or more narrow slices into other. +func pieMerge(slices []ChartSlice, minAngle float64, other string) []ChartSlice { + total := 0.0 + for _, s := range slices { + if s.Value < 0 || math.IsNaN(s.Value) || math.IsInf(s.Value, 0) || s.Label == "" { + panic("mujica: PieChart slices need a label and a finite value ≥ 0") + } + total += s.Value + } + var keep []ChartSlice + small, rest := 0, 0.0 + for _, s := range slices { + if total > 0 && s.Value/total*360 < minAngle { + small++ + rest += s.Value + } + } + for _, s := range slices { + if small < 2 || total == 0 || s.Value/total*360 >= minAngle { + keep = append(keep, s) + } + } + if small >= 2 { + keep = append(keep, ChartSlice{Label: other, Value: rest}) + } + return keep +} diff --git a/pie_chart_test.go b/pie_chart_test.go new file mode 100644 index 0000000..addb559 --- /dev/null +++ b/pie_chart_test.go @@ -0,0 +1,82 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +var pieSlices = []ChartSlice{{"Wax", 50}, {"Oil", 30}, {"Myrrh", 12}, {"Salt", 4}, {"Ash", 4}} + +func TestPieMerge(t *testing.T) { + got := pieMerge(pieSlices, 20, "Other") + if fmt.Sprint(got) != "[{Wax 50} {Oil 30} {Myrrh 12} {Other 8}]" { + t.Fatalf("merge 20°: %v", got) + } + if got := pieMerge(pieSlices[:4], 20, "Other"); len(got) != 4 { + t.Fatalf("a single narrow slice merged: %v", got) + } +} + +func TestPieChartReadoutAndHover(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return PieChart(c, pieSlices, PieChartOptions{Frame: ChartFrame{Label: "Stores"}, Donut: true, MinAngle: 20}) + }} + tt := ui.NewTester(h.view, 520, 420) + if !tt.HasText("Other") { + t.Fatalf("legend lacks Other: %q", tt.Texts()) + } + tabTo(t, tt, "Stores") + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); got != "Other · 8 · 8.0%" { + t.Fatalf("readout %q", got) + } + b := h.res.Element.Bounds() + plotTop := b.Y + 38 // below the one-line legend + cy := plotTop + 120 + tt.Move(b.X+b.W/2+60, cy-40) // upper right: the first slice + if got := chartReadout(tt); got != "Wax · 50 · 50.0%" { + t.Fatalf("hover %q", got) + } + tt.Key(0, ui.KeyEscape) + tt.Move(b.X+b.W/2, cy) // the hole + if h.res.Point != -1 { + t.Fatalf("hole picked %d", h.res.Point) + } +} + +func TestPieChartBad(t *testing.T) { + for _, s := range [][]ChartSlice{{{"a", -1}}, {{"", 1}}} { + func() { + defer func() { + if recover() == nil { + t.Errorf("%v: no panic", s) + } + }() + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + PieChart(c, s, PieChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) + }() + } + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return PieChart(c, []ChartSlice{{"a", 0}}, PieChartOptions{Frame: ChartFrame{Label: "x"}}) + }} + if tt := ui.NewTester(h.view, 300, 300); !tt.HasText("No data") { + t.Fatal("zero total is not empty") + } +} + +func TestPieChartSnapshot(t *testing.T) { + snapshot(t, "pie_chart", 640, 320, func(c *ui.Context) { + ui.Row(c).Padding(16).Gap(16).Children(func() { + ui.Column(c).Width(296).Children(func() { + PieChart(c, pieSlices, PieChartOptions{Frame: ChartFrame{Label: "Pie", Height: 220}}) + }) + ui.Column(c).Width(296).Children(func() { + PieChart(c, pieSlices, PieChartOptions{Frame: ChartFrame{Label: "Donut", Height: 220}, Donut: true, MinAngle: 20}) + }) + }) + }) +} diff --git a/radar_chart.go b/radar_chart.go new file mode 100644 index 0000000..d78b869 --- /dev/null +++ b/radar_chart.go @@ -0,0 +1,141 @@ +package mujica + +import ( + "math" + "strings" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// RadarChartOptions configure a RadarChart. +type RadarChartOptions struct { + Frame ChartFrame + // Max is the outer ring's value; 0 means automatic. + Max float64 + Format func(v float64) string +} + +// RadarChart draws series as polygons over three or more axes. +func RadarChart(c *ui.Context, axes []string, series []ChartSeries, opts RadarChartOptions) ChartResult { + if n := chartCheckSeries(series); len(axes) < 3 || n != len(axes) && len(series) > 0 || opts.Max < 0 { + panic("mujica: RadarChart needs three or more axes, one value per axis and Max ≥ 0") + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + keys := make([]chartKey, len(series)) + top := opts.Max + for i, s := range series { + keys[i] = chartKey{Name: s.Name, Color: pal[i%len(pal)], Shape: i} + for _, v := range s.Values { + if v < 0 { + panic("mujica: RadarChart values must be ≥ 0") + } + if !ch.hidden(s.Name) && opts.Max == 0 && !math.IsNaN(v) { + top = max(top, v) + } + } + } + n := len(axes) + if top == 0 { + n = 0 + } + var step float64 + if n > 0 && opts.Max == 0 { + _, top, step = internal.Nice(0, top, 4) + } else if n > 0 { + _, _, step = internal.Nice(0, top, 4) + } + geom := func(r ui.Rect) (cx, cy, rad float32) { + return r.X + r.W/2, r.Y + r.H/2 + 4, min(r.W/2-70, r.H/2-24) + } + angle := func(i int) float64 { return 2 * math.Pi * float64(i) / float64(len(axes)) } + spec := chartSpec{n: n, keys: keys, toggle: len(series) > 1} + spec.readout = func(i int) string { + parts := []string{axes[i]} + for _, s := range series { + if !ch.hidden(s.Name) { + parts = append(parts, s.Name+" "+chartValue(c, s.Values[i], opts.Format)) + } + } + return strings.Join(parts, " · ") + } + spec.pick = func(r ui.Rect, x, y float32) int { + cx, cy, rad := geom(r) + if math.Hypot(float64(x-cx), float64(y-cy)) > float64(rad)+16 { + return -1 + } + return internal.Nearest(len(axes), func(i int) (float32, float32) { return internal.Polar(cx, cy, rad, angle(i)) }, x, y, 2*rad+32, false) + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + cx, cy, rad := geom(r) + for _, t := range internal.Ticks(step, top, step) { + var ring ui.Path + for i := range axes { + x, y := internal.Polar(cx, cy, rad*float32(t/top), angle(i)) + if i == 0 { + ring.MoveTo(x, y) + } else { + ring.LineTo(x, y) + } + } + ring.Close() + p.StrokePath(&ring, 1, k.Border) + chartText(p, internal.FormatTick(t, step), cx-4, cy-rad*float32(t/top), size, k.TextMuted, 1, 0.5) + } + for i, a := range axes { + x, y := internal.Polar(cx, cy, rad, angle(i)) + w := float32(1) + if i == active { + w = 2 + } + var spoke ui.Path + spoke.MoveTo(cx, cy).LineTo(x, y) + p.StrokePath(&spoke, w, k.ControlBorder) + lx, ly := internal.Polar(cx, cy, rad+10, angle(i)) + ax := 0.5 + 0.5*float32(math.Sin(angle(i))) + col := k.TextMuted + if i == active { + col = k.Text + } + chartText(p, a, lx, ly, size, col, 1-ax, 0.5+0.5*float32(math.Cos(angle(i)))) + } + for si, s := range series { + if ch.hidden(s.Name) { + continue + } + var poly ui.Path + pt := func(i int) (float32, float32) { + v := s.Values[i] + if math.IsNaN(v) { + v = 0 + } + return internal.Polar(cx, cy, rad*float32(v/top), angle(i)) + } + for i := range axes { + if i == 0 { + poly.MoveTo(pt(i)) + } else { + poly.LineTo(pt(i)) + } + } + poly.Close() + p.FillPath(&poly, keys[si].Color.Alpha(0.16)) + p.StrokePath(&poly, 2, keys[si].Color) + for i := range axes { + x, y := pt(i) + sz := float32(7) + if i == active { + sz = 11 + } + internal.Marker(p, si, x, y, sz, keys[si].Color) + } + } + } + res, _ := ch.build(spec) + return res +} diff --git a/radar_chart_test.go b/radar_chart_test.go new file mode 100644 index 0000000..fde7651 --- /dev/null +++ b/radar_chart_test.go @@ -0,0 +1,71 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +var radarAxes = []string{"Voice", "Latin", "Chant", "Organ", "Bells"} + +func radarSeries() []ChartSeries { + return []ChartSeries{ + {Name: "Agnès", Values: []float64{8, 6, 9, 4, 7}}, + {Name: "Clare", Values: []float64{5, 9, 6, 8, 3}}, + } +} + +func TestRadarChartReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return RadarChart(c, radarAxes, radarSeries(), RadarChartOptions{Frame: ChartFrame{Label: "Skills"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Skills") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Latin · Agnès 6 · Clare 9" { + t.Fatalf("readout %q", got) + } + b := h.res.Element.Bounds() + cx, cy := b.X+b.W/2, b.Y+38+120+4 + tt.Key(0, ui.KeyEscape) + tt.Move(cx, cy-60) // straight up: the first axis + if got := chartReadout(tt); got != "Voice · Agnès 8 · Clare 5" { + t.Fatalf("hover %q", got) + } + if err := tt.Click("Clare"); err != nil { + t.Fatal(err) + } + tt.Move(cx, cy-60) + if got := chartReadout(tt); got != "Voice · Agnès 8" { + t.Fatalf("hidden series read: %q", got) + } +} + +func TestRadarChartBad(t *testing.T) { + for name, build := range map[string]func(c *ui.Context){ + "two axes": func(c *ui.Context) { + RadarChart(c, radarAxes[:2], nil, RadarChartOptions{Frame: ChartFrame{Label: "x"}}) + }, + "negative": func(c *ui.Context) { + RadarChart(c, radarAxes[:3], []ChartSeries{{Name: "a", Values: []float64{1, -1, 2}}}, RadarChartOptions{Frame: ChartFrame{Label: "x"}}) + }, + } { + func() { + defer func() { + if recover() == nil { + t.Errorf("%s: no panic", name) + } + }() + ui.NewTester(func(c *ui.Context) { Use(c, Settings{}); build(c) }, 300, 300) + }() + } +} + +func TestRadarChartSnapshot(t *testing.T) { + snapshot(t, "radar_chart", 520, 340, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + RadarChart(c, radarAxes, radarSeries(), RadarChartOptions{Frame: ChartFrame{Label: "Skills"}}) + }) + }) +} diff --git a/realtime_chart.go b/realtime_chart.go new file mode 100644 index 0000000..559f7be --- /dev/null +++ b/realtime_chart.go @@ -0,0 +1,121 @@ +package mujica + +import ( + "log/slog" + "math" + "sort" + "time" + + "github.com/egoist/mygo/ui" +) + +// RealtimeBuffer keeps the latest samples of named series. +type RealtimeBuffer struct { + names []string + limit int + times []time.Time + vals [][]float64 +} + +// NewRealtimeBuffer keeps up to capacity samples of the named series. +func NewRealtimeBuffer(capacity int, names ...string) *RealtimeBuffer { + if capacity < 2 || len(names) == 0 { + panic("mujica: RealtimeBuffer needs a capacity of 2 or more and a series name") + } + return &RealtimeBuffer{names: names, limit: capacity, vals: make([][]float64, len(names))} +} + +// Append adds one sample per series at a non-decreasing t. +func (b *RealtimeBuffer) Append(t time.Time, values ...float64) { + if len(values) != len(b.names) || len(b.times) > 0 && t.Before(b.times[len(b.times)-1]) { + panic("mujica: RealtimeBuffer.Append needs one value per series and a time not before the last") + } + b.times = append(b.times, t) + for i, v := range values { + b.vals[i] = append(b.vals[i], v) + } + // Old samples are dropped in blocks, so appends stay cheap. + if len(b.times) >= 2*b.limit { + drop := len(b.times) - b.limit + b.times = append([]time.Time(nil), b.times[drop:]...) + for i := range b.vals { + b.vals[i] = append([]float64(nil), b.vals[i][drop:]...) + } + } +} + +// Len is how many samples the buffer keeps. +func (b *RealtimeBuffer) Len() int { return min(len(b.times), b.limit) } + +// RealtimeChartOptions configure a RealtimeChart. +type RealtimeChartOptions struct { + Frame ChartFrame + // Window is the time shown up to the newest sample. + Window time.Duration + Format func(v float64) string +} + +// RealtimeChartState holds whether the view is paused, and where. +type RealtimeChartState struct { + Paused bool + end time.Time +} + +// RealtimeChart shows a fixed window ending at the newest sample. +func RealtimeChart(c *ui.Context, s *RealtimeChartState, buf *RealtimeBuffer, opts RealtimeChartOptions) ChartResult { + if opts.Window <= 0 { + panic("mujica: RealtimeChart needs a positive Window") + } + u := Density(c).Unit() + var res ChartResult + wrap := ui.Column(c).Gap(u * 2).MinWidth(0) + wrap.Children(func() { + label := msg(c, "realtime_chart.pause") + if s.Paused { + label = msg(c, "realtime_chart.resume") + } + if b := Button(c, label, ButtonOptions{Variant: Secondary, Disabled: wrap.IsDisabled()}).AlignSelf(ui.Start); b.Clicked() && !b.IsDisabled() { + s.Paused, res.value = !s.Paused, true + slog.Debug("mujica: realtime_chart pause", "paused", s.Paused) + } + times := buf.times[max(0, len(buf.times)-buf.limit):] + last := time.Time{} + if len(times) > 0 { + last = times[len(times)-1] + } + if !s.Paused || s.end.IsZero() { + s.end = last + } + from := s.end.Add(-opts.Window) + i0 := sort.Search(len(times), func(i int) bool { return !times[i].Before(from) }) + i1 := sort.Search(len(times), func(i int) bool { return times[i].After(s.end) }) + off := len(buf.times) - len(times) + ch := newChart(c, opts.Frame) + series := make([]ChartSeries, len(buf.names)) + tops := make([][]float64, len(buf.names)) + for i, name := range buf.names { + series[i] = ChartSeries{Name: name, Values: buf.vals[i][off+i0 : off+i1]} + tops[i] = series[i].Values + } + n := i1 - i0 + var ax chartX + if n > 0 { + ax = chartMemo(ch, "x", [2]any{chartID(times[i0:i1]), s.end}, func() chartX { + a := newChartX(n, nil, times[i0:i1]) + a.d0, a.d1 = float64(from.UnixNano())/1e9, float64(s.end.UnixNano())/1e9 + if a.d1 == a.d0 { + a.d0 -= 1 + } + return a + }) + } + lo, hi, ok := chartYRange(ch, series, false, nil) + if !ok || math.IsNaN(lo) { + n = 0 + } + r := chartLines(ch, chartLineData{series: series, tops: tops, ax: ax, lo: lo, hi: hi, n: n, format: opts.Format}) + res.Point, res.changed, res.retry, res.toggled = r.Point, r.changed, r.retry, r.toggled + }) + res.Element = wrap + return res +} diff --git a/realtime_chart_test.go b/realtime_chart_test.go new file mode 100644 index 0000000..ab71e08 --- /dev/null +++ b/realtime_chart_test.go @@ -0,0 +1,86 @@ +package mujica + +import ( + "math" + "strings" + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +var rtStart = time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC) + +func TestRealtimeBufferTrims(t *testing.T) { + b := NewRealtimeBuffer(100, "a") + for i := range 100_000 { + b.Append(rtStart.Add(time.Duration(i)*time.Second), float64(i)) + } + if b.Len() != 100 || len(b.times) >= 200 || b.vals[0][len(b.vals[0])-1] != 99_999 { + t.Fatalf("kept %d samples, %d stored", b.Len(), len(b.times)) + } + defer func() { + if recover() == nil { + t.Fatal("no panic for a sample back in time") + } + }() + b.Append(rtStart, 1) +} + +func TestRealtimeChartWindowAndPause(t *testing.T) { + buf := NewRealtimeBuffer(1000, "Bell", "Organ") + var st RealtimeChartState + values := 0 + h := &chartHarness{build: func(c *ui.Context) ChartResult { + r := RealtimeChart(c, &st, buf, RealtimeChartOptions{Frame: ChartFrame{Label: "Sound"}, Window: 10 * time.Second}) + if r.ValueChanged() { + values++ + } + return r + }} + tt := ui.NewTester(h.view, 520, 440) + if !tt.HasText("No data") { + t.Fatalf("empty buffer: %q", tt.Texts()) + } + for i := range 30 { + buf.Append(rtStart.Add(time.Duration(i)*time.Second), float64(i), float64(2*i)) + } + tt.Frame() + tabTo(t, tt, "Sound") + tt.Key(0, ui.KeyHome) + if got := chartReadout(tt); got != "2026-10-05 09:00:19 · Bell 19 · Organ 38" { + t.Fatalf("window start %q", got) + } + if err := tt.Click("Pause"); err != nil || !st.Paused || values != 1 { + t.Fatalf("pause: %v %v %d", err, st.Paused, values) + } + for i := 30; i < 40; i++ { + buf.Append(rtStart.Add(time.Duration(i)*time.Second), float64(i), 0) + } + tt.Frame() + tabTo(t, tt, "Sound") + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); !strings.HasPrefix(got, "2026-10-05 09:00:29 ·") { + t.Fatalf("paused view moved: %q", got) + } + _ = tt.Click("Resume") + tabTo(t, tt, "Sound") + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); !strings.HasPrefix(got, "2026-10-05 09:00:39 ·") || st.Paused { + t.Fatalf("resumed view %q", got) + } +} + +func TestRealtimeChartSnapshot(t *testing.T) { + buf := NewRealtimeBuffer(200, "Bell", "Organ") + for i := range 60 { + x := float64(i) + buf.Append(rtStart.Add(time.Duration(i)*time.Second), 5+3*math.Sin(x/5), 4+2*math.Sin(x/3+1)) + } + snapshot(t, "realtime_chart", 520, 380, func(c *ui.Context) { + var st RealtimeChartState + ui.Column(c).Padding(16).Children(func() { + RealtimeChart(c, &st, buf, RealtimeChartOptions{Frame: ChartFrame{Label: "Sound"}, Window: 30 * time.Second}) + }) + }) +} diff --git a/sankey_chart.go b/sankey_chart.go new file mode 100644 index 0000000..edfe561 --- /dev/null +++ b/sankey_chart.go @@ -0,0 +1,235 @@ +package mujica + +import ( + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// SankeyNode is a stage that flow passes through. +type SankeyNode struct{ ID, Label string } + +// SankeyLink carries Value from node From to node To. +type SankeyLink struct { + From, To string + Value float64 +} + +// SankeyChartOptions configure a SankeyChart. +type SankeyChartOptions struct { + Frame ChartFrame + Format func(v float64) string +} + +// sankeyLayout puts nodes in columns by longest path. +type sankeyLayout struct { + col []int + in, out []float64 + cols int + from, to []int +} + +func sankeyPlace(nodes []SankeyNode, links []SankeyLink) sankeyLayout { + at := map[string]int{} + for i, n := range nodes { + if n.ID == "" || n.Label == "" { + panic("mujica: SankeyChart nodes need an ID and a Label") + } + if _, dup := at[n.ID]; dup { + panic("mujica: SankeyChart has two nodes " + n.ID) + } + at[n.ID] = i + } + l := sankeyLayout{col: make([]int, len(nodes)), in: make([]float64, len(nodes)), out: make([]float64, len(nodes))} + for _, e := range links { + f, okf := at[e.From] + t, okt := at[e.To] + if !okf || !okt || f == t || !(e.Value > 0) || math.IsInf(e.Value, 0) { + panic("mujica: SankeyChart links need known ends and a positive value") + } + l.from, l.to = append(l.from, f), append(l.to, t) + l.out[f] += e.Value + l.in[t] += e.Value + } + // Relax columns; more passes than nodes means a cycle. + for pass := 0; ; pass++ { + if pass > len(nodes) { + panic("mujica: SankeyChart links form a cycle") + } + moved := false + for i := range links { + if l.col[l.to[i]] < l.col[l.from[i]]+1 { + l.col[l.to[i]], moved = l.col[l.from[i]]+1, true + } + } + if !moved { + break + } + } + for i := range nodes { + l.cols = max(l.cols, l.col[i]+1) + } + return l +} + +// SankeyChart draws flows; reading a mark highlights its paths. +func SankeyChart(c *ui.Context, nodes []SankeyNode, links []SankeyLink, opts SankeyChartOptions) ChartResult { + ch := newChart(c, opts.Frame) + l := chartMemo(ch, "layout", [2]string{chartID(nodes), chartID(links)}, func() sankeyLayout { return sankeyPlace(nodes, links) }) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + val := func(v float64) string { return chartValue(c, v, opts.Format) } + size1 := func(i int) float64 { return max(l.in[i], l.out[i]) } + // geom returns node boxes and link ends. + geom := func(r ui.Rect) (boxes []ui.Rect, y0, y1 []float32, scale float32) { + const gap, w = 10, 12 + plot := ui.Rect{X: r.X + 8, Y: r.Y + 6, W: r.W - 16, H: r.H - 12} + most, count := 0.0, 0 + for col := range l.cols { + sum, n := 0.0, 0 + for i := range nodes { + if l.col[i] == col { + sum, n = sum+size1(i), n+1 + } + } + if sum > most { + most, count = sum, n + } + } + scale = (plot.H - gap*float32(max(count-1, 0))) / float32(max(most, 1e-9)) + boxes = make([]ui.Rect, len(nodes)) + step := (plot.W - w) / float32(max(l.cols-1, 1)) + next := make([]float32, l.cols) + for i := range nodes { + h := max(float32(size1(i))*scale, 2) + boxes[i] = ui.Rect{X: plot.X + step*float32(l.col[i]), Y: plot.Y + next[l.col[i]], W: w, H: h} + next[l.col[i]] += h + gap + } + outAt, inAt := make([]float32, len(nodes)), make([]float32, len(nodes)) + for i := range links { + y0, y1 = append(y0, boxes[l.from[i]].Y+outAt[l.from[i]]), append(y1, boxes[l.to[i]].Y+inAt[l.to[i]]) + outAt[l.from[i]] += float32(links[i].Value) * scale + inAt[l.to[i]] += float32(links[i].Value) * scale + } + return + } + // ribbon returns link i's top edge at t and thickness. + ribbon := func(boxes []ui.Rect, y0, y1 []float32, scale float32, i int, t float32) (x, y, h float32) { + a, b := boxes[l.from[i]], boxes[l.to[i]] + s := t * t * (3 - 2*t) + return a.X + a.W + (b.X-a.X-a.W)*t, y0[i] + (y1[i]-y0[i])*s, float32(links[i].Value) * scale + } + n := len(nodes) + len(links) + if len(links) == 0 { + n = 0 + } + spec := chartSpec{n: n} + spec.readout = func(i int) string { + if i < len(nodes) { + return nodes[i].Label + " · " + msg(c, "sankey_chart.in") + " " + val(l.in[i]) + " · " + msg(c, "sankey_chart.out") + " " + val(l.out[i]) + } + e := links[i-len(nodes)] + return nodes[l.from[i-len(nodes)]].Label + " → " + nodes[l.to[i-len(nodes)]].Label + " · " + val(e.Value) + } + spec.pick = func(r ui.Rect, x, y float32) int { + boxes, y0, y1, scale := geom(r) + for i, b := range boxes { + if (ui.Rect{X: b.X - 4, Y: b.Y, W: b.W + 8, H: b.H}).Contains(x, y) { + return i + } + } + for i := range links { + a, b := boxes[l.from[i]], boxes[l.to[i]] + if x < a.X+a.W || x > b.X { + continue + } + _, top, h := ribbon(boxes, y0, y1, scale, i, (x-a.X-a.W)/(b.X-a.X-a.W)) + if y >= top && y <= top+max(h, 4) { + return len(nodes) + i + } + } + return -1 + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + boxes, y0, y1, scale := geom(r) + lit := sankeyLit(l, len(nodes), active) + for i := range links { + var band ui.Path + const steps = 24 + for s := 0; s <= steps; s++ { + x, y, _ := ribbon(boxes, y0, y1, scale, i, float32(s)/steps) + if s == 0 { + band.MoveTo(x, y) + } else { + band.LineTo(x, y) + } + } + for s := steps; s >= 0; s-- { + x, y, h := ribbon(boxes, y0, y1, scale, i, float32(s)/steps) + band.LineTo(x, y+h) + } + band.Close() + alpha := float32(0.4) + if lit != nil && !lit[len(nodes)+i] { + alpha = 0.12 + } + p.FillPath(&band, pal[l.from[i]%len(pal)].Alpha(alpha)) + if active == len(nodes)+i { + p.StrokePath(&band, 1.5, k.Text) + } + } + for i, b := range boxes { + col := pal[i%len(pal)] + if lit != nil && !lit[i] { + col = col.Mix(k.Surface, 0.6) + } + p.Fill(b, col, 1) + if i == active { + p.Stroke(ui.Rect{X: b.X - 2, Y: b.Y - 2, W: b.W + 4, H: b.H + 4}, k.Text, 2, 1.5) + } + if l.col[i] == l.cols-1 { + chartText(p, nodes[i].Label, b.X-6, b.Y+b.H/2, size, k.Text, 1, 0.5) + } else { + chartText(p, nodes[i].Label, b.X+b.W+6, b.Y+b.H/2, size, k.Text, 0, 0.5) + } + } + } + res, _ := ch.build(spec) + return res +} + +// sankeyLit marks everything on paths through active; nil means all. +func sankeyLit(l sankeyLayout, nodes, active int) []bool { + if active < 0 { + return nil + } + lit := make([]bool, nodes+len(l.from)) + var walk func(node int, down bool) + walk = func(node int, down bool) { + lit[node] = true + for i := range l.from { + if down && l.from[i] == node && !lit[nodes+i] { + lit[nodes+i] = true + walk(l.to[i], true) + } + if !down && l.to[i] == node && !lit[nodes+i] { + lit[nodes+i] = true + walk(l.from[i], false) + } + } + } + if active < nodes { + walk(active, true) + walk(active, false) + return lit + } + i := active - nodes + lit[active] = true + walk(l.to[i], true) + walk(l.from[i], false) + return lit +} diff --git a/sankey_chart_test.go b/sankey_chart_test.go new file mode 100644 index 0000000..056c1b5 --- /dev/null +++ b/sankey_chart_test.go @@ -0,0 +1,81 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +var sankeyNodes = []SankeyNode{{"tithe", "Tithes"}, {"alms", "Alms"}, {"fund", "Fund"}, {"roof", "Roof"}, {"bread", "Bread"}, {"bells", "Bells"}} +var sankeyLinks = []SankeyLink{ + {"tithe", "fund", 60}, {"alms", "fund", 30}, {"alms", "bread", 10}, + {"fund", "roof", 50}, {"fund", "bells", 40}, +} + +func TestSankeyPlaceStable(t *testing.T) { + l := sankeyPlace(sankeyNodes, sankeyLinks) + if fmt.Sprint(l.col) != "[0 0 1 2 1 2]" || l.cols != 3 || l.in[2] != 90 || l.out[1] != 40 { + t.Fatalf("layout %+v", l) + } + lit := sankeyLit(l, len(sankeyNodes), 0) // Tithes: its fund, roof and bells, not alms + if !lit[2] || !lit[3] || !lit[5] || lit[1] || lit[4] || !lit[6] || lit[7] { + t.Fatalf("lit from Tithes %v", lit) + } + lit = sankeyLit(l, len(sankeyNodes), 6+3) // the fund → roof link + if !lit[0] || !lit[1] || !lit[3] || lit[5] || lit[6+4] { + t.Fatalf("lit from fund → roof %v", lit) + } +} + +func TestSankeyChartReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return SankeyChart(c, sankeyNodes, sankeyLinks, SankeyChartOptions{Frame: ChartFrame{Label: "Money"}}) + }} + tt := ui.NewTester(h.view, 560, 440) + tabTo(t, tt, "Money") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Fund · in 90 · out 90" { + t.Fatalf("node %q", got) + } + tt.Key(0, ui.KeyEnd) + if got := chartReadout(tt); got != "Fund → Bells · 40" { + t.Fatalf("link %q", got) + } + tt.Key(0, ui.KeyEscape) + b := h.res.Element.Bounds() + tt.Move(b.X+8+4, b.Y+10) // the first node, at the top left + if got := chartReadout(tt); got != "Tithes · in 0 · out 60" { + t.Fatalf("hover %q", got) + } +} + +func TestSankeyChartBad(t *testing.T) { + for name, links := range map[string][]SankeyLink{ + "cycle": {{"tithe", "fund", 1}, {"fund", "tithe", 1}}, + "unknown": {{"tithe", "nowhere", 1}}, + "zero": {{"tithe", "fund", 0}}, + } { + func() { + defer func() { + if recover() == nil { + t.Errorf("%s: no panic", name) + } + }() + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + SankeyChart(c, sankeyNodes, links, SankeyChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) + }() + } +} + +func TestSankeyChartSnapshot(t *testing.T) { + snapshot(t, "sankey_chart", 560, 320, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + SankeyChart(c, sankeyNodes, sankeyLinks, SankeyChartOptions{Frame: ChartFrame{Label: "Money"}}) + }) + }) +} diff --git a/scatter_chart.go b/scatter_chart.go new file mode 100644 index 0000000..99764f8 --- /dev/null +++ b/scatter_chart.go @@ -0,0 +1,162 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + "slices" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// ScatterPoint is one dot; Size sets a bubble's area. +type ScatterPoint struct{ X, Y, Size float64 } + +// ScatterGroup is named points sharing color and shape. +type ScatterGroup struct { + Name string + Points []ScatterPoint +} + +// ScatterKey names point Point of group Group. +type ScatterKey struct{ Group, Point int } + +// ScatterChartOptions configure a ScatterChart. +type ScatterChartOptions struct { + Frame ChartFrame + // Bubbles maps Size to dot area, 4–18 DIPs across. + Bubbles bool + Format func(v float64) string +} + +type scatterDrag struct { + on bool + x0, y0, x1, y1 float32 +} + +// ScatterChart plots groups; box drag, Enter or Space selects. +func ScatterChart(c *ui.Context, selected *[]ScatterKey, groups []ScatterGroup, opts ScatterChartOptions) ChartResult { + ch := newChart(c, opts.Frame) + k := Tokens(c) + pal := internal.Palette(k) + size := FontSize(c, theme.CaptionSize) + keys := make([]chartKey, len(groups)) + var marks []ScatterKey + b := [6]float64{math.Inf(1), math.Inf(-1), math.Inf(1), math.Inf(-1), math.Inf(1), math.Inf(-1)} + for gi, g := range groups { + keys[gi] = chartKey{Name: g.Name, Color: pal[gi%len(pal)], Shape: gi} + if g.Name == "" || ch.hidden(g.Name) { + continue + } + for pi, pt := range g.Points { + if math.IsNaN(pt.X) || math.IsNaN(pt.Y) || pt.Size < 0 { + panic("mujica: ScatterChart points need finite X, Y and Size ≥ 0") + } + marks = append(marks, ScatterKey{gi, pi}) + b = [6]float64{min(b[0], pt.X), max(b[1], pt.X), min(b[2], pt.Y), max(b[3], pt.Y), min(b[4], pt.Size), max(b[5], pt.Size)} + } + } + var xs, ys [3]float64 + if len(marks) > 0 { + // A margin keeps dots off the plot edges. + px, py := (b[1]-b[0])*0.06, (b[3]-b[2])*0.06 + xs[0], xs[1], xs[2] = internal.Nice(b[0]-px, b[1]+px, 4) + ys[0], ys[1], ys[2] = internal.Nice(b[2]-py, b[3]+py, 4) + } + pt := func(m ScatterKey) ScatterPoint { return groups[m.Group].Points[m.Point] } + geom := func(r ui.Rect) (ui.Rect, internal.Linear, internal.Linear) { + plot := chartInset(r, 52, 26) + return plot, internal.Linear{D0: xs[0], D1: xs[1], R0: float64(plot.X), R1: float64(plot.X + plot.W)}, + internal.Linear{D0: ys[0], D1: ys[1], R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + } + radius := func(m ScatterKey) float32 { + if !opts.Bubbles || b[5] <= 0 { + return 4 + } + return 2 + 7*float32(math.Sqrt(pt(m).Size/b[5])) + } + toggle := func(m ScatterKey) { + if i := slices.Index(*selected, m); i >= 0 { + *selected = slices.Delete(slices.Clone(*selected), i, i+1) + } else { + *selected = append(slices.Clone(*selected), m) + } + ch.res.value = true + slog.Debug("mujica: scatter_chart select", "count", len(*selected)) + } + spec := chartSpec{n: len(marks), keys: keys, toggle: len(groups) > 1} + spec.readout = func(i int) string { + m, p := marks[i], pt(marks[i]) + s := fmt.Sprintf("%s · x %s · y %s", groups[m.Group].Name, chartValue(c, p.X, opts.Format), chartValue(c, p.Y, opts.Format)) + if opts.Bubbles { + s += " · " + msg(c, "scatter_chart.size") + " " + chartValue(c, p.Size, opts.Format) + } + if slices.Contains(*selected, m) { + s += " · " + msg(c, "scatter_chart.selected") + } + return s + } + spec.pick = func(r ui.Rect, x, y float32) int { + _, sx, sy := geom(r) + return internal.Nearest(len(marks), func(i int) (float32, float32) { return sx.Map(pt(marks[i]).X), sy.Map(pt(marks[i]).Y) }, x, y, 14, false) + } + spec.activate = func(i int) { toggle(marks[i]) } + drag := ui.Local(ch.res.Element, "mujica.scatter.drag", func() scatterDrag { return scatterDrag{} }) + box := *drag + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, sx, sy := geom(r) + internal.AxisY(p, plot, sy, internal.Ticks(ys[0], ys[1], ys[2]), func(v float64) string { return internal.FormatTick(v, ys[2]) }, size, k) + var tx []float32 + var tl []string + for _, t := range internal.Ticks(xs[0], xs[1], xs[2]) { + tx, tl = append(tx, sx.Map(t)), append(tl, internal.FormatTick(t, xs[2])) + } + internal.AxisX(p, plot, tx, tl, size, k) + for i, m := range marks { + x, y, rad := sx.Map(pt(m).X), sy.Map(pt(m).Y), radius(m) + internal.Marker(p, m.Group, x, y, 2*rad, keys[m.Group].Color.Alpha(0.85)) + if slices.Contains(*selected, m) || i == active { + var ring ui.Path + ring.Circle(internal.Snap(p, x), internal.Snap(p, y), rad+3+2*float32(chartBool(i == active))) + p.StrokePath(&ring, 1.5, k.Text) + } + } + if box.on { + p.StrokeDashed(scatterRect(box, r.X, r.Y), k.Text, 0, 1) + } + } + res, plot := ch.build(spec) + if plot != nil && !plot.IsDisabled() { + x, y, _ := plot.PointerPosition() + if _, _, held := plot.Dragged(); held { + if !drag.on { + *drag = scatterDrag{on: true, x0: x, y0: y} + } + drag.x1, drag.y1 = x, y + } else if drag.on { + if pb := plot.Bounds(); max(abs32(drag.x1-drag.x0), abs32(drag.y1-drag.y0)) > 4 { + _, sx, sy := geom(ui.Rect{W: pb.W, H: pb.H}) + in := scatterRect(*drag, 0, 0) + var picked []ScatterKey + for _, m := range marks { + if in.Contains(sx.Map(pt(m).X), sy.Map(pt(m).Y)) { + picked = append(picked, m) + } + } + *selected, res.value = picked, true + slog.Debug("mujica: scatter_chart box", "count", len(picked)) + } + *drag = scatterDrag{} + } + } + return res +} + +func scatterRect(d scatterDrag, ox, oy float32) ui.Rect { + return ui.Rect{X: ox + min(d.x0, d.x1), Y: oy + min(d.y0, d.y1), W: abs32(d.x1 - d.x0), H: abs32(d.y1 - d.y0)} +} + +func abs32(v float32) float32 { return max(v, -v) } diff --git a/scatter_chart_test.go b/scatter_chart_test.go new file mode 100644 index 0000000..713b57c --- /dev/null +++ b/scatter_chart_test.go @@ -0,0 +1,82 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +var scatterGroups = []ScatterGroup{ + {Name: "Monks", Points: []ScatterPoint{{1, 2, 4}, {3, 5, 9}, {6, 4, 1}}}, + {Name: "Nuns", Points: []ScatterPoint{{2, 7, 16}, {8, 9, 2}}}, +} + +func TestScatterChartKeyboardSelect(t *testing.T) { + var sel []ScatterKey + values := 0 + h := &chartHarness{build: func(c *ui.Context) ChartResult { + r := ScatterChart(c, &sel, scatterGroups, ScatterChartOptions{Frame: ChartFrame{Label: "Choir"}, Bubbles: true}) + if r.ValueChanged() { + values++ + } + return r + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Choir") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeySpace) + if fmt.Sprint(sel) != "[{0 1}]" || values != 1 { + t.Fatalf("Space selected %v (%d events)", sel, values) + } + if got := chartReadout(tt); got != "Monks · x 3 · y 5 · size 9 · selected" { + t.Fatalf("readout %q", got) + } + tt.Key(0, ui.KeyEnter) + if len(sel) != 0 { + t.Fatalf("Enter did not unselect: %v", sel) + } +} + +func TestScatterChartBoxSelect(t *testing.T) { + var sel []ScatterKey + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return ScatterChart(c, &sel, scatterGroups, ScatterChartOptions{Frame: ChartFrame{Label: "Choir"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + b := h.res.Element.Bounds() + top := b.Y + 38 + // Nice domains: x 0..10 over 52..W-12; y 0..10 over top+8..top+214. + x := func(v float32) float32 { return b.X + 52 + (b.W-64)*v/10 } + y := func(v float32) float32 { return top + 8 + 206*(1-v/10) } + tt.Press(x(0.5), y(6)) + tt.Move(x(4), y(4)) + tt.Move(x(6.5), y(1.5)) + tt.Release(x(6.5), y(1.5)) + if fmt.Sprint(sel) != "[{0 0} {0 1} {0 2}]" { + t.Fatalf("box chose %v", sel) + } +} + +func TestScatterChartBad(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for negative size") + } + }() + var sel []ScatterKey + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + ScatterChart(c, &sel, []ScatterGroup{{Name: "a", Points: []ScatterPoint{{1, 1, -1}}}}, ScatterChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestScatterChartSnapshot(t *testing.T) { + snapshot(t, "scatter_chart", 520, 340, func(c *ui.Context) { + sel := []ScatterKey{{1, 0}} + ui.Column(c).Padding(16).Children(func() { + ScatterChart(c, &sel, scatterGroups, ScatterChartOptions{Frame: ChartFrame{Label: "Choir"}, Bubbles: true}) + }) + }) +} diff --git a/sparkline.go b/sparkline.go new file mode 100644 index 0000000..7048ebe --- /dev/null +++ b/sparkline.go @@ -0,0 +1,170 @@ +package mujica + +import ( + "log/slog" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/internal" + "mujicaui/theme" +) + +// SparklineKind is how a Sparkline draws its values. +type SparklineKind int + +const ( + SparklineLine SparklineKind = iota + SparklineBar + SparklineArea +) + +// SparklineOptions configure a Sparkline; Frame.Height 0 means 28 DIPs. +type SparklineOptions struct { + Frame ChartFrame + Kind SparklineKind + // Width is the plot width; 0 means 96 DIPs. + Width float32 + Format func(v float64) string +} + +// Sparkline is an inline chart without axes. +func Sparkline(c *ui.Context, values []float64, opts SparklineOptions) ChartResult { + f := opts.Frame + if f.Label == "" || f.Height < 0 || opts.Width < 0 || opts.Kind > SparklineArea { + panic("mujica: Sparkline needs a Label, sizes ≥ 0 and a known Kind") + } + if f.Height == 0 { + f.Height = 28 + } + w := opts.Width + if w == 0 { + w = 96 + } + k := Tokens(c) + u := Density(c).Unit() + col := internal.Palette(k)[0] + size := FontSize(c, theme.CaptionSize) + lo, hi := math.Inf(1), math.Inf(-1) + last := -1 + for i, v := range values { + if !math.IsNaN(v) { + lo, hi, last = min(lo, v), max(hi, v), i + } + } + res := ChartResult{Point: -1} + res.Element = ui.Row(c).Gap(u * 2).AlignItems(ui.Center) + st := ui.Local(res.Element, "mujica.sparkline", func() chartState { return chartState{focus: -1, last: -1} }) + res.Element.Children(func() { + if f.Status == DataLoading || f.Status == DataFailed || last < 0 { + box := ui.Row(c).Size(w, f.Height).AlignItems(ui.Center).Gap(u) + box.Children(func() { + switch f.Status { + case DataLoading: + Spinner(c, SpinnerOptions{Size: 14, Label: msg(c, "list.loading")}) + case DataFailed: + ui.Text(c, dataError(c, f.Error)).FontSize(size).TextColor(k.Danger).SingleLine().Grow(1).MinWidth(0) + res.retry = iconAction(c, icons.Must("refresh-cw"), msg(c, "list.retry")).Clicked() + default: + empty := f.Empty + if empty == "" { + empty = msg(c, "chart.empty") + } + ui.Text(c, empty).FontSize(size).TextColor(k.TextMuted).SingleLine() + } + }) + st.focus = -1 + return + } + if lo == hi { + lo, hi = lo-1, hi+1 + } + if opts.Kind == SparklineBar { + lo, hi = min(lo, 0), max(hi, 0) + } + plot := ui.Box(c).Size(w, f.Height).Shrink(0).Focusable().Label(f.Label).Role(ui.RoleGroup) + internal.Ring(plot, k.Focus, theme.ControlRadius) + n := len(values) + x := func(r ui.Rect, i int) float32 { return r.X + 3 + (r.W-6)*float32(i)/float32(max(n-1, 1)) } + ys := func(r ui.Rect) internal.Linear { + return internal.Linear{D0: lo, D1: hi, R0: float64(r.Y + r.H - 3), R1: float64(r.Y + 3)} + } + if !plot.IsDisabled() { + to := st.focus + switch { + case plot.Shortcut(0, ui.KeyLeft): + to = max(st.focus-1, 0) + case plot.Shortcut(0, ui.KeyRight): + to = min(st.focus+1, n-1) + case plot.Shortcut(0, ui.KeyHome): + to = 0 + case plot.Shortcut(0, ui.KeyEnd): + to = n - 1 + case plot.Shortcut(0, ui.KeyEscape): + to = -1 + } + if to != st.focus { + st.focus = to + if to >= 0 { + c.Announce(chartValue(c, values[to], opts.Format)) + } + slog.Debug("mujica: sparkline focus", "label", f.Label, "mark", to) + } + } + active := -1 + if px, _, over := plot.PointerPosition(); over && !plot.IsDisabled() { + active = max(0, min(n-1, int(math.Round(float64((px-3)/(w-6)*float32(max(n-1, 1))))))) + } else if plot.Focused() { + active = st.focus + } + res.Point = active + plot.Draw(func(p *ui.Painter, r ui.Rect) { + s := ys(r) + if opts.Kind == SparklineBar { + bw := max((r.W-6)/float32(n)-1, 1) + for i, v := range values { + if math.IsNaN(v) { + continue + } + a, b := s.Map(0), s.Map(v) + cx := x(r, i) + p.Fill(ui.Rect{X: cx - bw/2, Y: min(a, b), W: bw, H: max(abs32(a-b), 1)}, col, 0) + } + } else { + chartRuns(values, func(i int) float32 { return x(r, i) }, func(idx []int) { + var line ui.Path + for j, i := range idx { + px, py := internal.Snap(p, x(r, i)), internal.Snap(p, s.Map(values[i])) + if j == 0 { + line.MoveTo(px, py) + } else { + line.LineTo(px, py) + } + } + if opts.Kind == SparklineArea { + fill := line + fill.LineTo(internal.Snap(p, x(r, idx[len(idx)-1])), r.Y+r.H-3).LineTo(internal.Snap(p, x(r, idx[0])), r.Y+r.H-3).Close() + p.FillPath(&fill, col.Alpha(0.22)) + } + p.StrokePath(&line, 1.5, col) + }) + } + // Diamond: last value. Ring: the value being read. + p.FillPath(internal.Diamond(internal.Snap(p, x(r, last)), internal.Snap(p, s.Map(values[last])), 7), k.Text) + if active >= 0 && !math.IsNaN(values[active]) { + var ring ui.Path + ring.Circle(internal.Snap(p, x(r, active)), internal.Snap(p, s.Map(values[active])), 4) + p.StrokePath(&ring, 1.5, k.Text) + } + }) + shown := last + if active >= 0 { + shown = active + } + ui.Text(c, chartValue(c, values[shown], opts.Format)).FontSize(size).TextColor(k.Text).SingleLine().Role(ui.RoleStatus) + }) + res.changed = res.Point != st.last + st.last = res.Point + return res +} diff --git a/sparkline_test.go b/sparkline_test.go new file mode 100644 index 0000000..b8bdbbd --- /dev/null +++ b/sparkline_test.go @@ -0,0 +1,78 @@ +package mujica + +import ( + "math" + "testing" + + "github.com/egoist/mygo/ui" +) + +var sparkValues = []float64{3, 5, 4, math.NaN(), 7, 6, 9} + +func TestSparklineEndValueAndKeys(t *testing.T) { + kind := SparklineLine + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return Sparkline(c, sparkValues, SparklineOptions{Frame: ChartFrame{Label: "Bells"}, Kind: kind}) + }} + tt := ui.NewTester(h.view, 300, 200) + if got := chartReadout(tt); got != "9" { + t.Fatalf("end value %q", got) + } + r, _ := tt.Find("Bells") + if r.H < 28 || r.W != 96 { + t.Fatalf("sparkline box %v", r) + } + tabTo(t, tt, "Bells") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "5" || h.res.Point != 1 { + t.Fatalf("read %q at %d", got, h.res.Point) + } + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "no value" { + t.Fatalf("missing %q", got) + } + for _, kind = range []SparklineKind{SparklineBar, SparklineArea} { + tt.Frame() + tt.Move(r.X+r.W-2, r.Y+r.H/2) + if got := chartReadout(tt); got != "9" || h.res.Point != 6 { + t.Fatalf("kind %d hover %q", kind, got) + } + } +} + +func TestSparklineStates(t *testing.T) { + status := DataLoading + var vals []float64 + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return Sparkline(c, vals, SparklineOptions{Frame: ChartFrame{Label: "Bells", Status: status}}) + }} + tt := ui.NewTester(h.view, 300, 200) + status = DataFailed + tt.Frame() + if err := tt.Click("Retry"); err != nil { + t.Fatal(err) + } + status = DataReady + tt.Frame() + if !tt.HasText("No data") { + t.Fatalf("empty %q", tt.Texts()) + } + defer func() { + if recover() == nil { + t.Fatal("no panic without a label") + } + }() + ui.NewTester(func(c *ui.Context) { Use(c, Settings{}); Sparkline(c, vals, SparklineOptions{}) }, 100, 100) +} + +func TestSparklineSnapshot(t *testing.T) { + snapshot(t, "sparkline", 420, 80, func(c *ui.Context) { + ui.Row(c).Padding(16).Gap(24).Children(func() { + for _, k := range []SparklineKind{SparklineLine, SparklineBar, SparklineArea} { + Sparkline(c, sparkValues, SparklineOptions{Frame: ChartFrame{Label: "Bells"}, Kind: k}) + } + }) + }) +} diff --git a/sunburst.go b/sunburst.go new file mode 100644 index 0000000..6ee6712 --- /dev/null +++ b/sunburst.go @@ -0,0 +1,155 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + "slices" + "strings" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// SunburstOptions configure a Sunburst. +type SunburstOptions struct { + Frame ChartFrame + // Depth is the number of rings; 0 means 3. + Depth int + Format func(v float64) string +} + +// sunArc is one drawn segment of a ring. +type sunArc struct { + path []string + node ChartNode + ring int + a0, a1 float64 + color int +} + +// Sunburst draws descendants of *path as rings; branches drill in. +func Sunburst(c *ui.Context, path *[]string, root ChartNode, opts SunburstOptions) ChartResult { + if opts.Depth < 0 { + panic("mujica: Sunburst Depth must be ≥ 0") + } + depth := opts.Depth + if depth == 0 { + depth = 3 + } + chartCheckTree(root) + chartDescend(root, *path) + k := Tokens(c) + u := Density(c).Unit() + size := FontSize(c, theme.CaptionSize) + pal := internal.Palette(k) + var res ChartResult + wrap := ui.Column(c).Gap(u * 2).MinWidth(0) + wrap.Children(func() { + res.value = chartPath(c, root.Name, path, wrap.IsDisabled()) + node := chartDescend(root, *path) + sum := node.total() + var arcs []sunArc + var walk func(n ChartNode, at []string, ring int, a0, a1 float64, color int) + walk = func(n ChartNode, at []string, ring int, a0, a1 float64, color int) { + total, width := n.total(), a1-a0 + for i, ch := range n.Children { + v := ch.total() + if v <= 0 { + continue + } + span := width * v / total + col := color + if ring == 0 { + col = i + } + arc := sunArc{path: append(slices.Clone(at), ch.Name), node: ch, ring: ring, a0: a0, a1: a0 + span, color: col} + arcs = append(arcs, arc) + if ring+1 < depth { + walk(ch, arc.path, ring+1, arc.a0, arc.a1, col) + } + a0 += span + } + } + if sum > 0 { + walk(node, nil, 0, 0, 2*math.Pi, 0) + } + geom := func(r ui.Rect) (cx, cy, hole, ring float32) { + rad := min(r.W, r.H)/2 - 6 + hole = rad * 0.3 + return r.X + r.W/2, r.Y + r.H/2, hole, (rad - hole) / float32(depth) + } + ch := newChart(c, opts.Frame) + spec := chartSpec{n: len(arcs)} + spec.readout = func(i int) string { + a := arcs[i] + s := fmt.Sprintf("%s · %s · %.1f%%", strings.Join(a.path, " › "), chartValue(c, a.node.total(), opts.Format), 100*a.node.total()/sum) + if len(a.node.Children) > 0 { + s += " · " + msg(c, "chart.opens") + } + return s + } + spec.pick = func(r ui.Rect, x, y float32) int { + cx, cy, hole, ring := geom(r) + d := float32(math.Hypot(float64(x-cx), float64(y-cy))) + a := math.Atan2(float64(x-cx), float64(cy-y)) + if a < 0 { + a += 2 * math.Pi + } + for i, arc := range arcs { + r0 := hole + ring*float32(arc.ring) + if d >= r0 && d < r0+ring && a >= arc.a0 && a < arc.a1 { + return i + } + } + return -1 + } + spec.activate = func(i int) { + if len(arcs[i].node.Children) > 0 { + *path = append(slices.Clone(*path), arcs[i].path...) + res.value = true + slog.Debug("mujica: sunburst drill", "path", strings.Join(*path, "/")) + } + } + // color fades outer rings, keeping 3:1 against Surface. + color := func(a sunArc) ui.Color { + col := pal[a.color%len(pal)] + if faded := col.Mix(k.Surface, 0.18*float32(a.ring)); theme.Contrast(faded, k.Surface) >= 3 { + return faded + } + return col + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + cx, cy, hole, ring := geom(r) + for i, a := range arcs { + r0 := hole + ring*float32(a.ring) + col := color(a) + p.FillPath(internal.Sector(cx, cy, r0, r0+ring, a.a0, a.a1), col) + p.StrokePath(internal.Sector(cx, cy, r0, r0+ring, a.a0, a.a1), 1.5, k.Surface) + if i == active { + p.StrokePath(internal.Sector(cx, cy, r0+2, r0+ring-2, a.a0, a.a1), 2, chartInk(k, col)) + } + } + // Labels go on top where arcs are long enough. + for _, a := range arcs { + r0 := hole + ring*float32(a.ring) + col := color(a) + if mid := float64(r0+ring/2) * (a.a1 - a.a0); mid > 44 { + x, y := internal.Polar(cx, cy, r0+ring/2, (a.a0+a.a1)/2) + chartText(p, chartFit(p, a.node.Name, min(float32(mid)*0.8, ring*1.25), size), x, y, size, chartInk(k, col), 0.5, 0.5) + } + } + chartText(p, chartFit(p, node.Name, hole*2-8, size), cx, cy, size, k.TextMuted, 0.5, 1) + chartText(p, chartValue(c, sum, opts.Format), cx, cy+2, FontSize(c, theme.BodySize), k.Text, 0.5, 0) + } + r, plot := ch.build(spec) + if plot != nil && !plot.IsDisabled() && plot.Shortcut(0, ui.KeyBackspace) && len(*path) > 0 { + *path, res.value = (*path)[:len(*path)-1], true + } + res.Point, res.changed, res.retry = r.Point, r.changed, r.retry + }) + res.Element = wrap + return res +} diff --git a/sunburst_test.go b/sunburst_test.go new file mode 100644 index 0000000..e65d9c4 --- /dev/null +++ b/sunburst_test.go @@ -0,0 +1,64 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestSunburstReadoutAndDrill(t *testing.T) { + var path []string + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return Sunburst(c, &path, chartTree(), SunburstOptions{Frame: ChartFrame{Label: "Rooms"}}) + }} + tt := ui.NewTester(h.view, 560, 440) + tabTo(t, tt, "Rooms") + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Library › Psalters · 30 · 34.1%" { + t.Fatalf("readout %q", got) + } + tt.Key(0, ui.KeyLeft) + tt.Key(0, ui.KeySpace) + if fmt.Sprint(path) != "[Library]" || !tt.HasText("Abbey") { + t.Fatalf("drill %v", path) + } + if err := tt.Click("Abbey"); err != nil || len(path) != 0 { + t.Fatalf("breadcrumb back: %v %v", err, path) + } + b := h.res.Element.Bounds() + plotTop := b.Y + b.H - 20 - 8 - 240 + cx, cy := b.X+b.W/2, plotTop+120 + tt.Key(0, ui.KeyEscape) + tt.Move(cx+50, cy-30) // inner ring, upper right: Library + if got := chartReadout(tt); got != "Library · 40 · 45.5% · Enter opens" { + t.Fatalf("hover %q", got) + } + tt.Move(cx-48*0.866, cy-48*0.5) // inner ring at 300°: Garden spans 266°–348° + if got := chartReadout(tt); got != "Garden · 20 · 22.7% · Enter opens" { + t.Fatalf("hover at 300° %q", got) + } +} + +func TestSunburstBad(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for duplicate children") + } + }() + var path []string + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + Sunburst(c, &path, ChartNode{Name: "r", Children: []ChartNode{{Name: "a", Value: 1}, {Name: "a", Value: 2}}}, SunburstOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestSunburstSnapshot(t *testing.T) { + snapshot(t, "sunburst", 560, 360, func(c *ui.Context) { + var path []string + ui.Column(c).Padding(16).Children(func() { + Sunburst(c, &path, chartTree(), SunburstOptions{Frame: ChartFrame{Label: "Rooms", Height: 260}}) + }) + }) +} diff --git a/testdata/snapshots/darwin/area_chart-dark.png b/testdata/snapshots/darwin/area_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..26128f55099cbef8291767e32fe8dbc80655fca1 GIT binary patch literal 18845 zcmdq|Wl&^G7X^qy<8(pe?(T)VySuwI?(XgmjeFzPxHayLyL$tTyE{zX@7_CcBj)GK zych39W>lOicIDZ*a_zNq*GVE3OHayxhK(sFy&ZM>`*&@5NC5NC{2=LJ5(b+nMu>)Wb2H9V-Rri*wHIFxg2{($ z78Zj?6aDNdBh6p&0#ZnjLP#NDLOcQBj9}0`U|3)fhG2mI|9-QbYG^n!i9a~w^o)Yp zVxF5T3(K`Kld3;bW63X1NlD|(XO_o*W9@u{&COUh!{MboHJq-mmzF9HentWt#CvIE zWode%u4a$c?k8Z+cJ z&8xIs&PRZ{EG|+?>l|tC#?JAhPIY3u*{)pgq(1d zdiie@%WNRtH?Pfh^SRX0`O18|YfukCLPt-jbq~HzJz&S9dL!PGAte>rQ^0KC57PMA zxh;6)KH?Y#{aknp4RgAgqNSpSMugx_7kY(G(< z=mq?Hx{OzhR8#17uE*MO1Uz*;TN+|wVxDH-^Yb_7U9_1*c8p1iQI5=&9M8@U7X7=_ zMMU`6&JJ!4fQyT8?{!x?!o#QvSVzYewA}H|>w3)0&NtVd;L&epTq|QM5l=V^Ox8MQ(bq%%yoY;0`bP)!zA zP7lmqKce;mdE793o*#g@c~>?Lzm4}4I6lzrJWUsV*>|}=M%#`*!wN^##1Cbv<)fpk zjZo`wo>!mrY0zl2wQ-sspcUJ!w%HsB^Q;|^keJjvM~ehO*x3F!I{STz9X`eB^K1Ji z&*{-;jh>X{;ifDe|J2sn>IC!g<$V8QW?_MVo|Yb-00rLFwNb3Uzajfft~7mq5stwC z+rrkivJ6ire5I~|k?qV}IHJA1GAYT|a}U_Y&23!wv-3^Y@X`wZjE7I6H7O=02JL3F zHP^Z8`MJH7pdpk5x!YyRK+pW>_}C^w?(pQI+oO($oNIG*R9Qm8FOQUzbYTHTcVmB! zlE`%L#dsHGk5U-$>!ngeiw-ee4m2MjwHmxd1DY| z{0FLX$Mo6``QpK*I|3 zmRWlG94S@KQxAW*>YdQxvsnOD!)wmB5qQGOP5pBup80eq1pxuhw}TV=V=`%m!-FDP3N}%a z4Eov2=mL7Csi^y-KDcwjg;s`}(eL)o^$R|oPA79wMW8=12e?I8E zFKcBfa0v+VS*XbKlS7nIq@_@GrAb0wdw|@tt4@`K4oT8`(2``zi58qZr4}=NPdv`> z=)2d8>pm1bEu0oBJMNo^Wt;wjt;+B592s0E{Q6HO+6A3+y5*u3c&aXB*OY2>Nzz4~ zoo`vnbHTx>kPLb*d!vH4VKp`S_(e57S;(pwEv)R*l{)hJ;P#$}vwb98*XlajlVK7+ zJ`5+eI$F<#^QoAQ3@GJuxtCmf=S<}Lepx^VJ09QGz-{@|cu-k#y11N4Tv%FJv9jg( zeH2m&OIoc??VBYDyc>qLakm%l>Us=3Gj)e2%jxVIlit*~NRoZq(KBs#*OLV|oE zRATabm0In-=rgNi!iwqbCFW+tp-A#P!@q=%?KQNpwAAnFp3-w|Y^p{?qzP4FcV*8) zVkScy1;SDvT*!V{4($`NG&VIoKR*xoc*RYq<6`}khWRBfBcnowLxA1u2EGPmgITNh zbLFgWV}(gpH$)iuOg}A4N$4H3QPnH2QV_P)$27oA!Z|i%iz8B$SsZGw^Z**#&ZWc$ zf~D4^Ck~tk`V@;`7{8x%GkKy%(B8q}Fg`{U39|LXh!5=H(W11pG~NvvQs_N~@qBU) zlmPPc`REY-FFU2n;r>g)`|~aGV*$k9Ag%oT40VP0nMdKJPFz(~O!Px&dVbb$*`6kR zH7E?nIRPi=N0=XWGBVUVI=%%*6Po&tUZiChyNkO>*s8Y^ymZG4uYQovYe$Zq=cUia zr8*!=h=~e%@H-Y-u(9I*$KT-OV=W$v@vX?7WaOUXuQltpE($2UyBKb5HVno8>c6!5 zbC&}XziVI!27%QB7A78UG*(hAgXu-PpzURunuC=`CE#;ybHy2QQO)d@Qdb$HXZm`e zfvrQna79C%H-;`A^~M3S6D@{SQc^l3vp0J%5|3J(v9jV(@XvgS!3Pzw=rP2jPnMbn zF^T6gSJoFiU%a+HCMN8MHovUnW@qKahyRNaPA8VSJp0`0?Cka7(M{k>@Kc=bMY+k9 z=sysOe2OyKo0=ZmmTuzayK!}VN|DatS(%%kSFK#wdAeBX_I3AR{go~%yDi7WPXP$y zYj^9yeW?YA6l=?sDt{EuRo;MWk^kGO2Gx``x^_h$5@U0obiH4;MPNX4AWV_wZIrJ6 zr%C^!u{1I=I(nEw>YI+!mpiZ4=sc6F;W?6{w4IICfBfQN z9H`qJ74GZl1YXVve4+lSS_1j7qU_%_rY(+WcOEeN+nsWx_fn*%L^vplP~nYgGyn!c!`)fiuoN?{hszch7cph zlaTqhQljhq&XHLUTyd(|WDN~L5jLX`*DLU~7eyN?Un?qJDbMMaF4+CIoN@yK#8n*R zrPL-rzkMlpE{wcj`y^R<{L-zIF+!u?bJ7+{;GqA9e zMPFVx-WosZ!T&M3MDInyYXf%Qs+&26%G)b$A$6Rmh`xlo*I0h}*LiF#Vbc4ou?iOW z8p}rR0;&sWZt@v^zW3Dof1OGXB=+(DQCvW=;iENefiC7bM=Dj|d*07^2L4Ye$Os|w zCr|_`#kIV3u!D%Io_Bs_9|afFjN-qyDfogFwRGeC5nSH#0Av@84?D z%rJt_Yu2igCnIsnF?;I(Hz9LlvLt2Da}@&mZ!is^!$cyf)pdM#GHiq+rcRE$_f9?D z9c(=l|Ksbng;U$Yq66y_9q~YW)5^{4%*v~WiEGAxOo)l^I_?Y*!WFV9LOj@)+I8~W zn)p|A4GRBHU)T+QbDj^ZtPAUioYp0UBuv~jRi_SZ0CT}eu-{eN&Y1J%0=ma zjVd|5Vx(k@*};U1AqiuYP?CrH{%qGv+ymZG|GQv5IgE#~LRy%%o=bL_!hNvB4M`>p zGyJm$>S%j&g#Xs~MlF4Yu&YTb$|>H(qdzG_keK=SNh0svgE##7%l}XI!(jylJ?y8h z4|n-&AQk1RX8G`tMc!X+^RJ@*8v{RjYAIQHKUS-52GO~L6Opd{es=412t2t({C8Ez zcxRRMbCfhI7LFndVi4VAcHYYCkpH{-wPjc`o^ox)qJ?S-6|uK%WOa^iPRairgM?yI zSt%>kUkQmdimvj(w+pp??$KWx7r!ly3#Av40TvGDpMW9?7vLjLHXt`U*U*%aO3r|mIGSNrah?ty7^etD6G?8 zH+L|fWR+XBnHD#B5WlFA2Ju@4=HI~dG~)Do&R$qV%1dtcRkkgB8Jw$5rOZ01Z2Z@x z2O5AkL|$@$wtD=9KtK$3WmWUU>Z!BxPD(Ia_3sJ=y62M1=r`xPYRQUKWqhQ9qC!Pg zl?%JTv8A&|3;WT3dFshe-ac$q8O`k>%2(c8KfmoW{V;lT;{_r!tOFLnt5dyHPpg;a za+d~4C_zCSiPiE6lODYZnaS~3s%g-(rNL6r>guHf{OOGmu^$m26$$t8qHvZvbaUpu zW#5hZ=X_q{;Hw#I5F;b&Yrlf~5=Sk@>x(v$5Z07DtF~=h@qn^EDh7HXh#h&3Jeklu z+7Qo0IJ=BxjLB%2n_c=`EF3k+A!jf})7fchDNnmo-Qz$yznc#pHVzwi|4xY^WJn_> zC74|Vaa7;p_pGc;$%#%whIV`uf^yK1Prsd(!`t;o0{xZG@@`p9ex`qF4HzK;bN{xxQ!JxVgA92U-tzuBi)jGK2#PO&31S#3 z(BJ(fH~0~*%51}B|3G!`C2gvM&3kurI7SuMnURRG!^r);1qT>Mks*YToU~Th^&Hk#K5C||=y51CGl^tSkt|rzqC`V=g~rj5;G8^} zGz>#nrIa7>=quOQRK;j9UBwoYch1eflv0*x#0h0l+6Qc}hq@d1K3T)upQ*8(4O|r- zFz60Y5+MzHM^R`prD0OQlOV$G(8Yhzb4}y%YAT`@lXH|LI!RIX$Nbb^x>luDHD+j6 zx43RR51N%aW@-FnF3-n&obA@rJ}s-<#`EEQ&DJa5I~pt`jui;E-y!;VhT%|8lDv_i z!edp&Yw-PE<7<`fJlcxt*cTv6r^Bws6!5}sG(X$cdY)=J!-BvblqFUEwCRV=&Qj9SK#cNCMkPUEuq! zN)evaPsNn*jp8kkh~Is|W`3O$Y!FhcQ`ctx`=U>o^@Q){3uS*0lr=2~{GDQ{Wb_^_ zV}_){qlGQvR5cD(JeZ%Y;8?EH0>@xIV1{5If_1<{m&%saXtPeiXEd1#msD`N3zcb> z1u;X){5I_jOk)cG|DUA?9AE}AIH_M=Fd@EySL$1^sjwBCMsz`XPgyFrEhFvQg;_Be zG#CWPoN?ZeNQ!y#`loi|@2{}zRH!s}-}>8>SyiC`(u5n|(f+w}GZ;XH$GpUyFF0>H zv(wY{y#E0vEUm8Ks|17{715t-+!VMKs6sJHiZY>$>7-ORa8NLS?$DnaXymoTGSuyb zB9QO;%wf-p+mwQvAIS@ptD;A>Vmo#-{=Qs^ZJU1LG2Vl-2KDbOt-g~)5XJdC;SP0O z9}8wE_Ro8b7@0$u3g^uwG(+BRgXzZWZ7FGZiLPq=5Y27{BlU zumA`~S@M&#g)@}O&*2PjckyZOZtwzuf(lgsn|32n#j4~V_(V

Drib?#Z-9kT_(TD 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/area_chart-light.png b/testdata/snapshots/darwin/area_chart-light.png new file mode 100644 index 0000000000000000000000000000000000000000..101392a5d071cccfa830dc4ef215f3709dde0934 GIT binary patch literal 18427 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 Jmvv4FO#qX`@xA~6 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/bar_chart-dark.png b/testdata/snapshots/darwin/bar_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..118d3936d7a7a60b1c658be6543cd3a6dc1e4b62 GIT binary patch literal 19288 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/bullet_chart-dark.png b/testdata/snapshots/darwin/bullet_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..82f62d53158279bd114f5245de5376417eeb2431 GIT binary patch literal 11624 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%0DiZT#eZ__ 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

!(S?A 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

#8u}@+JLfL>r*%BVnuc>fD9hfJlrr6VO4s`;7Vu zeH^H4`ua09*mQahnJ{3ye6&K`BKjgkLs~rPR$v40UEwV)P1R!Ux!x8NUpybOPsd<$ zck2ZWY;j-zJQzWhXg(!uBgtd-JjH3C>8^On#$OMx%ib9puF!mPriH5`>0y#!cc5?Tfvyj!xpV35rl ztzY!?J~?}*Vl@(zBOSVtm)Ue;0QU}f-FlX%V3_THHeD?_elaF>9;tibVte5ux*Udc zblG_0qu(-2ZVlN|hp4BdrKKfi5I54RQYvfRe@h9CN~COdJAIBf(^9h;?)vEJ0Zma+ z*>j5LqIb6|KOWYoJwH5-*N9Khh(8n_sc4F8w97~g1!x5ST$Ln@L;hFf4>v^# zW&{kB^V)FnND|J}=;&$p-x}21rQIQKM{%_qVKp4EFXt``lgA<&=`Vc*d3%}r^cA(> z`*2lNwWw!N&mz%{>BI`vM`*7#n2LUSnH&4Hac)+mlrGuF_L%=@&YDuR>KJ!onyyu!s92f9ZkUdZ5|7i_Ps zV-RL9VrT2syl`7|3uyQ79Vw-YTKNHzP0qFTEH%FcZP!cL`;OkqN?Ay)7GG%|oWMXI z!*MjidyROS4su9>qU>Tgu#FvcPkiSX;(8Wtc2kQ8CnjSVTYP=F{viv8cgHoF5ff`Jl`Qa?1<%cPc}W+l-4Dmih~=B?p>6n8l>ce( z1oOPs>J!hb7Uh=-PpYLPvef%;Z0L{jM2%Nh*R=;U&r5`WfV1;ccfVn#$RO|!9(>-Y zm3Z0S)!Uvks9Vz53zz+`{T&-YR>Oo$&VZ)?{E_DJJ?s-4jB}GtB;jiUv^jV3h$P+; zQZi*^rh@JZjKZK^+oNtB*6jF#a*XBVuzSNI$-d~0eWh%R^cbj}+< z87us3M+{OwSdn&wiQt?B!r5zd2Q(FerHLcTCrA;8>65C#aCZWT{nS~+2PWN$zpW7nAb%#miFrKv^ z%#bD~R5FZD{z1U&{##B~AfSo`ItJ39drRALD7=4sN%-W`u$W;cVCWbRZF%u8Zf~au zp?-)qEAfs-xaMH^hXfW*Y4>KD_eoBY-6t@#NGGReMClq?fB`uHDzjERB( literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/calendar_heatmap-dark.png b/testdata/snapshots/darwin/calendar_heatmap-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..75a10e3e5cca93a0292968d600b8a8faf9e1efed GIT binary patch literal 18785 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/funnel_chart-dark.png b/testdata/snapshots/darwin/funnel_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..0457c86b06af5838e9a75ce0da99eda5b8745abf GIT binary patch literal 17621 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 RlmoyYQ6VY8a(*4Z{|4yx#dH7w literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/gauge-dark.png b/testdata/snapshots/darwin/gauge-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..3abc39ec6ed4a17ba401a0d109d20441b9c02adc GIT binary patch literal 30567 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 S!@7UXqa>&HwnD}v@c#h;C(=^@ literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/gauge-light.png b/testdata/snapshots/darwin/gauge-light.png new file mode 100644 index 0000000000000000000000000000000000000000..fb55f171d2d6b1d1304a3fd79cbe4e9bfd628f79 GIT binary patch literal 30341 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/heatmap_chart-dark.png b/testdata/snapshots/darwin/heatmap_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd7b9e640acbc88638e71c7e901970d8ba89909 GIT binary patch literal 16948 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%0A; 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⁣BcYv(E?b$I-dtv14W{-^Fv#&yyh*PtT>Xc8`2X3mz9KhXpST+h|&ur**oErq zmA!Y*wZK!|_QPZ2!2d*rZkV2qh=>rG1QAw#?9A^uk43)|Afw7)u3+bB*4Ge(MgH7e zTcEL)s_a2mK|iL5q3z1kd9CtnOYMdR0s44|n*%=DVIx%b>Xi zpzL*)ji!7S`&xfNzqI6q%tQ>VGJ6v_Qay!~!v-!iM;&FfukhUJ8RJY)P>9k-9R4Ye zHGiCweoumvB9b=&q)Ta0 zBwGnxohl$l0a(}!k6Sz1R$qp!Ny;=f5>ytAG0QVb6e>w!Q{xt>&;k&9lJ^>Mfm{`+ zJuJ9M3x#Tl)2QQ{x$|_coSb)ZKvHSq~@zLsvYxJFIndO(k zgjBiI^qLHx5_ x&vE^itw!`bOa3=o5c#iL#2J4Bc;cbT3kV_O2jDee*jho3c~;Z literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/histogram-light.png b/testdata/snapshots/darwin/histogram-light.png new file mode 100644 index 0000000000000000000000000000000000000000..c8034032f15d11e8a5d3b2cb1a41b0b1c8bed107 GIT binary patch literal 12658 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

7m1@5f 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 BpP~Q& literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/network_graph-light.png b/testdata/snapshots/darwin/network_graph-light.png new file mode 100644 index 0000000000000000000000000000000000000000..90c1640590b92510ea0514840695577b66dd1b9b GIT binary patch literal 14812 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

S$WdASVYYt1-}r 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 k|J@QP=K3=x0FjFVuoRM0=$N-bRg zz#kwbDx~6`cDm}NplrSlcR7d%>kU)>i$n`mUk#HU$cpo|4G=Glq*pa(r8yNtm~|YH zXj8Aduu`F`SlF5sxQ!J~h!vj-Ma$*iWkp7^wH+Cjl|up#8{iKs=_>4AB@LC6BmD64 zwikW#nz4g6$o`b}=LWi+*OFEU6

&cP&JS8^8j9?E>HepbP+r{t*A~hkxea(GPmF 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 C*Khp* literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/sankey_chart-dark.png b/testdata/snapshots/darwin/sankey_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..29ad59c59c5191bebed36a8976643ea3567e7fde GIT binary patch literal 13436 zcmeHu1yEdFnRx0G!P)TLxQ_YaCdiy;10p1kr3RPKyVH2+PE%X@_pH= zsoAQ3W_D|9s^*@z&Xu~yp7XqRt2^wyyc7x|AtDqM6pA!ZLJ11$#TzInXc71q&re=! zjvGNiafnMxh^lKM@lbG7vs^E^OD$zg+jFlAieg3(y1X z1Rlr*3)7qg&hCC?M1Tn7tkJhrYGjt_P|@rE*`KfC%R+A3r@>Z<;+>-Lc2sACV-hBc zomV5V28k5=pF`r2`L5%0i{Q53h;1Pa6mWtCL{B~uh!%xvT;Ff8-IHGHcY6Mm0tQO_ zkNn3Gn4~E1;6L8=xUbQX;?leqPLO`YH;in#*ea#X`DA`FcXCBMZGlu?eyremY1*Fc zDeNN?^ev+r`H+;jjs0=A8sssk6$>N%OG>lI3zc^z>v+$OJa(O0nZDXeqM2tj9~x^ycJ zR6MSZ2x2-fUD1_L*#N5emGC@{T^AZ6|O|Y(FY5VS?sWp+ad>fpZ zR!?W&`z_F+2{b0Yt^ob}eT3Lx*!Z&2vN9Jxr{W>qOWCR0ZFQM=r?dN@#+4`FLd*Jv z9FdPhix9Y#IdBK^UX@G$@C6|(EZyiJB=MfIILf+{H#5z~3W1<6Evs>P_A+C?m_70} z06L<#!l#9Xap-f%L#49q2zTSd*6!#r!9tt{U{o$LB70F==8o#_e2zVmQ4AgsAfc8R zvbqa-gRkZ*e7F3?S$r-0ZJ(+um{=&Qma=f8e?c9rXaCOiUG{B{tNtDteIGSg`-@Xo z%}c2$A_PESWF`!LK_(Gzl|LJxCpk--L54BBlLc3dW0I3tfq%>T3K5W5ml=_e;^Zd* z4={qE{Yvh(Cz$OX^Ej8s)WpFB8onUIM*=8aSuu{XV2Dvw%GYX$|A;073Og$LkXbZX zEi`$}C;ZS#*J2wpomQKH2gJ|Nu;^r)AvLMCG6=WF(z^~BK5@Gk?$K;3gHiRRL~Xk8 z(sGENV$sEbu{1yrAjVV7mneklR%KO1tzF1%RiVCRneD_Ftpr_dW>y@DNnMqXsx4DL zOO(&Y^#~klVIQx<^4Y*yXYFYOKytO#QR?adPl{rqdTJY&TlkNU0;z~$e@baJqWMn_ zZZ7W0DTOTFhKlb~OA-5tKgJ5~9=tPNAGA0#2BFs=)HF;rxN%>&x?|-ZIv}Ui zC}&nP<6B)bC>Wc3=sIr4RWW{+?)kz1{}PUS(fESScJ;}~sJQ8^>7wAGVKSYgj%kj! zYJ_`x3d8~!I9N$vm;mOZb(}}(_nG%cL_2_S@w^ZTv@lXk!2+pcz(v7>_g!hb>ZJhGOKg;_tb{(6&JpV#$F+)E^QT5v^7mGiLru5@ebRBwU>a6D}ig<^-SQ*<*jrPku*}z&kmydO-kp zTRZ;^Tl139TM~|yFLYcq5|uD3KOnf{ad=#`O9_CIDGK*=^Wfdt#4XV7`OhM$+=1t@ zq@5vu(J>L`m+tdT1Xdyg$a0_9u=W09Sug9S@paCtBLdUEi30*g zOJL~$vB{8}5V(M1Nm99pJ^t_%UH*P8+r*AXf~Lf<6D~!s&rct+cC%J^uNo_U{$TH1 zX@|ljho0bhN$*2)S6K}zE@oT0p3P^MEp!!HrU}&Wc=9Swe(iC1SV=Tp)dFf?Lg4l} zTFi+delXewW6>%g0Jtjko5~zD^PFcMk4_#YV@m*v;(5UmC}D(3hMWak=5mDwH7ZQt zR3Tk>MJpTTQMzDdIk~z={UJR5tucO|)o;c8o$1_Hmlx&gNB~l;8iR-QDcw6zlh1?P z_8Mqy%rK+}HH-w4pUMSz5KA}@Xg?V#N(~=n>BRgoe|@*sTS;c^2yRGxY;xFD0`v%y z9Kw0{xY^#BiiI+6p4BM`VN}1O5_$1U%E$`PgjdEP`>cRK$EwUC`xY*6CjWLOme{@b zmKET%lV^E;zV+$*>Pd^fzJ43}KP)W;#L8zst`D59+iyvg@=(^Va&q@`#(i{}x`tFk zD%rJbRq7k-b)2IKF*&I$fWI*)YYJAuDjv&jKTMuOV>;GZoWA^d25$Du;`zP+D#%}7 zRb@QZY5uwEyuZfwdvUXX8gYXVm2Fh|CwMR)5#IgvV@MT_?2*?|X;djIt$cR6P^C2d z$I42bEysNb38({P2+kZOBAt;r?PVKo2)MiJp}RDWapZ)!qps{KXZZMaUTKQn?6xjilR%a*pyT3A?;N+Hp8 zahi*YVCKj3_8M7c(D&YYL|XmE)TZfE|7e!wT*Yu|+h=@5KWE4BIN`ZbTv0P^l&0{_ z`W>>Qq2WpsYyM$IqwRc0zuQ7nB3s*?xK4XlT%A!=O_4)A4d)bNAAZJd-A!xhP^BLS z&@z+buelOZl1GK*)+=d+iFNy|WL?p73QbHF^%ZbYdG~hK_TDF{6`d~pSwCBBuwa3F zy}T0u9D>V?xf#=#Swx^>&YQp_=Q#L|7bP+YC5Ku5OabqA3)oksH2~-Moq}i|qs#`J z%y;QUn>%VZ>6E^55?_B?I7x(p)({njw7htF@ujd$-$GT1DN<-F9cb9!UPMi#HO_bL ztEv+tzFOL?a)+kZ}Ju(AWfLPOy;Ch8~OnKMth+@P76!Oe8j@A!x*EF&=C0- z%I3AclOlALNz*~4_Cob1x|fn!g%I{U7+LbUsd$)TUs{#lf8 zfKfq8GIEMxbdwKRtoOQOryX0LQ##S+Zw^zUS{kN)*fBc4tJ1QUpB>Vj1y3!8lGx7T z9;I``{hBijaGjuF6|FGwy$oLPDW#;DKy67~zO`uPRIuaG*Hy}D+c`qKPst=>wdja!bEiz8aku0pD8idQAU$3KOCaEFJ7yO}GvrVSsn_W9g*?t34bMbNp03lb?jq~k~mk;~@{nk6?PRvEW`x$|IA z_s69s0~vHmteb%3q#-@l8LeR}Ld++8+1GXXN(}skVtI*)4E#y7N<%VL1&K2^lykpy zmjl`bh}_rE%@~KBc=;65FfE;I=5sEMiCL){PgnR5zD)&^q?WN9`HDP(Z)x&ud6zt6 z3sgvx3Svnh1wVPE(A`*S?Nf_*rK zt8L_L+yEGE?+O@dMy&2dF}riaD8QZ?FJr`OQ%B|nEz7hjVJ%C}qzio$ym>2}*`kk4 z)8CU)L+N8b)UST)(s%L6SpcsJ;4yzbh$hoLd2nk4ZTAa4?pm(gWo|=1ht*mlY@cd; z#}Cp?pbf#Z#-?U{#1`RYLsAF;Bdr%eM;Iyy9*Z^88(7+{Hx^0rLB9%h^8BmVBa7HR zD9UmIi1Jk49zIC-CB82-zHb=!2Pk?{QNsC!l+G{|>n4dOp(0IfHZ^s;BC^qeJZ+2mHD1V$a-PCGF)V61f}!Fqk@AU=ovei9#5~a59eM zC2{Y8b}KS(PoEIcoz+2IjqoVZoiB$tIW^4^-f9=$E3(}T)6FP9drw9DethfcRX0XT zFgt3FHHW(iku!%#oidOn23?L94 zGl_m-p*cWO^1)E~XpAwD@*lPqn7<5@%pW(aAN*x${?pX`uQn{O7a7vcZlI!m3m>=T zv}I~KyxVep6$=jt9I=y`5jg)=HB1tbylWjYcu`{IQ+77fC|gyOU`guv z!CG;3|G1q+{ZCLv0~cRb0?-wV`)gTsNq6_n;0efK3ctJi2E`xy#zb!J;&Iqm89rK6wl~_<^&W^PR>3@Q z+~(arc!(>;`G^)p47!;^VQ^uT2`G^SAA#5(&qk%3103Iu-)- z{bV~ z{LT`dYiuH5+#)ft)$xH&T+3;;8{`%a_U>`_=^A1zsWG$)9RT zW!boYvrMOI=ubt6ms0-Xw_E#n>j|b;yTX@8f?Q<=F)yz(dAHAN4qrE6(*?pdH`O;a zwWBlF2QFed_z{t+=aKh?R->Pz^$d{F5I#+zM}<9!AhY(FQNUs;A@rylXsPtP=g5T@ z(5U=PJTk!yoq^7agdAOJt+PW+pyYB5CkIXII;^jPEjyOSMio5_qA&^5;`95bp z|Kg3(UO?h1Uj*JgB_n(HJE%WR4PQ(|<8dE*-VhAeP7lwx8RSuuZFmF#?@x}!NPjxhQC>czZL_?$v!kb_X}@()NL8*kd;5OT7kS^=4sR&SG<|-QGs>bfX~IRF=i_rE2`m~{+Tp$ma+3EAU zKh9>VN+<%YyzV;|4s~riTu-JC!NuH_tYhLKfv5=o^b0!&NE*#jjm=SC`98Zm-oER% ziS)#Ir6HcsQc_o3)OhnPscmtfuR(U@_NQ{+bz3d3G7^m@?qHbFO=MGjV|#~(K2^MV z_Omzp8*voOg1sR`z69vttG`oSWfuAb(M79AUgV&{@?n^}O)w?QoX5}M zkeSyW7lp667v`^gyf@18X-5kY`Eqv!r#J3kq#X`bw_{oielRByWVzf( zjWq0S)iK$he>|Y?Q0v-JTX~tW?!1!Sd@E}?xMJ$SJo5Grfy}>>tAbhDUGh1f)vT0K^(OAmLW z(q|;mVMHhBrz6dO$O%>)T%UZQzZ>mxU4F9(?5nK+x|o=%$E1nGj*pgYC#Th}cs7Fi z65-?f+#b86<_bv$&1PFvN83S2KCL`!uW~d;4ZN=I|r@SU0+O6F~XA>+eW5 z^>#J70)>V~C&h#!kvORX@0tCjvGO{HNoK|D++<)dR`sL;@3N2g=SQC2c7|%Cafad*e52V)-Xj3Mc{HKsG!{#BeILrH!x{?DZ}yRD;S$AKIc-ureiKbZr_Iw z;f16fm-`QDk&IH~vhYNZi5IhyDmgkW9dT@GNFkaiS0?(0&o|Q3IjdMNH1ff6I+u`4 zMz{VPkjj{O`3r-BL^x@?qq}Ue-t~^@pk0Chxr4-;#TnGXX6jv`K=cvQz&GryiF8xQ zDoXS+B>gT2KV{E0OKwggEf=CGiG+UdJRvI3AL5I(0;y-ru9t|TM50GQLUf+G;@L)E z@r%r-oATVk8XG}=Q;QKHzByY(zfmfu+aDKCzn~+C*8M@_Lu$aKaa$8hI+p&+b?SHS zt(RUg>|8H|anerWT=()8V^CkPStyIA@bWdT59N~(V^zQSa*BvAB107Gk4p0{w7v&& zo?&vf1C0;GzVFR3501=RN^VqK`gBRYrQ}i(_=T#AxEG5y4E|E9f$1yBF-1LZP zHEM&e|K*pM2mw zTi_J&s_0?Qp}|>{xCJ%1=Soz$%tdnF>-!nqaiU^+bAr}!QIW%N!wqi$IBm-j$GC8d ziB~N2hn(rCrk3A^$LScJdI4<4>S*$((P#mTK&&d+7FWFi*{#w+giBd;ervm4;8l%x zoVK2h891IYkjL?{&(fBR4GZ4kYG9>guB3ei^QoM?CcLNE0OkF`Sa^xQ#zajp%ihJ* zIGN#XO!K-)DyHZJ&t`8+(E(+$v1;NwZd3U97mA%T`zsI1pFXe-wrjrgCx`c^dPV+! z@=E55zKKamE$&liK&pjz>JyJ9-8NWi~bUAAIupji92Hmtq=ApMwwp~a20wXat9Qmkxyokw-X zxLZXdh<|KhsYk3zC*!w0$W3chb?>wHkqfUG_r;N2G3KHeU?)|bZCck#dgsRnLMbWGeFUcd(`jX;_1Fcw zlcVG5r2{2}aOX$fmTh63TLcW}0i)q$CWB?@Kdf+vkKLkSy1lt(@f5O^bo!*UR#7)+ zKv7m!)$SF*R9n+Xl_$v0%??Tc8mTEN-t6w7wYM*7GEEi7GE}XQQ^>~64JyyM9&ypQ zS#e|iHiT5Z=M}yMHqVm~Cgn>%agQt7#0ci3v@aVCcv@xt$}uHz9$%R3m_os0fb0RB`v8#PI>`hp}DR z31Z^Oo+n%wx&w?xjV1HE_M{l?DfdN5g}sqGCz<-F^K)9ypSLMm-5|-u{hz-h7^>W1 zY;J_Vltj)TB;cCt_gKB>eFs+(`xnY$zjk*bfS~{^KlORhzhJJ6e`R>HuyE6smgV(p z#$y$)uJx=1fs`a&?epccAjozk3c=JkK=#H#cDyjYsA%h%3RcV4)tAxHd3l)PF98_V z^KDDxT`uDb2v%Hov!_3v*^KDPg4dB!p5nujl5GFf@2I_IydrQNP<*E(+y$p_+Vz9< zvFk^Ow86>4(PgEL^2*SMY$2I*nAS>bYu)!4aaGLvG$6PA>6{K5Dea7IgPQpT{#2ZQ zyMWH5qAlF5-K_fhdNzfpfy2@wZKq?{Klptk#@vcM5)KI@2f9N4dv5!DR`mJf$I~h* z{DgMiBlWaT?aRLc+g${I6)o}(G@y*}c2dN4DmBdR5AH4jxJvele4{r1)uPF zh@+cAh*HW&D|R&P>zgOeCL z8Hr?Vvx`ZvaaJQt@)pfBIs4PMZm|$|4>noBH9`^b{ivu>0k>H*bMuScAGC)Vx`msY zPW)31&Le%a@n2V2WSH^r^cYOk1V+zG0(PrTZ`!2S#d>aD$&HSVw3;%aHgbu2cZ9@b zeNZEZpFlcm5>*l|v#^k<*4x*j%8OO>d+g{Abob92rq*sW<>KOWt>i#QWJ%JIUP>ST zKFeW#fG;i{FnNwlK`7)DT0QnNDW`Df%#HO21sorr(}0nbLgxJ419XwPOeP5<8#g;A z7vavvmruQf7x*d@i_Lz~sGQCda^?%eRjTOYsd3PL-W{H#3YjTSs(q*}I$cg8glOW1 z!UB3L1aZo+y!`ao;l!sm=OatuV6f{pEe8kJ+?EnxwdHLO01UNziy`{M|yZt%QB!X_O5W|-LkS?$VlZUxhZWlSAU-pheuc5jpI5Xo(!$4bJ z?Ox{{+6EqO<&D|t3;{m`iMm55pt~=GibZn{kkBh1VPvmg@vB*V7J41d-=d|%|oFgs*sM)p*F2X@!=T7qhrB`=871jg^ynj zmBiA(Dp8+&)#AxqLPb{A@*@7KbIIpqa*mk7-S~bu8Fwqk^EAg}i~)i;aqXCU`mM34 zAsW?Zs>e*k*;?0q%Vuzs^udSnFAH%rh&orQtxrOtE2NMzwhs9uv9W$gfPtItc;q?H z4SMzfm}{n(e0JMNjnR<31mkkh+AhlJtUuJaN90jNIL0sGIh;u#SgB-)E|mw_MrQUCX5T zj$ILN$VgB)vNOg7Z8!{iRi)kg=hbzFXJlwAHJPZ)Og@tfL>My4#qqrfSF^zMh?%an z;Iyajt<)f&(SB2besvq`enY7hmv%`pH_K7ObmL`|zU{glj|olRJD;*56$VBIMz2)S zHoTCw_gda^>zaoagg(q1db6kFiW4i|+U-Xx&J(w(=Bw}E;2k>eW4!pGZS#g+LOs&J zna59nFVy?%1B$A8zf$TIb&5Q2hiT; z!25vt`sQIc?6iiPaZ}&R0~;`D&1S7pH=$1lOzuk=F6+48;tzbU9AVM(9dM4})vZrQ z4*zY{j#$`v>%1j`3zW6&PneNDY7(JVtUfsnLW~`>dc1}_$QQGJ`0TTVwF{qXWS;p> z(d%-JIy`N%ATayGwMDS2;7SgU^TCEWZpJ1HwtS8Ns|*vxmH5tN3({o83&3PC>!eQy zs(|C^M9VjW!0(jw(lv&X^cH&t{n6kR*AoMK1TnMsDg|@`Bg$db=XmiOSb=q|9o|dH z+^ookbsEyAHE^gtjLIs**i+99`(uc-m1jhbqR^w)!{_+|-|Ge_RqnzgA&9~s3VRml zsHtkNq*BO*#siymqTkaky6$}Gwcy0(fBIstn%9UF zeM3oGjxtV?M#VZSm zOoW(z4`G%SBes=_M4ywR1t+;9x>g70i?c#+fowVoCMJ%8l8v$=@!{F>2P#8#_*Y{7 zc7%~xAffx_=e%6xMJ(z2SfPitVRvdbw87nQU`^=l31y&`>LC>}MVth-qUI*Em5nNA zQ`t`bUEd(tm@tRuY>_id+UsOU3Nx92XW;TTboYSqT_=h_4lR-lxyP!Q_|WGck_;`i zEJ5zDyWd!l1;$pJe41hR9Qe77w=FS|`2k<@5e*Pfli=;Rb>jS4{#Y+z_xoNmvCStl z_>9p@rs(IC1$deBj0LIm`2DLg4|bpw>=?fn@xFDt1D9 z;_WYUikPe!z3x|)+&hO<8>F!?o{!;$V?9wM-K(+P`Er%^IFyE_cj;_%lq&^ibs)a}2_mE**U%1K`8fMCy>IO`( z3qv~6-%_j3RB3GWuT#seN61t!{Yd>toau}bwY-gqOE@%JQ&%LIE@W8N`F^LR!$6V8 zZHVS9@wJ-eST8q&t;&!!mxs>CtSF|vp<{&B4*)hizDGlj(LuOZ2r5f@&P|H7Z3!od zzL#soh896Pzb_2AU zu;0svrK@G#VJ~LPdTrM>A`D!*Yt>!3IBkdx?^z`>fhbR2sXj$2g>f6Q*!w zbI^~Ed;y|#KS8DfFmav7U;VnJ*7~9b2f;dtSuOle?Ed5q5X2#4)oiaFKJRGn+jq8a zv??2?h`9L?xEEYP0+vH*ilbr(*l(*rkUhf0I#YSs3oWgK1ip3v-5cLglXafxj~Zrn zCpg^~w~~e3eq&jj;zcE;v5acW+VK=}C)uQcKxW(&7`RszdL8E%O|C93O9pM}o3#uP zQ(TUF8+2i*S|M%gsi!)$eO=PWlZ=sBS<56ugqQ-thTu3uTJN^^`1t5wyoM#qUJ4eE z7}SXQ`|t2AuG;a)4BJrk_Df2=)qB>Tem&!Roi{GMg^YzMvehVLTvYpE=c>cWi*(fo zy!?S4Ks&Tu(YBCD+KnmBQt6411S~kT@S#Dl*^CoDsMRPuJ+UV+46XRNw<`SxgE{sM z_a@0=B0e51LOgaWyYr3u)2jUOy-iu}3eB)}i69+6ESTskcdAtv*Q=5cNr}LqyzD|j zF+JUk^i=Yw2n19__tTc%3_VS8TR=h$LFC}-7ZOy^s7($Rz1-S*PSP8$EgMt`_&KY_ z;G(S?0>@yKXnDE#qC%P<+Kaj4djoKYChstULQF^97F8vguMX!=w|B0re(sQH>&xZ{1yyyoSA}B1w8Zyq=Vue`l$6?jsMAEMWAhL2C(Swm z9)S<@Lhals*X(%Yzqx@Hum$PP#=~O1_X_1V=3;ce*^|HXkK`5ggI48q<`Gqynx^UN zR~y1vqDiPNeM^X^T>1e@I)Ca2{Dj)5F88&KsdihBK?5v;IDoGvDd#elfrwhBDE6&D-zh0ig zNz#!`?n4Vt)M;^lh;ARcZaFzZgwA=o61L5Gm_2uKmI|nC8Pn`WMlb=QEh2~A;;c9# zuC->_DN^7HK3Sp0aDQ%Tu%0;*2>c#{he&NO9v=j`@%Fa17=_C@$eo_1jaJa?vt(E2txo=g#NR@U|bdJ#7?Brlwkz5?TMTv}!+7NA| z!d#p8>)?;C%Nna=vP9s$P6o46)R-0;Z&Z=HhZq>fbecCx16u`MF25CO{wRij<)2Th z03!Tp6SnUJpS66lTI_*mYzj_g8#Jl&ay$rZ?XQCk>ZL}brR``i59qb9e$NHh>fOSR za7BM!(*IB_Z#$dybd&cgO_{dP*=330dX1dZqpG4TxvwvAxEx(<^Q`Qnc;4m|XExzZ zHh`r^p$X&&LDXA0ap*hHTp{M~`otL_TP>Htky|qPkSh6PSX7Z$TdLY%{4nq8vdM-j zui(y{yw4IG&8f{~iWHFzPESe5(o|EFCYi{c!tp%a{8r(nOj|^+%jh7;A2L*yK5vsy zs#}?RZ+N8YPR!=b+y>V;XeH#f<+*jBsbCB~k?KbV0R8$0@PIPRE^LDjCO0$*%uGzhLRPHxmP4zs-jkgh%TAAG7;y*N$f)7swfuP4cAmxgp6 zTZ}X(Pu>z_c1(Z_;p|$Nsw4bA;^!QjvMqJfU#*l!<{%wcH5Yfml0yU0=zy`YPlY;7 zdqF+Tv*J=6PmewHt;jE4ta&3rA&A@xLrG(k9@+7nOH%4WK||Y;J*&iXZqy3KiPa X$az*g75DtFA}Hy%@)A{IAN>Cp;2uiq literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/sankey_chart-light.png b/testdata/snapshots/darwin/sankey_chart-light.png new file mode 100644 index 0000000000000000000000000000000000000000..706817aaba4d6f4ea9c9d95a95bc6bd1eff40265 GIT binary patch literal 13005 zcmeHu1yEdDwbOjWp@%H^GGnSYmZZVZY(@-u6)OK*Ni~IlNO5lEbw9 zk^779omB{_LH!p@9G72LPZ>UYP(IVcduBtGCUU9llrbj3z*zd*N?C`eQ}IeM}oPMLM1ASggbvfuzn00m)&;#@biKtfQx^|t~+a~G0TV6!pPDs*T_^5hHQ;oz=JKR17?ow zHDDh!UXJ0yDDk83TdvFPI|(@s*2A7Ja5zTt4*NJ?;*8 zBZS5N7ymD4fEmHk&%FCmzi7^4AmY{BbJH*Kz%9&UnyOE9NTg_50v;Vg<^! zpMz_YUhFwz+Yt{dFDp0itA?yau_*uKLOcIi#4K8Dc^`qfhfY=9@}w?W$ux`e@t*r9 z;mJ?76wVCn7d;Xk7=LxA6g?CI_<^tE0fjk=As9%CNDRUivkQl0fivq0dwaW@4CSRR zhX;g;uQIa(rVkmHo0<_c-Pv+}9D)xU+np(A1Jy|Jq=%_zamvu%=jsO}N zqjzf!c;@l`X{*w#{Q4{1$ftqtn**lc#^()|kR*Es52 zHQlO?^_E)eo-{Sx1Um)M4Zb?u6}1nYY{j{Ms`FVYxK(an>dI>O0SjL5Ji0ZxGwTo9 z3t)=_0ww-nO<~9!Br!?dkM_Yz$J2%7NOYPMzb_ua%KN3u0R zJ&FQ9bMzzsu%G?KK`%$O#?^~Njwt)>BMdJ0XYoWwOBYoxklo2gQ!m`W$^gVAymfoS zZdD&r7>0@_Om0={Szg~QD=ly0L@f8(?!q`P?3uLdk6rA#tiS`$(!j1< zpZT0NO>#@6vs`g4?5bXF8u%#4^9|}Kb=rQ1b$f&;0%{R0GyE2Ab8gG(Ckzb1E6H`2 z{$Wd!UC*lKlk+*2-uK|tH7SM66|eg}&WLQaZh(YDK#4D0>5re>16#Ops8l)k)N<#h ziWqT}8Mdp_=JM&($sIsj>{bCgT_m+r1xm5ZmXY8VR|rzPeFu+xumYH-c)_LS(Hn|?z~|f zlwKSJ0twykwu`&EdVbk#5ICFFi+K!@kl+v@3|$T-pZ2b$!b3BUl4TjYDdbhrn8?ZC zW7L+2e!YGAvC*eFmXYw8%TI^6J)y8T&uH|{R8nYt8edUuZr;rXO5<4A;m~FaRPvrF zRi~w~*DtS>ZcW%&?91O2zK)?!Vy0L}sdY;HG5@M~aC`dzeV~i{JWd)t@zFiv7dYLp zLz}so{dQGe681ruxGWp|S=5@<0uL*S;B*Yd-7NUg>l+NQ0A} zfOF_Y&vBO3KQC5(q1rp2^Ie?|U1mVux3c3L%$Ra zejxDOE0BSnTE1PTV6mA?yYetLG!)L0dQH2d-foy5ITi}>|06zt6Ak}Vz&Xcxa<z z-GVhS7cF!@x!G+=r;l|u?VYfpz#6YX)~d*cQj3Z6@F8k>2q>hC^KbV#f*WRy+}s(U zI3xJ_Am@@%l}*+b^%TBm# zzlmjD3*D@Kk7Tnekh~}tnR_)w%pE5Wqf~}NyHI5_r?}BS8KF`+K5fkFEZJ*sErn;? z!kpTediZW7g?n%9?t|t=0{h(>_aA}Ka4&)tr(UjE34T4CN{HBF5qdt_$m&k-UHgc!)^B!lzOys+_e}Oy}=^VPs>jfB<#U2B*NF6VOf^XiXMe{&! znO8p@HxAxUXnzf88zM2^-5|7r@DFhKHj4ouvgV`57E3BlOi#}oS(pgg;LUf|-|Jt; zW=;|?`lq0ONL&cF7h48ud%v*ya5DjssdTtBZ&Wb@{}2S?^tQZTBe@Gt7(iY(MCkjM zP-*~(Sn9S<6DJGI2K+Be2RICxHfv1}!2SXUsz9uw;}Ea*wH4R9=5})-VPm%XyOYih zHc`ebCG4$c@inzfkTYc=XTjMFy0{ER1dmYHvn{}SFbq99_=nNfG_7v?M$IckL>t%1GV-(`w!jJ-^0M?MM}q z=2GeT772#hlH5B3hKz{WiYdkGL=72+%0~G_#RkHLEI_-GP}p%QiM!PHkUo|r_;mYh zf*O3fa;Nc2hxiW{oyCfkyT4c;G9O#HYZOY12T18?XMG`(Y{FK@a*zH}xw^E&9Hx&o zP8kblDIW{>hY699Rh|Mr#ut_X=%akMT2<&Z>7(=g))24>@(gt;9w?nm1QPm0aIRc9Huk7LW z=AiX07yH4E)Fsjw^{G`wK@A_)Khd$23s4Cs7uK>vSgYHG`4EFzz*A)~wc+gdQ>!5I zuhNC-ee5ABh1>Uh-2yEsRdSspZ{;s@o{u%XzNZ6saqA|ybblkwhr+?$dlg28q)}I} zDhbZ?rQifkXD^yXbIBOZLz9JjpwG%`wB|Bm5)!8=`)2#J&!TJose>@Q` z72pbx4qziWTTol+ejGi?;Orh!r)wJ?G#Nl$1pa26{7S|BfH=f`=y4QqAX z(%An;nT18#h*G$>^nU>UEx&#%Y_Ph7^Cw04!aLL<$Y-HC8NCkght_$hq|@277o~2^ z*9#@e=#57)c*^lUVNa+Q-TosOpINaZm1Yg<4{<p8H;^X zmdWFXZ33fmRF38uPhOE9lVsE4#$4-I-!e_TWvVPN{Vtjh1h3YOCC)HP*K>@=Gg6jH zuY8Vgb@Uo$Gj=Wy?WP%L8~ceeX2H!4nFE)Y()a_DwAth>U{soF_>xlksvMk)mIoor zZoa~cdkD@WTOLLB@qn`%Eb1BvmR-diswR?{C5FE&%yAVtH$bPo?;X@xgzHS5is=2^ zcx;xUoA*BGB%gJ$;|HM}xrBD}b$)p}URLsEBxy^VWgFbF4UtBMq%kF+bQy1o|yO_9Ekq$bkBv3lwOzo_AF@&ANE`3WVr z_68d8fDq5OthiCTpHRDvv-PEIYU;BED+eBdoDdhD$OuJj;k!ZSFP@K6zO8--^*)El zH$jhLKHBeZU}K5#0V+tGP4Vfb+B_h(Avy9q+{5sT^IA_4-iaO|_@@uY&NbbS@K4{a zQ$^ArxyexeIc1m}MTZlwuK%}nj!^p@2( zi19-Y!w~yrJdx{Hb5h>4t)kVebE4qYR~tN@!Tvh5b|ap$YFS-bPDK3Sw0nNtrA_(- z>YsR4i9$(d;wXJFtf+9YVDRLj)Z1s@-u4E?k}$?GfB?cJFX;+hSVKKM3Wz{T=sC zFm$*Pu)%MEOZ(%(b_()xymx#-7~k{0O>S9xch~;Xm<57ri!5YUGh7e3r(40JH_JWC zG(tj-cW3Qu$Oi2*2A3{jAeevVqY>Cb2ilbf`I1C74jlSw#uSx_EGG4{O1D{_K#Y(> z^c&YZQy4ln>^POfwo?b*56naH`u{>jkviM@tjFU-4023G58Y0pN+S7^jKQHnXz@3G zF~VOXSart^ZzY#rAHl%xPm_M0Yfa-#)pqMW+-PM)|GJB4`YWj6>kRV{vthd;g0h~< zvCw9fU%P>=S+r~U&3(vFU*7pod*~DpOOlYL&Vx!3$mGAP9Q1Z$UG#GhC*?v)q%_NySg_!f2%jMjOMouG2d^ec69$YhOICi$x*B+5rPI}TUPR;@Ndo+TPgh}wO;3lFV2%o)4QYwEIM z*>W!WF`x2xOU9P$u*li4>1Y{Q)7bnz-&!xnK*mh?I%+Uk0yroMuu#K-8pKn#9ZeJ)tDdz=hXomL;97rMMUZ zY>~XK4H7I2PUJadZvgoh4lE3;f{#F2ogOJHVKI>aQS6U+RK8H*=cLNssz5wqP*7km zbgnnxp0=pbdr7R_*?cT3jlG?z(&fNznd$Xazj!Y@O&>sT+x+S^x%6G!|9_JR9?^zf zS1C~8iH0^{zQK^b0YG6vPN)d6U61z#@<(esY5T|fi%nl=Zf?00p#J(5(n)3a`>fju zXxLavH$6R_Mep|q7*Pxtb4!5t^4$h>Z5U1xY)}Eg7uPFXW*KnPS-B>&y|4Z1i}UX3 z)6HJ5vSdV#{>5lEi2}*1wYTL`-Frgn~{i=(O-HfaMkmvo#+-Z_*<$J6GsmJ%iU#);qW+7?a?Tcxk6T3dBu}H z@_R<#GLP&1G<2cs$$?_tt6gNWGOOaIrUnGEs^(_P%BxS&dMz+_;(aeua1Xu~f2z)u zI~Hx=@FX)c$IX`}u;wH)SZj4$WQ2wBofxg`&hAcHtDos!6dGB7uX!@KWh$_$>}#jkC$MlFY^c< z)Z!S-|HvgvVEmEQ&I>?JH7+g_PuWNM3q$(A{1-rmj1GWB^)`W{@9YDq3}5&;E#O{( zM&MppZnt)+`l35uQ{V21`#2sM+i3gZ{8@OHOn^Jm<8V^{wdBat%p?2gQB`<~`Zgx) zr>sJ-AI(1l>iShgC7zLriH?aXDL$DTr$0WR3jY-_k~8AKH>)`ieud2Q!QyN7_k`Ce zWsJ{b!1Nf<$0doM!{>SW@BfmS&iWf=m<<)vXl$R#bbqraOll9B>?e1v&|fMeDl!Ne z&UB+!0z-4@58JHeo77tpD^3mAdq07Er#w}A|A^@uWWaPs1pbf3H=h|zzvOT?set23 zjhR`^izuJX*j_X6Gevi2f=$a4*U9x3qG&{R`m?rMblFgTva&LMPKAA9J3fi1OtgKt zrTQF6Wh+ZnJ0xr^O{KiykCeip)&ih&E*fi8WicZOk$fQnSLrC#$2Oh!Aj) z(n(|Lkhf843@(mqMShTd!wMzm24(i+O{9Bw8#H6x7f}rT0RQM7`hBR_X{f@_cLOSd z$0t&Z7Xc1=jJarbtAV=Q8}ste&PT<${RL-G&VnqUeI!~Ob!Um;Dp;a(qk{`0sQ5Qn zX_I=s7miABxN3MAZ6-)Z@ut6$eiLAi<{D^!vG?;hJ277QE{?UM95ohz(ESP&phf9L!E~3BDGk-7cu|GJjn6m09qwcd zo5#&zK$3W)ERtv>k!Vx83rIe|n|a)YtJ@~U1Ks4K?bA*b+k#w_GJFpu*c%b$X3lX7$aWOu^yx%AK2lk~uty(x+}C7^DgX;?bm{s3dD zbb8P^zNdIm(H?3cC%v>HrRnh2-;RljT`P1O5v+qjT=md}0nHlI&EK!rd-emUTaJ-$ zG5^6gEz(-#`@4lj`VX0vVzixy`&plQUiTvQ6fRNx;S4v-z49YFJRjkZnw46DdYM#P zU`3~Lk^h}|v|NOew(h)Z_Q}d}R1i_hfh5O0VjR=P;0t#Vk0WtN??^cWo%5Y zHQ{CL>B+F8Ltt?{PnP;fJLP%;eVxR;rrFrm0q`$^=BJGMRL|ggbnsju*elPme1t`s5$uprNrKx1jRwm2(b z{J7<#|7&3(!xjGTOiY-2(FV!pe*ZSBR!uixz}?v?T5#FPIhf}JvxYy$<+9Ka*qi$DE)BDSqi|4VIQmBRgS zNe(t}dl>uaF17atTbA+wUz;cqv}ZU`11Jp zxS?UjXKQ{l-~AZ@gNftTNo^gWO9_YE2|U5~V7aefU2RqfTVrx zs6k?-!0Yt1v|2bG%D<_whqq8v<`q`JM@w6~ZnK(=lW4O$pbsBwBGw@|@DEK19-9L& zU{L=jx%eO(I;?Nwxd#oQAAnflR&g6*-WUTQl_xqI3y169aCl1-Y08N}u;k=&VA(|h*Hr;0I`!Fgvg~WS;B8M$Y zj*T1i<%0JDeSRpNot;UhN%TqKoG2`u`nGKkqw*Srr39CXA3w~KK_Vr}hO{&5`8K!^ z^|8FEEqS$-rR{!e;FFQDVVsq3cK>C>7L!f=|&97^*;)K zPT7M(8fU%$zAty&hMwXS8)tCv+1t@tmDbdG8=kWMi&Q1dhq^t=eV1rprj3m^+s$UNtrdtAeg2dv|;>yMtD+z zO6yZDjitq9)Q-0Kx0A01H{4I%rBy%N99%-9Bivk^DD$uOCUOLQH0GJE(9h9z2?jSD zwBEAupagtPM4~$5sm`zHU0n3Anwpg~is1P$(Y5;Y;R6xpq6B@C)hN8K zfvo2^Xt3>GcmVbRc6D{tH{s{Ld7KCU7qxqJI?*K??Z z&I*_4@lk0yLz=pnTB5;g?=+Vtp!i-9-(p;^%i{s&EKsa!@g6)FIENTL5e@ggyU@U?99xJPq}W21apckl?pjM9U~@ZghsV45iVx(=;TQ^k+2`oo7=tFQc*4< zGJ5uGfuEPZv*XfqOL_2_Q3!KxVg4%m!VF?bB0_z2Wmo#MSt7-@_7Ef1N!Xqs$o~D} z{o?tr^IrC#o5mXn$|M<5@hmI5k~Dn0q}p?h&{AjK}59Ggz-m({7`08L%`LLCXYsnUDJ?Cphlm zt_cVH6AQol%}7R@>YHWtGI)%p1Fr-A$mDAj!Zml_3KEPVPlBzAy{ZT@B+e$@5l&Lg zVNNo*yuIP#DSu@B(^<@m%{@IlE4-YuN}5Z2KT=?H6TO=5od%@yT=9GpmW|gJ`$pLT z3qSy1)eOm!PnW7WdRta*Imj>^W?p+XI&ZCxxjye5%JJV!l+P(F3wz#HnNQZ*uPjdU zsYxp7TH8*Rsj+HA{Uq{l%tVqthYjqAGqFz||0K-?yshGPetdaJB|9BW7_V2nt$z|g zU)xax*mr?<`|W#K$B?T#rc960HF%@CZ>lQGSL?pYl49%&%vh$`ZJbRVm3F3C3e__Qu36@MUSMFsFwlVkA&*ujVZ3ux z8j15Fk#G0N06^$yt3H zG$0--tgss1l*Uo3ndzA?>c@vAnpZAB4xj5YDJlC%Cs&@+?uWPnxLC#+Ce&pD|DNAb zafG*Tyh@AI@{~g7tuo(LA~i1)A;4`*UsAcs2BN;f5@~A|_1sKRJYRR~avnQyNDr4^ zK@wx*O#3eK`*2D(e(mpD^fkd5 zVaF%OQFpvk1OxDb<3@KNmg3!aXexQGNwpR|{{{yvRO_2-yA4+0L-xi;=60>F8sx|+ z-eH6{QP_SU?oCM8U*gbAU0=Q><~BaJNil8P@oK~e4yKh3znga!_C8A+-NC9{Odz7^ zzCT7T>7z?<^a*AhMdJH5BIL;&XeP2Fa6f0GM7|Ni* zBd+GNN+@w~jg!jpYA5%{kB%p8jWS7W&j@%~KzQd6{*i=j4*3|AnDZ3y#>R$pIZf4W z&*!P58#a`!t6=&NjJnT2e@L)q3A_7FP6*~4zib0dW2R9$AGyn2A3e6<842sB6RnD5 zDm~p^>U;gAjrdLZoe#@fJ(8*HUO3ONEy6`1IaIz&QG-Z42cl_RqzGKKM5QZa-P zQ4gw@@XV;!x7P&n2?`9a>|Sff8%KR--A~||ZlCmGOJIE|%M?4xj89YhYdiQ+{l7=S0VcTrb z<*{^hLA>ZLQnCQ#uw`V^;jeiA#NyexMnrOK@mLdv5uY8m_G;TbGqIW%V*hg6d~Clo zN3Iy3qC0|5eTl{=9p`djn6mjy71d)>)1(W}j1Cjf1MP)=?BN$u6D$kt!;sIJECFZ~ z78XO~zceNWl6kVa*HQQZAxr-}_XncQqk=rFi@*trkhFK zRpw^Pvaq8R<5njm)S&17Q$h;vwTC1Al8TZ*wwA<^LN*;-bI&$r#XYB1P;>+A+wWb@ zKGofikC1(jn)v$;p;EQ<>^LEa>uerj_im=<%~|^xtZN$j?vUK&9P=FDxx9Oad(P>1 z{Hr#9lN{1HC1>HnHKbMxhB8T~(Pcm-xu)IiINX_Q9A|fawenNKM>@KLTU%$~nxj2~`}B;OvYKxE77SH1 zoc^?rgr+1Z#v&x?lvJuFRJK-c3mMr9kZm9ytoe#T%Bm-Z3qX zExn&i7rFMuB{F0+Vp>j~+ONCAW~c7t%x=BK&X^UCu|Dx4rNaS08J|{f&c)4%&Kqnt znZv}G4G32XRH0-z%&D-qv$9)SA}=sSw#KE8$LYl_oK>+psj<^*j*~Wtq&B`z(37Bj z7yhWOXZe(VS46LxvcR&pcZ?qqxt@6+Ov1{JlQD6Zz3_fND2p0)d@4rx;hxaXyU$@o z=|QCEPl)RlxTg}x3<6_HDyx*b zNUz2_%!rYn`4@i5^udhqb*N$FKP4Az+FQLB;-nbvx=@tguKl2_dAdma?s{R(T;T;Qw1;KtOL{iAD|LeJ Yam4FT->-uFO$AC?QbD3h?6d!W1MJX%VE_OC literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/scatter_chart-dark.png b/testdata/snapshots/darwin/scatter_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..35cea091b9d39e3ec1380d592b6ce7d81a2d6d07 GIT binary patch literal 13704 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/sparkline-light.png b/testdata/snapshots/darwin/sparkline-light.png new file mode 100644 index 0000000000000000000000000000000000000000..e17c6295e8e87aefccd0d809376b3432419f7edb GIT binary patch literal 2901 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 BXW9S& literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/sunburst-dark.png b/testdata/snapshots/darwin/sunburst-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..4c8c9f62c138add7dc21bbb706ff12aa3ba22b45 GIT binary patch literal 27106 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®+0C zLuFnDO6#gFshWb^e)eTbeOj775Sh=Mf^k|MraTZRxCQE zgQEjA70DDUfvCv*8458N`BfOwUCHMJN#9Mcr^+cROXc&h}k9RsnGxY{4@p7qOV^80D zUTk}iV-1iRH?yRPw~P!!Z#IK^Qpr)~s-cZG1svgPdu!X<`&t^lrtHZnau*VE6c_@r zh@LdWN7NsK?oB0aQNho^=U{@VtM;qeY04GAUi{B>-)zocL=00oCzMP~yfvT37Rl4n z+Edxu6LYdnQZ2U?kBY1|_+mu7vy=2!%{H}=>~xY;^_#ha3v@u8jvRy{|Ddy#D#ZMw zDs88|pF}_Rs23u%@X6KS_WAjhu^1OD_7fpiFIEViR-+Fd6Vsp+wylS!n%s-DNe3?< zeNxsmN5uqwftEWGV0me|aLBci-9TgOE7)~U%!%ifCHku}kyI&J^rpt>6HCZH~J)E09`P96+<6S+0XNh=zjI!+rR(E>)XJ0yh8SMT&wg2Flu3=Z;c^PBU{; zW4B5B*#<)m-}^M%SZDG$gvCft#zz^wDvoVvYaaJ!cdf224$VvY<+cBX$J@EtHdr|S zI1<2yEpx0}cEbo)@vf*eshX9Qm;3!z7!IIV@95YVP|>mQW8_75;+|8n`YG{uaxxZoR9&#P%y&f;CjO+y(Q$rw~uYgV7S zN0h-g>YSlVW&3c zv9f?V?3knH2U$AM?K(T7JLd1P^?$sL`h+< zl0&t+lS4K^nVcy#oe4-E#-b&PQ@-@_QU545X<(;t6?ECX6f9xZQ@($hphh(~L!qi_ zDs!_LZIZAi2;}WEkUzWP{kyb!Mlv%03A1!E*C*^J#U>U`;iOFn{j%%VL6vsFh)^f5p>oH_dGQXT?Fdr>Tw?G zu^v!n`%Wg?0ttWw%8;Cvqp$9PTT?q_L>PO{>q2I}4MO(|)BB75sfz*Mvo+gVg%BuD zL7l>`w*EChio$?mhVG5Oe*n2a+@AJms+Os~dVvOs&G`AYM}7`}UcZ%5I~#LHGU9MN zT{mkFJ`2@+*~wWc({05Iz5Cs%I1%SUsOWe=c^glGaIT7()Bsue>$ggH8wX%z#Ol{~ zc*(JH2DWD>1l*+2^ICngMox1j?NMQ~&AJQ^jtAb_uHp{6N&IZ-h`idi0Y+_#&AtUp zgjzh__4>S}f*N@hefgj+BrxAPf^ud*;p?=Vop!Loy@?jBeE{-@AwLXxl6DBuC~w;? zEb=mFEeJ08Alm*)Ez@0i{`^+AH8F8}zT9H;+Nw^+k-SW;hUo}P^Kvy(q;vfIHs>%` z-^`%n^aAR`mbOKlmVko;#tjFpw0a(%x7rWH)K;Zkjq-bzOpricW_R7L8kwNPAYTQa#_n z!Q^DOn5juGB64DLGXAP;hgTYfi?zPk3n_vErR(b$iQy&lsL0MOAFCSI!%f;9 z5j0zpMqEuKM?c23IF7&bR|-f=u%&=w zkM6_sG6cOtEaNjHK^c3%)r#<*_8>!isi58F4eFpx*l@Wkq+XRl;FQ)+CmN*SZ)(8h zY^y#I-9S3UsG6B305LB6k$i>xjXp^}gxt?YA<|u3sPE*FNCzWAuB1$7KRCjR(%-En zhM7CFibJNNzbR-+HZt+p*@fRo70T7jAqUY=Ak-!)(qhI!?LBAgr6^vm6~O8>P_b*# zQq=N+kKYYMrYDzAJ1#%zEr9LmU_kUi>iRCbUU6X;u~pc43EV1GT_xYGGVzh~`hRu* zdDJ->Notu^1?@h0Zodr<(PLD^g>!;BjX0C_V#NWRH|Xv@XEu%p;{CB-ILQ!gHd3v` zKouj>Qsr}%)-|3?SBQ>c4d#J{*t8Wg5DDlHeEuBk5PxBxSb3wc=#u*88o|Hb^FDd< zQy&=*ah>+@U6R=Ha+6V2M`s>0;_rq+q`yBD%|7}1_{^&8Jj9)Xo4ZzWn)y-H-s0~I uI`L@%4KG_YtR4~>EWJPS|6UEnRveiI~u>S$r(6eFy literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/sunburst-light.png b/testdata/snapshots/darwin/sunburst-light.png new file mode 100644 index 0000000000000000000000000000000000000000..297c87154c230bb56ce7a15a51477b56164abe54 GIT binary patch literal 26863 zcmeFYWmjBV6E)gcaCf(c-~@Mfcemg!!5xA_aCd@hLL{{GBhk-7i?V9_Wg zDx~V3d9rLPtD=De{d;I-9xJW8hzgUHPL%9JmfiONjDqh}ox!GKt7H>$V#S6NoGGPa zc^P?jUyxpYF^i^rij*frf-)bY683QUjPXSglt=?^D+EHNr|*!_iB4}pW*>z)c@rS! zyyIHEs_9zYC&*nYp@0-Zfjm5RumO(+pb3IY0$@qNfc}vGUwiO^R*<}xJg);f89CL= zGE|8E(oti1-ihF1NkPjSEu6dD#+VNpABOuMJn`tj4tWC&ouMmU+UAt$+OleDmcF7N z6{RixR;;#g~^?@Cos5eoZ+YVE=v9r8$AK-gOULY-D+PPNrE|$Xh$LoGmA3dQO&>m^xn~ zGZP+01Dupg4Sf0<2zh2ON68w6EqP|-P6_oz3}_e_-b~i^Zf{paRZEoZU&%lho+|Zp zc{NIJ4@I^V6qx8ABNqA^p2_DDKhl$qR&d*v^!l?9+j1iA&@fiKd}UpUkn?^tbd zYN|MS9**l=TU#TG8y*^JD=E2teUWdJk3-$;?CcAt`Xb-1NY(Cn!>yAG1;2MKyGMaC zHD?|5{(3|_kRZuojrDoi9R9Rx5jYxpOAQqtRtIeq>tJej+Do`(Zl}s)FGhvWahCVylPGK!a1H7Z+_J)*&Q_rQoYW$hAqq zt8$l;@5y1><mT)awTg++=d zq%LfG@N*PH6sOOBMp6dD?>$X zIosnK-J&4Y>(rh6vN}{s`yG`vK>Q~R-c7Ff3x2`=ikZ7!Bj=e;lkaK{1i%WuH}n7NH+Z(O7B^6k;4R%hE20fu@`jCrOmInoDi}Q& z15W%vnOZt(;>0(K86J_wn_ZWlBsC!Y;g#T(tINZw70k zhT*e{3Eq#Wr?J3bRo%h*{!AICN ziHo;bp(Ru8<8e$nKF}rc$4T|%*toK z(r|=n@*sCR#T_o3pMhW<)x`EQWDl#swTP8x*_lDtbewJH;My#Ic zO389TYHx0Yqvf^VTe&aT$PD*yv(ie^EQ?P%d0<6AkyZ=Z{f-X z)oSYgn$`Ks`hp9na598(D_Es@y7v25o_FXCs?yv1$F^*gvJ)s+;erowzi#96^Dj1c zdH2}Qn=p)V$VXv9@qY>%QmC}Y__ubc+lAmNcIMI3FRoqf8R_{~6=~lN8q6yhCckeC z(H!Fmn?cGZo6f8dtJ>11*Uf2y2Qbd78h?UGHtPoO}l|N3C4^JP(;7ubji{U;lMRDMhWmFMvJ#^Xrk zG~P^14#Q)o=8AUUOmTGapo%C#%q7sWdo0+>;vrJ>y)bF0m=9xu`pYyu z7|9?rt*p3|os?UfwwsYCK8P2qNt~i3O9@UoLAd9A7q>qoGi7Y2{>EI+hL*18^*>Hr zfy1(-!>C(Vw=5I6pDu}fw3@xOH}&+M4mjbxQOHj)E6zgM1voa45;$JgiJVvZ{V=vQ zZ1|8xN-3&g`=2^SaY&|;ara@QPhk+!_*{chc%D2By3WJ#t8{a3^DRVnbnrPaC&s#5 zU$bun|k3{zJUE(h2q3OQ>LtWe-zLCnGT-O z2r(%PikkUl)mR>l4k-E`X@N|YmUgSROP!&O?cd+sX|J7TcB=#t3B)r>p@3XyN{>0vWx_e zu!YjZs%J)_`FFqF-omfgncWiNIA@w3Dt6jMF?Yljpminn3g5WRuy_+|HxtU@GQ>@+p_-7jyVvbU=<{f4 zDU@c?uXm+&MJ`8LxI99)89V$@E66DdwP`m>wx_o(~GvbW!ITzUcx^ zxAe5?&KQ>4qz8A>^7pu%xW4_7z1s6OBWF7Ms*$_LxHI(rLBw^5sbu8agComgAlh z%N%|%mCP9@hrJ*9;nv=B7kiQ)$7_UD-TId|gaZmafhf-=^wj&Q|1@M^5R)0}Xu;IJ z%N&pNH;GQ_PgZU>yWg1Oi!gU4%Gnp5n(H`_UG7|=DV$t97P}D?9d*4OZJwRnY*p=r z5ah5kXv_)<*6zw(+DQnwmFjl4?*`6KknJq-^%qdqhc-rPpVvb^I#%g;4iGQYYD1jg z^{%^B->vnZ`TS|G=&)#m82M3xsh+-fZ?bYjb9<=MC)MwIJWtm`Lr#6u5%@H>$KrI0 ztfF8aQ$BX(ICWd)_j(!d%c1S;ZBjsGYpW`g@BMscY#hl;3ncXtx#@g&=j!!D*03z) zl>UIDk4Q{>?FC)cy6+Y_*!=`;qJ@`r7t94r6$$vWz~yok_=|r~5}!O-b+n60L{Xru;m8%$&;OGkMevCTN{W=8Oz5Q&gL8Hpkdo8C}e5hT&T_&xFTa|kNrR5MA zpMBMNB`$<}W+aXjftN_efYF7 zYJ;fL^TL2|wRBK-+lMaMSe*Pc6kpA7oenp9&eq?Luv7~fF*P^qw&CFJ-v+%uWHk6{ zvwsF%-Sv5+{rDL5=KW{BdsnbgnvibEwIWc4eVePCr_rcphBH`rzLLuAS2ny=IzbOz>Pw9~;&|%^j!+O3k%giR2w$H**u=%u|Q)a39m+ zarPb#Dda-A(X5)IxSKHH>Oru1&dfKw(6>6bJwqk+Q(}QhX85|AvC3MiKzJ(Z=C8pp zxmEu7lnkk==`y$JP!V0M4WHOj97-j9NX4W{1ksmNQN+YB#Nyac#awabmvZ*q5c@>z zE#SCWetBh`Z^opZb0LqLF0c_#_-yR+qe!Ai+Ed1&1Wo(`K(4*4Ts%*x{#+PaKt!Q5 zq+%bR@+hfkY55vg7>>J)+hSGbp=zL3WNwp&+E!KCm{-~;On0)h?egU}Ecr}aTc-J4 zv#H)>Z~we4*}~$_{t5Ag)gW^t$%}A7MO8(u1dsca^j_wzCGIZYq=Ch_^NX*hXwH~=Eql?e1y=`06bm)6oNNZ;AbI#<@ zoZD?UjQ)Mk3H6zPZMN23fu@?^<9QF$Y)-RHCFsedqo+ukImtwqu{BjsLs_2wP(eoV1-NZ&hlz*ScTKa4c-6p5b*K#@9 z1#==a^O77mWj+Lqy9<&0Yd5%(qeSaXGQ=lQ;qF2Y$*pPqMxWLQKYDVtU256@1g*~I zsy7toS=kh?{LmxvG?1Ph?;KBvheW6p=mn36c*z3`-r?$4~{~P;$DIN z=?nEJkQb}^^dy=?T8ZvS(LREKQ zfCLC^SzZ3gDf^K8jmXTB{^x#HOFz}!IAB`m-NA{TQ0pG0ks-X$u)!q&WA+#}+duH* zuUQ{(Btwe}fMUHdij@8<2+#3E(8HxLC1K3yPAlx0j= zGM-DrrxMQ!dm}OP+MG0{s!DszXso=bVQ)sY& zPnydBl0T*MPx*X`wLriE{8H>KeGh4Lh9IFR(lHVNNpJ5^CUz&~jq9NOv12wvqjV(Y zSbS3tQb>;elv*Tzl=E4pWV<3Ls!d9me|_UAa04lQ>8ey}ytJWlQ(05=?oIkHb2!i> zapW~tMYDY_j$T$07dR;CJ=7>K7BlDgUx~fCiX&g;-grN8eJtP4OQEKa5MpG>VDfPn zpKC?WsrBkzjsJlU6neH^=_&>xn;c$xRwy+^OjqpP!l*)j>1uBSc#z z?fJ8G!14eoWuV2T0=se&yR4XX(-b_L7@vSxfi14LWbdB_@SpTuY&hz^)hLR)EEfM+ zGSV7?Ejc@lgy?TEoIeBmt&Rvm)`v&Uk~bU`Q^qI>wV{pyEz@zee1`Q zCpz;C+ZzHcF#BhX@`q}R%Fto-JX%bsx3jS*2JJiYRLNJzAQY+4XP z*_tNe&>nbv%;rYI5BGmM>qF6pdPht#wzpQ=0T&h~=p7VS@p@U447zXL8MEOQ1`& z=8&bo;MG0#e*9YnV9-E3J*7L$v~)r6%iVH=7%B1AM+2w|N=fF&-WI(niBgKP1<)2a zLOw2XO@1U;alWs$vT%$=2EyeFyX1-qifOqVFwNrtGQv={k-_vYK@fo?xl|!W_btb1 zVli{>UxhgmZhZ*~`ZjH&IO`eNDBIjL9^in9_@7Hol1*pzP)!U!iY(^Y!gD_XFm6nO*EQN}gM(u#UtNX-DQMN) zH7AMJwCjRXLx4Z7fp0Gh^LHB;>MvLNU%a5@7yfOC0fKm%g1w*cLS~E@iyOZM(L5DS z;(O|z#){Fx#4q}8N$#!bj;dGT>FCgfbcl7}H;;x(KfByuWeR09Y_l|WdTv|B-$t(< z)ZxfW)c77e!u{=hF@ky4Uj~$=wC&hUOT->|v#J|N-~ED6LnqA46&sh;t_w1Y?R)nQ zRR+7&rh?01@!gydZm@{gMyBVAP8O2V_zZ?tQ#}_71FmpwU7|Rnmij{fq9!8X{z2EqaRPI6KB)G5AMu%0x#@DUV1FPB8qkhk3pdc}$cupV zl;2D~nzK8#F}eCky-GKsn4<+mD2{YGG6@GAK@(nphYQZ z8K5V-gSyJ`~;gceSj)2CtDY0E4T70Jj|QKu`QxkQB& zbIL<|TlDbSd;7D=#lT6;RePij zh``JX$(6umTl6_Fam@Q}gq>mAlXpeL&uqgAR2mwE|9LxP!G0C+PMd3O!CnWk{O>`u z*f0%iaeYQsKFnTBLTLOM3niu4BKCu80^ckV=tWfUN8KSrhr?d%UV~)MIyXgHlgY~1 zP1;{d(#~a{P6Cx!)=S&31ZmJ%JP3s4CB?Qfrp(D8*k_aYTU{Pk!@IxNR;+HxEO4i% zyZngEd0QzJLK9s-AHk6qVIl}Q`8%$dZc`I$HkWbbXd#U`cl$>OOub>E^K%hnCW=e;|7r6yNo?Xp zc~CjFiK7eV!g$V+CC6gfFD0$5Irzi{fmStTL6pmjGZ_Tg3Rw^VUC14RiO+-Jmtbq# zi$0+~dSd-CTF#s)Z50Dgu297l0eMCV{nZC0mW{^r0!|4R!;PAVRj=7dBUW|Z7u!>H zJ*R|CJM^I+7ZucW_lI2)pjZ6-Trz^}dz9YshcwohgDc4$)lv+W@!OvCr({%kfySP@2nbocMa zECPuXn*W3m5+sTvZpaK`1*XP>mOPFzm(bMGSD+N6P$kjJsjIBA$OHNjmmICtK+*Wa zNW`|$q%Jeh_Lu?=f%@Ji`W#f@=f+T78j(+`4>dzSZV%Q!x*!iduv~|v7M{X3-MMn$ za`Bq(qw*-EQN5v8Uj#o`tTqmZ8oz_W0e&0&eO#kp1rfRA36MmtXCgQX$MaiflUf2lPhn2L77x- z@lU^(ZChk-Z_^8%Zf&f5wO7;^B%Sw8B?Cx!3~)4&+3Se{NW$L7nm7pN`rhW2q8th zgs4260IJcj%dPmUt$13;t5Od{OUwT3cQkRK$>C=_?W_*zie$--8P3HO6N?5Condx?;`FgMq>Hp8UXm#1$#7eL5|KR z;$xfTg)Bq0{m`pO$E^8fec0>jDCiWLTm=p3qd4s(e#hyjSL2*uA%QdMDi6G0n=A`+ zBB6cszRI01Da1rB+zH~*g`1py)w_{Vv{1G_D;;V0I0L>e{+`gHgyS7c2sipv;`vi) zqkHyHBWc)o#0w?_F%yPR`#=DocfV3u!VF$0R!kt2xq%BUu9bbf`UF4Or?1vt^Y*2w z);au)|s-2OBAvArEwmZaAEC5t?wleQyb+Zf{ggH4zMKs3RA9A%idh1+N<4 z+GX4vv21h<^si>;dmWP|drtz|eVF0~TR$A{(SZRh>ROC#?h)w&?DKk8f(U0t7*nva z;u@by;>CeNVapjowozq;ab(VvDG|Y-JXbK%l<42idRfk^cPk|6$sx-GlFQtcVuN6S z6J9+kg(NbmOCc+)kQo$=|MPpzv@8;=QZl%Np5ir}FbakWP*(Mpu-~*M#p6-hw6-sN zia%i$02uu?qIWt3<$mwX02YcSzxGmRu~(FIN*2ej;gz^s&BU(P@Zmj7M&HLu1+b1_ zJC^zT$L*{k3(?bnh46_RaiCOKFbF1qd5QaW{p|htk`ublQy$LToA{I5*qe8d{+glF zU5*Arsc}@*o78L7tL{LyvN=EPk|g$Dn}q@Tf4A^(*{w^0vMEykzOXu#+?T$x5^t|B zHQr%mXYo7`uuGvp6jifH3pV(D>Wz=Fd)>-i&R9fO{V1x}8fWP5|eeEu5)tAXx!=Mr|)d63W1A-2hbx-`^Isi~p9UMERe;YLVK?<$6Q5+$Es-fA*)jkvBz|FZwyG8Vr z!fIax`QZ#9y=6DyeOgN_W^R~g57S;bNMF9{xe#FgHGy|l@zhx-4hZ;;*`OBPC(en4 zzxml#M$SK}4l9zt>Pko4@yl*LKp{sdx$l5eE~nVo(&+WL5NLWN8B-4G+Y~PXx`qY6 zpL>}Xl-t{yF%6k|4rXQMOV#wrLgOFe*1Oi{v}MBrsJtFiNk-BpRKNhin0`c3k)3*% zf;Hx4&_Bn_P;*q#xTyk3?y{nrQ{8;*Wg$b1 z$U_z#QX~49l+#Yu`{D~S=@7*32AtQV^=D>dGZPwS`*^zh%u|BNRviSKsM%_Ey_7(j2&-hCxl}Q)Z~tB8a9HcCedTpKIH)y6Zp89_xY3Osy4kQ z$~B^^NV7}0x2Ay@@H!M*uG!(6=32#3_v(`dg{`PX+&M~gZ?!FoJ&bUifrFXRm-Q)J7LCU!gzE2`>1hej0{ej9(xmiWM z`80(XCV(@+XT>lQkkQx$K$yIxdw9nXrAJPxf198mn3UFpqLR+s8bisGm`EJ}@Oyh{!!e>YeP(!v z8D0eaXo}%Nli))XL$b65PG#RFTO&+?<5JIkNmyc#DN!f7IA?wR8;Cevk?xV^(&3=g z!B`JM$jkc9#>M!hmk@tZmOfmTrV!~Tfpl12Hbl>+7mo_tjz(N)5~Hga@!HjKjb${t zE1ki|l(B*>*QAB1j)~YYU>*`!LSfzSP{PeCb+t9d!#U%sf{NcNL_)O1-u0ihKksZ% zs^$vR*>g?gd?hJq9TWM^TJdInF8e*Nb(+_ALzzbvj4XnrHX;nhNOg8TtQj&+zCMA) zEV5?C@(FkgY-CCpkY_e#ovwa~jMXt_B;6AXY_P4{1aOL1~M_L_wks@Qlsd%M*yH_cn2smVLH9&QWsO@eDU!lDK@cGjcv@ZGUo)e!BHka~=E<@Uc-Aj~JVU5>42> zr4i5X^bSq5=KU|#Z)yO4q^9z3;vEQ{b3R~zu<$U|y9-f;r|P`8b1!v_CJq7HwPHW@ zwn-?-V%O6T09kF;rj(p8JO;f&m8XN*P9fRTe8D_Hyic(hCC-eT!HQo2H0%A13;bTi zeW#wcuPzy9PacIgj~c~Y>O;y@snBq$+L_T|vDJQ_4nCg3mu(Wa>PuFW-a6`*prvZZ z@n$8|JmAaFdd%+*SX#Qp%PDv&8%MXsUSj)rvA2MTlQYqpJqVsA{64xxIek+DA_zdF ze5yZTzp9?9jej2U z1^o1hnD)w0!g5@+jR=yx{bPk`+hRyiy$~F3BpKhl&;z8zwGUqDD2OlYw88Zyz2% zD-boCkbA~D?fy*}69z(*9MIjF^6FFY6Xt~qL+X+eYRBf0;ucjsqhadQMqym9`*;M| zt0CE7%i@wl?v?2CCC7_PZWjZ@y^CS{A{7WIkjp^tOE!wMamVC}GXF!$GPlPJCJ9xD zoOppREB;_a`>C#?LEzXizQNjjBG(YNj@k1el)-w5;`*WY0z>j&0|P@Fa|{6LS9Ast z_9rIAR|@W~ZT0Re>xAUviC8 zCAz4(iQ?lSa~tNdcxVH6Vf-+tm>(%NIpxmb|HfwG-|wh#RJpCupNK&S54eBMFz$F3 zO+-U~`xT!<6Tut6e%zX|{F4gkX=Cw&^Mt%K0^(x>rN~x$+M@%Z%M-kG zy*8r-?d;zb3{VKcyj_*A`4|wTgY@eOLM6!6&X5wJUXNdRY61)3Hr5~jlH+58NJds= zqHV4SV}FxF{eV^_*1>6wcU%*gdX}1cWP7qU{nQ(4d%JTzFtab2XO1)9{b*k@4NpTi z37uzF(lK@R#T7EoXxJB|?i1aE^fww|LFJY1S=Qy@#;>r`YviNb$p5g?Q4Y} zq;P4IZ-2)t9`1*N0n+a1`;d&7L$o!Mi{I=2kC7n&Lw4;5P#Uue&?j$Yn&&9}5;ia{p6Px{p||9Nb?L+>vrB9Lf()pUIy$j(1Y>&9~j zW>(C0f5WxeoO+1A;+;&vNP6zVCc639koL1(LPNmiv8x&xckGH*-`DI`D2zElA#P@PK@U2a}$sRgTCzGYXQWdk&V!lS?TG2drJiHwA~6V+KH z2?w{&L*1&%sE_=t@25sDWmWP%Pv{%;FRvQ~PuY<)LR`mydEx)1ycxum5*?sUj zYYgHcIjW|L=?#W2_+IyD;;%i=MC|r|sjOs_TN#;~{^kblkZOVE3?&pkt@lWhbB@LR zD@D`4BVxTF;LBhV$a{H|8{3bVT~TJXX^9R-5eP~e8tc^!$|q8@fA?HomY9#+r@6{(u}S9JeRJ9xr;f3 zMEorx8cpnCx~Zg3N5*MvZnQjHD*V3kReF2^2XjS&%IU7_*?8HJn1sAo*4x>>XRq!_ z{mrzEf*Bm}$!)DHr|apckND-Vr50lFC;v2=CgbK{A%!tCZUcwMR}6ocRPgY3JG_O8 zZ#~{RIl-CMv-`PN?EvU*VpCfb5$=$O+2*Uap7|5G8j;P*;N|WepC!y+l^Ba^N~pOj&BPu^whIbCht9<$dWsq1P@;&* zXVFK;Ef{D0EyCzn@XHf4G!x3~7HEKGw#!F-B+bHs!Yk~Fp{nkJM5zEO-A-pNO7;)7 zqft@rhYu+@AySjFlj#||FKDs6Tn|${>0-e+_!uJQi z)sQQXz^5Dpia(m0k9+^h9voBS!Y6Jt=%_4eb+LSY z->fNzeD3plryb~fxOZb<`;Y>B_ou2=zHx+s7YU^hRL{qyO#gIRhHv}0^_f3uc z(pGI|EB<$U0ZmyIP-5WP@v*cx+YgR0&ayro^wx?A0xZ5Ry8;C5d>J5c^tYeduEuUG z`ZgZV>Kc(MviMige+^C&0iX=Hoi`D4g%>6i8ke04RDIN%&lCX4Dx1T|8c7ju2GSYX!argt#wD6laN4j*rKD@rAA=+b>%TzwyJEB>-fj969tiN~2L#s;DZy}riigJ3kR+4*NR85;zW;=d zfo7u4WIT(%*jd|PA{J*Vri`JK$irvU(NWh?M`3J)fzTbkP>mW`CMP9h4a_kL%?7&r zE@tiht7K6&Btj)K_wc|F!$@wQ*dB{%{6IwUgdQA|PmqUm!A!%S5!h1$I;`_Kc$YhN zkvr_B2w50qZx{&?1y}%1-Cjju{cZ^ zACW7PAjPjJ%m{V+J04y-=El}-<7X$(EUy`J>sSKOveG&^Xpl9PmHaeTCsAxtFS=xA zD86-9+eAcYMw*S|^FaovYM;@l|7DGx3Q0``C7q_m?|!V40|*v`h)@^ z?-B#K)oezR4Q9j*g@Gwd`eh*RiYlCP^eTMkc;s$|8B6e(Cwd zzFu4IEd>TnPTB+~N?zt9dQmgmi7WFSlPTN|x$keMh=Yh9I-Na=tOY&><8~nmi}lrD zCFC}&1^YnGZi%{WyMxGL+vx$nk_hcH`SqTc%U6_@P2FX#|$>s(iiE>7xI0b zM*sMFdwABNQK{PT)^nDZ7yta+X6G6Hy)^%!Rr@uzmWnaf2AkH)04E*cNL3d`YCX|z zX^Nhw)zmG+ehF$=u>h*4+2Imo%Fpw~ZZ}H>H-zHJJ=;q|-q7%3-j-)}=;}!Wr0KAq znW0Z+N)v_D@l5$X*^4UE1^pCiRT0s&!H9~r2-@)r`lE5z#^A7g$79O60Ol=ze(l=J ziBh~QDTf5!62C7i(Sf1Sw(idwBO~FarkM7a?R{6z2^qd?ZxqVPcgL03DTdHY0~5mJ zbEeZ*vAvX{F5^*!|IP1sdxGEuL-d*QzBI}Wh;oJ7?(tG~wzdbJBqB zRW26X5TEj2r$fX~Nh_zXxiX^Yr>XPYI;Sn)?su!PN2^rr4#{?PW?o}DSdgm@b)Vkq zvKtoGdA!bLnWcm!$r6AiIAlyg(881)=UlDwg323FHjibCPITcVV6Q?qzk-rwT_$RJeB?;+(oDT7KTe<3&p$7C?b$PO>ck?K;bv&G2UZi? zGKJDtj%nq%1?pTFnM@MiH`Jdb-Jy^Q1wo>siAqX~NmeYCd~t|`xqjv13w6Id(6rhM z`bvn~FmIFi5q)=e7ZnSu-DqIpLkB+<=Wpf5-J9dLrB)Ys35me`{7o&Louvj$+tX4{ zlZ(NR99A7PaorgNr0UXGoFNxNf!O2INPBjfl;&A@>` zL)Cd`Yz)HqnM|i41r+o$oPr-lT5OYbp_w0!b6FyUP7F7uy9;wX*-`z>2n(;ymI8v4 z33n~QX10HIXGkc*mDcAiQC(lxR}h|d+0{H)Oa)khX-FFuXv)xoc;7W38GdT}ujmWbw{Q#orc;EJ1K1+?? zw4W(Qo}FnWVB|lWzZvm^4-Z9HKNn2V2%5r`QQrvq-P0UAiIkrxKWPzHR1I2Hm(_w) zP^`AKqS4Q?-n?17(yHkZmkl%t`O;adWo}B5*fwlb_0m;{=YD~65|4k9xGsi@AC}qB zokEQ;IgK>C-L872pg42ByrWW9Mf!jp^fS4@GI^9{Yos)_#-2O~iBVSuVQFW6HpNU8 zd=eGHAM&4cP9P;K3L~(C&TIq1N$ccwhZ(4-hf*8!`?GEYl9-b;bl)DpFHF?Sn>^EL z%N;Q}1>w$?d+^-|b5eE- zry0tHNpf9G%D1Y829;9qj{@vuXsyEGgo%r4<^4$Sag<32ZfVt}E6K^8h$5s7T=dSW zJ=ugxU8;W_V}LV04#!^R^2kQ3uLkv-=8yy>9z=#(rn9AUVpaC{CM{xjp#Aw`<`_v} z1Fpwcs#GAEb~L0s=3=>YP=vL!WI9aI#0)|5+}zq3pC0wsZH>n0BRhnj&-Ye;a6iD; zm?UUekZga)bjSJ&2%01e>9-a%(pk#-8nP<+vTk$xScb36coJ|k{gsTpnuT*x8b!C> z&DHluh(=>oNKz1Lc;f>;Z||hJ{1$;C7Wcl5`5$zipwK4MJ+g@(#W9#LrsC>w^Reyn zEw#&?2AhdoCf^-RagjzW$8x?l1rCLQ!aQZ4{9tlzpnA!J6cgCvlzj*zg#wr)8QDL; z{=q0lFh07+L&n)X0SQ$uJU5JCA46XMwF88bIdzb|>Wlkr>VTEIxGa8p-0$I+x+i4~ zrqb2@1WfLu@3nE^2CvBO!&>@vy3i6o%O)Su_;ojQ5rENjR`p` z)5apBlsMR=`tEmhsJu*po`ewj_6R%18I%S3{@ z;b3EJs_%4b{f)|bX`Y8HbzigjD6tmnby0v=$(~_#X-Yd5-p5DDq$jMBMjbA`(eM-o*Q!+FXohD;vNo}4@ zp*}uVMLOeX&o6D~Dx;qtGw5yB*bc659M-u64quV;ESQtSYj4YoK7m{uJRS5KXnaki z?D&^db+teC&F&EH2D`b+r+@qn_pDBBb?^w)`a!{BG;)a&i6YNXkw}7r{I8vwa2%4cK_A)`>n<%g;UG?#(TjxB{F!VK_5V= zA}q3(kG2s%VRC;i7!&ZVK@#C@0!}5;RBs2NsPd;a7B>Q|@ zbjdw#Ivb4C*)(!U<*(4uJvNIJA0o*jfx!so{1(2ygbkZPRT@W|uWU)w;hW)maGyJ= zu91|8mVbt^&NCs*;Nkt3&U@7IMXIk8#q@S8dij9s1fK8JnGa#DJ~&=57ZVktL;PlhwcjlynwoWF z1780_l#yPz*7pz|OQle|oS0~1FDEp6UFEx9aTu(vtj6uamatFvuFledPOulm}E=v(_9#j9I~ zWkr^Q$qFUR@X_4Pq_hUbN;xfwPCGW@6Q^j&+g+~*rzG|R<%>CWA(a_bQ^(PC>x%k{ z1RT`VRu00FO-KSibhI2r8ZAmaCK+&4u*YRJ04S@Y0ykn84*e_Rwt7BYH z{k~M`gRJzyuq)++ycp=5t2rOW>`I+ciS z-4qW!uUnrEdp(HCu(68^L>j_4x*LinO ztvtuY75AOrMQJXM(DC_S7}wU1rj0bc6Wi*1&#{fkAUaTm$vqp^UYCaRX@?kdc)QEL zl6!!eCdIoVlFs_>0E}j{biMHhqX{EXr1iU^2qrE{d3+bSJoF9s8mc+CqgHDR3^iFU zf8)^<=s-v16Ya@$w}&51WB}ep`2;~Sk7~Kqf07VACdZWz#@K4&;6BVhL`CDg&GoqQ z)H60g|9I1g^UCY&u>KfR{OXcWV0WECD$MeAJ%g!K<8t072kl^+-Q1bi1JN|er>^;4 z-&D{hOC3R)*dCLp&L^q+%1c1oq_V{OdfSKb{Pq>sfU;^sygbbpzNqu!;z?7j&l^@u zDQg}7!)d^GJ;m{5sDDNp>!=LQ`v&IMc=7@FDk_RBP`7R5(|yK1Y6}RxO2Vn zF5_Bm zEd@6BmA^(+l!NoAiio*8x2v4&3W}a2nxr4i!u>+iS4EM+l3MHPuu4q*wL|dcnE`(W zLP+4@a|oML1y`wC8}fQM`MQWt=dR>nR9>1CAFm#wf(;*y0OLX=zSwZtM&M@%DHJOXDXt}@xVw9TLyNmZi@QT9!M$j3 z*HEmu7m5_kP2021y8qyw4>wus{gCYSX7AZE&pb2p&d#wa9|RHw`04i}esK4DGC4b3 z7U;$h0^8$a^(X|Q~#++E~U^jtc)wDoj8VgzgZ3s*{tJB5JR z_~3$S*O{cfSwI4|N2e%*bz9wnc9KT3Pr*QdYOV}mZ1O#cVjhHb#^fpZ^9nE$J)baJ9NTc_&ptl zfy)C1@l*xlHW7c2S(CmBQ zYE}Ktvs6NoUkL-uGzklxw^?NtOU)$=)T}Q?OkisMy(c~(rA8XSoJujFD&~0>4~xYa zjg(r8_-Dfe_w@PGeszs_=QH)0wpSe`VPB~zm(bEs^xo&v`gm_iPs??aCmYjJ&M5@_ z&*h9YgI1I^B9AosqXu_6Zq|awYArMC4YclA^vRm}dQ`*X*)uBTRs{As_e$kiG)_}0 zbW_~0qFj==JMv{)x^3}g2*0(r_@))N=IJ;azzbvMizfabcYkRqw;&oft<|qSTD_%) zeF&bt8_Aiv?IbcN^N@Ufz6kl$Ck8OpzMdXY5kDY*k#MrUOTG2wZITQicTkuCY4DZN zeEs4E`BH-Zrg#Eb?Y^a^oass3ak*vjF-RK9#Ry=QRMx_21SdTT0KNa}aA>>K+&Vco zr(vrr47EU@>Mqcjsgq%);wf{Xx|mFBeMG88Y~{29Mzun(#4jwl(3Ep>a-$MTeUmFTEkjr5q%+ka8>u){P#(4`w?@yPcu{kEj zG9lj7Et|lNF_!O0fdCpCg`tk`_g~UezAbxApE#pSN^qb}ziRxNl6y1m;K>Hy-7#UO zObWt1eb;_9oN#J0b#3qcU5(}P7vx}=A#0oHu}k}nYP?m8s2XowlU?@k;?Vc;+bcH5 z>Fg?E$M2l_eK_{8kLJxeDGzO4=xGf-pd$2;qaS=jSl;z|7NLSKHR*9quKF?t2XCkS zG-C>3EU2qXof}L1w4vC!rbq;0S2esCNfU-A(E9o_?G`XcyC`*Yv`GTS<3+DERqawEnnC5qV43 zNfcV&cGnjmyOhbh$C8lu*smctK_M50%et?ptNkbXjn<+O{B=mtt+ObXr5m4kJCjY7 zZ5_7Pej4=d$NXGFo&@i0?W8~jLa$x`2(?p|zrxzjLaz0n7~nPPrlwQJ-!K!ve~O@5 zMg@WWw34{kE^={i_EO*MF?gS6rlxqxTV1gQdv3lj552mG}v_>rm?Egcr&?U%7<1(U4_@7wT zjDw}Y71x;@LuGq=hRe<+We#E0J->P;BGSIUAhHS$sJTdwo!BlKyW8|?QrOj!@Vi(g zhzj{8d=d$0a$hIwspc=&uKg(CK%ivvLH=ns6x{s*uaCl{@)^gIv-g~GJUwtJIp)3F z%@8pv%8EA$W*QNrlam%@uh|d|%$LDT+enMV`*s|vwJn{gBPPSWu~p`fs_CVi3+jw*hJnCE32 zR>3BFZ?1O9H5MGh`qG+*HZ4^S1;?ZFvSc&4I+=i9^9{6`b5li1w{hFPHhxZxWk1&p zO(#zu62GlzF5#6RivM+cjexydpDc3X*M+Ff8Od>gNfsSEr{-#0l>Ixy+ zQGxGGn{8*Av1NGF^Z+^uVI9+HP2%LiF5rC^k#lL&wD*pFV6Vd5I~`M9 z-Qv2H=S%GV$(mX@j_Ok1CZh_P_c?^@<)q@WYi?tS6iOJty>&d>f1vhvc=l}5Sci&^ zh-x|oHEC&mEp$31v)OVfFi8L8Ne!b}u{`nU39R6=rcFg@4N{p`pEr0f50LfJ_cA{T z>p7>Fy{+ZDp>Tbq*k!NUcK(Gp!S(zZlZI)}LWKl<&cy1(pZvii8f*!|Ui#6HjE)ic zh?ICB@sBD19+@J3PbA*h;f&(+vUMhf@Rq_GUGvJf7b#@am2neH<(xNOY<){GI6o`h z2Y3cPE2{Y7UD{?64SWMps|Af}W9@~elI!lN_z7?`jTlmDKz6JymEQY9v~B|`B7CvN ze4z78K(6D$=pRggm9MK?&E*#h;vX}kLEHwLAL-wRDu5spiJvx#i0@UE<(n#p7K{q` z$YB0z{lDgCG0Y)vHMTEcLVq3DGKOmg)}cCAE#Z{`epq z{uvHBgy>&gZuO<4G?!DJD|aQmH+JP*(Q~guS-+pL21xQEd1@Q|wQ*K$?1?S1n)`B& zoC_rW%>UiV$+k#e@dbrk{}})9SS>_5ru|BFmhLvTizz1i<`#KE%98?RJ`JHemPB2n ztG{wX3+$sPj}lnal|s$od&M_yxek}(uUO>ODo7vTP(4pY?$sbY%p&XZ6XBmt9n|p> zfGqF4xGlClW+zUZ1;>a9pAEdS$RQZFlC$~?z^k-Rhu^rQI% z&NgIk{ru>qu=9+>I;r)xy`c9OJ{*Q4wMPRMK#v#teDQRuUG}v0*ciyJeo3H{Z@}9K zj()zkZ1}4-KeAq2xnD(5M`WxWGKa(ai0mnC^j{`AiH{b(9b6ZHFblMDD)fjFPS^2% z(IO3=uAR9o7OSUl=2x_QG7hlft>q1fqYOHrF%#&a74DSp(sNQO=+ZQ|r*3sd)Pl0A zoh$hlzEx|a>^AS>iU5DceS7l=4_l<5W&91{hn{Mnv`qqIIA#MI7r1RJ@DO2!HstmQ zW$RR+KemqjVdJ4h7ln+~@P_20guW8PGlWI}jhzM${MDTZ2CXn)L9!ng1jUE7+<>4U zMr_x#fkbBP%~@ifB&mec)qvl@+91iy%1C%gZ0LXZHTDNL0W@q{jjhVZGt!2_t_HPD zT4k#rqLlGM`(!#FIFhc4enxBk6DmEJ{E0?5_KPfkSy@6s>$TT zG@l;6 zC3KPAH-vdmk>|Owg`2P}(9ZkUa*D*4AL_H(DAjZY8Hs_8uCs$P6~b8HA!SqVEqH| zU_bFm?~3n(aNx{IbEBYjJj+Q^P{0F9^qmmz4}XdUk7zu3<1%ipqe2|T5ib#d?D3of zj{T&E_b${7G64GYXk#N@)+m|t+KH0CH?@{}C~ri#1?r1^|C@P}b#vZ2e1a!hQjH8w zEVWG|Bw&)~>PrP{TMPK@h!5aB%VX9#I%K;CnuT+j5Wpn;+0Gi4o&DK7az$xIJ9 zQr9lSu8d&Lo`swy;xye*O;@(R84NN(2|7TRi314|`_YngfHstC2-jl4vxi;ywbSaK z%*x;S{L6Lxs}THO^8Ekb{wvM>)2{y!X~n2O1SBKRoV8Y<_^D+}MhAn;_-nJ|f@I|cKe z#ud}yKMHFdUXR=OPK?W>;1Vz^ylivVfvhkeUA9CnTwRLYEUqk*OVWM>JqkvDjQxy| z8TeK%Cr;vj^Mlx0Q1guYzRnQe-qEMaUpsT1MqJZ_wh$r8~k`tTt@O-9{3@kX>O;gLO z4t2^S>^1{rcR2O54eFF8_=)4CPq{|vNS3G6TaSvb?e$sBHx0R{hjChKGn&13USHh} zG^Yve9mVgU85zaqbC=?YqoGSyctbLa`(4j)otyMnw{urbdZqnKJ7Tl(l7A}xh%bxc zn~L61p%NDqv^ni|NRuU@Jft+=9xRekEhK#K;G5|OELvbtTxMowTbn4vvi8(F7Tn`LwOc?Jz)oDwG#=XL>CM_Xgpa_lT%$!E3qCE zev&bqah>MHA4(}K%)ceTourx6Bwkb4RCuVfIMZBC?$^-y`c7bnr+uWPs`NPkgKf3~ zzZshVM7+&5dg~!m2@W0TB1~a0B9#%8sGZ3<=Lv}2u-u;OwI9KHyO%X_C5 zr|Xn|7!q5hYT}Yt{w>+XsCE!GnAerJmTMed1vH051m?fFYC0|IW2{qHLQFOvPT9MM znoI9JmJZFMsaowjCpVz0!Z>+ydwU1rBfu#ZD;$6S$1X=zsZ&X5I-ko6MDu{%95hS zC#rg5Fb+K!jTt=%Tu=y}99gor9t2l6d_H}s2>ohyDaE-E-(Bcnc1E_8VbzNG?Ed;C zN?S_z-#MNy3AwG}3-)Z7Z;pgz#y5-AAvOH(*L;HFWb)OPG*In7I)~${_@I)Cf{Oe$ z)Ae+6q7=qwB+r)HD8&8OeB!luHy2ps*%FlY&mE2&Ubf%T1r9Lxb4URA1o*e9N3;3d zXCtPGA$*Wx)hvGUUG{Rx{bE=vtgw^;;%j39HW^T57>OPMHv+T~%5fQtM6=bc(ml){D+U<#Ux;WTNM9`)CV6@>de>89?sF^91^0 znV6#7*{#_bTg_1EpiQ$at2zXM&qj;rN)teDlD}xd#s1Q_EtXZ3UncQHufw@bCSUOC zP9Cdm1HB=Bw6ZprPWeXjXwc1t5@9A$@XqHU;I z0CKOJz3^V*?Rg*Nv{m{dm+w&a((FozO76lqV47 z8_uNI3NnSEG53+LDMoMn{W~-agavJ037#7yv~CO?8t$E6rw#EDyrb)Xab5OFgGK0> zy0t5*yD&hCH0-UmRSA2N0)JXfBu{9!vy&4(0He=4NKa3H>mJGpvO+{zGsTj_2T?bG z$!Tjzk%FvdziTI(C%cji=Tgwv&U`&1q9mfEB(kS)sMU#YkXtBB!jvZfRo9rvZv$v+ z2IDL$joj>buX0fkuxpbj$6nR~{*;hLh)-%{*0XQF6yY!!`kpk9r}^>r)=|Cnuc8TF zU{wlJl@f_!k4bprmW%Qm-@umQ7H%|JobKC55iU03yJd};NK%MzhWc%Zfe|Iub(*()L$bh=vD7VnlIZm`T zdaAb_1r^pcy)Q>~b!hh)arF>7FC{nIa?BM-f?Zszn{ow}NM@(!flfqc=NDI4zu)2Z zjprY*u(IpGeB|Xk!s=#mVgXgjb0I;&C|7s)=$3+ll5vMePndHhe9WX;L?n7cc2V#J z4(55|L<+m%j~{y`9AB$iPaezb+wr$-6epmt&J;)1&D{^yiwW*Y3Oifc#SApIa*`{3 z8zK{Q>LG$CQ8B8`eOo@`6_{lUS5{Ifph5>d0(rr(t(6gEr}j+G;a<(&j{?!6UjVR| zg1y?>s~W0w7btmI`g_=lPDUp!hBGFXXWQ=*4^>80rc8_BqcMdpR^PUN!Np#m40M|= z4IXXvZIzv}p8ovIaXA`*1M1h|W4}AQIJ2N0c4(Qk;3CBbttEEL{)%twZtRs;tkL*+ zRQ1hS529NLF8%&}NoFdprRC-hKcV>3_Q6$6%_~?K4jr!uub;d~*Z9w$PS;0ndjuPF zPPt-}YviCY>RPlRiKU+%&OB>L=jBf}t9m=JM z%006yjTd3wlv+%K$t?)9bZ}>pwt~sI8Gcxvzd($#xIG77^+oE5zAII){n+-_dF^aq zN_0t-J;iw>jwWn5%V0|NkFQM6p$P)E6Y_`pR&J)j6kp&!`?h{kAq{yn9%AA=`J=U> zwWIw;(@@;d1(M`N0l)_A$}<4PvQ(d(?wuDcV3CAbd*<77uW>OVvuta#b+*~ zSW)Ol9+4w2iIRW@l*Rw`Nq4*GO})dSO}*)3Z@I6bXFZ3ssi_^)9c8U$HEr+8CrGH+ zo+Qb>@)!ZisWiXO99ZN9B+ zqndJo)_{S51r`>Da0w|Di&6ASmdGT^5mDBsNr;7orIxYzg{6ZwK@ncNN>?ym44S_7~bJJI_IPZzhZ+qmpO|n5kF(3xwBsC%3THo%j+4jA?hbu9@ z+u;Om4-IK@t~9u>)K@N|6anQ01vgT^8F8VoHU3lb+~Sh3>yZ+x=QLLkZItDh?)hXH z3LoefWVP%x^n57BvSdX+g6KiztY!7~OMTUwa%hDq3ZtmgIUQ$o@*7M&;S^UfV^v;R zA~j4;6AUU^fBw4i{mjr3G?EQsOK|}hf%BE$x&&v zT4rOTPH5O#yIAx0Yqb8wh#0jVVMiM>sWGwWE$~l{G1l7PF%6YEpghPnyz=pb-dDGp zqKHF7tia|fZmX1m9q!^HJYBCa<8@i>aj-d@am=6UyE}e27h_`T=M1Yo9V4TTN8Om- zX(I_#r09}StMqoGjk`>e_>Ck2i-O}ewMryYcBb0-6JHnX$jQAXESd=HF+6pzwL5rLiUUB+ZW{w7Z%=X~#{d&A^d=e{Rf2R)8KX z-Qyd$e7asw7h#Et^H8H_DQd^9c-^y0?mNE0_{jIjUbTt*@0^e;z=a#108%IvJ}Sh4)sSy59Fm)q`rWR0{#y?W9Nzh literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/treemap-dark.png b/testdata/snapshots/darwin/treemap-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..18f2d90dc0148fc109878615fdf83757bbdc6d6f GIT binary patch literal 15168 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 f8z=OX{Q=4Cqru%>f;#~k4bYe0 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 0 { + kids = append(kids, ch) + } + } + slices.SortStableFunc(kids, func(a, b ChartNode) int { return cmp.Compare(b.total(), a.total()) }) + sum := node.total() + values := make([]float64, len(kids)) + for i, ch := range kids { + values[i] = ch.total() + } + ch := newChart(c, opts.Frame) + tiles := func(r ui.Rect) []ui.Rect { return squarify(values, r) } + spec := chartSpec{n: len(kids)} + spec.readout = func(i int) string { + s := fmt.Sprintf("%s · %s · %.1f%%", kids[i].Name, chartValue(c, values[i], opts.Format), 100*values[i]/sum) + if len(kids[i].Children) > 0 { + s += " · " + msg(c, "chart.opens") + } + return s + } + spec.pick = func(r ui.Rect, x, y float32) int { + for i, t := range tiles(r) { + if t.Contains(x, y) { + return i + } + } + return -1 + } + spec.activate = func(i int) { + if len(kids[i].Children) > 0 { + *path = append(slices.Clone(*path), kids[i].Name) + res.value = true + slog.Debug("mujica: treemap drill", "path", strings.Join(*path, "/")) + } + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + for i, t := range tiles(r) { + bg := pal[i%len(pal)] + p.Fill(t, bg, 2) + p.Stroke(t, k.Surface, 2, 2) + if i == active { + p.Stroke(ui.Rect{X: t.X + 3, Y: t.Y + 3, W: t.W - 6, H: t.H - 6}, chartInk(k, bg), 1, 2) + } + // Labels show only where tiles have room. + if t.W >= 36 && t.H >= 22 { + ink := chartInk(k, bg) + chartText(p, chartFit(p, kids[i].Name, t.W-12, size), t.X+6, t.Y+5, size, ink, 0, 0) + if t.H >= 40 { + chartText(p, chartFit(p, chartValue(c, values[i], opts.Format), t.W-12, size), t.X+6, t.Y+22, size, ink, 0, 0) + } + } + } + } + r, plot := ch.build(spec) + if plot != nil && !plot.IsDisabled() && plot.Shortcut(0, ui.KeyBackspace) && len(*path) > 0 { + *path, res.value = (*path)[:len(*path)-1], true + } + res.Element, res.Point, res.changed, res.retry = r.Element, r.Point, r.changed, r.retry + }) + res.Element = wrap + return res +} diff --git a/treemap_test.go b/treemap_test.go new file mode 100644 index 0000000..4abeacb --- /dev/null +++ b/treemap_test.go @@ -0,0 +1,89 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +func chartTree() ChartNode { + return ChartNode{Name: "Abbey", Children: []ChartNode{ + {Name: "Library", Children: []ChartNode{{Name: "Psalters", Value: 30}, {Name: "Maps", Value: 10}}}, + {Name: "Kitchen", Value: 25}, + {Name: "Garden", Children: []ChartNode{{Name: "Herbs", Value: 12}, {Name: "Vines", Value: 8}}}, + {Name: "Cell of a very long-winded brother", Value: 3}, + }} +} + +func TestSquarifyFills(t *testing.T) { + rects := squarify([]float64{6, 6, 4, 3, 2, 2, 1}, ui.Rect{W: 600, H: 400}) + area := float32(0) + for _, r := range rects { + area += r.W * r.H + if r.W <= 0 || r.H <= 0 { + t.Fatalf("empty tile %v", r) + } + } + if area < 600*400-1 || area > 600*400+1 { + t.Fatalf("tiles cover %v of %v", area, 600*400) + } +} + +func TestTreemapDrillAndBack(t *testing.T) { + var path []string + values := 0 + h := &chartHarness{build: func(c *ui.Context) ChartResult { + r := Treemap(c, &path, chartTree(), TreemapOptions{Frame: ChartFrame{Label: "Rooms"}}) + if r.ValueChanged() { + values++ + } + return r + }} + tt := ui.NewTester(h.view, 560, 440) + tabTo(t, tt, "Rooms") + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != "Library · 40 · 45.5% · Enter opens" { + t.Fatalf("readout %q", got) + } + tt.Key(0, ui.KeyEnter) + if fmt.Sprint(path) != "[Library]" || values != 1 || !tt.HasText("Library") { + t.Fatalf("drill path %v events %d", path, values) + } + tt.Key(0, ui.KeyRight) + tt.Key(0, ui.KeyEnter) // a leaf stays + if fmt.Sprint(path) != "[Library]" { + t.Fatalf("leaf drilled: %v", path) + } + tt.Key(0, ui.KeyBackspace) + if len(path) != 0 { + t.Fatalf("Backspace kept %v", path) + } + path = []string{"Garden"} + tt.Frame() + if err := tt.Click("Back"); err != nil || len(path) != 0 { + t.Fatalf("Back: %v %v", err, path) + } +} + +func TestTreemapBadPath(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("no panic for an unknown path") + } + }() + path := []string{"Nowhere"} + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + Treemap(c, &path, chartTree(), TreemapOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) +} + +func TestTreemapSnapshot(t *testing.T) { + snapshot(t, "treemap", 560, 340, func(c *ui.Context) { + var path []string + ui.Column(c).Padding(16).Children(func() { + Treemap(c, &path, chartTree(), TreemapOptions{Frame: ChartFrame{Label: "Rooms"}}) + }) + }) +} diff --git a/waterfall_chart.go b/waterfall_chart.go new file mode 100644 index 0000000..e7bf0b7 --- /dev/null +++ b/waterfall_chart.go @@ -0,0 +1,125 @@ +package mujica + +import ( + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// WaterfallKind says how a step's bar is drawn. +type WaterfallKind int + +const ( + // WaterfallDelta adds Value to the running total. + WaterfallDelta WaterfallKind = iota + // WaterfallSubtotal shows the running total; its Value must be zero. + WaterfallSubtotal + // WaterfallTotal shows the final total; Value must be zero. + WaterfallTotal +) + +// WaterfallStep is one bar of a WaterfallChart. +type WaterfallStep struct { + Label string + Value float64 + Kind WaterfallKind +} + +// WaterfallChartOptions configure a WaterfallChart. +type WaterfallChartOptions struct { + Frame ChartFrame + Format func(v float64) string +} + +// WaterfallChart builds a total from rises and falls. +func WaterfallChart(c *ui.Context, steps []WaterfallStep, opts WaterfallChartOptions) ChartResult { + from, to := make([]float64, len(steps)), make([]float64, len(steps)) + run, lo, hi := 0.0, 0.0, 0.0 + for i, s := range steps { + if s.Label == "" || math.IsNaN(s.Value) || math.IsInf(s.Value, 0) || s.Kind != WaterfallDelta && s.Value != 0 || s.Kind > WaterfallTotal { + panic("mujica: WaterfallChart steps need a label, a finite value, and zero for totals") + } + if s.Kind == WaterfallDelta { + from[i], to[i], run = run, run+s.Value, run+s.Value + } else { + from[i], to[i] = 0, run + } + lo, hi = min(lo, from[i], to[i]), max(hi, from[i], to[i]) + } + ch := newChart(c, opts.Frame) + k := Tokens(c) + size := FontSize(c, theme.CaptionSize) + var step float64 + if len(steps) > 0 { + pad := (hi - lo) * 0.12 + lo, hi, step = internal.Nice(lo-pad*chartBool(lo < 0), hi+pad, 4) + } + val := func(v float64) string { return chartValue(c, v, opts.Format) } + signed := func(v float64) string { + if v >= 0 { + return "+" + val(v) + } + return "−" + val(-v) + } + geom := func(r ui.Rect) (ui.Rect, internal.Band, internal.Linear) { + plot := chartInset(r, 52, 26) + return plot, internal.Band{N: len(steps), R0: plot.X, R1: plot.X + plot.W, Pad: 0.3}, + internal.Linear{D0: lo, D1: hi, R0: float64(plot.Y + plot.H), R1: float64(plot.Y)} + } + spec := chartSpec{n: len(steps)} + spec.readout = func(i int) string { + if steps[i].Kind != WaterfallDelta { + return steps[i].Label + " · " + val(to[i]) + } + return steps[i].Label + " · " + signed(steps[i].Value) + " · " + msg(c, "waterfall_chart.running") + " " + val(to[i]) + } + spec.pick = func(r ui.Rect, x, y float32) int { + plot, band, _ := geom(r) + if !plot.Contains(x, y) { + return -1 + } + return min(len(steps)-1, int((x-plot.X)/band.Step())) + } + spec.draw = func(p *ui.Painter, r ui.Rect, active int) { + plot, band, ys := geom(r) + internal.AxisY(p, plot, ys, internal.Ticks(lo, hi, step), func(v float64) string { return internal.FormatTick(v, step) }, size, k) + var xs []float32 + var names []string + for i, s := range steps { + xs, names = append(xs, band.Center(i)), append(names, s.Label) + } + internal.AxisX(p, plot, xs, names, size, k) + internal.Rule(p, plot.X, plot.X+plot.W, ys.Map(0), k.ControlBorder) + for i, s := range steps { + a, b := ys.Map(from[i]), ys.Map(to[i]) + bar := ui.Rect{X: band.Start(i), Y: min(a, b), W: band.Width(), H: max(abs32(a-b), 1)} + col, shape, text := internal.Palette(k)[5], 1, val(to[i]) + switch { + case s.Kind != WaterfallDelta: + case s.Value >= 0: + col, shape, text = k.Success, 3, signed(s.Value) + default: + col, shape, text = k.Danger, 4, signed(s.Value) + } + p.Fill(bar, col, 1) + internal.Marker(p, shape, bar.X+bar.W/2, bar.Y-14+(bar.H+28)*float32(chartBool(s.Kind == WaterfallDelta && s.Value < 0)), 8, col) + ty, ay := bar.Y-22, float32(1) + if s.Kind == WaterfallDelta && s.Value < 0 { + ty, ay = bar.Y+bar.H+22, 0 + } + chartText(p, text, bar.X+bar.W/2, ty, size, k.Text, 0.5, ay) + if i+1 < len(steps) { + y := internal.Snap(p, ys.Map(to[i])) + p.Line(bar.X+bar.W, y, band.Start(i+1), y, 1, k.TextMuted) + } + if i == active { + p.Stroke(ui.Rect{X: bar.X - 2, Y: bar.Y - 2, W: bar.W + 4, H: bar.H + 4}, k.Text, 2, 1.5) + } + } + } + res, _ := ch.build(spec) + return res +} diff --git a/waterfall_chart_test.go b/waterfall_chart_test.go new file mode 100644 index 0000000..70c9b7d --- /dev/null +++ b/waterfall_chart_test.go @@ -0,0 +1,54 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +var waterfallSteps = []WaterfallStep{ + {Label: "Tithes", Value: 12}, + {Label: "Repairs", Value: -5}, + {Label: "Q1", Kind: WaterfallSubtotal}, + {Label: "Alms", Value: 4}, + {Label: "Year", Kind: WaterfallTotal}, +} + +func TestWaterfallChartReadout(t *testing.T) { + h := &chartHarness{build: func(c *ui.Context) ChartResult { + return WaterfallChart(c, waterfallSteps, WaterfallChartOptions{Frame: ChartFrame{Label: "Ledger"}}) + }} + tt := ui.NewTester(h.view, 520, 420) + tabTo(t, tt, "Ledger") + want := []string{"Tithes · +12 · running total 12", "Repairs · −5 · running total 7", "Q1 · 7", "Alms · +4 · running total 11", "Year · 11"} + for i, w := range want { + tt.Key(0, ui.KeyRight) + if got := chartReadout(tt); got != w { + t.Fatalf("step %d: %q, want %q", i, got, w) + } + } +} + +func TestWaterfallChartBad(t *testing.T) { + for _, s := range []WaterfallStep{{Label: "x", Value: 3, Kind: WaterfallTotal}, {Value: 1}, {Label: "x", Kind: 9}} { + func() { + defer func() { + if recover() == nil { + t.Errorf("%+v: no panic", s) + } + }() + ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + WaterfallChart(c, []WaterfallStep{s}, WaterfallChartOptions{Frame: ChartFrame{Label: "x"}}) + }, 300, 300) + }() + } +} + +func TestWaterfallChartSnapshot(t *testing.T) { + snapshot(t, "waterfall_chart", 520, 320, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + WaterfallChart(c, waterfallSteps, WaterfallChartOptions{Frame: ChartFrame{Label: "Ledger"}}) + }) + }) +}

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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/radar_chart-dark.png b/testdata/snapshots/darwin/radar_chart-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..aa910f8b08b271df52eb607023263756ac7efb85 GIT binary patch literal 30389 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/radar_chart-light.png b/testdata/snapshots/darwin/radar_chart-light.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce2f9753d34937b03bd241f71b51a23efa3e85a GIT binary patch literal 29501 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 H1ONX66Qs%w>$yP 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