/****************************** * 说明:图表控件 * 创建人:龚宇超 * 创建日期:2018-01-29 * 修改人: * 修改日期: * 修改备注: * 版本:1.0.0.0 ******************************/ using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using Lskj.Model; using DevExpress.XtraCharts; using DevExpress.Utils; using Lskj.Control.Model; using DevExpress.XtraEditors; using Lskj.Business.Impl; using DevExpress.XtraGrid.Columns; using System.Collections; using Lskj.Util; namespace Lskj.Control { /// /// 图表控件 /// public partial class ChartControlEx : UserControl { private List _models; /// /// 图表控件 /// /// The chart control object. public ChartControl ChartControlObj { get { return this.cmMain; } } /// /// 图表控件 /// /// The chart control object. public GridControlEx GridControlObj { get { return this.gridControlEx1; } } /// /// 图表控件 /// /// The chart control object. public DevExpress.XtraEditors.PanelControl PanelControlObj { get { return this.pl_buttom; } } /// /// 选中位置 /// public SeriesPoint SeriesPoint; /// /// 是否为横向展示 /// public bool transverseHistogram; public ChartControlEx() { InitializeComponent(); } /// /// 说明: /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The chart. private void CreateSeriesChart(ChartModel chart, Series series, DataTable chartData, DevExpress.XtraGrid.Views.Grid.GridView view = null) { foreach (DataRow item in chartData.Rows) { //string formatStr = string.Empty; //if (view != null) //{ // IEnumerable columns = view.Columns.Where(n => n.FieldName.Equals(chart.YValueField)); // GridColumn column = columns.Count() > 0 ? columns.First() : null; // if (view != null && column != null) formatStr = (column.Tag is GridColumnModel) ? (column.Tag as GridColumnModel).DataFormat : string.Empty; //} string xValue = item[chart.XLabelField] + ""; string yValue = item[chart.YValueField] + ""; //if (formatStr == "0%") series.Label.TextPattern = "{V:0%}"; if (chart.IsAbsolutely != null && chart.IsAbsolutely.Equals("1")) { series.Label.TextPattern = "{V:0.00%}"; } switch (chart.ChartType) { default: case ChartType.LineChart: CreateSeries(xValue, yValue, item, series); break; case ChartType.BarChart: if (chart.Chart3D == 1) CreateSeriesBar3D(xValue, yValue, item, series); else CreateSeries(xValue, yValue, item, series); break; case ChartType.PieChart: if (chart.Chart3D == 1) CreateSeriesPie3D(xValue, yValue, item, series); else CreateSeriesPie(xValue, yValue, item, series); break; } } } /// /// 说明:根据数据创建一个图形展现 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// Name of the col. /// The col value. /// The series. /// Series. private Series CreateSeries(string colName, string colValue, DataRow dataRow, Series series) { SeriesPoint seriesPoint = new SeriesPoint(colName + "" == "" ? "*指标为空*" : colName, colValue + "" == "" ? "0" : colValue); seriesPoint.Tag = dataRow;//缓存数据源 series.Points.Add(seriesPoint); series.ArgumentScaleType = ScaleType.Qualitative; series.LabelsVisibility = DevExpress.Utils.DefaultBoolean.True;//显示标注标签 return series; } /// /// 说明:根据数据创建一个柱状图3D展现 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// Name of the col. /// The col value. /// The series. /// Series. private Series CreateSeriesBar3D(string colName, string colValue, DataRow dataRow, Series series) { SeriesPoint seriesPoint = new SeriesPoint(colName + "" == "" ? "*指标为空*" : colName, new double[] { Convert.ToDouble(colValue + "" == "" ? "0" : colValue) }); seriesPoint.Tag = dataRow; series.Points.Add(seriesPoint); return series; } /// /// 说明:根据数据创建一个饼图3D展现 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// Name of the col. /// The col value. /// The series. /// Series. private Series CreateSeriesPie3D(string colName, string colValue, DataRow dataRow, Series series) { if (!string.IsNullOrWhiteSpace(colValue) && double.Parse(colValue) < 0) return series; SeriesPoint seriesPoint = new SeriesPoint(colName + "" == "" ? "*指标为空*" : colName, new double[] { Convert.ToDouble(colValue + "" == "" ? "0" : colValue) }); seriesPoint.Tag = dataRow; series.Points.Add(seriesPoint); return series; } /// /// 说明:根据数据创建一个饼图展现 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// Name of the col. /// The col value. /// The series. /// Series. private Series CreateSeriesPie(string colName, string colValue, DataRow dataRow, Series series) { if (!string.IsNullOrWhiteSpace(colValue) && double.Parse(colValue) < 0) return series; SeriesPoint seriesPoint = new SeriesPoint(colName + "" == "" ? "*指标为空*" : colName, new double[] { Convert.ToDouble(colValue + "" == "" ? "0" : colValue) }); seriesPoint.Tag = dataRow; series.Points.Add(seriesPoint); return series; } /// /// 说明:创建图表的第二坐标系 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The series. /// Type of the chart. /// The chart3 d. /// SecondaryAxisY. private SecondaryAxisY CreateAxisY(Series series, ChartType chartType, int chart3D) { SecondaryAxisY myAxis = new SecondaryAxisY(series.Name); try { ((XYDiagram)((Diagram)cmMain.Diagram)).SecondaryAxesY.Add(myAxis); } catch (Exception) { } if (chartType == ChartType.LineChart) ((LineSeriesView)series.View).AxisY = myAxis; if (chartType == ChartType.BarChart) ((BarSeriesView)series.View).AxisY = myAxis; myAxis.Title.Text = series.Name; myAxis.Title.Alignment = StringAlignment.Far; //顶部对齐 myAxis.Title.Visibility = DefaultBoolean.True; //显示标题 myAxis.Title.Font = new Font("宋体", 9.0f); Color color = series.View.Color;//设置坐标的颜色和图表线条颜色一致 myAxis.Title.TextColor = color; myAxis.Label.TextColor = color; myAxis.Color = color; return myAxis; } /// /// 说明:设置图表配置数据 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The table. public void SetCharts(DataTable table) { this._models = new List(); DataRow[] drs = table.Select("", "orderId"); foreach (DataRow item in drs) { ChartModel chart = new ChartModel(); chart.Chart3D = Convert.ToInt32(item["chart3D"]); chart.ChartType = (ChartType)Convert.ToInt32(item["chartType"]); chart.YAxisShared = Convert.ToInt32(item["YAxisShared"]); chart.YAxisTitle = item["YAxisTitle"] + ""; chart.XLabelField = item["XLabelField"] + ""; chart.YValueField = item["YValueField"] + ""; chart.IsAbsolutely = item.Table.Columns.Contains("IsAbsolutely") ? item["IsAbsolutely"] + "" : null; chart.YScale = item.Table.Columns.Contains("YScale") && !string.IsNullOrWhiteSpace(item["YScale"].ToString()) ? double.Parse(item["YScale"].ToString()) : 0; this._models.Add(chart); } } /// /// 说明:创建图表 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The models. /// The fields. public void CreateChart(DataTable chartData, DevExpress.XtraGrid.Views.Grid.GridView gridView = null) { if (cmMain.Diagram is XYDiagram) (cmMain.Diagram as XYDiagram).SecondaryAxesY.Clear(); cmMain.Series.Clear(); foreach (ChartModel chart in this._models) { Series series = null; switch (chart.ChartType) { case ChartType.LineChart: default: series = new Series(chart.YAxisTitle, chart.Chart3D == 1 ? ViewType.Line3D : ViewType.Line); break; case ChartType.BarChart: series = new Series(chart.YAxisTitle, chart.Chart3D == 1 ? ViewType.Bar3D : ViewType.Bar); //柱状图显示值出现在顶端 BarSeriesLabel label = (BarSeriesLabel)series.Label; label.Position = BarSeriesLabelPosition.Top; break; case ChartType.PieChart: { if (chart.Chart3D == 1) { series = new Series(chart.YAxisTitle, ViewType.Doughnut3D); PiePointOptions options = series.Label.PointOptions as PiePointOptions; ((PiePointOptions)series.LegendPointOptions).PointView = PointView.ArgumentAndValues; Doughnut3DSeriesView view = series.View as Doughnut3DSeriesView; view.ExplodeMode = PieExplodeMode.All; series.LegendPointOptions.ValueNumericOptions.Format = NumericFormat.Percent; series.LabelsVisibility = DefaultBoolean.True; if (options != null) { options.PercentOptions.ValueAsPercent = true; options.PointView = PointView.ArgumentAndValues; } } else { series = new Series(chart.YAxisTitle, ViewType.Pie); PiePointOptions options = series.Label.PointOptions as PiePointOptions; series.LegendPointOptions.ValueNumericOptions.Format = NumericFormat.Percent; ((PiePointOptions)series.LegendPointOptions).PointView = PointView.ArgumentAndValues; PieSeriesView view = series.View as PieSeriesView; view.ExplodeMode = PieExplodeMode.All; view.Rotation = 50; view.RuntimeExploding = true; series.LabelsVisibility = DefaultBoolean.True; if (options != null) { options.PercentOptions.ValueAsPercent = true; options.PointView = PointView.ArgumentAndValues; } } series.LegendTextPattern = "{A}: {VP:P2},{V} "; break; } } if (series != null) { this.CreateSeriesChart(chart, series, chartData, gridView); series.View.Color = System.Drawing.ColorTranslator.FromHtml(chart.ChartColor); this.cmMain.Series.Add(series); //if (chart.ChartType == ChartType.LineChart) //{ // if (series.Points.Count > 0) // { // // 创建文本注解 // TextAnnotation textAnnotation = new TextAnnotation // { // Text = chart.YAxisTitle // }; // SeriesPoint seriesPoint = series.Points[0]; // textAnnotation.AnchorPoint = new SeriesPointAnchorPoint(seriesPoint); // RelativePosition relativePosition = new RelativePosition(); // relativePosition.Angle = 135; // relativePosition.ConnectorLength = 100; // textAnnotation.ShapePosition = relativePosition; // cmMain.AnnotationRepository.Add(textAnnotation); // } //} if (chart.YScale > 0) { (cmMain.Diagram as XYDiagram).AxisY.WholeRange.SetMinMaxValues(0, chart.YScale); } if (chart.YAxisShared == 0) CreateAxisY(series, chart.ChartType, chart.Chart3D); } } if (transverseHistogram && cmMain.Diagram != null) ((XYDiagram)cmMain.Diagram).Rotated = true; this.cmMain.Legend.Visibility = DefaultBoolean.True; this.cmMain.SeriesTemplate.LabelsVisibility = DefaultBoolean.True; this.cmMain.CrosshairEnabled = DefaultBoolean.True; this.cmMain.ToolTipEnabled = DefaultBoolean.True; this.cmMain.CustomDrawCrosshair += OnCmMainCustomDrawCrosshair; this.cmMain.CustomDrawSeriesPoint += OnCmMainCustomDrawSeriesPoint; // this.cmMain.Legend.AlignmentVertical = LegendAlignmentVertical.Top; } /// /// 说明:双击图表 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The source of the event. /// The instance containing the event data. private void cmMain_MouseDoubleClick(object sender, MouseEventArgs e) { try { ChartHitInfo hitInfo = this.cmMain.CalcHitInfo(e.Location); if (hitInfo.SeriesPoint != null) { if (this.cmMain.ContextMenuStrip != null) { foreach (ToolStripMenuItem item in this.cmMain.ContextMenuStrip.Items) { if (item.Tag == null && !(item.Tag is GridRightMenuModel)) continue; GridRightMenuModel model = item.Tag as GridRightMenuModel; if (model.DbClick) { item.PerformClick(); } } } } } catch (Exception ex) { string Message = ErrorMessage.PromptErrorMessage(ex); MessageUtil.Show(Message, ex.Message); } } /// /// 说明:鼠标移动 /// 创建人:龚宇超 /// 创建日期:2018-01-29 /// 修改人: /// 修改日期: /// 修改备注: /// 版本:1.0 /// /// The source of the event. /// The instance containing the event data. private void cmMain_MouseMove(object sender, MouseEventArgs e) { try { this.SeriesPoint = null; ChartHitInfo hitInfo = this.cmMain.CalcHitInfo(e.Location); StringBuilder builder = new StringBuilder(); if (hitInfo.InDiagram) builder.AppendLine("In Diagram"); if (hitInfo.InNonDefaultPane) builder.AppendLine("In non-default pane: " + hitInfo.NonDefaultPane.Name); if (hitInfo.InAxis) { builder.AppendLine("In axis: " + hitInfo.Axis.Name); if (hitInfo.AxisLabelItem != null) builder.AppendLine(" Label item: " + hitInfo.AxisLabelItem.Text); if (hitInfo.AxisTitle != null) builder.AppendLine(" Axis title: " + hitInfo.AxisTitle.Text); } if (hitInfo.InChartTitle) builder.AppendLine("In chart title: " + hitInfo.ChartTitle.Text); if (hitInfo.InLegend) builder.AppendLine("In legend"); if (hitInfo.InSeries) builder.AppendLine("In series: " + ((Series)hitInfo.Series).Name); if (hitInfo.InSeriesLabel) { builder.AppendLine("In series label"); builder.AppendLine(" Series: " + ((Series)hitInfo.Series).Name); } if (hitInfo.SeriesPoint != null) { SeriesPoint = hitInfo.SeriesPoint; builder.AppendLine(" Argument: " + hitInfo.SeriesPoint.Argument); if (!hitInfo.SeriesPoint.IsEmpty) builder.AppendLine(" Value: " + hitInfo.SeriesPoint.Values[0]); } } catch (Exception ex) { string Message = ErrorMessage.PromptErrorMessage(ex); MessageUtil.Show(Message, ex.Message); } } /// /// 自定义悬浮框信息 /// /// /// private void OnCmMainCustomDrawCrosshair(object sender, CustomDrawCrosshairEventArgs e) { foreach (CrosshairElementGroup group in e.CrosshairElementGroups) { CrosshairGroupHeaderElement groupHeaderElement = group.HeaderElement; SeriesPoint seriesPoint = groupHeaderElement.SeriesPoints.FirstOrDefault(); if (seriesPoint != null && seriesPoint.Tag != null && seriesPoint.Tag is DataRow dataRow) { if (dataRow.Table.Columns.Contains("customHeaderTips")) { string customHeaderTips = dataRow["customHeaderTips"] + ""; if (!string.IsNullOrEmpty(customHeaderTips)) { groupHeaderElement.Text = ReplaceHelper.ReplaceRowParam(dataRow, customHeaderTips); } } } } } /// /// 自定义点样式 /// /// /// private void OnCmMainCustomDrawSeriesPoint(object sender, CustomDrawSeriesPointEventArgs e) { int index = e.Series.Points.IndexOf(e.SeriesPoint); if (e.Series.View is LineSeriesView && index == 0 && e.SeriesPoint != null && e.SeriesPoint.Length > 0)//第一个点显示名称 { e.LabelText = $"{e.Series.Name}:{e.SeriesPoint[0]}"; } } } /// /// 图表类型 /// public enum ChartType { /// /// 线型图表 /// LineChart = 1, /// /// 柱状图表 /// BarChart = 2, /// /// 圆饼图表 /// PieChart = 3 } /// /// 图表对象 /// public class ChartMo