using DevExpress.Utils;
using DevExpress.XtraCharts;
using NPOI.SS.Formula.Functions;
namespace Yw.WinFrmUI.Phart
{
///
///
///
public partial class ValveEditChart : DevExpress.XtraEditors.XtraUserControl
{
public ValveEditChart()
{
InitializeComponent();
InitialChart();
}
#region Private Variable
private XYDiagram _diagram;
private XYDiagramDefaultPane _default_pane;
private XYDiagramPane _bottom_pane;
private AxisX _axis_x_flow;
private AxisY _axis_y_head_loss;
private SecondaryAxisX _axis_x_opening;
private SecondaryAxisY _axis_y_k_loss;
private Series _series_edit_pt;
private Yw.Ahart.eCurveType _edit_curve_type = Ahart.eCurveType.QL;
private ValveCoordinate _coordinate;
private bool _initial_data = false;
private bool _mouse_mode = false;//鼠标模式
private bool _exist_ql = false;
private bool _exist_ol = false;
private List _vm_list = null;
#endregion
#region Public Variable
///
/// 鼠标模式
///
public bool MouseModel
{
get
{
return _mouse_mode;
}
set
{
_mouse_mode = value;
}
}
#endregion
#region Public Evnet
///
/// 坐标变更事件
///
public event Action CoordinateChangedEvent;
///
/// 定义点变更事件
///
public event Action> DefinePointChangedEvent;
///
/// 选中点
///
public event Action SelectedPointIndexChangedEvent;
#endregion
#region Private 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)this.chartControl1.Diagram;
_default_pane = _diagram.DefaultPane;
_bottom_pane = _diagram.Panes[0];
_axis_x_flow = _diagram.AxisX;
_axis_x_flow.SetAxisXQDisplay();
_axis_y_head_loss = _diagram.AxisY;
_axis_y_head_loss.SetAxisYQHDisplay();
_axis_x_flow.Visibility = DefaultBoolean.False;
_axis_x_flow.GridLines.Visible = false;
_axis_y_head_loss.Visibility = DefaultBoolean.False;
_axis_y_head_loss.GridLines.Visible = false;
_axis_x_opening = _diagram.SecondaryAxesX[0];
_axis_x_opening.SetAxisXQDisplay();
_axis_y_k_loss = _diagram.SecondaryAxesY[0];
_axis_y_k_loss.SetSecondaryAxisYQPDisplay();
_axis_x_opening.Visibility = DefaultBoolean.False;
_axis_x_opening.GridLines.Visible = false;
_axis_y_k_loss.Visibility = DefaultBoolean.False;
_axis_y_k_loss.GridLines.Visible = false;
this.chartControl1.SetChartMonoColorDisplay();
}
///
/// 初始化坐标轴
///
private void InitialCoordinate()
{
//设置成白板坐标
_coordinate = new ValveCoordinate();
_coordinate.QL = new();
_coordinate.OL = new();
_coordinate.QL.GridNumberX = 30;
_coordinate.QL.GridNumberY = 16;
_coordinate.QL.StartLineNoY = 10;
_coordinate.QL.EndLineNoY = 15;
_coordinate.QL.CoordMinX = 0;
_coordinate.QL.CoordSpaceX = 1000;
_coordinate.QL.CoordMinY = 10;
_coordinate.QL.CoordSpaceY = 100;
_coordinate.OL.GridNumberX = 30;
_coordinate.OL.GridNumberY = 16;
_coordinate.OL.StartLineNoY = 10;
_coordinate.OL.EndLineNoY = 15;
_coordinate.OL.CoordMinX = 0;
_coordinate.OL.CoordSpaceX = 1000;
_coordinate.OL.CoordMinY = 10;
_coordinate.OL.CoordSpaceY = 100;
}
#endregion Initial
#region Private 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.InSeries && hitInfo.Series != _series_edit_pt)
{
return;
}
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;
var diagram_coordinates = _diagram.PointToDiagram(e.Location);
AxisYBase axis_y = null;
if (_edit_curve_type == Ahart.eCurveType.QL)
{
axis_y = _axis_y_head_loss;
}
else
{
axis_y = _axis_y_k_loss;
}
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 (_mouse_mode)
return;
if (_pick_point_index < 0)
return;
if (IsInvalidData())
return;
double coord_space_x, coord_space_y;
if (_edit_curve_type == Ahart.eCurveType.QL)
{
coord_space_x = _coordinate.QL.CoordSpaceX;
coord_space_y = _coordinate.QL.CoordSpaceY;
}
else
{
coord_space_x = _coordinate.OL.CoordSpaceX;
coord_space_y = _coordinate.OL.CoordSpaceY;
}
double space_x = coord_space_x / 50;
double space_y = coord_space_y / 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;
var vm = _vm_list.Find(x => x.IsUpdate);
if (vm == null)
return;
vm.DefPointList[index].X = x;
vm.DefPointList[index].Y = y;
this.DefinePointChangedEvent?.Invoke(vm.DefPointList);
}
#endregion
#region Set
///
/// 绑定数据
///
public void Clear()
{
_initial_data = false;
_coordinate = null;
_series_edit_pt = null;
_vm_list = null;
_exist_ql = false;
_exist_ol = false;
this.chartControl1.BeginInit();
this.chartControl1.Series.Clear();
this.chartControl1.AnnotationRepository.Clear();
this.chartControl1.Legend.CustomItems.Clear();
this.chartControl1.EndInit();
}
///
/// 绑定数据
///
public void SetBindingData(List vm_list, string coordinate = null)
{
_initial_data = false;
_coordinate = ValveCoordinate.ToModel(coordinate);
_series_edit_pt = null;
_vm_list = vm_list;
_exist_ql = false;
_exist_ol = false;
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;
}
AxisXBase axis_x = null;
AxisYBase axis_y = null;
XYDiagramPaneBase pane = null;
foreach (var vm in _vm_list)
{
if (vm.CurveType == Ahart.eCurveType.QL)
{
axis_x = _axis_x_flow;
axis_y = _axis_y_head_loss;
pane = _default_pane;
_exist_ql = true;
}
else if (vm.CurveType == Ahart.eCurveType.OL)
{
axis_x = _axis_x_opening;
axis_y = _axis_y_k_loss;
pane = _bottom_pane;
_exist_ol = true;
}
if (vm.IsUpdate)
{
_edit_curve_type = vm.CurveType;
_series_edit_pt = AddPointSeries(Color.Red, axis_x, axis_y, pane, vm.DefPointList);
AddLineSeries(Color.Red, axis_x, axis_y, pane, vm.FitPointList);
}
else
{
AddPointSeries(Color.Black, axis_x, axis_y, pane, vm.DefPointList);
AddLineSeries(Color.Black, axis_x, axis_y, pane, vm.FitPointList);
}
}
if (_coordinate == null)
SetCoordinate();
SetChartAxis();
this.chartControl1.EndInit();
_initial_data = true;
}
//是否是无效数据
private bool IsInvalidData()
{
if (_vm_list == null || !_vm_list.Any())
{
return true;
}
if (!_vm_list.Exists(x => x.IsUpdate))
{
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 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);
}
#endregion
#endregion
#region Set Axis
private double _min_x_flow, _max_x_flow;
private double _max_y_head_loss = 0, _min_y_head_loss = 10000;
private double _min_x_opening, _max_x_opening;
private double _max_y_k_loss = 0, _min_y_k_loss = 10000;
///
/// 设置坐标
///
private void SetCoordinate()
{
InitialCoordinate();
if (IsInvalidData())
{
return;
}
_max_x_flow = 0; _min_x_flow = 100000;
_max_x_opening = 0; _min_x_opening = 100000;
_max_y_head_loss = 0; _min_y_head_loss = 10000;
_max_y_k_loss = 0; _min_y_k_loss = 10000;
foreach (var vm in _vm_list)
{
if (vm.DefPointList == null || !vm.DefPointList.Any())
{
continue;
}
if (vm.CurveType == Ahart.eCurveType.QL)
{
_min_x_flow = Math.Min(vm.DefPointList.Min(x => x.X), _min_x_flow);
_max_x_flow = Math.Max(vm.DefPointList.Max(x => x.X), _max_x_flow);
_min_y_head_loss = Math.Min(vm.DefPointList.Min(x => x.Y), _min_y_head_loss);
_max_y_head_loss = Math.Max(vm.DefPointList.Max(x => x.Y), _max_y_head_loss);
_min_x_flow = Math.Min(vm.FitPointList.Min(x => x.X), _min_x_flow);
_max_x_flow = Math.Max(vm.FitPointList.Max(x => x.X), _max_x_flow);
_min_y_head_loss = Math.Min(vm.FitPointList.Min(x => x.Y), _min_y_head_loss);
_max_y_head_loss = Math.Max(vm.FitPointList.Max(x => x.Y), _max_y_head_loss);
}
else if (vm.CurveType == Ahart.eCurveType.OL)
{
_min_x_opening = Math.Min(vm.DefPointList.Min(x => x.X), _min_x_opening);
_max_x_opening = Math.Max(vm.DefPointList.Max(x => x.X), _max_x_opening);
_min_y_k_loss = Math.Min(vm.DefPointList.Min(x => x.Y), _min_y_k_loss);
_max_y_k_loss = Math.Max(vm.DefPointList.Max(x => x.Y), _max_y_k_loss);
_min_x_opening = Math.Min(vm.FitPointList.Min(x => x.X), _min_x_opening);
_max_x_opening = Math.Max(vm.FitPointList.Max(x => x.X), _max_x_opening);
_min_y_k_loss = Math.Min(vm.FitPointList.Min(x => x.Y), _min_y_k_loss);
_max_y_k_loss = Math.Max(vm.FitPointList.Max(x => x.Y), _max_y_k_loss);
}
}
_coordinate.QL = ValveQLCoordinate.CalcCoordinate(_min_x_flow, _max_x_flow, _min_y_head_loss, _max_y_head_loss);
if (_coordinate.QL != null)
{
if (_coordinate.QL.CoordMinX + _coordinate.QL.CoordSpaceX * this._coordinate.QL.GridNumberX < _max_x_flow * 1.05)
{
_coordinate.QL.GridNumberX++;
}
}
_coordinate.OL = ValveOLCoordinate.CalcCoordinate(_min_x_opening, _max_x_opening, _min_y_k_loss, _max_y_k_loss);
}
///
/// 设置图表轴
///
public void SetChartAxis()
{
if (_coordinate == null || IsInvalidData())
{
_axis_x_flow.Visibility = DefaultBoolean.False;
_axis_x_flow.GridLines.Visible = false;
_axis_y_head_loss.Visibility = DefaultBoolean.False;
_axis_y_head_loss.GridLines.Visible = false;
_axis_x_opening.Visibility = DefaultBoolean.False;
_axis_x_opening.GridLines.Visible = false;
_axis_y_k_loss.Visibility = DefaultBoolean.False;
_axis_y_k_loss.GridLines.Visible = false;
return;
}
if (_exist_ql)
{
//计算刻度 x_flow
var axis_x_flow_labels = new List();
var display_x_flow = _coordinate.QL.CoordMinX;
for (int i = 0; i < _coordinate.QL.GridNumberX + 1; i++)
{
var x = _coordinate.QL.CoordSpaceX < 1 ? $"{display_x_flow:N1}" : $"{display_x_flow:N0}";
axis_x_flow_labels.Add(new CustomAxisLabel(x, display_x_flow));
display_x_flow = display_x_flow + _coordinate.QL.CoordSpaceX;
}
_axis_x_flow.CustomLabels.Clear();
_axis_x_flow.CustomLabels.AddRange(axis_x_flow_labels.ToArray());
_axis_x_flow.Visibility = DefaultBoolean.True;
_axis_x_flow.GridLines.Visible = true;
//计算刻度 y_head_loss
var axis_y_head_loss_labels = new List();
var display_y_head_loss = _coordinate.QL.CoordMinY + _coordinate.QL.CoordSpaceY * _coordinate.QL.StartLineNoY;
for (int i = _coordinate.QL.StartLineNoY; i < _coordinate.QL.EndLineNoY + 1; i++)
{
var y = _coordinate.QL.CoordSpaceY < 1 ? $"{display_y_head_loss:N1}" : $"{display_y_head_loss:N0}";
axis_y_head_loss_labels.Add(new CustomAxisLabel(y, display_y_head_loss));
display_y_head_loss = display_y_head_loss + _coordinate.QL.CoordSpaceY;
}
_axis_y_head_loss.CustomLabels.Clear();
_axis_y_head_loss.CustomLabels.AddRange(axis_y_head_loss_labels.ToArray());
_axis_y_head_loss.Visibility = DefaultBoolean.True;
_axis_y_head_loss.GridLines.Visible = true;
_axis_x_flow.SetAxisRange(_coordinate.QL.CoordMinX, _coordinate.QL.DispMaxX());
_axis_y_head_loss.SetAxisRange(_coordinate.QL.DispMinY(), _coordinate.QL.DispMaxY());
_default_pane.Visibility = ChartElementVisibility.Visible;
}
else
{
_default_pane.Visibility = ChartElementVisibility.Hidden;
}
if (_exist_ol)
{
//计算刻度 x_opening
var axis_x_opening_labels = new List();
var display_x_opening = _coordinate.OL.CoordMinX;
for (int i = 0; i < _coordinate.OL.GridNumberX + 1; i++)
{
var x = _coordinate.OL.CoordSpaceX < 1 ? $"{display_x_opening:N1}" : $"{display_x_opening:N0}";
axis_x_opening_labels.Add(new CustomAxisLabel(x, display_x_opening));
display_x_opening = display_x_opening + _coordinate.OL.CoordSpaceX;
}
_axis_x_opening.CustomLabels.Clear();
_axis_x_opening.CustomLabels.AddRange(axis_x_opening_labels.ToArray());
_axis_x_opening.Visibility = DefaultBoolean.True;
_axis_x_opening.GridLines.Visible = true;
//计算刻度 y_k_loss
var axis_y_k_loss_labels = new List();
var display_y_k_loss = _coordinate.OL.CoordMinY + _coordinate.OL.CoordSpaceY * _coordinate.OL.StartLineNoY;
for (int i = _coordinate.OL.StartLineNoY; i < _coordinate.OL.EndLineNoY + 1; i++)
{
var y = _coordinate.OL.CoordSpaceY < 1 ? $"{display_y_k_loss:N1}" : $"{display_y_k_loss:N0}";
axis_y_k_loss_labels.Add(new CustomAxisLabel(y, display_y_k_loss));
display_y_k_loss = display_y_k_loss + _coordinate.OL.CoordSpaceY;
}
_axis_y_k_loss.CustomLabels.Clear();
_axis_y_k_loss.CustomLabels.AddRange(axis_y_k_loss_labels.ToArray());
_axis_y_k_loss.Visibility = DefaultBoolean.True;
_axis_y_k_loss.GridLines.Visible = true;
_axis_x_opening.SetAxisRange(_coordinate.OL.CoordMinX, _coordinate.OL.DispMaxX());
_axis_y_k_loss.SetAxisRange(_coordinate.OL.DispMinY(), _coordinate.OL.DispMaxY());
_bottom_pane.Visibility = ChartElementVisibility.Visible;
}
else
{
_bottom_pane.Visibility = ChartElementVisibility.Hidden;
}
}
#endregion Calc
}
}