summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2019-08-04 20:24:59 +0800
committerxuri <xuri.me@gmail.com>2019-08-04 20:24:59 +0800
commitcbe919fdf6c00733513494680b89171b8b1b41a1 (patch)
tree429364a03ce2e01f672d4055974f6dec88c2e094
parent1092009541430c711676efb95b876598f59bb53c (diff)
New feature: sparkline supported
-rw-r--r--excelize.go12
-rw-r--r--sheet.go2
-rw-r--r--sparkline.go509
-rw-r--r--sparkline_test.go297
-rw-r--r--styles.go2
-rw-r--r--xmlDrawing.go7
-rw-r--r--xmlWorksheet.go108
7 files changed, 932 insertions, 5 deletions
diff --git a/excelize.go b/excelize.go
index c7eff10..6d014a0 100644
--- a/excelize.go
+++ b/excelize.go
@@ -181,11 +181,21 @@ func checkSheet(xlsx *xlsxWorksheet) {
// Office Excel 2007.
func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
var oldXmlns = []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
- var newXmlns = []byte(`<worksheet xr:uid="{00000000-0001-0000-0000-000000000000}" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac xr xr2 xr3" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
+ var newXmlns = []byte(`<worksheet xr:uid="{00000000-0001-0000-0000-000000000000}" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr6="http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" xmlns:xr10="http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" mc:Ignorable="x14ac xr xr2 xr3 xr6 xr10 x15" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
workbookMarshal = bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
return workbookMarshal
}
+// replaceStyleRelationshipsNameSpaceBytes provides a function to replace
+// xl/styles.xml XML tags to self-closing for compatible Microsoft Office
+// Excel 2007.
+func replaceStyleRelationshipsNameSpaceBytes(contentMarshal []byte) []byte {
+ var oldXmlns = []byte(`<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
+ var newXmlns = []byte(`<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac x16r2 xr xr9" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x16r2="http://schemas.microsoft.com/office/spreadsheetml/2015/02/main" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr9="http://schemas.microsoft.com/office/spreadsheetml/2016/revision9">`)
+ contentMarshal = bytes.Replace(contentMarshal, oldXmlns, newXmlns, -1)
+ return contentMarshal
+}
+
// UpdateLinkedValue fix linked values within a spreadsheet are not updating in
// Office Excel 2007 and 2010. This function will be remove value tag when met a
// cell have a linked value. Reference
diff --git a/sheet.go b/sheet.go
index 347f255..e02782a 100644
--- a/sheet.go
+++ b/sheet.go
@@ -232,7 +232,7 @@ func replaceRelationshipsBytes(content []byte) []byte {
// a horrible hack to fix that after the XML marshalling is completed.
func replaceRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
oldXmlns := []byte(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
- newXmlns := []byte(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x15" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main">`)
+ newXmlns := []byte(`<workbook xr:uid="{00000000-0001-0000-0000-000000000000}" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr6="http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" xmlns:xr10="http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" mc:Ignorable="x14ac xr xr2 xr3 xr6 xr10 x15" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
return bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
}
diff --git a/sparkline.go b/sparkline.go
new file mode 100644
index 0000000..73e125e
--- /dev/null
+++ b/sparkline.go
@@ -0,0 +1,509 @@
+// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+//
+// Package excelize providing a set of functions that allow you to write to
+// and read from XLSX files. Support reads and writes XLSX file generated by
+// Microsoft Excelâ„¢ 2007 and later. Support save file without losing original
+// charts of XLSX. This library needs Go version 1.8 or later.
+
+package excelize
+
+import (
+ "encoding/xml"
+ "errors"
+ "strings"
+)
+
+// addSparklineGroupByStyle provides a function to create x14:sparklineGroups
+// element by given sparkline style ID.
+func (f *File) addSparklineGroupByStyle(ID int) *xlsxX14SparklineGroup {
+ groups := []*xlsxX14SparklineGroup{
+ {
+ ColorSeries: &xlsxTabColor{Theme: 4, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 5},
+ ColorMarkers: &xlsxTabColor{Theme: 4, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 4, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 4, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 4},
+ ColorLow: &xlsxTabColor{Theme: 4},
+ }, // 0
+ {
+ ColorSeries: &xlsxTabColor{Theme: 4, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 5},
+ ColorMarkers: &xlsxTabColor{Theme: 4, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 4, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 4, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 4},
+ ColorLow: &xlsxTabColor{Theme: 4},
+ }, // 1
+ {
+ ColorSeries: &xlsxTabColor{Theme: 5, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 6},
+ ColorMarkers: &xlsxTabColor{Theme: 5, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 5, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 5, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 5},
+ ColorLow: &xlsxTabColor{Theme: 5},
+ }, // 2
+ {
+ ColorSeries: &xlsxTabColor{Theme: 6, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 7},
+ ColorMarkers: &xlsxTabColor{Theme: 6, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 6, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 6, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 6},
+ ColorLow: &xlsxTabColor{Theme: 6},
+ }, // 3
+ {
+ ColorSeries: &xlsxTabColor{Theme: 7, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 8},
+ ColorMarkers: &xlsxTabColor{Theme: 7, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 7, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 7, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 7},
+ ColorLow: &xlsxTabColor{Theme: 7},
+ }, // 4
+ {
+ ColorSeries: &xlsxTabColor{Theme: 8, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 9},
+ ColorMarkers: &xlsxTabColor{Theme: 8, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 8, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 8, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 8},
+ ColorLow: &xlsxTabColor{Theme: 8},
+ }, // 5
+ {
+ ColorSeries: &xlsxTabColor{Theme: 9, Tint: -0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 4},
+ ColorMarkers: &xlsxTabColor{Theme: 9, Tint: -0.499984740745262},
+ ColorFirst: &xlsxTabColor{Theme: 9, Tint: 0.39997558519241921},
+ ColorLast: &xlsxTabColor{Theme: 9, Tint: 0.39997558519241921},
+ ColorHigh: &xlsxTabColor{Theme: 9},
+ ColorLow: &xlsxTabColor{Theme: 9},
+ }, // 6
+ {
+ ColorSeries: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorNegative: &xlsxTabColor{Theme: 5},
+ ColorMarkers: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 5},
+ ColorLow: &xlsxTabColor{Theme: 5},
+ }, // 7
+ {
+ ColorSeries: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorNegative: &xlsxTabColor{Theme: 6},
+ ColorMarkers: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ }, // 8
+ {
+ ColorSeries: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorNegative: &xlsxTabColor{Theme: 7},
+ ColorMarkers: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ }, // 9
+ {
+ ColorSeries: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorNegative: &xlsxTabColor{Theme: 8},
+ ColorMarkers: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ }, // 10
+ {
+ ColorSeries: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorNegative: &xlsxTabColor{Theme: 9},
+ ColorMarkers: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ }, // 11
+ {
+ ColorSeries: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorNegative: &xlsxTabColor{Theme: 4},
+ ColorMarkers: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ }, // 12
+ {
+ ColorSeries: &xlsxTabColor{Theme: 4},
+ ColorNegative: &xlsxTabColor{Theme: 5},
+ ColorMarkers: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ }, // 13
+ {
+ ColorSeries: &xlsxTabColor{Theme: 5},
+ ColorNegative: &xlsxTabColor{Theme: 6},
+ ColorMarkers: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ }, // 14
+ {
+ ColorSeries: &xlsxTabColor{Theme: 6},
+ ColorNegative: &xlsxTabColor{Theme: 7},
+ ColorMarkers: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ }, // 15
+ {
+ ColorSeries: &xlsxTabColor{Theme: 7},
+ ColorNegative: &xlsxTabColor{Theme: 8},
+ ColorMarkers: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ }, // 16
+ {
+ ColorSeries: &xlsxTabColor{Theme: 8},
+ ColorNegative: &xlsxTabColor{Theme: 9},
+ ColorMarkers: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ }, // 17
+ {
+ ColorSeries: &xlsxTabColor{Theme: 9},
+ ColorNegative: &xlsxTabColor{Theme: 4},
+ ColorMarkers: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ }, // 18
+ {
+ ColorSeries: &xlsxTabColor{Theme: 4, Tint: 0.39997558519241921},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: -0.499984740745262},
+ ColorMarkers: &xlsxTabColor{Theme: 4, Tint: 0.79998168889431442},
+ ColorFirst: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 4, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 4, Tint: -0.499984740745262},
+ ColorLow: &xlsxTabColor{Theme: 4, Tint: -0.499984740745262},
+ }, // 19
+ {
+ ColorSeries: &xlsxTabColor{Theme: 5, Tint: 0.39997558519241921},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: -0.499984740745262},
+ ColorMarkers: &xlsxTabColor{Theme: 5, Tint: 0.79998168889431442},
+ ColorFirst: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 5, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 5, Tint: -0.499984740745262},
+ ColorLow: &xlsxTabColor{Theme: 5, Tint: -0.499984740745262},
+ }, // 20
+ {
+ ColorSeries: &xlsxTabColor{Theme: 6, Tint: 0.39997558519241921},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: -0.499984740745262},
+ ColorMarkers: &xlsxTabColor{Theme: 6, Tint: 0.79998168889431442},
+ ColorFirst: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 6, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 6, Tint: -0.499984740745262},
+ ColorLow: &xlsxTabColor{Theme: 6, Tint: -0.499984740745262},
+ }, // 21
+ {
+ ColorSeries: &xlsxTabColor{Theme: 7, Tint: 0.39997558519241921},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: -0.499984740745262},
+ ColorMarkers: &xlsxTabColor{Theme: 7, Tint: 0.79998168889431442},
+ ColorFirst: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 7, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 7, Tint: -0.499984740745262},
+ ColorLow: &xlsxTabColor{Theme: 7, Tint: -0.499984740745262},
+ }, // 22
+ {
+ ColorSeries: &xlsxTabColor{Theme: 8, Tint: 0.39997558519241921},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: -0.499984740745262},
+ ColorMarkers: &xlsxTabColor{Theme: 8, Tint: 0.79998168889431442},
+ ColorFirst: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 8, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 8, Tint: -0.499984740745262},
+ ColorLow: &xlsxTabColor{Theme: 8, Tint: -0.499984740745262},
+ }, // 23
+ {
+ ColorSeries: &xlsxTabColor{Theme: 9, Tint: 0.39997558519241921},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: -0.499984740745262},
+ ColorMarkers: &xlsxTabColor{Theme: 9, Tint: 0.79998168889431442},
+ ColorFirst: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 9, Tint: -0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 9, Tint: -0.499984740745262},
+ ColorLow: &xlsxTabColor{Theme: 9, Tint: -0.499984740745262},
+ }, // 24
+ {
+ ColorSeries: &xlsxTabColor{Theme: 1, Tint: 0.499984740745262},
+ ColorNegative: &xlsxTabColor{Theme: 1, Tint: 0.249977111117893},
+ ColorMarkers: &xlsxTabColor{Theme: 1, Tint: 0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 1, Tint: 0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 1, Tint: 0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 1, Tint: 0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 1, Tint: 0.249977111117893},
+ }, // 25
+ {
+ ColorSeries: &xlsxTabColor{Theme: 1, Tint: 0.34998626667073579},
+ ColorNegative: &xlsxTabColor{Theme: 0, Tint: 0.249977111117893},
+ ColorMarkers: &xlsxTabColor{Theme: 0, Tint: 0.249977111117893},
+ ColorFirst: &xlsxTabColor{Theme: 0, Tint: 0.249977111117893},
+ ColorLast: &xlsxTabColor{Theme: 0, Tint: 0.249977111117893},
+ ColorHigh: &xlsxTabColor{Theme: 0, Tint: 0.249977111117893},
+ ColorLow: &xlsxTabColor{Theme: 0, Tint: 0.249977111117893},
+ }, // 26
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF323232"},
+ ColorNegative: &xlsxTabColor{RGB: "FFD00000"},
+ ColorMarkers: &xlsxTabColor{RGB: "FFD00000"},
+ ColorFirst: &xlsxTabColor{RGB: "FFD00000"},
+ ColorLast: &xlsxTabColor{RGB: "FFD00000"},
+ ColorHigh: &xlsxTabColor{RGB: "FFD00000"},
+ ColorLow: &xlsxTabColor{RGB: "FFD00000"},
+ }, // 27
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF000000"},
+ ColorNegative: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorMarkers: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorFirst: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorLast: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorHigh: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorLow: &xlsxTabColor{RGB: "FF0070C0"},
+ }, // 28
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF376092"},
+ ColorNegative: &xlsxTabColor{RGB: "FFD00000"},
+ ColorMarkers: &xlsxTabColor{RGB: "FFD00000"},
+ ColorFirst: &xlsxTabColor{RGB: "FFD00000"},
+ ColorLast: &xlsxTabColor{RGB: "FFD00000"},
+ ColorHigh: &xlsxTabColor{RGB: "FFD00000"},
+ ColorLow: &xlsxTabColor{RGB: "FFD00000"},
+ }, // 29
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorNegative: &xlsxTabColor{RGB: "FF000000"},
+ ColorMarkers: &xlsxTabColor{RGB: "FF000000"},
+ ColorFirst: &xlsxTabColor{RGB: "FF000000"},
+ ColorLast: &xlsxTabColor{RGB: "FF000000"},
+ ColorHigh: &xlsxTabColor{RGB: "FF000000"},
+ ColorLow: &xlsxTabColor{RGB: "FF000000"},
+ }, // 30
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF5F5F5F"},
+ ColorNegative: &xlsxTabColor{RGB: "FFFFB620"},
+ ColorMarkers: &xlsxTabColor{RGB: "FFD70077"},
+ ColorFirst: &xlsxTabColor{RGB: "FF5687C2"},
+ ColorLast: &xlsxTabColor{RGB: "FF359CEB"},
+ ColorHigh: &xlsxTabColor{RGB: "FF56BE79"},
+ ColorLow: &xlsxTabColor{RGB: "FFFF5055"},
+ }, // 31
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF5687C2"},
+ ColorNegative: &xlsxTabColor{RGB: "FFFFB620"},
+ ColorMarkers: &xlsxTabColor{RGB: "FFD70077"},
+ ColorFirst: &xlsxTabColor{RGB: "FF777777"},
+ ColorLast: &xlsxTabColor{RGB: "FF359CEB"},
+ ColorHigh: &xlsxTabColor{RGB: "FF56BE79"},
+ ColorLow: &xlsxTabColor{RGB: "FFFF5055"},
+ }, // 32
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FFC6EFCE"},
+ ColorNegative: &xlsxTabColor{RGB: "FFFFC7CE"},
+ ColorMarkers: &xlsxTabColor{RGB: "FF8CADD6"},
+ ColorFirst: &xlsxTabColor{RGB: "FFFFDC47"},
+ ColorLast: &xlsxTabColor{RGB: "FFFFEB9C"},
+ ColorHigh: &xlsxTabColor{RGB: "FF60D276"},
+ ColorLow: &xlsxTabColor{RGB: "FFFF5367"},
+ }, // 33
+ {
+ ColorSeries: &xlsxTabColor{RGB: "FF00B050"},
+ ColorNegative: &xlsxTabColor{RGB: "FFFF0000"},
+ ColorMarkers: &xlsxTabColor{RGB: "FF0070C0"},
+ ColorFirst: &xlsxTabColor{RGB: "FFFFC000"},
+ ColorLast: &xlsxTabColor{RGB: "FFFFC000"},
+ ColorHigh: &xlsxTabColor{RGB: "FF00B050"},
+ ColorLow: &xlsxTabColor{RGB: "FFFF0000"},
+ }, // 34
+ {
+ ColorSeries: &xlsxTabColor{Theme: 3},
+ ColorNegative: &xlsxTabColor{Theme: 9},
+ ColorMarkers: &xlsxTabColor{Theme: 8},
+ ColorFirst: &xlsxTabColor{Theme: 4},
+ ColorLast: &xlsxTabColor{Theme: 5},
+ ColorHigh: &xlsxTabColor{Theme: 6},
+ ColorLow: &xlsxTabColor{Theme: 7},
+ }, // 35
+ {
+ ColorSeries: &xlsxTabColor{Theme: 1},
+ ColorNegative: &xlsxTabColor{Theme: 9},
+ ColorMarkers: &xlsxTabColor{Theme: 8},
+ ColorFirst: &xlsxTabColor{Theme: 4},
+ ColorLast: &xlsxTabColor{Theme: 5},
+ ColorHigh: &xlsxTabColor{Theme: 6},
+ ColorLow: &xlsxTabColor{Theme: 7},
+ }, // 36
+ }
+ return groups[ID]
+}
+
+// AddSparkline provides a function to add sparklines to the worksheet by
+// given formatting options. Sparklines are small charts that fit in a single
+// cell and are used to show trends in data. Sparklines are a feature of Excel
+// 2010 and later only. You can write them to an XLSX file that can be read by
+// Excel 2007 but they won't be displayed. For example, add a grouped
+// sparkline. Changes are applied to all three:
+//
+// err := f.AddSparkline("Sheet1", &excelize.SparklineOption{
+// Location: []string{"A1", "A2", "A3"},
+// Range: []string{"Sheet2!A1:J1", "Sheet2!A2:J2", "Sheet2!A3:J3"},
+// Markers: true,
+// })
+//
+// The following shows the formatting options of sparkline supported by excelize:
+//
+// Parameter | Description
+// -----------+--------------------------------------------
+// Location | Required, must have the same number with 'Range' parameter
+// Range |Required, must have the same number with 'Location' parameter
+// Type | Enumeration value: line, column, win_loss
+// Style | Value range: 0 - 35
+// Hight | Toggle sparkine high points
+// Low | Toggle sparkine low points
+// First | Toggle sparkine first points
+// Last | Toggle sparkine last points
+// Negative | Toggle sparkine negative points
+// Markers | Toggle sparkine markers
+// ColorAxis | An RGB Color is specified as RRGGBB
+// Axis | Show sparkline axis
+//
+func (f *File) AddSparkline(sheet string, opt *SparklineOption) error {
+ // parameter validation
+ ws, err := f.parseFormatAddSparklineSet(sheet, opt)
+ if err != nil {
+ return err
+ }
+ // Handle the sparkline type
+ sparkType := "line"
+ sparkTypes := map[string]string{"line": "line", "column": "column", "win_loss": "stacked"}
+ if opt.Type != "" {
+ specifiedSparkTypes, ok := sparkTypes[opt.Type]
+ if !ok {
+ return errors.New("parameter 'Type' must be 'line', 'column' or 'win_loss'")
+ }
+ sparkType = specifiedSparkTypes
+ }
+ group := f.addSparklineGroupByStyle(opt.Style)
+ group.Type = sparkType
+ group.ColorAxis = &xlsxColor{RGB: "FF000000"}
+ group.DisplayEmptyCellsAs = "gap"
+ group.High = opt.High
+ group.Low = opt.Low
+ group.First = opt.First
+ group.Last = opt.Last
+ group.Negative = opt.Negative
+ group.DisplayXAxis = opt.Axis
+ group.Markers = opt.Markers
+ if opt.SeriesColor != "" {
+ group.ColorSeries = &xlsxTabColor{
+ RGB: getPaletteColor(opt.SeriesColor),
+ }
+ }
+ if opt.Reverse {
+ group.RightToLeft = opt.Reverse
+ }
+ f.addSparkline(opt, group)
+ if ws.ExtLst.Ext != "" { // append mode ext
+ decodeExtLst := decodeWorksheetExt{}
+ err = xml.Unmarshal([]byte("<extLst>"+ws.ExtLst.Ext+"</extLst>"), &decodeExtLst)
+ if err != nil {
+ return err
+ }
+ for idx, ext := range decodeExtLst.Ext {
+ // hack: add back missing namespace
+ decodeExtLst.Ext[idx].XMLNSX14 = decodeExtLst.Ext[idx].X14
+ decodeExtLst.Ext[idx].XMLNSX15 = decodeExtLst.Ext[idx].X15
+ decodeExtLst.Ext[idx].XMLNSX14 = ""
+ decodeExtLst.Ext[idx].XMLNSX15 = ""
+ if ext.URI == ExtURISparklineGroups {
+ decodeSparklineGroups := decodeX14SparklineGroups{}
+ _ = xml.Unmarshal([]byte(ext.Content), &decodeSparklineGroups)
+ sparklineGroupBytes, _ := xml.Marshal(group)
+ groups := xlsxX14SparklineGroups{
+ XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
+ Content: decodeSparklineGroups.Content + string(sparklineGroupBytes),
+ }
+ sparklineGroupsBytes, _ := xml.Marshal(groups)
+ decodeExtLst.Ext[idx].Content = string(sparklineGroupsBytes)
+ }
+ }
+ extLstBytes, _ := xml.Marshal(decodeExtLst)
+ extLst := string(extLstBytes)
+ ws.ExtLst = &xlsxExtLst{
+ Ext: strings.TrimSuffix(strings.TrimPrefix(extLst, "<extLst>"), "</extLst>"),
+ }
+ } else {
+ groups := xlsxX14SparklineGroups{
+ XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
+ SparklineGroups: []*xlsxX14SparklineGroup{group},
+ }
+ sparklineGroupsBytes, _ := xml.Marshal(groups)
+ extLst := xlsxWorksheetExt{
+ XMLNSX14: NameSpaceSpreadSheetX14,
+ URI: ExtURISparklineGroups,
+ Content: string(sparklineGroupsBytes),
+ }
+ extBytes, _ := xml.Marshal(extLst)
+ ws.ExtLst.Ext = string(extBytes)
+ }
+ return nil
+}
+
+// parseFormatAddSparklineSet provides a function to validate sparkline
+// properties.
+func (f *File) parseFormatAddSparklineSet(sheet string, opt *SparklineOption) (*xlsxWorksheet, error) {
+ ws, err := f.workSheetReader(sheet)
+ if err != nil {
+ return ws, err
+ }
+ if opt == nil {
+ return ws, errors.New("parameter is required")
+ }
+ if len(opt.Location) < 1 {
+ return ws, errors.New("parameter 'Location' is required")
+ }
+ if len(opt.Range) < 1 {
+ return ws, errors.New("parameter 'Range' is required")
+ }
+ // The ranges and locations must match.\
+ if len(opt.Location) != len(opt.Range) {
+ return ws, errors.New(`must have the same number of 'Location' and 'Range' parameters`)
+ }
+ if opt.Style < 0 || opt.Style > 35 {
+ return ws, errors.New("parameter 'Style' must betweent 0-35")
+ }
+ if ws.ExtLst == nil {
+ ws.ExtLst = &xlsxExtLst{}
+ }
+ return ws, err
+}
+
+// addSparkline provides a function to create a sparkline in a sparkline group
+// by given properties.
+func (f *File) addSparkline(opt *SparklineOption, group *xlsxX14SparklineGroup) {
+ for idx, location := range opt.Location {
+ group.Sparklines.Sparkline = append(group.Sparklines.Sparkline, &xlsxX14Sparkline{
+ F: opt.Range[idx],
+ Sqref: location,
+ })
+ }
+}
diff --git a/sparkline_test.go b/sparkline_test.go
new file mode 100644
index 0000000..d52929b
--- /dev/null
+++ b/sparkline_test.go
@@ -0,0 +1,297 @@
+package excelize
+
+import (
+ "fmt"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAddSparkline(t *testing.T) {
+ f := prepareSparklineDataset()
+
+ // Set the columns widths to make the output clearer
+ style, err := f.NewStyle(`{"font":{"bold":true}}`)
+ assert.NoError(t, err)
+ assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "B1", style))
+ assert.NoError(t, f.SetSheetViewOptions("Sheet1", 0, ZoomScale(150)))
+
+ f.SetColWidth("Sheet1", "A", "A", 14)
+ f.SetColWidth("Sheet1", "B", "B", 50)
+ // Headings
+ f.SetCellValue("Sheet1", "A1", "Sparkline")
+ f.SetCellValue("Sheet1", "B1", "Description")
+
+ f.SetCellValue("Sheet1", "B2", `A default "line" sparkline.`)
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A2"},
+ Range: []string{"Sheet3!A1:J1"},
+ }))
+
+ f.SetCellValue("Sheet1", "B3", `A default "column" sparkline.`)
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A3"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ }))
+
+ f.SetCellValue("Sheet1", "B4", `A default "win/loss" sparkline.`)
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A4"},
+ Range: []string{"Sheet3!A3:J3"},
+ Type: "win_loss",
+ }))
+
+ f.SetCellValue("Sheet1", "B6", "Line with markers.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A6"},
+ Range: []string{"Sheet3!A1:J1"},
+ Markers: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B7", "Line with high and low points.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A7"},
+ Range: []string{"Sheet3!A1:J1"},
+ High: true,
+ Low: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B8", "Line with first and last point markers.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A8"},
+ Range: []string{"Sheet3!A1:J1"},
+ First: true,
+ Last: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B9", "Line with negative point markers.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A9"},
+ Range: []string{"Sheet3!A1:J1"},
+ Negative: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B10", "Line with axis.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A10"},
+ Range: []string{"Sheet3!A1:J1"},
+ Axis: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B12", "Column with default style (1).")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A12"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ }))
+
+ f.SetCellValue("Sheet1", "B13", "Column with style 2.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A13"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ Style: 2,
+ }))
+
+ f.SetCellValue("Sheet1", "B14", "Column with style 3.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A14"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ Style: 3,
+ }))
+
+ f.SetCellValue("Sheet1", "B15", "Column with style 4.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A15"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ Style: 4,
+ }))
+
+ f.SetCellValue("Sheet1", "B16", "Column with style 5.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A16"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ Style: 5,
+ }))
+
+ f.SetCellValue("Sheet1", "B17", "Column with style 6.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A17"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ Style: 6,
+ }))
+
+ f.SetCellValue("Sheet1", "B18", "Column with a user defined color.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A18"},
+ Range: []string{"Sheet3!A2:J2"},
+ Type: "column",
+ SeriesColor: "#E965E0",
+ }))
+
+ f.SetCellValue("Sheet1", "B20", "A win/loss sparkline.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A20"},
+ Range: []string{"Sheet3!A3:J3"},
+ Type: "win_loss",
+ }))
+
+ f.SetCellValue("Sheet1", "B21", "A win/loss sparkline with negative points highlighted.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A21"},
+ Range: []string{"Sheet3!A3:J3"},
+ Type: "win_loss",
+ Negative: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B23", "A left to right column (the default).")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A23"},
+ Range: []string{"Sheet3!A4:J4"},
+ Type: "column",
+ Style: 20,
+ }))
+
+ f.SetCellValue("Sheet1", "B24", "A right to left column.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A24"},
+ Range: []string{"Sheet3!A4:J4"},
+ Type: "column",
+ Style: 20,
+ Reverse: true,
+ }))
+
+ f.SetCellValue("Sheet1", "B25", "Sparkline and text in one cell.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A25"},
+ Range: []string{"Sheet3!A4:J4"},
+ Type: "column",
+ Style: 20,
+ }))
+ f.SetCellValue("Sheet1", "A25", "Growth")
+
+ f.SetCellValue("Sheet1", "B27", "A grouped sparkline. Changes are applied to all three.")
+ assert.NoError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A27", "A28", "A29"},
+ Range: []string{"Sheet3!A5:J5", "Sheet3!A6:J6", "Sheet3!A7:J7"},
+ Markers: true,
+ }))
+
+ // Sheet2 sections
+ assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
+ Location: []string{"F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ Type: "win_loss",
+ Negative: true,
+ }))
+
+ assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
+ Location: []string{"F1"},
+ Range: []string{"Sheet2!A1:E1"},
+ Markers: true,
+ }))
+
+ assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
+ Location: []string{"F2"},
+ Range: []string{"Sheet2!A2:E2"},
+ Type: "column",
+ Style: 12,
+ }))
+
+ assert.NoError(t, f.AddSparkline("Sheet2", &SparklineOption{
+ Location: []string{"F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ Type: "win_loss",
+ Negative: true,
+ }))
+
+ // Save xlsx file by the given path.
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddSparkline.xlsx")))
+
+ // Test error exceptions
+ assert.EqualError(t, f.AddSparkline("SheetN", &SparklineOption{
+ Location: []string{"F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ }), "sheet SheetN is not exist")
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", nil), "parameter is required")
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Range: []string{"Sheet2!A3:E3"},
+ }), `parameter 'Location' is required`)
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"F3"},
+ }), `parameter 'Range' is required`)
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"F2", "F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ }), `must have the same number of 'Location' and 'Range' parameters`)
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ Type: "unknown_type",
+ }), `parameter 'Type' must be 'line', 'column' or 'win_loss'`)
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ Style: -1,
+ }), `parameter 'Style' must betweent 0-35`)
+
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"F3"},
+ Range: []string{"Sheet2!A3:E3"},
+ Style: -1,
+ }), `parameter 'Style' must betweent 0-35`)
+
+ f.Sheet["xl/worksheets/sheet1.xml"].ExtLst.Ext = `<extLst>
+ <ext x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}">
+ <x14:sparklineGroups
+ xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main">
+ <x14:sparklineGroup>
+ </x14:sparklines>
+ </x14:sparklineGroup>
+ </x14:sparklineGroups>
+ </ext>
+ </extLst>`
+ assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOption{
+ Location: []string{"A2"},
+ Range: []string{"Sheet3!A1:J1"},
+ }), "XML syntax error on line 6: element <sparklineGroup> closed by </sparklines>")
+}
+
+func prepareSparklineDataset() *File {
+ f := NewFile()
+ sheet2 := [][]int{
+ {-2, 2, 3, -1, 0},
+ {30, 20, 33, 20, 15},
+ {1, -1, -1, 1, -1},
+ }
+ sheet3 := [][]int{
+ {-2, 2, 3, -1, 0, -2, 3, 2, 1, 0},
+ {30, 20, 33, 20, 15, 5, 5, 15, 10, 15},
+ {1, 1, -1, -1, 1, -1, 1, 1, 1, -1},
+ {5, 6, 7, 10, 15, 20, 30, 50, 70, 100},
+ {-2, 2, 3, -1, 0, -2, 3, 2, 1, 0},
+ {3, -1, 0, -2, 3, 2, 1, 0, 2, 1},
+ {0, -2, 3, 2, 1, 0, 1, 2, 3, 1},
+ }
+ f.NewSheet("Sheet2")
+ f.NewSheet("Sheet3")
+ for row, data := range sheet2 {
+ f.SetSheetRow("Sheet2", fmt.Sprintf("A%d", row+1), &data)
+ }
+ for row, data := range sheet3 {
+ f.SetSheetRow("Sheet3", fmt.Sprintf("A%d", row+1), &data)
+ }
+ return f
+}
diff --git a/styles.go b/styles.go
index b246e30..04a5c33 100644
--- a/styles.go
+++ b/styles.go
@@ -1010,7 +1010,7 @@ func (f *File) stylesReader() *xlsxStyleSheet {
func (f *File) styleSheetWriter() {
if f.Styles != nil {
output, _ := xml.Marshal(f.Styles)
- f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpaceBytes(output))
+ f.saveFileList("xl/styles.xml", replaceStyleRelationshipsNameSpaceBytes(output))
}
}
diff --git a/xmlDrawing.go b/xmlDrawing.go
index 2f75eef..20cb83d 100644
--- a/xmlDrawing.go
+++ b/xmlDrawing.go
@@ -32,7 +32,9 @@ const (
NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
NameSpaceSpreadSheetX14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
+ NameSpaceSpreadSheetX15 = "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
NameSpaceSpreadSheetExcel2006Main = "http://schemas.microsoft.com/office/excel/2006/main"
+ NameSpaceMacExcel2008Main = "http://schemas.microsoft.com/office/mac/excel/2008/main"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
StrictSourceRelationship = "http://purl.oclc.org/ooxml/officeDocument/relationships"
@@ -50,12 +52,15 @@ const (
ExtURIConditionalFormattings = "{78C0D931-6437-407D-A8EE-F0AAD7539E65}"
ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
ExtURISparklineGroups = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"
- ExtURISlicerList = "{A8765BA9-456A-4DAB-B4F3-ACF838C121DE}"
+ ExtURISlicerListX14 = "{A8765BA9-456A-4DAB-B4F3-ACF838C121DE}"
+ ExtURISlicerCachesListX14 = "{BBE1A952-AA13-448e-AADC-164F8A28A991}"
+ ExtURISlicerListX15 = "{3A4CF648-6AED-40f4-86FF-DC5316D8AED3}"
ExtURIProtectedRanges = "{FC87AEE6-9EDD-4A0A-B7FB-166176984837}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
ExtURIWebExtensions = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
ExtURITimelineRefs = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
+ ExtURIMacExcelMX = "{64002731-A6B0-56B0-2670-7721B7C09600}"
)
var supportImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff"}
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index b94c521..7168df6 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -238,6 +238,7 @@ type xlsxPageSetUpPr struct {
// xlsxTabColor directly maps the tabColor element in the namespace currently I
// have not checked it for completeness - it does as much as I need.
type xlsxTabColor struct {
+ RGB string `xml:"rgb,attr,omitempty"`
Theme int `xml:"theme,attr,omitempty"`
Tint float64 `xml:"tint,attr,omitempty"`
}
@@ -336,7 +337,7 @@ type xlsxCustomSheetView struct {
PageSetup *xlsxPageSetUp `xml:"pageSetup"`
HeaderFooter *xlsxHeaderFooter `xml:"headerFooter"`
AutoFilter *xlsxAutoFilter `xml:"autoFilter"`
- ExtLst *xlsxExt `xml:"extLst"`
+ ExtLst *xlsxExtLst `xml:"extLst"`
GUID string `xml:"guid,attr"`
Scale int `xml:"scale,attr,omitempty"`
ColorID int `xml:"colorId,attr,omitempty"`
@@ -632,6 +633,111 @@ type xlsxLegacyDrawing struct {
RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"`
}
+// xlsxWorksheetExt directly maps the ext element in the worksheet.
+type xlsxWorksheetExt struct {
+ XMLName xml.Name `xml:"ext"`
+ XMLNSX14 string `xml:"xmlns:x14,attr,omitempty"`
+ XMLNSX15 string `xml:"xmlns:x15,attr,omitempty"`
+ X14 string `xml:"x14,attr,omitempty"`
+ X15 string `xml:"x15,attr,omitempty"`
+ URI string `xml:"uri,attr"`
+ Content string `xml:",innerxml"`
+}
+
+// decodeWorksheetExt directly maps the ext element.
+type decodeWorksheetExt struct {
+ XMLName xml.Name `xml:"extLst"`
+ Ext []*xlsxWorksheetExt `xml:"ext"`
+}
+
+// decodeX14SparklineGroups directly maps the sparklineGroups element.
+type decodeX14SparklineGroups struct {
+ XMLName xml.Name `xml:"sparklineGroups"`
+ XMLNSXM string `xml:"xmlns:xm,attr"`
+ Content string `xml:",innerxml"`
+}
+
+// xlsxX14SparklineGroups directly maps the sparklineGroups element.
+type xlsxX14SparklineGroups struct {
+ XMLName xml.Name `xml:"x14:sparklineGroups"`
+ XMLNSXM string `xml:"xmlns:xm,attr"`
+ SparklineGroups []*xlsxX14SparklineGroup `xml:"x14:sparklineGroup"`
+ Content string `xml:",innerxml"`
+}
+
+// xlsxX14SparklineGroup directly maps the sparklineGroup element.
+type xlsxX14SparklineGroup struct {
+ XMLName xml.Name `xml:"x14:sparklineGroup"`
+ ManualMax int `xml:"manualMax,attr,omitempty"`
+ ManualMin int `xml:"manualMin,attr,omitempty"`
+ LineWeight float64 `xml:"lineWeight,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ DateAxis bool `xml:"dateAxis,attr,omitempty"`
+ DisplayEmptyCellsAs string `xml:"displayEmptyCellsAs,attr,omitempty"`
+ Markers bool `xml:"markers,attr,omitempty"`
+ High bool `xml:"high,attr,omitempty"`
+ Low bool `xml:"low,attr,omitempty"`
+ First bool `xml:"first,attr,omitempty"`
+ Last bool `xml:"last,attr,omitempty"`
+ Negative bool `xml:"negative,attr,omitempty"`
+ DisplayXAxis bool `xml:"displayXAxis,attr,omitempty"`
+ DisplayHidden bool `xml:"displayHidden,attr,omitempty"`
+ MinAxisType string `xml:"minAxisType,attr,omitempty"`
+ MaxAxisType string `xml:"maxAxisType,attr,omitempty"`
+ RightToLeft bool `xml:"rightToLeft,attr,omitempty"`
+ ColorSeries *xlsxTabColor `xml:"x14:colorSeries"`
+ ColorNegative *xlsxTabColor `xml:"x14:colorNegative"`
+ ColorAxis *xlsxColor `xml:"x14:colorAxis"`
+ ColorMarkers *xlsxTabColor `xml:"x14:colorMarkers"`
+ ColorFirst *xlsxTabColor `xml:"x14:colorFirst"`
+ ColorLast *xlsxTabColor `xml:"x14:colorLast"`
+ ColorHigh *xlsxTabColor `xml:"x14:colorHigh"`
+ ColorLow *xlsxTabColor `xml:"x14:colorLow"`
+ Sparklines xlsxX14Sparklines `xml:"x14:sparklines"`
+}
+
+// xlsxX14Sparklines directly maps the sparklines element.
+type xlsxX14Sparklines struct {
+ Sparkline []*xlsxX14Sparkline `xml:"x14:sparkline"`
+}
+
+// xlsxX14Sparkline directly maps the sparkline element.
+type xlsxX14Sparkline struct {
+ F string `xml:"xm:f"`
+ Sqref string `xml:"xm:sqref"`
+}
+
+// SparklineOption directly maps the settings of the sparkline.
+type SparklineOption struct {
+ Location []string
+ Range []string
+ Max int
+ CustMax int
+ Min int
+ CustMin int
+ Type string
+ Weight float64
+ DateAxis bool
+ Markers bool
+ High bool
+ Low bool
+ First bool
+ Last bool
+ Negative bool
+ Axis bool
+ Hidden bool
+ Reverse bool
+ Style int
+ SeriesColor string
+ NegativeColor string
+ MarkersColor string
+ FirstColor string
+ LastColor string
+ HightColor string
+ LowColor string
+ EmptyCells string
+}
+
// formatPanes directly maps the settings of the panes.
type formatPanes struct {
Freeze bool `json:"freeze"`