OpenXML: excel 插入BarChart图表
Openxml format SDK 2.0 v2 的 how to 文章里提供了一个怎样插入 chart 图表的示例, 但这个 chart的数据是独立不是根据excel sheet 上data 动态生成的chart,因此, 我在此示例代码上做了一些改动,可以根据excel sheet 上的数据, 生成 chart 图片, 效果如图
画图的逻辑结构为:
WorksheetPart<-DrawingsPart<-ChartPart<-ChartSpace<-Chart<-PlotArea<-BarChart<-BarChartSeries
Openxml 画excel 柱状图的数据存在在BarChartSeries, 一个BarChartSeries的实例代表一个颜色的柱子, 上图共有C1, C2两个BarChartSeries实例。
BarChartSeries 又包含三个部门:CategoryAxisData(x轴坐标), SeriesText(类型的名字, 这个也可以通过数据源取,sdk是传的固定值), Values(值, 柱状图的y轴值)。
Openxml的数据源对应的类型是DocumentFormat.OpenXml.Drawing.Charts.Formula, 如:new DocumentFormat.OpenXml.Drawing.Charts.Formula(”sheet1!$A$1:$C$4“), 这个是说取 sheet1的 A1 到C4的数据
这样我们改造sdk的代码就是 变BarChartSeries的值参, 为Openxml 的 Formula数据源
1. 生成x轴的数据源实例:
string formulaString = string.Format("{0}!${1}${2}:${3}${4}", sheetName, columnName, startx + 1, columnName, startx + rowCount -1);
CategoryAxisData cad = new CategoryAxisData();
cad.StringReference = new StringReference() { Formula = new DocumentFormat.OpenXml.Drawing.Charts.Formula(formulaString) };
2. 生成数据的数据源实例:
formulaString = string.Format("{0}!${1}${2}:${3}${4}", sheetName, columnName, startx +1, columnName, startx + rowCount-1);
DocumentFormat.OpenXml.Drawing.Charts.Values v = new DocumentFormat.OpenXml.Drawing.Charts.Values();
v.NumberReference = new NumberReference() { Formula = new DocumentFormat.OpenXml.Drawing.Charts.Formula(formulaString) };
这个数据源取得数据需要把保证cell的datatype 是"Number";因此在写数据时要用如下方法
Cell cell = InsertCellInWorksheet(name, Convert.ToUInt32(j + startx), worksheetPart);
cell.CellValue = new CellValue(index.ToString());
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
worksheetPart.Worksheet.Save();
3. 生成分类柱的名字:
formulaString = string.Format("{0}!${1}${2}", sheetName, columnName, startx);
SeriesText st = new SeriesText();
st.StringReference = new StringReference() { Formula = new DocumentFormat.OpenXml.Drawing.Charts.Formula(formulaString) };
4. 生成柱状图的一个分类的实例:
BarChartSeries barChartSeries = barChart.AppendChild<BarChartSeries>(new BarChartSeries(new Index() { Val = new UInt32Value(i) },
new Order() { Val = new UInt32Value(i) }, st, v));
if (sIndex == 1)
barChartSeries.AppendChild(cad);
这里startx表示excel行索引, starty表示excel的列索引
改造SDK how to 方法的完整代码:
1
/// <summary>2
/// draw the 2D bar chart3
/// index start from 14
/// </summary>5
/// <param name="startx">index start from 1 for row</param>6
/// <param name="starty">index start from 1 for column</param>7
/// <param name="columnCount"></param>8
/// <param name="rowCount"></param>9
public void InsertChartInSpreadsheet(int startx, int starty, int columnCount, int rowCount)10
{11
WorksheetPart worksheetPart = CurrentWorksheetPart;12

13
SDK How to example code32

33
string sheetName = GetCurrentSheetName();34
string columnName = GetColumnName(starty - 1);35
string formulaString = string.Format("{0}!${1}${2}:${3}${4}", sheetName, columnName, startx + 1, columnName, startx + rowCount - 1);36
CategoryAxisData cad = new CategoryAxisData();37
cad.StringReference = new StringReference() { Formula = new DocumentFormat.OpenXml.Drawing.Charts.Formula(formulaString) };38

39
uint i = 0;40
for (int sIndex = 1; sIndex < columnCount; sIndex++)41
{42
columnName = GetColumnName(starty + sIndex - 1);43
formulaString = string.Format("{0}!${1}${2}", sheetName, columnName, startx);44
SeriesText st = new SeriesText();45
st.StringReference = new StringReference() { Formula = new DocumentFormat.OpenXml.Drawing.Charts.Formula(formulaString) };46

47
formulaString = string.Format("{0}!${1}${2}:${3}${4}", sheetName, columnName, startx + 1, columnName, startx + rowCount - 1);48
DocumentFormat.OpenXml.Drawing.Charts.Values v = new DocumentFormat.OpenXml.Drawing.Charts.Values();49
v.NumberReference = new NumberReference() { Formula = new DocumentFormat.OpenXml.Drawing.Charts.Formula(formulaString) };50

51
BarChartSeries barChartSeries = barChart.AppendChild<BarChartSeries>(new BarChartSeries(new Index() { Val = new UInt32Value(i) },52
new Order() { Val = new UInt32Value(i) }, st, v));53
if (sIndex == 1)54
barChartSeries.AppendChild(cad);55
i++;56
}57
SDK how to example Code134
}
获取当前sheet name的方法:
private string GetCurrentSheetName()
{
string name = "";
WorkbookPart workbookPart = spreadSheet.WorkbookPart;
string relationshipId = workbookPart.GetIdOfPart(CurrentWorksheetPart);
Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
foreach (Sheet item in sheets)
{
if (item.Id == relationshipId)
{
name = item.Name;
break;
}
}
return name;
}
怎样生成excel 并写数据请参看 http://www.cnblogs.com/skyfei/archive/2009/06/12/Openxml.html


浙公网安备 33010602011771号