JS前端以轻量fabric.js实现示例理解canvas

作者:交互手记时间:2026-10-25 17:15:54浏览:635

本文通过fabric.js库深入解析Canvas绘图机制,介绍其对象模型如何简化交互与状态管理。文章涵盖Canvas基础API、save/restore栈结构原理及数据驱动视图思想,旨在帮助开发者系统掌握Canvas可视化开发技巧,为后续实现复杂图形交互奠定基础。

缘起

近期计划系统学习 canvas 技术,因此选取了一个相关库进行调研。原本构思撰写一两篇文章作为总结,但发现涉及内容较为庞杂,于是决定将其拆分为系列文章,预计包含十余章节,大致目录结构如下:

缘起

目前约完成了 80% 的草稿编写,后续将每周整理并发布一篇。

目前关于 canvas 的系统性资料相对匮乏,多数内容仅为 API 教程(适合入门)或特定效果实现(易学难记),导致知识体系显得零散,难以形成关联。

此前在学习相关技术时也曾感到迷茫,不知从何入手,但 fabric.js 库确实能作为切入点,帮助开发者进入 canvas 的开发领域。

若希望向可视化方向深入发展,该系列文章将提供有益帮助。

fabric.js 初体验

Canvas 功能强大,可创建各类图形与特效,但其原生 API 仅负责绘制,若需实现交互或修改画布内容,操作较为繁琐。fabric.js 为 Canvas 补充了缺失的对象模型,负责管理画布状态与渲染,允许开发者直接通过对象操作画布,大幅简化开发流程。未接触过 fabric.js 的读者建议访问官网体验效果,此处提供一张动图供参考:

缘起

本系列文章将逐步演示如何实现上述效果,虽篇幅精简但涵盖核心功能。尽管讲解重点在于 fabric.js 的实现原理,但实质涉及 Canvas 的基础知识,掌握本系列后,再学习其他 Canvas 库将更加顺畅。

鉴于部分读者可能未尝试过 fabric.js,此处简要介绍其基本用法:

// 第一步:初始化画布
const canvas = new fabric.Canvas('canvas');
// 第二步:创建物体
const rect = new fabric.Rect({
    top: 200,
    left: 100,
    width: 100,
    height: 100,
    fill: 'green',
});
// 第三步:向画布中添加物体,调用 add 才会绘制到画布中
canvas.add(rect);
// 第四步:让物体动起来
rect.animate(
    { top: 50, left: 400, angle: 45 },
    { duration: 1000, onChange: canvas.renderAll.bind(canvas) }
);

仅需少量代码即可在 Canvas 中绘制绿色矩形并实现动画效果,同时默认支持平移、旋转、缩放三种变换操作,非常适用于编辑与交互场景。

fabric.js 的大体结构

fabric.js 具体包含哪些内容?引入库后,可在控制台打印 fabric 对象查看:

缘起

结果可见 fabric 命名空间下挂载了众多类与方法,此处截取部分源码截图:

缘起

源码结构与控制台输出基本一致。fabric.js 源码结构清晰,几乎每个文件对应一个类,层次分明且注释丰富(英文)。通过类名可推测其功能。我们将实现其核心部分并讲解具体设计思想,大致结构如下:

缘起

此处提供最终实现版本的效果图:

缘起

若缺乏相关经验,可能会产生诸多疑问,例如:

  • 如何判断物体被点选和框选
  • 变换操作怎么搞
  • 动画怎么弄
  • 怎么分组
  • 如何扩展
  • 要啥数学知识
  • ... 那就让我们带着问题一起学习吧🚗。

canvas 能干嘛?

鉴于部分读者对 Canvas 接触较少,此处简要回顾其基础知识。实际上 Canvas API 数量有限,类似 HTML 标签,常用功能不多。若未接触过,常觉得复杂难学,但只需明确其功能即可🤔:

  • 它能画圆弧、矩形、图片、文本、线段、贝塞尔曲线、svg
  • 绘制时可设置多种属性,主要涉及线宽、填充色、描边色,掌握这两点即可,其余全靠想象力,例如:
  • 你要画一个圆就用圆弧来画
  • 你要画一个点就用一个很小的圆来画
  • 你要画一个多边形,那就用多条线段相连
  • 你要画一个很长的曲线,那就用多段贝塞尔曲线相连,或者用多段很小很小的线段以直代曲
  • 你要画个图表,那就得一笔一笔慢慢画,比如雷达图就是一堆圆圈和一个多边形组成
  • 当然最好配合上图片,这样能让 canvas 看起来更加多姿多彩
  • ... 另外你还要知道 canvas 虽然是个标签,但它其实就是一幅画,画完的东西是不可改的,只能覆盖或者重新画;也无状态,canvas 并不知道你画的是啥,也不知道你鼠标点的是哪个物体,要是想稍微修改下画布上面物体的大小或者让物体动起来,那一定是要清除(整个或局部)画布再重新绘制的。 然后再说几个注意事项:
  • 画新的几何图形和线条之前最好都要调用一下 beginPath,不然前后两个图形可能会相互影响,这是个好习惯。
  • save() 和 restore() 一定要配对使用,这也是个好习惯。
  • 善于运用 transform 的三种变换,以后的章节会讲解到。

这里简单扩充下 save 和 restore 这个知识点,因为一开始我们可能会对这个 api 的用法比较迷茫。一般来说 canvas 上面的东西是一个一个绘制的,每个东西有自己的状态,以 lineWidth(线宽) 和 strokeStyle(描边色) 为例子:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// ... 这里如果有绘制东西,用的是默认值
ctx.save(); // ---------①开始----------↓
ctx.lineWidth = 1;
ctx.strokeStyle = 'red';
ctx.strokeRect(0, 0, 20, 20);
  ctx.save(); // ----------②开始---------↓
  ctx.lineWidth = 2;
  ctx.strokeStyle = 'green';
  ctx.strokeRect(20, 20, 20, 20);
    ctx.save(); // ----------③开始----------↓
    ctx.lineWidth = 3;
    ctx.strokeStyle = 'blue';
    ctx.strokeRect(40, 40, 20, 20);
    // ... 这里如果有绘制东西,用的是③的状态
    ctx.restore(); // ---------③结束----------↑
    // ... 这里如果有绘制东西,用的是②的状态
  ctx.restore(); // ----------②结束---------↑
// ... 这里如果有绘制东西,用的是①的状态
ctx.restore(); // ----------①开始---------↑
// ... 这里如果有绘制东西,用的是默认值

效果大概是下面这个样子:

缘起

你可以把 save 和 restore 当做一对花括号🤯,所以它们得成对出现,每个括号里面是一种新的绘制状态,括号外面又是另一种状态。

它的本质是栈的结构(就是只能尾部添加或删除的数组),save 的时候会把当前的一堆状态属性保存起来(就是一个大对象),restore 的时候就是将栈顶的保存的状态拿出来置为当前的状态,看看下面这张图应该能比较好的理解👇🏻:

缘起

我自己觉得 canvas 的库大体都是数据驱动视图的一种很好体现,我们只负责单纯的修改数据(物体的各种属性状态值),canvas 只负责单纯的绘制,两者各司其职,互不干扰,也有点单向数据流的味道。

小结

本章简要介绍了 fabric.js 与 Canvas,作为系列首篇,后续文章正在筹备中。暂先提供简版 fabric.js 代码链接,目前仍在整理中。

以上就是JS前端以轻量fabric.js实现示例理解canvas的详细内容,更多关于JS前端轻量fabric.js canvas的资料请关注本站其它相关文章!

作者最新文章