diff --git a/_examples/spreadsheet/bar-chart/main.go b/_examples/spreadsheet/bar-chart/main.go new file mode 100644 index 00000000..05196e18 --- /dev/null +++ b/_examples/spreadsheet/bar-chart/main.go @@ -0,0 +1,71 @@ +// Copyright 2017 Baliance. All rights reserved. +package main + +import ( + "fmt" + "log" + + "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() + chart := dwng.AddChart() + // make it a bit wider than the default + dwng.BottomRight().SetCol(15) + + lc := chart.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 := chart.AddCategoryAxis() + va := chart.AddValueAxis() + lc.AddAxis(ca) + lc.AddAxis(va) + + ca.SetCrosses(va) + va.SetCrosses(ca) + + // add a title and legend + title := chart.AddTitle() + title.SetText("Items Sold") + chart.AddLegend() + + // 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("bar-chart.xlsx") +} diff --git a/chart/barchart.go b/chart/barchart.go index 931133b8..afd63e9b 100644 --- a/chart/barchart.go +++ b/chart/barchart.go @@ -7,10 +7,13 @@ package chart -import crt "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml/2006/chart" +import ( + crt "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml/2006/chart" +) // BarChart is a 2D bar chart. type BarChart struct { + chartBase x *crt.CT_BarChart } @@ -18,3 +21,33 @@ type BarChart struct { func (c BarChart) X() *crt.CT_BarChart { return c.x } + +// InitializeDefaults the bar chart to its defaults +func (c BarChart) InitializeDefaults() { + c.SetDirection(crt.ST_BarDirCol) +} + +// SetDirection changes the direction of the bar chart (bar or column). +func (c BarChart) SetDirection(d crt.ST_BarDir) { + c.x.BarDir.ValAttr = d +} + +// AddSeries adds a default series to a bar chart. +func (c BarChart) AddSeries() BarChartSeries { + clr := c.nextColor(len(c.x.Ser)) + ser := crt.NewCT_BarSer() + c.x.Ser = append(c.x.Ser, ser) + ser.Idx.ValAttr = uint32(len(c.x.Ser) - 1) + ser.Order.ValAttr = uint32(len(c.x.Ser) - 1) + + bs := BarChartSeries{ser} + bs.InitializeDefaults() + bs.Properties().SetSolidFill(clr) + return bs +} + +func (c BarChart) AddAxis(axis Axis) { + axisID := crt.NewCT_UnsignedInt() + axisID.ValAttr = axis.AxisID() + c.x.AxId = append(c.x.AxId, axisID) +} diff --git a/chart/barchartseries.go b/chart/barchartseries.go new file mode 100644 index 00000000..77ad1985 --- /dev/null +++ b/chart/barchartseries.go @@ -0,0 +1,55 @@ +// 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 chart + +import ( + "baliance.com/gooxml/drawing" + dml "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml" + crt "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml/2006/chart" +) + +type BarChartSeries struct { + x *crt.CT_BarSer +} + +// X returns the inner wrapped XML type. +func (c BarChartSeries) X() *crt.CT_BarSer { + return c.x +} + +// InitializeDefaults initializes a bar chart series to the default values. +func (c BarChartSeries) InitializeDefaults() { +} + +// SetText sets the series text +func (c BarChartSeries) SetText(s string) { + c.x.Tx = crt.NewCT_SerTx() + c.x.Tx.Choice.V = &s +} + +func (c BarChartSeries) CategoryAxis() AxisDataSource { + if c.x.Cat == nil { + c.x.Cat = crt.NewCT_AxDataSource() + } + return MakeAxisDataSource(c.x.Cat) +} + +func (c BarChartSeries) Values() NumberDataSource { + if c.x.Val == nil { + c.x.Val = crt.NewCT_NumDataSource() + } + return MakeNumberDataSource(c.x.Val) +} + +// Properties returns the bar chart series shape properties. +func (c BarChartSeries) Properties() drawing.ShapeProperties { + if c.x.SpPr == nil { + c.x.SpPr = dml.NewCT_ShapeProperties() + } + return drawing.MakeShapeProperties(c.x.SpPr) +} diff --git a/chart/chart.go b/chart/chart.go index c74db334..2b97bdb6 100644 --- a/chart/chart.go +++ b/chart/chart.go @@ -43,7 +43,7 @@ func (c Chart) AddLineChart() LineChart { // TODO: needed? chc.LineChart.Marker = crt.NewCT_Boolean() chc.LineChart.Marker.ValAttr = gooxml.Bool(true) - return LineChart{chc.LineChart} + return LineChart{x: chc.LineChart} } // AddBarChart adds a new bar chart to a chart. @@ -54,7 +54,9 @@ func (c Chart) AddBarChart() BarChart { chc.BarChart.Grouping = crt.NewCT_BarGrouping() chc.BarChart.Grouping.ValAttr = crt.ST_BarGroupingStandard - return BarChart{chc.BarChart} + b := BarChart{x: chc.BarChart} + b.InitializeDefaults() + return b } func (c Chart) Properties() drawing.ShapeProperties { diff --git a/chart/chartbase.go b/chart/chartbase.go new file mode 100644 index 00000000..0b6df7cf --- /dev/null +++ b/chart/chartbase.go @@ -0,0 +1,24 @@ +// 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 chart + +import "baliance.com/gooxml/color" + +var defaultColors = []color.Color{color.RGB(0x33, 0x66, 0xcc), color.RGB(0xDC, 0x39, 0x12), color.RGB(0xFF, 0x99, 0x00), + color.RGB(0x10, 0x96, 0x18), color.RGB(0x99, 0x00, 0x99), color.RGB(0x3B, 0x3E, 0xAC), color.RGB(0x00, 0x99, 0xC6), + color.RGB(0xDD, 0x44, 0x77), color.RGB(0x66, 0xAA, 0x00), color.RGB(0xB8, 0x2E, 0x2E), color.RGB(0x31, 0x63, 0x95), + color.RGB(0x99, 0x44, 0x99), color.RGB(0x22, 0xAA, 0x99), color.RGB(0xAA, 0xAA, 0x11), color.RGB(0x66, 0x33, 0xCC), + color.RGB(0xE6, 0x73, 0x00), color.RGB(0x8B, 0x07, 0x07), color.RGB(0x32, 0x92, 0x62), color.RGB(0x55, 0x74, 0xA6), + color.RGB(0x3B, 0x3E, 0xAC)} + +type chartBase struct { +} + +func (c chartBase) nextColor(idx int) color.Color { + return defaultColors[idx%len(defaultColors)] +} diff --git a/chart/linechart.go b/chart/linechart.go index 033b90d1..b3d2b4bd 100644 --- a/chart/linechart.go +++ b/chart/linechart.go @@ -8,11 +8,11 @@ package chart import ( - "baliance.com/gooxml/color" crt "baliance.com/gooxml/schema/schemas.openxmlformats.org/drawingml/2006/chart" ) type LineChart struct { + chartBase x *crt.CT_LineChart } @@ -21,20 +21,9 @@ func (c LineChart) X() *crt.CT_LineChart { return c.x } -var colors = []color.Color{color.RGB(0x33, 0x66, 0xcc), color.RGB(0xDC, 0x39, 0x12), color.RGB(0xFF, 0x99, 0x00), - color.RGB(0x10, 0x96, 0x18), color.RGB(0x99, 0x00, 0x99), color.RGB(0x3B, 0x3E, 0xAC), color.RGB(0x00, 0x99, 0xC6), - color.RGB(0xDD, 0x44, 0x77), color.RGB(0x66, 0xAA, 0x00), color.RGB(0xB8, 0x2E, 0x2E), color.RGB(0x31, 0x63, 0x95), - color.RGB(0x99, 0x44, 0x99), color.RGB(0x22, 0xAA, 0x99), color.RGB(0xAA, 0xAA, 0x11), color.RGB(0x66, 0x33, 0xCC), - color.RGB(0xE6, 0x73, 0x00), color.RGB(0x8B, 0x07, 0x07), color.RGB(0x32, 0x92, 0x62), color.RGB(0x55, 0x74, 0xA6), - color.RGB(0x3B, 0x3E, 0xAC)} - -func (c LineChart) nextColor() color.Color { - idx := len(c.x.Ser) - return colors[idx%len(colors)] -} - +// AddSeries adds a default series to a line chart. func (c LineChart) AddSeries() LineChartSeries { - color := c.nextColor() + color := c.nextColor(len(c.x.Ser)) ser := crt.NewCT_LineSer() c.x.Ser = append(c.x.Ser, ser) ser.Idx.ValAttr = uint32(len(c.x.Ser) - 1) @@ -46,6 +35,7 @@ func (c LineChart) AddSeries() LineChartSeries { return ls } +// AddAxis adds an axis to a line chart. func (c LineChart) AddAxis(axis Axis) { axisID := crt.NewCT_UnsignedInt() axisID.ValAttr = axis.AxisID()