Browse Source

Made insert chart method and created legend class for this chart

master
DragonFire_cp 14 years ago
parent
commit
c8e4262a6d
4 changed files with 441 additions and 253 deletions
  1. 421
    0
      DocX/Chart.cs
  2. 10
    251
      DocX/DocX.cs
  3. 1
    0
      DocX/DocX.csproj
  4. 9
    2
      Examples/Program.cs

+ 421
- 0
DocX/Chart.cs View File

@@ -0,0 +1,421 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.IO.Packaging;
namespace Novacode
{
/// <summary>
/// Represents a Chart in this document.
/// </summary>
public class Chart
{
private XElement LegendXml;
private XElement ChartXml;
private XElement ChartRootXml;
public XDocument Xml { get; private set; }
public List<XElement> Series
{
get
{
List<XElement> series = new List<XElement>();
GetSeriesRecursive(Xml.Root, series);
return series;
}
}
private void GetSeriesRecursive(XElement element, List<XElement> series)
{
if (element.Name.LocalName == "ser")
{
series.Add(element);
}
else
{
if (element.HasElements)
foreach (XElement e in element.Elements())
GetSeriesRecursive(e, series);
}
}
private ChartLegend legend;
public ChartLegend Legend { get { return legend; } }
/// <summary>
/// Create an Chart for this document
/// </summary>
public Chart()
{
#region Create Bar Chart
ChartXml = XElement.Parse(
@"<c:barChart xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"">
<c:barDir val=""col""/>
<c:grouping val=""clustered""/>
<c:ser>
<c:idx val=""0""/>
<c:order val=""0""/>
<c:tx>
<c:strRef>
<c:f>Лист1!$B$1</c:f>
<c:strCache>
<c:ptCount val=""1""/>
<c:pt idx=""0"">
<c:v>Ряд 1</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:invertIfNegative val=""0""/>
<c:cat>
<c:strRef>
<c:f>Лист1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>Категория 1</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>Категория 2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>Категория 3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>Категория 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Лист1!$B$2:$B$5</c:f>
<c:numCache>
<c:formatCode>Основной</c:formatCode>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>4.3</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>2.5</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>3.5</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>4.5</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
<c:ser>
<c:idx val=""1""/>
<c:order val=""1""/>
<c:tx>
<c:strRef>
<c:f>Лист1!$C$1</c:f>
<c:strCache>
<c:ptCount val=""1""/>
<c:pt idx=""0"">
<c:v>Ряд 2</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:invertIfNegative val=""0""/>
<c:cat>
<c:strRef>
<c:f>Лист1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>Категория 1</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>Категория 2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>Категория 3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>Категория 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Лист1!$C$2:$C$5</c:f>
<c:numCache>
<c:formatCode>Основной</c:formatCode>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>2.4</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>4.4000000000000004</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>1.8</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>2.8</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
<c:ser>
<c:idx val=""2""/>
<c:order val=""2""/>
<c:tx>
<c:strRef>
<c:f>Лист1!$D$1</c:f>
<c:strCache>
<c:ptCount val=""1""/>
<c:pt idx=""0"">
<c:v>Ряд 3</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:invertIfNegative val=""0""/>
<c:cat>
<c:strRef>
<c:f>Лист1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>Категория 1</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>Категория 2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>Категория 3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>Категория 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Лист1!$D$2:$D$5</c:f>
<c:numCache>
<c:formatCode>Основной</c:formatCode>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>2</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>5</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
<c:dLbls>
<c:showLegendKey val=""0""/>
<c:showVal val=""0""/>
<c:showCatName val=""0""/>
<c:showSerName val=""0""/>
<c:showPercent val=""0""/>
<c:showBubbleSize val=""0""/>
</c:dLbls>
<c:gapWidth val=""150""/>
<c:axId val=""148921728""/>
<c:axId val=""154227840""/>
</c:barChart>");
#endregion
XElement catAx = XElement.Parse(
@"<c:catAx xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"">
<c:axId val=""148921728""/>
<c:scaling>
<c:orientation val=""minMax""/>
</c:scaling>
<c:delete val=""0""/>
<c:axPos val=""b""/>
<c:majorTickMark val=""out""/>
<c:minorTickMark val=""none""/>
<c:tickLblPos val=""nextTo""/>
<c:crossAx val=""154227840""/>
<c:crosses val=""autoZero""/>
<c:auto val=""1""/>
<c:lblAlgn val=""ctr""/>
<c:lblOffset val=""100""/>
<c:noMultiLvlLbl val=""0""/>
</c:catAx>");
XElement valAx = XElement.Parse(
@"<c:valAx xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"">
<c:axId val=""154227840""/>
<c:scaling>
<c:orientation val=""minMax""/>
</c:scaling>
<c:delete val=""0""/>
<c:axPos val=""l""/>
<c:majorGridlines/>
<c:numFmt formatCode=""Основной"" sourceLinked=""1""/>
<c:majorTickMark val=""out""/>
<c:minorTickMark val=""none""/>
<c:tickLblPos val=""nextTo""/>
<c:crossAx val=""148921728""/>
<c:crosses val=""autoZero""/>
<c:crossBetween val=""between""/>
</c:valAx>");
XElement PlotArea = new XElement(
XName.Get("plotArea", DocX.c.NamespaceName),
new XElement(XName.Get("layout", DocX.c.NamespaceName)),
ChartXml, catAx, valAx);
Xml = XDocument.Parse
(@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<c:chartSpace xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"" xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"" xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships"">
<c:roundedCorners val=""0""/>
<c:chart>
<c:autoTitleDeleted val=""0""/>
<c:plotVisOnly val=""1""/>
<c:dispBlanksAs val=""gap""/>
<c:showDLblsOverMax val=""0""/>
</c:chart>
</c:chartSpace>");
ChartRootXml = Xml.Root.Element(XName.Get("chart", DocX.c.NamespaceName));
ChartRootXml.Add(PlotArea);
}
public void AddLegend()
{
AddLegend(ChartLegendPosition.Right, false);
}
public void AddLegend(ChartLegendPosition position, Boolean overlay)
{
if (legend != null)
RemoveLegend();
legend = new ChartLegend(position, overlay);
ChartRootXml.Add(legend.Xml);
}
public void RemoveLegend()
{
legend.Xml.Remove();
legend = null;
}
}
/// <summary>
/// Represents a chart legend
/// More: http://msdn.microsoft.com/ru-ru/library/cc845123.aspx
/// </summary>
public class ChartLegend
{
/// <summary>
/// Legend xml element
/// </summary>
internal XElement Xml { get; private set; }
/// <summary>
/// Specifies that other chart elements shall be allowed to overlap this chart element
/// </summary>
public Boolean Overlay
{
get { return Xml.Element(XName.Get("overlay", DocX.c.NamespaceName)).Attribute("val").Value == "1"; }
set { Xml.Element(XName.Get("overlay", DocX.c.NamespaceName)).Attribute("val").Value = GetOverlayValue(value); }
}
/// <summary>
/// Specifies the possible positions for a legend
/// </summary>
public ChartLegendPosition Position
{
get
{
switch (Xml.Element(XName.Get("legendPos", DocX.c.NamespaceName)).Attribute("val").Value)
{
case "t": return ChartLegendPosition.Top;
case "b": return ChartLegendPosition.Bottom;
case "l": return ChartLegendPosition.Left;
case "r": return ChartLegendPosition.Right;
case "tr": return ChartLegendPosition.TopRight;
default: throw new NotImplementedException();
}
}
set
{
Xml.Element(XName.Get("legendPos", DocX.c.NamespaceName)).Attribute("val").Value = GetPositionValue(value);
}
}
internal ChartLegend(ChartLegendPosition position, Boolean overlay)
{
Xml = new XElement(
XName.Get("legend", DocX.c.NamespaceName),
new XElement(XName.Get("legendPos", DocX.c.NamespaceName), new XAttribute("val", GetPositionValue(position))),
new XElement(XName.Get("overlay", DocX.c.NamespaceName), new XAttribute("val", GetOverlayValue(overlay)))
);
}
/// <summary>
/// ECMA-376, page 3840
/// 21.2.2.132 overlay (Overlay)
/// </summary>
private String GetOverlayValue(Boolean overlay)
{
if (overlay)
return "1";
else
return "0";
}
/// <summary>
/// ECMA-376, page 3906
/// 21.2.3.24 ST_LegendPos (Legend Position)
/// </summary>
private String GetPositionValue(ChartLegendPosition position)
{
switch (position)
{
case ChartLegendPosition.Top:
return "t";
case ChartLegendPosition.Bottom:
return "b";
case ChartLegendPosition.Left:
return "l";
case ChartLegendPosition.Right:
return "r";
case ChartLegendPosition.TopRight:
return "tr";
default:
throw new NotImplementedException();
}
}
}
/// <summary>
/// Specifies the possible positions for a legend
/// </summary>
public enum ChartLegendPosition
{
Top,
Bottom,
Left,
Right,
TopRight
}
}

+ 10
- 251
DocX/DocX.cs View File

@@ -2854,248 +2854,11 @@ namespace Novacode
return p;
}
public void InsertChartInTheDevelopment()
{
// Magic
String chartXml =
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<c:chartSpace xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"" xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"" xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships"">
<c:roundedCorners val=""0""/>
<c:chart>
<c:autoTitleDeleted val=""0""/>
<c:plotArea>
<c:layout/>
<c:barChart>
<c:barDir val=""col""/>
<c:grouping val=""clustered""/>
<c:varyColors val=""0""/>
<c:ser>
<c:idx val=""0""/>
<c:order val=""0""/>
<c:tx>
<c:strRef>
<c:f>Лист1!$B$1</c:f>
<c:strCache>
<c:ptCount val=""1""/>
<c:pt idx=""0"">
<c:v>Ряд 1</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:invertIfNegative val=""0""/>
<c:cat>
<c:strRef>
<c:f>Лист1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>Категория 1</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>Категория 2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>Категория 3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>Категория 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Лист1!$B$2:$B$5</c:f>
<c:numCache>
<c:formatCode>Основной</c:formatCode>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>4.3</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>2.5</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>3.5</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>4.5</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
<c:ser>
<c:idx val=""1""/>
<c:order val=""1""/>
<c:tx>
<c:strRef>
<c:f>Лист1!$C$1</c:f>
<c:strCache>
<c:ptCount val=""1""/>
<c:pt idx=""0"">
<c:v>Ряд 2</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:invertIfNegative val=""0""/>
<c:cat>
<c:strRef>
<c:f>Лист1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>Категория 1</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>Категория 2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>Категория 3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>Категория 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Лист1!$C$2:$C$5</c:f>
<c:numCache>
<c:formatCode>Основной</c:formatCode>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>2.4</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>4.4000000000000004</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>1.8</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>2.8</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
<c:ser>
<c:idx val=""2""/>
<c:order val=""2""/>
<c:tx>
<c:strRef>
<c:f>Лист1!$D$1</c:f>
<c:strCache>
<c:ptCount val=""1""/>
<c:pt idx=""0"">
<c:v>Ряд 3</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:invertIfNegative val=""0""/>
<c:cat>
<c:strRef>
<c:f>Лист1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>Категория 1</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>Категория 2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>Категория 3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>Категория 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Лист1!$D$2:$D$5</c:f>
<c:numCache>
<c:formatCode>Основной</c:formatCode>
<c:ptCount val=""4""/>
<c:pt idx=""0"">
<c:v>2</c:v>
</c:pt>
<c:pt idx=""1"">
<c:v>2</c:v>
</c:pt>
<c:pt idx=""2"">
<c:v>3</c:v>
</c:pt>
<c:pt idx=""3"">
<c:v>5</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
<c:dLbls>
<c:showLegendKey val=""0""/>
<c:showVal val=""0""/>
<c:showCatName val=""0""/>
<c:showSerName val=""0""/>
<c:showPercent val=""0""/>
<c:showBubbleSize val=""0""/>
</c:dLbls>
<c:gapWidth val=""150""/>
<c:axId val=""148921728""/>
<c:axId val=""154227840""/>
</c:barChart>
<c:catAx>
<c:axId val=""148921728""/>
<c:scaling>
<c:orientation val=""minMax""/>
</c:scaling>
<c:delete val=""0""/>
<c:axPos val=""b""/>
<c:majorTickMark val=""out""/>
<c:minorTickMark val=""none""/>
<c:tickLblPos val=""nextTo""/>
<c:crossAx val=""154227840""/>
<c:crosses val=""autoZero""/>
<c:auto val=""1""/>
<c:lblAlgn val=""ctr""/>
<c:lblOffset val=""100""/>
<c:noMultiLvlLbl val=""0""/>
</c:catAx>
<c:valAx>
<c:axId val=""154227840""/>
<c:scaling>
<c:orientation val=""minMax""/>
</c:scaling>
<c:delete val=""0""/>
<c:axPos val=""l""/>
<c:majorGridlines/>
<c:numFmt formatCode=""Основной"" sourceLinked=""1""/>
<c:majorTickMark val=""out""/>
<c:minorTickMark val=""none""/>
<c:tickLblPos val=""nextTo""/>
<c:crossAx val=""148921728""/>
<c:crosses val=""autoZero""/>
<c:crossBetween val=""between""/>
</c:valAx>
</c:plotArea>
<c:legend>
<c:legendPos val=""r""/>
<c:overlay val=""0""/>
</c:legend>
<c:plotVisOnly val=""1""/>
<c:dispBlanksAs val=""gap""/>
<c:showDLblsOverMax val=""0""/>
</c:chart>
</c:chartSpace>";
/// <summary>
/// Insert a chart in document
/// </summary>
public void InsertChartInTheDevelopment(Chart chart)
{
// Create a new chart part uri.
String chartPartUriPath = String.Empty;
Int32 chartIndex = 1;
@@ -3110,18 +2873,14 @@ namespace Novacode
} while (package.PartExists(new Uri(chartPartUriPath, UriKind.Relative)));
// Create chart part.
PackagePart chart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml");
PackagePart chartPackagePart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml");
// Create a new chart relationship
String relID = GetNextFreeRelationshipID();
PackageRelationship rel = mainPart.CreateRelationship(chart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID);
PackageRelationship rel = mainPart.CreateRelationship(chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID);
// Open a Stream to the newly created chart part.
using (Stream stream = chart.GetStream(FileMode.Create, FileAccess.Write))
{
byte[] byteArray = Encoding.UTF8.GetBytes(chartXml);
stream.Write(byteArray, 0, byteArray.Length);
}
// Save a chart info the chartPackagePart
chart.Xml.Save(chartPackagePart.GetStream(FileMode.Create, FileAccess.Write));
// Insert a new chart into a paragraph.
Paragraph p = InsertParagraph();
@@ -3147,7 +2906,7 @@ namespace Novacode
)
)
));
p.Xml.Add(chartElement);
p.Xml.Add(chartElement);
}
#region IDisposable Members

+ 1
- 0
DocX/DocX.csproj View File

@@ -87,6 +87,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Border.cs" />
<Compile Include="Chart.cs" />
<Compile Include="Container.cs" />
<Compile Include="Footers.cs" />
<Compile Include="Footer.cs" />

+ 9
- 2
Examples/Program.cs View File

@@ -46,11 +46,18 @@ namespace Examples
{
using (DocX document = DocX.Create(@"docs\Chart.docx"))
{
Chart c = new Chart();
c.AddLegend(ChartLegendPosition.Bottom, false);
c.Legend.Overlay = true;
c.Legend.Position = ChartLegendPosition.Top;
c.RemoveLegend();
c.AddLegend();
c.AddLegend(ChartLegendPosition.Left, true);
document.InsertParagraph("Красивая диаграмма").FontSize(20);
document.InsertParagraph("Текст1");
document.InsertChartInTheDevelopment();
document.InsertChartInTheDevelopment(c);
document.InsertParagraph("Текст2");
document.InsertChartInTheDevelopment();
document.Save();
}
}

Loading…
Cancel
Save