H5 Canvas 高分屏绘制与动画

举报
yd_290101916 发表于 2026/10/03 11:31:37 2026/10/03
【摘要】 H5 Canvas 高分屏绘制与动画摘要:Canvas 可以绘制图表、地图标注和互动动画,但 CSS 尺寸与位图尺寸不同,高分屏上容易模糊。本文介绍设备像素比处理、动画循环、尺寸变化、命中测试和性能控制。 一、区分 CSS 尺寸与位图尺寸Canvas 元素的 CSS 尺寸决定页面布局,width 与 height 属性决定内部位图分辨率。高分屏设备需要更大的位图,再通过变换把绘图坐标维持在...

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,
  };
}

如果场景应用了缩放、旋转或平移,还要将局部坐标通过逆变换映射到场景坐标。交互对象可维护包围盒或空间索引,避免每次点击遍历大量图元。

六、减少绘制成本

  1. 预先缓存不变的背景或复杂静态图层。
  2. 避免每帧创建大量临时对象和渐变。
  3. 只重绘变化区域,或把静态与动态内容分层。
  4. 根据实际显示大小控制位图分辨率。
  5. 大型场景优先使用视口裁剪和空间索引。

离屏 Canvas 可以将部分工作移出主线程,但需确认目标浏览器支持情况并提供回退路径。把绘制移出主线程不会自动解决数据同步或过量绘制的问题。

七、清理资源与提供替代内容

组件卸载时取消动画帧、断开 ResizeObserver 并移除事件监听。Canvas 中的关键信息应同时提供可访问的文本说明或 DOM 控件,不能让画布成为唯一的信息入口。可交互图表也要提供键盘可达的替代操作。

八、调试建议

检查 CSS 显示尺寸、位图宽高和设备像素比是否匹配;确认绘制状态重置;观察帧循环是否重复启动;用性能分析器判断时间花在脚本、绘制还是图片解码。性能测试应覆盖低端设备和较大场景。

九、总结

清晰的 Canvas 实现需要管理 CSS 尺寸与位图分辨率、让动画按帧调度、处理坐标变换并及时清理任务。将场景更新与绘制分离,再通过测量控制重绘范围,可以在高分屏和复杂交互中保持清晰与流畅。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。