[Canvas](http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html)可以让我们在网络上创造出绝对惊人的图形。但它提供的API是令人失望的。如果我们只想在画布上画几条基本的形状,不会觉得有什么繁琐。但是一旦需要任何形式的互动,任何时候改变图片或绘制更复杂的形状,代码复杂度会急剧增加。 Fabric旨在解决这个问题。 原生canvas方法只允许我们触发简单的图形命令,盲目的修改canvas的位图,想画一个矩形?使用`fillRect(left, top, width, height).`,想画一条线?使用`moveTo(left, top)`和`lineTo(x, y)`的组合命令,就好像我们**用刷子画画**,上层涂上越来越多的颜料,几乎没有控制。 Fabric不是在这么低的层次上运行,而是在原生方法之上提供简单而强大的对象模型。它负责画布状态和渲染,并让我们直接使用绘制后的“对象”。 让我们来看一个简单的例子来说明这个差异。假设我们想在画布上画一个红色的矩形。以下是我们如何使用原生的`<canvas>`API。 ~~~js // 有一个id是c的canvas元素 var canvasEl = document.getElementById('c'); // 获取2d位图模型 var ctx = canvasEl.getContext('2d'); // 设置填充颜色 ctx.fillStyle = 'red'; // 创建一个坐标100,190,尺寸是20,20的矩形 ctx.fillRect(100, 100, 20, 20); ~~~ 现在使用Fabric做同样的事情: ~~~js // 用原生canvas元素创建一个fabric实例 var canvas = new fabric.Canvas('c'); // 创建一个矩形对象 var rect = new fabric.Rect({ left: 100, top: 100, fill: 'red', width: 20, height: 20 }); // 将矩形添加到canvas画布上 canvas.add(rect); ~~~ ![](https://img.kancloud.cn/af/a9/afa9372fd091c7ab541021dba345854c_209x209.png) 在这种情况下,这两个例子非常相似,大小几乎没有差别。但是,您可以看到使用canvas的方法有多么不同。使用原生方法,我们在**上下文**中操作(表示整个画布位图的对象),在Fabric中,我们操作对象,实例化它们,更改其属性,并将其添加到画布。你可以看到这些对象是Fabric中的**第一等公民**。 但渲染纯正的红色矩形就如此无聊。我们至少可以做一些有趣的事情!也许,稍稍旋转? 旋转45度,首先使用原生的canvas方法: ~~~js var canvasEl = document.getElementById('c'); var ctx = canvasEl.getContext('2d'); ctx.fillStyle = 'red'; ctx.translate(100, 100); ctx.rotate(Math.PI / 180 * 45); ctx.fillRect(-10, -10, 20, 20); ~~~ 使用Fabric: ~~~js var canvas = new fabric.Canvas('c'); // 创建一个45度的矩形 var rect = new fabric.Rect({ left: 100, top: 100, fill: 'red', width: 20, height: 20, angle: 45 }); canvas.add(rect); ~~~ ![](https://img.kancloud.cn/cc/bc/ccbc3fa69333db0220ad271aa68c2e16_208x209.png) 这里发生了什么? 我们在Fabric中所做的一切都是将对象的“角度”值更改为`45`。然而使用原生的方法,事情变得更加有趣,记住我们无法对对象进行操作,相反,我们调整整个画布位图(`ctx.translate`,`ctx.rotate`)的位置和角度,以适应我们的需要。然后,我们再次绘制矩形,但记住要正确地偏移位图(-10,-10),所以它仍然呈现在100,100点。作为练习,我们不得不在旋转画布位图时将度数转换为弧度。 我相信你刚刚开始明白为什么面料存在,以及它解决了多少低级写法。 如果在某些时候,我们想将现在熟悉的红色矩形移动到画布上稍微不同的位置怎么办?我们如何在无法操作对象的情况下执行此操作?我们会在canvas位图上调用另一个`fillRect`吗? 不完全的。调用另一个`fillRect`命令实际上在画布上绘制的东西所有之上绘制矩形。还记得我前边说的用刷子画画吗?为了“移动”它,我们需要先**擦除以前绘制的内容**,然后在新的位置绘制矩形。 ~~~js var canvasEl = document.getElementById('c'); ... ctx.strokRect(100, 100, 20, 20); ... // 擦除整个画布 ctx.clearRect(0, 0, canvasEl.width, canvasEl.height); ctx.fillRect(20, 50, 20, 20); ~~~ 我们如何用Fabric完成这个? ~~~js var canvas = new fabric.Canvas('c'); ... canvas.add(rect); ... rect.set({ left: 20, top: 50 }); canvas.renderAll(); ~~~ ![](https://img.kancloud.cn/82/6b/826bbf90e8e5457c74893887270e5eff_208x208.png) 注意一个非常重要的区别。使用Fabric,在尝试“修改”任何内容之前,我们不再需要擦除内容。我们仍然使用对象,只需更改其属性,然后重新绘制画布即可获得“最新图片”。