WPF 自定义的图表(适用大量数据绘制)
在WPF中绘制图表比较简单,有很多的第三方控件,但是在绘制大量数据的时候,就显得有些吃力,即便是自己用StreamGeometry画也达不到理想的效果,要达到绘制大量数据而不会顿卡现象,只有一个途径,就是首先在内存中绘制好所有的图形,再一次性加载(或者说绘制)到界面控件Canvas或Grid中。
废话不多说,直接看效果吧
选中放大效果
源代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
namespace Zero_Gjy.UserControls
{
public class DrawingCanvas : Canvas
{
private List<Visual> visuals = new List<Visual>();
public enum MouseMode
{
ZOOM,
VIEW
}
public MouseMode mMode = MouseMode.VIEW;
public DrawingCanvas()
{
this.Background = Brushes.Transparent;
this.PreviewMouseLeftButtonDown += DrawingCanvas_MouseLeftButtonDown;
this.PreviewMouseLeftButtonUp += DrawingCanvas_MouseLeftButtonUp;
this.MouseMove += DrawingCanvas_MouseMove;
this.MouseLeave += DrawingCanvas_MouseLeave;
}
private void DrawingCanvas_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
if(mMode == MouseMode.VIEW && textVisual !=null)
{
this.RemoveVisual(textVisual);
this.InvalidateVisual();
}
}
private void DrawingCanvas_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
isMouseDown = false;
mMode = MouseMode.VIEW;
endup = e.GetPosition(this).X;
if (endup < YZero)
endup = YZero;
if (endup > canvasWidth)
endup = canvasWidth;
//重画 选中区域
double step = (canvasWidth - YZero) / sData.Count;
if (isMouseMoved && Math.Abs(endup - startDown) > step)
{
int startIndex = 0;
int endIndex = 0;
if (endup > startDown)
{
startIndex = (int)((startDown - YZero) / step)+1;
endIndex = (int)((endup - YZero) / step);
}
else
{
startIndex = (int)((endup - YZero) / step)+1;
endIndex = (int)((startDown - YZero) / step);
}
//暂存
DoubleCollection tempM = new DoubleCollection(mData.Count);
DoubleCollection tempS = new DoubleCollection(sData.Count);
for(int i = 0;i < mData.Count;i++)
{
tempM.Add(mData[i]);
tempS.Add(sData[i]);
}
mData.Clear();
sData.Clear();
for(int i = startIndex; i <= endIndex;i++)
{
mData.Add(tempM[i]);
sData.Add(tempS[i]);
}
this.Polyline();
this.RemoveVisual(rectVisual);
this.InvalidateVisual();
}
isMouseMoved = false;
}
double preMoved = YZero;
private void DrawingCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
double positionX = e.GetPosition(this).X;
if(mMode == MouseMode.VIEW)
{
Console.WriteLine("Moving" + positionX);
if (positionX > YZero && positionX < canvasWidth && Math.Abs(positionX - preMoved) >= (canvasWidth-YZero)/mData.Count)
{
Console.WriteLine("" + positionX);
this.PolyText(positionX);
//this.InvalidateVisual();
}
}
else if (isMouseDown && startDown > YZero && startDown < canvasWidth)
{
isMouseMoved = true;
this.PolyRect(startDown, positionX);
this.InvalidateVisual();
}
}
private bool isMouseDown = false;
private bool isMouseMoved = false;
private double startDown;
private double endup;
private int clickTimes = 0;
private void DrawingCanvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
isMouseDown = true;
mMode = MouseMode.ZOOM;
startDown = e.GetPosition(this).X;
if (textVisual != null)
this.RemoveVisual(textVisual);
//双击
clickTimes ++;
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 300);
timer.Tick += (s, e1) => { timer.IsEnabled = false; clickTimes = 0; };
timer.IsEnabled = true;
if (clickTimes % 2 == 0)
{
Console.WriteLine("double");
timer.IsEnabled = false;
clickTimes = 0;
mData.Clear();
sData.Clear();
for (int i = 0 ; i < rtData.Count; i++)
{
mData.Add(rtData[i]);
sData.Add(thData[i]);
}
this.Polyline();
this.InvalidateVisual();
}
}
//获取Visual的个数
protected override int VisualChildrenCount
{
get { return visuals.Count; }
}
//获取Visual
protected override Visual GetVisualChild(int index)
{
return visuals[index];
}
//添加Visual
public void AddVisual(Visual visual)
{
visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
//删除Visual
public void RemoveVisual(Visual visual)
{
visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
//命中测试
public DrawingVisual GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
return hitResult.VisualHit as DrawingVisual;
}
private const double YZero = 50;
private const double YMargin = 10;
private const double YLabelLen = 5;
private double yHeight;
private Brush line1Color = Brushes.Black;
private Brush labelColor = Brushes.Black;
private Brush axisColor = Brushes.Black;
private Brush line2Color = Brushes.Black;
private double thinkness = 1;
private double yLabelMax = 100;
private double yLabelMin = -100;
private double canvasWidth = 0;
private const int yLinesCount = 12;
DoubleCollection rtData;
DoubleCollection thData;
DoubleCollection mData;
DoubleCollection sData;
//使用DrawVisual画Polyline
DrawingVisual lineVisual;
public DrawingVisual Polyline()
{
if (lineVisual != null)
this.RemoveVisual(lineVisual);
lineVisual = new DrawingVisual();
DrawingContext dc = lineVisual.RenderOpen();
Pen penAxis = new Pen(AxisColor,Thinkness);
penAxis.Freeze();
//画Y轴
dc.DrawLine(penAxis, new Point(YZero,YMargin),new Point(YZero,YHeight-YMargin));
dc.DrawLine(penAxis, new Point(YZero - YLabelLen, YMargin),new Point(YZero,YMargin));
dc.DrawLine(penAxis, new Point(YZero - YLabelLen, YHeight/2), new Point(YZero, YHeight / 2));
dc.DrawLine(penAxis, new Point(YZero - YLabelLen, YHeight-YMargin), new Point(YZero, YHeight - YMargin));
FormattedText ft1 = new FormattedText(yLabelMax.ToString(),new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"),10,Brushes.Black);
dc.DrawText(ft1, new Point(YZero - YLabelLen - ft1.Width, YMargin - ft1.Height/2));
FormattedText ft2 = new FormattedText(((yLabelMax + yLabelMin) / 2).ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
dc.DrawText(ft2, new Point(YZero - YLabelLen - ft2.Width, YHeight / 2 - ft2.Height / 2));
FormattedText ft3 = new FormattedText(yLabelMin.ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
dc.DrawText(ft3, new Point(YZero - YLabelLen - ft3.Width, YHeight - YMargin - ft3.Height / 2));
//画线
Pen linePen1 = new Pen(Line1Color, Thinkness);
linePen1.Freeze();
Pen linePen2 = new Pen(Line2Color, Thinkness);
linePen2.Freeze();
double ratio = (yLabelMax - yLabelMin) / (YHeight - 2 * YMargin);
for (int i = 0; i < mData.Count - 1; i++)
{
//将数值转换成位置
//理论值
Point p3 = new Point(YZero + i * (canvasWidth - YZero) / sData.Count, YMargin + (yLabelMax - sData[i]) / ratio);
Point p4 = new Point(YZero + (i + 1) * (canvasWidth - YZero) / sData.Count, YMargin + (yLabelMax - sData[i + 1]) / ratio);
dc.DrawLine(linePen2, p3, p4);
//实测值
Point p1 = new Point(YZero + i * (canvasWidth - YZero) / mData.Count, YMargin + (yLabelMax - mData[i]) / ratio);
Point p2 = new Point(YZero + (i+1) * (canvasWidth - YZero) / mData.Count, YMargin + (yLabelMax - mData[i + 1]) / ratio);
dc.DrawLine(linePen1, p1, p2);
}
//绘制纵向网格和x轴文本
Pen pen3 = new Pen(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#666666")),4);
pen3.DashStyle = new DashStyle(new double[] {2.5,2.5 },0);
pen3.Freeze();
double stepX = (canvasWidth - YZero) / yLinesCount;
int stepData = mData.Count / yLinesCount;
if (stepData < 1)
stepData = 1;
for (int i = 1; i < yLinesCount; i++)
{
//纵向网格
Point p1 = new Point(YZero + i * stepX, YHeight - YMargin);
Point p2 = new Point(YZero + i * stepX,YMargin);
dc.DrawLine(pen3, p1, p2);
//x轴文本
FormattedText ftX = new FormattedText((i*stepData).ToString(), new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10, Brushes.Black);
Point p3 = new Point(YZero + i * stepX - ftX.Width/2,yHeight - YMargin);
dc.DrawText(ftX, p3);
}
dc.Close();
this.AddVisual(lineVisual);
return lineVisual;
}
//绘制鼠标选择放大的矩形
DrawingVisual rectVisual;
public DrawingVisual PolyRect(double startx,double endx)
{
if (rectVisual != null)
this.RemoveVisual(rectVisual);
rectVisual = new DrawingVisual();
DrawingContext dc = rectVisual.RenderOpen();
Pen pen = new Pen(new SolidColorBrush(Color.FromArgb(100, 255, 200, 200)), 1);
dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(100, 255, 200, 200)), pen, new Rect(new Point(startx, YMargin), new Point(endx, YHeight - YMargin)));
dc.Close();
this.AddVisual(rectVisual);
return rectVisual;
}
//绘制显示选中的数值
DrawingVisual textVisual;
public void PolyText(double xPosition)
{
if (textVisual != null)
{
this.RemoveVisual(textVisual);
//textVisual = new DrawingVisual();
//this.AddVisual(textVisual);
}
textVisual = new DrawingVisual();
DrawingContext dc = textVisual.RenderOpen();
double step = (canvasWidth - YZero) / mData.Count;
int index = (int)((xPosition - YZero) / step);
double ax = YZero + index * step;
//竖线
Pen pen = new Pen(Brushes.Transparent, 3);
pen.Freeze();
FormattedText ftX = new FormattedText("里程:"+index+" 实测:"+mData[index]+" 设计:"+sData[index], new System.Globalization.CultureInfo("zh-CHS", false), FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"),15, Brushes.White);
//计算是否超出范围
if(ax + ftX.Width < canvasWidth)
{
dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(200, 0, 150, 179)), pen, new Rect(new Point(ax, YMargin), new Point(ax + ftX.Width, YMargin + ftX.Height)));
dc.DrawText(ftX, new Point(ax, YMargin));
}
else
{
dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(200, 0, 150, 179)), pen, new Rect(new Point(ax-ftX.Width, YMargin), new Point(ax, YMargin + ftX.Height)));
dc.DrawText(ftX, new Point(ax-ftX.Width, YMargin));
}
Pen penLine = new Pen(new SolidColorBrush(Color.FromArgb(200, 0, 150, 179)), 3);
penLine.DashStyle = new DashStyle(new double[] { 2.5, 2.5 }, 0);
penLine.Freeze();
dc.DrawLine(penLine, new Point(ax, YMargin), new Point(ax, YHeight - YMargin));
dc.Close();
this.AddVisual(textVisual);
}
public double YHeight
{
get
{
return yHeight;
}
set
{
yHeight = value;
}
}
public Brush LabelColor
{
get
{
return labelColor;
}
set
{
labelColor = value;
}
}
public Brush AxisColor
{
get
{
return axisColor;
}
set
{
axisColor = value;
}
}
public double Thinkness
{
get
{
return thinkness;
}
set
{
thinkness = value;
}
}
public double YLabelMax
{
get
{
return yLabelMax;
}
set
{
yLabelMax = value;
}
}
public double YLabelMin
{
get
{
return yLabelMin;
}
set
{
yLabelMin = value;
}
}
public static double YZero1
{
get
{
return YZero;
}
}
public double CanvasWidth
{
get
{
return canvasWidth;
}
set
{
canvasWidth = value;
}
}
public Brush Line2Color
{
get
{
return line2Color;
}
set
{
line2Color = value;
}
}
public Brush Line1Color
{
get
{
return line1Color;
}
set
{
line1Color = value;
}
}
public DoubleCollection RtData
{
get
{
return rtData;
}
set
{
rtData = value;
mData = new DoubleCollection(value.Count);
foreach (double temp in value)
{
mData.Add(temp);
}
}
}
public DoubleCollection ThData
{
get
{
return thData;
}
set
{
thData = value;
sData = new DoubleCollection(value.Count);
foreach(double temp in value)
{
sData.Add(temp);
}
}
}
}
}
WPF 自定义的图表(适用大量数据绘制)的更多相关文章
- WPF 自定义的图表(适用大量数据绘制)下
原文:WPF 自定义的图表(适用大量数据绘制)下 上一篇文章中讲了WPF中自定义绘制大量数据的图标,思路是先将其绘制在内存,然后一次性加载到界面,在后续的调试过程中,发现当数据量到达10W时,移动鼠标 ...
- Highcharts使用CSV格式数据绘制图表
Highcharts使用CSV格式数据绘制图表 CSV(Comma-Separated Values,逗号分隔值文本格式)是採用逗号切割的纯文本数据.通常情况下.每一个数据之间使用逗号切割,几个相关数 ...
- linux环境安装nagiosgraph将nagios的性能数据绘制成动态图表?
需求描述: 在安装完成nagios之后,比如有监控磁盘负载信息的,连接数的,进程数的,可以通过安装nagiosgraph软件, 将nagios的性能数据绘制成图表,可以看到一段时间内数据的变化 环境说 ...
- Highcharts使用表格数据绘制图表
Highcharts使用表格数据绘制图表 在Highcharts中,同意用户使用网页中现有的表格数据作为数据来源,然后依据该数据来源绘制图表.对于一个典型的HTML表格.当中,第一列的数据会作为x轴刻 ...
- DevExpress WPF v19.2图表图形控件功能增强?速速种草
通过DevExpress WPF Controls,你能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案. 无论是Office办公软件的衍 ...
- WPF 自定义柱状图 BarChart
WPF 自定义柱状图 当前的Telerik控件.DevExpress控件在图表控件方面做得不错,但是有时项目中需要特定的样式,不是只通过修改图表的模板和样式就能实现的. 或者说,通过修改当前的第三方控 ...
- WPF 自定义雷达图
自定义雷达图表如下: Git下载地址:https://github.com/Kybs0/RadarChartControl 1.创建UserControl,名为“RadarChartControl” ...
- WPF自定义LED风格数字显示控件
原文:WPF自定义LED风格数字显示控件 版权声明:本文为博主原创文章,转载请注明作者和出处 https://blog.csdn.net/ZZZWWWPPP11199988899/article/de ...
- wpf 自定义圆形按钮
wpf 自定义圆形按钮 效果图 默认样式 获取焦点样式 点击样式 下面是实现代码: 一个是自定义控件类,一个是控件类皮肤 using System; using System.Collections. ...
随机推荐
- js进阶 12-3 如何实现元素跟随鼠标移动
js进阶 12-3 如何实现元素跟随鼠标移动 一.总结 一句话总结:获取鼠标位置,将鼠标位置设置为元素偏移即可. 1.用什么事件获取鼠标位置? 用mousemove可以获取鼠标移动的时候的位置 $(d ...
- Chinese remainder theorem
https://en.wikipedia.org/wiki/Chinese_remainder_theorem http://planetmath.org/ChineseRemainderTheore ...
- C++中string类的操作函数。
相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有没有这样使用起来非常方便的类呢?答案是肯 ...
- 【Heritrix基础教程之2】Heritrix基本内容介绍 分类: B1_JAVA H3_NUTCH 2014-06-01 13:02 878人阅读 评论(0) 收藏
1.版本说明 (1)最新版本:3.3.0 (2)最新release版本:3.2.0 (3)重要历史版本:1.14.4 3.1.0及之前的版本:http://sourceforge.net/projec ...
- CentOS7.1 KVM虚拟化之虚拟机快照(5)
这里用之前克隆的虚拟机vm1-clone进行快照操作 注: 1.快照实际上做的是虚拟机的XML配置文件,默认快照XML文件在/var/lib/libvirt/qemu/snapshot/虚拟机名/下 ...
- alloc init初始化后对象依然还在父视图
self.TableView=[[UITableView alloc]init]; ........2个cell //下面但方法和addsubviews方法不一样 [self.view insertS ...
- 【t080】遗址
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 很久很久以前有一座寺庙,从上往下看寺庙的形状正好是一个正方形,在4个角上竖立着圆柱搭建而成.现在圆柱都 ...
- [DevExpress]DevExpress 中 汉化包 汉化方法
第一步: 在Debug 下加入 zh-CN 汉化包(自行下载) 第二步: 在 Program.cs中加入下面代码 : System.Threading.Thread.CurrentThread.Cur ...
- springMvc中restful风格的api路径中把小数点当参数,SpringMvc中url有小数点
在springMvc web项目中restful风格的api路径中有小数点会被过滤后台拿不到最后一个小数点的问题, 有两种解决方案: 1:在api路径中加入:.+ @RequestMapping(&q ...
- java中的方法返回值使用泛型,实现灵活的返回值类型
痛点: 使用Mybatis框架的时候,想封装一个底层JDBC控制器,用于提供和Mybatis交互的增删改查接口(公用的接口),但由于公用的查询方法可能是用户自定义的任意一个和表对应的java ...