H5 Canvas 高分屏绘制与动画
H5 Canvas 高分屏绘制与动画
摘要:Canvas 可以绘制图表、地图标注和互动动画,但 CSS 尺寸与位图尺寸不同,高分屏上容易模糊。本文介绍设备像素比处理、动画循环、尺寸变化、命中测试和性能控制。
一、区分 CSS 尺寸与位图尺寸
Canvas 元素的 CSS 尺寸决定页面布局,width 与 height 属性决定内部位图分辨率。高分屏设备需要更大的位图,再通过变换把绘图坐标维持在 CSS 像素:
function resizeCanvas(canvas, context, cssWidth, cssHeight) {
const ratio = window.devicePixelRatio || 1;
canvas.style.width = `${cssWidth}px`;
canvas.style.height = `${cssHeight}px`;
canvas.width = Math.round(cssWidth * ratio);
canvas.height = Math.round(cssHeight * ratio);
context.setTransform(ratio, 0, 0, ratio, 0, 0);
}
每次尺寸变化后都要重新设置变换矩阵,因为修改位图宽高会重置绘图状态。设备像素比过大时可设置上限,避免超大画布占用过多内存。
二、响应容器尺寸变化
容器尺寸可能因旋转、分屏和布局变化而改变。使用 ResizeObserver 观察绘图容器,在尺寸确实变化后调整位图并重绘。对于全屏 Canvas,还需考虑视口变化和安全区域的布局。
避免每次窗口滚动都执行昂贵重绘。尺寸回调中只记录最新尺寸,再通过一次动画帧更新,可以合并短时间内的多次变化。
三、使用 requestAnimationFrame
动画应由浏览器帧循环调度,页面不可见时可暂停:
let frameId = 0;
let previousTime = 0;
function frame(time) {
const delta = previousTime === 0 ? 0 : Math.min(time - previousTime, 50);
previousTime = time;
updateScene(delta);
drawScene(context);
frameId = requestAnimationFrame(frame);
}
function start() {
if (frameId === 0) frameId = requestAnimationFrame(frame);
}
function stop() {
cancelAnimationFrame(frameId);
frameId = 0;
previousTime = 0;
}
使用时间增量推进动画,避免帧率较高的设备上动画跑得更快。长时间切后台后限制 delta,防止物体突然跳跃。页面隐藏时停止循环,恢复后重新开始。
四、组织绘制状态
Canvas 的绘图状态是命令式的,填充色、变换、裁剪和合成模式会持续影响后续绘制。复杂绘制区域可配合 save() 和 restore() 隔离状态,避免某个图层的裁剪意外影响全画布。
绘制函数尽量根据明确的场景数据生成画面,不要让渲染逻辑偷偷改变业务状态。动画更新模型,绘制过程读取模型,两者分开后更容易调试和重放。
五、命中测试与坐标转换
鼠标和触摸事件通常给出视口坐标,绘图需要转换成 Canvas 局部坐标:
function canvasPoint(event, canvas) {
const bounds = canvas.getBoundingClientRect();
return {
x: event.clientX - bounds.left,
y: event.clientY - bounds.top,
};
}
如果场景应用了缩放、旋转或平移,还要将局部坐标通过逆变换映射到场景坐标。交互对象可维护包围盒或空间索引,避免每次点击遍历大量图元。
六、减少绘制成本
- 预先缓存不变的背景或复杂静态图层。
- 避免每帧创建大量临时对象和渐变。
- 只重绘变化区域,或把静态与动态内容分层。
- 根据实际显示大小控制位图分辨率。
- 大型场景优先使用视口裁剪和空间索引。
离屏 Canvas 可以将部分工作移出主线程,但需确认目标浏览器支持情况并提供回退路径。把绘制移出主线程不会自动解决数据同步或过量绘制的问题。
七、清理资源与提供替代内容
组件卸载时取消动画帧、断开 ResizeObserver 并移除事件监听。Canvas 中的关键信息应同时提供可访问的文本说明或 DOM 控件,不能让画布成为唯一的信息入口。可交互图表也要提供键盘可达的替代操作。
八、调试建议
检查 CSS 显示尺寸、位图宽高和设备像素比是否匹配;确认绘制状态重置;观察帧循环是否重复启动;用性能分析器判断时间花在脚本、绘制还是图片解码。性能测试应覆盖低端设备和较大场景。
九、总结
清晰的 Canvas 实现需要管理 CSS 尺寸与位图分辨率、让动画按帧调度、处理坐标变换并及时清理任务。将场景更新与绘制分离,再通过测量控制重绘范围,可以在高分屏和复杂交互中保持清晰与流畅。
- 点赞
- 收藏
- 关注作者
评论(0)