跳到主要内容

Canvas 库怎么选

选型的困难不在于不了解这些库,而在于没有先把需求拆成可判定的维度。 「哪个 Canvas 库最好」没有答案,「上千个可拖拽元素、要导出高清图、不需要 WebGL」有。

先确定三个维度​

这三个问题的答案基本就决定了结论,其余都是次要因素。

① 要不要交互? 具体指:点击、悬停、拖拽、缩放旋转控件、框选。 只要有其中任何一项,你就需要命中检测,也就需要一个保留模式的场景图。 没有任何一项,直接用原生 API 或图表库,不要引入任何 Canvas 框架。

② 同屏图形的数量级是多少? 十、千、还是万。 这个数字决定渲染后端:几十到几百,Canvas 2D 绰绰有余; 上千要开始做缓存和分层;上万基本只能走 WebGL。 注意数的是同屏,不是总数——虚拟化之后只渲染视口内的,量级会掉一个档。

③ 要不要 GPU? 指着色器、粒子、大量半透明叠加、实时滤镜。 需要就只能 WebGL;不需要就别为它付出复杂度。

逐个方案的适用边界​

渲染后端保留模式内置变换控件体积量级典型场景
原生 CanvasCanvas 2D否无0静态图形、一次性绘制
SVGDOM是(就是 DOM)无0图标、可访问性要求、元素少
KonvaCanvas 2D是Transformer百 KB 级可交互画布、标注、白板、编辑器内核
Fabric.jsCanvas 2D是内置百 KB 级开箱即用的图形编辑器
PixiJSWebGL(回退 2D)是无百 KB 级游戏、粒子、万级精灵

几条表里放不下的分界线:

Konva 与 Fabric 的区别不是功能多少,是产品形态的归属权。 Fabric 把「图形编辑器该长什么样」这件事替你决定了——选中框、控制点、 自由绘制、SVG 导入导出都是内置且有既定外观的。你要做的编辑器如果长得 跟它想的一样,会非常快;如果不一样,你会花更多时间去改它而不是去写它。 Konva 给的是 Transformer 这样一个可完全自定义外观的部件, 其余交互逻辑由你写。先想清楚你的产品是不是标准形态的编辑器。

PixiJS 的 WebGL 不是免费的性能。 它在万级精灵时压倒性领先, 但在几百个元素时未必比 Canvas 2D 快——上传纹理、切换批次同样有开销。 而且它引入了两个 Canvas 2D 没有的问题:文本要先渲染成纹理 (中文字体尤其占显存),以及上下文丢失需要自己恢复。

SVG 的拐点比多数人想的要早。 不是「元素上万才慢」, 而是元素上千且有动画时就会明显卡——每帧改属性都会触发样式重算与重绘。 静态的 SVG 几千个元素依然流畅。

常见问题​

万级图形应该选什么?​

先问一句:真的需要同屏一万个吗?

多数「万级」场景其实是总量一万、视口内只有几百。 这种情况做视口剔除(只把可见范围内的节点加进图层)比换渲染后端划算得多, Konva 完全能胜任。

如果确实要同屏上万个且都要动,那 Canvas 2D 会掉帧, 选 PixiJS。如果同屏上万但基本不动,Konva 也可以—— 把静态部分整体 cache() 成一张位图,绘制成本就跟数量无关了, 见 图形缓存。

介于两者之间的做法是在 Konva 里组合使用 listening(false)、 图层拆分与缓存,性能优化总览 把这些手段列在一起。

Fabric.js 和 Konva 到底差在哪?​

一句话:Fabric 是半成品的编辑器,Konva 是画布的运行时。

Fabric 内置了选中框、旋转控制点、自由绘制笔、SVG 的导入导出、 以及一套图形编辑器常见的默认交互。你 new fabric.Canvas() 之后 立刻就能拖能转,不用写一行交互代码。

Konva 不预设你要做什么。它给你场景图、事件系统、命中检测、 以及一个外观和行为都可改的 Transformer。选中逻辑、 快捷键、撤销重做、图层面板都要你自己写。

所以判断标准是:你的需求跟「一个通用图形编辑器」有多像。 很像就用 Fabric,省下的时间是实打实的;差得远——比如你做的是 医学影像标注、座位图、流程图这类有强领域约束的东西—— 那 Fabric 内置的那套反而要一件件关掉,不如从 Konva 开始。

已经在用 Fabric、打算换过来的,概念与事件的逐项对照见从 Fabric.js 迁移。

已经用了 ECharts / D3 还需要 Canvas 库吗?​

通常不需要。ECharts 内部就是 ZRender(一个 Canvas 渲染层), D3 也能直接操作 Canvas,它们已经把渲染管好了。

真正需要再叠一层的只有一种情况:你要在图表之上做自定义的可交互图层—— 比如让用户在 K 线图上画趋势线、在热力图上框选区域并拖动。 这时可以在图表画布上方叠一个透明的 Konva Stage 专门管标注层, 两者各管各的,通过坐标换算对齐。但要先确认图表库自身的 自定义图形能力(ECharts 的 graphic 组件)满足不了,再上这一层。

小程序 / 跨端环境能用吗?​

Konva 依赖标准的 DOM Canvas API 与 document.createElement('canvas'), 微信小程序的 canvas 不是标准 DOM 元素,不能直接用。 社区有适配层,但维护状态不稳定,上生产前务必确认。

React Native 同理,需要走 react-native-skia 这类方案。 Electron、Tauri 这些内嵌浏览器的环境则没有任何问题。

与其他方案的取舍​

把前面的维度串成一条可以直接走的决策路径:

  1. 不需要交互? → 原生 Canvas。别引入框架。
  2. 需要可访问性或 CSS 控制样式,且元素少于约一千? → SVG。 这是唯一能被屏幕阅读器读到的方案,在政府、医疗、教育类项目里 常常是硬性要求,没有商量余地。
  3. 同屏上万且都在动,或者需要着色器? → PixiJS。 接受它在文本与上下文丢失上的额外成本。
  4. 需求就是一个标准形态的图形编辑器? → Fabric.js。 先花半天用它的默认交互搭个原型,确认形态吻合再投入。
  5. 其余情况 → Konva。可交互、Canvas 2D 够用、 交互逻辑要自己定义——这是绝大多数业务画布的形态。

还有一条不在列表里但同样重要:选型要看维护状态。 这几个库都在活跃维护,但活跃程度不同,且都高度依赖少数几位核心维护者。 把一个画布库放进长期项目之前,去看一眼它最近半年的提交频率和 issue 响应速度, 这比任何功能对比都更能预测你三年后的处境。

Konva 本身的定位与它解决的核心问题,见 为什么选择 Konva。