using DevExpress.Utils;
|
using DevExpress.XtraCharts;
|
using Yw.Geometry;
|
|
namespace Yw.WinFrmUI.Phart
|
{
|
/// <summary>
|
/// 通用图表
|
/// </summary>
|
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<Yw.Geometry.Point2d> _pt_list = null;
|
private UniversalCoordinate _coordinate = null;
|
|
private bool _line_visible = true;
|
private bool _initial_data = false;
|
|
#endregion
|
|
#region Public Variable
|
|
/// <summary>
|
/// X轴标题
|
/// </summary>
|
public string AxisXTitle
|
{
|
get
|
{
|
return _axis_x.Title.Text;
|
}
|
set
|
{
|
_axis_x.Title.Text = value;
|
}
|
}
|
|
/// <summary>
|
/// Y轴标题
|
/// </summary>
|
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;
|
}
|
}
|
|
#endregion
|
|
#region Private Initial
|
|
/// <summary>
|
/// 初始化图表
|
/// </summary>
|
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();
|
|
|
_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();
|
|
_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;
|
}
|
|
/// <summary>
|
/// 初始化坐标轴
|
/// </summary>
|
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 diagramCoordinates = _diagram.PointToDiagram(e.Location);
|
var axis_value = diagramCoordinates.GetAxisValue(_axis_x);
|
if (axis_value == null)
|
return;
|
double x = axis_value.NumericalValue;
|
SetAxisXValue(x);
|
|
}
|
else if (_on_move_y_line)
|
{
|
var diagramCoordinates = _diagram.PointToDiagram(e.Location);
|
var axis_value = diagramCoordinates.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
|
|
/// <summary>
|
/// 绑定数据
|
/// </summary>
|
public void SetBindingData(List<Yw.Geometry.Point2d> pt_list, string caption = "", string coordinate = null, Color? color = null)
|
{
|
_pt_list = pt_list;
|
_coordinate = UniversalCoordinate.ToModel(coordinate);
|
|
this.chartControl1.BeginInit();
|
this.chartControl1.Series.Clear();
|
this.chartControl1.AnnotationRepository.Clear();
|
this.chartControl1.Legend.CustomItems.Clear();
|
if (pt_list == null || !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, pt_list);
|
if (!string.IsNullOrEmpty(caption))
|
{
|
AddAnnotation( caption, color.Value, _axis_y, _default_pane, pt_list.Last());
|
}
|
|
if (_coordinate == null)
|
SetCoordinate();
|
|
SetChartAxis();
|
this.chartControl1.EndInit();
|
_initial_data = true;
|
}
|
|
//是否是无效数据
|
private bool IsInvalidData()
|
{
|
if (_pt_list == null || !_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<Yw.Geometry.Point2d> 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<Yw.Geometry.Point2d> 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;
|
|
this.chartControl1.AnnotationRepository.Add(text_annotation);
|
}
|
|
#endregion
|
|
#endregion
|
|
#region Set Axis
|
|
private double _minX, _maxX;
|
private double _maxY = 0, _minY = 10000;
|
|
/// <summary>
|
/// 设置坐标
|
/// </summary>
|
private void SetCoordinate()
|
{
|
if (IsInvalidData())
|
{
|
InitialCoordinate();
|
return;
|
}
|
|
_minX = _pt_list.Min(x => x.X);
|
_maxX = _pt_list.Max(x => x.X);
|
|
_minY = _pt_list.Min(x => x.Y);
|
_maxY = _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++;
|
}
|
}
|
|
/// <summary>
|
/// 设置图表轴
|
/// </summary>
|
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<CustomAxisLabel>();
|
var dis_x = _coordinate.CoordMinX;
|
for (int i = 0; i < _coordinate.GridNumberX + 1; i++)
|
{
|
axis_x_labels.Add(new CustomAxisLabel(dis_x.ToString("N0"), dis_x));
|
dis_x = dis_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<CustomAxisLabel>();
|
var dis_y = _coordinate.CoordMinY + _coordinate.CoordSpaceY * _coordinate.StartLineNoY;
|
for (int i = _coordinate.StartLineNoY; i < _coordinate.EndLineNoY + 1; i++)
|
{
|
axis_y_labels.Add(new CustomAxisLabel(dis_y.ToString(), dis_y));
|
dis_y = dis_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
|
|
/// <summary>
|
/// 设置X轴值
|
/// </summary>
|
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 = _pt_list.Min(x => x.X);
|
var max_x = _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 = _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}";
|
|
}
|
|
/// <summary>
|
/// 设置Y轴值
|
/// </summary>
|
public void SetAxisYValue(double y)
|
{
|
if (!_line_visible)
|
return;
|
if (IsInvalidData())
|
return;
|
|
var min_y = _pt_list.Min(x => x.Y);
|
var max_y = _pt_list.Max(x => x.Y);
|
if (y < min_y || y > max_y)
|
return;
|
|
var x_value = _pt_list.GetInterPointsX(y)?.LastOrDefault();
|
SetAxisXValue(x_value);
|
|
}
|
|
#endregion
|
|
}
|
}
|