1package chart23import (4 "image"56 "src.rest/cat/012/internal/sheet"7)89// A plan is a chart laid out in w by h cells: the layout Draw and Image10// share, so text and image line up.11type plan interface {12 // note is a message shown instead of the chart, such as "No numbers13 // to chart", or "" when there's a chart to draw.14 note() string15 // plotArea is the rectangle, in cells, that an image covers.16 plotArea() image.Rectangle17 // draw draws the chart as text; with o.Image, all but the plot area.18 draw(g *Grid, o Options)19 // image draws the plot area, one cell per cv.cw by cv.ch pixels.20 image(cv *canvas)21}2223// A chartType lays out data as one type of chart. The legend of series24// is Draw's: it gives the layout the room the legend leaves, and names25// returns the series it lists, nil for a type that draws its own.26type chartType struct {27 layout func(d sheet.ChartData, w, h int, o Options) plan28 names func(d sheet.ChartData) []string29}3031// types are the chart types, each a layout whose plan draws it as text32// and as an image. The types themselves, their names and the order the33// chart editor offers them, are in the sheet package, since charts are34// saved with sheets; adding one is a constant there and a row here.35var types = map[sheet.ChartType]chartType{36 sheet.ChartColumn: {columnLayout(columnBars), allSeries},37 sheet.ChartBar: {func(d sheet.ChartData, w, h int, o Options) plan {38 return newBarPlan(d, w, h, o.Chart)39 }, allSeries},40 sheet.ChartLine: {columnLayout(columnLine), allSeries},41 sheet.ChartPie: {func(d sheet.ChartData, w, h int, o Options) plan {42 return newPiePlan(d, w, h, o)43 }, nil},44 sheet.ChartArea: {columnLayout(columnArea), allSeries},45 sheet.ChartScatter: {func(d sheet.ChartData, w, h int, o Options) plan {46 return newScatterPlan(d, w, h, o.Chart)47 }, func(d sheet.ChartData) []string {48 _, ys := scatterSeries(d)49 return seriesNames(ys)50 }},51}5253func columnLayout(kind columnKind) func(d sheet.ChartData, w, h int, o Options) plan {54 return func(d sheet.ChartData, w, h int, o Options) plan { return newColumnPlan(d, w, h, kind, o.Chart) }55}5657func allSeries(d sheet.ChartData) []string { return seriesNames(d.Series) }5859// planFor lays out d as a chart of type t, with its legend; an unknown60// type is drawn as columns.61func planFor(t sheet.ChartType, d sheet.ChartData, w, h int, o Options) (plan, legendBox) {62 ct, ok := types[t]63 if !ok {64 ct = types[sheet.ChartColumn]65 }66 lg := legendBox{pos: sheet.LegendNone}67 if ct.names != nil {68 lg, w, h = placeLegend(ct.names(d), o.Chart.Legend, w, h)69 }70 return ct.layout(d, w, h, o), lg71}7273func (p *columnPlan) note() string { return p.msg }74func (p *columnPlan) plotArea() image.Rectangle { return p.plot }75func (p *barPlan) note() string { return p.msg }76func (p *barPlan) plotArea() image.Rectangle { return p.plot }77func (p *piePlan) note() string { return p.msg }78func (p *piePlan) plotArea() image.Rectangle { return p.disc }79func (p *scatterPlan) note() string { return p.msg }80func (p *scatterPlan) plotArea() image.Rectangle { return p.plot }