using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
/*******************************************************************************
*
* 文件名:UserCurve.cs
* 程序功能:显示曲线信息,包含了曲线,坐标轴,鼠标移动信息
*
* 创建人:Richard.Hu
* 时间:2018年1月21日 18:36:08
*
*******************************************************************************/
namespace HslCommunication.Controls
{
///
/// 曲线控件对象
///
///
/// 详细参照如下的博客:
///
public partial class UserCurve : UserControl
{
#region Constructor
///
/// 实例化一个曲线显示的控件
///
public UserCurve( )
{
InitializeComponent( );
DoubleBuffered = true;
random = new Random( );
data_list = new Dictionary( );
auxiliary_lines = new List( );
format_left = new StringFormat
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Near
};
format_right = new StringFormat
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Far,
};
format_center = new StringFormat
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center,
};
font_size9 = new Font( "宋体", 9 );
font_size12 = new Font( "宋体", 12 );
InitializationColor( );
pen_dash = new Pen( color_deep );
pen_dash.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
pen_dash.DashPattern = new float[] { 5, 5 };
}
#endregion
#region Const Data
private const int value_count_max = 2048; // 缓存的数据的最大量
#endregion
#region Private Member
private float value_max_left = 100; // 左坐标的最大值
private float value_min_left = 0; // 左坐标的最小值
private float value_max_right = 100; // 右坐标的最大值
private float value_min_right = 0; // 右坐标的最小值
private int value_Segment = 5; // 纵轴的片段分割
private bool value_IsAbscissaStrech = false; // 指示横坐标是否填充满整个坐标系
private int value_StrechDataCountMax = 300; // 拉伸模式下的最大数据量
private bool value_IsRenderDashLine = true; // 是否显示虚线的信息
private bool value_IsRenderAbscissaText = false; // 指示是否显示横轴的文本信息
private string textFormat = "HH:mm"; // 时间文本的信息
private int value_IntervalAbscissaText = 100; // 指示显示横轴文本的间隔数据
private Random random = null; // 获取随机颜色使用
private string value_title = ""; // 图表的标题
private int leftRight = 50;
private int upDowm = 25;
#endregion
#region Data Member
Dictionary data_list = null; // 等待显示的实际数据
private string[] data_text = null; // 等待显示的横轴信息
#endregion
#region Public Properties
///
/// 获取或设置图形的纵坐标的最大值,该值必须大于最小值
///
[Category( "外观" )]
[Description( "获取或设置图形的左纵坐标的最大值,该值必须大于最小值" )]
[Browsable( true )]
[DefaultValue( 100f )]
public float ValueMaxLeft
{
get { return value_max_left; }
set
{
if (value > value_min_left)
{
value_max_left = value;
Invalidate( );
}
}
}
///
/// 获取或设置图形的纵坐标的最小值,该值必须小于最大值
///
[Category( "外观" )]
[Description( "获取或设置图形的左纵坐标的最小值,该值必须小于最大值" )]
[Browsable( true )]
[DefaultValue( 0f )]
public float ValueMinLeft
{
get { return value_min_left; }
set
{
if (value < value_max_left)
{
value_min_left = value;
Invalidate( );
}
}
}
///
/// 获取或设置图形的纵坐标的最大值,该值必须大于最小值
///
[Category( "外观" )]
[Description( "获取或设置图形的右纵坐标的最大值,该值必须大于最小值" )]
[Browsable( true )]
[DefaultValue( 100f )]
public float ValueMaxRight
{
get { return value_max_right; }
set
{
if (value > value_min_right)
{
value_max_right = value;
Invalidate( );
}
}
}
///
/// 获取或设置图形的纵坐标的最小值,该值必须小于最大值
///
[Category( "外观" )]
[Description( "获取或设置图形的右纵坐标的最小值,该值必须小于最大值" )]
[Browsable( true )]
[DefaultValue( 0f )]
public float ValueMinRight
{
get { return value_min_right; }
set
{
if (value < value_max_right)
{
value_min_right = value;
Invalidate( );
}
}
}
///
/// 获取或设置图形的纵轴分段数
///
[Category( "外观" )]
[Description( "获取或设置图形的纵轴分段数" )]
[Browsable( true )]
[DefaultValue( 5 )]
public int ValueSegment
{
get { return value_Segment; }
set
{
value_Segment = value;
Invalidate( );
}
}
///
/// 获取或设置所有的数据是否强制在一个界面里显示
///
[Category( "外观" )]
[Description( "获取或设置所有的数据是否强制在一个界面里显示" )]
[Browsable( true )]
[DefaultValue( false )]
public bool IsAbscissaStrech
{
get { return value_IsAbscissaStrech; }
set
{
value_IsAbscissaStrech = value;
Invalidate( );
}
}
///
/// 获取或设置拉伸模式下的最大数据量
///
[Category( "外观" )]
[Description( "获取或设置拉伸模式下的最大数据量" )]
[Browsable( true )]
[DefaultValue( 300 )]
public int StrechDataCountMax
{
get { return value_StrechDataCountMax; }
set
{
value_StrechDataCountMax = value;
Invalidate( );
}
}
///
/// 获取或设置虚线是否进行显示
///
[Category( "外观" )]
[Description( "获取或设置虚线是否进行显示" )]
[Browsable( true )]
[DefaultValue( true )]
public bool IsRenderDashLine
{
get { return value_IsRenderDashLine; }
set
{
value_IsRenderDashLine = value;
Invalidate( );
}
}
///
/// 获取或设置坐标轴及相关信息文本的颜色
///
[Category( "外观" )]
[Description( "获取或设置坐标轴及相关信息文本的颜色" )]
[Browsable( true )]
[DefaultValue( typeof( Color ), "DimGray" )]
public Color ColorLinesAndText
{
get { return color_deep; }
set
{
color_deep = value;
InitializationColor( );
Invalidate( );
}
}
///
/// 获取或设置虚线的颜色
///
[Category( "外观" )]
[Description( "获取或设置虚线的颜色" )]
[Browsable( true )]
[DefaultValue( typeof( Color ), "Gray" )]
public Color ColorDashLines
{
get { return color_dash; }
set
{
color_dash = value;
pen_dash?.Dispose( );
pen_dash = new Pen( color_dash );
pen_dash.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
pen_dash.DashPattern = new float[] { 5, 5 };
Invalidate( );
}
}
///
/// 获取或设置纵向虚线的分隔情况,单位为多少个数据
///
[Category( "外观" )]
[Description( "获取或设置纵向虚线的分隔情况,单位为多少个数据" )]
[Browsable( true )]
[DefaultValue( 100 )]
public int IntervalAbscissaText
{
get { return value_IntervalAbscissaText; }
set
{
value_IntervalAbscissaText = value;
Invalidate( );
}
}
///
/// 获取或设置实时数据新增时文本相对应于时间的格式化字符串,默认HH:mm
///
[Category( "外观" )]
[Description( "获取或设置实时数据新增时文本相对应于时间的格式化字符串,默认HH:mm" )]
[Browsable( true )]
[DefaultValue( "HH:mm" )]
public string TextAddFormat
{
get { return textFormat; }
set { textFormat = value; Invalidate(); }
}
///
/// 获取或设置图标的标题信息
///
[Category("外观")]
[Description("获取或设置图标的标题信息")]
[Browsable(true)]
[DefaultValue("")]
public string Title
{
get { return value_title; }
set { value_title = value; Invalidate(); }
}
private void InitializationColor( )
{
pen_normal?.Dispose( );
brush_deep?.Dispose( );
pen_normal = new Pen( color_deep );
brush_deep = new SolidBrush( color_deep );
}
#endregion
#region Public Method
///
/// 设置曲线的横坐标文本,适用于显示一些固定的曲线信息
///
/// 应该和曲线的点数一致
public void SetCurveText(string[] descriptions)
{
data_text = descriptions;
// 重绘图形
Invalidate( );
}
///
/// 新增或修改一条指定关键字的左参考系曲线数据,需要指定数据,颜色随机,没有数据上限,线条宽度为1
///
/// 曲线关键字
/// 曲线的具体数据
public void SetLeftCurve( string key, float[] data )
{
SetLeftCurve( key, data, Color.FromArgb( random.Next( 256 ), random.Next( 256 ), random.Next( 256 ) ) );
}
///
/// 新增或修改一条指定关键字的左参考系曲线数据,需要指定数据,颜色,没有数据上限,线条宽度为1
///
/// 曲线关键字
///
///
public void SetLeftCurve( string key, float[] data, Color lineColor )
{
SetCurve( key, true, data, lineColor, 1f );
}
///
/// 新增或修改一条指定关键字的右参考系曲线数据,需要指定数据,颜色随机,没有数据上限,线条宽度为1
///
/// 曲线关键字
///
public void SetRightCurve( string key, float[] data )
{
SetRightCurve( key, data, Color.FromArgb( random.Next( 256 ), random.Next( 256 ), random.Next( 256 ) ) );
}
///
/// 新增或修改一条指定关键字的右参考系曲线数据,需要指定数据,颜色,没有数据上限,线条宽度为1
///
/// 曲线关键字
///
///
public void SetRightCurve( string key, float[] data, Color lineColor )
{
SetCurve( key, false, data, lineColor, 1f );
}
///
/// 新增或修改一条指定关键字的曲线数据,需要指定参考系及数据,颜色,线条宽度
///
/// 曲线关键字
/// 是否以左侧坐标轴为参照系
/// 数据
/// 线条颜色
/// 线条宽度
public void SetCurve( string key, bool isLeft, float[] data, Color lineColor, float thickness )
{
if (data_list.ContainsKey( key ))
{
if (data == null) data = new float[] { };
data_list[key].Data = data;
}
else
{
if (data == null) data = new float[] { };
data_list.Add( key, new HslCurveItem( )
{
Data = data,
LineThickness = thickness,
LineColor = lineColor,
IsLeftFrame = isLeft,
} );
if (data_text == null) data_text = new string[data.Length];
}
// 重绘图形
Invalidate( );
}
///
/// 移除指定关键字的曲线
///
/// 曲线关键字
public void RemoveCurve( string key )
{
if (data_list.ContainsKey( key ))
{
data_list.Remove( key );
}
// 重绘图形
Invalidate( );
}
///
/// 移除指定关键字的曲线
///
public void RemoveAllCurve( )
{
int count = data_list.Count;
data_list.Clear( );
// 重绘图形
if (count > 0) Invalidate( );
}
// ======================================================================================================
///
/// 新增指定关键字曲线的一个数据,注意该关键字的曲线必须存在,否则无效
///
/// 新增曲线的关键字
///
/// 是否刷新界面
private void AddCurveData( string key, float[] values, bool isUpdateUI )
{
if (values?.Length < 1) return; // 没有传入数据
if (data_list.ContainsKey( key ))
{
HslCurveItem curve = data_list[key];
if (curve.Data != null)
{
if (value_IsAbscissaStrech)
{
// 填充玩整个图形的情况
BasicFramework.SoftBasic.AddArrayData( ref curve.Data, values, value_StrechDataCountMax );
}
else
{
// 指定点的情况,必然存在最大值情况
BasicFramework.SoftBasic.AddArrayData( ref curve.Data, values, value_count_max );
}
if (isUpdateUI) Invalidate( );
}
}
}
// 新增曲线的时间节点
private void AddCurveTime( int count )
{
if (data_text == null) return;
string[] values = new string[count];
for (int i = 0; i < values.Length; i++)
{
values[i] = DateTime.Now.ToString( textFormat );
}
if(value_IsAbscissaStrech)
{
BasicFramework.SoftBasic.AddArrayData( ref data_text, values, value_StrechDataCountMax );
}
else
{
BasicFramework.SoftBasic.AddArrayData( ref data_text, values, value_count_max );
}
}
///
/// 新增指定关键字曲线的一个数据,注意该关键字的曲线必须存在,否则无效
///
/// 曲线的关键字
/// 数据值
public void AddCurveData( string key, float value )
{
AddCurveData( key, new float[] { value } );
}
///
/// 新增指定关键字曲线的一组数据,注意该关键字的曲线必须存在,否则无效
///
/// 曲线的关键字
/// 数组值
public void AddCurveData( string key, float[] values )
{
AddCurveData( key, values, false );
if (values?.Length > 0)
{
AddCurveTime( values.Length );
}
Invalidate( );
}
///
/// 新增指定关键字数组曲线的一组数据,注意该关键字的曲线必须存在,否则无效,一个数据对应一个数组
///
/// 曲线的关键字数组
/// 数组值
public void AddCurveData( string[] keys, float[] values )
{
if (keys == null) throw new ArgumentNullException( "keys" );
if (values == null) throw new ArgumentNullException( "values" );
if (keys.Length != values.Length) throw new Exception( "两个参数的数组长度不一致。" );
for (int i = 0; i < keys.Length; i++)
{
AddCurveData( keys[i], new float[] { values[i] }, false );
}
AddCurveTime( 1 );
// 统一的更新显示
Invalidate( );
}
#endregion
#region Auxiliary Line
// 辅助线的信息,允许自定义辅助线信息,来标注特殊的线条
private List auxiliary_lines; // 所有辅助线的列表
///
/// 新增一条左侧的辅助线,使用默认的文本颜色
///
/// 数据值
public void AddLeftAuxiliary( float value )
{
AddLeftAuxiliary( value, ColorLinesAndText );
}
///
/// 新增一条左侧的辅助线,使用指定的颜色
///
/// 数据值
/// 线条颜色
public void AddLeftAuxiliary( float value, Color lineColor )
{
AddLeftAuxiliary( value, lineColor, 1f );
}
///
/// 新增一条左侧的辅助线
///
/// 数据值
/// 线条颜色
/// 线条宽度
public void AddLeftAuxiliary( float value, Color lineColor, float lineThickness )
{
AddAuxiliary( value, lineColor, lineThickness, true );
}
///
/// 新增一条右侧的辅助线,使用默认的文本颜色
///
/// 数据值
public void AddRightAuxiliary( float value )
{
AddRightAuxiliary( value, ColorLinesAndText );
}
///
/// 新增一条右侧的辅助线,使用指定的颜色
///
/// 数据值
/// 线条颜色
public void AddRightAuxiliary( float value, Color lineColor )
{
AddRightAuxiliary( value, lineColor, 1f );
}
///
/// 新增一条右侧的辅助线
///
/// 数据值
/// 线条颜色
/// 线条宽度
public void AddRightAuxiliary( float value, Color lineColor, float lineThickness )
{
AddAuxiliary( value, lineColor, lineThickness, false );
}
private void AddAuxiliary( float value, Color lineColor, float lineThickness, bool isLeft )
{
auxiliary_lines.Add( new AuxiliaryLine( )
{
Value = value,
LineColor = lineColor,
PenDash = new Pen( lineColor )
{
DashStyle = System.Drawing.Drawing2D.DashStyle.Custom,
DashPattern = new float[] { 5, 5 }
},
IsLeftFrame = isLeft,
LineThickness = lineThickness,
LineTextBrush = new SolidBrush( lineColor ),
} );
Invalidate( );
}
///
/// 移除所有的指定值的辅助曲线,包括左边的和右边的
///
///
public void RemoveAuxiliary( float value )
{
int removeCount = 0;
for (int i = auxiliary_lines.Count - 1; i >= 0; i--)
{
if (auxiliary_lines[i].Value == value)
{
auxiliary_lines[i].Dispose( );
auxiliary_lines.RemoveAt( i );
removeCount++;
}
}
if (removeCount > 0) Invalidate( );
}
///
/// 移除所有的辅助线
///
public void RemoveAllAuxiliary( )
{
int removeCount = auxiliary_lines.Count;
auxiliary_lines.Clear( );
if (removeCount > 0) Invalidate( );
}
#endregion
#region Private Method
#endregion
#region Core Paint
private Font font_size9 = null;
private Font font_size12 = null;
private Brush brush_deep = null; // 文本的颜色
private Pen pen_normal = null; // 绘制极轴和分段符的坐标线
private Pen pen_dash = null; // 绘制图形的虚线
private Color color_normal = Color.DeepPink; // 文本的颜色
private Color color_deep = Color.DimGray; // 坐标轴及数字文本的信息
private Color color_dash = Color.Gray; // 虚线的颜色
private StringFormat format_left = null; // 靠左对齐的文本
private StringFormat format_right = null; // 靠右对齐的文本
private StringFormat format_center = null; // 中间对齐的文本
private void UserCurve_Paint( object sender, PaintEventArgs e )
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
if (BackColor != Color.Transparent)
{
g.Clear( BackColor );
}
int width_totle = Width;
int heigh_totle = Height;
if (width_totle < 120 || heigh_totle < 60) return;
// 绘制极轴
g.DrawLines( pen_normal, new Point[] {
new Point(leftRight-1, upDowm - 8),
new Point(leftRight-1, heigh_totle - upDowm),
new Point(width_totle - leftRight, heigh_totle - upDowm),
new Point(width_totle - leftRight, upDowm - 8)
} );
// 绘制图表的标题
if(!string.IsNullOrEmpty(value_title))
{
g.DrawString(value_title, font_size9, brush_deep, new Rectangle(0, 0, width_totle - 1, 20), format_center);
}
// 绘制倒三角
BasicFramework.SoftPainting.PaintTriangle( g, brush_deep, new Point( leftRight - 1, upDowm - 8 ), 4, BasicFramework.GraphDirection.Upward );
BasicFramework.SoftPainting.PaintTriangle( g, brush_deep, new Point( width_totle - leftRight, upDowm - 8 ), 4, BasicFramework.GraphDirection.Upward );
// 计算所有辅助线的实际值
for (int i = 0; i < auxiliary_lines.Count; i++)
{
if (auxiliary_lines[i].IsLeftFrame)
{
auxiliary_lines[i].PaintValue = BasicFramework.SoftPainting.ComputePaintLocationY( value_max_left, value_min_left, (heigh_totle - upDowm - upDowm), auxiliary_lines[i].Value ) + upDowm;
}
else
{
auxiliary_lines[i].PaintValue = BasicFramework.SoftPainting.ComputePaintLocationY( value_max_right, value_min_right, (heigh_totle - upDowm - upDowm), auxiliary_lines[i].Value ) + upDowm;
}
}
// 绘制刻度线,以及刻度文本
for (int i = 0; i <= value_Segment; i++)
{
float valueTmpLeft = i * (value_max_left - value_min_left) / value_Segment + value_min_left;
float paintTmp = BasicFramework.SoftPainting.ComputePaintLocationY( value_max_left, value_min_left, (heigh_totle - upDowm - upDowm), valueTmpLeft ) + upDowm;
if (IsNeedPaintDash( paintTmp ))
{
// 左坐标轴
g.DrawLine( pen_normal, leftRight - 4, paintTmp, leftRight - 1, paintTmp );
RectangleF rectTmp = new RectangleF( 0, paintTmp - 9, leftRight - 4, 20 );
g.DrawString( valueTmpLeft.ToString( ), font_size9, brush_deep, rectTmp, format_right );
// 右坐标轴
float valueTmpRight = i * (value_max_right - value_min_right) / value_Segment + value_min_right;
g.DrawLine( pen_normal, width_totle - leftRight + 1, paintTmp, width_totle - leftRight + 4, paintTmp );
rectTmp.Location = new PointF( width_totle - leftRight + 4, paintTmp - 9 );
g.DrawString( valueTmpRight.ToString( ), font_size9, brush_deep, rectTmp, format_left );
if (i > 0 && value_IsRenderDashLine) g.DrawLine( pen_dash, leftRight, paintTmp, width_totle - leftRight, paintTmp );
}
}
// 绘制纵向虚线信息
if (value_IsRenderDashLine)
{
if (value_IsAbscissaStrech)
{
// 拉伸模式下,因为错位是均匀的,所以根据数据来显示
float offect = (width_totle - leftRight * 2) * 1.0f / (value_StrechDataCountMax - 1);
int dataCount = CalculateDataCountByOffect( offect );
for (int i = 0; i < value_StrechDataCountMax; i += dataCount)
{
if (i > 0 && i < value_StrechDataCountMax - 1)
{
g.DrawLine( pen_dash, i * offect + leftRight, upDowm, i * offect + leftRight, heigh_totle - upDowm - 1 );
}
if (data_text != null)
{
if (i < data_text.Length && ((i * offect + leftRight) < (data_text.Length - 1) * offect + leftRight -40 ))
{
Rectangle rec = new Rectangle( (int)(i * offect), heigh_totle - upDowm + 1, 100, upDowm );
g.DrawString( data_text[i], font_size9, brush_deep, rec, format_center );
}
}
}
if (data_text?.Length > 1)
{
if (data_text.Length < value_StrechDataCountMax)
{
// 绘制最前端的虚线
g.DrawLine( pen_dash, (data_text.Length - 1) * offect + leftRight, upDowm, (data_text.Length - 1) * offect + leftRight, heigh_totle - upDowm - 1 );
}
Rectangle rec = new Rectangle( (int)((data_text.Length - 1) * offect + leftRight) - leftRight, heigh_totle - upDowm + 1, 100, upDowm );
g.DrawString( data_text[data_text.Length - 1], font_size9, brush_deep, rec, format_center );
}
}
else
{
int countTmp = width_totle - 2 * leftRight + 1;
// 普通模式下绘制图形
for (int i = leftRight; i < width_totle - leftRight; i += value_IntervalAbscissaText)
{
if (i != leftRight)
{
g.DrawLine( pen_dash, i, upDowm, i, heigh_totle - upDowm - 1 );
}
if (data_text != null)
{
int right_limit = countTmp > data_text.Length ? data_text.Length : countTmp;
if ((i - leftRight) < data_text.Length)
{
if ((right_limit - (i - leftRight)) > 40)
{
// 点数大于1的时候才绘制
if (data_text.Length <= countTmp)
{
Rectangle rec = new Rectangle( i - leftRight, heigh_totle - upDowm + 1, 100, upDowm );
g.DrawString( data_text[i - leftRight], font_size9, brush_deep, rec, format_center );
}
else
{
Rectangle rec = new Rectangle( i - leftRight, heigh_totle - upDowm + 1, 100, upDowm );
g.DrawString( data_text[i - leftRight + data_text.Length - countTmp], font_size9, brush_deep, rec, format_center );
}
}
}
}
}
if (data_text?.Length > 1)
{
if (data_text.Length < countTmp)
{
// 绘制最前端的虚线
g.DrawLine( pen_dash, (data_text.Length + leftRight - 1), upDowm, (data_text.Length + leftRight - 1), heigh_totle - upDowm - 1 );
Rectangle rec = new Rectangle( (data_text.Length + leftRight - 1) - leftRight, heigh_totle - upDowm + 1, 100, upDowm );
g.DrawString( data_text[data_text.Length - 1], font_size9, brush_deep, rec, format_center );
}
else
{
Rectangle rec = new Rectangle( width_totle - leftRight - leftRight, heigh_totle - upDowm + 1, 100, upDowm );
g.DrawString( data_text[data_text.Length - 1], font_size9, brush_deep, rec, format_center );
}
}
}
}
// 绘制辅助线信息
for (int i = 0; i < auxiliary_lines.Count; i++)
{
if (auxiliary_lines[i].IsLeftFrame)
{
// 左坐标轴
g.DrawLine( auxiliary_lines[i].PenDash, leftRight - 4, auxiliary_lines[i].PaintValue, leftRight - 1, auxiliary_lines[i].PaintValue );
RectangleF rectTmp = new RectangleF( 0, auxiliary_lines[i].PaintValue - 9, leftRight - 4, 20 );
g.DrawString( auxiliary_lines[i].Value.ToString( ), font_size9, auxiliary_lines[i].LineTextBrush, rectTmp, format_right );
}
else
{
g.DrawLine( auxiliary_lines[i].PenDash, width_totle - leftRight + 1, auxiliary_lines[i].PaintValue, width_totle - leftRight + 4, auxiliary_lines[i].PaintValue );
RectangleF rectTmp = new RectangleF( width_totle - leftRight + 4, auxiliary_lines[i].PaintValue - 9, leftRight - 4, 20 );
g.DrawString( auxiliary_lines[i].Value.ToString( ), font_size9, auxiliary_lines[i].LineTextBrush, rectTmp, format_left );
}
g.DrawLine( auxiliary_lines[i].PenDash, leftRight, auxiliary_lines[i].PaintValue, width_totle - leftRight, auxiliary_lines[i].PaintValue );
}
// 绘制线条
if (value_IsAbscissaStrech)
{
// 横坐标充满图形
foreach (var line in data_list.Values)
{
if (line.Data?.Length > 1)
{
float offect = (width_totle - leftRight * 2) * 1.0f / (value_StrechDataCountMax - 1);
// 点数大于1的时候才绘制
PointF[] points = new PointF[line.Data.Length];
for (int i = 0; i < line.Data.Length; i++)
{
points[i].X = leftRight + i * offect;
points[i].Y = BasicFramework.SoftPainting.ComputePaintLocationY(
line.IsLeftFrame ? value_max_left : value_max_right,
line.IsLeftFrame ? value_min_left : value_min_right,
(heigh_totle - upDowm - upDowm), line.Data[i] ) + upDowm;
}
using (Pen penTmp = new Pen( line.LineColor, line.LineThickness ))
{
g.DrawLines( penTmp, points );
}
}
}
}
else
{
// 横坐标对应图形
foreach (var line in data_list.Values)
{
if (line.Data?.Length > 1)
{
int countTmp = width_totle - 2 * leftRight + 1;
PointF[] points;
// 点数大于1的时候才绘制
if (line.Data.Length <= countTmp)
{
points = new PointF[line.Data.Length];
for (int i = 0; i < line.Data.Length; i++)
{
points[i].X = leftRight + i;
points[i].Y = BasicFramework.SoftPainting.ComputePaintLocationY(
line.IsLeftFrame ? value_max_left : value_max_right,
line.IsLeftFrame ? value_min_left : value_min_right,
(heigh_totle - upDowm - upDowm), line.Data[i] ) + upDowm;
}
}
else
{
points = new PointF[countTmp];
for (int i = 0; i < points.Length; i++)
{
points[i].X = leftRight + i;
points[i].Y = BasicFramework.SoftPainting.ComputePaintLocationY(
line.IsLeftFrame ? value_max_left : value_max_right,
line.IsLeftFrame ? value_min_left : value_min_right,
(heigh_totle - upDowm - upDowm), line.Data[i + line.Data.Length - countTmp] ) + upDowm;
}
}
using (Pen penTmp = new Pen( line.LineColor, line.LineThickness ))
{
g.DrawLines( penTmp, points );
}
}
}
}
}
private bool IsNeedPaintDash( float paintValue )
{
// 遍历所有的数据组
for (int i = 0; i < auxiliary_lines.Count; i++)
{
if (Math.Abs( auxiliary_lines[i].PaintValue - paintValue ) < font_size9.Height)
{
// 与辅助线冲突,不需要绘制
return false;
}
}
// 需要绘制虚线
return true;
}
private int CalculateDataCountByOffect(float offect)
{
if (offect > 40) return 1;
offect = 40f / offect;
return (int)Math.Ceiling( offect );
}
#endregion
#region Size Changed
private void UserCurve_SizeChanged( object sender, EventArgs e )
{
Invalidate( );
}
#endregion
}
///
/// 曲线数据对象
///
internal class HslCurveItem
{
///
/// 实例化一个对象
///
public HslCurveItem( )
{
LineThickness = 1.0f;
IsLeftFrame = true;
}
///
/// 数据
///
public float[] Data = null;
///
/// 线条的宽度
///
public float LineThickness { get; set; }
///
/// 曲线颜色
///
public Color LineColor { get; set; }
///
/// 是否左侧参考系,True为左侧,False为右侧
///
public bool IsLeftFrame { get; set; }
}
///
/// 辅助线对象
///
internal class AuxiliaryLine : IDisposable
{
///
/// 实际的数据值
///
public float Value { get; set; }
///
/// 实际的数据绘制
///
public float PaintValue { get; set; }
///
/// 辅助线的颜色
///
public Color LineColor { get; set; }
///
/// 辅助线的画笔资源
///
public Pen PenDash { get; set; }
///
/// 辅助线的宽度
///
public float LineThickness { get; set; }
///
/// 辅助线文本的画刷
///
public Brush LineTextBrush { get; set; }
///
/// 是否左侧参考系,True为左侧,False为右侧
///
public bool IsLeftFrame { get; set; }
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用
protected virtual void Dispose( bool disposing )
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)。
PenDash?.Dispose( );
LineTextBrush.Dispose( );
}
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。
disposedValue = true;
}
}
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
// ~AuxiliaryLine() {
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
// Dispose(false);
// }
// 添加此代码以正确实现可处置模式。
///
/// 释放内存信息
///
public void Dispose( )
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose( true );
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
// GC.SuppressFinalize(this);
}
#endregion
}
}