ZedGraph如何显示鼠标附近的曲线的点?介绍三种方法

article/2025/10/6 23:52:12

使用ZedGraph绘制曲线图的时候,不仅仅是看曲线的走向,也需要查看曲线上某位位置处采集到的数据是多少。下面介绍三种方法,从简单到复杂。

文章目录

      • 1、使用自带的功能显示点的坐标
      • 2、 多条曲线的坐标点同时显示
      • 3、 多条曲线的坐标点同时显示(GDI绘制)

1、使用自带的功能显示点的坐标

使用ZedGraph自带的属性IsShowPointValues,来显示曲线点坐标

注 zedGraph是控件ZedGraph的名称将IsShowPointValues设置为true
 zedGraph.IsShowPointValues = true;

在这里插入图片描述
可以显示点的坐标,但是也有个缺点,只能显示某一条曲线上的一个点,如果我想两条曲线上的点一起显示呢,想对比一下数据?

2、 多条曲线的坐标点同时显示

既然已经可以显示某个点的坐标了,那么显示多个点,也应该是可以的。
ZedGraph提供了一个PointValueEvent坐标值事件,它的返回值是一个字符串。哎巧了,这个字符串就是显示坐标点值的字符串,那就可以随便发挥了。

  private string ZedGraph_PointValueEvent(ZedGraphControl sender, GraphPane pane, CurveItem curve, int iPt){string info = "";if (zedGraph.GraphPane.CurveList.Count > 0){//有曲线if (  iPt > 0){foreach (CurveItem item in zedGraph.GraphPane.CurveList){//遍历曲线info += "(X:" + item.Points[iPt].X.ToString() + " , Y:"+ item.Points[iPt].Y.ToString() + ")\r\n";}}}return info;}

在这里插入图片描述
这么看着是不是觉得还少了什么,应该是一根标识鼠标位置的竖线。点都已经显示出来了,不要再加要求了。(客户根本不会听滴~)你以为就这一个要求,太年轻。能不能把显示坐标点的背景色改改啊,加上曲线的名称啦,更过分的是还得配上对应曲线的颜色。

3、 多条曲线的坐标点同时显示(GDI绘制)

客户就是上帝,为了这碎银几两,还是得折腰。
分析一下需求:1 加上鼠标位置的竖线(游标); 2 加上曲线名称(容易);3 改背景色 4 与曲线颜色对应上。

前面两种方法ZedGraph本质上是使用ToolTip来显示曲线坐标点的,但是ZedGraph并没有提供给我们有关于ToolTip的接口。

那么有两种方案:1 、更改ZedGraph的源码; 2、在ZedGraph上重绘一个类似ToolTip的提示框。

这里使用的是第二种方法。
思路: 在鼠标移动的时候,绘制曲线点的坐标以及竖直线游标。

关键的一个点是:鼠标距离曲线上最近的点是哪个呢?幸运的是,我们所关注的这个问题,ZedGraph有提供相关接口可以访问。通过FindNearestPoint
就可以找到最接近的点了。该函数有三个重载方法,可按需使用。

  public bool FindNearestPoint(PointF mousePt, CurveList targetCurveList, out CurveItem nearestCurve, out int iNearest);public bool FindNearestPoint(PointF mousePt, CurveItem targetCurve, out CurveItem nearestCurve, out int iNearest);public bool FindNearestPoint(PointF mousePt, out CurveItem nearestCurve, out int iNearest);

来吧,自己动手丰俭由人。
记得先把前面的IsShowPointValues设置为false,接着使用ZedGraph中的MousMove事件,在鼠标移动的时候获取最近点的坐标并使用GDI绘制。

 private void ZedGraph_MouseMove(object sender, MouseEventArgs e){ShowPonitByDraw(e);}private void ShowPonitByDraw(MouseEventArgs e){if (zedGraph.GraphPane.Chart.Rect.Contains(e.Location) == false){return;}using (Graphics graphics = zedGraph.CreateGraphics()){//在zedGraph上创建画布zedGraph.Refresh();using (Pen pen = new Pen(Color.Red, 2)){//创建画笔并设置样式pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;//画竖直线graphics.DrawLine(pen, e.X, zedGraph.GraphPane.Chart.Rect.Top, e.X, zedGraph.GraphPane.Chart.Rect.Bottom);if (zedGraph.GraphPane.CurveList.Count <= 0){return;}//找最近的一个点zedGraph.GraphPane.FindNearestPoint(e.Location, out CurveItem nearCurve, out int nearIndex);if (nearCurve == null || nearIndex < 0){return;}string tempMax = "";List<string> infoList = new List<string>();foreach (CurveItem curve in zedGraph.GraphPane.CurveList){//曲线名称 + 坐标点string tmp = curve.Points[nearIndex].Y.ToString();//填充到8个长度tmp =  tmp.PadLeft(8);tmp = tmp.Insert(0, curve.Label.Text + ": " );infoList.Add(tmp);if (tmp.Length > tempMax.Length){//记录最大的长度字符串tempMax = tmp;}}//文本绘制的一些字体和画刷配置Font font = new Font("Arial", 10, System.Drawing.FontStyle.Regular, GraphicsUnit.World);//得到一个字体绘制的大小SizeF tempSizeF = graphics.MeasureString(tempMax, font, (int)font.Size);//根据字符长度计算矩形的宽度 10是颜色矩形框的宽度float rectWidth = tempSizeF.Width * tempMax.Length;//高度float rectHeight = (infoList.Count + 1) * 18 + 5;//背景颜色框的左上角点的坐标,偏移2个像素Point point = new Point(e.X + 2, e.Y + 2);#region 计算左上角坐标 让背景矩形框在曲线的矩形框范围之内if (point.X + rectWidth > zedGraph.GraphPane.Chart.Rect.Right){point.X = (int)(point.X - rectWidth - 2);}if (point.Y + rectHeight > zedGraph.GraphPane.Chart.Rect.Bottom){point.Y = (int)(point.Y - rectHeight - 2);}#endregionpen.Color = Color.White;//绘制背景矩形框Rectangle rectBg = new Rectangle(point, new Size((int)rectWidth, (int)rectHeight));graphics.DrawRectangle(pen, rectBg);graphics.FillRectangle(new SolidBrush(Color.FromArgb(70, 70, 70)), rectBg);//颜色框的大小Size colorSize = new Size(10, 10);//绘制文本的颜色SolidBrush textBrush = new SolidBrush(Color.Red);//绘制文本内容 时间int time = 0;//"时间(ms):"string timeStr = "时间: " + nearCurve[nearIndex].X.ToString();graphics.DrawString(timeStr , font, textBrush,new Point(point.X + 20, point.Y + 5 + time * 16));for (int m = 0; m < infoList.Count; m++){time++;//绘制每条曲线的颜色小矩形框 Rectangle rect1 = new Rectangle(new Point(point.X + 5, point.Y + 5 + time * 16), colorSize);graphics.DrawRectangle(new Pen(zedGraph.GraphPane.CurveList[m].Color), rect1);graphics.FillRectangle(new SolidBrush(zedGraph.GraphPane.CurveList[m].Color), rect1);//绘制文本内容graphics.DrawString(infoList[m], font, textBrush,new Point(point.X + 20, point.Y + 5 + time * 16));}}}}

在这里插入图片描述
方法总比困难多,只要敢想且敢做。如果有更好的方法,请告诉我吖。

代码已打包在git:https://github.com/GXXMei/ZedGraphShowPoint
CSDN也有资源(土豪请随意):


http://chatgpt.dhexx.cn/article/VChidA2A.shtml

相关文章

开源框架ZedGraph的使用

.Net的绘图控件ZedGraph的使用 ZedGraph 是一个开源的.NET图表类库&#xff0c; 全部代码都是用C#开发的。它可以利用任意的数据集合创建2D的线性和柱形图表 我们一般不直接使用ZedGraphControl对象&#xff0c;而是使用它的面板对象来进行操作&#xff0c;这里我们将它的面板…

redis解决高并发问题,如商品秒杀

redis真的是一个很好的技术&#xff0c;它可以很好的在一定程度上解决网站一瞬间的并发量&#xff0c;例如商品抢购秒杀等活动。。。 redis之所以能解决高并发的原因是它可以直接访问内存&#xff0c;而以往我们用的是数据库(硬盘),提高了访问效率,解决了数据库服务器压力。 …

Redis的高并发场景解决方案

1.Redis的信息 &#xff08;1&#xff09;单线程容易实现。 &#xff08;2&#xff09;效率高轻松处理每秒几十万数据&#xff08;因为是占内存的所以CPU不是瓶颈&#xff09;。 &#xff08;3&#xff09;支持数据类型多&#xff08;String&#xff0c;List&#xff0c;has…

java如何解决高并发问题_java怎么处理高并发?

java处理高并发的方法:1、优化代码,减少不必要的资源浪费;2、把图片与页面进行分离,将图片放到独立的图片服器;3、使用缓存,可以大量减少与数据库的交互,提高性能;4、使用数据库集群;5、进行DB优化;6、硬件上做到负载均衡等等。 java处理高并发的方法: 1、从最基础的…

flask 多进程/多线程 解决高并发问题

1、简介&#xff1a; Flask 默认是单进程&#xff0c;单线程阻塞的任务模式&#xff0c;在项目上线的时候可以通过nginxgunicorn 的方式部署flask任务。 app.run()中可以接受两个参数&#xff0c;分别是threaded和processes&#xff0c;用于开启线程支持和进程支持。 1.thre…

高并发超卖问题简要解决方案

1、传统通过数据库保证不超卖 事务行锁并不是解决超卖的方案&#xff0c;只是保障数据的统一性。传统通过回滚事务的方式防止某些用户多卖的情况。 采用新建一个防重表事务的方式防止超卖。同一事务中&#xff0c;采用如 用户ID商品ID 的方式作为防重表唯一索引字段的数值&…

python 中如何解决高并发问题

python 中小量高并发问题的解决 描述&#xff1a;在多个用户同时发起对同一个商品的下单请求时&#xff0c;先查询商品库存&#xff0c;再修改商品库存&#xff0c;会出现资源竞争问题&#xff0c;导致库存的最终结果出现异常。 例如&#xff1a;id为16的商品的库存为10&#…

高并发的解决方式

大型网站如何防止崩溃&#xff0c;解决高并发带来的问题 大型网站&#xff0c;比如门户网站&#xff0c;在面对大量用户访问、高并发请求方面带来的问题 1大并发&#xff1a;在同一个时间点&#xff0c;有大量的客户来访问我们的网站&#xff0c;如果访问量过大&#xff0c;就…

三个方法解决php并发问题

福利&#xff1a;[网络安全重磅福利&#xff1a;入门&进阶全套282G学习资源包免费分享 &#xff01;] 解决php并发问题的方法有很多&#xff0c;具体可以使用MySQL的行级锁、乐观锁和Redis的分布式锁等技术来解决。此外&#xff0c;还可以使用消息队列、多进程、多线程等技…

Redis(十)redis使用list解决高并发问题,如商品秒杀

redis真的是一个很好的技术&#xff0c;它可以很好的在一定程度上解决网站一瞬间的并发量&#xff0c;例如商品抢购秒杀等活动。 redis之所以能解决高并发的原因是它可以直接访问内存&#xff0c;而以往我们用的是数据库(硬盘),提高了访问效率,解决了数据库服务器压力。 为什…

PHP解决高并发问题

举个例子&#xff0c;高速路口&#xff0c;1秒钟来5部车&#xff0c;每秒通过5部车&#xff0c;高速路口运作正常。突然&#xff0c;这个路口1秒钟只能通过4部车&#xff0c;车流量仍然依旧&#xff0c;结果必定出现大塞车。&#xff08;5条车道忽然变成4条车道的感觉&#xff…

如何解决高并发,秒杀问题

相信不少人会被这个问题困扰&#xff0c;分享大家一篇这样的文章&#xff0c;希望能够帮到你&#xff01; 一、秒杀业务为什么难做&#xff1f; 1&#xff09;im系统&#xff0c;例如qq或者微博&#xff0c; 每个人都读自己的数据 &#xff08;好友列表、群列表、个人信息&a…

JAVA RedisTemplate实现(加锁/解锁) 解决高并发问题

基于传统的单机模式下的并发锁&#xff0c;已远远不能满足当下高并发大负载的情况&#xff0c;当下常用的并发处理如下 1、使用synchronized关键字 2、select for update 乐观锁 3、使用redis实现同步锁 方案一 适合单机模式&#xff0c; 方案二 虽然满足多节点服务实例…

mysql 高并发写入锁表_使用mysql中的锁解决高并发问题

阿里云产品通用代金券,最高可领1888分享一波阿里云红包. 阿里云的购买入口 为什么要加锁 多核计算机的出现,计算机实现真正并行计算,可以在同一时刻,执行多个任务。在多线程编程中,因为线程执行顺序不可控导致的数据错误。比如,多线程的理想状态是这样的 多线程理想.jpg 但是…

php如何解决高并发问题

如何用PHP解决高并发问题&#xff1f;&#xff08;附源码&#xff09;-php教程-PHP中文网上篇文章给大家介绍了《让我们再进一步了解PHP流程控制语句之if语句吧&#xff01;&#xff01;&#xff01;(附源码)​》&#xff0c;本文继续给大家介绍PHP解决高并发问题https://www.p…

Mysql如何利用乐观锁解决高并发问题

Mysql如何利用乐观锁解决高并发问题 msql Mysql如何利用乐观锁解决高并发问题前言一、案例说明&#xff1a;二、乐观锁&#xff1a;1.介绍:使用版本号实现乐观锁 2.代码实现 总结 前言 例如&#xff1a;在这之前已经许久未写博客了&#xff0c;最近突发奇想还是决定把这个捡起…

Redis解决高并发问题

1 模拟商品抢购和并发的效果 这里模拟一个商品抢购的过程所带来的问题&#xff0c;以及解决问题的思路。 这里模拟的商品抢购过程是一个商品正常购买的过程&#xff0c;其中包含了两个主要的步骤&#xff1a;商品库存减少和商品购买记录的添加。 下面搭建项目环境。 1.1 数…

一文教你如何处理高并发

目录 前言 一、为什么要解决高并发问题 二、性能评估 计算峰值流量方法 本章结论 三、性能测试 测试目的 找到系统最高承受压力的临界点 找出系统中的短板 测试工具 简单测试 1.数据抓包 2.加压测试 3.硬件跟踪 4.JVM跟踪 5.其它组件测试 6.总括 全链路测试&…

高并发场景设计与解决方案

所有的平台或系统建设和维护中&#xff0c;高并发场景都存在&#xff0c;解决方案也是各种样式&#xff0c;本次将从初中、高二个场景给出设计方案。 本文内容&#xff1a;高并发场景定义&#xff0c;高并发初中级场景与解决方案&#xff0c;高并发高级场景与解决方案 第一部分…

数据库关系代数运算

转载&#xff1a;https://wenku.baidu.com/view/f301bf48e45c3b3567ec8b75.html