前端性能优化:Canvas

前端性能优化:Canvas,第1张

Canvas 最常见的用途是渲染动画,目前,所有的主流浏览器都支持。

渲染动画的基本原理,无非是反复地擦除和重绘。为了动画的流畅,60Hz 刷新率设备的帧预算为 16.67ms,在这个时间之内,计算每个对象的位置、状态,还需要把它们都画出来。高刷设备的帧预算更低。所以需要时刻关注性能,防止计算和绘制耗时过长造成卡顿。

基础优化

1. 在离屏canvas上预渲染相似的图形或重复的对象

对于在每个动画帧上的重复相同的绘制 *** 作,请考虑将其分流到屏幕外的画布上。然后根据需要频繁地将屏幕外图像渲染到主画布上,而不必首先重复生成该图像的步骤。

myEntity.offscreenCanvas = document.createElement("canvas");
myEntity.offscreenCanvas.width = myEntity.width;
myEntity.offscreenCanvas.height = myEntity.height;
myEntity.offscreenContext = myEntity.offscreenCanvas.getContext("2d");

myEntity.render(myEntity.offscreenContext);

2. 避免浮点数的坐标点,用整数取而代之

当画一个没有整数坐标点的对象时会发生子像素渲染。 浏览器为了达到抗锯齿的效果会做额外的运算。为了避免这种情况,请保证调用drawImage()函数时,用 Math.floor()函数对所有的坐标点取整。

ctx.drawImage(myImage, Math.floor(2.05), Math.floor(4.01));

3. 不要在用drawImage时缩放图像

在离屏canvas中缓存图片的不同尺寸,而不要用 drawImage()去缩放它们。

4. 使用多层画布去画一个复杂的场景

若​​某些对象需要经常移动或更改,而其他对象则保持相对静态,可能的优化是使用多个元素对您的项目进行分层。


  
  
  
  
  
  


5. 大背景图用CSS设置

为了避免在每一帧在画布上绘制大图,可以用一个静态的元素,结合background 特性,以及将它置于画布元素之后。

6. 用CSS transforms特性缩放画布

CSS transforms 使用GPU,因此速度更快。最好的情况是不直接缩放画布,或者具有较小的画布并按比例放大,而不是较大的画布并按比例缩小:

const scaleX = window.innerWidth / canvas.width;
const scaleY = window.innerHeight / canvas.height;

const scaleToFit = Math.min(scaleX, scaleY);
csont scaleToCover = Math.max(scaleX, scaleY);

stage.style.transformOrigin = '0 0'; // scale from top left
stage.style.transform = 'scale(' + scaleToFit + ')';

7. 关闭透明度

若使用画布而且不需要透明,当使用 HTMLCanvasElement.getContext() 创建一个绘图上下文时把 alpha 选项设置为 false 。这个选项可以帮助浏览器进行内部优化:

const ctx = canvas.getContext('2d', { alpha: false });
画布渲染优化

1.  局部渲染缓存

进行局部渲染时,判断需要局部渲染的图形是否在视窗内可以极大加速渲染速度,而裁剪可以进一步分为分组的裁剪和图形的裁剪,而且需要缓存一些计算中间结果:

从画布->分组...-> 分组 到当前图形总的矩阵

图形在画布上的包围盒

图形当前是否在视窗内

单个图形发生过局部渲染,可以记录下受影响的图形,下次重新发生局部渲染可以直接使用缓存。本质上是缓存同单个图形相交的图形(成本太大,可以做渐进式缓存)

缓存一个时间段(16ms)内需要局部渲染的图形,进行一次统一的局部渲染

增加缓存可以有效提升渲染速度,但是当图形属性、父元素属性发生变化时清理缓存,这会增加额外的成本。

2. 是否放入局部刷新的队列

如果图形发生改变,首先检查其父元素是否发生改变,如果父元素发生改变,则不放入刷新队列中。因为父元素的改变在前时,已经加入刷新队列,或者其父元素的父元素已经在队列中。
如果图形变化前和变化后都不在视窗内,则也不应该放入刷新队列。

3. 减少包围盒的比对

​​​​​​​​​​​​​​如果元素未发生变化,则检测缓存的包围盒是否相交,如果不相交则停止检测。如果相交则递归检测其子元素是否同刷新的视窗相交。

4. 减少 Group 渲染

从循环遍历图形一轮,改成遍历两轮,第一轮先给每个 group,每个图形打标 refresh,如果有 refresh 标记第二次循环是绘制,否则跳过。

5. 控制渲染的频率

常用的技术主要有:debounce 和 throttle,保证 16ms 内必须要渲染一次。即在一段时间 16ms 内调用 n 次渲染,仅渲染最后那一次(方案1)或者渲染第一次和最后一次(方案2)。

优缺点:

方案1 相同时间内绘制的帧数低,如果在数据量非常大的情况下拾取时间 + 16ms 的延迟,能够出现明显的卡顿效果,两次渲染中间给交互留出了响应时间。

方案2 保证马上绘制:在测试时方便,不需要进行延迟测试;动画的执行也比较准确,绘制帧率高,相同时间内能够渲染的帧数要比第二种方案高

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/938109.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存