spreadsheet: add a multi chart example

This commit is contained in:
Todd 2017-09-04 17:16:05 -05:00
parent b8bfe8129e
commit 5ee1459321
6 changed files with 217 additions and 67 deletions

View File

@ -28,9 +28,9 @@ func main() {
// Charts need to reside in a drawing
dwng := ss.AddDrawing()
chart := dwng.AddChart()
chart, anc := dwng.AddChart()
// make it a bit wider than the default
dwng.BottomRight().SetCol(15)
anc.BottomRight().SetCol(15)
lc := chart.AddBarChart()
priceSeries := lc.AddSeries()

View File

@ -28,9 +28,9 @@ func main() {
// Charts need to reside in a drawing
dwng := ss.AddDrawing()
chart := dwng.AddChart()
chart, anc := dwng.AddChart()
// make it a bit wider than the default
dwng.BottomRight().SetCol(15)
anc.BottomRight().SetCol(15)
lc := chart.AddLineChart()
priceSeries := lc.AddSeries()
@ -57,9 +57,9 @@ func main() {
va.SetCrosses(ca)
// add a title and legend
// title := chart.AddTitle()
// title.SetText("Items Sold")
// chart.AddLegend()
title := chart.AddTitle()
title.SetText("Items Sold")
chart.AddLegend()
// and finally add the chart to the sheet
sheet.SetDrawing(dwng)

View File

@ -0,0 +1,101 @@
// Copyright 2017 Baliance. All rights reserved.
package main
import (
"fmt"
"log"
"baliance.com/gooxml/chart"
"baliance.com/gooxml/spreadsheet"
)
func main() {
ss := spreadsheet.New()
sheet := ss.AddSheet()
// Create all of our data
row := sheet.AddRow()
row.AddCell().SetString("Item")
row.AddCell().SetString("Price")
row.AddCell().SetString("# Sold")
row.AddCell().SetString("Total")
for r := 0; r < 5; r++ {
row := sheet.AddRow()
row.AddCell().SetString(fmt.Sprintf("Product %d", r+1))
row.AddCell().SetNumber(1.23 * float64(r+1))
row.AddCell().SetNumber(float64(r%3 + 1))
row.AddCell().SetFormulaRaw(fmt.Sprintf("C%d*B%d", r+2, r+2))
}
// Charts need to reside in a drawing
dwng := ss.AddDrawing()
chrt1, anc1 := dwng.AddChart()
chrt2, anc2 := dwng.AddChart()
addBarChart(chrt1)
addLineChart(chrt2)
anc1.SetWidth(9)
anc1.MoveTo(5, 1)
anc2.MoveTo(1, 23)
// and finally add the chart to the sheet
sheet.SetDrawing(dwng)
if err := ss.Validate(); err != nil {
log.Fatalf("error validating sheet: %s", err)
}
ss.SaveToFile("multiple-chart.xlsx")
}
func addBarChart(chrt chart.Chart) {
chrt.AddTitle().SetText("Bar Chart")
lc := chrt.AddBarChart()
priceSeries := lc.AddSeries()
priceSeries.SetText("Price")
// Set a category axis reference on the first series to pull the product names
priceSeries.CategoryAxis().SetReference(`'Sheet 1'!A2:A6`)
priceSeries.Values().SetReference(`'Sheet 1'!B2:B6`)
soldSeries := lc.AddSeries()
soldSeries.SetText("Sold")
soldSeries.Values().SetReference(`'Sheet 1'!C2:C6`)
totalSeries := lc.AddSeries()
totalSeries.SetText("Total")
totalSeries.Values().SetReference(`'Sheet 1'!D2:D6`)
// the line chart accepts up to two axes
ca := chrt.AddCategoryAxis()
va := chrt.AddValueAxis()
lc.AddAxis(ca)
lc.AddAxis(va)
ca.SetCrosses(va)
va.SetCrosses(ca)
}
func addLineChart(chrt chart.Chart) {
chrt.AddTitle().SetText("Line Chart")
lc := chrt.AddLineChart()
priceSeries := lc.AddSeries()
priceSeries.SetText("Price")
// Set a category axis reference on the first series to pull the product names
priceSeries.CategoryAxis().SetReference(`'Sheet 1'!A2:A6`)
priceSeries.Values().SetReference(`'Sheet 1'!B2:B6`)
soldSeries := lc.AddSeries()
soldSeries.SetText("Sold")
soldSeries.Values().SetReference(`'Sheet 1'!C2:C6`)
totalSeries := lc.AddSeries()
totalSeries.SetText("Total")
totalSeries.Values().SetReference(`'Sheet 1'!D2:D6`)
// the line chart accepts up to two axes
ca := chrt.AddCategoryAxis()
va := chrt.AddValueAxis()
lc.AddAxis(ca)
lc.AddAxis(va)
ca.SetCrosses(va)
va.SetCrosses(ca)
}

20
spreadsheet/anchor.go Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2017 Baliance. All rights reserved.
//
// Use of this source code is governed by the terms of the Affero GNU General
// Public License version 3.0 as published by the Free Software Foundation and
// appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com.
package spreadsheet
// Anchor is the interface implemented by anchors. It's modeled after the most
// common anchor (Two cell variant with a from/to position), but will also be
// used for one-cell anchors. In that case the only non-noop methods are
// TopLeft() and MoveTo().
type Anchor interface {
BottomRight() CellMarker
TopLeft() CellMarker
MoveTo(col, row int32)
SetWidth(w int32)
SetHeight(h int32)
}

View File

@ -28,26 +28,12 @@ func (d Drawing) X() *sd.WsDr {
}
func (d Drawing) InitializeDefaults() {
d.x.TwoCellAnchor = sd.NewCT_TwoCellAnchor()
d.x.TwoCellAnchor.EditAsAttr = sd.ST_EditAsOneCell
// provide a default size so its visible, if from/to are both 0,0 then the
// chart won't show up.
d.x.TwoCellAnchor.From.Col = 5
d.x.TwoCellAnchor.From.Row = 0
// Mac Excel requires the offsets be present
d.x.TwoCellAnchor.From.ColOff.ST_CoordinateUnqualified = gooxml.Int64(0)
d.x.TwoCellAnchor.From.RowOff.ST_CoordinateUnqualified = gooxml.Int64(0)
d.x.TwoCellAnchor.To.Col = 10
d.x.TwoCellAnchor.To.Row = 20
d.x.TwoCellAnchor.To.ColOff.ST_CoordinateUnqualified = gooxml.Int64(0)
d.x.TwoCellAnchor.To.RowOff.ST_CoordinateUnqualified = gooxml.Int64(0)
}
func (d Drawing) AddChart() chart.Chart {
func (d Drawing) AddChart() (chart.Chart, Anchor) {
chartSpace := crt.NewChartSpace()
d.wb.charts = append(d.wb.charts, chartSpace)
chrt := chart.MakeChart(chartSpace)
fn := gooxml.AbsoluteFilename(gooxml.DocTypeSpreadsheet, gooxml.ChartContentType, len(d.wb.charts))
d.wb.ContentTypes.AddOverride(fn, gooxml.ChartContentType)
@ -63,60 +49,42 @@ func (d Drawing) AddChart() chart.Chart {
}
}
// maybe use a one cell anchor?
if d.x.TwoCellAnchor == nil {
d.InitializeDefaults()
}
d.x.TwoCellAnchor.Choice = &sd.EG_ObjectChoicesChoice{}
d.x.TwoCellAnchor.Choice.GraphicFrame = sd.NewCT_GraphicalObjectFrame()
tca := sd.NewCT_TwoCellAnchor()
d.x.EG_Anchor = append(d.x.EG_Anchor, &sd.EG_Anchor{TwoCellAnchor: tca})
tca.EditAsAttr = sd.ST_EditAsOneCell
// provide a default size so its visible, if from/to are both 0,0 then the
// chart won't show up.
tca.From.Col = 5
tca.From.Row = 0
// Mac Excel requires the offsets be present
tca.From.ColOff.ST_CoordinateUnqualified = gooxml.Int64(0)
tca.From.RowOff.ST_CoordinateUnqualified = gooxml.Int64(0)
tca.To.Col = 10
tca.To.Row = 20
tca.To.ColOff.ST_CoordinateUnqualified = gooxml.Int64(0)
tca.To.RowOff.ST_CoordinateUnqualified = gooxml.Int64(0)
tca.Choice = &sd.EG_ObjectChoicesChoice{}
tca.Choice.GraphicFrame = sd.NewCT_GraphicalObjectFrame()
// required by Mac Excel
d.x.TwoCellAnchor.Choice.GraphicFrame.NvGraphicFramePr = sd.NewCT_GraphicalObjectFrameNonVisual()
d.x.TwoCellAnchor.Choice.GraphicFrame.NvGraphicFramePr.CNvPr.IdAttr = 2
d.x.TwoCellAnchor.Choice.GraphicFrame.NvGraphicFramePr.CNvPr.NameAttr = "Chart"
tca.Choice.GraphicFrame.NvGraphicFramePr = sd.NewCT_GraphicalObjectFrameNonVisual()
tca.Choice.GraphicFrame.NvGraphicFramePr.CNvPr.IdAttr = 2
tca.Choice.GraphicFrame.NvGraphicFramePr.CNvPr.NameAttr = "Chart"
d.x.TwoCellAnchor.Choice.GraphicFrame.Graphic = dml.NewGraphic()
d.x.TwoCellAnchor.Choice.GraphicFrame.Graphic.GraphicData.UriAttr = "http://schemas.openxmlformats.org/drawingml/2006/chart"
tca.Choice.GraphicFrame.Graphic = dml.NewGraphic()
tca.Choice.GraphicFrame.Graphic.GraphicData.UriAttr = "http://schemas.openxmlformats.org/drawingml/2006/chart"
c := c.NewChart()
c.IdAttr = chartID
d.x.TwoCellAnchor.Choice.GraphicFrame.Graphic.GraphicData.Any = []gooxml.Any{c}
tca.Choice.GraphicFrame.Graphic.GraphicData.Any = []gooxml.Any{c}
//chart.Chart.PlotVisOnly = crt.NewCT_Boolean()
//chart.Chart.PlotVisOnly.ValAttr = gooxml.Bool(true)
chrt := chart.MakeChart(chartSpace)
chrt.Properties().SetSolidFill(color.White)
chrt.SetDisplayBlanksAs(crt.ST_DispBlanksAsGap)
return chrt
}
// TopLeft allows manipulating the top left position of the drawing.
func (d Drawing) TopLeft() CellMarker {
if d.x.TwoCellAnchor != nil {
if d.x.TwoCellAnchor.From == nil {
d.x.TwoCellAnchor.From = sd.NewCT_Marker()
}
return CellMarker{d.x.TwoCellAnchor.From}
}
if d.x.OneCellAnchor != nil {
if d.x.OneCellAnchor.From == nil {
d.x.OneCellAnchor.From = sd.NewCT_Marker()
}
return CellMarker{d.x.OneCellAnchor.From}
}
// this will crash if used...
return CellMarker{}
}
// BottomRight allows manipulating the bottom right position of the drawing.
func (d Drawing) BottomRight() CellMarker {
if d.x.TwoCellAnchor != nil {
if d.x.TwoCellAnchor.To == nil {
d.x.TwoCellAnchor.To = sd.NewCT_Marker()
}
return CellMarker{d.x.TwoCellAnchor.To}
}
// this will crash if used...
return CellMarker{}
return chrt, TwoCellAnchor{tca}
}

View File

@ -0,0 +1,61 @@
// Copyright 2017 Baliance. All rights reserved.
//
// Use of this source code is governed by the terms of the Affero GNU General
// Public License version 3.0 as published by the Free Software Foundation and
// appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting sales@baliance.com.
package spreadsheet
import (
sd "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
)
// TwoCellAnchor is an anchor that is attached from a top-left to a bottom-right
// cell (from & to cells).
type TwoCellAnchor struct {
x *sd.CT_TwoCellAnchor
}
// BottomRight returns the CellMaker for the bottom right corner of the anchor.
func (t TwoCellAnchor) BottomRight() CellMarker {
if t.x.To == nil {
t.x.To = sd.NewCT_Marker()
}
return CellMarker{t.x.To}
}
// TopLeft returns the CellMaker for the top left corner of the anchor.
func (t TwoCellAnchor) TopLeft() CellMarker {
if t.x.From == nil {
t.x.From = sd.NewCT_Marker()
}
return CellMarker{t.x.From}
}
// MoveTo repositions the anchor without changing the objects size.
func (t TwoCellAnchor) MoveTo(col, row int32) {
tl := t.TopLeft()
br := t.BottomRight()
w := br.Col() - tl.Col()
h := br.Row() - tl.Row()
tl.SetCol(col)
tl.SetRow(row)
t.SetWidth(w)
t.SetHeight(h)
}
// SetWidth sets the height the anchored objet by moving the right hand side.
func (t TwoCellAnchor) SetWidth(w int32) {
tl := t.TopLeft()
br := t.BottomRight()
br.SetCol(tl.Col() + w)
}
// SetHeight sets the height the anchored objet by moving the bottom.
func (t TwoCellAnchor) SetHeight(h int32) {
tl := t.TopLeft()
br := t.BottomRight()
br.SetRow(tl.Row() + h)
}