需求是这样的, 要用 canvas 画出心电图,后端 1 秒给我传 1 个数组,数组里有 250 个数据 结构是这样的 https://nas-1253716007.cos.ap-guangzhou.myqcloud.com/mmexport1591493767956.png 但是呢,实际效果就是,渲染速度跟不上后端给我数据的速度。 我是用了 requestAnimationRequest 来循环渲染数据的。 想了一下,1 秒渲染 250 个数据,不就是 250 帧了吗,普通的屏幕才 60hz 的刷新率,感觉不可能做到的啊
1 zhouchijian OP 格式怎么乱掉了。。。 |
![]() | 2 qiayue PRO 抽稀 |
![]() | 3 qiayue PRO 合并、取样、抽稀 |
![]() | 4 imdong 2020-06-07 09:47:40 +08:00 应该是一秒一帧,如何做到尽可能少的绘制。 看了你的格式,起码 0-36 这样的数据可以压缩为一次操作? 应该是类似折线图吧?最简单的能给出的意见就是这样。 连续在 dom 上绘制 速度比较慢,能不能把操作在内存绘制好,然后放到 dom 上呢? 一秒钟渲染一张图片应该问题不大,具体我也不懂,业余人士瞎比比。 |
![]() | 5 cornetCat 2020-06-07 09:51:34 +08:00 1 秒渲染 250 个数据,不就是 250 帧了吗 这不对吧 想达到 60fps,应该是 1/60s 内渲染完 250 个数据 |
![]() | 6 Perry 2020-06-07 09:52:37 +08:00 需求完全没说清楚,请先说清楚这 250 个数据是什么数据,需求是什么 |
![]() | 7 MoHen9 2020-06-07 09:55:29 +08:00 via Android 每次多绘制几个点就行,人眼看不出来区别的,我在 Android 上也是这样做的,我们用 C++做的客户端也不会一次只绘制一个点,采样率有可能是 1000/s,难道也要每秒绘制 1000 次? 楼上方法也可以 |
8 hakono 2020-06-07 09:58:18 +08:00 via Android 我看你这数据,感觉是一秒渲染一次啊 如果后端给你的数据是每帧数据,先不提渲染赶不赶得上,你显示器首先刷新率绝对就没有 250Hz 吧,就算真渲染出了 250fps,你这也是没有任何用处啊。直接 250 个数据每隔 10 个取一个数,渲染成 25fps 人眼都感觉不太出区别 |
![]() | 9 binux 2020-06-07 10:00:28 +08:00 250 个标量?别说 250 个了,25000 个都没问题 |
10 whileFalse 2020-06-07 10:00:33 +08:00 ![]() 大哥,一秒传你一次数据,其中包含 250 个数,那其实是 1hz 啊……只不过每次屏幕更新要在已有数据基础上绘制 250 个点而已。如果忽略数据处理、网络传输、绘制等时间,数据从收集到展现的平均时间是 0.5s 。 当然,用户可以觉得这种仿照微软 windows 任务管理器的更新速度不够接地气,并愿意加一倍的钱让他更新速度变快。那你就可以每秒钟绘制 2 帧( 2hz ),并每帧绘制 125 个点。依照这种思路,只要用户肯出 60 倍的钱,你就可以每秒绘制 60 次,每次绘制 4 个点或 5 个点。你可以以 settimeout 方式执行每秒多次绘制。 如果用户肯出 100 倍的钱一劳永逸地完美地解决这个问题,那你就用 requestAnimationRequest 吧。你可以很简单地计算出上一次执行到本次执行之间用了多少毫秒,然后除以 4 (即 1000/250 ),得出你本次应该绘制的点的数量。此外,你还应该对上次绘制的图进行平移。 |
11 zhouchijian OP |
12 zhouchijian OP ![]() @MoHen9 有道理,每次只绘制一个点太蠢了 |
![]() | 13 zhugefubin 2020-06-07 10:25:52 +08:00 via Android 一下绘制一组数据不行么 |
![]() | 14 binbinyouliiii 2020-06-07 10:27:33 +08:00 4K 显示器有 3840*2160 个像素点,岂不是有 3840*2160 的刷新率 |
15 zhouchijian OP @imdong 其实就是折线图,但是要求有动画效果,就是类似于那种扫描效果,现在是每次只绘制一个点,你说的对,应该尽可能少的绘制 |
16 zhouchijian OP @zhugefubin 我也想这么简单粗暴,但是要有动画效果 |
![]() | 17 7gugu 2020-06-07 10:58:19 +08:00 via Android 不考虑一下现有的图表库么?比如 Echarts 和 Uchart 等. |
![]() | 18 reus 2020-06-07 10:59:20 +08:00 你一秒渲染多少帧,和屏幕刷新率有什么关系? 那些游戏一秒几十几百帧,为什么可以显示? 一辆车从你眼前开过,你眨一下眼睛,难道车会根据你眨眼睛慢了,速度就变了? 显示器就是你的眼睛,只是在采样观察外部世界,而外部世界并不会受你的眼睛影响。 |
![]() | 19 zhugefubin 2020-06-07 11:20:14 +08:00 via Android 我对这个不是很懂 @zhouchijian |
![]() | 20 abelce 2020-06-07 11:36:07 +08:00 via iPhone 你一秒渲染一次就可以了呀,我以前渲染几十万个点都没毛病 |
21 zhouchijian OP @reus 对喔。。难道是我理解错刷新率了 |
22 zhouchijian OP @7gugu 不给用 echarts,原因我也不知道 |
23 zhouchijian OP @abelce 不行,要有动画,一秒渲染一次就没动画了 |
24 jackmod 2020-06-07 12:19:18 +08:00 markdown 要 2 次换行才是新段落,发之前点一下预览 |
![]() | 25 reus 2020-06-07 12:57:34 +08:00 via Android @zhouchijian 动画的话,每秒渲染 30 次左右就够了,也就是 256/32,每次渲染 8 个点,每 1000/32ms 渲染一次 |
![]() | 26 reus 2020-06-07 12:58:28 +08:00 via Android @zhouchijian 一秒一次就是 1hz 的动画,怎么叫没有? |
![]() | 27 rockjike 2020-06-07 13:29:25 +08:00 via Android 一桢更新 10 个数据,一个周期不一定要 1s,可以先把后端数据储存起来 |
![]() | 28 Cabana 2020-06-07 13:37:52 +08:00 via Android 1 秒 250 个数据分成 25 帧,一帧绘制 10 个数据不行吗? |
29 nightv2 2020-06-07 13:55:00 +08:00 via Android 比如说每秒在内存中把 250 个数据生成一个折线图,然后和上一秒的折线图做一个带有动画效果的切换,切换应该是有现成的轮子的 |
![]() | 30 javaluo 2020-06-07 14:39:24 +08:00 via Android 每秒渲染一次,弄一个遮罩平行移动展示出来不就行了? |
31 aturx 2020-06-07 14:49:38 +08:00 via Android 同事做过类似的,要动画效果,可以传数据的时候可以几秒传一组数据,渲染的时候频率高点持续渲染。 |
![]() | 32 justin2018 2020-06-07 16:23:48 +08:00 |
33 zhouchijian OP @justin2018 对,就是这种效果 |
34 zhouchijian OP ![]() |
35 sarlanori 2020-06-07 16:39:01 +08:00 via Android 这个和我们绘制频谱图波形图是一样的,你这个相当于一秒一帧,一帧数据有 50 个点,你只需要连续绘制就可以了,每次数据来了就把可视区域内的数据重新绘制,自然就有了动态效果。 |
36 ghostheaven 2020-06-07 16:39:36 +08:00 via Android 动画和绘制的时间精确控制在一秒,开始的时候缓存几秒数据再开始 |
![]() | 37 Torpedo 2020-06-07 16:41:55 +08:00 你延迟一秒画。 不就变成你有 250 个数据,然后在 1s 里,60 帧,每帧画 4 个。 |
![]() | 38 reus 2020-06-07 20:25:19 +08:00 @zhouchijian 闪瞎眼……不要每次都重绘,做一下平移,然后渲染新的点就行了。这么闪,还不如用 svg,至少不闪…… |
![]() | 39 jiejiss 2020-06-07 20:52:16 +08:00 动画效果 30Hz 足够用了,你每帧绘制 8 - 9 个点就行 但是 requestAnimationFrame 每帧之间的间隔不一定一样,比如设备卡了上一个 frame 和下一个 frame 之间间隔 1s 怎么办?所以你可以整个全局数组,拿 setInterval 以固定的频率(比如 30Hz )往里 push 数据,然后在 requestAnimationFrame 里把这个数组里的全部数据消费掉 |
40 jakezh 2020-06-07 22:08:24 +08:00 那我这种一秒渲染 50 万个数据的怎么算帧率? |
41 zhouchijian OP @jakezh 那老哥你是怎么解决这种问题的 |
42 zhouchijian OP @reus 闪应该是正常的。。因为我每帧都绘制 10 个点了。。每 16ms 绘制一次,改成每帧绘制 4 个点就舒服多了。。至于 svg,刚开始我也想用 svg 的,因为项目的老代码也是用 canvas 来做心电图的,然后时间紧,就想着继续用 canvas,没有用 svg,因为以前也没写过 svg 。。 |
![]() | 43 cheng6563 2020-06-07 23:05:34 +08:00 via Android 双缓冲,就不会闪了。。。。这不是基本操作吗 |
44 zhouchijian OP @cheng6563 不清楚耶,第一次搞这种图表 |
![]() | 45 reus 2020-06-07 23:55:24 +08:00 @zhouchijian 用双缓冲: https://stackoverflow.com/questions/2795269/does-html5-canvas-support-double-buffering 就是不要直接清空,而是在另一个 canvas 里更新,更新完了再切换,就不会闪了 |
![]() | 46 wangcheng 2020-06-08 00:33:58 +08:00 不应该假设 requestAnimationFrame 每 16ms 绘制一次,应该用 requestAnimationFrame 回调中的第一个参数时间戳来计算动画。否则帧率不是 60 的时候动画速度就乱了。 |
![]() | 47 weixiangzhe 2020-06-08 09:35:17 +08:00 via Android 按比例采样吧, |
![]() | 48 redbuck 2020-06-08 14:27:03 +08:00 渲染和生成路径(即更新 view model)分开. 生成路径随便 push. 渲染按照固定频率把路径绘制到 canvas 上. |
49 jakezh 2020-06-08 21:37:24 +08:00 我是先渲染上,然后按照鼠标事件加动画。 没有你这种每秒全局刷新的需求 |