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
}
}