| /******************************************************************************* |
| * 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.Globalization; |
| using System.Text; |
| using System.Xml; |
| using System.IO; |
| using OfficeOpenXml.Table.PivotTable; |
| using OfficeOpenXml.Utils; |
| using OfficeOpenXml.Packaging; |
| |
| namespace OfficeOpenXml.Drawing.Chart |
| { |
| #region "Chart Enums" |
| /// <summary> |
| /// Chart type |
| /// </summary> |
| public enum eChartType |
| { |
| Area3D=-4098, |
| AreaStacked3D=78, |
| AreaStacked1003D=79, |
| BarClustered3D= 60, |
| BarStacked3D=61, |
| BarStacked1003D=62, |
| Column3D=-4100, |
| ColumnClustered3D=54, |
| ColumnStacked3D=55, |
| ColumnStacked1003D=56, |
| Line3D=-4101, |
| Pie3D=-4102, |
| PieExploded3D=70, |
| Area=1, |
| AreaStacked=76, |
| AreaStacked100=77, |
| BarClustered=57, |
| BarOfPie=71, |
| BarStacked=58, |
| BarStacked100=59, |
| Bubble=15, |
| Bubble3DEffect=87, |
| ColumnClustered=51, |
| ColumnStacked=52, |
| ColumnStacked100=53, |
| ConeBarClustered=102, |
| ConeBarStacked=103, |
| ConeBarStacked100=104, |
| ConeCol=105, |
| ConeColClustered=99, |
| ConeColStacked=100, |
| ConeColStacked100=101, |
| CylinderBarClustered=95, |
| CylinderBarStacked=96, |
| CylinderBarStacked100=97, |
| CylinderCol=98, |
| CylinderColClustered=92, |
| CylinderColStacked=93, |
| CylinderColStacked100=94, |
| Doughnut=-4120, |
| DoughnutExploded=80, |
| Line=4, |
| LineMarkers=65, |
| LineMarkersStacked=66, |
| LineMarkersStacked100=67, |
| LineStacked=63, |
| LineStacked100=64, |
| Pie=5, |
| PieExploded=69, |
| PieOfPie=68, |
| PyramidBarClustered=109, |
| PyramidBarStacked=110, |
| PyramidBarStacked100=111, |
| PyramidCol=112, |
| PyramidColClustered=106, |
| PyramidColStacked=107, |
| PyramidColStacked100=108, |
| Radar=-4151, |
| RadarFilled=82, |
| RadarMarkers=81, |
| StockHLC=88, |
| StockOHLC=89, |
| StockVHLC=90, |
| StockVOHLC=91, |
| Surface=83, |
| SurfaceTopView=85, |
| SurfaceTopViewWireframe=86, |
| SurfaceWireframe=84, |
| XYScatter=-4169, |
| XYScatterLines=74, |
| XYScatterLinesNoMarkers=75, |
| XYScatterSmooth=72, |
| XYScatterSmoothNoMarkers=73 |
| } |
| /// <summary> |
| /// Bar or column |
| /// </summary> |
| public enum eDirection |
| { |
| Column, |
| Bar |
| } |
| /// <summary> |
| /// How the series are grouped |
| /// </summary> |
| public enum eGrouping |
| { |
| Standard, |
| Clustered, |
| Stacked, |
| PercentStacked |
| } |
| /// <summary> |
| /// Shape for bar charts |
| /// </summary> |
| public enum eShape |
| { |
| Box, |
| Cone, |
| ConeToMax, |
| Cylinder, |
| Pyramid, |
| PyramidToMax |
| } |
| /// <summary> |
| /// Smooth or lines markers |
| /// </summary> |
| public enum eScatterStyle |
| { |
| LineMarker, |
| SmoothMarker, |
| } |
| public enum eRadarStyle |
| { |
| /// <summary> |
| /// Specifies that the radar chart shall be filled and have lines but no markers. |
| /// </summary> |
| Filled, |
| /// <summary> |
| /// Specifies that the radar chart shall have lines and markers but no fill. |
| /// </summary> |
| Marker, |
| /// <summary> |
| /// Specifies that the radar chart shall have lines but no markers and no fill. |
| /// </summary> |
| Standard |
| } |
| /// <summary> |
| /// Bar or pie |
| /// </summary> |
| public enum ePieType |
| { |
| Bar, |
| Pie |
| } |
| /// <summary> |
| /// Position of the labels |
| /// </summary> |
| public enum eLabelPosition |
| { |
| BestFit, |
| Left, |
| Right, |
| Center, |
| Top, |
| Bottom, |
| InBase, |
| InEnd, |
| OutEnd |
| } |
| /// <summary> |
| /// Axis label position |
| /// </summary> |
| public enum eTickLabelPosition |
| { |
| High, |
| Low, |
| NextTo, |
| None |
| } |
| /// <summary> |
| /// Markerstyle |
| /// </summary> |
| public enum eMarkerStyle |
| { |
| Circle, |
| Dash, |
| Diamond, |
| Dot, |
| None, |
| Picture, |
| Plus, |
| Square, |
| Star, |
| Triangle, |
| X, |
| } |
| /// <summary> |
| /// The build in style of the chart. |
| /// </summary> |
| public enum eChartStyle |
| { |
| None, |
| Style1, |
| Style2, |
| Style3, |
| Style4, |
| Style5, |
| Style6, |
| Style7, |
| Style8, |
| Style9, |
| Style10, |
| Style11, |
| Style12, |
| Style13, |
| Style14, |
| Style15, |
| Style16, |
| Style17, |
| Style18, |
| Style19, |
| Style20, |
| Style21, |
| Style22, |
| Style23, |
| Style24, |
| Style25, |
| Style26, |
| Style27, |
| Style28, |
| Style29, |
| Style30, |
| Style31, |
| Style32, |
| Style33, |
| Style34, |
| Style35, |
| Style36, |
| Style37, |
| Style38, |
| Style39, |
| Style40, |
| Style41, |
| Style42, |
| Style43, |
| Style44, |
| Style45, |
| Style46, |
| Style47, |
| Style48 |
| } |
| /// <summary> |
| /// Type of Trendline for a chart |
| /// </summary> |
| public enum eTrendLine |
| { |
| /// <summary> |
| /// Specifies the trendline shall be an exponential curve in the form |
| /// </summary> |
| Exponential, |
| /// <summary> |
| /// Specifies the trendline shall be a logarithmic curve in the form , where log is the natural |
| /// </summary> |
| Linear, |
| /// <summary> |
| /// Specifies the trendline shall be a logarithmic curve in the form , where log is the natural |
| /// </summary> |
| Logarithmic, |
| /// <summary> |
| /// Specifies the trendline shall be a moving average of period Period |
| /// </summary> |
| MovingAvgerage, |
| /// <summary> |
| /// Specifies the trendline shall be a polynomial curve of order Order in the form |
| /// </summary> |
| Polynomial, |
| /// <summary> |
| /// Specifies the trendline shall be a power curve in the form |
| /// </summary> |
| Power |
| } |
| /// <summary> |
| /// Specifies the possible ways to display blanks |
| /// </summary> |
| public enum eDisplayBlanksAs |
| { |
| /// <summary> |
| /// Blank values shall be left as a gap |
| /// </summary> |
| Gap, |
| /// <summary> |
| /// Blank values shall be spanned with a line (Line charts) |
| /// </summary> |
| Span, |
| /// <summary> |
| /// Blank values shall be treated as zero |
| /// </summary> |
| Zero |
| } |
| public enum eSizeRepresents |
| { |
| /// <summary> |
| /// Specifies the area of the bubbles shall be proportional to the bubble size value. |
| /// </summary> |
| Area, |
| /// <summary> |
| /// Specifies the radius of the bubbles shall be proportional to the bubble size value. |
| /// </summary> |
| Width |
| } |
| #endregion |
| |
| |
| /// <summary> |
| /// Base class for Chart object. |
| /// </summary> |
| public class ExcelChart : ExcelDrawing |
| { |
| const string rootPath = "c:chartSpace/c:chart/c:plotArea"; |
| //string _chartPath; |
| protected internal ExcelChartSeries _chartSeries; |
| internal ExcelChartAxis[] _axis; |
| protected XmlHelper _chartXmlHelper; |
| #region "Constructors" |
| internal ExcelChart(ExcelDrawings drawings, XmlNode node, eChartType type, bool isPivot) : |
| base(drawings, node, "xdr:graphicFrame/xdr:nvGraphicFramePr/xdr:cNvPr/@name") |
| { |
| ChartType = type; |
| CreateNewChart(drawings, type, null); |
| |
| Init(drawings, _chartNode); |
| |
| _chartSeries = new ExcelChartSeries(this, drawings.NameSpaceManager, _chartNode, isPivot); |
| |
| SetTypeProperties(); |
| LoadAxis(); |
| } |
| internal ExcelChart(ExcelDrawings drawings, XmlNode node, eChartType type, ExcelChart topChart, ExcelPivotTable PivotTableSource) : |
| base(drawings, node, "xdr:graphicFrame/xdr:nvGraphicFramePr/xdr:cNvPr/@name") |
| { |
| ChartType = type; |
| CreateNewChart(drawings, type, topChart); |
| |
| Init(drawings, _chartNode); |
| |
| _chartSeries = new ExcelChartSeries(this, drawings.NameSpaceManager, _chartNode, PivotTableSource!=null); |
| if (PivotTableSource != null) SetPivotSource(PivotTableSource); |
| |
| SetTypeProperties(); |
| if (topChart == null) |
| LoadAxis(); |
| else |
| { |
| _axis = topChart.Axis; |
| if (_axis.Length > 0) |
| { |
| XAxis = _axis[0]; |
| YAxis = _axis[1]; |
| } |
| } |
| } |
| internal ExcelChart(ExcelDrawings drawings, XmlNode node, Uri uriChart, ZipPackagePart part, XmlDocument chartXml, XmlNode chartNode) : |
| base(drawings, node, "xdr:graphicFrame/xdr:nvGraphicFramePr/xdr:cNvPr/@name") |
| { |
| UriChart = uriChart; |
| Part = part; |
| ChartXml = chartXml; |
| _chartNode = chartNode; |
| InitChartLoad(drawings, chartNode); |
| ChartType = GetChartType(chartNode.LocalName); |
| } |
| internal ExcelChart(ExcelChart topChart, XmlNode chartNode) : |
| base(topChart._drawings, topChart.TopNode, "xdr:graphicFrame/xdr:nvGraphicFramePr/xdr:cNvPr/@name") |
| { |
| UriChart = topChart.UriChart; |
| Part = topChart.Part; |
| ChartXml = topChart.ChartXml; |
| _plotArea = topChart.PlotArea; |
| _chartNode = chartNode; |
| |
| InitChartLoad(topChart._drawings, chartNode); |
| } |
| private void InitChartLoad(ExcelDrawings drawings, XmlNode chartNode) |
| { |
| //SetChartType(); |
| bool isPivot = false; |
| Init(drawings, chartNode); |
| _chartSeries = new ExcelChartSeries(this, drawings.NameSpaceManager, _chartNode, isPivot /*ChartXml.SelectSingleNode(_chartPath, drawings.NameSpaceManager)*/); |
| LoadAxis(); |
| } |
| |
| private void Init(ExcelDrawings drawings, XmlNode chartNode) |
| { |
| //_chartXmlHelper = new XmlHelper(drawings.NameSpaceManager, chartNode); |
| _chartXmlHelper = XmlHelperFactory.Create(drawings.NameSpaceManager, chartNode); |
| _chartXmlHelper.SchemaNodeOrder = new string[] { "title", "pivotFmt", "autoTitleDeleted", "view3D", "floor", "sideWall", "backWall", "plotArea", "wireframe", "barDir", "grouping", "scatterStyle", "radarStyle", "varyColors", "ser", "dLbls", "bubbleScale", "showNegBubbles", "dropLines", "upDownBars", "marker", "smooth", "shape", "legend", "plotVisOnly", "dispBlanksAs", "showDLblsOverMax", "overlap", "bandFmts", "axId", "spPr", "printSettings" }; |
| WorkSheet = drawings.Worksheet; |
| } |
| #endregion |
| #region "Private functions" |
| private void SetTypeProperties() |
| { |
| /******* Grouping *******/ |
| if (IsTypeClustered()) |
| { |
| Grouping = eGrouping.Clustered; |
| } |
| else if ( |
| IsTypeStacked()) |
| { |
| Grouping = eGrouping.Stacked; |
| } |
| else if ( |
| IsTypePercentStacked()) |
| { |
| Grouping = eGrouping.PercentStacked; |
| } |
| |
| /***** 3D Perspective *****/ |
| if (IsType3D()) |
| { |
| View3D.RotY = 20; |
| View3D.Perspective = 30; //Default to 30 |
| if (IsTypePieDoughnut()) |
| { |
| View3D.RotX = 30; |
| } |
| else |
| { |
| View3D.RotX = 15; |
| } |
| } |
| } |
| private void CreateNewChart(ExcelDrawings drawings, eChartType type, ExcelChart topChart) |
| { |
| if (topChart == null) |
| { |
| XmlElement graphFrame = TopNode.OwnerDocument.CreateElement("graphicFrame", ExcelPackage.schemaSheetDrawings); |
| graphFrame.SetAttribute("macro", ""); |
| TopNode.AppendChild(graphFrame); |
| graphFrame.InnerXml = string.Format("<xdr:nvGraphicFramePr><xdr:cNvPr id=\"{0}\" name=\"Chart 1\" /><xdr:cNvGraphicFramePr /></xdr:nvGraphicFramePr><xdr:xfrm><a:off x=\"0\" y=\"0\" /> <a:ext cx=\"0\" cy=\"0\" /></xdr:xfrm><a:graphic><a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/chart\"><c:chart xmlns:c=\"http://schemas.openxmlformats.org/drawingml/2006/chart\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"rId1\" /> </a:graphicData> </a:graphic>",_id); |
| TopNode.AppendChild(TopNode.OwnerDocument.CreateElement("clientData", ExcelPackage.schemaSheetDrawings)); |
| |
| var package = drawings.Worksheet._package.Package; |
| UriChart = GetNewUri(package, "/xl/charts/chart{0}.xml"); |
| |
| ChartXml = new XmlDocument(); |
| ChartXml.PreserveWhitespace = ExcelPackage.preserveWhitespace; |
| LoadXmlSafe(ChartXml, ChartStartXml(type), Encoding.UTF8); |
| |
| // save it to the package |
| Part = package.CreatePart(UriChart, "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", _drawings._package.Compression); |
| |
| StreamWriter streamChart = new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write)); |
| ChartXml.Save(streamChart); |
| streamChart.Close(); |
| package.Flush(); |
| |
| var chartRelation = drawings.Part.CreateRelationship(UriHelper.GetRelativeUri(drawings.UriDrawing, UriChart), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/chart"); |
| graphFrame.SelectSingleNode("a:graphic/a:graphicData/c:chart", NameSpaceManager).Attributes["r:id"].Value = chartRelation.Id; |
| package.Flush(); |
| _chartNode = ChartXml.SelectSingleNode(string.Format("c:chartSpace/c:chart/c:plotArea/{0}", GetChartNodeText()), NameSpaceManager); |
| } |
| else |
| { |
| ChartXml = topChart.ChartXml; |
| Part = topChart.Part; |
| _plotArea = topChart.PlotArea; |
| UriChart = topChart.UriChart; |
| _axis = topChart._axis; |
| |
| XmlNode preNode = _plotArea.ChartTypes[_plotArea.ChartTypes.Count - 1].ChartNode; |
| _chartNode = ((XmlDocument)ChartXml).CreateElement(GetChartNodeText(), ExcelPackage.schemaChart); |
| preNode.ParentNode.InsertAfter(_chartNode, preNode); |
| if (topChart.Axis.Length == 0) |
| { |
| AddAxis(); |
| } |
| string serieXML = GetChartSerieStartXml(type, int.Parse(topChart.Axis[0].Id), int.Parse(topChart.Axis[1].Id), topChart.Axis.Length>2?int.Parse(topChart.Axis[2].Id) : -1); |
| _chartNode.InnerXml = serieXML; |
| } |
| } |
| private void LoadAxis() |
| { |
| XmlNodeList nl = _chartNode.SelectNodes("c:axId", NameSpaceManager); |
| List<ExcelChartAxis> l = new List<ExcelChartAxis>(); |
| foreach (XmlNode node in nl) |
| { |
| string id = node.Attributes["val"].Value; |
| var axNode = ChartXml.SelectNodes(rootPath + string.Format("/*/c:axId[@val=\"{0}\"]", id), NameSpaceManager); |
| if (axNode != null && axNode.Count>1) |
| { |
| foreach (XmlNode axn in axNode) |
| { |
| if (axn.ParentNode.LocalName.EndsWith("Ax")) |
| { |
| XmlNode axisNode = axNode[1].ParentNode; |
| ExcelChartAxis ax = new ExcelChartAxis(NameSpaceManager, axisNode); |
| l.Add(ax); |
| } |
| } |
| } |
| } |
| _axis = l.ToArray(); |
| |
| if(_axis.Length > 0) XAxis = _axis[0]; |
| if (_axis.Length > 1) YAxis = _axis[1]; |
| } |
| //private void SetChartType() |
| //{ |
| // ChartType = 0; |
| // //_plotArea = new ExcelChartPlotArea(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace/c:chart/c:plotArea", NameSpaceManager)); |
| // int pos=0; |
| // foreach (XmlElement n in ChartXml.SelectSingleNode(rootPath, _drawings.NameSpaceManager).ChildNodes) |
| // { |
| // if (pos == 0) |
| // { |
| // ChartType = GetChartType(n.Name); |
| // if (ChartType != 0) |
| // { |
| // //_chartPath = rootPath + "/" + n.Name; |
| // PlotArea.ChartTypes.Add(this); |
| // } |
| // } |
| // else |
| // { |
| // var chartSerieType = GetChart(_drawings, TopNode/*, n*/); |
| // chartSerieType = GetChart(n, _drawings, TopNode, UriChart, Part, ChartXml, null, isPivot); |
| // PlotArea.ChartTypes.Add(chartSerieType); |
| // //var chartType = GetChartType(n.Name); |
| // } |
| // if (ChartType != 0) |
| // { |
| // pos++; |
| // } |
| // } |
| //} |
| internal virtual eChartType GetChartType(string name) |
| { |
| |
| switch (name) |
| { |
| case "area3DChart": |
| if(Grouping==eGrouping.Stacked) |
| { |
| return eChartType.AreaStacked3D; |
| } |
| else if (Grouping == eGrouping.PercentStacked) |
| { |
| return eChartType.AreaStacked1003D; |
| } |
| else |
| { |
| return eChartType.Area3D; |
| } |
| case "areaChart": |
| if (Grouping == eGrouping.Stacked) |
| { |
| return eChartType.AreaStacked; |
| } |
| else if (Grouping == eGrouping.PercentStacked) |
| { |
| return eChartType.AreaStacked100; |
| } |
| else |
| { |
| return eChartType.Area; |
| } |
| case "doughnutChart": |
| return eChartType.Doughnut; |
| case "pie3DChart": |
| return eChartType.Pie3D; |
| case "pieChart": |
| return eChartType.Pie; |
| case "radarChart": |
| return eChartType.Radar; |
| case "scatterChart": |
| return eChartType.XYScatter; |
| case "surface3DChart": |
| case "surfaceChart": |
| return eChartType.Surface; |
| case "stockChart": |
| return eChartType.StockHLC; |
| default: |
| return 0; |
| } |
| } |
| #region "Xml init Functions" |
| private string ChartStartXml(eChartType type) |
| { |
| StringBuilder xml=new StringBuilder(); |
| int axID=1; |
| int xAxID=2; |
| int serAxID = IsTypeSurface() ? 3 : -1; |
| |
| xml.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"); |
| xml.AppendFormat("<c:chartSpace xmlns:c=\"{0}\" xmlns:a=\"{1}\" xmlns:r=\"{2}\">", ExcelPackage.schemaChart, ExcelPackage.schemaDrawings, ExcelPackage.schemaRelationships); |
| xml.Append("<c:chart>"); |
| xml.AppendFormat("{0}{1}<c:plotArea><c:layout/>",AddPerspectiveXml(type), AddSurfaceXml(type)); |
| |
| string chartNodeText = GetChartNodeText(); |
| xml.AppendFormat("<{0}>", chartNodeText); |
| xml.Append(GetChartSerieStartXml(type, axID, xAxID, serAxID)); |
| xml.AppendFormat("</{0}>", chartNodeText); |
| |
| //Axis |
| if (!IsTypePieDoughnut()) |
| { |
| if (IsTypeScatterBubble()) |
| { |
| xml.AppendFormat("<c:valAx><c:axId val=\"{0}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\"/><c:axPos val=\"b\"/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{1}\"/><c:crosses val=\"autoZero\"/></c:valAx>", axID, xAxID); |
| } |
| else |
| { |
| xml.AppendFormat("<c:catAx><c:axId val=\"{0}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\"/><c:axPos val=\"b\"/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{1}\"/><c:crosses val=\"autoZero\"/><c:auto val=\"1\"/><c:lblAlgn val=\"ctr\"/><c:lblOffset val=\"100\"/></c:catAx>", axID, xAxID); |
| } |
| xml.AppendFormat("<c:valAx><c:axId val=\"{1}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\"/><c:axPos val=\"l\"/><c:majorGridlines/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{0}\"/><c:crosses val=\"autoZero\"/><c:crossBetween val=\"between\"/></c:valAx>", axID, xAxID); |
| if (serAxID==3) //Sureface Chart |
| { |
| xml.AppendFormat("<c:serAx><c:axId val=\"{0}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\"/><c:axPos val=\"b\"/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{1}\"/><c:crosses val=\"autoZero\"/></c:serAx>", serAxID, xAxID); |
| } |
| } |
| |
| xml.AppendFormat("</c:plotArea><c:legend><c:legendPos val=\"r\"/><c:layout/><c:overlay val=\"0\" /></c:legend><c:plotVisOnly val=\"1\"/></c:chart>", axID, xAxID); |
| |
| xml.Append("<c:printSettings><c:headerFooter/><c:pageMargins b=\"0.75\" l=\"0.7\" r=\"0.7\" t=\"0.75\" header=\"0.3\" footer=\"0.3\"/><c:pageSetup/></c:printSettings></c:chartSpace>"); |
| return xml.ToString(); |
| } |
| |
| private string GetChartSerieStartXml(eChartType type, int axID, int xAxID, int serAxID) |
| { |
| StringBuilder xml = new StringBuilder(); |
| |
| xml.Append(AddScatterType(type)); |
| xml.Append(AddRadarType(type)); |
| xml.Append(AddBarDir(type)); |
| xml.Append(AddGrouping()); |
| xml.Append(AddVaryColors()); |
| xml.Append(AddHasMarker(type)); |
| xml.Append(AddShape(type)); |
| xml.Append(AddFirstSliceAng(type)); |
| xml.Append(AddHoleSize(type)); |
| if (ChartType == eChartType.BarStacked100 || |
| ChartType == eChartType.BarStacked || |
| ChartType == eChartType.ColumnStacked || |
| ChartType == eChartType.ColumnStacked100) |
| { |
| xml.Append("<c:overlap val=\"100\"/>"); |
| } |
| if (IsTypeSurface()) |
| { |
| xml.Append("<c:bandFmts/>"); |
| } |
| xml.Append(AddAxisId(axID, xAxID, serAxID)); |
| |
| return xml.ToString(); |
| } |
| private string AddAxisId(int axID,int xAxID, int serAxID) |
| { |
| if (!IsTypePieDoughnut()) |
| { |
| if (IsTypeSurface()) |
| { |
| return string.Format("<c:axId val=\"{0}\"/><c:axId val=\"{1}\"/><c:axId val=\"{2}\"/>", axID, xAxID, serAxID); |
| } |
| else |
| { |
| return string.Format("<c:axId val=\"{0}\"/><c:axId val=\"{1}\"/>", axID, xAxID); |
| } |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddAxType() |
| { |
| switch(ChartType) |
| { |
| case eChartType.XYScatter: |
| case eChartType.XYScatterLines: |
| case eChartType.XYScatterLinesNoMarkers: |
| case eChartType.XYScatterSmooth: |
| case eChartType.XYScatterSmoothNoMarkers: |
| case eChartType.Bubble: |
| case eChartType.Bubble3DEffect: |
| return "valAx"; |
| default: |
| return "catAx"; |
| } |
| } |
| private string AddScatterType(eChartType type) |
| { |
| if (type == eChartType.XYScatter || |
| type == eChartType.XYScatterLines || |
| type == eChartType.XYScatterLinesNoMarkers || |
| type == eChartType.XYScatterSmooth || |
| type == eChartType.XYScatterSmoothNoMarkers) |
| { |
| return "<c:scatterStyle val=\"\" />"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddRadarType(eChartType type) |
| { |
| if (type == eChartType.Radar || |
| type == eChartType.RadarFilled|| |
| type == eChartType.RadarMarkers) |
| { |
| return "<c:radarStyle val=\"\" />"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddGrouping() |
| { |
| //IsTypeClustered() || IsTypePercentStacked() || IsTypeStacked() || |
| if(IsTypeShape() || IsTypeLine()) |
| { |
| return "<c:grouping val=\"standard\"/>"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddHoleSize(eChartType type) |
| { |
| if (type == eChartType.Doughnut || |
| type == eChartType.DoughnutExploded) |
| { |
| return "<c:holeSize val=\"50\" />"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddFirstSliceAng(eChartType type) |
| { |
| if (type == eChartType.Doughnut || |
| type == eChartType.DoughnutExploded) |
| { |
| return "<c:firstSliceAng val=\"0\" />"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddVaryColors() |
| { |
| if (IsTypePieDoughnut()) |
| { |
| return "<c:varyColors val=\"1\" />"; |
| } |
| else |
| { |
| return "<c:varyColors val=\"0\" />"; |
| } |
| } |
| private string AddHasMarker(eChartType type) |
| { |
| if (type == eChartType.LineMarkers || |
| type == eChartType.LineMarkersStacked || |
| type == eChartType.LineMarkersStacked100 /*|| |
| type == eChartType.XYScatterLines || |
| type == eChartType.XYScatterSmooth*/) |
| { |
| return "<c:marker val=\"1\"/>"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddShape(eChartType type) |
| { |
| if (IsTypeShape()) |
| { |
| return "<c:shape val=\"box\" />"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddBarDir(eChartType type) |
| { |
| if (IsTypeShape()) |
| { |
| return "<c:barDir val=\"col\" />"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddPerspectiveXml(eChartType type) |
| { |
| //Add for 3D sharts |
| if (IsType3D()) |
| { |
| return "<c:view3D><c:perspective val=\"30\" /></c:view3D>"; |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| private string AddSurfaceXml(eChartType type) |
| { |
| if (IsTypeSurface()) |
| { |
| return AddSurfacePart("floor") + AddSurfacePart("sideWall") + AddSurfacePart("backWall"); |
| } |
| else |
| { |
| return ""; |
| } |
| } |
| |
| private string AddSurfacePart(string name) |
| { |
| return string.Format("<c:{0}><c:thickness val=\"0\"/><c:spPr><a:noFill/><a:ln><a:noFill/></a:ln><a:effectLst/><a:sp3d/></c:spPr></c:{0}>", name); |
| } |
| #endregion |
| #endregion |
| #region "Chart type functions |
| internal static bool IsType3D(eChartType chartType) |
| { |
| return chartType == eChartType.Area3D || |
| chartType == eChartType.AreaStacked3D || |
| chartType == eChartType.AreaStacked1003D || |
| chartType == eChartType.BarClustered3D || |
| chartType == eChartType.BarStacked3D || |
| chartType == eChartType.BarStacked1003D || |
| chartType == eChartType.Column3D || |
| chartType == eChartType.ColumnClustered3D || |
| chartType == eChartType.ColumnStacked3D || |
| chartType == eChartType.ColumnStacked1003D || |
| chartType == eChartType.Line3D || |
| chartType == eChartType.Pie3D || |
| chartType == eChartType.PieExploded3D || |
| chartType == eChartType.ConeBarClustered || |
| chartType == eChartType.ConeBarStacked || |
| chartType == eChartType.ConeBarStacked100 || |
| chartType == eChartType.ConeCol || |
| chartType == eChartType.ConeColClustered || |
| chartType == eChartType.ConeColStacked || |
| chartType == eChartType.ConeColStacked100 || |
| chartType == eChartType.CylinderBarClustered || |
| chartType == eChartType.CylinderBarStacked || |
| chartType == eChartType.CylinderBarStacked100 || |
| chartType == eChartType.CylinderCol || |
| chartType == eChartType.CylinderColClustered || |
| chartType == eChartType.CylinderColStacked || |
| chartType == eChartType.CylinderColStacked100 || |
| chartType == eChartType.PyramidBarClustered || |
| chartType == eChartType.PyramidBarStacked || |
| chartType == eChartType.PyramidBarStacked100 || |
| chartType == eChartType.PyramidCol || |
| chartType == eChartType.PyramidColClustered || |
| chartType == eChartType.PyramidColStacked || |
| chartType == eChartType.PyramidColStacked100 || |
| chartType == eChartType.Surface || |
| chartType == eChartType.SurfaceTopView || |
| chartType == eChartType.SurfaceTopViewWireframe || |
| chartType == eChartType.SurfaceWireframe; |
| } |
| internal protected bool IsType3D() |
| { |
| return IsType3D(ChartType); |
| } |
| protected bool IsTypeLine() |
| { |
| return ChartType == eChartType.Line || |
| ChartType == eChartType.LineMarkers || |
| ChartType == eChartType.LineMarkersStacked100 || |
| ChartType == eChartType.LineStacked || |
| ChartType == eChartType.LineStacked100 || |
| ChartType == eChartType.Line3D; |
| } |
| protected bool IsTypeScatterBubble() |
| { |
| return ChartType == eChartType.XYScatter || |
| ChartType == eChartType.XYScatterLines || |
| ChartType == eChartType.XYScatterLinesNoMarkers || |
| ChartType == eChartType.XYScatterSmooth || |
| ChartType == eChartType.XYScatterSmoothNoMarkers || |
| ChartType == eChartType.Bubble || |
| ChartType == eChartType.Bubble3DEffect; |
| } |
| protected bool IsTypeSurface() |
| { |
| return ChartType == eChartType.Surface || |
| ChartType == eChartType.SurfaceTopView || |
| ChartType == eChartType.SurfaceTopViewWireframe || |
| ChartType == eChartType.SurfaceWireframe; |
| } |
| protected bool IsTypeShape() |
| { |
| return ChartType == eChartType.BarClustered3D || |
| ChartType == eChartType.BarStacked3D || |
| ChartType == eChartType.BarStacked1003D || |
| ChartType == eChartType.BarClustered3D || |
| ChartType == eChartType.BarStacked3D || |
| ChartType == eChartType.BarStacked1003D || |
| ChartType == eChartType.Column3D || |
| ChartType == eChartType.ColumnClustered3D || |
| ChartType == eChartType.ColumnStacked3D || |
| ChartType == eChartType.ColumnStacked1003D || |
| //ChartType == eChartType.3DPie || |
| //ChartType == eChartType.3DPieExploded || |
| //ChartType == eChartType.Bubble3DEffect || |
| ChartType == eChartType.ConeBarClustered || |
| ChartType == eChartType.ConeBarStacked || |
| ChartType == eChartType.ConeBarStacked100 || |
| ChartType == eChartType.ConeCol || |
| ChartType == eChartType.ConeColClustered || |
| ChartType == eChartType.ConeColStacked || |
| ChartType == eChartType.ConeColStacked100 || |
| ChartType == eChartType.CylinderBarClustered || |
| ChartType == eChartType.CylinderBarStacked || |
| ChartType == eChartType.CylinderBarStacked100 || |
| ChartType == eChartType.CylinderCol || |
| ChartType == eChartType.CylinderColClustered || |
| ChartType == eChartType.CylinderColStacked || |
| ChartType == eChartType.CylinderColStacked100 || |
| ChartType == eChartType.PyramidBarClustered || |
| ChartType == eChartType.PyramidBarStacked || |
| ChartType == eChartType.PyramidBarStacked100 || |
| ChartType == eChartType.PyramidCol || |
| ChartType == eChartType.PyramidColClustered || |
| ChartType == eChartType.PyramidColStacked || |
| ChartType == eChartType.PyramidColStacked100; //|| |
| //ChartType == eChartType.Doughnut || |
| //ChartType == eChartType.DoughnutExploded; |
| } |
| protected internal bool IsTypePercentStacked() |
| { |
| return ChartType == eChartType.AreaStacked100 || |
| ChartType == eChartType.BarStacked100 || |
| ChartType == eChartType.BarStacked1003D || |
| ChartType == eChartType.ColumnStacked100 || |
| ChartType == eChartType.ColumnStacked1003D || |
| ChartType == eChartType.ConeBarStacked100 || |
| ChartType == eChartType.ConeColStacked100 || |
| ChartType == eChartType.CylinderBarStacked100 || |
| ChartType == eChartType.CylinderColStacked || |
| ChartType == eChartType.LineMarkersStacked100 || |
| ChartType == eChartType.LineStacked100 || |
| ChartType == eChartType.PyramidBarStacked100 || |
| ChartType == eChartType.PyramidColStacked100; |
| } |
| protected internal bool IsTypeStacked() |
| { |
| return ChartType == eChartType.AreaStacked || |
| ChartType == eChartType.AreaStacked3D || |
| ChartType == eChartType.BarStacked || |
| ChartType == eChartType.BarStacked3D || |
| ChartType == eChartType.ColumnStacked3D || |
| ChartType == eChartType.ColumnStacked || |
| ChartType == eChartType.ConeBarStacked || |
| ChartType == eChartType.ConeColStacked || |
| ChartType == eChartType.CylinderBarStacked || |
| ChartType == eChartType.CylinderColStacked || |
| ChartType == eChartType.LineMarkersStacked || |
| ChartType == eChartType.LineStacked || |
| ChartType == eChartType.PyramidBarStacked || |
| ChartType == eChartType.PyramidColStacked; |
| } |
| protected bool IsTypeClustered() |
| { |
| return ChartType == eChartType.BarClustered || |
| ChartType == eChartType.BarClustered3D || |
| ChartType == eChartType.ColumnClustered3D || |
| ChartType == eChartType.ColumnClustered || |
| ChartType == eChartType.ConeBarClustered || |
| ChartType == eChartType.ConeColClustered || |
| ChartType == eChartType.CylinderBarClustered || |
| ChartType == eChartType.CylinderColClustered || |
| ChartType == eChartType.PyramidBarClustered || |
| ChartType == eChartType.PyramidColClustered; |
| } |
| protected internal bool IsTypePieDoughnut() |
| { |
| return ChartType == eChartType.Pie || |
| ChartType == eChartType.PieExploded || |
| ChartType == eChartType.PieOfPie || |
| ChartType == eChartType.Pie3D || |
| ChartType == eChartType.PieExploded3D || |
| ChartType == eChartType.BarOfPie || |
| ChartType == eChartType.Doughnut || |
| ChartType == eChartType.DoughnutExploded; |
| } |
| #endregion |
| /// <summary> |
| /// Get the name of the chart node |
| /// </summary> |
| /// <returns>The name</returns> |
| protected string GetChartNodeText() |
| { |
| switch (ChartType) |
| { |
| case eChartType.Area3D: |
| case eChartType.AreaStacked3D: |
| case eChartType.AreaStacked1003D: |
| return "c:area3DChart"; |
| case eChartType.Area: |
| case eChartType.AreaStacked: |
| case eChartType.AreaStacked100: |
| return "c:areaChart"; |
| case eChartType.BarClustered: |
| case eChartType.BarStacked: |
| case eChartType.BarStacked100: |
| case eChartType.ColumnClustered: |
| case eChartType.ColumnStacked: |
| case eChartType.ColumnStacked100: |
| return "c:barChart"; |
| 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: |
| return "c:bar3DChart"; |
| case eChartType.Bubble: |
| case eChartType.Bubble3DEffect: |
| return "c:bubbleChart"; |
| case eChartType.Doughnut: |
| case eChartType.DoughnutExploded: |
| return "c:doughnutChart"; |
| case eChartType.Line: |
| case eChartType.LineMarkers: |
| case eChartType.LineMarkersStacked: |
| case eChartType.LineMarkersStacked100: |
| case eChartType.LineStacked: |
| case eChartType.LineStacked100: |
| return "c:lineChart"; |
| case eChartType.Line3D: |
| return "c:line3DChart"; |
| case eChartType.Pie: |
| case eChartType.PieExploded: |
| return "c:pieChart"; |
| case eChartType.BarOfPie: |
| case eChartType.PieOfPie: |
| return "c:ofPieChart"; |
| case eChartType.Pie3D: |
| case eChartType.PieExploded3D: |
| return "c:pie3DChart"; |
| case eChartType.Radar: |
| case eChartType.RadarFilled: |
| case eChartType.RadarMarkers: |
| return "c:radarChart"; |
| case eChartType.XYScatter: |
| case eChartType.XYScatterLines: |
| case eChartType.XYScatterLinesNoMarkers: |
| case eChartType.XYScatterSmooth: |
| case eChartType.XYScatterSmoothNoMarkers: |
| return "c:scatterChart"; |
| case eChartType.Surface: |
| case eChartType.SurfaceWireframe: |
| return "c:surface3DChart"; |
| case eChartType.SurfaceTopView: |
| case eChartType.SurfaceTopViewWireframe: |
| return "c:surfaceChart"; |
| case eChartType.StockHLC: |
| return "c:stockChart"; |
| default: |
| throw(new NotImplementedException("Chart type not implemented")); |
| } |
| } |
| /// <summary> |
| /// Add a secondary axis |
| /// </summary> |
| internal void AddAxis() |
| { |
| XmlElement catAx = ChartXml.CreateElement(string.Format("c:{0}",AddAxType()), ExcelPackage.schemaChart); |
| int axID; |
| if (_axis.Length == 0) |
| { |
| _plotArea.TopNode.AppendChild(catAx); |
| axID = 1; |
| } |
| else |
| { |
| _axis[0].TopNode.ParentNode.InsertAfter(catAx, _axis[_axis.Length-1].TopNode); |
| axID = int.Parse(_axis[0].Id) < int.Parse(_axis[1].Id) ? int.Parse(_axis[1].Id) + 1 : int.Parse(_axis[0].Id) + 1; |
| } |
| |
| |
| XmlElement valAx = ChartXml.CreateElement("c:valAx", ExcelPackage.schemaChart); |
| catAx.ParentNode.InsertAfter(valAx, catAx); |
| |
| if (_axis.Length == 0) |
| { |
| catAx.InnerXml = string.Format("<c:axId val=\"{0}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\" /><c:axPos val=\"b\"/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{1}\"/><c:crosses val=\"autoZero\"/><c:auto val=\"1\"/><c:lblAlgn val=\"ctr\"/><c:lblOffset val=\"100\"/>", axID, axID + 1); |
| valAx.InnerXml = string.Format("<c:axId val=\"{1}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\" /><c:axPos val=\"l\"/><c:majorGridlines/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{0}\"/><c:crosses val=\"autoZero\"/><c:crossBetween val=\"between\"/>", axID, axID + 1); |
| } |
| else |
| { |
| catAx.InnerXml = string.Format("<c:axId val=\"{0}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"1\" /><c:axPos val=\"b\"/><c:tickLblPos val=\"none\"/><c:crossAx val=\"{1}\"/><c:crosses val=\"autoZero\"/>", axID, axID + 1); |
| valAx.InnerXml = string.Format("<c:axId val=\"{0}\"/><c:scaling><c:orientation val=\"minMax\"/></c:scaling><c:delete val=\"0\" /><c:axPos val=\"r\"/><c:tickLblPos val=\"nextTo\"/><c:crossAx val=\"{1}\"/><c:crosses val=\"max\"/><c:crossBetween val=\"between\"/>", axID + 1, axID); |
| } |
| |
| if (_axis.Length == 0) |
| { |
| _axis = new ExcelChartAxis[2]; |
| } |
| else |
| { |
| ExcelChartAxis[] newAxis = new ExcelChartAxis[_axis.Length + 2]; |
| Array.Copy(_axis, newAxis, _axis.Length); |
| _axis = newAxis; |
| } |
| |
| _axis[_axis.Length - 2] = new ExcelChartAxis(NameSpaceManager, catAx); |
| _axis[_axis.Length - 1] = new ExcelChartAxis(NameSpaceManager, valAx); |
| foreach (var chart in _plotArea.ChartTypes) |
| { |
| chart._axis = _axis; |
| } |
| } |
| internal void RemoveSecondaryAxis() |
| { |
| throw (new NotImplementedException("Not yet implemented")); |
| } |
| #region "Properties" |
| /// <summary> |
| /// Reference to the worksheet |
| /// </summary> |
| public ExcelWorksheet WorkSheet { get; internal set; } |
| /// <summary> |
| /// The chart xml document |
| /// </summary> |
| public XmlDocument ChartXml { get; internal set; } |
| /// <summary> |
| /// Type of chart |
| /// </summary> |
| public eChartType ChartType { get; internal set; } |
| internal protected XmlNode _chartNode = null; |
| internal XmlNode ChartNode |
| { |
| get |
| { |
| return _chartNode; |
| } |
| } |
| /// <summary> |
| /// Titel of the chart |
| /// </summary> |
| public ExcelChartTitle Title |
| { |
| get |
| { |
| if (_title == null) |
| { |
| _title = new ExcelChartTitle(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace/c:chart", NameSpaceManager)); |
| } |
| return _title; |
| } |
| } |
| /// <summary> |
| /// Chart series |
| /// </summary> |
| public virtual ExcelChartSeries Series |
| { |
| get |
| { |
| return _chartSeries; |
| } |
| } |
| /// <summary> |
| /// An array containg all axis of all Charttypes |
| /// </summary> |
| public ExcelChartAxis[] Axis |
| { |
| get |
| { |
| return _axis; |
| } |
| } |
| /// <summary> |
| /// The XAxis |
| /// </summary> |
| public ExcelChartAxis XAxis |
| { |
| get; |
| private set; |
| } |
| /// <summary> |
| /// The YAxis |
| /// </summary> |
| public ExcelChartAxis YAxis |
| { |
| get; |
| private set; |
| } |
| bool _secondaryAxis=false; |
| /// <summary> |
| /// If true the charttype will use the secondary axis. |
| /// The chart must contain a least one other charttype that uses the primary axis. |
| /// </summary> |
| public bool UseSecondaryAxis |
| { |
| get |
| { |
| return _secondaryAxis; |
| } |
| set |
| { |
| if (_secondaryAxis != value) |
| { |
| if (value) |
| { |
| if (IsTypePieDoughnut()) |
| { |
| throw (new Exception("Pie charts do not support axis")); |
| } |
| else if (HasPrimaryAxis() == false) |
| { |
| throw (new Exception("Can't set to secondary axis when no serie uses the primary axis")); |
| } |
| if (Axis.Length == 2) |
| { |
| AddAxis(); |
| } |
| var nl = ChartNode.SelectNodes("c:axId", NameSpaceManager); |
| nl[0].Attributes["val"].Value = Axis[2].Id; |
| nl[1].Attributes["val"].Value = Axis[3].Id; |
| XAxis = Axis[2]; |
| YAxis = Axis[3]; |
| } |
| else |
| { |
| var nl = ChartNode.SelectNodes("c:axId", NameSpaceManager); |
| nl[0].Attributes["val"].Value = Axis[0].Id; |
| nl[1].Attributes["val"].Value = Axis[1].Id; |
| XAxis = Axis[0]; |
| YAxis = Axis[1]; |
| } |
| _secondaryAxis = value; |
| } |
| } |
| } |
| /// <summary> |
| /// The build-in chart styles. |
| /// </summary> |
| public eChartStyle Style |
| { |
| get |
| { |
| XmlNode node = ChartXml.SelectSingleNode("c:chartSpace/c:style/@val", NameSpaceManager); |
| if (node == null) |
| { |
| return eChartStyle.None; |
| } |
| else |
| { |
| int v; |
| if (int.TryParse(node.Value, out v)) |
| { |
| return (eChartStyle)v; |
| } |
| else |
| { |
| return eChartStyle.None; |
| } |
| } |
| |
| } |
| set |
| { |
| if (value == eChartStyle.None) |
| { |
| XmlElement element = ChartXml.SelectSingleNode("c:chartSpace/c:style", NameSpaceManager) as XmlElement; |
| if (element != null) |
| { |
| element.ParentNode.RemoveChild(element); |
| } |
| } |
| else |
| { |
| XmlElement element = ChartXml.CreateElement("c:style", ExcelPackage.schemaChart); |
| element.SetAttribute("val", ((int)value).ToString()); |
| XmlElement parent = ChartXml.SelectSingleNode("c:chartSpace", NameSpaceManager) as XmlElement; |
| parent.InsertBefore(element, parent.SelectSingleNode("c:chart", NameSpaceManager)); |
| } |
| } |
| } |
| const string _plotVisibleOnlyPath="../../c:plotVisOnly/@val"; |
| /// <summary> |
| /// Show data in hidden rows and columns |
| /// </summary> |
| public bool ShowHiddenData |
| { |
| get |
| { |
| //!!Inverted value!! |
| return !_chartXmlHelper.GetXmlNodeBool(_plotVisibleOnlyPath); |
| } |
| set |
| { |
| //!!Inverted value!! |
| _chartXmlHelper.SetXmlNodeBool(_plotVisibleOnlyPath, !value); |
| } |
| } |
| const string _displayBlanksAsPath = "../../c:dispBlanksAs/@val"; |
| /// <summary> |
| /// Specifies the possible ways to display blanks |
| /// </summary> |
| public eDisplayBlanksAs DisplayBlanksAs |
| { |
| get |
| { |
| string v=_chartXmlHelper.GetXmlNodeString(_displayBlanksAsPath); |
| if (string.IsNullOrEmpty(v)) |
| { |
| return eDisplayBlanksAs.Zero; //Issue 14715 Changed in Office 2010-? |
| } |
| else |
| { |
| return (eDisplayBlanksAs)Enum.Parse(typeof(eDisplayBlanksAs), v, true); |
| } |
| } |
| set |
| { |
| _chartSeries.SetXmlNodeString(_displayBlanksAsPath, value.ToString().ToLower(CultureInfo.InvariantCulture)); |
| } |
| } |
| const string _showDLblsOverMax = "../../c:showDLblsOverMax/@val"; |
| /// <summary> |
| /// Specifies data labels over the maximum of the chart shall be shown |
| /// </summary> |
| public bool ShowDataLabelsOverMaximum |
| { |
| get |
| { |
| return _chartXmlHelper.GetXmlNodeBool(_showDLblsOverMax, true); |
| } |
| set |
| { |
| _chartXmlHelper.SetXmlNodeBool(_showDLblsOverMax,value, true); |
| } |
| } |
| private bool HasPrimaryAxis() |
| { |
| if (_plotArea.ChartTypes.Count == 1) |
| { |
| return false; |
| } |
| foreach (var chart in _plotArea.ChartTypes) |
| { |
| if (chart != this) |
| { |
| if (chart.UseSecondaryAxis == false && chart.IsTypePieDoughnut()==false) |
| { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| ///// <summary> |
| ///// Sets position of the axis of a chart-serie |
| ///// </summary> |
| ///// <param name="XAxis">Left or Right</param> |
| ///// <param name="YAxis">Top or Bottom</param> |
| //internal void SetAxis(eXAxisPosition XAxis, eYAxisPosition YAxis) |
| //{ |
| // bool xAxisExists = false, yAxisExists = false; |
| // foreach (var axis in _axis) |
| // { |
| // if (axis.AxisPosition == (eAxisPosition)XAxis) |
| // { |
| // //Found |
| // xAxisExists=true; |
| // if (axis != this.XAxis) |
| // { |
| // CheckRemoveAxis(this.XAxis); |
| // this.XAxis = axis; |
| // } |
| // } |
| // else if (axis.AxisPosition == (eAxisPosition)YAxis) |
| // { |
| // yAxisExists = true; |
| // if (axis != this.YAxis) |
| // { |
| // CheckRemoveAxis(this.YAxis); |
| // this.YAxis = axis; |
| // } |
| // } |
| // } |
| |
| // if (!xAxisExists) |
| // { |
| // if (ExistsAxis(this.XAxis)) |
| // { |
| // AddAxis((eAxisPosition)XAxis); |
| // this.XAxis = Axis[Axis.Length - 1]; |
| // } |
| // else |
| // { |
| // this.XAxis.AxisPosition = (eAxisPosition)XAxis; |
| // } |
| // } |
| // if (!yAxisExists) |
| // { |
| // if (ExistsAxis(this.XAxis)) |
| // { |
| // AddAxis((eAxisPosition)YAxis); |
| // this.YAxis = Axis[Axis.Length - 1]; |
| // } |
| // else |
| // { |
| // this.YAxis.AxisPosition = (eAxisPosition)YAxis; |
| // } |
| // } |
| //} |
| |
| /// <summary> |
| /// Remove all axis that are not used any more |
| /// </summary> |
| /// <param name="excelChartAxis"></param> |
| private void CheckRemoveAxis(ExcelChartAxis excelChartAxis) |
| { |
| if (ExistsAxis(excelChartAxis)) |
| { |
| //Remove the axis |
| ExcelChartAxis[] newAxis = new ExcelChartAxis[Axis.Length - 1]; |
| int pos = 0; |
| foreach (var ax in Axis) |
| { |
| if (ax != excelChartAxis) |
| { |
| newAxis[pos] = ax; |
| } |
| } |
| |
| //Update all charttypes. |
| foreach (ExcelChart chartType in _plotArea.ChartTypes) |
| { |
| chartType._axis = newAxis; |
| } |
| } |
| } |
| |
| private bool ExistsAxis(ExcelChartAxis excelChartAxis) |
| { |
| foreach (ExcelChart chartType in _plotArea.ChartTypes) |
| { |
| if (chartType != this) |
| { |
| if (chartType.XAxis.AxisPosition == excelChartAxis.AxisPosition || |
| chartType.YAxis.AxisPosition == excelChartAxis.AxisPosition) |
| { |
| //The axis exists |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| ExcelChartPlotArea _plotArea = null; |
| /// <summary> |
| /// Plotarea |
| /// </summary> |
| public ExcelChartPlotArea PlotArea |
| { |
| get |
| { |
| if (_plotArea == null) |
| { |
| _plotArea = new ExcelChartPlotArea(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace/c:chart/c:plotArea", NameSpaceManager), this); |
| } |
| return _plotArea; |
| } |
| } |
| ExcelChartLegend _legend = null; |
| /// <summary> |
| /// Legend |
| /// </summary> |
| public ExcelChartLegend Legend |
| { |
| get |
| { |
| if (_legend == null) |
| { |
| _legend = new ExcelChartLegend(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace/c:chart/c:legend", NameSpaceManager), this); |
| } |
| return _legend; |
| } |
| |
| } |
| ExcelDrawingBorder _border = null; |
| /// <summary> |
| /// Border |
| /// </summary> |
| public ExcelDrawingBorder Border |
| { |
| get |
| { |
| if (_border == null) |
| { |
| _border = new ExcelDrawingBorder(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace",NameSpaceManager), "c:spPr/a:ln"); |
| } |
| return _border; |
| } |
| } |
| ExcelDrawingFill _fill = null; |
| /// <summary> |
| /// Fill |
| /// </summary> |
| public ExcelDrawingFill Fill |
| { |
| get |
| { |
| if (_fill == null) |
| { |
| _fill = new ExcelDrawingFill(NameSpaceManager, ChartXml.SelectSingleNode("c:chartSpace", NameSpaceManager), "c:spPr"); |
| } |
| return _fill; |
| } |
| } |
| /// <summary> |
| /// 3D-settings |
| /// </summary> |
| public ExcelView3D View3D |
| { |
| get |
| { |
| if (IsType3D()) |
| { |
| return new ExcelView3D(NameSpaceManager, ChartXml.SelectSingleNode("//c:view3D", NameSpaceManager)); |
| } |
| else |
| { |
| throw (new Exception("Charttype does not support 3D")); |
| } |
| |
| } |
| } |
| //string _groupingPath = "c:chartSpace/c:chart/c:plotArea/{0}/c:grouping/@val"; |
| string _groupingPath = "c:grouping/@val"; |
| public eGrouping Grouping |
| { |
| get |
| { |
| return GetGroupingEnum(_chartXmlHelper.GetXmlNodeString(_groupingPath)); |
| } |
| internal set |
| { |
| _chartXmlHelper.SetXmlNodeString(_groupingPath, GetGroupingText(value)); |
| } |
| } |
| //string _varyColorsPath = "c:chartSpace/c:chart/c:plotArea/{0}/c:varyColors/@val"; |
| string _varyColorsPath = "c:varyColors/@val"; |
| /// <summary> |
| /// If the chart has only one serie this varies the colors for each point. |
| /// </summary> |
| public bool VaryColors |
| { |
| get |
| { |
| return _chartXmlHelper.GetXmlNodeBool(_varyColorsPath); |
| } |
| set |
| { |
| if (value) |
| { |
| _chartXmlHelper.SetXmlNodeString(_varyColorsPath, "1"); |
| } |
| else |
| { |
| _chartXmlHelper.SetXmlNodeString(_varyColorsPath, "0"); |
| } |
| } |
| } |
| internal Packaging.ZipPackagePart Part { get; set; } |
| /// <summary> |
| /// Package internal URI |
| /// </summary> |
| internal Uri UriChart { get; set; } |
| internal new string Id |
| { |
| get { return ""; } |
| } |
| ExcelChartTitle _title = null; |
| #endregion |
| #region "Grouping Enum Translation" |
| private string GetGroupingText(eGrouping grouping) |
| { |
| switch (grouping) |
| { |
| case eGrouping.Clustered: |
| return "clustered"; |
| case eGrouping.Stacked: |
| return "stacked"; |
| case eGrouping.PercentStacked: |
| return "percentStacked"; |
| default: |
| return "standard"; |
| |
| } |
| } |
| private eGrouping GetGroupingEnum(string grouping) |
| { |
| switch (grouping) |
| { |
| case "stacked": |
| return eGrouping.Stacked; |
| case "percentStacked": |
| return eGrouping.PercentStacked; |
| default: //"clustered": |
| return eGrouping.Clustered; |
| } |
| } |
| #endregion |
| internal static ExcelChart GetChart(ExcelDrawings drawings, XmlNode node/*, XmlNode chartTypeNode*/) |
| { |
| XmlNode chartNode = node.SelectSingleNode("xdr:graphicFrame/a:graphic/a:graphicData/c:chart", drawings.NameSpaceManager); |
| if (chartNode != null) |
| { |
| var drawingRelation = drawings.Part.GetRelationship(chartNode.Attributes["r:id"].Value); |
| var uriChart = UriHelper.ResolvePartUri(drawings.UriDrawing, drawingRelation.TargetUri); |
| |
| var part = drawings.Part.Package.GetPart(uriChart); |
| var chartXml = new XmlDocument(); |
| LoadXmlSafe(chartXml, part.GetStream()); |
| |
| ExcelChart topChart = null; |
| foreach (XmlElement n in chartXml.SelectSingleNode(rootPath, drawings.NameSpaceManager).ChildNodes) |
| { |
| if (topChart == null) |
| { |
| topChart = GetChart(n, drawings, node, uriChart, part, chartXml, null); |
| if(topChart!=null) |
| { |
| topChart.PlotArea.ChartTypes.Add(topChart); |
| } |
| } |
| else |
| { |
| var subChart = GetChart(n, null, null, null, null, null, topChart); |
| if (subChart != null) |
| { |
| topChart.PlotArea.ChartTypes.Add(subChart); |
| } |
| } |
| } |
| return topChart; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| internal static ExcelChart GetChart(XmlElement chartNode, ExcelDrawings drawings, XmlNode node, Uri uriChart, Packaging.ZipPackagePart part, XmlDocument chartXml, ExcelChart topChart) |
| { |
| switch (chartNode.LocalName) |
| { |
| case "area3DChart": |
| case "areaChart": |
| case "stockChart": |
| if (topChart == null) |
| { |
| return new ExcelChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelChart(topChart, chartNode); |
| } |
| case "surface3DChart": |
| case "surfaceChart": |
| if (topChart == null) |
| { |
| return new ExcelSurfaceChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelSurfaceChart(topChart, chartNode); |
| } |
| case "radarChart": |
| if (topChart == null) |
| { |
| return new ExcelRadarChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelRadarChart(topChart, chartNode); |
| } |
| case "bubbleChart": |
| if (topChart == null) |
| { |
| return new ExcelBubbleChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelBubbleChart(topChart, chartNode); |
| } |
| case "barChart": |
| case "bar3DChart": |
| if (topChart == null) |
| { |
| return new ExcelBarChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelBarChart(topChart, chartNode); |
| } |
| case "doughnutChart": |
| if (topChart == null) |
| { |
| return new ExcelDoughnutChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelDoughnutChart(topChart, chartNode); |
| } |
| case "pie3DChart": |
| case "pieChart": |
| if (topChart == null) |
| { |
| return new ExcelPieChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelPieChart(topChart, chartNode); |
| } |
| case "ofPieChart": |
| if (topChart == null) |
| { |
| return new ExcelOfPieChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelBarChart(topChart, chartNode); |
| } |
| case "lineChart": |
| case "line3DChart": |
| if (topChart == null) |
| { |
| return new ExcelLineChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelLineChart(topChart, chartNode); |
| } |
| case "scatterChart": |
| if (topChart == null) |
| { |
| return new ExcelScatterChart(drawings, node, uriChart, part, chartXml, chartNode); |
| } |
| else |
| { |
| return new ExcelScatterChart(topChart, chartNode); |
| } |
| default: |
| return null; |
| } |
| } |
| internal static ExcelChart GetNewChart(ExcelDrawings drawings, XmlNode drawNode, eChartType chartType, ExcelChart topChart, ExcelPivotTable PivotTableSource) |
| { |
| switch(chartType) |
| { |
| case eChartType.Pie: |
| case eChartType.PieExploded: |
| case eChartType.Pie3D: |
| case eChartType.PieExploded3D: |
| return new ExcelPieChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.BarOfPie: |
| case eChartType.PieOfPie: |
| return new ExcelOfPieChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.Doughnut: |
| case eChartType.DoughnutExploded: |
| return new ExcelDoughnutChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.BarClustered: |
| case eChartType.BarStacked: |
| case eChartType.BarStacked100: |
| case eChartType.BarClustered3D: |
| case eChartType.BarStacked3D: |
| case eChartType.BarStacked1003D: |
| case eChartType.ConeBarClustered: |
| case eChartType.ConeBarStacked: |
| case eChartType.ConeBarStacked100: |
| case eChartType.CylinderBarClustered: |
| case eChartType.CylinderBarStacked: |
| case eChartType.CylinderBarStacked100: |
| case eChartType.PyramidBarClustered: |
| case eChartType.PyramidBarStacked: |
| case eChartType.PyramidBarStacked100: |
| case eChartType.ColumnClustered: |
| case eChartType.ColumnStacked: |
| case eChartType.ColumnStacked100: |
| case eChartType.Column3D: |
| case eChartType.ColumnClustered3D: |
| case eChartType.ColumnStacked3D: |
| case eChartType.ColumnStacked1003D: |
| case eChartType.ConeCol: |
| case eChartType.ConeColClustered: |
| case eChartType.ConeColStacked: |
| case eChartType.ConeColStacked100: |
| case eChartType.CylinderCol: |
| case eChartType.CylinderColClustered: |
| case eChartType.CylinderColStacked: |
| case eChartType.CylinderColStacked100: |
| case eChartType.PyramidCol: |
| case eChartType.PyramidColClustered: |
| case eChartType.PyramidColStacked: |
| case eChartType.PyramidColStacked100: |
| return new ExcelBarChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.XYScatter: |
| case eChartType.XYScatterLines: |
| case eChartType.XYScatterLinesNoMarkers: |
| case eChartType.XYScatterSmooth: |
| case eChartType.XYScatterSmoothNoMarkers: |
| return new ExcelScatterChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.Line: |
| case eChartType.Line3D: |
| case eChartType.LineMarkers: |
| case eChartType.LineMarkersStacked: |
| case eChartType.LineMarkersStacked100: |
| case eChartType.LineStacked: |
| case eChartType.LineStacked100: |
| return new ExcelLineChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.Bubble: |
| case eChartType.Bubble3DEffect: |
| return new ExcelBubbleChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.Radar: |
| case eChartType.RadarFilled: |
| case eChartType.RadarMarkers: |
| return new ExcelRadarChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| case eChartType.Surface: |
| case eChartType.SurfaceTopView: |
| case eChartType.SurfaceTopViewWireframe: |
| case eChartType.SurfaceWireframe: |
| return new ExcelSurfaceChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| default: |
| return new ExcelChart(drawings, drawNode, chartType, topChart, PivotTableSource); |
| } |
| } |
| public ExcelPivotTable PivotTableSource |
| { |
| get; |
| private set; |
| } |
| internal void SetPivotSource(ExcelPivotTable pivotTableSource) |
| { |
| PivotTableSource = pivotTableSource; |
| XmlElement chart = ChartXml.SelectSingleNode("c:chartSpace/c:chart", NameSpaceManager) as XmlElement; |
| |
| var pivotSource = ChartXml.CreateElement("pivotSource", ExcelPackage.schemaChart); |
| chart.ParentNode.InsertBefore(pivotSource, chart); |
| pivotSource.InnerXml = string.Format("<c:name>[]{0}!{1}</c:name><c:fmtId val=\"0\"/>", PivotTableSource.WorkSheet.Name, pivotTableSource.Name); |
| |
| var fmts = ChartXml.CreateElement("pivotFmts", ExcelPackage.schemaChart); |
| chart.PrependChild(fmts); |
| fmts.InnerXml = "<c:pivotFmt><c:idx val=\"0\"/><c:marker><c:symbol val=\"none\"/></c:marker></c:pivotFmt>"; |
| |
| Series.AddPivotSerie(pivotTableSource); |
| } |
| internal override void DeleteMe() |
| { |
| try |
| { |
| Part.Package.DeletePart(UriChart); |
| } |
| catch (Exception ex) |
| { |
| throw (new InvalidDataException("EPPlus internal error when deleteing chart.", ex)); |
| } |
| base.DeleteMe(); |
| } |
| } |
| } |