首先我们来说下
1. 十字光标是做什么用的。十字光标用来查看某一天或某一个时间点上对应的行情数据及各个窗口对应指标数据。
2. 哪些操作可以控制十字光标。键盘左右, 鼠标左右移动, 手机端手势的左右移动。
了解了这些, 我们就可以开始讲如何做十字光标了。
首先我们要解决的一个问题就是十字光标在左右移动的时候, 屏幕的重绘的问题。
假设目前屏幕上显示一个2000年-2018年的数据,一年我们算200个交易日(18*200=3600个数据), 我们就说一个主图吧。k线柱子 + MA5(线段) + MA10(线段)+ M20(线段)。也就是说十字光标每移动一下就需要绘制3600个柱子+3600点的线段3根。如果你们机器够好,GPU够快应该没什么问题, 但大部分一般的配置机器就会卡, 网页也一样。 那就是说鼠标移动的时候全屏重绘是一个不太好的解决方案。 解决这个问题我们首先要了解十字光标移动的时候,哪些UI是变动的,哪些UI是不变动的。看下图
用红框框出来的都是动态变动的,其他的都是不变的。
接下来解决方案的思路就是只重绘变动的数据, 其他的不重绘。这个需要结合各个语言和平台接口来制定具体的解决方案。以下是我所开发过的平台的解决方案,
1. c++ windows平台 (双缓存绘图这个是必须的就不说了)
把每个指标窗口分割成3部分, 下图有标识这3个部分
1. 框架内部具体的图形区域 (黄色框)
2. 框架外部具体的坐标刻度区域 (红色框)
3. 指标标题部分 (蓝色框)
看图2,3区域是需要重绘的, 1号区域是不要重绘了。那么windows有重绘部分区域的函数吗?
InvalidateRect/InvalidateRgn 可以通知窗口重绘部分区域 (https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-invalidaterect)
BeginPaint 可以获取到上面2个函数传递过来的重回的区域(https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-beginpaint)
通过上面的2个函数,十字光标移动的时候我们就重绘2,3区域。 哪还有一个十字线段是横跨图区区域,这个如何解决, 我们继续查api文档,
SetROP2 (https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-setrop2)这个函数提供一个异或绘制功能,也就是在原来的绘制十字线的地方再绘制一边就可以擦出掉,再在新的地方绘制十字线
ok . c++的完整的解决方案就全部给出来了。 (第3方框架的绘图本人没用过不清楚解决方案,只用过windows api绘图)
2. canvas H5 页面解决方案
由于canvas没有提供异或擦出线段的函数(我没找到, 如果你知道可以告诉我),所以十字光标移动就只能是全屏重绘了。那有什么方法可以绘制的快点呢?继续查找api文档
我们找到了 getImageData(),和putImageData() (https://developer.mozilla.org/en-US/docs/Web/API/ImageData) 这2个函数可以保存当前画布的数据和设置画布的数据。
方案: 第1次绘制
1) 绘制坐标和图形
2) getImageData() 把当前数据保存
3) 绘制指标标题
4)绘制十字光标
十字光标移动的时候
1) putImageData() 把上一次画的数据贴回去
2)绘制指标标题
3)绘制十字光标
3. 微信小程序解决方案
如果用h5页面的解决方案来做微信小程序,恭喜你, 你踩雷了,小程序比h5页面弱多了,wx.canvasPutImageData() 这个函数巨慢无比而且还有数据大小显示,太大的数据直接就报错。那这么版本,继续查api文档。
我们找到 wx.canvasToTempFilePath 这个函数可以把画布的信息保存到缓存文件 相当于h5的getImageData(), 然后再用drawImage() 把图片贴回去。
方案:
第1次绘制 (好在手机没有鼠标,所以十字光标只有在手势移动的时候才出现)
1) 绘制坐标和图形
3) 绘制指标标题 (可以画也可以不画看你自己了)
2) wx.canvasToTempFilePath () 把当前数据保存
手势移动十字光标
1)drawImage 把保存的缓存图片贴回去
2)绘制指标标题 (如果你们第1次是绘制的画, 你直接用背景色把标题区域绘制下,然后再写标题)
3)绘制十字光标
对了还漏了一个K线上的tooltip提示框信息
c++ windows上 创建一个非模态窗口,窗口透明度设置下, 十字光标移动的时候movewindows到对应为位置就可以。这个就不多说了
h5页面 用div来做这个比较快, 十字光标移动的时候把div移动到对应为位置就可以
移动端:最好使用画布画,使用div有些框架不支持操作dom, 你就会歇菜了,响应速度上也比用div快,就是开发麻烦。
最后一个问题 为什么K线的tooltip是用div ,但是指标的信息不用div做呢?
1. 位置的关系,K线的tooltip显示的位置可能会超出画图的区域,而指标信息是固定的位置不会超出画布区域
2. 速度上没有画布上直接画快。 div 设置数据(有些数据还需要根据数值来显示红或绿色这样还需要动态的绑定到css的元素)会消耗一点时间, pc端感觉不大,移动端会有延迟的感觉。
3. 第3放的小程序,可能都不允许你操作document的,微信小程序就是。 为了移动端更好的兼容,用画布画兼容性更好一点
实例代码:https://github.com/jones2000/HQChart
下一章 我们来讲下K线图