using DevExpress.Utils; using DevExpress.XtraCharts; using Yw.Geometry; namespace Yw.WinFrmUI.Phart { /// /// 通用图表 /// public partial class UniversalViewChart : DevExpress.XtraEditors.XtraUserControl { public UniversalViewChart() { InitializeComponent(); InitialChart(); } #region Private Variable private XYDiagram _diagram; private XYDiagramDefaultPane _default_pane; private AxisX _axis_x; private AxisY _axis_y; private ConstantLine _const_line_x; private ConstantLine _const_line_y; private List _fit_pt_list = null; private UniversalCoordinate _coordinate = null; private bool _line_visible = false; private bool _initial_data = false; #endregion #region Public Variable /// /// X轴标题 /// public string AxisXTitle { get { return _axis_x.Title.Text; } set { _axis_x.Title.Text = value; } } /// /// Y轴标题 /// public string AxisYTitle { get { return _axis_y.Title.Text; } set { _axis_y.Title.Text = value; } } public bool LineVisible { get { return _line_visible; } set { _line_visible = value; _const_line_x.Visible = value; _const_line_y.Visible = value; SetAxisXValue(); } } #endregion #region Private Initial /// /// 初始化图表 /// private void InitialChart() { this.chartControl1.SetChartDisplay(); this.chartControl1.RuntimeHitTesting = true; this.chartControl1.AnimationStartMode = ChartAnimationMode.OnLoad; this.chartControl1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chartControl1_MouseMove); this.chartControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.chartControl1_MouseUp); this.chartControl1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chartControl1_MouseDown); _diagram = (XYDiagram)this.chartControl1.Diagram; _default_pane = _diagram.DefaultPane; _axis_x = _diagram.AxisX; _axis_x.SetAxisXQDisplay(); _axis_y = _diagram.AxisY; _axis_y.SetAxisYQHDisplay(); _axis_x.Visibility = DefaultBoolean.False; _axis_x.GridLines.Visible = false; _axis_y.Visibility = DefaultBoolean.False; _axis_y.GridLines.Visible = false; _const_line_x = (ConstantLine)_diagram.AxisX.ConstantLines.GetElementByName("ConstantLineX"); _const_line_x.SetWorkPointLineDisplay(); _const_line_y = (ConstantLine)_diagram.AxisY.ConstantLines.GetElementByName("ConstantLineY"); _const_line_y.SetWorkPointLineDisplay(); _const_line_x.Visible = false; _const_line_y.Visible = false; } /// /// 初始化坐标轴 /// private void InitialCoordinate() { //设置成白板坐标 _coordinate = new UniversalCoordinate(); _coordinate.GridNumberX = 30; _coordinate.GridNumberY = 16; _coordinate.StartLineNoY = 10; _coordinate.EndLineNoY = 15; _coordinate.CoordMinX = 0; _coordinate.CoordSpaceX = 1000; _coordinate.CoordMinY = 10; _coordinate.CoordSpaceY = 100; } #endregion #region Private Chart Event private bool _on_move_x_line = false; private bool _on_move_y_line = false; private void chartControl1_MouseDown(object sender, MouseEventArgs e) { if (!_initial_data) return; var hitInfo = chartControl1.CalcHitInfo(e.Location); if (e.Button == MouseButtons.Left) { if (hitInfo.InConstantLine) { if (hitInfo.ConstantLine == _const_line_x) { _on_move_x_line = true; } else if (hitInfo.ConstantLine == _const_line_y) { _on_move_y_line = true; } } } } private void chartControl1_MouseMove(object sender, MouseEventArgs e) { if (!_initial_data) return; if (_on_move_x_line) { var diagram_coordinates = _diagram.PointToDiagram(e.Location); var axis_value = diagram_coordinates.GetAxisValue(_axis_x); if (axis_value == null) return; double x = axis_value.NumericalValue; SetAxisXValue(x); } else if (_on_move_y_line) { var diagram_coordinates = _diagram.PointToDiagram(e.Location); var axis_value = diagram_coordinates.GetAxisValue(_axis_y); if (axis_value == null) return; double y = axis_value.NumericalValue; SetAxisYValue(y); } else { var hitInfo = chartControl1.CalcHitInfo(e.Location); if (hitInfo.InConstantLine) { this.chartControl1.Cursor = Cursors.Hand; } else if (hitInfo.InAnnotation) { this.chartControl1.Cursor = Cursors.SizeAll; } else { this.chartControl1.Cursor = Cursors.Default; } } } private void chartControl1_MouseUp(object sender, MouseEventArgs e) { if (!_initial_data) return; _on_move_x_line = false; _on_move_y_line = false; } #endregion #region Set /// /// 清空 /// public void Clear() { _initial_data = false; _fit_pt_list = null; _coordinate = null; this.chartControl1.BeginInit(); this.chartControl1.Series.Clear(); this.chartControl1.AnnotationRepository.Clear(); this.chartControl1.Legend.CustomItems.Clear(); this.chartControl1.EndInit(); } /// /// 绑定数据 /// public void SetBindingData(List fit_pt_list, List def_pt_list = null, string caption = "", string coordinate = null, Color? color = null) { _fit_pt_list = fit_pt_list?.Select(t => { var x = Math.Round(t.X, 2); var y = Math.Round(t.Y, 2); return new Point2d(x, y); }).ToList(); _coordinate = UniversalCoordinate.ToModel(coordinate); this.chartControl1.BeginInit(); this.chartControl1.Series.Clear(); this.chartControl1.AnnotationRepository.Clear(); this.chartControl1.Legend.CustomItems.Clear(); if (fit_pt_list == null || !fit_pt_list.Any()) { _initial_data = false; this.chartControl1.EndInit(); return; } if (color == null) color = PumpChartDisplay.CurveColorQH; AddLineSeries(color.Value, _axis_x, _axis_y, _default_pane, fit_pt_list); if (!string.IsNullOrEmpty(caption)) { AddAnnotation(caption, color.Value, _axis_y, _default_pane, fit_pt_list.Last()); } if (def_pt_list != null && def_pt_list.Any()) { AddPointSeries(color.Value, _axis_x, _axis_y, _default_pane, def_pt_list); } if (_coordinate == null) SetCoordinate(); SetChartAxis(); this.chartControl1.EndInit(); _initial_data = true; } //是否是无效数据 private bool IsInvalidData() { if (_fit_pt_list == null || !_fit_pt_list.Any()) { return true; } return false; } #region Add Chart Data private void AddPointSeries(Color color, AxisXBase axis_x, AxisYBase axis_y, XYDiagramPaneBase pane, List pt_list) { if (pt_list == null || !pt_list.Any()) return; var view = new DevExpress.XtraCharts.PointSeriesView(); view.PointMarkerOptions.Size = 8; view.PointMarkerOptions.Kind = MarkerKind.Circle; view.PointMarkerOptions.BorderColor = color; view.Color = color; view.AxisX = axis_x; view.AxisY = axis_y; view.EmptyPointOptions.Color = Color.Transparent; view.Pane = pane; var series_pt_list = pt_list.Select(x => x.ToSeriesPoint()).ToArray(); var series = new DevExpress.XtraCharts.Series(); series.ShowInLegend = false; series.ArgumentScaleType = DevExpress.XtraCharts.ScaleType.Numerical; series.LabelsVisibility = DevExpress.Utils.DefaultBoolean.False; series.CrosshairEnabled = DefaultBoolean.False; series.CrosshairLabelVisibility = DefaultBoolean.False; series.ToolTipEnabled = DefaultBoolean.False; series.SeriesPointsSorting = SortingMode.None; series.Visible = true; series.View = view; series.CrosshairLabelPattern = "{A}"; series.Points.AddRange(series_pt_list); this.chartControl1.Series.Add(series); } private void AddLineSeries(Color color, AxisXBase axis_x, AxisYBase axis_y, XYDiagramPaneBase pane, List pt_list, DashStyle dash = DashStyle.Solid) { if (pt_list == null || !pt_list.Any()) return; var view = new DevExpress.XtraCharts.LineSeriesView(); view.LineStyle.DashStyle = dash; view.LineStyle.LineJoin = System.Drawing.Drawing2D.LineJoin.Round; view.LineStyle.Thickness = 2; view.Color = color; view.EnableAntialiasing = DefaultBoolean.True; view.MarkerVisibility = DefaultBoolean.False; view.AxisX = axis_x; view.AxisY = axis_y; view.EmptyPointOptions.Color = Color.Transparent; view.Pane = pane; var series_pt_list = pt_list.Select(x => x.ToSeriesPoint()).ToArray(); var series = new DevExpress.XtraCharts.Series(); series.ShowInLegend = false; series.ArgumentScaleType = DevExpress.XtraCharts.ScaleType.Numerical; series.LabelsVisibility = DevExpress.Utils.DefaultBoolean.False; series.CrosshairEnabled = DefaultBoolean.False; series.ToolTipEnabled = DefaultBoolean.False; series.SeriesPointsSorting = SortingMode.None; series.Visible = true; series.View = view; series.Points.AddRange(series_pt_list); this.chartControl1.Series.Add(series); } private void AddAnnotation(string caption, Color color, AxisYBase axis_y, XYDiagramPaneBase pane, Yw.Geometry.Point2d pt, double angle = -10) { if (pt == null) return; var anchor_pt = pt; var pane_anchor_pt = new DevExpress.XtraCharts.PaneAnchorPoint(); pane_anchor_pt.Pane = pane; pane_anchor_pt.AxisYCoordinate.Axis = axis_y; pane_anchor_pt.AxisXCoordinate.AxisValue = anchor_pt.X; pane_anchor_pt.AxisYCoordinate.AxisValue = anchor_pt.Y; var relative_position = new DevExpress.XtraCharts.RelativePosition(); relative_position.Angle = angle; relative_position.ConnectorLength = 20; var text_annotation = new TextAnnotation(); text_annotation.Border.Visibility = DefaultBoolean.False; text_annotation.AnchorPoint = pane_anchor_pt; text_annotation.AutoHeight = true; text_annotation.AutoWidth = true; text_annotation.BackColor = System.Drawing.Color.Transparent; text_annotation.Border.Color = color; text_annotation.ConnectorStyle = DevExpress.XtraCharts.AnnotationConnectorStyle.Line; text_annotation.Padding.Bottom = 1; text_annotation.Padding.Left = 1; text_annotation.Padding.Right = 1; text_annotation.Padding.Top = 1; text_annotation.RuntimeMoving = true; text_annotation.RuntimeAnchoring = false; text_annotation.RuntimeResizing = false; text_annotation.RuntimeRotation = false; text_annotation.Text = caption; text_annotation.TextColor = color; text_annotation.ShapePosition = relative_position; text_annotation.Visible = true; text_annotation.DXFont = new DevExpress.Drawing.DXFont(this.Font.Name, 11F); this.chartControl1.AnnotationRepository.Add(text_annotation); } #endregion #endregion #region Set Axis private double _minX, _maxX; private double _maxY = 0, _minY = 10000; /// /// 设置坐标 /// private void SetCoordinate() { if (IsInvalidData()) { InitialCoordinate(); return; } _minX = _fit_pt_list.Min(x => x.X); _maxX = _fit_pt_list.Max(x => x.X); _minY = _fit_pt_list.Min(x => x.Y); _maxY = _fit_pt_list.Max(x => x.Y); _coordinate = UniversalCoordinate.CalcCoordinate(_minX, _maxX, _minY, _maxY); if (_coordinate == null) return; if (_coordinate.CoordMinX + _coordinate.CoordSpaceX * this._coordinate.GridNumberX < _maxX * 1.05) { _coordinate.GridNumberX++; } } /// /// 设置图表轴 /// private void SetChartAxis() { if (_coordinate == null || IsInvalidData()) { _axis_x.Visibility = DefaultBoolean.False; _axis_x.GridLines.Visible = false; _axis_y.Visibility = DefaultBoolean.False; _axis_y.GridLines.Visible = false; _const_line_x.Visible = false; _const_line_y.Visible = false; return; } //计算刻度 X var axis_x_labels = new List(); var display_x = _coordinate.CoordMinX; for (int i = 0; i < _coordinate.GridNumberX + 1; i++) { axis_x_labels.Add(new CustomAxisLabel(display_x.ToString("N0"), display_x)); display_x = display_x + _coordinate.CoordSpaceX; } _axis_x.CustomLabels.Clear(); _axis_x.CustomLabels.AddRange(axis_x_labels.ToArray()); _axis_x.Visibility = DefaultBoolean.True; _axis_x.GridLines.Visible = true; //计算刻度 Y var axis_y_labels = new List(); var display_y = _coordinate.CoordMinY + _coordinate.CoordSpaceY * _coordinate.StartLineNoY; for (int i = _coordinate.StartLineNoY; i < _coordinate.EndLineNoY + 1; i++) { axis_y_labels.Add(new CustomAxisLabel(display_y.ToString(), display_y)); display_y = display_y + _coordinate.CoordSpaceY; } _axis_y.CustomLabels.Clear(); _axis_y.CustomLabels.AddRange(axis_y_labels.ToArray()); _axis_y.Visibility = DefaultBoolean.True; _axis_y.GridLines.Visible = true; _axis_x.SetAxisRange(_coordinate.CoordMinX, _coordinate.DispMaxX()); _axis_y.SetAxisRange(_coordinate.DispMinY(), _coordinate.DispMaxY()); } #endregion #region Set Axis Value /// /// 设置X轴值 /// public void SetAxisXValue(double? x = null) { if (!_line_visible) { _const_line_x.Visible = false; _const_line_x.Title.Visible = false; _const_line_y.Visible = false; _const_line_y.Title.Visible = false; return; } else { _const_line_x.Visible = true; _const_line_x.Title.Visible = true; _const_line_y.Visible = true; _const_line_y.Title.Visible = true; } if (this.IsInvalidData()) return; var min_x = _fit_pt_list.Min(x => x.X); var max_x = _fit_pt_list.Max(x => x.X); if (x == null) { x = (min_x + max_x) / 2; } else { if (x < min_x || x > max_x) return; } var x_value = x.Value; var y_value = _fit_pt_list.GetInterPointsY(x_value)?.FirstOrDefault(); _const_line_x.AxisValue = x_value; _const_line_x.Title.Text = $"{x_value:N1}"; _const_line_y.AxisValue = y_value; _const_line_y.Title.Text = $"{y_value:N1}"; } /// /// 设置Y轴值 /// public void SetAxisYValue(double y) { if (!_line_visible) return; if (IsInvalidData()) return; var min_y = _fit_pt_list.Min(x => x.Y); var max_y = _fit_pt_list.Max(x => x.Y); if (y < min_y || y > max_y) return; var x_value = _fit_pt_list.GetInterPointsX(y)?.LastOrDefault(); SetAxisXValue(x_value); } #endregion } }