一、前言

  • 项目中涉及到了心率监测,而且数据量达到了百万级别,通过WPF实现大数据曲线图时,尝试过最基础的Canvas来实现,但是性能堪忧,而且全部画出来也不实际。同时也尝试过找第三方的开源库,但是因为曲线图涉及到很多细节功能,第三方的肯定也没法满足。没办法,只能自己实现,上网查找后发现DrawingVisual这个玩意可以实现高性能画图,同时再搭配局部显示,这样就能实现自己想要的效果。话不多说,今天把大致的实现思路写一下,就不直接把项目的源码贴出来,写个简单的Demo就好了。

二、正文

1、首先新建个项目,然后创建个自定义控件,命名CurveChartDrawingVisual,然后让它继承FrameworkElement。因为要使用DrawingVisual对象的话,需要为它创建一个主机容器。关于其他相关DrawingVisual的细节这里不做过多阐述,不明白的可以去微软官网看。

2、实现的具体代码如下,相关细节有备注标注了。这里记得要重写一下VisualChildrenCount属性和重写 GetVisualChild() 方法,不然图画不出来

public class CruveChartDrawingVisual : FrameworkElement
{private List<Visual> visuals = new List<Visual>();private DrawingVisual Layer;private double offset_x = 0;//滑动条偏移值private double y_scale;//y轴方向缩放比例private List<int> list_points;//曲线数据private static int Top_Val_Max = 100;//y轴最大值private static int Top_Val_Min = 0;//y轴最小值private static int X_Sex = 20;//x轴分度值private static int Y_Sex = 20;//y轴分度值private static int Bottom = 30;//底部x轴坐标显示高度Pen pen = new Pen(Brushes.Green, 2);Pen primarygrid_pen = new Pen(Brushes.Black, 1);Pen secondgrid_pen = new Pen(Brushes.Gray, 1);public CruveChartDrawingVisual(){pen.Freeze();//冻结笔,提高性能关键所在primarygrid_pen.Freeze();secondgrid_pen.Freeze();Layer = new DrawingVisual();visuals.Add(Layer);}public void SetupData(List<int> points){list_points = points;offset_x = 0;DrawContent();}public void OffsetX(double offset){offset_x = offset;DrawContent();InvalidateVisual();}private void DrawContent(){var dc = Layer.RenderOpen();y_scale = (RenderSize.Height - Bottom) / (Top_Val_Max - Top_Val_Min);var mat = new Matrix();mat.ScaleAt(1, -1, 0, RenderSize.Height / 2);mat.OffsetX = -offset_x;dc.PushTransform(new MatrixTransform(mat));//横线for (int y = 0; y <= Top_Val_Max - Top_Val_Min; y += 10){Point point1 = new Point(offset_x, y * y_scale + Bottom);Point point2 = new Point(offset_x + RenderSize.Width, y * y_scale + Bottom);if (y % Y_Sex == 0){dc.DrawLine(primarygrid_pen, point1, point2);continue;}dc.DrawLine(secondgrid_pen, point1, point2);}//竖线与文字for (int i = 0; i <= (offset_x + RenderSize.Width); i += X_Sex * 2){if (i < offset_x){continue;}var point1 = new Point(i, Bottom);var point2 = new Point(i, (Top_Val_Max - Top_Val_Min) * y_scale + Bottom);//y轴文字if (i % 100 == 0){var text1 = new FormattedText(i + "", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 16, Brushes.Black);var mat3 = new Matrix();mat3.ScaleAt(1, -1, i - text1.Width / 2, 8 + text1.Height / 2);dc.PushTransform(new MatrixTransform(mat3));dc.DrawText(text1, new Point(i - text1.Width / 2, 8));dc.Pop();}//表格刻度文字if (i % 100 == 0){for (int y = Top_Val_Min; y <= Top_Val_Max; y += 10){if (y % Y_Sex == 0){var text1 = new FormattedText(y + "", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 12, Brushes.Black);var mat3 = new Matrix();mat3.ScaleAt(1, -1, i + 1, (y - Top_Val_Min) * y_scale + Bottom + text1.Height / 2);dc.PushTransform(new MatrixTransform(mat3));dc.DrawText(text1, new Point(i + 1, (y - Top_Val_Min) * y_scale + Bottom));dc.Pop();}}//深色竖线dc.DrawLine(primarygrid_pen, point1, point2);continue;}//浅色竖线dc.DrawLine(secondgrid_pen, point1, point2);}if (list_points != null){for (int i = (int)offset_x; i < list_points.Count - 1; i++){if (i > offset_x + RenderSize.Width){break;}dc.DrawLine(pen, new Point(i, list_points[i] * y_scale + Bottom), new Point(i + 1, list_points[i + 1] * y_scale + Bottom));}}dc.Pop();dc.Close();}protected override int VisualChildrenCount => visuals.Count;protected override Visual GetVisualChild(int index){return visuals[index];}protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo){DrawContent();base.OnRenderSizeChanged(sizeInfo);}protected override void OnRender(DrawingContext drawingContext){drawingContext.DrawRectangle(Brushes.White, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));base.OnRender(drawingContext);}
}

3、接着测试一下,打开MainWindow,添加我们的自定义控件,这里局部显示需要搭配一个ScrollViewer来实现,记得这里没有将我们的自定义控件嵌入ScrollViewer,而是放一个Canvas来填充,代码如下

<Grid><local:CruveChartDrawingVisual x:Name="curve" Margin="0,15,0,20" /><ScrollViewerName="scroll"HorizontalScrollBarVisibility="Auto"ScrollChanged="ScrollViewer_ScrollChanged"VerticalScrollBarVisibility="Disabled"><Canvas x:Name="canvas" Height="1" /></ScrollViewer>
</Grid>

4、接着就是后台代码,比较简单,就是自动生成一个List,然后传给自定义控件,Canvas的宽度直接设置为List的长度,因为这里是水平方向一个像素点画一个点,然后滑动条滑动时再将对应的偏移值传递到控件,再通过偏移值更新视图

public partial class MainWindow : Window
{private bool isAdd = true;public MainWindow(){InitializeComponent();}private void Window_Loaded(object sender, RoutedEventArgs e){List<int> lists = new List<int>();int temp = 20;for (int i = 0; i < 60 * 60; i++){if (isAdd){lists.Add(temp);temp ++;}else{lists.Add(temp);temp --;}if (temp == 90) isAdd = false;if (temp == 10) isAdd = true;}canvas.Width = lists.Count;curve.SetupData(lists);}private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e){curve.OffsetX(scroll.HorizontalOffset);}
}

5、运行效果如下,滑动条拖到哪里就显示哪里,这样就算数据量再大也没问题,这种曲线图跟常规的曲线图有点差别,这里更多的是提供一种思路。

[1]

参考资料

[1]

链接: https://www.cnblogs.com/cong2312/p/15921146.html

WPF 使用DrawingVisual绘制高性能曲线图相关推荐

  1. WPF 动态模拟CPU 使用率曲线图

    在工作中经常会遇到需要将一组数据绘制成曲线图的情况,最简单的方法是将数据导入Excel,然后使用绘图功能手动生成曲线图.但是如果基础数据频繁更改,则手动创建图形可能会变得枯燥乏味.本篇将利用Dynam ...

  2. R语言绘制ROC曲线图

    受试者工作特征曲线(ROC曲线),最初作为一种分析方法在二战时用于评价雷达性能(鉴别敌方,友方以及噪音),目前广泛应用于医学诊断.生物信息学.数据挖掘和机器学习等研究中. ROC曲线可用于评价生物标记 ...

  3. R语言绘制生存曲线图

    R语言绘制生存曲线图 KMunicate是支持按照Morris等人的KMunicate研究推荐的方式生成Kaplan-Meier图. 1958年,Edward L. Kaplan 和Paul Meie ...

  4. Matplotlib绘制动态曲线图,超简单!!

    效果预览 配上动感的音乐感觉就是不一样啊,要达到上述效果除了核心的Matplotlib绘图外,其他工具和上篇推文 Hans Rosling Charts Matplotlib 绘制 所使用的工具一样啊 ...

  5. WPF使用Canvas绘制可变矩形

    WPF使用Canvas绘制可变矩形 原文:WPF使用Canvas绘制可变矩形 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/WANGYAN9110/ ...

  6. python画曲线图-利用python绘制数据曲线图的实现

    "在举国上下万众一心.众志成城做好新冠肺炎疫情防控工作的特殊时刻,我们不能亲临主战场,但我们能坚持在大战中坚定信心.不负韶华." 1.爬取新闻保存为json文件,并将绘图所需数据保 ...

  7. 二次函数图像如何用计算机绘制,怎么在WPS表格中绘制二次函数曲线图

    WPS表格软件的最新版本集成了强大的函数功能和数据处理功能,在计算机办公领域内,基本胜任常用数据统计管理的办公任务.下面小编就教你怎么在WPS表格中绘制二次函数曲线图. WPS表格中绘制二次函数曲线图 ...

  8. 怎么在WPS表格中绘制二次函数曲线图

    WPS表格软件的最新版本集成了强大的函数功能和数据处理功能,在计算机办公领域内,基本胜任常用数据统计管理的办公任务.下面小编就教你怎么在WPS表格中绘制二次函数曲线图. WPS表格中绘制二次函数曲线图 ...

  9. android心率曲线绘制,【图解鸿蒙】使用绘图组件Canvas绘制心率曲线图

    一.运行效果 在页面中显示页面标题.心率曲线图.心率最大值及其图标.心率最小值及其图标.心率在每分钟内的平均次数.如下图所示: 二.实现思路 在页面的生命周期事件函数onInit()中,随机生成若干个 ...

最新文章

  1. 如何看待「上帝掷骰子」这场概率骗局
  2. VUE-CLI webpack配置autoprefixer后build模式与dev不相同,打包后部分前缀或属性丢失,所见即所得...
  3. 计算机视觉编程——增强现实基础
  4. FixedSizeList的使用
  5. 解决,文件上传到 ftp 服务器,中文出现乱码问题
  6. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 4丨游戏玩法分析 I【难度简单】
  7. 信息熵 条件熵 信息增益 信息增益比 GINI系数
  8. vue开发移动端h5使用 lib-flexible移动端适配
  9. 【项目知识点】Vue中实现扫描二维码获取信息
  10. 自定义strcmp函数
  11. 5s管理常用工具汇总
  12. 数字信号处理——多速率信号处理
  13. C# 字节(数组)与位之间的计算
  14. 小皮phpstudy中的mysql无法启动,启动就马上停止
  15. 天翼云铸牢国云安全,护航千行百业
  16. linux系统软路由软件,使用Linux+Zebra构建软路由系统
  17. 微信小程序 —— 保留两位小数
  18. 开发人员必知的5个CI/CD工具
  19. SSH使用及协议分析。
  20. 批量识别图片大致不相同图片_批量图片识别文字软件

热门文章

  1. [zz]为 Lua 绑定 C/C++ 对象
  2. ASP语言基础之常量的定义方法
  3. mysql 重复字段查询及排除重复值
  4. 关于初始化C++类成员
  5. this表示当前对象简单实例
  6. C#种将String类型转换成int型
  7. 智能停车O2O 独角兽初现:“ETCP停车”获5000万美金A轮融资
  8. Vue学习笔记入门篇——数据及DOM
  9. 猎豹MFC--CMenu菜单 设置主菜单 给主对话框设置菜单 设置快捷菜单
  10. POJ 2240 ZOJ 1082 Arbitrage 最短路,c++ stl pass g++ tle 难度:0