161 lines
2.9 KiB
Go
161 lines
2.9 KiB
Go
package view
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/go-echarts/go-echarts/v2/charts"
|
|
"github.com/go-echarts/go-echarts/v2/opts"
|
|
)
|
|
|
|
type Chart interface {
|
|
AddX(interface{})
|
|
AddY(string, []int)
|
|
Render(io.Writer) error
|
|
Overlap(Chart)
|
|
}
|
|
|
|
func NewChart(name string) Chart {
|
|
switch name {
|
|
case "line":
|
|
return NewLine()
|
|
case "bar":
|
|
return NewBar()
|
|
case "stack":
|
|
return NewStack()
|
|
case "pie":
|
|
return NewPie()
|
|
default:
|
|
panic("bad chart name " + name)
|
|
}
|
|
}
|
|
|
|
type Line struct {
|
|
*charts.Line
|
|
}
|
|
|
|
func NewLine() Line {
|
|
return Line{Line: charts.NewLine()}
|
|
}
|
|
|
|
func (line Line) AddX(v interface{}) {
|
|
line.SetXAxis(v)
|
|
}
|
|
|
|
func (line Line) AddY(name string, v []int) {
|
|
y := make([]opts.LineData, len(v))
|
|
for i := range y {
|
|
y[i].Value = v[i]
|
|
}
|
|
line.AddSeries(name, y).
|
|
SetSeriesOptions(charts.WithBarChartOpts(opts.BarChart{
|
|
Stack: "stackB",
|
|
}))
|
|
}
|
|
|
|
func (line Line) Overlap(other Chart) {
|
|
overlapper, ok := other.(charts.Overlaper)
|
|
if !ok {
|
|
panic(fmt.Sprintf("cannot overlap %T", other))
|
|
}
|
|
line.Line.Overlap(overlapper)
|
|
}
|
|
|
|
type Bar struct {
|
|
*charts.Bar
|
|
}
|
|
|
|
func NewBar() Bar {
|
|
return Bar{Bar: charts.NewBar()}
|
|
}
|
|
|
|
func (bar Bar) AddX(v interface{}) {
|
|
bar.SetXAxis(v)
|
|
}
|
|
|
|
func (bar Bar) AddY(name string, v []int) {
|
|
y := make([]opts.BarData, len(v))
|
|
for i := range v {
|
|
y[i].Value = v[i]
|
|
}
|
|
bar.AddSeries(name, y)
|
|
}
|
|
|
|
func (bar Bar) Overlap(other Chart) {
|
|
overlapper, ok := other.(charts.Overlaper)
|
|
if !ok {
|
|
panic(fmt.Sprintf("cannot overlap %T", other))
|
|
}
|
|
bar.Bar.Overlap(overlapper)
|
|
}
|
|
|
|
type Stack struct {
|
|
Bar
|
|
}
|
|
|
|
func NewStack() Stack {
|
|
bar := NewBar()
|
|
bar.SetSeriesOptions(charts.WithBarChartOpts(opts.BarChart{Stack: "x"}))
|
|
return Stack{Bar: bar}
|
|
}
|
|
|
|
func (stack Stack) AddY(name string, v []int) {
|
|
y := make([]opts.BarData, len(v))
|
|
for i := range v {
|
|
y[i].Value = v[i]
|
|
}
|
|
stack.AddSeries(name, y).
|
|
SetSeriesOptions(charts.WithBarChartOpts(opts.BarChart{
|
|
Stack: "stackA",
|
|
}))
|
|
}
|
|
|
|
type Pie struct {
|
|
*charts.Pie
|
|
series []opts.PieData
|
|
}
|
|
|
|
func NewPie() *Pie {
|
|
return &Pie{Pie: charts.NewPie()}
|
|
}
|
|
|
|
func (pie *Pie) AddX(v interface{}) {
|
|
}
|
|
|
|
func (pie *Pie) Render(w io.Writer) error {
|
|
slices.SortFunc(pie.series, func(a, b opts.PieData) int {
|
|
return strings.Compare(a.Name, b.Name)
|
|
})
|
|
commonPrefixLen := -1
|
|
for i := 0; i < len(pie.series[0].Name) && i < len(pie.series[len(pie.series)-1].Name); i++ {
|
|
if pie.series[0].Name[i] != pie.series[len(pie.series)-1].Name[i] {
|
|
break
|
|
}
|
|
commonPrefixLen = i
|
|
}
|
|
for i := range pie.series {
|
|
pie.series[i].Name = pie.series[i].Name[commonPrefixLen+1:]
|
|
}
|
|
|
|
pie.AddSeries("", pie.series)
|
|
pie.SetGlobalOptions(charts.WithLegendOpts(opts.Legend{
|
|
Show: false,
|
|
}))
|
|
return pie.Pie.Render(w)
|
|
}
|
|
|
|
func (pie *Pie) AddY(name string, v []int) {
|
|
for _, v := range v {
|
|
pie.series = append(pie.series, opts.PieData{
|
|
Name: fmt.Sprintf("%s ($%d)", name, v),
|
|
Value: v,
|
|
})
|
|
}
|
|
}
|
|
|
|
func (pie *Pie) Overlap(other Chart) {
|
|
panic("nope")
|
|
}
|