using DevExpress.Utils; using DevExpress.XtraCharts; namespace Yw.WinFrmUI.Phart { /// /// /// public partial class PumpEditChart : DevExpress.XtraEditors.XtraUserControl { public PumpEditChart() { InitializeComponent(); InitialChart(); } #region Private Variable private XYDiagram _diagram; private XYDiagramDefaultPane _default_pane; private AxisX _axis_x_flow; private AxisY _axis_y_head; private SecondaryAxisY _axis_y_eff, _axis_y_power; private Series _series_edit_pt; private Yw.Ahart.eCurveType _edit_curve_type; private List _def_qh_pt_list; private List _fit_qh_pt_list; private List _def_qe_pt_list; private List _fit_qe_pt_list; private List _def_qp_pt_list; private List _fit_qp_pt_list; private PumpCoordinate _coordinate; private bool _initial_data = false; private bool _mouse_mode = false;//鼠标模式 #endregion #region Public Evnet /// /// 坐标变更事件 /// public event Action CoordinateChangedEvent; /// /// 定义点变更事件 /// public event Action> DefinePointChangedEvent; /// /// 选中点索引变更事件 /// public event Action SelectedPointIndexChangedEvent; #endregion #region Public Variable /// /// 鼠标模式 /// public bool MouseModel { get { return _mouse_mode; } set { _mouse_mode = value; } } #endregion #region Initial /// /// 初始化图表 /// private void InitialChart() { this.chartControl1.SetChartDisplay(); this.chartControl1.Legend.Visibility = DevExpress.Utils.DefaultBoolean.False; this.chartControl1.SeriesSelectionMode = SeriesSelectionMode.Point; this.chartControl1.SelectionMode = ElementSelectionMode.Single; this.chartControl1.RuntimeHitTesting = true; 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); this.chartControl1.KeyUp += new System.Windows.Forms.KeyEventHandler(this.chartControl1_KeyUp); _diagram = (XYDiagram)chartControl1.Diagram; _default_pane=_diagram.DefaultPane; _axis_x_flow = _diagram.AxisX; _axis_x_flow.SetAxisXQDisplay(); _axis_y_head = _diagram.AxisY; _axis_y_head.SetAxisYQHDisplay(); _axis_y_eff = _diagram.SecondaryAxesY.GetAxisByName("AxisYQE"); _axis_y_eff.SetSecondaryAxisYQEDisplay(); _axis_y_power = _diagram.SecondaryAxesY.GetAxisByName("AxisYQP"); _axis_y_power.SetSecondaryAxisYQPDisplay(); _axis_x_flow.Visibility = DefaultBoolean.False; _axis_x_flow.GridLines.Visible = false; _axis_y_head.Visibility = DefaultBoolean.False; _axis_y_head.GridLines.Visible = false; _axis_y_eff.Visibility = DefaultBoolean.False; _axis_y_eff.GridLines.Visible = false; _axis_y_power.Visibility = DefaultBoolean.False; _axis_y_power.GridLines.Visible = false; this.chartControl1.SetChartMonoColorDisplay(); } /// /// 初始化坐标轴 /// private void InitialCoordinate() { //设置成白板坐标 _coordinate = new PumpCoordinate(); _coordinate.GridNumberX = 30; _coordinate.GridNumberY = 16; _coordinate.StartLineNoH = 10; _coordinate.EndLineNoH = 15; _coordinate.StartLineNoE = 0; _coordinate.EndLineNoE = 10; _coordinate.StartLineNoP = 2; _coordinate.EndLineNoP = 9; _coordinate.CoordMinQ = 0; _coordinate.CoordSpaceQ = 1000; _coordinate.CoordMinH = 10; _coordinate.CoordSpaceH = 100; _coordinate.CoordMinE = 0; _coordinate.CoordSpaceE = 100; _coordinate.CoordMinP = 10; _coordinate.CoordSpaceP = 100; } #endregion #region Set /// /// 初始化图表数据 /// public void Clear() { _initial_data = false; _fit_qh_pt_list = null; _fit_qe_pt_list = null; _fit_qp_pt_list = null; _def_qh_pt_list = null; _def_qe_pt_list = null; _def_qp_pt_list = null; _coordinate = null; _series_edit_pt = null; this.chartControl1.BeginInit(); this.chartControl1.Series.Clear(); this.chartControl1.AnnotationRepository.Clear(); this.chartControl1.Legend.CustomItems.Clear(); this.chartControl1.EndInit(); } /// /// 绑定数据 /// public void SetBindingData( List def_qh_pt_list, List fit_qh_pt_list, List def_qe_pt_list, List fit_qe_pt_list, List def_qp_pt_list, List fit_qp_pt_list, Yw.Ahart.eCurveType curve_type = Ahart.eCurveType.QH, string coordinate = null) { _initial_data = false; _def_qh_pt_list = def_qh_pt_list?.Select(x => new Geometry.Point2d(x.X, x.Y)).ToList(); _fit_qh_pt_list = fit_qh_pt_list?.Select(x => new Geometry.Point2d(x.X, x.Y)).ToList(); _def_qe_pt_list = def_qe_pt_list?.Select(x => new Geometry.Point2d(x.X, x.Y)).ToList(); _fit_qe_pt_list = fit_qe_pt_list?.Select(x => new Geometry.Point2d(x.X, x.Y)).ToList(); _def_qp_pt_list = def_qp_pt_list?.Select(x => new Geometry.Point2d(x.X, x.Y)).ToList(); _fit_qp_pt_list = fit_qp_pt_list?.Select(x => new Geometry.Point2d(x.X, x.Y)).ToList(); _edit_curve_type = curve_type; _coordinate = PumpCoordinate.ToModel(coordinate); this.chartControl1.BeginInit(); this.chartControl1.Series.Clear(); this.chartControl1.AnnotationRepository.Clear(); this.chartControl1.Legend.CustomItems.Clear(); if (IsInvalidData()) { _initial_data = false; this.chartControl1.EndInit(); return; } var color_qh = curve_type == Ahart.eCurveType.QH ? PumpChartDisplay.CurveColorQH : Color.Black; var color_qe = curve_type == Ahart.eCurveType.QE ? PumpChartDisplay.CurveColorQE : Color.Black; var color_qp = curve_type == Ahart.eCurveType.QP ? PumpChartDisplay.CurveColorQP : Color.Black; if (curve_type == Ahart.eCurveType.QH) { var series_qh = AddPointSeries(color_qh, _axis_x_flow, _axis_y_head, _default_pane, _def_qh_pt_list); _series_edit_pt = series_qh; } AddLineSeries(color_qh, _axis_x_flow, _axis_y_head, _default_pane, _fit_qh_pt_list); if (_def_qe_pt_list != null && _def_qe_pt_list.Any()) { AddLineSeries(color_qe, _axis_x_flow, _axis_y_eff, _default_pane, _fit_qe_pt_list); if (curve_type == Ahart.eCurveType.QE) { var series_qe = AddPointSeries(color_qe, _axis_x_flow, _axis_y_eff, _default_pane, _def_qe_pt_list); _series_edit_pt = series_qe; } } if (_def_qp_pt_list != null && _def_qp_pt_list.Any()) { AddLineSeries(color_qp, _axis_x_flow, _axis_y_power, _default_pane, _fit_qp_pt_list); if (curve_type == Ahart.eCurveType.QP) { var series_qp = AddPointSeries(color_qp, _axis_x_flow, _axis_y_power, _default_pane, _def_qp_pt_list); _series_edit_pt = series_qp; } } if (_coordinate == null) SetCoordinate(); SetChartAxis(); this.chartControl1.EndInit(); _initial_data = true; } //是否是无效数据 private bool IsInvalidData() { if (_def_qh_pt_list == null || !_def_qh_pt_list.Any()) { return true; } if (_fit_qh_pt_list == null || !_fit_qh_pt_list.Any()) { return true; } return false; } #region Add Chart Data private Series AddPointSeries(Color color, AxisXBase axis_x, AxisYBase axis_y, XYDiagramPaneBase pane, List pt_list) { if (pt_list == null || !pt_list.Any()) return null; 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 = new List(); for (int i = 0; i < pt_list.Count; i++) { var pt = pt_list[i]; var series_pt = new DevExpress.XtraCharts.SeriesPoint(pt.X, new double[] { pt.Y }); series_pt.Tag = i; series_pt_list.Add(series_pt); } 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.ToArray()); this.chartControl1.Series.Add(series); return series; } private Series 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 default; 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); return series; } #endregion #endregion #region Set Axis private double _minQ, _maxQ; private double _maxH = 0, _minH = 10000; private double _maxE = 0, _minE = 0; private double _maxP = 0, _minP = 1000; /// /// 计算坐标 /// public void SetCoordinate() { if (IsInvalidData()) { InitialCoordinate(); return; } _maxQ = 0; _minQ = 10000; _maxH = 0; _minH = 10000; _maxE = 0; _minE = 0; _maxP = 0; _minP = 1000; var q_list_list = new List>(); var h_list_list = new List>(); var e_list_list = new List>(); var p_list_list = new List>(); q_list_list.Add(_def_qh_pt_list.Select(x => x.X).ToList()); h_list_list.Add(_def_qh_pt_list.Select(x => x.Y).ToList()); q_list_list.Add(_fit_qh_pt_list.Select(x => x.X).ToList()); h_list_list.Add(_fit_qh_pt_list.Select(x => x.Y).ToList()); if (_def_qe_pt_list != null && _def_qe_pt_list.Any()) { e_list_list.Add(_def_qe_pt_list.Select(x => x.Y).ToList()); } if (_fit_qe_pt_list != null && _fit_qe_pt_list.Any()) { e_list_list.Add(_fit_qe_pt_list.Select(x => x.Y).ToList()); } if (_def_qp_pt_list != null && _def_qp_pt_list.Any()) { p_list_list.Add(_def_qp_pt_list.Select(x => x.Y).ToList()); } if (_fit_qp_pt_list != null && _fit_qp_pt_list.Any()) { p_list_list.Add(_fit_qp_pt_list.Select(x => x.Y).ToList()); } foreach (var list in q_list_list) { _minQ = Math.Min(_minQ, list.Min()); _maxQ = Math.Max(_maxQ, list.Max()); } foreach (var list in h_list_list) { _minH = Math.Min(_minH, list.Min()); _maxH = Math.Max(_maxH, list.Max()); } foreach (var list in e_list_list) { _minE = Math.Max(_minE, list.Min()); _maxE = Math.Max(_maxE, list.Max()); } foreach (var list in p_list_list) { _minP = Math.Min(_minP, list.Min()); _maxP = Math.Max(_maxP, list.Max()); } _coordinate = PumpCoordinate.CalcCoordinate(_minQ, _maxQ, _minH, _maxH, _minE, _maxE, _minP, _maxP); if (_coordinate == null) return; if (_coordinate.CoordMinQ + _coordinate.CoordSpaceQ * this._coordinate.GridNumberX < _maxQ * 1.05) { _coordinate.GridNumberX++; } } /// /// 计算图表轴 /// public void SetChartAxis() { if (_coordinate == null) { _axis_x_flow.Visibility = DefaultBoolean.False; _axis_x_flow.GridLines.Visible = false; _axis_y_head.Visibility = DefaultBoolean.False; _axis_y_head.GridLines.Visible = false; _axis_y_eff.Visibility = DefaultBoolean.False; _axis_y_eff.GridLines.Visible = false; _axis_y_power.Visibility = DefaultBoolean.False; _axis_y_power.GridLines.Visible = false; return; } var default_visible = _def_qh_pt_list != null && _def_qh_pt_list.Any(); var eff_visible = _def_qe_pt_list != null && _def_qe_pt_list.Any(); var power_visible = _def_qp_pt_list != null && _def_qp_pt_list.Any(); //流量 if (default_visible) { //计算刻度 var labels = new List(); var disQ = _coordinate.CoordMinQ; for (int i = 0; i < _coordinate.GridNumberX + 1; i++) { labels.Add(new CustomAxisLabel(disQ.ToString("N0"), disQ)); disQ = disQ + _coordinate.CoordSpaceQ; } //坐标刻度 _axis_x_flow.CustomLabels.Clear(); _axis_x_flow.CustomLabels.AddRange(labels.ToArray()); _axis_x_flow.Visibility = DefaultBoolean.True; _axis_x_flow.GridLines.Visible = true; _axis_x_flow.SetAxisRange(_coordinate.CoordMinQ, _coordinate.CoordMinQ + _coordinate.GridNumberX * _coordinate.CoordSpaceQ); //计算刻度 labels = new List(); var display_head = _coordinate.CoordMinH + _coordinate.CoordSpaceH * _coordinate.StartLineNoH; for (int i = _coordinate.StartLineNoH; i < _coordinate.EndLineNoH + 1; i++) { labels.Add(new CustomAxisLabel(display_head.ToString(), display_head)); display_head = display_head + _coordinate.CoordSpaceH; } _axis_y_head.CustomLabels.Clear(); _axis_y_head.CustomLabels.AddRange(labels.ToArray()); _axis_y_head.Visibility = DefaultBoolean.True; _axis_y_head.GridLines.Visible = true; } //效率 if (eff_visible) { //计算刻度 var labels = new List(); var display_eff = _coordinate.CoordMinE + _coordinate.CoordSpaceE * _coordinate.StartLineNoE; for (int i = _coordinate.StartLineNoE; i < _coordinate.EndLineNoE + 1; i++) { labels.Add(new CustomAxisLabel(display_eff.ToString(), display_eff)); display_eff = display_eff + _coordinate.CoordSpaceE; } _axis_y_eff.CustomLabels.Clear(); _axis_y_eff.CustomLabels.AddRange(labels.ToArray()); _axis_y_eff.Visibility = DefaultBoolean.True; _axis_y_eff.GridLines.Visible = true; } //功率 if (power_visible) { //计算刻度 var labels = new List(); double display_power = _coordinate.CoordMinP + _coordinate.CoordSpaceP * _coordinate.StartLineNoP; for (int i = _coordinate.StartLineNoP; i < _coordinate.EndLineNoP + 1; i++) { labels.Add(new CustomAxisLabel(display_power.ToString(), display_power)); display_power = display_power + _coordinate.CoordSpaceP; } _axis_y_power.CustomLabels.Clear(); _axis_y_power.CustomLabels.AddRange(labels.ToArray()); _axis_y_power.Visibility = DefaultBoolean.True; _axis_y_power.GridLines.Visible = true; } if ((!eff_visible) && (!power_visible)) { _axis_y_head.SetAxisRange(_coordinate.DispMinH(), _coordinate.DispMaxH()); } else if ((!eff_visible) && power_visible) { var grid_count_eff = _coordinate.EndLineNoE - _coordinate.StartLineNoE; var grid_delete_head = grid_count_eff * _coordinate.CoordSpaceH; grid_delete_head = _coordinate.CoordMinH < 0 ? -grid_delete_head : grid_delete_head; var grid_delete_power = grid_count_eff * _coordinate.CoordSpaceP; _axis_y_head.SetAxisRange(_coordinate.CoordMinH - grid_delete_head, _coordinate.CoordMinH + _coordinate.GridNumberY * _coordinate.CoordSpaceH); _axis_y_power.SetAxisRange(_coordinate.CoordMinP, _coordinate.CoordMinP + _coordinate.GridNumberY * _coordinate.CoordSpaceP - grid_delete_power); } else if (eff_visible && (!power_visible)) { var grid_count_power = _coordinate.EndLineNoP - _coordinate.StartLineNoP; var grid_delete_head = grid_count_power * _coordinate.CoordSpaceH; grid_delete_head = _coordinate.CoordMinH < 0 ? -grid_delete_head : grid_delete_head; var grid_delete_eff = (grid_count_power) * _coordinate.CoordSpaceE; grid_delete_eff = _coordinate.CoordMinE < 0 ? -grid_delete_eff : grid_delete_eff; _axis_y_head.SetAxisRange(_coordinate.CoordMinH - grid_delete_head, _coordinate.CoordMinH + _coordinate.GridNumberY * _coordinate.CoordSpaceH); _axis_y_eff.SetAxisRange(_coordinate.CoordMinE - grid_delete_eff, _coordinate.CoordMinE + _coordinate.GridNumberY * _coordinate.CoordSpaceE); } else { _axis_y_head.SetAxisRange(_coordinate.CoordMinH, _coordinate.CoordMinH + _coordinate.GridNumberY * _coordinate.CoordSpaceH); _axis_y_eff.SetAxisRange(_coordinate.CoordMinE, _coordinate.CoordMinE + _coordinate.GridNumberY * _coordinate.CoordSpaceE); _axis_y_power.SetAxisRange(_coordinate.CoordMinP, _coordinate.CoordMinP + _coordinate.GridNumberY * _coordinate.CoordSpaceP); } } #endregion #region Chart Event private int _pick_point_index = -1; private void chartControl1_MouseDown(object sender, MouseEventArgs e) { if (!_initial_data) return; var hitInfo = chartControl1.CalcHitInfo(e.Location); _pick_point_index = -1; if (e.Button == MouseButtons.Left) { if (hitInfo.InSeriesPoint && hitInfo.SeriesPoint.Tag is int index) { _pick_point_index = index; this.SelectedPointIndexChangedEvent?.Invoke(_pick_point_index); } } } private void chartControl1_MouseMove(object sender, MouseEventArgs e) { if (!_mouse_mode) return; if (_pick_point_index < 0) return; if (IsInvalidData()) return; AxisYBase axis_y = null; if (_edit_curve_type == Yw.Ahart.eCurveType.QH) axis_y = _axis_y_head; else if (_edit_curve_type == Yw.Ahart.eCurveType.QE) axis_y = _axis_y_eff; else if (_edit_curve_type == Yw.Ahart.eCurveType.QP) axis_y = _axis_y_power; var diagram_coordinates = _diagram.PointToDiagram(e.Location); var axis_value = diagram_coordinates.GetAxisValue(axis_y); if (axis_value == null) return; _series_edit_pt.Points[_pick_point_index].Values[0] = axis_value.NumericalValue; _series_edit_pt.Points[_pick_point_index].NumericalArgument = diagram_coordinates.NumericalArgument; } private void chartControl1_MouseUp(object sender, MouseEventArgs e) { if (!_mouse_mode) return; if (_pick_point_index < 0) return; if (IsInvalidData()) return; var x = _series_edit_pt.Points[_pick_point_index].NumericalArgument; var y = _series_edit_pt.Points[_pick_point_index].Values[0]; x = Math.Round(x, 2); y = Math.Round(y, 2); SetPointValue(_pick_point_index, x, y); _pick_point_index = -1; } private void chartControl1_KeyUp(object sender, KeyEventArgs e) { if (!_initial_data) return; if (_mouse_mode) return; if (_pick_point_index < 0) return; if (IsInvalidData()) return; double space_x = _coordinate.CoordSpaceQ / 50; double space_y = 0; if (_edit_curve_type == Yw.Ahart.eCurveType.QH) space_y = _coordinate.CoordSpaceH / 50; else if (_edit_curve_type == Yw.Ahart.eCurveType.QE) space_y = _coordinate.CoordSpaceE / 50; else if (_edit_curve_type == Yw.Ahart.eCurveType.QP) space_y = _coordinate.CoordSpaceP / 50; double x = _series_edit_pt.Points[_pick_point_index].NumericalArgument; double y = _series_edit_pt.Points[_pick_point_index].Values[0]; if (e.KeyCode == Keys.Up) { y += space_y; } else if (e.KeyCode == Keys.Down) { y -= space_y; } else if (e.KeyCode == Keys.Left) { x -= space_x; } else if (e.KeyCode == Keys.Right) { x += space_x; } x = Math.Round(x, 2); y = Math.Round(y, 2); _series_edit_pt.Points[_pick_point_index].NumericalArgument = x; _series_edit_pt.Points[_pick_point_index].Values[0] = y; SetPointValue(_pick_point_index, x, y); } /// /// 更新数据 /// private void SetPointValue(int index, double x, double y) { if (IsInvalidData()) return; List def_pt_list = null; if (_edit_curve_type == Yw.Ahart.eCurveType.QH) def_pt_list = _def_qh_pt_list; else if (_edit_curve_type == Yw.Ahart.eCurveType.QE) def_pt_list = _def_qe_pt_list; else if (_edit_curve_type == Yw.Ahart.eCurveType.QP) def_pt_list = _def_qp_pt_list; def_pt_list[index].X = x; def_pt_list[index].Y = y; this.DefinePointChangedEvent?.Invoke(_edit_curve_type, def_pt_list); } #endregion } }