/// <summary> /// 输出图表 /// </summary> /// <param name="p_ws"></param> /// <param name="p_row"></param> /// <param name="p_col"></param> public void Render(Worksheet p_ws, int p_row, int p_col) { if (!ValidFilds()) { return; } Rect rc = p_ws.GetRangeLocation(new CellRange(p_row, p_col, RowSpan, ColSpan)); var chartType = GetChartType(); SpreadChart c = p_ws.AddChart("chart" + p_ws.Charts.Count.ToString(), chartType, rc.Left, rc.Top, rc.Width, rc.Height); // 锁定图表,禁止拖动缩放 c.Locked = true; string title = _data.Str("title"); if (!string.IsNullOrEmpty(title)) { c.ChartTitle = new ChartTitle { Text = title } } ; title = _data.Str("titlex"); if (!string.IsNullOrEmpty(title)) { c.AxisX.Title = new ChartTitle { Text = title } } ; title = _data.Str("titley"); if (!string.IsNullOrEmpty(title)) { c.AxisY.Title = new ChartTitle { Text = title } } ; if (ShowLegend) { c.Legend.Text = _data.Str("legtitle"); if (Enum.TryParse <Dt.Charts.LegendPosition>(_data.Str("legpos"), out var pos)) { c.Legend.Alignment = GetLegendAlignment(pos); } if (Enum.TryParse <Orientation>(_data.Str("legorientation"), out var ori)) { c.Legend.Orientation = ori; } } else { c.Legend = null; } if (string.IsNullOrEmpty(FieldSeries)) { LoadTable(c); } else { LoadMatrix(c); } } void LoadMatrix(SpreadChart p_chart) { // Build()中已判断空的情况 RptData data = _part.Inst.Info.GetData(Tbl).Result; var tbl = data.Data.CreateMatrix(FieldX, FieldSeries, FieldY); for (int i = 0; i < tbl.Columns.Count; i++) { string colName = tbl.Columns[i].ID; if (colName == FieldX) { continue; } SpreadDataSeries ser = new SpreadDataSeries(); ser.Name = colName; DoubleSeriesCollection vals = new DoubleSeriesCollection(); foreach (var row in tbl) { try { double val = row.Double(i); vals.Add(val); } catch { vals.Add(0); } } ser.Values = vals; p_chart.DataSeries.Add(ser); } // 添加系列数据时已创建x轴Items,只能重新设置x轴 p_chart.AxisX.Items.Clear(); for (int i = 0; i < tbl.Count; i++) { p_chart.AxisX.Items.Add(tbl[i].Str(FieldX)); } } void LoadTable(SpreadChart p_chart) { RptData data = _part.Inst.Info.GetData(Tbl).Result; SpreadDataSeries ser = new SpreadDataSeries(); DoubleSeriesCollection vals = new DoubleSeriesCollection(); foreach (var row in data.Data) { try { double val = row.Double(FieldY); vals.Add(val); } catch { vals.Add(0); } } ser.Values = vals; p_chart.DataSeries.Add(ser); p_chart.AxisX.Items.Clear(); foreach (var row in data.Data) { p_chart.AxisX.Items.Add(row.Str(FieldX)); } } /// <summary> /// 判断数据表字段是否完整 /// </summary> /// <returns></returns> bool ValidFilds() { if (string.IsNullOrEmpty(Tbl)) { Kit.Msg("数据源不可为空。"); return(false); } string type = _data.Str("type"); if (type == "Gantt") { if (string.IsNullOrEmpty(FieldZ) || string.IsNullOrEmpty(FieldX) || string.IsNullOrEmpty(FieldY)) { Kit.Msg("任务字段、起始时间字段及终止时间字段均不可为空,图表生成失败。"); return(false); } } else { if (string.IsNullOrEmpty(FieldX) || string.IsNullOrEmpty(FieldY)) { Kit.Msg("分类字段和值字段不可为空,图表生成失败。"); return(false); } } return(true); } SpreadChartType GetChartType() { if (Enum.TryParse <ChartType>(_data.Str("type"), out var tp)) { switch (tp) { case ChartType.Bar: return(SpreadChartType.BarClustered); case ChartType.BarStacked: return(SpreadChartType.BarStacked); case ChartType.Column: return(SpreadChartType.ColumnClustered); case ChartType.ColumnStacked: return(SpreadChartType.ColumnStacked); case ChartType.Line: return(SpreadChartType.Line); case ChartType.LineSmoothed: return(SpreadChartType.LineSmoothed); case ChartType.LineStacked: return(SpreadChartType.LineStacked); case ChartType.LineSymbols: return(SpreadChartType.LineWithMarkers); case ChartType.LineSymbolsSmoothed: return(SpreadChartType.LineWithMarkersSmoothed); case ChartType.LineSymbolsStacked: return(SpreadChartType.LineStackedWithMarkers); case ChartType.Pie: return(SpreadChartType.Pie); case ChartType.PieExploded: return(SpreadChartType.PieExploded); case ChartType.PieDoughnut: return(SpreadChartType.PieDoughnut); case ChartType.PieExplodedDoughnut: return(SpreadChartType.PieExplodedDoughnut); case ChartType.Area: return(SpreadChartType.Area); case ChartType.AreaStacked: return(SpreadChartType.AreaStacked); case ChartType.AreaStacked100pc: return(SpreadChartType.AreaStacked); case ChartType.Radar: return(SpreadChartType.Radar); case ChartType.RadarSymbols: return(SpreadChartType.RadarWithMarkers); case ChartType.RadarFilled: return(SpreadChartType.RadarFilled); case ChartType.XYPlot: return(SpreadChartType.Scatter); case ChartType.Bubble: return(SpreadChartType.Bubble); case ChartType.Candle: return(SpreadChartType.StockHighLowOpenClose); } } return(SpreadChartType.ColumnClustered); } LegendAlignment GetLegendAlignment(Charts.LegendPosition pos) { switch (pos) { case Charts.LegendPosition.TopLeft: return(LegendAlignment.TopLeft); case Charts.LegendPosition.TopRight: return(LegendAlignment.TopRight); case Charts.LegendPosition.TopCenter: return(LegendAlignment.TopCenter); case Charts.LegendPosition.Left: return(LegendAlignment.MiddleLeft); case Charts.LegendPosition.Right: return(LegendAlignment.MiddleRight); case Charts.LegendPosition.BottomLeft: return(LegendAlignment.BottomLeft); case Charts.LegendPosition.BottomCenter: return(LegendAlignment.BottomCenter); case Charts.LegendPosition.BottomRight: return(LegendAlignment.BottomRight); } return(LegendAlignment.BottomCenter); }
/// <summary> /// 创建小计 /// </summary> /// <param name="totals"></param> /// <param name="p_header"></param> /// <param name="p_matInst"></param> /// <param name="p_curRow"></param> /// <param name="p_data"></param> /// <param name="p_loc"></param> void CreateTotalInst(List <RptMtxSubtotal> totals, RptMtxHeader p_header, RptMatrixInst p_matInst, Row p_curRow, RptData p_data, TotalLocation p_loc) { foreach (RptMtxSubtotal total in totals) { if (total.TotalLoc == p_loc) { if (total.SubTotals.Count > 0) { CreateTotalInst(total.SubTotals, p_header, p_matInst, p_curRow, p_data, p_loc); } else { RptMtxHeaderInst totalInst = new RptMtxHeaderInst(p_header); for (int j = 0; j < p_header.Levels.IndexOf(total.Level); j++) { RptMtxLevel nLevel = p_header.Levels[j]; nLevel.Item.ColSpan = 1; nLevel.Item.RowSpan = 1; RptTextInst txtlevel = new RptTextInst(nLevel.Item); totalInst.TxtInsts.Add(txtlevel); totalInst.Filter.Add(nLevel.Field, p_curRow.Str(nLevel.Field)); } RptItemBase parent = total.Parent; while (parent is RptMtxSubtotal) { RptTextInst parTotal = new RptTextInst((parent as RptMtxSubtotal).Item); totalInst.TxtInsts.Add(parTotal); parent = parent.Parent; } RptTextInst txtTotal = new RptTextInst(total.Item); totalInst.TxtInsts.Add(txtTotal); totalInst.RptData = p_data; totalInst.RptData.Current = p_curRow.Index; totalInst.Index = p_curRow.Index; if (p_header is RptMtxColHeader) { totalInst.MtxRowsCol = total.Col; p_matInst.AddColHeader(totalInst); } else { totalInst.MtxRowsRow = total.Row; p_matInst.AddRowHeader(totalInst); } } } } }
/// <summary> /// 创建标题 /// </summary> /// <param name="p_titles"></param> /// <param name="p_header"></param> /// <param name="p_matInst"></param> /// <param name="p_curRow"></param> /// <param name="p_data"></param> void CreateSubTiltelInst(List <RptMtxSubtitle> p_titles, RptMtxHeader p_header, RptMatrixInst p_matInst, Row p_curRow, RptData p_data) { foreach (RptMtxSubtitle title in p_titles) { if (title.SubTitles.Count > 0) { CreateSubTiltelInst(title.SubTitles, p_header, p_matInst, p_curRow, p_data); } else { RptMtxHeaderInst titleInst = new RptMtxHeaderInst(p_header); for (int j = 0; j <= p_header.Levels.IndexOf(title.Level); j++) { RptMtxLevel nLevel = p_header.Levels[j]; nLevel.Item.ColSpan = 1; nLevel.Item.RowSpan = 1; RptTextInst txtlevel = new RptTextInst(nLevel.Item); titleInst.TxtInsts.Add(txtlevel); titleInst.Filter.Add(nLevel.Field, p_curRow.Str(nLevel.Field)); } RptItemBase parent = title.Parent; while (parent is RptMtxSubtotal) { RptTextInst parTotal = new RptTextInst((parent as RptMtxSubtotal).Item); titleInst.TxtInsts.Add(parTotal); parent = parent.Parent; } RptTextInst txtTotal = new RptTextInst(title.Item); titleInst.TxtInsts.Add(txtTotal); titleInst.RptData = p_data; titleInst.RptData.Current = p_curRow.Index; titleInst.Index = p_curRow.Index; if (p_header is RptMtxColHeader) { titleInst.MtxRowsCol = title.Col; p_matInst.AddColHeader(titleInst); } else { titleInst.MtxRowsRow = title.Row; p_matInst.AddRowHeader(titleInst); } } } }
/// <summary> /// 构造行头或列头 /// </summary> /// <param name="p_rptData"></param> /// <param name="p_header"></param> /// <param name="p_matInst"></param> void BuildHeader(RptData p_rptData, RptMtxHeader p_header, RptMatrixInst p_matInst) { List <string> colNames = p_header.GetFieldNames(); List <Row> allHeaderData = SelectDistinctDataRows(p_rptData.Data, colNames); Row preRow = null; for (int i = 0; i < allHeaderData.Count; i++) { Row curRow = allHeaderData[i]; if (preRow == null || !string.IsNullOrEmpty(CompareTwoRows(preRow, curRow, colNames))) { //前面小计 foreach (RptMtxLevel level in p_header.Levels) { if (level.SubTotals.Count <= 0) { continue; } RptMtxLevel beforLevel = null; if (p_header.Levels.IndexOf(level) - 1 >= 0) { beforLevel = p_header.Levels[p_header.Levels.IndexOf(level) - 1]; } //第一行(列) 或者 前一行(列)层值与当前行层值不同 创建小计 if (preRow == null || (beforLevel != null && preRow.Str(beforLevel.Field) != curRow.Str(beforLevel.Field))) { CreateTotalInst(level.SubTotals, p_header, p_matInst, curRow, p_rptData, TotalLocation.Before); } } //数据 RptMtxHeaderInst headerInst = new RptMtxHeaderInst(p_header); foreach (RptMtxLevel level in p_header.Levels) { if (level.SubTitles.Count > 0) { CreateSubTiltelInst(level.SubTitles, p_header, p_matInst, curRow, p_rptData); } else { //手动置1,因为输出头的时候按一行或一列输出,不需要控件合并 level.Item.ColSpan = 1; level.Item.RowSpan = 1; RptTextInst txtlevel = new RptTextInst(level.Item); headerInst.TxtInsts.Add(txtlevel); } } if (headerInst.TxtInsts.Count > 0) { headerInst.RptData = p_rptData; headerInst.Index = curRow.Index; if (p_header is RptMtxColHeader) { headerInst.MtxRowsCol = p_header.Levels[p_header.Levels.Count - 1].Col; p_matInst.AddColHeader(headerInst); } else { headerInst.MtxRowsRow = p_header.Levels[p_header.Levels.Count - 1].Row; p_matInst.AddRowHeader(headerInst); } //生成条件 foreach (string name in colNames) { headerInst.Filter.Add(name, curRow.Str(name)); } } //后面小计 for (int k = p_header.Levels.Count - 1; k >= 0; k--) { RptMtxLevel level = p_header.Levels[k]; if (level.SubTotals.Count <= 0) { continue; } RptMtxLevel beforLevel = null; if (p_header.Levels.IndexOf(level) - 1 >= 0) { beforLevel = p_header.Levels[p_header.Levels.IndexOf(level) - 1]; } Row nextRow = null; if (i < allHeaderData.Count - 1) { nextRow = allHeaderData[i + 1]; } //最后一行(列) 或者 下一行(列)层值与当前行层值不同 创建小计 if (nextRow == null || (beforLevel != null && curRow.Str(beforLevel.Field) != nextRow.Str(beforLevel.Field))) { foreach (RptMtxSubtotal total in level.SubTotals) { CreateTotalInst(level.SubTotals, p_header, p_matInst, curRow, p_rptData, TotalLocation.After); } } } } preRow = curRow; } }