using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms.DataVisualization.Charting;
namespace FLY.ControlLibrary
{
///
/// GraphRange.xaml 的交互逻辑
/// IsAutoTarget, 自动目标值
/// IsPercent,百分比显示,alarm = curr_target * Alarm/Target,
///
public partial class GraphRange : UserControl, IGraphRange, INotifyPropertyChanged
{
#region 私有成员变量
int autotarget = 30;
protected int AutoTarget
{
get
{
return autotarget;
}
set
{
if (autotarget != value)
{
autotarget = value;
NotifyPropertyChanged("AutoTarget");
}
}
}
#endregion
#region 接口
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(GraphRange), new PropertyMetadata(
"Title",
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("Title");
})));
public string Title
{
get
{
return GetValue(TitleProperty) as string;
}
set
{
SetValue(TitleProperty, value);
}
}
public static readonly DependencyProperty Title2Property =
DependencyProperty.Register("Title2", typeof(string), typeof(GraphRange), new PropertyMetadata(
"",
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("Title2");
})));
public string Title2
{
get
{
return GetValue(Title2Property) as string;
}
set
{
SetValue(Title2Property, value);
}
}
///
/// 计算结果
///
public static readonly DependencyProperty CalStateProperty =
DependencyProperty.Register("CalState", typeof(string), typeof(GraphRange), new PropertyMetadata(
"Max:null Min:null Avg:null 2σ:null",
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
})));
public string CalState
{
get
{
return (string)GetValue(CalStateProperty);
}
set
{
SetValue(CalStateProperty, value);
}
}
///
/// 空的数据,定义某个值为空,默认为 99999998
///
public static readonly DependencyProperty EmptyValueProperty =
DependencyProperty.Register("EmptyValue", typeof(int), typeof(GraphRange), new PropertyMetadata(
99999998,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("EmptyValue");
})));
public int EmptyValue
{
get
{
return (int)GetValue(EmptyValueProperty);
}
set
{
SetValue(EmptyValueProperty, value);
}
}
///
/// 放大倍数, 目标值= Target/放大倍数
///
public static readonly DependencyProperty MultiProperty =
DependencyProperty.Register("Multi", typeof(int), typeof(GraphRange), new PropertyMetadata(
100,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("Multi");
})));
public int Multi
{
get
{
return (int)GetValue(MultiProperty);
}
set
{
SetValue(MultiProperty, value);
}
}
///
/// %显示
///
public static readonly DependencyProperty IsPercentProperty =
DependencyProperty.Register("IsPercent", typeof(bool), typeof(GraphRange), new PropertyMetadata(
false,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("IsPercent");
})));
public bool IsPercent
{
get
{
return (bool)GetValue(IsPercentProperty);
}
set
{
SetValue(IsPercentProperty, value);
}
}
///
/// 自动目标值
///
public static readonly DependencyProperty IsAutoTargetProperty =
DependencyProperty.Register("IsAutoTarget", typeof(bool), typeof(GraphRange), new PropertyMetadata(
false,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("IsAutoTarget");
})));
public bool IsAutoTarget
{
get
{
return (bool)GetValue(IsAutoTargetProperty);
}
set
{
SetValue(IsAutoTargetProperty, value);
}
}
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register("Type", typeof(GraphRangeType), typeof(GraphRange), new PropertyMetadata(
GraphRangeType.Sigma2,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("Type");
})));
public GraphRangeType Type
{
get
{
return (GraphRangeType)GetValue(TypeProperty);
}
set
{
SetValue(TypeProperty, value);
}
}
public static readonly DependencyProperty XAxisTypeProperty =
DependencyProperty.Register("XAxisType", typeof(GraphRangeXAxisType), typeof(GraphRange), new PropertyMetadata(
GraphRangeXAxisType.Time,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("XAxisType");
})));
public GraphRangeXAxisType XAxisType
{
get
{
return (GraphRangeXAxisType)GetValue(XAxisTypeProperty);
}
set
{
SetValue(XAxisTypeProperty, value);
}
}
///
/// 目标值
///
public static readonly DependencyProperty TargetProperty =
DependencyProperty.Register("Target", typeof(int), typeof(GraphRange), new PropertyMetadata(
3000,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("Target");
})));
public int Target
{
get
{
return (int)GetValue(TargetProperty);
}
set
{
SetValue(TargetProperty, value);
}
}
///
/// 报警值
///
public static readonly DependencyProperty AlarmProperty =
DependencyProperty.Register("Alarm", typeof(int), typeof(GraphRange), new PropertyMetadata(
1000,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("Alarm");
})));
public int Alarm
{
get
{
return (int)GetValue(AlarmProperty);
}
set
{
SetValue(AlarmProperty, value);
}
}
///
/// 控制线
///
public static readonly DependencyProperty HasCtrlLineProperty =
DependencyProperty.Register("HasCtrlLine", typeof(bool), typeof(GraphRange), new PropertyMetadata(
false,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("HasCtrlLine");
})));
public bool HasCtrlLine
{
get
{
return (bool)GetValue(HasCtrlLineProperty);
}
set
{
SetValue(HasCtrlLineProperty, value);
}
}
///
/// 控制线
///
public static readonly DependencyProperty CtrlLineProperty =
DependencyProperty.Register("CtrlLine", typeof(int), typeof(GraphRange), new PropertyMetadata(
1000,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("CtrlLine");
})));
public int CtrlLine
{
get
{
return (int)GetValue(CtrlLineProperty);
}
set
{
SetValue(CtrlLineProperty, value);
}
}
///
/// Y轴是 Alarm 的N倍 默认是 3倍
///
public static readonly DependencyProperty YRangePercentProperty =
DependencyProperty.Register("YRangePercent", typeof(double), typeof(GraphRange), new PropertyMetadata(
3.0,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("YRangePercent");
})));
public double YRangePercent
{
get
{
return (double)GetValue(YRangePercentProperty);
}
set
{
SetValue(YRangePercentProperty, value);
}
}
public static readonly DependencyProperty DataCntProperty =
DependencyProperty.Register("DataCnt", typeof(int), typeof(GraphRange), new PropertyMetadata(
80,
new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as GraphRange).NotifyPropertyChanged("DataCnt");
})));
public int DataCnt
{
get
{
return (int)GetValue(DataCntProperty);
}
set
{
SetValue(DataCntProperty, value);
}
}
///
/// 数据源
///
private ObservableCollection _datasource;
public ObservableCollection DataSource
{
get
{
return _datasource;
}
set
{
if (_datasource != null)
_datasource.CollectionChanged -= _dataSource_CollectionChanged;
_datasource = value;
_datasource.CollectionChanged += _dataSource_CollectionChanged;
mRefresh.UpdateData = true;
}
}
System.Collections.Specialized.NotifyCollectionChangedEventHandler _dataSource_CollectionChanged;
public event EventHandler ShowSettingDialogEvent;
#endregion
#region 刷新率控制
class Refresh
{
///
/// 控制刷新率
///
System.Windows.Threading.DispatcherTimer timer;
bool updatedata_flag = false;
bool updatey_flag = false;
bool updatex_flag = false;
bool updatecalx_flag = false;
///
/// 最快0.1s 刷新一次
///
TimeSpan REFRESH_RATE = TimeSpan.FromSeconds(0.1);
public Refresh(GraphRange graph)
{
timer = new System.Windows.Threading.DispatcherTimer();
timer.Tick += new EventHandler(delegate(object sender, EventArgs e)
{
if (UpdateData)
{
UpdateData = false;
graph.UpdateAutoTarget();
graph.DataBindAll();
}
if (UpdateY)
{
UpdateY = false;
graph.UpdateAxisY();
}
if (UpdateX)
{
UpdateX = false;
graph.UpdateXRange();
graph.UpdateXType();
}
timer.Stop();
});
timer.Interval = REFRESH_RATE;
timer.Start();
}
public bool UpdateData
{
get { return updatedata_flag; }
set
{
updatedata_flag = value;
if (value)
{
if (!timer.IsEnabled)
timer.Start();
}
}
}
public bool UpdateY
{
get { return updatey_flag; }
set
{
updatey_flag = value;
if (value)
{
if (!timer.IsEnabled)
timer.Start();
}
}
}
public bool UpdateX
{
get { return updatex_flag; }
set
{
updatex_flag = value;
if (value)
{
if (!timer.IsEnabled)
timer.Start();
}
}
}
public bool UpdateCalX
{
get { return updatecalx_flag; }
set
{
updatecalx_flag = value;
if (value)
{
if (!timer.IsEnabled)
timer.Start();
}
}
}
}
Refresh mRefresh;
#endregion
public GraphRange()
{
InitializeComponent();
InitializeComponent2();
_dataSource_CollectionChanged = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(dataSource_CollectionChanged);
this.PropertyChanged += new PropertyChangedEventHandler(GraphRange_PropertyChanged);
mRefresh = new Refresh(this);
mRefresh.UpdateX = true;
mRefresh.UpdateY = true;
CheckDataSourceEmpty();
run_title.Text = Title;
run_title2.Text = Title2;
}
void GraphRange_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if ((e.PropertyName == "Target") ||
(e.PropertyName == "Alarm") ||
(e.PropertyName == "YRangePercent") ||
(e.PropertyName == "AutoTarget") ||
(e.PropertyName == "IsAutoTarget") ||
(e.PropertyName == "IsPercent") ||
(e.PropertyName == "Type"))
{
mRefresh.UpdateY = true;
mRefresh.UpdateData = true;
}
else if ((e.PropertyName == "DataCnt") ||
(e.PropertyName == "XAxisType"))
{
mRefresh.UpdateX = true;
}
else if (e.PropertyName == "Title") {
run_title.Text = Title;
}
else if (e.PropertyName == "Title2")
{
run_title2.Text = Title2;
}
}
void InitializeComponent2()
{
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Series series_sigma = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.Series series_avg = new System.Windows.Forms.DataVisualization.Charting.Series();
chart1.Name = "chart1";
chart1.BackColor = System.Drawing.Color.Transparent;
//
// chart1
//---------------------------------------------------------------------------------------
chartArea1.Name = "chartArea1";
chartArea1.AxisX.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
chartArea1.AxisX.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
chartArea1.AxisX.IsMarksNextToAxis = false;
chartArea1.AxisX.IsLabelAutoFit = true;
chartArea1.AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
chartArea1.AxisX.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount;
chartArea1.AxisY.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold);
chartArea1.AxisY.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
chartArea1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
chartArea1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
//chartArea1.Position.Height = 100;// 42F;
//chartArea1.Position.Width = 100;// 88F;
//chartArea1.Position.X = 0;// 3F;
//chartArea1.Position.Y = 0;// 10F;
chart1.ChartAreas.Add(chartArea1);
//---------------------------------------------------------------------------------------
series_sigma.Name = "series_sigma";
series_sigma.ChartArea = chartArea1.Name;
series_sigma.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.RangeColumn;
series_sigma.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));
series_sigma.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));
series_sigma.BorderWidth = 2;
series_sigma.ShadowColor = System.Drawing.Color.Black;
series_sigma.ShadowOffset = 2;
series_sigma.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
series_sigma.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
chart1.Series.Add(series_sigma);
//---------------------------------------------------------------------------------------
series_avg.Name = "series_avg";
series_avg.ChartArea = chartArea1.Name;
series_avg.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline;
series_avg.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));
series_avg.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));
series_avg.BorderWidth = 3;
series_avg.ShadowColor = System.Drawing.Color.Black;
series_avg.ShadowOffset = 2;
series_avg.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32;
series_avg.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
chart1.Series.Add(series_avg);
//chart1.PrePaint += new EventHandler(Chart1_PrePaint);
this.chart1.PrePaint += new System.EventHandler(Chart1_PrePaint);
}
public void UpdateCtrlLine()
{
//chart1.Invalidate();
}
protected virtual void Chart1_PrePaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e)
{
//if (e.ChartElement is ChartArea)
//{
// ChartArea area = (ChartArea)e.ChartElement;
// if (area.Name == "chartArea1")
// {
// if (!HasCtrlLine)
// return;
// double c1 = ((double)(Target+CtrlLine)) / Multi;
// double c2 = ((double)(Target-CtrlLine)) / Multi;
// if (c1 > area.AxisY.Maximum || c2 < area.AxisY.Minimum)
// return;
// // Take Graphics object from chart
// System.Drawing.Graphics graph = e.ChartGraphics.Graphics;
// // Convert X and Y values to screen position
// c1 = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.Y, c1);
// c2 = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.Y, c2);
// double XMin = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Minimum);
// double XMax = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Maximum);
// // Draw Maximum trangle
// System.Drawing.Pen darkPen = new System.Drawing.Pen(System.Drawing.Color.DarkRed, 2);
// System.Drawing.PointF[] points = new System.Drawing.PointF[2];
// points[0].X = (float)XMin;
// points[1].X = (float)XMax;
// points[0].Y = points[1].Y = (float)c1;
// // Convert relative coordinates to absolute coordinates.
// points[0] = e.ChartGraphics.GetAbsolutePoint(points[0]);
// points[1] = e.ChartGraphics.GetAbsolutePoint(points[1]);
// graph.DrawLine(darkPen, points[0], points[1]);
// points[0].X = (float)XMin;
// points[1].X = (float)XMax;
// points[0].Y = points[1].Y = (float)c2;
// // Convert relative coordinates to absolute coordinates.
// points[0] = e.ChartGraphics.GetAbsolutePoint(points[0]);
// points[1] = e.ChartGraphics.GetAbsolutePoint(points[1]);
// graph.DrawLine(darkPen, points[0], points[1]);
// }
//}
}
void dataSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
mRefresh.UpdateData = true;
}
#region 绑定画图
void DataBindAll()
{
CheckDataSourceEmpty();
UpdateAutoTarget();
switch (Type)
{
case GraphRangeType.All:
DataBindAll_all();
break;
case GraphRangeType.Avg:
DataBindAll_avg();
break;
case GraphRangeType.Sigma2:
DataBindAll_2sigma();
break;
}
UpdateXType();
}
#endregion
void UpdateDataCalRange()
{
switch (Type)
{
case GraphRangeType.All:
UpdateDataCalRange_avg();
break;
case GraphRangeType.Avg:
UpdateDataCalRange_avg();
break;
case GraphRangeType.Sigma2:
UpdateDataCalRange_2sigma();
break;
}
}
///
/// DataSource 里面的数据都是 EmptyValue 组成, 当修改数据时,应该clear ,再添加
///
bool DataSourceIsEmpty = false;
///
/// 当一个数据都没有时,需要添加空数据
///
protected void CheckDataSourceEmpty()
{
if ((DataSource == null) || (DataSource.Count() == 0))
{
chart1.Series["series_avg"].Points.Clear();
chart1.Series["series_sigma"].Points.Clear();
chart1.Series["series_sigma"].Points.AddXY(0, 10,-10);
chart1.Series["series_sigma"].Points[0].IsEmpty = true;
DataSourceIsEmpty = true;
}
else
{
DataSourceIsEmpty = false;
}
}
public void Button_Click(object sender, RoutedEventArgs e)
{
if (ShowSettingDialogEvent != null)
ShowSettingDialogEvent(this, new EventArgs());
}
///
/// 与 FirstBoltNo,FirstIndex,LastIndex 相关
///
void UpdateXRange()
{
// Set manual minimum and maximum values.
chart1.ChartAreas["chartArea1"].AxisX.Minimum = 0;
chart1.ChartAreas["chartArea1"].AxisX.Maximum = DataCnt;
}
void UpdateXType()
{
UpdateDataCalRange();
if (DataSource == null)
return;
switch (XAxisType)
{
case GraphRangeXAxisType.Index:
{
for (int i = 0; i < DataSource.Count(); i++)
{
if (i < chart1.Series["series_sigma"].Points.Count)
{
DataPoint p = chart1.Series["series_sigma"].Points[i];
p.AxisLabel = null;
}
if (i < chart1.Series["series_avg"].Points.Count)
{
DataPoint p = chart1.Series["series_avg"].Points[i];
p.AxisLabel = null;
}
}
}break;
case GraphRangeXAxisType.Time:
{
for (int i = 0; i < DataSource.Count(); i++)
{
if (i < chart1.Series["series_sigma"].Points.Count)
{
DataPoint p = chart1.Series["series_sigma"].Points[i];
p.AxisLabel = DataSource[i].Time.ToString("HH:mm");
}
if (i < chart1.Series["series_avg"].Points.Count)
{
DataPoint p = chart1.Series["series_avg"].Points[i];
p.AxisLabel = DataSource[i].Time.ToString("HH:mm");
}
}
}break;
}
}
void UpdateAutoTarget()
{
AutoTarget = Target;
if (DataSource == null)
return;
for (int i = 0; i < DataSource.Count(); i++)
{
if (DataSource[DataSource.Count - 1 - i].Avg != EmptyValue)
{
AutoTarget = DataSource[DataSource.Count - 1 - i].Avg;
break;
}
}
}
void UpdateAxisY()
{
switch(Type)
{
case GraphRangeType.Sigma2:
UpdateAxisY_2sigma();
break;
case GraphRangeType.All:
UpdateAxisY_all();
break;
case GraphRangeType.Avg:
UpdateAxisY_avg();
break;
}
}
protected void SetCustomLabel(Axis axisY, double p, string s, GridTickTypes gt, System.Drawing.Color c)
{
double multi = Multi;
double r = axisY.Maximum - axisY.Minimum;
double f, t;
f = p + r / 2;
t = p - r / 2;
CustomLabel customLabel = axisY.CustomLabels.Add(f, t, s);
customLabel.GridTicks = gt;
customLabel.ForeColor = c;
}
#region 2sigma
protected virtual void SetCustomLabel_2sigma(Axis axisY, double p, GridTickTypes gt, System.Drawing.Color c, bool ispercent, string message)
{
double multi = Multi;
double r = axisY.Maximum - axisY.Minimum;
double f, t;
f = p + r / 2;
t = p - r / 2;
CustomLabel customLabel;
string str;
if (!ispercent)
{
str = p.ToString("N1");
}
else
{
str = p.ToString("N1") + "%";
}
if (!string.IsNullOrEmpty(message))
str = message + " " + str;
customLabel = axisY.CustomLabels.Add(f, t, str);
customLabel.GridTicks = gt;
customLabel.ForeColor = c;
}
protected virtual void UpdateAxisY_2sigma()
{
double multi = Multi;
double alarm;
double yrange;
if (IsPercent)
{
alarm = 100.0 * Alarm / Target;
yrange = alarm * YRangePercent;
}
else
{
alarm = Alarm / multi;
yrange = alarm * YRangePercent;
}
if ((alarm < 0.1) || (yrange<0.3))
{
alarm = 0.1;
yrange = 0.3;
}
Axis axisY = chart1.ChartAreas["chartArea1"].AxisY;
//TODO
axisY.Crossing = 0;
// Set manual minimum and maximum values.
axisY.Minimum = -yrange;
axisY.Maximum = yrange;
axisY.CustomLabels.Clear();
//上下限
SetCustomLabel_2sigma(axisY, alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, IsPercent, null);
SetCustomLabel_2sigma(axisY, -alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, IsPercent, null);
//2倍上下限
SetCustomLabel_2sigma(axisY, alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, IsPercent, null);
SetCustomLabel_2sigma(axisY, -alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, IsPercent, null);
//SetCustomLabel_2sigma(axisY, axisY.Maximum, GridTickTypes.All, System.Drawing.Color.Black, IsPercent, null);
//SetCustomLabel_2sigma(axisY, axisY.Minimum, GridTickTypes.All, System.Drawing.Color.Black, IsPercent, null);
//显示范围数值
if ((yrange != alarm) && (yrange != 2 * alarm))
{
SetCustomLabel_2sigma(axisY, axisY.Minimum, GridTickTypes.TickMark, System.Drawing.Color.Black, IsPercent, null);
SetCustomLabel_2sigma(axisY, axisY.Maximum, GridTickTypes.TickMark, System.Drawing.Color.Black, IsPercent, null);
}
//显示范围太小,多加纵坐标
if (yrange <= alarm)
{
SetCustomLabel_2sigma(axisY, (axisY.Maximum + axisY.Minimum) / 2 - (axisY.Maximum - axisY.Minimum) / 4, GridTickTypes.All, System.Drawing.Color.Black, IsPercent, null);
SetCustomLabel_2sigma(axisY, (axisY.Maximum + axisY.Minimum) / 2 + (axisY.Maximum - axisY.Minimum) / 4, GridTickTypes.All, System.Drawing.Color.Black, IsPercent, null);
}
}
protected virtual void UpdateOnePoint_2sigma(int index)
{
double multi = Multi;
int emptyvalue = EmptyValue;
DataPoint point;
double sigma2 = 2 * DataSource[index].Sigma / multi;
double avg = DataSource[index].Avg / multi;
if (IsPercent)
{
if (avg <= 0)
{
//异常
sigma2 = 0;
}
else
{
sigma2 = sigma2 / avg * 100;
}
}
if (index >= chart1.Series["series_sigma"].Points.Count)
{
chart1.Series["series_sigma"].Points.AddXY(index, sigma2, -sigma2);
point = chart1.Series["series_sigma"].Points[index];
}
else
{
point = chart1.Series["series_sigma"].Points[index];
point.YValues[0] = sigma2;
point.YValues[1] = -sigma2;
point.XValue = index;
}
//设定空数据
if (DataSource[index].Avg == emptyvalue)
{
point.IsEmpty = true;
}
else
{
point.IsEmpty = false;
double threshold1;
double threshold2;
if (IsPercent)
threshold1 = 100.0 * Alarm / Target;
else
threshold1 = Alarm / multi;
threshold2 = threshold1 * 2;
System.Drawing.Color c;
if (sigma2 > threshold2)
c = System.Drawing.Color.Red;
else if (sigma2 > threshold1)
c = System.Drawing.Color.Orange;
else
c = System.Drawing.Color.Green;
point.BorderColor = c;
point.Color = c;
}
}
void DataBindAll_2sigma()
{
chart1.Series["series_avg"].Points.Clear();
chart1.Series["series_sigma"].Points.Clear();
if (DataSource != null)
{
for (int i = 0; i < DataSource.Count(); i++)
{
UpdateOnePoint_2sigma(i);
}
}
CheckDataSourceEmpty();
}
///
/// 与 FirstBoltNo,DataFirst,DataLast 相关
///
void UpdateDataCalRange_2sigma()
{
System.Windows.Forms.DataVisualization.Charting.Axis axisX = chart1.ChartAreas["chartArea1"].AxisX;
axisX.CustomLabels.Clear();
}
#endregion
#region all
void UpdateAxisY_all()
{
chart1.Series["series_avg"].ChartType = SeriesChartType.Spline;
UpdateAxisY_avg();
}
protected virtual void UpdateOnePoint_all(int index)
{
double multi = Multi;
int emptyvalue = EmptyValue;
DataPoint point_sigma;
DataPoint point_avg;
double sigma2 = 2 * DataSource[index].Sigma / multi;
double avg = DataSource[index].Avg / multi;
if (index >= chart1.Series["series_sigma"].Points.Count)
{
chart1.Series["series_sigma"].Points.AddXY(index, avg + sigma2, avg - sigma2);
point_sigma = chart1.Series["series_sigma"].Points[index];
chart1.Series["series_avg"].Points.AddXY(index, avg);
point_avg = chart1.Series["series_avg"].Points[index];
}
else
{
point_sigma = chart1.Series["series_sigma"].Points[index];
point_sigma.YValues[0] = avg + sigma2;
point_sigma.YValues[1] = avg - sigma2;
point_sigma.XValue = index;
point_avg = chart1.Series["series_avg"].Points[index];
point_avg.YValues[0] = avg;
point_avg.XValue = index;
}
//设定空数据
if (DataSource[index].Avg == emptyvalue)
{
point_sigma.IsEmpty = true;
point_avg.IsEmpty = true;
}
else
{
point_sigma.IsEmpty = false;
double alarm;
double target;
double yrange;
bool ispercent;
GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent);
double threshold1 = alarm;
double threshold2 = alarm * 2;
System.Drawing.Color c;
if (((avg + sigma2) > (target + threshold2)) || ((avg + sigma2) < (target - threshold2)))
{
c = System.Drawing.Color.Red;
}
else if (((avg - sigma2) > (target + threshold2)) || ((avg - sigma2) < (target - threshold2)))
{
c = System.Drawing.Color.Red;
}
else if (((avg + sigma2) > (target + threshold1)) || ((avg + sigma2) < (target - threshold1)))
{
c = System.Drawing.Color.Orange;
}
else if (((avg - sigma2) > (target + threshold1)) || ((avg - sigma2) < (target - threshold1)))
{
c = System.Drawing.Color.Orange;
}
else
{
c = System.Drawing.Color.Green;
}
point_sigma.BorderColor = c;
point_sigma.Color = c;
point_avg.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240)))));
point_avg.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105)))));
}
}
void DataBindAll_all()
{
chart1.Series["series_avg"].Points.Clear();
chart1.Series["series_sigma"].Points.Clear();
if (DataSource != null)
{
for (int i = 0; i < DataSource.Count(); i++)
{
UpdateOnePoint_all(i);
}
}
CheckDataSourceEmpty();
UpdateCalState_all();
}
///
/// 与 Multi,EmptyValue,DataFirst,DataLast 相关
///
void UpdateCalState_all()
{
int emptyvalue = EmptyValue;
double multi = Multi;
if (DataSource == null)
{
goto _err;
}
string title;
var dats_max = from data in DataSource where data.Avg != emptyvalue select data.Avg+data.Sigma*2;
var dats_min = from data in DataSource where data.Avg != emptyvalue select data.Avg - data.Sigma * 2;
List dats = new List();
dats.AddRange(dats_max);
dats.AddRange(dats_min);
if (dats.Count() == 0)
{
goto _err;
}
else
{
//AutoTarget = (int)dats.Average();
double avg = dats.Average() / multi;
double max = dats.Max() / multi;
double min = dats.Min() / multi;
double sum = 0;
foreach (int dat in dats)
{
sum += Math.Pow(avg - (double)dat / multi, 2);
}
sum /= (dats.Count() - 1);
double sigma = Math.Sqrt(sum);
if (IsPercent)
{
title = "Max:+" + ((max / avg * 100) - 100).ToString("N1") + "% " +
"Min:-" + (100 - (min / avg * 100)).ToString("N1") + "% " +
"Avg:" + avg.ToString("N1") + " " +
"2σ:" + (sigma / avg * 2 * 100).ToString("N1") + "%";
}
else
{
title = "Max:" + max.ToString("N1") + " " +
"Min:" + min.ToString("N1") + " " +
"Avg:" + avg.ToString("N1") + " " +
"2σ:" + (sigma * 2).ToString("N1");
}
}
goto _end;
_err:
//title = Properties.Resources.StrMax + ":" + "NULL " +
// Properties.Resources.StrMin+":"+"NULL "+
// Properties.Resources.StrAvg+":"+"NULL "+
// "3Sigma:"+"NULL ";
title = "Max:null Min:null Avg:null 2σ:null";
_end:
CalState = title;
UpdateDataCalRange_avg();
}
#endregion
#region avg
protected void SetCustomLabel(Axis axisY, double p, GridTickTypes gt, System.Drawing.Color c, bool ispercent, string message)
{
double multi = Multi;
double r = axisY.Maximum - axisY.Minimum;
double f, t;
f = p + r / 2;
t = p - r / 2;
double target = (axisY.Maximum + axisY.Minimum) / 2;
CustomLabel customLabel;
string str;
if (!ispercent)
{
str = p.ToString("N1");
}
else
{
if (target == p)
{
str = p.ToString("N1");
}
else
{
double percent;
percent = ((p - target) / target) * 100;
str = percent.ToString("N1") + "%";
}
}
if (!string.IsNullOrEmpty(message))
str = message + " " + str;
customLabel = axisY.CustomLabels.Add(f, t, str);
customLabel.GridTicks = gt;
customLabel.ForeColor = c;
}
///
/// 获取实际应用的目标值,公差
///
///
///
///
void GetActualTargetAlarm(out double target, out double alarm, out double yrange, out bool ispercent)
{
double multi = Multi;
if (IsAutoTarget)
target = AutoTarget / multi;//AutoTarget 计算得到的平均值
else
target = Target / multi;
ispercent = IsPercent;
if ((ispercent) && (Target <= 0) || (Alarm < 0) || (target <= 0))
ispercent = false;
if (ispercent)
{
alarm = target * Alarm / Target;
yrange = alarm * YRangePercent;
}
else
{
alarm = Alarm / multi;
yrange = alarm * YRangePercent;
}
if ((alarm < 0.1) || (yrange < 0.3))
{
alarm = 0.1;
yrange = 0.3;
}
}
protected virtual void UpdateAxisY_avg()
{
double alarm;
double target;
double yrange;
bool ispercent;
GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent);
Axis axisY = chart1.ChartAreas["chartArea1"].AxisY;
axisY.Crossing = target;
// Set manual minimum and maximum values.
axisY.Minimum = target - yrange;// 3 * alarm;
axisY.Maximum = target + yrange;// 3 * alarm;
axisY.CustomLabels.Clear();
//目标值
SetCustomLabel(axisY, target, GridTickTypes.All, System.Drawing.Color.Green, false, null);
//上下限
SetCustomLabel(axisY, target + alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, ispercent, null);
SetCustomLabel(axisY, target - alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, ispercent, null);
//2倍上下限
SetCustomLabel(axisY, target + alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null);
SetCustomLabel(axisY, target - alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null);
//显示范围数值
if ((yrange != alarm) && (yrange != 2 * alarm))
{
SetCustomLabel(axisY, axisY.Minimum, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null);
SetCustomLabel(axisY, axisY.Maximum, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null);
}
//显示范围太小,多加纵坐标
if (yrange <= alarm)
{
SetCustomLabel(axisY, target - yrange / 2, GridTickTypes.All, System.Drawing.Color.Black, ispercent, null);
SetCustomLabel(axisY, target + yrange / 2, GridTickTypes.All, System.Drawing.Color.Black, ispercent, null);
}
}
protected virtual void UpdateOnePoint_avg(int index)
{
double multi = Multi;
int emptyvalue = EmptyValue;
DataPoint point_avg;
double avg = DataSource[index].Avg / multi;
if (index >= chart1.Series["series_avg"].Points.Count)
{
chart1.Series["series_avg"].Points.AddXY(index, avg);
point_avg = chart1.Series["series_avg"].Points[index];
}
else
{
point_avg = chart1.Series["series_avg"].Points[index];
point_avg.YValues[0] = avg;
point_avg.XValue = index;
}
//设定空数据
if (DataSource[index].Avg == emptyvalue)
{
point_avg.IsEmpty = true;
}
else
{
point_avg.IsEmpty = false;
double alarm;
double target;
double yrange;
bool ispercent;
GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent);
double threshold1 = alarm;
double threshold2 = alarm * 2;
System.Drawing.Color c;
if ((avg > (target + threshold2)) || (avg < (target - threshold2)))
{
c = System.Drawing.Color.Red;
}
else if ((avg > (target + threshold1)) || (avg < (target - threshold1)))
{
c = System.Drawing.Color.Orange;
}
else
{
c = System.Drawing.Color.Green;
}
point_avg.BorderColor = c;
point_avg.Color = c;
}
}
void DataBindAll_avg()
{
chart1.Series["series_avg"].ChartType = SeriesChartType.Column;
chart1.Series["series_avg"].Points.Clear();
chart1.Series["series_sigma"].Points.Clear();
if (DataSource != null)
{
for (int i = 0; i < DataSource.Count(); i++)
{
UpdateOnePoint_avg(i);
}
}
CheckDataSourceEmpty();
UpdateCalState_avg();
}
///
/// 与 Multi,EmptyValue,DataFirst,DataLast 相关
///
void UpdateCalState_avg()
{
int emptyvalue = EmptyValue;
double multi = Multi;
if (DataSource == null)
{
goto _err;
}
string title;
var dats = from data in DataSource where data.Avg != emptyvalue select data.Avg;
if (dats.Count() == 0)
{
goto _err;
}
else
{
//AutoTarget = (int)dats.Average();
double avg = dats.Average() / multi;
double max = dats.Max() / multi;
double min = dats.Min() / multi;
double sum = 0;
foreach (int dat in dats)
{
sum += Math.Pow(avg - (double)dat / multi, 2);
}
sum /= (dats.Count() - 1);
double sigma = Math.Sqrt(sum);
if (IsPercent)
{
title = "Max:+" + ((max / avg * 100) - 100).ToString("N1") + "% " +
"Min:-" + (100 - (min / avg * 100)).ToString("N1") + "% " +
"Avg:" + avg.ToString("N1") + " " +
"2σ:" + (sigma / avg * 2 * 100).ToString("N1") + "%";
}
else
{
title = "Max:" + max.ToString("N1") + " " +
"Min:" + min.ToString("N1") + " " +
"Avg:" + avg.ToString("N1") + " " +
"2σ:" + (sigma * 2).ToString("N1");
}
}
goto _end;
_err:
//title = Properties.Resources.StrMax + ":" + "NULL " +
// Properties.Resources.StrMin+":"+"NULL "+
// Properties.Resources.StrAvg+":"+"NULL "+
// "3Sigma:"+"NULL ";
title = "Max:null Min:null Avg:null 2σ:null";
_end:
CalState = title;
UpdateDataCalRange_avg();
}
///
/// 与 FirstBoltNo,DataFirst,DataLast 相关
///
void UpdateDataCalRange_avg()
{
System.Windows.Forms.DataVisualization.Charting.Axis axisX = chart1.ChartAreas["chartArea1"].AxisX;
axisX.CustomLabels.Clear();
System.Windows.Forms.DataVisualization.Charting.CustomLabel customlabel
= new System.Windows.Forms.DataVisualization.Charting.CustomLabel(0,DataCnt,
CalState, 1,
System.Windows.Forms.DataVisualization.Charting.LabelMarkStyle.LineSideMark);
axisX.CustomLabels.Add(customlabel);
}
#endregion
#region INotifyPropertyChanged 成员
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
public interface IGraphRange
{
#region 附加属性
///
/// 标题1
///
string Title { get; set; }
///
/// 标题2
///
string Title2 { get; set; }
///
/// 计算结果
///
string CalState { get; set; }
///
/// 空的数据,定义某个值为空,默认为 99999998
///
int EmptyValue { get; set; }
///
/// 放大倍数, 目标值= Target/放大倍数
///
int Multi { get; set; }
///
/// %显示
///
bool IsPercent { get; set; }
///
/// 自动目标值
///
bool IsAutoTarget { get; set; }
///
/// 图显示的内容,
/// 当为Sigma2, 只有 IsPercent 有效
/// 当为Avg,
/// 当为All,
///
GraphRangeType Type { get; set; }
///
/// 目标值
///
int Target { get; set; }
///
/// 报警值
///
int Alarm { get; set; }
///
/// 数据总量
///
int DataCnt { get; set; }
///
/// 数据,当 数据>数据总量, 只显示最后的数据!
///
ObservableCollection DataSource { get; set; }
///
/// 设置事件
///
event EventHandler ShowSettingDialogEvent;
#endregion
}
public enum GraphRangeType
{
///
/// 只显示 Sigma2 趋势图
///
Sigma2,
///
/// 只显示 平均值趋势图
///
Avg,
///
/// 平均值 与 Sigma2 趋势图
///
All
}
///
/// X轴显示类型
///
public enum GraphRangeXAxisType
{
///
/// 时间
///
Time,
///
/// 序号!!
///
Index
}
public struct GraphRangeData
{
public DateTime Time;
public int Avg;
public int Sigma;
public bool InCtrl;//控制中
}
}