1package sheet23import (4 "encoding/json"5 "fmt"6)78// fileChart is a chart, one per line after the cells:9//10// {"type": "column", "data": "A1:C7", "at": "E2", "width": 44, "height": 14, "header": true, "labels": true}11//12// Options at their defaults are left out, so they need no version bump:13// older versions of 012 draw such a chart with the defaults, and older14// versions still ignore the field and drop the charts. A type they don't15// know makes them refuse the file.16type fileChart struct {17 Type string `json:"type"`18 Data string `json:"data"`19 At string `json:"at"`20 Width int `json:"width"`21 Height int `json:"height"`22 ByRow bool `json:"byRow,omitempty"`23 Header bool `json:"header,omitempty"`24 Labels bool `json:"labels,omitempty"`25 Title string `json:"title,omitempty"`26 // Options: "stacked" or "percent"; a trend line; the ends of the value27 // axis; a log scale; gridlines, only when off; "right" or "none".28 Stack string `json:"stack,omitempty"`29 Trend bool `json:"trend,omitempty"`30 Min *float64 `json:"min,omitempty"`31 Max *float64 `json:"max,omitempty"`32 Log bool `json:"log,omitempty"`33 Gridlines *bool `json:"gridlines,omitempty"`34 Legend string `json:"legend,omitempty"`35}3637func encodeChart(c Chart) ([]byte, error) {38 fc := fileChart{39 Type: c.Type.String(), Data: c.Data.String(), At: c.At.String(), Width: c.W, Height: c.H,40 ByRow: c.ByRow, Header: c.Header, Labels: c.Labels, Title: c.Title,41 Stack: c.Stack.String(), Trend: c.Trend, Log: c.Log,42 Min: axisEnd(c.Min, c.HasMin), Max: axisEnd(c.Max, c.HasMax),43 }44 if c.NoGrid {45 fc.Gridlines = new(bool)46 }47 if c.Legend != LegendBottom {48 fc.Legend = c.Legend.String()49 }50 return json.Marshal(fc)51}5253func decodeChart(fc fileChart) (Chart, error) {54 t, ok := ParseChartType(fc.Type)55 if !ok {56 return Chart{}, fmt.Errorf("unknown chart type %q", fc.Type)57 }58 data, ok := ParseRange(fc.Data)59 if !ok {60 return Chart{}, fmt.Errorf("invalid chart range %q", fc.Data)61 }62 at, ok := ParseAddr(fc.At)63 if !ok {64 return Chart{}, fmt.Errorf("invalid chart position %q", fc.At)65 }66 c := Chart{Type: t, Data: data, At: at, W: fc.Width, H: fc.Height,67 ByRow: fc.ByRow, Header: fc.Header, Labels: fc.Labels, Title: fc.Title}68 // Options a later build writes and this one doesn't know are left at69 // their defaults, as an older build would.70 c.Stack, _ = ParseChartStack(fc.Stack)71 c.Legend, _ = ParseChartLegend(fc.Legend)72 c.Trend, c.Log = fc.Trend, fc.Log73 c.NoGrid = fc.Gridlines != nil && !*fc.Gridlines74 if fc.Min != nil {75 c.Min, c.HasMin = *fc.Min, true76 }77 if fc.Max != nil {78 c.Max, c.HasMax = *fc.Max, true79 }80 return c.clamped(), nil81}