Canvas 与 SVG 的交互式图形对比
Canvas 和 SVG 使用不同的渲染模型。这种差异会影响性能、交互代码、可访问性和导出行为。
SVG 会将每个形状保留为一个 DOM 元素。浏览器工具和 CSS 可以检查每个元素。这种模型非常适合形状数量较少的图表。
Canvas 会将像素绘制到一个位图中。浏览器不会保留已绘制的形状。对于包含大量形状或需要频繁重绘的场景,Canvas 通常表现更好。
| 要求 | 通常选择 |
|---|---|
| 每个形状都有可访问的 DOM 元素 | SVG |
| 每个形状都支持 CSS 选择器和 DOM 事件 | SVG |
| 大量频繁变化的形状 | Canvas |
| 像素编辑或图像滤镜 | Canvas |
| Canvas 上的保留式形状模型 | Konva |
这些选择并不是绝对的。请在用户使用的设备上测量真实场景。
原生 Canvas 的权衡
Canvas API 在 fillRect() 返回后不会记住这个矩形:
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
context.fillStyle = '#4dabf7';
context.fillRect(40, 40, 120, 80);
应用程序必须存储矩形数据。它还必须重绘场景并检测指针命中。
使用 Konva 添加对象模型
Konva 会在场景图中存储节点。每个节点都有属性、事件和方法。Konva 还会管理命中检测和重绘。
拖动此示例中的矩形:
import Konva from 'konva';
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: 360,
});
const layer = new Konva.Layer();
stage.add(layer);
const rectangle = new Konva.Rect({
x: 40,
y: 60,
width: 160,
height: 100,
fill: '#4dabf7',
stroke: '#1c7ed6',
strokeWidth: 3,
cornerRadius: 8,
draggable: true,
});
const label = new Konva.Text({
x: 40,
y: 20,
text: 'Drag the rectangle',
fontSize: 18,
fill: '#212529',
});
rectangle.on('dragmove', () => {
label.text(`Position: ${Math.round(rectangle.x())}, ${Math.round(rectangle.y())}`);
});
layer.add(label, rectangle);
Konva 不会为 canvas 形状创建可访问的 DOM 元素。请将必要的控件和内容保留在 HTML 中。为这些 HTML 元素添加键盘控件和可访问标签。
当每个图形元素都必须参与 DOM 时,请使用 SVG。当场景需要 Canvas 性能和交互式对象模型时,请使用 Konva。