C# 历史曲线控件 基于时间的曲线控件 可交互的高级曲线控件 HslControls曲线控件使用教程

本篇博客主要对 HslControls 中的曲线控件做一个详细的教程说明,大家可以根据下面的教程开发出高质量的曲线控件

Prepare



先从nuget下载到组件,然后就可以使用组件里的各种组件信息了。

在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装:

Install-Package HslControls

  

NuGet安装教程  http://www.cnblogs.com/dathlin/p/7705014.html

技术支持QQ群:群1:592132877(满)  群2:948305931(组件的版本更新细节也将第一时间在群里发布)

如果你在使用控件的过程中有什么疑问,或是发现了BUG,或是功能建议,等等都可以加入上面的QQ群进行讨论。文章更新时间:2019年1月5日 16:51:41

Demo



demo项目的源代码,https://github.com/dathlin/HslControlsDemo

有一个demo程序可以下载,地址为 demo.zip

所支持的控件信息如下:

曲线控件先上图,看看

适用场景



正式开始文章之前,我们先来看看这个曲线控件到底为了解决什么样子的问题的,在工业的场景中,我们会采集一些设备的工艺参数信息,比如锅炉和模具温度,锅炉压力,仓库湿度,等等情况的信息,我们会在数据库建立一张数据表,可能2秒钟存储一条数据,可能5秒钟存储一条数据等等,甚至可能30秒,现在我们有数据了,需要将数据进行显示出来,使用本控件即可以快速的开发可交互式的曲线显示。

如下就是一个数据库的示例

曲线显示



当然实际中你可以根据自己的情况来,不过这都无所谓,应该本控件是需要传入处理过的数据的,ok,我们现在界面上拖一个控件

先调整两侧坐标轴的,比如温度的范围是0-250,压力的范围是0-5,我们就调整这个控件的属性来实现功能

还可以调整分割线的情况,我们调整成如下的数据

然后显示如下:

我们再调整下文字,设置为空,在新增一个按钮,点击的时候就要去数据库查询数据了,由于查询的时间不定,需要花费一些时间,我们还需要进行友好的提示信息,比如正在查询数据...

然后我们完善代码

        private void button1_Click( object sender, EventArgs e )
        {
            hslCurveHistory1.Text = "正在加载数据...";
            hslCurveHistory1.RemoveAllCurve( );
            new Thread( new ThreadStart( ThreadReadExample1 ) ) { IsBackground = true }.Start( );
        }

        private void ThreadReadExample1( )
        {
            // 模拟下查询时间
            Thread.Sleep( 2000 );

            // 这里数据数据,实际应该是你的真实的数据
            float[] temp = new float[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
            }

            // 显示出数据信息来
            Invoke( new Action( ( ) =>
            {
                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

        private Random random = new Random( );

此处只有一条曲线,横轴还没设置,这已经是最简单的曲线显示了,而且支持按钮多次重复点击,不会发生数据叠加。效果如下:

当光标移动的时候,还会提示当前的光标所在位置的数据信息,目前所具备的功能还是比较简单的,我们从数据库获取到数据,通常还包含了时间轴,此处就要传入同等数量长度的时间轴信息

注意,时间轴是随着时间逐渐增加的信息,确保是单向增加的。

所以我们的代码改成如下:

        private void ThreadReadExample1( )
        {
            // 模拟下查询时间
            Thread.Sleep( 2000 );

            // 这里数据数据,实际应该是你的真实的数据
            float[] temp = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 显示出数据信息来
            Invoke( new Action( ( ) =>
            {
                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.RenderCurveUI( );// 所有的曲线设置好后,调用这个方法统一显示曲线信息,这样的设计可以有效的避免闪烁的问题
            } ) );
        }

  

这时候的效果已经改变了。最下面已经多了一个时间的信息显示。

这时候我们在图形的任意区域点击鼠标左键,然后移动鼠标,然后再松开鼠标左键就会发生填充辅助曲线信息

这时候可以多次的重复操作,可以标记多个图形信息。

如果想要清除上面的所有的数据信息,怎么办?右键点击下图形的任意界面,所有的辅助曲线就不存在了。

接下来我们再增加一条曲线,压力相关的,再看看效果。

        private void ThreadReadExample1( )
        {
            // 模拟下查询时间
            Thread.Sleep( 2000 );

            // 这里数据数据,实际应该是你的真实的数据
            float[] temp = new float[2000];
            float[] press = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 显示出数据信息来
            Invoke( new Action( ( ) =>
            {
                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

效果如下:

假设我还有个步序的信息,只想在曲线里提示出来,但是不想显示步序曲线,应该怎么操作呢

        private void ThreadReadExample1( )
        {
            // 模拟下查询时间
            Thread.Sleep( 2000 );

            // 这里数据数据,实际应该是你的真实的数据
            float[] temp = new float[2000];
            float[] press = new float[2000];
            float[] steps = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 显示出数据信息来
            Invoke( new Action( ( ) =>
            {
                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不显示曲线信息
                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

  

这样之后我们就可以显示步序的提示信息,但是不显示步序的曲线。

这里有个小问题,如果我希望步序显示顺序在最上面怎么办?或者是这里的提示信息是根据什么顺序来排序的?

答案是曲线的添加顺序,我们只需要调整曲线添加的顺序即可。如下:

                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不显示曲线信息
                hslCurveHistory1.RenderCurveUI( );

  

到这里为止,曲线控件的简单应用已经差不多了,已经实现了一般的情况的应用了。接下来就是比较高级的操作了。

高级操作



在高级的操作之前,需要先普及个概念,贯穿于这个曲线控件的所有的部分。这个概念就是数据点位的信息,比如我们有2000个数据,那么数据点位就是0-1999,在图形上显示不一定是0-1999的位置,存在一个缩放的等级,默认缩放等级是1,也就是说0-1999就是0-1999,如果我们的缩放等级调整为2,那么就是放大,0-1999对应 0-3998,如果缩放等级为0.5,那么就是缩小一倍,0-1999对应0-999

辅助线功能

如果我们需要标记一段特殊的虚线,可以是报警的分界线,也可以是重点的线。操作如下:在窗体的载入中添加如下的代码即可

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f );
        }

  

效果如下:

当然我们也可以指定颜色

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
        }

  

当然也可以添加右曲线信息

缩放功能



如果你觉得目前的数据点位太多了,曲线太长了,可以进行缩小,那么可以设置缩放等级,在窗口载入的时候设置一次即可。

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
            hslCurveHistory1.SetScaleByXAxis( 0.5f );
        }

  

接下来我们看看缩放等级设置为4的效果

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
            hslCurveHistory1.SetScaleByXAxis( 4f );
        }

  

背景标识操作



我们现在有个需求,我们有了步序之后就可以分析出曲线对应的产品信息,比如分析出点位是从1000点开始到1300点结束的,是一个产品,条码是 K1234567890 ,现在要在曲线里显示出来。我们来看看如果通过代码实现

我们先调整为正常的缩放等级,也就是1f,

        private void ThreadReadExample1( )
        {
            // 模拟下查询时间
            Thread.Sleep( 2000 );

            // 这里数据数据,实际应该是你的真实的数据
            float[] temp = new float[2000];
            float[] press = new float[2000];
            float[] steps = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 显示出数据信息来
            Invoke( new Action( ( ) =>
            {
                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不显示曲线信息

                HslControls.HslMarkBackSection backSection = new HslControls.HslMarkBackSection( )
                {
                    StartIndex = 1000,
                    EndIndex = 1300,
                    MarkText = "K1234567890",
                };
                hslCurveHistory1.AddMarkBackSection( backSection );

                hslCurveHistory1.RenderCurveUI( );
            } ) );
        }

        private Random random = new Random( );

        private void FormCurveDemo_Load( object sender, EventArgs e )
        {
            hslCurveHistory1.AddLeftAuxiliary( 172f, Color.Yellow );
        }

  

代码上来说,就是新增一个 backSection 对象,至于1000和1300怎么分析出来的,就是要自己写代码实现了,简单的说,通过遍历数据,前后对比可以实现。运行效果如下:

可以清楚的看到有一个颜色稍微淡一点点的标记层,如果你的缩放等级是0.5,那么这个阴影的宽度会减少一半,这都是自动适应的。

当然你也可以添加多个背景的标记,如果想要清除标记,只能调用清除所有曲线的方法,

如下是缩放等级为0.5的情况

区间标识操作



我们现在有另外的需求,需要标记某些特殊的区间,比如某个区间发生了报警,例如区间 600-700发生了报警,内容为“温度超标了”;应该怎么操作

        private void ThreadReadExample1( )
        {
            // 模拟下查询时间
            Thread.Sleep( 2000 );

            // 这里数据数据,实际应该是你的真实的数据
            float[] temp = new float[2000];
            float[] press = new float[2000];
            float[] steps = new float[2000];
            DateTime[] times = new DateTime[2000];
            for (int i = 0; i < temp.Length; i++)
            {
                temp[i] = Convert.ToSingle( random.NextDouble( ) * 40 + 100 );
                press[i] = Convert.ToSingle( random.NextDouble( ) * 0.5d + 4 );
                times[i] = DateTime.Now.AddSeconds( i - 2000 );
            }

            // 显示出数据信息来
            Invoke( new Action( ( ) =>
            {
                // 设置曲线属性,名称,数据,颜色,是否平滑,格式化显示文本
                hslCurveHistory1.SetLeftCurve( "步序", steps );
                hslCurveHistory1.SetLeftCurve( "温度", temp, Color.DodgerBlue, true, "{0:F1} ℃" );
                hslCurveHistory1.SetRightCurve( "压力", press, Color.Tomato, true, "{0:F2} Mpa" );
                hslCurveHistory1.SetDateTimes( times );
                hslCurveHistory1.SetCurveVisible( "步序", false );         // 不显示曲线信息

                HslControls.HslMarkBackSection backSection = new HslControls.HslMarkBackSection( )
                {
                    StartIndex = 1000,
                    EndIndex = 1300,
                    MarkText = "K1234567890",
                };
                hslCurveHistory1.AddMarkBackSection( backSection );

                HslControls.HslMarkForeSection foreSection = new HslControls.HslMarkForeSection( )
                {
                    StartIndex = 600,
                    EndIndex = 800,
                    StartHeight = 0.3f,         // 如果值是(0-1)的话,表示的是位置百分比,0.9就是曲线高度为90%,从上往下看的视角,如果填了600,那就是绝对坐标
                    Height = 0.9f,              // 和上面同理
                    LinePen = Pens.Chocolate,   // 指定颜色
                    IsRenderTimeText = false,   // 是否显示额外的起始时间和结束时间,此处就不要了
                    MarkText = "温度超标了",
                };
                hslCurveHistory1.AddMarkForeSection( foreSection );

                hslCurveHistory1.RenderCurveUI( );  // 将曲线显示出来
            } ) );
        }

  

  如上图,我们完成了标记信息的添加,上述 的几个属性,你可以修改试试看,然后运行看看效果。上述的效果如下:

当然了,文字的颜色也可以设定的,用于不同功能的区段的提醒,这个区段也是支持自动的缩放的。

好了,更详细的就参考demo项目的源代码,https://github.com/dathlin/HslControlsDemo

原文地址:https://www.cnblogs.com/dathlin/p/10291327.html

时间: 2024-10-10 12:34:52

C# 历史曲线控件 基于时间的曲线控件 可交互的高级曲线控件 HslControls曲线控件使用教程的相关文章

基于CkEditor实现.net在线开发之路(3)常用From表单控件介绍与说明

这一章主要介绍常用From表单控件,如图所示: 红色框框住的就是常用From表单控件.从左到右分别是From,复选框,单选框,文本框,多行文本框,下拉列表,按钮,图片按钮,隐藏文本框,Lable 复选框和单选框介绍与说明: 因为单选框和复选框属性和设置界面一直,所以就一起讲解,点击复选框按钮弹出,复选框设置界面,如下图: 属性说明与用法: 字段说明 输入类型 说明 控件ID   自动生成,生成一个唯一的控件ID,如果页面存在重复预览页面会报错 控件名称 手工输入 方便编辑时,知道该控件是做什么的

基于时间加权svm的指数优化复制策略

1 引言 指数追踪,利用某些金融资产组合去追踪某一股票指数,指数型基金核心技术.  目前主要有两种指数复制方法 基于两种假设 一:历史能够重演,在过去一段时间能构造历史追踪误差最小的,未来也将是最优,现在大多数指数复制类型为此类.二:从统计角度,找到与目标指数具有最大相关 具有协整关系的股票组合,保证未来表现与未来尽可能一致. 从股票数量复制角度,分为两种,完全复制和不完全复制,完全复制按照指数构造方式购买成分证券,但市场时序上变化迅速,造成成本高,逐渐不被使用.不完全复制根据优化方法寻找成分证

MySQL中基于mysqldump和二进制日志log-bin二进制日志进行逻辑备份以及基于时间点的还原

本文出处:http://www.cnblogs.com/wy123/p/6956464.html 本文仅模拟使用mysqldump和log-bin二进制日志进行简单测试,仅作为个人学习笔记,可能离实际应用还有很大差距,仅参考. 开启MySQL的bin-log二进制日志 模拟还原是需要mysqldump出来的文件和log-bin,因此需要开始log-bin二进制日志. mysql5.7.18在开启二进制日志的时候除了要设置log-bin的位置之外,另外需要设置一个server-id,MySQL之前

ORACLE调度之基于时间的调度(一)【weber出品】

一.调度的概述 这里我看到一篇对调度的概述觉得描述的比我好,但仅限于概述部分,其他部分我觉得我讲的比他好,于是发生以下事情: ************************华丽的转载************************************************************************* 在Oracle中任务调度指某一执行程序在特定的时间被周期性的执行.Oracle把任务调度称为job.而一个基本的job由两方面组成program和schedule.其中

JavaScript基于时间的动画算法

转自:https://segmentfault.com/a/1190000002416071 前言 前段时间无聊或有聊地做了几个移动端的HTML5游戏.放在不同的移动端平台上进行测试后有了诡异的发现,有些手机的动画会“快”一点,有些手机的动画会“慢”一点,有些慢得还不是一两点. 通过查找资料发现,基于帧的算法(Frame-based)来实现动画会导致不同帧率的平台体验不一致,而基于时间(Time-based)的动画算法可以很好地改良这种情况,让不同帧率的情况下都能达到较为统一的速度上的体验. 本

Oracle 学习之RMAN(十四)恢复实战--基于时间点恢复

1. 我们先做一个全备 RMAN> backup database ; Starting backup at 2015/07/09 13:40:47 allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID=28 device type=DISK channel ORA_DISK_1: starting full datafile backup set channel ORA_DISK_1: specifying datafile(s) in b

表空间基于时间点的恢复

步骤:1.检测和解决对要恢复的表空间有依赖关系的对象问题select *  from sys.ts_pitr_check where (ts1_name = 'UERS' and ts2_name != 'USERS')    or (ts1_name != 'USERS' and ts2_name = 'USERS');如果有依赖约束,可以考虑disable掉约束:或者同时还原依赖对象所在的表空间 2.检测哪些对象不会被还原如果有些表,在还原后还需要存在,可以使用数据泵等工具导出,等表空间还原

Python:SQLMap源码精读之基于时间的盲注(time-based blind)

基于时间的盲注(time-based blind) 测试应用是否存在SQL注入漏洞时,经常发现某一潜在的漏洞难以确认.这可能源于多种原因,但主要是因为Web应用未显示任何错误,因而无法检索任何数据. 对于这种情况,要想识别漏洞,向数据库注入时间延迟并检查服务器响应是否也已经延迟会很有帮助.时间延迟是一种很强大的技术,Web服务器虽然可以隐藏错误或数据,但必须等待数据库返回结果,因此可用它来确认是否存在SQL注入.该技术尤其适合盲注. 源码解释 代码位置:在checkSqlInjection函数中

mysql基于“时间”的盲注

无需页面报错,根据页面响应时间做判断! mysql基于时间的盲注 ====================================================================================================================================================================== * 猜解库名 - 下面是猜解正确 mysql> select sleep(1) from (sele