zhouchijian
V2EX  ›  问与答

工作上有个需求, canvas 一秒渲染 250 个数据,不可能做到吧

  •  
  •   zhouchijian · Jun 7, 2020 · 7253 views
    This topic created in 2350 days ago, the information mentioned may be changed or developed.

    需求是这样的, 要用 canvas 画出心电图,后端 1 秒给我传 1 个数组,数组里有 250 个数据 结构是这样的 https://nas-1253716007.cos.ap-guangzhou.myqcloud.com/mmexport1591493767956.png 但是呢,实际效果就是,渲染速度跟不上后端给我数据的速度。 我是用了 requestAnimationRequest 来循环渲染数据的。 想了一下,1 秒渲染 250 个数据,不就是 250 帧了吗,普通的屏幕才 60hz 的刷新率,感觉不可能做到的啊

    49 replies  •  2020-06-08 21:37:24 +08:00
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020
    1
    格式怎么乱掉了。。。
    qiayue
    qiayue
    Jun 7, 2020
    2
    抽稀
    qiayue
    qiayue
    Jun 7, 2020
    3
    合并、取样、抽稀
    imdong
    imdong
    Jun 7, 2020
    4
    应该是一秒一帧,如何做到尽可能少的绘制。

    看了你的格式,起码 0-36 这样的数据可以压缩为一次操作?

    应该是类似折线图吧?最简单的能给出的意见就是这样。

    连续在 dom 上绘制 速度比较慢,能不能把操作在内存绘制好,然后放到 dom 上呢?

    一秒钟渲染一张图片应该问题不大,具体我也不懂,业余人士瞎比比。
    cornetCat
    cornetCat
    Jun 7, 2020
    5
    1 秒渲染 250 个数据,不就是 250 帧了吗
    这不对吧
    想达到 60fps,应该是 1/60s 内渲染完 250 个数据
    Perry
    Perry
    Jun 7, 2020
    6
    需求完全没说清楚,请先说清楚这 250 个数据是什么数据,需求是什么
    MoHen9
    MoHen9
    Jun 7, 2020 via Android
    7
    每次多绘制几个点就行,人眼看不出来区别的,我在 Android 上也是这样做的,我们用 C++做的客户端也不会一次只绘制一个点,采样率有可能是 1000/s,难道也要每秒绘制 1000 次?

    楼上方法也可以
    hakono
    hakono
    Jun 7, 2020 via Android
    8
    我看你这数据,感觉是一秒渲染一次啊
    如果后端给你的数据是每帧数据,先不提渲染赶不赶得上,你显示器首先刷新率绝对就没有 250Hz 吧,就算真渲染出了 250fps,你这也是没有任何用处啊。直接 250 个数据每隔 10 个取一个数,渲染成 25fps 人眼都感觉不太出区别
    binux
    binux
    Jun 7, 2020
    9
    250 个标量?别说 250 个了,25000 个都没问题
    whileFalse
    whileFalse
    Jun 7, 2020❤️3
    10
    大哥,一秒传你一次数据,其中包含 250 个数,那其实是 1hz 啊……只不过每次屏幕更新要在已有数据基础上绘制 250 个点而已。如果忽略数据处理、网络传输、绘制等时间,数据从收集到展现的平均时间是 0.5s 。

    当然,用户可以觉得这种仿照微软 windows 任务管理器的更新速度不够接地气,并愿意加一倍的钱让他更新速度变快。那你就可以每秒钟绘制 2 帧( 2hz ),并每帧绘制 125 个点。依照这种思路,只要用户肯出 60 倍的钱,你就可以每秒绘制 60 次,每次绘制 4 个点或 5 个点。你可以以 settimeout 方式执行每秒多次绘制。

    如果用户肯出 100 倍的钱一劳永逸地完美地解决这个问题,那你就用 requestAnimationRequest 吧。你可以很简单地计算出上一次执行到本次执行之间用了多少毫秒,然后除以 4 (即 1000/250 ),得出你本次应该绘制的点的数量。此外,你还应该对上次绘制的图进行平移。
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020
    11
    @hakono 怪我没说清楚,其实要的效果就是类似于扫描动画
    类似于这种
    http://pic.16xx8.com/allimg/110810/1A0303356-0.gif
    https://nas-1253716007.cos.ap-guangzhou.myqcloud.com/1591495891362.mp4
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020❤️1
    12
    @MoHen9 有道理,每次只绘制一个点太蠢了
    zhugefubin
    zhugefubin
    Jun 7, 2020 via Android
    13
    一下绘制一组数据不行么
    binbinyouliiii
    binbinyouliiii
    Jun 7, 2020
    14
    4K 显示器有 3840*2160 个像素点,岂不是有 3840*2160 的刷新率
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020
    15
    @imdong 其实就是折线图,但是要求有动画效果,就是类似于那种扫描效果,现在是每次只绘制一个点,你说的对,应该尽可能少的绘制
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020
    16
    @zhugefubin 我也想这么简单粗暴,但是要有动画效果
    7gugu
    7gugu
    Jun 7, 2020 via Android
    17
    不考虑一下现有的图表库么?比如 Echarts 和 Uchart 等.
    reus
    reus
    Jun 7, 2020
    18
    你一秒渲染多少帧,和屏幕刷新率有什么关系?

    那些游戏一秒几十几百帧,为什么可以显示?

    一辆车从你眼前开过,你眨一下眼睛,难道车会根据你眨眼睛慢了,速度就变了?

    显示器就是你的眼睛,只是在采样观察外部世界,而外部世界并不会受你的眼睛影响。
    zhugefubin
    zhugefubin
    Jun 7, 2020 via Android
    19
    我对这个不是很懂
    @zhouchijian
    abelce
    abelce
    Jun 7, 2020 via iPhone
    20
    你一秒渲染一次就可以了呀,我以前渲染几十万个点都没毛病
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    21
    @reus 对喔。。难道是我理解错刷新率了
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    22
    @7gugu 不给用 echarts,原因我也不知道
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    23
    @abelce 不行,要有动画,一秒渲染一次就没动画了
    jackmod
    jackmod
    Jun 7, 2020
    24
    markdown 要 2 次换行才是新段落,发之前点一下预览
    reus
    reus
    Jun 7, 2020 via Android
    25
    @zhouchijian 动画的话,每秒渲染 30 次左右就够了,也就是 256/32,每次渲染 8 个点,每 1000/32ms 渲染一次
    reus
    reus
    Jun 7, 2020 via Android
    26
    @zhouchijian 一秒一次就是 1hz 的动画,怎么叫没有?
    rockjike
    rockjike
    Jun 7, 2020 via Android
    27
    一桢更新 10 个数据,一个周期不一定要 1s,可以先把后端数据储存起来
    Cabana
    Cabana
    Jun 7, 2020 via Android
    28
    1 秒 250 个数据分成 25 帧,一帧绘制 10 个数据不行吗?
    nightv2
    nightv2
    Jun 7, 2020 via Android
    29
    比如说每秒在内存中把 250 个数据生成一个折线图,然后和上一秒的折线图做一个带有动画效果的切换,切换应该是有现成的轮子的
    javaluo
    javaluo
    Jun 7, 2020 via Android
    30
    每秒渲染一次,弄一个遮罩平行移动展示出来不就行了?
    aturx
    aturx
    Jun 7, 2020 via Android
    31
    同事做过类似的,要动画效果,可以传数据的时候可以几秒传一组数据,渲染的时候频率高点持续渲染。
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    33
    @justin2018 对,就是这种效果
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020❤️1
    34
    楼上各位老哥的意思我都懂,就是一次绘制多个点,不要只绘制一个点,抽空写了个小 demo

    https://jsrun.net/xM2Kp
    sarlanori
    sarlanori
    Jun 7, 2020 via Android
    35
    这个和我们绘制频谱图波形图是一样的,你这个相当于一秒一帧,一帧数据有 250 个点,你只需要连续绘制就可以了,每次数据来了就把可视区域内的数据重新绘制,自然就有了动态效果。
    ghostheaven
    ghostheaven
    Jun 7, 2020 via Android
    36
    动画和绘制的时间精确控制在一秒,开始的时候缓存几秒数据再开始
    Torpedo
    Torpedo
    Jun 7, 2020
    37
    你延迟一秒画。
    不就变成你有 250 个数据,然后在 1s 里,60 帧,每帧画 4 个。
    reus
    reus
    Jun 7, 2020
    38
    @zhouchijian 闪瞎眼……不要每次都重绘,做一下平移,然后渲染新的点就行了。这么闪,还不如用 svg,至少不闪……
    jiejiss
    jiejiss
    Jun 7, 2020
    39
    动画效果 30Hz 足够用了,你每帧绘制 8 - 9 个点就行

    但是 requestAnimationFrame 每帧之间的间隔不一定一样,比如设备卡了上一个 frame 和下一个 frame 之间间隔 1s 怎么办?所以你可以整个全局数组,拿 setInterval 以固定的频率(比如 30Hz )往里 push 数据,然后在 requestAnimationFrame 里把这个数组里的全部数据消费掉
    jakezh
    jakezh
    Jun 7, 2020
    40
    那我这种一秒渲染 50 万个数据的怎么算帧率?
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    41
    @jakezh 那老哥你是怎么解决这种问题的
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    42
    @reus 闪应该是正常的。。因为我每帧都绘制 10 个点了。。每 16ms 绘制一次,改成每帧绘制 4 个点就舒服多了。。至于 svg,刚开始我也想用 svg 的,因为项目的老代码也是用 canvas 来做心电图的,然后时间紧,就想着继续用 canvas,没有用 svg,因为以前也没写过 svg 。。
    cheng6563
    cheng6563
    Jun 7, 2020 via Android
    43
    双缓冲,就不会闪了。。。。这不是基本操作吗
    zhouchijian
    zhouchijian
    OP
    Jun 7, 2020 via Android
    44
    @cheng6563 不清楚耶,第一次搞这种图表
    reus
    reus
    Jun 7, 2020
    45
    @zhouchijian 用双缓冲: https://stackoverflow.com/questions/2795269/does-html5-canvas-support-double-buffering
    就是不要直接清空,而是在另一个 canvas 里更新,更新完了再切换,就不会闪了
    wangcheng
    wangcheng
    Jun 8, 2020
    46
    不应该假设 requestAnimationFrame 每 16ms 绘制一次,应该用 requestAnimationFrame 回调中的第一个参数时间戳来计算动画。否则帧率不是 60 的时候动画速度就乱了。
    weixiangzhe
    weixiangzhe
    Jun 8, 2020 via Android
    47
    按比例采样吧,
    redbuck
    redbuck
    Jun 8, 2020
    48
    渲染和生成路径(即更新 view model)分开.

    生成路径随便 push.

    渲染按照固定频率把路径绘制到 canvas 上.
    jakezh
    jakezh
    Jun 8, 2020
    49
    我是先渲染上,然后按照鼠标事件加动画。
    没有你这种每秒全局刷新的需求
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2114 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 95ms · UTC 11:19 · PVG 19:19 · LAX 03:19 · JFK 06:19
    ♥ Do have faith in what you're doing.