# Canvas

# Canvas 面试总览:位图画布、状态机与工程边界

⚡ 30 秒速记

  • Canvas 是即时模式的位图画布:浏览器只保留像素,不保留圆、线、文本这些可查询的图形对象
  • 一次绘制由「设置状态 → 建路径 → 描边或填充」组成;save() / restore() 管理的是绘图状态栈,不是像素快照
  • 高清屏模糊的根因是位图像素不足:位图尺寸乘 devicePixelRatio,再缩回 CSS 尺寸并缩放坐标系
  • 动画要在每帧执行「更新状态 → 清屏 → 重绘」,通常用 requestAnimationFrame,离屏后要暂停并释放资源
  • 大量动态图元、像素处理适合 Canvas;需要节点语义、无障碍和逐元素事件时优先 SVG / DOM

Canvas 本质上是即时绘制的位图画布,浏览器保留的是像素,而不是可查询的图形节点。 绘制通常是设置状态、建立路径再执行 fill()stroke()save()restore() 管理绘图状态,并不会保存像素。高清屏要同时处理位图尺寸、CSS 显示尺寸和 devicePixelRatio,动画则用 requestAnimationFrame 持续清屏重绘。大量动态图元适合 Canvas,需要节点语义、无障碍或逐元素事件时更适合 SVGDOM

CanvasRenderingContext2D 可以看成一台带状态的画笔。fillStylestrokeStyle、变换矩阵、裁剪区等属性会影响之后的命令;beginPath() 只会清空当前路径,不会擦除画布像素,真正落笔要调用 fill()stroke()。这也是常见 bug 的来源:忘记 beginPath() 会把旧子路径再次描边,忘记 restore() 会让缩放、透明度继续污染后续绘制。

工程里通常把「数据状态」作为事实来源,而不是试图从像素里还原对象。以拖拽图形为例,需要在 JavaScript 中保存每个图形的位置和命中区域,指针移动时自己做 hit test,然后清屏并按新状态完整重绘。复杂场景可以把静态背景画到离屏画布,只重绘变化层;像素计算可交给 Web WorkerOffscreenCanvas,但主线程上的 DOM 事件和最终合成仍要纳入性能预算。

高清适配必须区分两种尺寸:canvas.width/height 决定位图缓冲区,style.width/height 决定页面显示大小。只写 CSS 尺寸会把较少的物理像素拉伸;只放大位图又不缩放坐标系,会让逻辑尺寸改变。上面的实验会真实读取当前设备的 devicePixelRatio、重建 backing store,并从绘制结果采样像素,能直观看出两条路径的差别。

💬 面试官追问

  • 代码里连续画两条独立折线,第二次调用 stroke() 时第一条线又被描了一遍;同事认为 stroke() 后路径会自动清空,你怎么判断?

    stroke() 只把当前路径描到位图上,不会清空路径,因此旧子路径仍会参与下一次描边。每组独立路径应在构造前调用 beginPath();它只重置当前路径,不会清除已经落到画布上的像素。

  • 一个流程图编辑器支持拖拽节点,产品要求刷新重绘后节点仍可命中,你会把节点位置和选中状态存在哪里?

    节点位置、层级和命中区域应保存在 JavaScript 数据状态中,像素只作为状态的绘制结果。指针事件先做 hit test,再更新数据并清屏重绘;若试图从画布像素反推业务对象,会丢失语义且难以维护交互状态。

  • 监控大屏的静态底图很复杂,只有少量指标每帧变化;如果整张画布重绘已经挤占主线程,你会先改哪一层?

    我会把静态背景预绘到离屏画布,更新时复用它,只重绘动态层并完成合成。像素计算较重时可评估 Web WorkerOffscreenCanvas;但 DOM 事件处理和最终合成成本仍需测量,不能假设移出部分计算就消除了主线程压力。

  • 组件库统一执行了 ctx.scale(2, 2),随后同一上下文中的透明度和裁剪区域也异常影响后续组件,你会怎样定位状态泄漏?

    先检查每段局部绘制是否用 save()restore() 成对包住变换、透明度及裁剪设置,并确认异常路径没有提前返回而漏掉恢复。CanvasRenderingContext2D 是有状态画笔,属性会持续影响后续命令;仅调用 beginPath() 无法恢复这些状态。

  • 设计师要求签名板在 2x 屏清晰,但导出文件必须保持固定逻辑尺寸,你会怎样处理显示和导出的冲突?

    显示时把 canvas.width/height 设为 CSS 尺寸乘 devicePixelRatio,保留原 CSS 尺寸,并用 setTransform() 将逻辑坐标统一回来。固定逻辑尺寸的导出应另行绘制或缩放到目标缓冲区;直接导出高清 backing store 会得到更大的物理像素图。

  • 地图上两万个点要支持 hover,交互负责人坚持使用 Canvas,无障碍负责人希望每个点都能键盘聚焦,你会怎么拆解选型?

    Canvas 可通过网格、四叉树或颜色拾取降低命中成本,但不会天然提供每个点的 DOM 语义和键盘焦点。若逐点可访问性是硬约束,应评估 SVGDOM 或分层混合方案;选择语义节点会增加节点管理成本,却能避免自行重建整套交互语义。

webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
折叠侧边栏
收起全部