OpenXML: excel 插入BarChart图表

it2022-05-09  17

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轴的数据源实例:        

Code   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. 生成数据的数据源实例:

 

Code  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. 生成分类柱的名字:

Code 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. 生成柱状图的一个分类的实例:

Code     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 方法的完整代码:

Code   1 /**//// <summary>  2    /// draw the 2D bar chart  3    /// index start from 1  4    /// </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 code#region SDK How to example code 14        // Add a new drawing to the worksheet. 15        DrawingsPart drawingsPart = worksheetPart.AddNewPart<DrawingsPart>(); 16        worksheetPart.Worksheet.Append(new DocumentFormat.OpenXml.Spreadsheet.Drawing() { Id = worksheetPart.GetIdOfPart(drawingsPart) }); 17        worksheetPart.Worksheet.Save(); 18 19        // Add a new chart and set the chart language to English-US. 20        ChartPart chartPart = drawingsPart.AddNewPart<ChartPart>(); 21        chartPart.ChartSpace = new ChartSpace(); 22        chartPart.ChartSpace.Append(new EditingLanguage() { Val = new StringValue("en-US") }); 23        DocumentFormat.OpenXml.Drawing.Charts.Chart chart = chartPart.ChartSpace.AppendChild<DocumentFormat.OpenXml.Drawing.Charts.Chart>( 24            new DocumentFormat.OpenXml.Drawing.Charts.Chart()); 25 26        // Create a new clustered column chart. 27        PlotArea plotArea = chart.AppendChild<PlotArea>(new PlotArea()); 28        Layout layout = plotArea.AppendChild<Layout>(new Layout()); 29        BarChart barChart = plotArea.AppendChild<BarChart>(new BarChart(new BarDirection() { Val = new EnumValue<BarDirectionValues>(BarDirectionValues.Column) }, 30            new BarGrouping() { Val = new EnumValue<BarGroupingValues>(BarGroupingValues.Clustered) }));  31        #endregion 32 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 Code#region SDK how to  example Code 58 59        barChart.Append(new AxisId() { Val = new UInt32Value(48650112u) }); 60        barChart.Append(new AxisId() { Val = new UInt32Value(48672768u) }); 61 62        // Add the Category Axis. 63        CategoryAxis catAx = plotArea.AppendChild<CategoryAxis>(new CategoryAxis(new AxisId() { Val = new UInt32Value(48650112u) }, 64            new Scaling(new Orientation() 65            { 66                Val = new EnumValue<DocumentFormat.OpenXml.Drawing.Charts.OrientationValues>( 67                    DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax) 68            }), 69            new AxisPosition() { Val = new EnumValue<AxisPositionValues>(AxisPositionValues.Bottom) }, 70            new TickLabelPosition() { Val = new EnumValue<TickLabelPositionValues>(TickLabelPositionValues.NextTo) }, 71            new CrossingAxis() { Val = new UInt32Value(48672768U) }, 72            new Crosses() { Val = new EnumValue<CrossesValues>(CrossesValues.AutoZero) }, 73            new AutoLabeled() { Val = new BooleanValue(true) }, 74            new LabelAlignment() { Val = new EnumValue<LabelAlignmentValues>(LabelAlignmentValues.Center) }, 75            new LabelOffset() { Val = new UInt16Value((ushort)100) })); 76 77        // Add the Value Axis. 78        ValueAxis valAx = plotArea.AppendChild<ValueAxis>(new ValueAxis(new AxisId() { Val = new UInt32Value(48672768u) }, 79            new Scaling(new Orientation() 80            { 81                Val = new EnumValue<DocumentFormat.OpenXml.Drawing.Charts.OrientationValues>( 82                    DocumentFormat.OpenXml.Drawing.Charts.OrientationValues.MinMax) 83            }), 84            new AxisPosition() { Val = new EnumValue<AxisPositionValues>(AxisPositionValues.Left) }, 85            new MajorGridlines(), 86            new DocumentFormat.OpenXml.Drawing.Charts.NumberFormat() { FormatCode = new StringValue("General"), SourceLinked = new BooleanValue(true) }, 87            new TickLabelPosition() { Val = new EnumValue<TickLabelPositionValues>(TickLabelPositionValues.NextTo) }, 88            new CrossingAxis() { Val = new UInt32Value(48650112U) }, 89            new Crosses() { Val = new EnumValue<CrossesValues>(CrossesValues.AutoZero) }, 90            new CrossBetween() { Val = new EnumValue<CrossBetweenValues>(CrossBetweenValues.Between) })); 91 92        // Add the chart Legend. 93        Legend legend = chart.AppendChild<Legend>(new Legend(new LegendPosition() { Val = new EnumValue<LegendPositionValues>(LegendPositionValues.Right) }, 94            new Layout())); 95 96        chart.Append(new PlotVisibleOnly() { Val = new BooleanValue(true) }); 97 98        // Save the chart part. 99        chartPart.ChartSpace.Save();100101        // Position the chart on the worksheet using a TwoCellAnchor object.102        drawingsPart.WorksheetDrawing = new WorksheetDrawing();103        TwoCellAnchor twoCellAnchor = drawingsPart.WorksheetDrawing.AppendChild<TwoCellAnchor>(new TwoCellAnchor());104        twoCellAnchor.Append(new FromMarker(new ColumnId("9"),105            new ColumnOffset("581025"),106            new RowId("17"),107            new RowOffset("114300")));108        twoCellAnchor.Append(new ToMarker(new ColumnId("17"),109            new ColumnOffset("276225"),110            new RowId("32"),111            new RowOffset("0")));112113        // Append a GraphicFrame to the TwoCellAnchor object.114        DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame graphicFrame =115            twoCellAnchor.AppendChild<DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame>(116            new DocumentFormat.OpenXml.Drawing.Spreadsheet.GraphicFrame());117        graphicFrame.Macro = "";118119        graphicFrame.Append(new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameProperties(120            new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties() { Id = new UInt32Value(2u), Name = "Chart 1" },121            new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualGraphicFrameDrawingProperties()));122123        graphicFrame.Append(new Transform(new Offset() { X = 0L, Y = 0L },124                                                                new Extents() { Cx = 0L, Cy = 0L }));125126        graphicFrame.Append(new Graphic(new GraphicData(new ChartReference() { Id = drawingsPart.GetIdOfPart(chartPart) }{ Uri = "http://schemas.openxmlformats.org/drawingml/2006/chart" }));127128        twoCellAnchor.Append(new ClientData());129130        // Save the WorksheetDrawing object.131        drawingsPart.WorksheetDrawing.Save();132133        #endregion134    }

 

获取当前sheet name的方法:

Code   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 

转载于:https://www.cnblogs.com/skyfei/archive/2009/06/17/1505187.html

相关资源:数据结构—成绩单生成器

最新回复(0)