package chartjs import ( "slices" "sync" ) // DataCounter 计数统计, 实现类似Pie 和 Doughnut 之类的图形 type DataCounter struct { mutex sync.Mutex legends map[string]*counterValue } func (c *DataCounter) Inc(leg string, label string, value float64) { c.mutex.Lock() defer c.mutex.Unlock() v, ok := c.legends[leg] if !ok { v = &counterValue{ Label: leg, Values: make(map[string]float64), } c.legends[leg] = v } v.Values[label] += value } func (c *DataCounter) Dec(legend string, label string, value float64) { c.mutex.Lock() defer c.mutex.Unlock() v, ok := c.legends[legend] if !ok { return } if _, ok := v.Values[label]; ok { v.Values[label] -= value } } func (c *DataCounter) Data() *CounterData { c.mutex.Lock() defer c.mutex.Unlock() data := &CounterData{ Lables: make([]string, 0, 5), Datasets: make([]*CounterValue, 0, len(c.legends)), } for _, row := range c.legends { for k, _ := range row.Values { if !slices.Contains(data.Lables, k) { data.Lables = append(data.Lables, k) } } } for _, row := range c.legends { set := &CounterValue{ Label: row.Label, Data: make([]float64, 0, len(data.Lables)), } for _, label := range data.Lables { set.Data = append(set.Data, row.Values[label]) } data.Datasets = append(data.Datasets, set) } return data } func NewDataCounter(legends ...string) *DataCounter { c := &DataCounter{ legends: make(map[string]*counterValue), } for _, legend := range legends { c.legends[legend] = &counterValue{ Label: legend, Values: make(map[string]float64), } } return c }