Fabric.js 简介第 1部分 — Fabric.js Javascript Canvas库

分享于 

26分钟阅读

ionic

 

Fabric.js. 部件 1简介。

今天我将向你介绍 Fabric.js,它是一个强大的Javascript库,它使得与的工作轻而易举。 fabric 为画布提供了一个缺少的对象模型,以及SVG解析器。交互层和一套其他不可或缺的工具。 它是一个完全开源的项目,在MIT下许可,在过去的几年里有许多贡献。

开始开发 fabric 3年前,发现了使用原生画布API的困难。 为了让用户设计自己的服装,我正在为 printio.ru 创建一个交互式的设计编辑器。 我们想要的互动类型在那些日子里只存在于 Flash 应用中。 即使现在,很少有人能够接近 fabric的可以能性。

让我们来仔细看看 !

为什么 fabric?

我们可以在网页上创建一些 但是它提供的API是 disappointingly低级别。 如果我们只想在画布上画几个基本形状并忘记它们,那是一件事情。 但是,只要需要任何类型的交互,在任何点改变图片,或者绘制更复杂的形状 — situtation 。

fabric 旨在解决这一问题。

本机画布方法只允许我们触发简单的图形命令,盲目地修改整个画布位图。 要绘制 rectangle? 用户 fillRect(left, top, width, height) 要绘制线条? 使用 moveTo(left, top)lineTo(x, y)的组合。 it ,layering control control control 。

fabric 不是在如此低级别上运行,而是在原生方法之上提供简单但强大的对象模型。 它负责画布状态和渲染,并让我们直接使用"对象"。

让我们来看看演示这个差异的简单示例。 我们想在画布上画一个红色的rectangle 。 下面是本机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 context
ctx.fillStyle = 'red';
//create rectangle at a 100,100 point, with 20x20 dimensions
ctx.fillRect(100, 100, 20, 20);

现在,让我们来看看如何使用 fabric 进行相同的操作:

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

此时,大小—几乎没有区别,两个示例非常相似。 然而,你已经可以看到使用画布的方法是如何不同的。 对于本机方法,我们对上下文 —进行了操作,该对象代表整个画布位图。 在 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:

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

这里发生了什么?

我们在 fabric 中所要做的就是把"对象角度"值改为 45 。 然而,在本机方法中,事情变得更加复杂了。 记住我们不能在物体上操作。 相反,我们调整整个画布位图( ctx.translatectx.rotate )的定位和角度以适应我们的需要。 然后再次绘制 rectangle,但记住对位图进行适当的( -10,-10 ) 偏移,以便在 100,100点上呈现它。 作为额外的练习,我们在旋转画布位图时必须将度数转换为弧度。

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

但是让我们来看看另一个例子 —,它跟踪画布状态。

如果在某些时候,我们想移动到现在熟悉的红色 rectangle 到画布上稍微不同的位置? 如果不能够对对象进行操作,我们该怎么做? 我们在画布上调用另一个 fillRect

不是,调用另一个 fillRect 命令实际上在画布上绘制了 rectangle 。 记得我以前用画笔画过画? 我们需要先对以前绘制的内容进行收费,然后在新位置绘制 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();

注意一个非常重要的区别。 对于 fabric,我们不再需要删除内容,然后再尝试"修改"任何内容。 我们仍然使用对象,只是改变它们的属性,然后渲染画布以获得一个"新图片"。

对象

我们已经看到了如何通过实例化 fabric.Rect 构造函数来处理矩形。 但当然 fabric 覆盖了所有它的他基本形状以及—圆。三角形。椭圆等等。 它们均以 fabric.Circlefabric.Trianglefabric.Ellipse 等形式公开在 fabric"命名空间"下。

7 在 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);

。and我们有一个绿色圆圈,在 100,100位置绘制,在 50,50位置绘制一个蓝色三角形。

操作对象

创建图形对象—矩形。圆或者其他—当然只是开始。 有些时候我们可能需要修改那些。 也许某些动作需要触发状态的改变,或者播放某些排序的动画。 或者我们可能想要更改某些鼠标交互中的对象属性( 。颜色,不透明度,大小,位置) 。

fabric 负责画布渲染和状态管理。 我们只需要修改对象本身。

前面的示例演示了 set 方法以及如何调用 set({ left: 20, top: 50 }) from previous上的object移动"对象。 同样地,我们可以改变对象的任何其他属性。 但是这些属性是什么?

,—,positioning,dimension,dimension,skewY,,,,,,

是,在 fabric 中创建翻转对象与将flip*属性设置为 true 一样简单。

你可以通过 get 方法读取这些属性,并通过 set 设置它们。 让我们尝试更改 rectangle的一些红色属性:

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);

首先,我们将"填充"值设置为"红色",这实际上是使红色成为。 下一条语句设置"strokewidth"和"笔画"值,给出 rectangle的5px 笔画。 finally,我们正在更改"角度"和"flipY"属性。 注意每个 3语句使用的语法稍有不同。

这说明 set 是一种通用方法。 你可以能会经常使用它,所以它应该尽可以能的方便。

我们已经覆盖了 setter,而getter又? 很明显,有通用的get 方法,也有许多特定的get* 方法。 若要读取对象的"宽度"值,可以使用 get('width') 或者 getWidth() 。 获取"宋体"值 — get('scaleX') 或者 getScaleX(),等等。 对于每个"public"对象属性("笔划","strokewidth","角度",等等,都有一个类似 getWidth 或者 getScaleX的方法

在前面的示例中,你可能注意到对象是用与我们在 set 方法中使用的相同的配置哈希创建的。 那是因为它的价格是同一个。 你可以在创建时创建"配置"对象,也可以在以下情况下使用 set 方法:

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

默认选项

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

当然,fabric 中的对象总是具有默认属性集。 创建时 omited,它是这里默认属性集,即"给给"。 我们可以自己尝试一下:

var rect = new fabric.Rect();//notice no options passed in
rect.get('width');//0
rect.get('height');//0
rect.get('left');//0
rect.get('top');//0
rect.get('fill');//rgb(0,0,0)
rect.get('stroke');//null
rect.get('opacity');//1

我们的rectangle 得到了一个默认的属性集。 定位于 0,0,是 black 颜色,完全不透明,没有行程,没有任何尺寸的( 宽度和高度为 0 ) 。 因为没有尺寸,我们在画布上看不到。 但是为宽度/高度赋予任何正值肯定会在画布的左/右角显示 black rectangle 。

层次结构和继承

fabric 对象不只是独立于彼此。 它们形成了一个非常精确的层次。

root fabric.Object 中大多数对象的inherit 。 fabric.Object 几乎代表了一个 2-dimensional 形状,位于 2-dimensional 画布平面。 它是一个具有左/顶和宽/高特性的实体,以及一系列其他图形特性。 我们在对象—填充。笔画。角度。不透明度。flip* 。等等 —上看到的属性对于所有 fabric 对象都是通用的,从 fabric.Object

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

fabric.Object.prototype.getAngleInRadians = function() {
 return this.get('angle')/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;//true
circle instanceof fabric.Object;//true

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

虽然来自 fabric.Object的子"类"inherit,它们通常也定义自己的方法和属性。 例如 fabric.Circle 需要有"半径"属性。 我们将用 fabric.Image —来查看—需要使用 getElement/setElement 方法来访问/设置 HTML 元素,这些元素实例来自于一个/。
使用Prototype来获取自定义呈现和行为对于高级项目非常常见。

画布

我们已经详细介绍了对象,让我们回到画布。

首先,在 fabric 示例中,如果创建画布对象 — new fabric.Canvas('...'),你可以看到。 fabric.Canvas 作为元素的包装器,负责管理特定画布上的所有 fabric 对象。 它获取一个元素的id,并返回一个 fabric.Canvas 实例。

我们可以将对象 add,引用它们,或者删除它们:

var canvas = new fabric.Canvas('c');
var rect = new fabric.Rect();
canvas.add(rect);//add object
canvas.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 上设置,也可以在创建时或者之后设置:

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

交互性

我们在一个画布元素的主题上,讨论交互。 在—中构建的fabric —的一个独特特性是我们所看到的所有方便的对象模型上的一层交互。

对象模型,允许在画布上编程访问和对对象进行操作。 但是在外部,在用户级别上,可以通过鼠标( 触摸设备上的触摸) 操作这些对象。 只要通过 new fabric.Canvas('...') 初始化画布,就可以选择对象。拖动它们。缩放或者旋转它们,甚至将组合在一起,以便在一个块中操作。

我们只想让用户在画布上拖动东西,我们就可以说,我们只需要初始化画布,然后在它上面添加一个对象就可以了。 不需要额外的配置或者设置。

为了控制这种交互性,我们可以在画布上使用"。fabric的选择"布尔属性组合各个对象的"可选"布尔属性。

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

但是如果你根本不希望这样的交互层? 如果是这样的话,你可以用 fabric.StaticCanvas 替换 fabric.Canvas 。 初始化的语法完全相同;你只使用 StaticCanvas 而不是 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 )

( js )

var canvas = new fabric.Canvas('c');
var imgElement = document.getElementById('my-image');
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度角,并稍微透明 ! 不错。

如果我们在文档中没有图像,但只有一个图像的URL? 没有问题。让我们看看如何使用 fabric.Image.fromURL:

fabric.Image.fromURL('http://fabricjs.com//my_image.png', function(oImg) {
 canvas.add(oImg);
});

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

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

路径

我们看了简单的形状然后图像。 更复杂,丰富的形状和内容?

满足电源耦合—路径和 Gropus 。

fabric 中的路径代表可以用其他方式填充。抚摸和修改的形状的轮廓。 路径由一系列命令组成,它们基本上模仿从一点到另一点的笔。 借助"移动"。"线条"。"曲线"或者"arc"之类的命令,路径可以形成非常复杂的形状。 并且通过一组路径( pathgroup'的帮助,可以能更多地开启了。

fabric 中的路径与 SVG元素相似。 它们使用相同的命令集,可以从元素中创建它们,并将它们序列化为。 稍后我们将更深入地讨论序列化和SVG解析,但是现在值得注意的是,你很可能很少手工创建路径实例。 相反,你将使用内置的fabric SVG解析器。 要了解什么是路径对象,让我们尝试手工创建一个简单的对象:

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);

我们正在实例化 fabric.Path 对象,传递一串路径指令。 虽然看起来很神秘但是很容易理解。 ,"表示"移动"命令,并告诉不可见的笔移动到 0,0点。 ""代表"行and笔绘制到 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);

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

...
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,0"点上开始绘制程序。 然后有"l"命令将它带到" 44.58,0"。 到现在为止还不错接下来是什么? ""命令,它代表"三次贝塞尔曲线"。 它使笔从当前点到" 36.67,0"曲线绘制贝塞尔曲线。 它使用" 29.5,3.22"作为控制点在行的开头," 24.31,8.41"作为行末尾的控制点。 这一整件事后跟着几个它的他三次贝塞尔命令,finally 创建一个很好看的箭头形状。

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

从整体上说,在SVG文档中,路径通常表示SVG元素,而SVG文档中经常出现的路径则表示为组( 。fabric.Group 实例) ( Groups ) 。 可以想象,组只是一组路径和其他对象。 由于 fabric.Groupfabric.Object 继承,它可以像它的他任何对象一样被添加到画布中,并且操纵了相同的方法。

和路径一样,你可能不会直接跟他们一起工作。 但是,如果在解析SVG文档后偶然发现了一个,你就会知道它是什么,以及它。

后记

我们只触及了 fabric 可能的表面。 现在,你可以轻松创建任何简单形状。复杂形状。图像;将它们添加到画布中,以任何你希望—位置。尺寸。颜色。笔触。不透明度—为你选择的方式。

在本系列的下一部分,我们将看到组;动画;文本;SVG解析。渲染。序列化;事件;。

,我们可以在elsewhere或者 benchmarks google小组或者 benchmarks,加入小组的讨论,或者直接访问文档,wiki 。

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

读取第 2部分。

JAVA  INT  Javascript  PAR  CAN  introduction  
相关文章