Fabric.js 简介:第 1部分

分享于 

26分钟阅读

Web开发

  繁體 雙語

在10天内开发 Windows 8应用程序。

本文介绍了 Fabric.js 强大的JavaScript库,它使使用 HTML5 Canvas 元素变得轻而易举。 fabric 为画布提供了一个缺少的对象模型,以及一个SVG解析器。一层交互和一套不可以缺少的工具。 它是一个完全开源的项目,在MIT下许可,在过去的几年里有许多贡献。

在三年前,我开始使用 fabric 开发,发现使用原生画布API的困难。 为了让用户能够设计自己的服装,我为 printio.ru -my启动创建一个交互式设计编辑器。 我想要的互动类型只在那些日子的Flash 应用中存在。 现在,几乎没有几个库能够接近 fabric的可以能性,所以让我们仔细查看一下。

为什么 fabric?

在网页上,你可以创建一些绝对 amazing图形,但它提供的API是disappointingly低级别的。 如果你只是想在画布上画一些基本的形状并忘记它们,那是一回事。 如果需要任何交互,在任何点更改图片或者绘制更复杂的形状,情况会显著变化。 fabric 旨在解决这一问题。

本机画布方法只允许你触发简单的图形命令,盲目地修改整个画布位图。 你要绘制 rectangle? 使用 fillRect ( 左,顶,宽,高)。 要绘制线条? 使用 moveTo ( 左,顶) 和 lineTo ( x,y )的组合。 就好像你在画一个画布,把更多的油或者丙烯酸层分层,很少控制。

fabric 不是在如此低的级别上运行,而是在本地方法之上提供了一个简单但强大的对象模型。 它负责画布状态和渲染,并让你直接处理对象。

下面是一个演示这个差异的简单示例。 假设你想在画布上画一个红色的rectangle。 下面是使用本机 canvas API的方法:

// reference canvas element (with id="c")var canvasEl = document.getElementById('c');// get 2d context to draw on (the"bitmap" mentioned earlier)var ctx = canvasEl.getContext('2d');// set fill color of contextctx.fillStyle = 'red';// create rectangle at a 100,100 point, with 20x20 dimensionsctx.fillRect(100, 100, 20, 20);

代码 below 展示了如何使用 fabric 做同样的事情。 这两种方法的结果都显示在图 1

// create a wrapper around native canvas element (with id="c")var canvas = new fabric.Canvas('c');// create a rectangle objectvar rect = new fabric.Rect({
 left: 100,
 top: 100,
 fill: 'red',
 width: 20,
 height: 20});//"add" rectangle onto canvascanvas.add(rect);

Red Rectangle Drawn with Fabric or Native Canvas Methods

图 1用 fabric 或者本机画布方法绘制的红色 rectangle

此时,代码的大小几乎没有差别,这两个示例非常相似。 然而,你已经可以看到使用画布的方法是如何不同的。 使用本机方法,可以对表示整个画布位图的对象进行操作。 在 fabric 中,操作实例化的对象,更改它们的属性,并将它们添加到画布。 你可以看到,这些对象是 fabric 土地上的一等公民。

呈现纯红色 rectangle 太简单了。 你至少可以对它做一些有趣的事情,也许稍微旋转一下形状。 让我们尝试 45度,首先使用原生画布方法:

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 中做的。 ( 请参见图 2 以获得结果)。

var canvas = new fabric.Canvas('c');// create a rectangle with angle=45var rect = new fabric.Rect({
 left: 100,
 top: 100,
 fill: 'red',
 width: 20,
 height: 20,
 angle: 45});
canvas.add(rect);

Red, Rotated Rectangle Drawn with Fabric or Native Canvas Methods

图 2红色,用 fabric 或者本机画布方法绘制的旋转 rectangle

这里发生了什么在 fabric 中所要做的就是将对象值的角度改变为 45.? 但是,对于本机方法,需要更多的工作。 记住你不能在物体上操作。 相反,你必须调整整个画布位图(。翻译。转换。旋转)的定位和角度以适应你的需要。 然后再次绘制 rectangle,记住正确偏移位图,使它仍然在点呈现。 另外,你需要在旋转画布位图时将度数转换为弧度。

我相信你已经开始了解为什么 fabric 存在以及隐藏了多少低级别的样板。

让我们看另一个例子: 跟踪画布状态。

如果你想将 rectangle 移动到画布上的一个稍微不同的位置,该怎么做? 如何在不操作对象的情况下执行这里操作? 你能在画布上调用另一个 fillRect? 不是,调用另一个 fillRect 命令实际上会在画布上绘制的任何东西上绘制一个 rectangle。 要移动 rectangle,你需要先清除以前绘制的内容,然后在新位置( 请参见图 3 ) 中绘制 rectangle。

var canvasEl = document.getElementById('c');
...
ctx.strokRect(100, 100, 20, 20);
...// erase entire canvas areactx.clearRect(0, 0, canvasEl.width, canvasEl.height);
ctx.fillRect(20, 50, 20, 20);

以下是使用 fabric 实现这里目的的方法:

var canvas = new fabric.Canvas('c');
...
canvas.add(rect);
...
rect.set({ left: 20, top: 50 });
canvas.renderAll();

Red Rectangle Drawn at a new Location

图 3在新位置绘制红色 rectangle

注意一个非常重要的区别: 使用 fabric,你无需在尝试修改任何内容之前清除内容。 你仍然可以通过改变对象的属性,然后再次渲染画布来得到新的图片。

对象

在最后一节中你看到了如何通过实例化 fabric.Rect 构造函数来处理矩形。 当然,fabric 覆盖了其他基本形状,圆。三角形。椭圆等。 这些形状以 fabric.Circlefabric.Trianglefabric.Ellipse 等形式在 fabric"命名空间"下公开。 fabric 提供了七个基本形状:

画一个圆,只需创建一个圆对象并将它的添加到画布。

var circle = new fabric.Circle({
 radius: 20, fill: 'green', left: 100, top: 100});var triangle = new fabric.Triangle({
 width: 20, height: 30, fill: 'blue', left: 50, top: 50});
canvas.add(circle, triangle);

你用任何其他的基本形状做同样的事情。 图 4 显示在 100,100位置绘制一个绿色圆圈的例子,以及 50,50的蓝色三角形。

A Blue Triangle and a Green Circle Drawn with Fabric

图 4蓝色三角形和用 fabric 绘制的绿色圆圈

操作对象

创建图形对象矩形,圆形或者其他对象只是开始。 在某些时候,你可能需要修改对象。 也许某个动作会触发状态的改变或者播放某种形式的动画。 或者你可能想要更改某些鼠标交互中的对象属性(。例如颜色,不透明度,大小,位置)。

fabric 为你负责画布渲染和状态管理。 我们只需要修改物体本身。 前面的示例演示了set方法以及调用集( {左: 20,顶部:50 }) 将对象从它的上一个位置移动。 同样,你可以更改对象的任何其他属性。

如预期,fabric 对象与定位( 左,顶),尺寸( 宽度,高度),渲染( 填充,不透明度,笔划,strokeWidth ),缩放和旋转( 200mb,scaleY,角度) 以及翻转( flipX,flipY ) 相关。是,在 fabric 中创建翻转对象与将flip*属性设置为 true 一样简单。

你可以通过a 方法读取这些属性,并通过设置。 下面是如何更改 rectangle的某些红色属性的示例。 图 5 显示结果。

var canvas = new fabric.Canvas('c');
...
canvas.add(rect);
rect.set('fill', 'red');
rect.set({ strokeWidth: 5, stroke: 'rgba(100,200,200,0.5)' });
rect.set('angle', 15).set('flipY', true);

Red, Rotated, Stroked Rectangle Drawn with Fabric
用 fabric 绘制的图 5红色,旋转的rectangle

首先,填充值设置为"红色"。 下一个语句设置strokeWidth和笔划值,给 rectangle 一个 5像素的淡绿色颜色。 finally,代码将更改角度和flipY属性。 注意这三个语句中的每个语句使用的语法稍有不同。

这说明集合是一种通用方法。 你可能会经常使用它,这意味着要尽可以能方便。 getter有一般的获取方法和一些特定的方法。 若要读取对象的宽度属性,请使用 get ('宽度') width或者 getWidth()。 要获取MAXDOP值,你可以使用 get ('scaleX') getScaleX() 等等。 有一个方法,如 getWidth 或者 getScaleX,每个"public"对象属性( 笔划,strokeWidth,角度等)。

你可以能已经注意到在前面的示例中,对象与我们在set方法中使用的配置哈希相同。 在创建或者使用set方法时,可以在创建时使用对象:

var rect = new fabric.Rect({ width: 10, height: 20, fill: '#f55', opacity: 0.7 });// or functionally identicalvar rect = new fabric.Rect();
rect.set({ width: 10, height: 20, fill: '#f55', opacity: 0.7 });

默认选项

此时,你可能会想知道当创建一个对象而不传递任何"配置"对象时会发生什么。 它还有那些属性?

在创建过程中省略特定设置时,fabric 中的对象始终具有默认属性集。 你可以使用下面的代码自己查看这里代码:

var rect = new fabric.Rect(); // notice no options passed inrect.getWidth(); // 0rect.getHeight(); // 0rect.getLeft(); // 0rect.getTop(); // 0rect.getFill(); // rgb(0,0,0)rect.getStroke(); // nullrect.getOpacity(); // 1

这里 rectangle 具有默认属性集。 它位于 0,0,black 和完全不透明,没有中风,没有尺寸( 宽度和高度为 0 )。 因为没有标注,所以你在画布上看不到。 对于宽度和高度的任何正值,在画布左上角显示一个黑色 rectangle,如图 6所示,如图所示。

How Default Rectangle looks when given Dimensions
图 6给定维度默认 rectangle 外观

层次结构和继承

fabric 对象不独立于彼此存在。 它们形成了一个非常精确的层次。 大多数对象 inherit 从 root fabric.Object。 fabric.Object root 对象代表( 或多或少)的二维形状,位于二维画布平面中。 它是一个具有左/顶和宽/高特性的实体,以及一系列其他图形特性。 列的所有对象都是由对象填充。笔触。角度。不透明度。flip*等属性所列出的属性。

这种继承允许你定义 fabric.Object 上的方法,并在所有子"类"中共享它们。 例如如果要对所有对象都使用 getAngleInRadians 方法,则只需在 fabric.Object.prototype 上创建它,如下所示:

fabric.Object.prototype.getAngleInRadians = function() {
 returnthis.getAngle()/180 * Math.PI;
};var rect = new fabric.Rect({ angle: 45 });
rect.getAngleInRadians(); // 0.785...var circle = new fabric.Circle({ angle: 30, radius: 10 });
circle.getAngleInRadians(); // 0.523...circle instanceof fabric.Circle; // truecircle instanceof fabric.Object; // true

可以看到,该方法在所有实例中都立即可用。

即使来自 fabric.Object的子"类"inherit,它们也常常定义自己的方法和属性。 例如 fabric.Circle 需要radius属性,而 fabric.Image -which需要一个用于访问和设置一个图像实例所源自的HTML <> 元素的getElementsetElement 方法。

画布

既然你已经了解了一些细节,让我们回到画布吧。

你在所有 fabric 示例中看到的第一件事是创建画布 object- new fabric.Canvas('...')。 fabric.Canvas 对象作为 <canvas> 元素的包装器,负责管理该特定画布上的所有 fabric 对象。 它获取一个元素的ID,并返回一个 fabric.Canvas 实例。

可以向它的添加对象,从中引用对象,或者删除对象,如下所示:

var canvas = new fabric.Canvas('c');var rect = new fabric.Rect();
canvas.add(rect); // add objectcanvas.item(0); // reference fabric.Rect added earlier (first object)canvas.getObjects(); // get all objects on canvas (rect will be first and only)canvas.remove(rect); // remove previously-added fabric.Rect

管理对象是 fabric.Canvas的主要目的,但它也充当配置主机。 是否需要为整个画布设置 background 颜色或者图像,将所有内容剪贴到某个区域,设置不同的宽度和高度。 所有这些选项( 等等) 都可以在 fabric.Canvas 上设置,或者在创建时或者更后。 代码 below 显示一个示例。

var canvas = new fabric.Canvas('c', {
 backgroundColor: 'rgb(100,100,200)',
 selectionColor: 'blue',
 selectionLineWidth: 2//.. .});// orvar canvas = new fabric.Canvas('c');
canvas.backgroundImage = 'http://...';
canvas.onFpsUpdate = function(){ /*.. . */ };//.. .

交互性

fabric 独特的特性之一是在对象模型之上有一层交互性。 对象模型存在以允许编程访问和操作画布上的对象,但是在用户级别上,通过鼠标( 触摸设备触摸设备) 操纵。 只要通过新 fabric.Canvas('...')call, it's possible to select objects (see Figure 7 ), 初始化画布,就可以将它们拖动。缩放或者旋转,甚至将它们组合在一起,以在一个块中进行操作 !

Red, Rotated Rectangle in Selected State (Controls Visible)

图 7红色,旋转的rectangle 处于选中状态( 控件可见)

Rectangle and Circle Grouped (Controls Visible)

图 8 rectangle 和圆分组( 控件可见)

如果你想让用户在画布上拖动某些东西,让我们说一个图像,就是初始化画布。 不需要额外的配置或者设置。

若要控制这里交互性,可以在画布对象上与单个对象的可选布尔属性结合使用 fabric 布尔属性:

var canvas = new fabric.Canvas('c');
...
canvas.selection = false; // disable group selectionrect.set('selectable', false); // make object unselectable

但是如果你根本不想要交互层? 如果是这样的话,你可以用 fabric.StaticCanvas 替换 fabric.Canvas。 初始化的语法是完全相同的:

var staticCanvas = new fabric.StaticCanvas('c');
staticCanvas.add(
 new fabric.Rect({
 width: 10, height: 20,
 left: 100, top: 100,
 fill: 'yellow',
 angle: 30 }));

这就创建了一个"打火机"版本的画布,没有任何事件处理逻辑。 你仍然可以使用整个对象模型来添加。删除或者修改对象,还可以更改任何画布配置。 所有这些仍然是工作的,只是事件处理失败了。

在本文的后面,当我进行自定义生成选项时,你将看到如果 StaticCanvas 是你所需要的,你甚至可以创建 fabric。 如果你需要在应用程序中使用非交互图表或者非交互图像,这可以能是一个很好的选择。

图像

在画布中添加矩形和圆是有趣的,但如你现在所想到的,fabric 也可以很容易地使用图像。 下面是实例化 fabric.Image 对象并将它的添加到画布中的方法,首先是 HTML,然后是 JavaScript:

HTML

<canvasid="c"></canvas><imgsrc="my_image.png"id="my-image">

Javascript

var canvas = new fabric.Canvas('c');var imgElement = document.getElementById('my-img');var imgInstance = new fabric.Image(imgElement, {
 left: 100,
 top: 100,
 angle: 30,
 opacity: 0.85});
canvas.add(imgInstance);

请注意,你将一个图像元素传递给 fabric.Image 构造函数。 这将创建一个 fabric.Image 实例,它看起来像来自文档的图像。 此外,你立即将左/上值设置为 100/100, 角度至 30,不透明度为 0.85. 一旦图像被添加到画布,它在位置 100,100以 30-degree 角度呈现,稍微透明( 请参见图 9 )。 不错 !

Slightly Transparent and Rotated Image, Rendered with Fabric

图 9稍微透明和旋转的图像,用 fabric 渲染

如果文档中没有图像,但只有图像的URL,则可以使用 fabric.Image.fromURL:

fabric.Image.fromURL('my_image.png', function(oImg) {
 canvas.add(oImg);
});

看起来很简单,不是? 只需调用 fabric.Image.fromURL,使用一个图像的URL,并给它一个调用,一旦加载并创建了图像。 回调函数接收已经创建的fabric.Image 对象作为它的第一个参数。 此时,你可以将它的添加到画布,或者先更改它,然后再添加它,如下所示:

fabric.Image.fromURL('my_image.png', function(oImg) {
 // scale image down, and flip it, before adding it onto canvas oImg.scale(0.5).setFlipX(true);
 canvas.add(oImg);
});

路径和 PathGroup

我们看了简单的形状和图像。 更复杂,更丰富的形状和内容? 满足路径和 PathGroup,电源耦合。

fabric 中的路径代表形状的轮廓,可以其他方式填充。抚摸和修改图形。 路径由一系列命令组成,这些命令从一个点到另一个点模拟笔。 借助移动。直线。曲线和 arc 等命令,路径可以形成非常复杂的形状。 通过一组路径( PathGroup )的帮助,可能会更多地开启。

fabric 中的路径与 SVG <路径> 元素相似。 它们使用相同的命令集,可以从 <路径> 元素创建,并且可以将它们序列化为它们。 稍后我将介绍序列化和SVG解析,但是现在值得注意的是,你可能只需要手工创建路径实例。 相反,你将使用 fabric SVG解析器中内置的。 但是,为了了解什么是路径对象,让我们手工创建一个简单的( 有关结果,请参见图 10 ):

var canvas = new fabric.Canvas('c');var path = new fabric.Path('M 0 0 L 200 100 L 170 200 z');
path.set({ left: 120, top: 120 });
canvas.add(path);

Simple Path Rendered with Fabric

图 10用 fabric 呈现的简单路径

这里你实例化 fabric.Path 对象并传递一串路径指令。 它看起来很神秘,但实际上很容易理解。 M 表示移动命令,并指示隐形笔移动到点 0,0. L 代表直线,使笔绘制直线到 200,100. 然后,另一个L 创建一行到 170,200. 最后,z 强制绘图笔关闭当前路径,并将形状 finalize。

由于 fabric.Path 与 fabric 中的任何其他对象一样,你也可以更改它的某些属性,或者修改它,如下面的图所示。

...var path = new fabric.Path('M 0 0 L 300 100 L 200 300 z');
...
path.set({ fill: 'red', stroke: 'green', opacity: 0.5 });
canvas.add(path);

A Simple, Modified Path

图 11一个简单的修改过的路径

出于好奇,让我们来看看稍微复杂一点的路径语法。 你将看到为什么手工创建路径可能不是最好的做法:

...var path = new fabric.Path('M121.32,0L44.58,0C36.67,0,29.5,3.22,24.31,8.41
c-5.19,5.19-8.41,12.37-8.41,20.28c0,15.82,12.87,28.69,28.69,28.69c0,0,4.4,
0,7.48,0C36.66,72.78,8.4,101.04,8.4,101.04C2.98,106.45,0,113.66,0,121.32
c0,7.66,2.98,14.87,8.4,20.29l0,0c5.42,5.42,12.62,8.4,20.28,8.4c7.66,0,14.87
-2.98,20.29-8.4c0,0,28.26-28.25,43.66-43.66c0,3.08,0,7.48,0,7.48c0,15.82,
12.87,28.69,28.69,28.69c7.66,0,14.87-2.99,20.29-8.4c5.42-5.42,8.4-12.62,8.4
-20.28l0-76.74c0-7.66-2.98-14.87-8.4-20.29C136.19,2.98,128.98,0,121.32,0z');
canvas.add(path.set({ left: 100, top: 200 }));

这里,M 仍然代表移动命令,所以笔在点 121.32处开始绘制它的绘制行程。 然后有一个L ( 线条) 命令将笔带到 44.58,0. 目前为止,这个命令是"三次贝塞尔曲线。"命令,它代表从当前点到 36.67点绘制一条贝塞尔曲线,0. 在一行的开头使用 29.5作为控制点,在行的末尾为 24.31,作为控制点。 整个操作之后,再跟随十几个其他的三次bezier命令,它们创建一个漂亮的箭头形状,如图5 所示。

Complex Path Rendered with Fabric

图 12用 fabric 呈现的复杂路径

你可能不会直接跟这些野兽一起工作。 相反,可以使用 fabric.loadSVGFromString 或者 fabric.loadSVGFromURL 方法加载整个SVG文件,并让 fabric 解析器的SVG完成遍历所有SVG元素并创建相应路径对象的工作。

尽管 fabric 对象路径通常表示 SVG <路径> 元素,但在SVG文档中,路径的集合通常表示为一个PathGroup实例( 织物。PathGroup ) ( )。 PathGroup只是一组路径对象,因为 fabric.PathGroup 从继承,它可以像任何它的他对象一样被添加到画布。

和路径一样,你可能不直接使用 PathGroup。 但是,如果在解析SVG文档后遇到一个错误,你将明确了解它是什么用途和用途。

整理

我只scratch了可以用 fabric的Surface。 现在,你可以轻松创建任何简单形状。复杂形状或者图像;将它们添加到画布中,并按照你希望的位置。尺寸。颜色。笔触。不透明度。不透明度等方式对它们进行。

在本系列的下一篇文章中,我将讨论使用组;动画;文本;SVG解析。呈现和序列化;事件;图像过滤器等等。

,我们可以查看注释的演示插件或者基准插件,加入堆栈溢出,或者直接进入文档wiki和源。MSDN开发者中心,你还可以了解更多关于 HTML5 Canvas的信息,或者查看一篇关于 asp 5 Canvas元素的介绍,该文章介绍了脚本工具的。

使用 fabric 进行有趣的实验 ! 我希望你能享受到。

本文是由 Juriy Zaytsev编写的。 Juriy是一个充满热情的JavaScript开发者,在纽约生活。 他是 ex-Prototype.js 核心成员,perfectionkills.com,的博客作者,Fabric.js canvas库的创建者。 目前Juriy在 printio.ru 启动上工作,使 fabric 更加有趣。

查找 Juriy:


INT  PAR  introduction  FAB  Fabric  
相关文章