|  | /******************************************************************************* | 
|  | * You may amend and distribute as you like, but don't remove this header! | 
|  | * | 
|  | * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | 
|  | * See http://www.codeplex.com/EPPlus for details. | 
|  | * | 
|  | * Copyright (C) 2011  Jan Källman | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | * See the GNU Lesser General Public License for more details. | 
|  | * | 
|  | * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | 
|  | * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | 
|  | * | 
|  | * All code and executables are provided "as is" with no warranty either express or implied. | 
|  | * The author accepts no liability for any damage or loss of business that this product may cause. | 
|  | * | 
|  | * Code change notes: | 
|  | * | 
|  | * Author							Change						Date | 
|  | ******************************************************************************* | 
|  | * Jan Källman		Added		2009-10-01 | 
|  | * Jan Källman		License changed GPL-->LGPL 2011-12-16 | 
|  | *******************************************************************************/ | 
|  | using System; | 
|  | using System.Collections.Generic; | 
|  | using System.Text; | 
|  | using System.Xml; | 
|  | using System.Collections; | 
|  | using OfficeOpenXml.Table.PivotTable; | 
|  | namespace OfficeOpenXml.Drawing.Chart | 
|  | { | 
|  | public sealed class ExcelBubbleChartSeries : ExcelChartSeries | 
|  | { | 
|  | internal ExcelBubbleChartSeries(ExcelChart chart, XmlNamespaceManager ns, XmlNode node, bool isPivot) | 
|  | : base(chart,ns,node, isPivot) | 
|  | { | 
|  | //_chartSeries = new ExcelChartSeries(this, _drawings.NameSpaceManager, _chartNode, isPivot); | 
|  | } | 
|  | public ExcelChartSerie Add(ExcelRangeBase Serie, ExcelRangeBase XSerie, ExcelRangeBase BubbleSize) | 
|  | { | 
|  | return base.AddSeries(Serie.FullAddressAbsolute, XSerie.FullAddressAbsolute, BubbleSize.FullAddressAbsolute); | 
|  | } | 
|  | public ExcelChartSerie Add(string SerieAddress, string XSerieAddress, string BubbleSizeAddress) | 
|  | { | 
|  | return base.AddSeries(SerieAddress, XSerieAddress, BubbleSizeAddress); | 
|  | } | 
|  | } | 
|  | /// <summary> | 
|  | /// Collection class for chart series | 
|  | /// </summary> | 
|  | public class ExcelChartSeries : XmlHelper, IEnumerable | 
|  | { | 
|  | List<ExcelChartSerie> _list=new List<ExcelChartSerie>(); | 
|  | internal ExcelChart _chart; | 
|  | XmlNode _node; | 
|  | XmlNamespaceManager _ns; | 
|  | internal ExcelChartSeries(ExcelChart chart, XmlNamespaceManager ns, XmlNode node, bool isPivot) | 
|  | : base(ns,node) | 
|  | { | 
|  | _ns = ns; | 
|  | _chart=chart; | 
|  | _node=node; | 
|  | _isPivot = isPivot; | 
|  | SchemaNodeOrder = new string[] { "view3D", "plotArea", "barDir", "grouping", "scatterStyle", "varyColors", "ser", "explosion", "dLbls", "firstSliceAng", "holeSize", "shape", "legend", "axId" }; | 
|  | foreach(XmlNode n in node.SelectNodes("c:ser",ns)) | 
|  | { | 
|  | ExcelChartSerie s; | 
|  | if (chart.ChartNode.LocalName == "scatterChart") | 
|  | { | 
|  | s = new ExcelScatterChartSerie(this, ns, n, isPivot); | 
|  | } | 
|  | else if (chart.ChartNode.LocalName == "lineChart") | 
|  | { | 
|  | s = new ExcelLineChartSerie(this, ns, n, isPivot); | 
|  | } | 
|  | else if (chart.ChartNode.LocalName == "pieChart" || | 
|  | chart.ChartNode.LocalName == "ofPieChart" || | 
|  | chart.ChartNode.LocalName == "pie3DChart" || | 
|  | chart.ChartNode.LocalName == "doughnutChart") | 
|  | { | 
|  | s = new ExcelPieChartSerie(this, ns, n, isPivot); | 
|  | } | 
|  | else | 
|  | { | 
|  | s = new ExcelChartSerie(this, ns, n, isPivot); | 
|  | } | 
|  | _list.Add(s); | 
|  | } | 
|  | } | 
|  |  | 
|  | #region IEnumerable Members | 
|  |  | 
|  | public IEnumerator GetEnumerator() | 
|  | { | 
|  | return (_list.GetEnumerator()); | 
|  | } | 
|  | /// <summary> | 
|  | /// Returns the serie at the specified position. | 
|  | /// </summary> | 
|  | /// <param name="PositionID">The position of the series.</param> | 
|  | /// <returns></returns> | 
|  | public ExcelChartSerie this[int PositionID] | 
|  | { | 
|  | get | 
|  | { | 
|  | return (_list[PositionID]); | 
|  | } | 
|  | } | 
|  | public int Count | 
|  | { | 
|  | get | 
|  | { | 
|  | return _list.Count; | 
|  | } | 
|  | } | 
|  | /// <summary> | 
|  | /// Delete the chart at the specific position | 
|  | /// </summary> | 
|  | /// <param name="PositionID">Zero based</param> | 
|  | public void Delete(int PositionID) | 
|  | { | 
|  | ExcelChartSerie ser = _list[PositionID]; | 
|  | ser.TopNode.ParentNode.RemoveChild(ser.TopNode); | 
|  | _list.RemoveAt(PositionID); | 
|  | } | 
|  | #endregion | 
|  | /// <summary> | 
|  | /// A reference to the chart object | 
|  | /// </summary> | 
|  | public ExcelChart Chart | 
|  | { | 
|  | get | 
|  | { | 
|  | return _chart; | 
|  | } | 
|  | } | 
|  | #region "Add Series" | 
|  |  | 
|  | /// <summary> | 
|  | /// Add a new serie to the chart. Do not apply to pivotcharts. | 
|  | /// </summary> | 
|  | /// <param name="Serie">The Y-Axis range</param> | 
|  | /// <param name="XSerie">The X-Axis range</param> | 
|  | /// <returns></returns> | 
|  | public virtual ExcelChartSerie Add(ExcelRangeBase Serie, ExcelRangeBase XSerie) | 
|  | { | 
|  | if (_chart.PivotTableSource != null) | 
|  | { | 
|  | throw (new InvalidOperationException("Can't add a serie to a pivotchart")); | 
|  | } | 
|  | return AddSeries(Serie.FullAddressAbsolute, XSerie.FullAddressAbsolute,""); | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a new serie to the chart.Do not apply to pivotcharts. | 
|  | /// </summary> | 
|  | /// <param name="SerieAddress">The Y-Axis range</param> | 
|  | /// <param name="XSerieAddress">The X-Axis range</param> | 
|  | /// <returns></returns> | 
|  | public virtual ExcelChartSerie Add(string SerieAddress, string XSerieAddress) | 
|  | { | 
|  | if (_chart.PivotTableSource != null) | 
|  | { | 
|  | throw (new InvalidOperationException("Can't add a serie to a pivotchart")); | 
|  | } | 
|  | return AddSeries(SerieAddress, XSerieAddress, ""); | 
|  | } | 
|  | internal protected ExcelChartSerie AddSeries(string SeriesAddress, string XSeriesAddress, string bubbleSizeAddress) | 
|  | { | 
|  | XmlElement ser = _node.OwnerDocument.CreateElement("ser", ExcelPackage.schemaChart); | 
|  | XmlNodeList node = _node.SelectNodes("c:ser", _ns); | 
|  | if (node.Count > 0) | 
|  | { | 
|  | _node.InsertAfter(ser, node[node.Count-1]); | 
|  | } | 
|  | else | 
|  | { | 
|  | InserAfter(_node, "c:varyColors,c:grouping,c:barDir,c:scatterStyle", ser); | 
|  | } | 
|  | int idx = FindIndex(); | 
|  | ser.InnerXml = string.Format("<c:idx val=\"{1}\" /><c:order val=\"{1}\" /><c:tx><c:strRef><c:f></c:f><c:strCache><c:ptCount val=\"1\" /></c:strCache></c:strRef></c:tx>{5}{0}{2}{3}{4}", AddExplosion(Chart.ChartType), idx, AddScatterPoint(Chart.ChartType), AddAxisNodes(Chart.ChartType), AddSmooth(Chart.ChartType), AddMarker(Chart.ChartType)); | 
|  | ExcelChartSerie serie; | 
|  | switch (Chart.ChartType) | 
|  | { | 
|  | case eChartType.Bubble: | 
|  | case eChartType.Bubble3DEffect: | 
|  | serie = new ExcelBubbleChartSerie(this, NameSpaceManager, ser, _isPivot) | 
|  | { | 
|  | Bubble3D=Chart.ChartType==eChartType.Bubble3DEffect, | 
|  | Series = SeriesAddress, | 
|  | XSeries = XSeriesAddress, | 
|  | BubbleSize = bubbleSizeAddress | 
|  | }; | 
|  | break; | 
|  | case eChartType.XYScatter: | 
|  | case eChartType.XYScatterLines: | 
|  | case eChartType.XYScatterLinesNoMarkers: | 
|  | case eChartType.XYScatterSmooth: | 
|  | case eChartType.XYScatterSmoothNoMarkers: | 
|  | serie = new ExcelScatterChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | break; | 
|  | case eChartType.Radar: | 
|  | case eChartType.RadarFilled: | 
|  | case eChartType.RadarMarkers: | 
|  | serie = new ExcelRadarChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | break; | 
|  | case eChartType.Surface: | 
|  | case eChartType.SurfaceTopView: | 
|  | case eChartType.SurfaceTopViewWireframe: | 
|  | case eChartType.SurfaceWireframe: | 
|  | serie = new ExcelSurfaceChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | break; | 
|  | case eChartType.Pie: | 
|  | case eChartType.Pie3D: | 
|  | case eChartType.PieExploded: | 
|  | case eChartType.PieExploded3D: | 
|  | case eChartType.PieOfPie: | 
|  | case eChartType.Doughnut: | 
|  | case eChartType.DoughnutExploded: | 
|  | case eChartType.BarOfPie: | 
|  | serie = new ExcelPieChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | break; | 
|  | case eChartType.Line: | 
|  | case eChartType.LineMarkers: | 
|  | case eChartType.LineMarkersStacked: | 
|  | case eChartType.LineMarkersStacked100: | 
|  | case eChartType.LineStacked: | 
|  | case eChartType.LineStacked100: | 
|  | serie = new ExcelLineChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | if (Chart.ChartType == eChartType.LineMarkers || | 
|  | Chart.ChartType == eChartType.LineMarkersStacked || | 
|  | Chart.ChartType == eChartType.LineMarkersStacked100) | 
|  | { | 
|  | ((ExcelLineChartSerie)serie).Marker = eMarkerStyle.Square; | 
|  | } | 
|  | ((ExcelLineChartSerie)serie).Smooth = ((ExcelLineChart)Chart).Smooth; | 
|  | break; | 
|  | case eChartType.BarClustered: | 
|  | case eChartType.BarStacked: | 
|  | case eChartType.BarStacked100: | 
|  | case eChartType.ColumnClustered: | 
|  | case eChartType.ColumnStacked: | 
|  | case eChartType.ColumnStacked100: | 
|  | case eChartType.BarClustered3D: | 
|  | case eChartType.BarStacked3D: | 
|  | case eChartType.BarStacked1003D: | 
|  | case eChartType.ColumnClustered3D: | 
|  | case eChartType.ColumnStacked3D: | 
|  | case eChartType.ColumnStacked1003D: | 
|  | case eChartType.ConeBarClustered: | 
|  | case eChartType.ConeBarStacked: | 
|  | case eChartType.ConeBarStacked100: | 
|  | case eChartType.ConeCol: | 
|  | case eChartType.ConeColClustered: | 
|  | case eChartType.ConeColStacked: | 
|  | case eChartType.ConeColStacked100: | 
|  | case eChartType.CylinderBarClustered: | 
|  | case eChartType.CylinderBarStacked: | 
|  | case eChartType.CylinderBarStacked100: | 
|  | case eChartType.CylinderCol: | 
|  | case eChartType.CylinderColClustered: | 
|  | case eChartType.CylinderColStacked: | 
|  | case eChartType.CylinderColStacked100: | 
|  | case eChartType.PyramidBarClustered: | 
|  | case eChartType.PyramidBarStacked: | 
|  | case eChartType.PyramidBarStacked100: | 
|  | case eChartType.PyramidCol: | 
|  | case eChartType.PyramidColClustered: | 
|  | case eChartType.PyramidColStacked: | 
|  | case eChartType.PyramidColStacked100: | 
|  | serie = new ExcelBarChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | ((ExcelBarChartSerie)serie).InvertIfNegative=false; | 
|  | break; | 
|  | default: | 
|  | serie = new ExcelChartSerie(this, NameSpaceManager, ser, _isPivot); | 
|  | break; | 
|  | } | 
|  | serie.Series = SeriesAddress; | 
|  | serie.XSeries = XSeriesAddress; | 
|  | _list.Add(serie); | 
|  | return serie; | 
|  | } | 
|  | bool _isPivot; | 
|  | internal void AddPivotSerie(ExcelPivotTable pivotTableSource) | 
|  | { | 
|  | var r=pivotTableSource.WorkSheet.Cells[pivotTableSource.Address.Address]; | 
|  | _isPivot = true; | 
|  | AddSeries(r.Offset(0, 1, r._toRow - r._fromRow + 1, 1).FullAddressAbsolute, r.Offset(0, 0, r._toRow - r._fromRow + 1, 1).FullAddressAbsolute,""); | 
|  | } | 
|  | private int FindIndex() | 
|  | { | 
|  | int ret = 0, newID=0; | 
|  | if (_chart.PlotArea.ChartTypes.Count > 1) | 
|  | { | 
|  | foreach (var chart in _chart.PlotArea.ChartTypes) | 
|  | { | 
|  | if (newID>0) | 
|  | { | 
|  | foreach (ExcelChartSerie serie in chart.Series) | 
|  | { | 
|  | serie.SetID((++newID).ToString()); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (chart == _chart) | 
|  | { | 
|  | ret += _list.Count + 1; | 
|  | newID=ret; | 
|  | } | 
|  | else | 
|  | { | 
|  | ret += chart.Series.Count; | 
|  | } | 
|  | } | 
|  | } | 
|  | return ret-1; | 
|  | } | 
|  | else | 
|  | { | 
|  | return _list.Count; | 
|  | } | 
|  | } | 
|  | #endregion | 
|  | #region "Xml init Functions" | 
|  | private string AddMarker(eChartType chartType) | 
|  | { | 
|  | if (chartType == eChartType.Line || | 
|  | chartType == eChartType.LineStacked || | 
|  | chartType == eChartType.LineStacked100 || | 
|  | chartType == eChartType.XYScatterLines || | 
|  | chartType == eChartType.XYScatterSmooth || | 
|  | chartType == eChartType.XYScatterLinesNoMarkers || | 
|  | chartType == eChartType.XYScatterSmoothNoMarkers) | 
|  | { | 
|  | return "<c:marker><c:symbol val=\"none\" /></c:marker>"; | 
|  | } | 
|  | else | 
|  | { | 
|  | return ""; | 
|  | } | 
|  | } | 
|  | private string AddScatterPoint(eChartType chartType) | 
|  | { | 
|  | if (chartType == eChartType.XYScatter) | 
|  | { | 
|  | return "<c:spPr><a:ln w=\"28575\"><a:noFill /></a:ln></c:spPr>"; | 
|  | } | 
|  | else | 
|  | { | 
|  | return ""; | 
|  | } | 
|  | } | 
|  | private string AddAxisNodes(eChartType chartType) | 
|  | { | 
|  | if ( chartType == eChartType.XYScatter || | 
|  | chartType == eChartType.XYScatterLines || | 
|  | chartType == eChartType.XYScatterLinesNoMarkers || | 
|  | chartType == eChartType.XYScatterSmooth || | 
|  | chartType == eChartType.XYScatterSmoothNoMarkers || | 
|  | chartType == eChartType.Bubble || | 
|  | chartType == eChartType.Bubble3DEffect) | 
|  | { | 
|  | return "<c:xVal /><c:yVal />"; | 
|  | } | 
|  | else | 
|  | { | 
|  | return "<c:val />"; | 
|  | } | 
|  | } | 
|  |  | 
|  | private string AddExplosion(eChartType chartType) | 
|  | { | 
|  | if (chartType == eChartType.PieExploded3D || | 
|  | chartType == eChartType.PieExploded || | 
|  | chartType == eChartType.DoughnutExploded) | 
|  | { | 
|  | return "<c:explosion val=\"25\" />"; //Default 25; | 
|  | } | 
|  | else | 
|  | { | 
|  | return ""; | 
|  | } | 
|  | } | 
|  | private string AddSmooth(eChartType chartType) | 
|  | { | 
|  | if (chartType == eChartType.XYScatterSmooth || | 
|  | chartType == eChartType.XYScatterSmoothNoMarkers) | 
|  | { | 
|  | return "<c:smooth val=\"1\" />"; //Default 25; | 
|  | } | 
|  | else | 
|  | { | 
|  | return ""; | 
|  | } | 
|  | } | 
|  | #endregion | 
|  | } | 
|  | } |