Преглед изворни кода

New feature: sparkline supported

xuri пре 6 година
родитељ
комит
cbe919fdf6
7 измењених фајлова са 932 додато и 5 уклоњено
  1. 11 1
      excelize.go
  2. 1 1
      sheet.go
  3. 509 0
      sparkline.go
  4. 297 0
      sparkline_test.go
  5. 1 1
      styles.go
  6. 6 1
      xmlDrawing.go
  7. 107 1
      xmlWorksheet.go

+ 11 - 1
excelize.go

@@ -181,11 +181,21 @@ func checkSheet(xlsx *xlsxWorksheet) {
 // Office Excel 2007.
 // Office Excel 2007.
 func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
 func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
 	var oldXmlns = []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
 	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)
 	workbookMarshal = bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
 	return workbookMarshal
 	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
 // 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
 // Office Excel 2007 and 2010. This function will be remove value tag when met a
 // cell have a linked value. Reference
 // cell have a linked value. Reference

+ 1 - 1
sheet.go

@@ -232,7 +232,7 @@ func replaceRelationshipsBytes(content []byte) []byte {
 // a horrible hack to fix that after the XML marshalling is completed.
 // a horrible hack to fix that after the XML marshalling is completed.
 func replaceRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
 func replaceRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
 	oldXmlns := []byte(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
 	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)
 	return bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
 }
 }
 
 

+ 509 - 0
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,
+		})
+	}
+}

+ 297 - 0
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
+}

+ 1 - 1
styles.go

@@ -1010,7 +1010,7 @@ func (f *File) stylesReader() *xlsxStyleSheet {
 func (f *File) styleSheetWriter() {
 func (f *File) styleSheetWriter() {
 	if f.Styles != nil {
 	if f.Styles != nil {
 		output, _ := xml.Marshal(f.Styles)
 		output, _ := xml.Marshal(f.Styles)
-		f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpaceBytes(output))
+		f.saveFileList("xl/styles.xml", replaceStyleRelationshipsNameSpaceBytes(output))
 	}
 	}
 }
 }
 
 

+ 6 - 1
xmlDrawing.go

@@ -32,7 +32,9 @@ const (
 	NameSpaceDrawingMLSpreadSheet        = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
 	NameSpaceDrawingMLSpreadSheet        = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
 	NameSpaceSpreadSheet                 = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
 	NameSpaceSpreadSheet                 = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
 	NameSpaceSpreadSheetX14              = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/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"
 	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"
 	NameSpaceXML                         = "http://www.w3.org/XML/1998/namespace"
 	NameSpaceXMLSchemaInstance           = "http://www.w3.org/2001/XMLSchema-instance"
 	NameSpaceXMLSchemaInstance           = "http://www.w3.org/2001/XMLSchema-instance"
 	StrictSourceRelationship             = "http://purl.oclc.org/ooxml/officeDocument/relationships"
 	StrictSourceRelationship             = "http://purl.oclc.org/ooxml/officeDocument/relationships"
@@ -50,12 +52,15 @@ const (
 	ExtURIConditionalFormattings = "{78C0D931-6437-407D-A8EE-F0AAD7539E65}"
 	ExtURIConditionalFormattings = "{78C0D931-6437-407D-A8EE-F0AAD7539E65}"
 	ExtURIDataValidations        = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
 	ExtURIDataValidations        = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
 	ExtURISparklineGroups        = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"
 	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}"
 	ExtURIProtectedRanges        = "{FC87AEE6-9EDD-4A0A-B7FB-166176984837}"
 	ExtURIIgnoredErrors          = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
 	ExtURIIgnoredErrors          = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
 	ExtURIWebExtensions          = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
 	ExtURIWebExtensions          = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
 	ExtURITimelineRefs           = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
 	ExtURITimelineRefs           = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
 	ExtURIDrawingBlip            = "{28A0092B-C50C-407E-A947-70E740481C1C}"
 	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"}
 var supportImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff"}

+ 107 - 1
xmlWorksheet.go

@@ -238,6 +238,7 @@ type xlsxPageSetUpPr struct {
 // xlsxTabColor directly maps the tabColor element in the namespace currently I
 // xlsxTabColor directly maps the tabColor element in the namespace currently I
 // have not checked it for completeness - it does as much as I need.
 // have not checked it for completeness - it does as much as I need.
 type xlsxTabColor struct {
 type xlsxTabColor struct {
+	RGB   string  `xml:"rgb,attr,omitempty"`
 	Theme int     `xml:"theme,attr,omitempty"`
 	Theme int     `xml:"theme,attr,omitempty"`
 	Tint  float64 `xml:"tint,attr,omitempty"`
 	Tint  float64 `xml:"tint,attr,omitempty"`
 }
 }
@@ -336,7 +337,7 @@ type xlsxCustomSheetView struct {
 	PageSetup      *xlsxPageSetUp    `xml:"pageSetup"`
 	PageSetup      *xlsxPageSetUp    `xml:"pageSetup"`
 	HeaderFooter   *xlsxHeaderFooter `xml:"headerFooter"`
 	HeaderFooter   *xlsxHeaderFooter `xml:"headerFooter"`
 	AutoFilter     *xlsxAutoFilter   `xml:"autoFilter"`
 	AutoFilter     *xlsxAutoFilter   `xml:"autoFilter"`
-	ExtLst         *xlsxExt          `xml:"extLst"`
+	ExtLst         *xlsxExtLst       `xml:"extLst"`
 	GUID           string            `xml:"guid,attr"`
 	GUID           string            `xml:"guid,attr"`
 	Scale          int               `xml:"scale,attr,omitempty"`
 	Scale          int               `xml:"scale,attr,omitempty"`
 	ColorID        int               `xml:"colorId,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"`
 	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.
 // formatPanes directly maps the settings of the panes.
 type formatPanes struct {
 type formatPanes struct {
 	Freeze      bool   `json:"freeze"`
 	Freeze      bool   `json:"freeze"`