主题
11 · Canvas 与 2D 可视化入门
目标:说清自绘 Canvas 与图表库的取舍;处理坐标与高清屏 DPR;能画一个最小 demo。
1. 背景与目标
手帐导出、海报、简单波形图,常碰到 2D 绘制。先分清:用 ECharts 等库,还是自己上 Canvas。
| 场景 | 更合适 |
|---|---|
| 标准图表、交互提示、主题 | 图表库 |
| 像素级海报、自定义排版导出、游戏感绘制 | Canvas / 设计稿栅格 |
| 大量点实时刷新 | Canvas(或 WebGL) |
2. 核心概念
text
canvas 像素缓冲 ←→ 用 ctx 画路径/图/字
CSS 显示尺寸 ≠ 内部像素尺寸(DPR 要对齐)1
2
2
高清屏:
js
const dpr = Math.min(devicePixelRatio, 2)
canvas.width = cssWidth * dpr
canvas.height = cssHeight * dpr
canvas.style.width = cssWidth + 'px'
canvas.style.height = cssHeight + 'px'
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)1
2
3
4
5
6
2
3
4
5
6
之后按 CSS 像素坐标 画即可。
3. 最小实践
html
<canvas id="c"></canvas>
<script>
const canvas = document.getElementById('c')
const ctx = canvas.getContext('2d')
const W = 320, H = 180
const dpr = Math.min(devicePixelRatio, 2)
canvas.width = W * dpr
canvas.height = H * dpr
canvas.style.width = W + 'px'
canvas.style.height = H + 'px'
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
ctx.fillStyle = '#f5f5f5'
ctx.fillRect(0, 0, W, H)
ctx.fillStyle = '#333'
ctx.font = '16px sans-serif'
ctx.fillText('hello canvas', 24, 40)
ctx.strokeStyle = '#4ea1ff'
ctx.lineWidth = 2
ctx.strokeRect(24, 60, 120, 80)
</script>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
导出图:canvas.toDataURL('image/png')(注意跨域污染)。
4. 踩坑与取舍
- 糊:忘了乘 DPR。
- 越画越慢:每帧全清 + 重绘全部;大数据要脏矩形或分层。
- 无障碍:Canvas 对读屏不友好,关键信息要有 DOM 旁路。
- 和 DOM 混排:事件坐标要减
getBoundingClientRect。
5. 验收清单
- [ ] 能说清何时用库、何时自绘
- [ ] 跑通高清文字/矩形 demo
- [ ] 知道
toDataURL与跨域限制 - [ ] (可选)对照 Journal 导出预览想一层:DOM 排版 vs Canvas 光栅
