原文:WPF 曲线图表控件(自制)(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/koloumi/article/details/77521872

    如果还有不懂的请去资源区下载控件包含所有源码

http://download.csdn.net/download/koloumi/9947692

接下来将代码上的。

界面调整部分的代码函数

    还有一个重要的函数就是控件的MyChart_SizeChanged事件。
/// <summary>
/// 尺寸改变
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MyChart_SizeChanged(object sender, SizeChangedEventArgs e)
{
Size newsize = e.NewSize;
if(!e.WidthChanged)
{
this.Width = newsize.Width;
}
if(!e.HeightChanged)
{
this.Height = newsize.Height;
}
AdjustSize();
AdjustScale();
AdjustLines();
AdjustLinesAndPoints();
}
    接下来是先看下定义的属性:
/// <summary>
/// 数据集
/// </summary>
private Dictionary<string, DrawData> _data = new Dictionary<string, DrawData>();
/// <summary>
/// 坐标原点
/// </summary>
private Point _origPoint = new Point();
/// <summary>
/// X轴上的文字
/// </summary>
private List<TextBlock> _xTip = new List<TextBlock>();
/// <summary>
/// Y轴上的文字
/// </summary>
private List<TextBlock> _yTip = new List<TextBlock>();
/// <summary>
/// X轴的区间
/// </summary>
private VectorChart2 _xLimt = new VectorChart2(double.MaxValue, double.MinValue);
/// <summary>
/// Y轴的区间
/// </summary>
private VectorChart2 _yLimt = new VectorChart2(double.MaxValue, double.MinValue);
/// <summary>
/// 每个像素映射为多少距离
/// </summary>
private VectorChart2 _everyDisForPiexl = new VectorChart2();
/// <summary>
/// 缩放中心点的偏移
/// </summary>
private VectorChart2 _centerOffect = new VectorChart2(0, 0);
/// <summary>
/// 当前线的缩放比例
/// </summary>
private Vector4 _currentLinesScale = new Vector4(1, 1, 1, 1);
/// <summary>
/// 每个刻度之间的间隔
/// </summary>
private static double _everyDis = 30;
    在这个控件上我们将每个刻度的间隔直接定死,这样有需要的时候直接修改刻度上的数值,而不用去移动刻度。如果尺寸变大只要增加刻度线,减少反之。
在控件中用到的数据结构
/// <summary>
/// 向量
/// </summary>
public struct VectorChart2
{
public double Vec1; public double Vec2; public VectorChart2(double v1, double v2)
{
this.Vec1 = v1;
this.Vec2 = v2;
}
/// <summary>
/// Point 转换VectorChart2
/// </summary>
/// <param name="p"></param>
public static implicit operator VectorChart2(Point p)
{
return new VectorChart2(p.X, p.Y);
}
/// <summary>
/// 乘法
/// </summary>
/// <param name="v1"></param>
/// <param name="ratio"></param>
/// <returns></returns>
public static VectorChart2 operator * (VectorChart2 v1, double ratio)
{
return new VectorChart2(v1.Vec1 * ratio, v1.Vec2 * ratio);
}
}
/// <summary>
/// 4维向量
/// </summary>
public struct Vector4
{
/// <summary>
/// 空
/// </summary>
public static Vector4 Empty = new Vector4() { _isEmpty = true }; public double Vec1; public double Vec2; public double Vec3; public double Vec4;
/// <summary>
/// 是否为空数据
/// </summary>
private bool _isEmpty; public Vector4(double Vec1, double Vec2, double Vec3, double Vec4)
{
this.Vec1 = Vec1;
this.Vec2 = Vec2;
this.Vec3 = Vec3;
this.Vec4 = Vec4;
_isEmpty = false;
} /// <summary>
/// 重载等号运算符
/// </summary>
/// <param name="v1"></param>
/// <param name="v2"></param>
/// <returns></returns>
public static bool operator ==(Vector4 v1, Vector4 v2)
{
if (v1.Vec1 == v2.Vec1 && v1.Vec2 == v2.Vec2 && v1.Vec3 == v2.Vec3 && v1.Vec4 == v2.Vec4 && v1._isEmpty == v2._isEmpty)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 重载
/// </summary>
/// <param name="v1"></param>
/// <param name="v2"></param>
/// <returns></returns>
public static bool operator !=(Vector4 v1, Vector4 v2)
{
return !(v1 == v2);
} public override bool Equals(object obj)
{
return base.Equals(obj);
} public override int GetHashCode()
{
return base.GetHashCode();
}
}
/// <summary>
/// 绘图数据
/// </summary>
public class DrawData : IDisposable
{
/// <summary>
/// 线
/// </summary>
public Polyline Line;
/// <summary>
/// 线的标记点
/// </summary>
public List<Ellipse> Points = new List<Ellipse>();
/// <summary>
/// 源数据集合
/// </summary>
public ObservableCollection<Point> Ps = null;
/// <summary>
/// 极值
/// </summary>
public Vector4 Vec4 = Vector4.Empty;
/// <summary>
/// 提示
/// </summary>
public LineTitle LineTitle = new LineTitle(); public DrawData()
{ } ~DrawData()
{
this.Dispose();
}
#region IDisposable Support
private bool disposedValue = false; // 要检测冗余调用 protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)。
Line = null;
Ps = null;
Points = null;
LineTitle = null;
} // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。 disposedValue = true;
}
} // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
// ~DrawData() {
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
// Dispose(false);
// } // 添加此代码以正确实现可处置模式。
public void Dispose()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(true);
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
GC.SuppressFinalize(this);
}
#endregion
}
调整曲线 刻度(直接修改)部分:

然后是调整所有绘图区的尺寸:

极值的调整 这里乘以0.15 是为了扩大上限 让初始曲线能够包括在视图中。

还有曲线刻度的添加式修改:(因为增加删除速度比较慢,所以只在有必要的时候调用这个,比如尺寸改变的时候,平时直接修改刻度即可)
/// <summary>
/// 调整刻度\网格线(删除重新添加)
/// </summary>
protected void AdjustScale()
{
//if (!IsHaveLine) return;
if (X_Axis.Width == 0 || X_Axis.Height == 0 || X_Axis.Width == double.NaN || X_Axis.Height == double.NaN) return;
//if (GridLines.Width == 0 || GridLines.Height == 0 || GridLines.Width == double.NaN || double.IsNaN(GridLines.Height)) return;
///清除X轴的刻度
if (X_Axis.Children.Count > 1)
{
X_Axis.Children.RemoveRange(1, X_Axis.Children.Count - 1);
}
///清除Y轴的刻度
if (Y_Axis.Children.Count > 1)
{
Y_Axis.Children.RemoveRange(1, Y_Axis.Children.Count - 1);
}
///清除网格线
GridLines.Children.Clear();
///清除刻度线的提示文字
_xTip.Clear();
_yTip.Clear(); ///添加X轴的
for (double i = _origPoint.X; i < X_Axis.Width; i += _everyDis)
{
Line x_scale = new Line();
x_scale.StrokeThickness = 2;
x_scale.Stroke = new SolidColorBrush(Colors.Black);
x_scale.StrokeStartLineCap = PenLineCap.Round;
x_scale.StrokeEndLineCap = PenLineCap.Round;
x_scale.Width = 4;
x_scale.Height = 20;
x_scale.X1 = 2;
x_scale.Y1 = 4;
x_scale.X2 = 2;
x_scale.Y2 = x_scale.Height;
Canvas.SetLeft(x_scale, i);
Canvas.SetTop(x_scale, 0);
X_Axis.Children.Add(x_scale);
///网格线
GridLines.Children.Add(GetGridLine(new Point(i - 2, 0), false, GridLinesArea.Vec2));
//double.IsNaN(GridLines.Height) ? GridLines.ActualHeight : GridLines.Height
///添加提示文字
TextBlock block = new TextBlock();
block.FontSize = 10;
block.Text = i.ToString();
Canvas.SetLeft(block, i);
Canvas.SetTop(block, 25);
_xTip.Add(block);
X_Axis.Children.Add(block);
}
///添加Y轴的
for (double i = _origPoint.Y; i < Y_Axis.Height; i += _everyDis)
{
Line y_scale = new Line();
y_scale.StrokeThickness = 2;
y_scale.Stroke = new SolidColorBrush(Colors.Black);
y_scale.StrokeStartLineCap = PenLineCap.Round;
y_scale.StrokeEndLineCap = PenLineCap.Round;
y_scale.Width = 20;
y_scale.Height = 4;
y_scale.X1 = 4;
y_scale.Y1 = 2;
y_scale.X2 = y_scale.Width;
y_scale.Y2 = 2;
Canvas.SetBottom(y_scale, i + 1);
Canvas.SetRight(y_scale, 2);
Y_Axis.Children.Add(y_scale);
///网格线
GridLines.Children.Add(GetGridLine(new Point(i - 2, 0), true, GridLinesArea.Vec1));
//double.IsNaN(GridLines.Width) ? GridLines.ActualWidth : GridLines.Width)
///添加提示文字
TextBlock block = new TextBlock();
block.FontSize = 10;
block.Text = i.ToString();
Canvas.SetBottom(block, i);
Canvas.SetRight(block, 10);
_yTip.Add(block);
Y_Axis.Children.Add(block);
} }
调整线和点:(主要是,缩放和拖动)

调整线和点的大小比例AdjustLinesAndPointsSize 这个函数可以删掉,后来发现没有用。

鼠标滚轮事件:
/// <summary>
/// 鼠标滚轮事件
/// </summary>
/// <param name="e"></param>
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
VectorChart2 curPDraw = (VectorChart2)e.GetPosition(Draw);
VectorChart2 curPLinesAndPoint = (VectorChart2)e.GetPosition(DrawLineAndPoint); double delta = 1;
if(e.Delta >= 120)
{
delta = 1.2;
}
else if(e.Delta <= -120)
{
delta = (double)5 / (double)6;
}
if (IsXZoom)
{
DrawLineAndPoint.Width *= delta;
curPDraw.Vec1 *= delta;
curPLinesAndPoint.Vec1 *= delta;
}
if (IsYZoom)
{
DrawLineAndPoint.Height *= delta;
curPDraw.Vec2 *= delta;
curPLinesAndPoint.Vec2 *= delta;
} _currentLinesScale.Vec4 *= delta;
//Canvas.SetLeft(DrawLineAndPoint, curPDraw.Vec1 - curPLinesAndPoint.Vec1);
//Canvas.SetBottom(DrawLineAndPoint, -(DrawArea.Vec2 - (curPLinesAndPoint.Vec2 - curPDraw.Vec2))); ///调整刻度
AdjustLines(); AdjustLinesAndPoints();
}
重置按钮:



鼠标移动的时候计算移动的差值然后调用该函数:



获取偏移量函数:

/// <summary>
/// 获取偏移量
/// </summary>
/// <returns></returns>
protected VectorChart2 GetOffectValue(VectorChart2 offectValue)
{
return new VectorChart2( -offectValue.Vec1 * _everyDisForPiexl.Vec1, offectValue.Vec2 * _everyDisForPiexl.Vec2);
}
至此全部结束 如果还有不懂的请去资源区下载控件包含所有源码

http://download.csdn.net/download/koloumi/9947692

WPF 曲线图表控件(自制)(二)的更多相关文章

  1. WPF 曲线图表控件(自制)(一)

    原文:WPF 曲线图表控件(自制)(一) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/koloumi/article/details/775092 ...

  2. WPF Visifire 图表控件

    Visifire WPF 图表控件 破解 可能用WPF生成过图表的开发人员都知道,WPF虽然本身的绘图能力强大,但如果每种图表都自己去实现一次的话可能工作量就大了, 尤其是在开发时间比较紧的情况下.这 ...

  3. C# WPF DevExpress 图表控件之柱状图

    说明:DevExpress版本是17.1.VS是2015. XAML: <!--#region 图表控件--> <dxc:ChartControl x:Name="char ...

  4. 【WPF】 OxyPlot图表控件学习

    最近在学习OxyPlot图表控件,一些基本的学习心得,在这里记录一下,方便以后进行查找.   一.引用 OxyPlot控件可以直接在VS的 " Nuget " 里面下载   选择: ...

  5. Visifire For WPF 图表控件 如何免费

    可能用WPF生成过图表的开发人员都知道,WPF虽然本身的绘图能力强大,但如果每种图表都自己去实现一次的话可能工作量就大了, 尤其是在开发时间比较紧的情况下.这时候有必要借助一种专业的图表工具. Vis ...

  6. 二十六、【开源框架】EFW框架Winform前端开发之Grid++Report报表、条形码、Excel导出、图表控件

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...

  7. echart图表控件配置入门(二)常用图表数据动态绑定

    上一节 <echart图表控件配置入门(一)>介绍了echarts图表控件的入门配置,使开发人员可以快速搭建出一个静态的图表.但是在实际开发过程这还是不够的,不可能所有的图表控件都是静态数 ...

  8. 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步

    深入理解MVC   MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...

  9. WPF 4 DataGrid 控件(进阶篇二)

    原文:WPF 4 DataGrid 控件(进阶篇二)      上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...

随机推荐

  1. ZOJ 2421 Recaman's Sequence

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1421 题目大意: 定义a^m为 a^m = a^(m-1) - m  如果a^ ...

  2. 动态布局Cell的高度

    1 自定义Cell, 在Cell的构造方法里面添加好所有的子控件 2 3 2 在HeightForRowAtIndexPath方法中返回每一行Cell对应的高度 4 5 3 在Cell的layoutS ...

  3. 20、RTC驱动程序

    drivers\rtc\rtc-s3c.c s3c_rtc_init platform_driver_register s3c_rtc_probe rtc_device_register(" ...

  4. [TypeStyle] Add responsive styles using TypeStyle Media Queries

    Media queries are very important for designs that you want to work on both mobile and desktop browse ...

  5. hdu 4406 费用流

    这题问题就是当前时刻究竟选择哪门课程,易知选择是和分数有关的,而且是一个变化的权值,所以能够用拆点的方式,把从基础分到100分都拆成点.但若这样拆点的话,跑费用流时就必须保证顺序.这样就麻烦了..观察 ...

  6. angular表单的使用实例

    原文 https://www.jianshu.com/p/da1fd5396798 大纲 1.模板驱动表单的创建 2.响应式表单的创建 3.模板驱动型表单的自定义指令 4.响应式表单的自定义指令 5. ...

  7. POJ 1287 Networking (ZOJ 1372) MST

    http://poj.org/problem?id=1287 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=372 和上次那题差 ...

  8. Windows Phone 8.1 数据处理

    Windows Phone 8.1 应用的数据存储位置包括: Installation Folder ApplicationData Credential Locker Known Folders S ...

  9. Redis使用文档一

    1 Redis概述 1.1前言 Redis是一个开源.支持网络.基于内存亦可持久化的日志型.键值对存储数据库.使用ANSI C编写.并提供多种语言的API. 其开发由VMware主持,是最流行的键值对 ...

  10. Android JNI编程(八)——体验AS2.2.2编写Jni程序、Java调C、C调Java函数、将C代码中的Log打印至Logcat

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 不得不说在AS2.2以上的版本进行开发就一个字——爽,在2.0上使用jni出 ...