Files
lserp_cs_6.0/插件库/Lskj.Control/ChartControlEx.cs
T
2026-07-02 10:11:39 +00:00

646 lines
27 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************
* 说明:图表控件
* 创建人:龚宇超
* 创建日期: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
{
/// <summary>
/// 图表控件
/// </summary>
public partial class ChartControlEx : UserControl
{
private List<ChartModel> _models;
/// <summary>
/// 图表控件
/// </summary>
/// <value>The chart control object.</value>
public ChartControl ChartControlObj { get { return this.cmMain; } }
/// <summary>
/// 图表控件
/// </summary>
/// <value>The chart control object.</value>
public GridControlEx GridControlObj { get { return this.gridControlEx1; } }
/// <summary>
/// 图表控件
/// </summary>
/// <value>The chart control object.</value>
public DevExpress.XtraEditors.PanelControl PanelControlObj { get { return this.pl_buttom; } }
/// <summary>
/// 选中位置
/// </summary>
public SeriesPoint SeriesPoint;
/// <summary>
/// 是否为横向展示
/// </summary>
public bool transverseHistogram;
/// <summary>
/// 分割条
/// </summary>
/// <value>The chart control object.</value>
public DevExpress.XtraEditors.SplitContainerControl SplitMain { get { return this.splitMain; } }
public ChartControlEx()
{
InitializeComponent();
this.splitMain.PanelVisibility = SplitPanelVisibility.Panel1;//初始化时默认隐藏下方
}
/// <summary>
/// <para>说明:</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="chart">The chart.</param>
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<GridColumn> 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;
}
}
}
/// <summary>
/// <para>说明:根据数据创建一个图形展现</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="colName">Name of the col.</param>
/// <param name="colValue">The col value.</param>
/// <param name="series">The series.</param>
/// <returns>Series.</returns>
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;
}
/// <summary>
/// <para>说明:根据数据创建一个柱状图3D展现</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="colName">Name of the col.</param>
/// <param name="colValue">The col value.</param>
/// <param name="series">The series.</param>
/// <returns>Series.</returns>
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;
}
/// <summary>
/// <para>说明:根据数据创建一个饼图3D展现</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="colName">Name of the col.</param>
/// <param name="colValue">The col value.</param>
/// <param name="series">The series.</param>
/// <returns>Series.</returns>
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;
}
/// <summary>
/// <para>说明:根据数据创建一个饼图展现</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="colName">Name of the col.</param>
/// <param name="colValue">The col value.</param>
/// <param name="series">The series.</param>
/// <returns>Series.</returns>
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;
}
/// <summary>
/// <para>说明:创建图表的第二坐标系</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="series">The series.</param>
/// <param name="chartType">Type of the chart.</param>
/// <param name="chart3D">The chart3 d.</param>
/// <returns>SecondaryAxisY.</returns>
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;
}
/// <summary>
/// <para>说明:设置图表配置数据</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="table">The table.</param>
public void SetCharts(DataTable table)
{
this._models = new List<ChartModel>();
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;
chart.ChartColor= item.Table.Columns.Contains("ChartColor") ? item["ChartColor"] + "" : "";
chart.ValueVisible = item.Table.Columns.Contains("valueVisible") ? "1".Equals(item["valueVisible"] + "") : false;
chart.ChartTitle = item.Table.Columns.Contains("ChartTitle") ? item["ChartTitle"] + "" : "";
this._models.Add(chart);
}
}
/// <summary>
/// <para>说明:创建图表</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="models">The models.</param>
/// <param name="fields">The fields.</param>
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;
string Title = !string.IsNullOrWhiteSpace(chart.ChartTitle) ? chart.ChartTitle : chart.YAxisTitle;
switch (chart.ChartType)
{
case ChartType.LineChart:
default:
series = new Series(Title, chart.Chart3D == 1 ? ViewType.Line3D : ViewType.Line);
break;
case ChartType.BarChart:
series = new Series(Title, 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(Title, 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(Title, 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);
if(chart.ValueVisible) series.LabelsVisibility = DevExpress.Utils.DefaultBoolean.False;
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;
this.cmMain.CrosshairOptions.ShowOnlyInFocusedPane = false;
}
/// <summary>
/// <para>说明:双击图表</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
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);
}
}
/// <summary>
/// <para>说明:鼠标移动</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-01-29 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
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);
}
}
/// <summary>
/// 自定义悬浮框信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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);
}
}
}
}
}
/// <summary>
/// 自定义点样式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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]}";
}
}
/// <summary>
/// 设置图标标题
/// </summary>
/// <param name="text"></param>
/// <param name="color"></param>
public void SetTitle(string text,string color)
{
// 清空标题
cmMain.Titles.Clear();
// 创建标题
ChartTitle chartTitle = new ChartTitle();
chartTitle.Text = text; // 替换为你的实际标题内容
chartTitle.Font = new Font("微软雅黑", 12, FontStyle.Bold); // 字体样式
if(!string.IsNullOrWhiteSpace(color))chartTitle.TextColor = System.Drawing.ColorTranslator.FromHtml(color);
chartTitle.Dock = ChartTitleDockStyle.Bottom; // 固定在顶部
// 添加到图表
cmMain.Titles.Add(chartTitle);
}
}
/// <summary>
/// 图表类型
/// </summary>
public enum ChartType
{
/// <summary>
/// 线型图表
/// </summary>
LineChart = 1,
/// <summary>
/// 柱状图表
/// </summary>
BarChart = 2,
/// <summary>
/// 圆饼图表
/// </summary>
PieChart = 3
}
/// <summary>
/// 图表对象
/// </summary>
public class ChartModel
{
/// <summary>
/// The chart3 d
/// </summary>
public int Chart3D;
/// <summary>
/// The y axis shared
/// </summary>
public int YAxisShared;
/// <summary>
/// The y axis title
/// </summary>
public string YAxisTitle;
/// <summary>
/// The x label field
/// </summary>
public string XLabelField;
/// <summary>
/// The y value field
/// </summary>
public string YValueField;
/// <summary>
/// The chart color
/// </summary>
public string ChartColor;
/// <summary>
/// The chart type
/// </summary>
public ChartType ChartType;
/// <summary>
/// 是否为百分比
/// </summary>
public string IsAbsolutely;
/// <summary>
/// Y轴最大刻度
/// </summary>
public double YScale;
/// <summary>
/// 禁显数字
/// </summary>
public bool ValueVisible;
/// <summary>
/// 图表标题
/// </summary>
public string ChartTitle;
}
}