fabric.js 中文教程第四部分

我们已经在前几个系列涵盖了很多话题,从基础对象操作到动画,事件,滤镜,组合和子类。但还有几件非常有趣和有用的事情要讨论!

自由绘制

如果说<canvas>有什么闪光点的话,那就是它对自由绘制有极好的支持!由于画布只是一个2D位图——一张可以在上面绘制的纸——所以进行自由绘制是非常自然的。当然,Fabric会帮我们解决这个问题。

只需将Fabric canvas的isDrawingMode属性设置为true,即可启用自由绘制模式。这会立即使画布上的任何进一步点击和移动被解释为铅笔/画笔。

isDrawingModetrue时,您可以在画布上任意绘制多次。但只要您执行任何动作,然后是“mouseup”事件,Fabric就会触发“path:created”事件,并实际将刚刚绘制的形状转换为真实的fabric.Path实例!

如果在任何时候将isDrawingMode设置回false,则最终所有创建的路径对象仍存在于画布上。因为它们是fabric.Path对象,您可以按任何方式修改它们-移动、旋转、缩放等。

还有2个属性可用于自定义自由绘制——freeDrawingBrush.colorfreeDrawingBrush.width。两者都可以通过freeDrawingBrush实例在Fabric画布实例上使用。freeDrawingBrush.color可以是任何常规颜色值,代表画笔的颜色。freeDrawingBrush.width是一个以像素为单位的数字,代表画笔的宽度。
freeDrawing
在不久的将来,我们计划为自由绘制添加更多选项——各种版本的画笔(如喷雾状或粉笔状)。还有自定义画笔图案,以及一个可以使用自己的画笔扩展的选项,类似于Fabric图像滤镜。

擦除(Erasing)是另一个很酷的可用功能,可以很好地与自由绘图配合使用。

自定义

Fabric的一个惊人之处在于它的可定制性。您可以在画布或画布对象上调整数十个不同的参数,以使其行为完全符合您的要求。让我们来看看其中的一些。

锁定对象(Locking objects)

画布上的每个对象都可以通过几种方式锁定。“lockMovementX”、“lockMovementY”、“lockRotation”、“ockScalingX”和“lockScalingY”是锁定相应对象动作的属性。所以设置object.lockMovementXtrue可阻止对象水平移动。但您仍然可以在垂直平面中移动它。类似地,lockRotation防止旋转,lockScalingX/lockScalingY可以阻止水平或者垂直缩放。所有这些都是可叠加的。你可以用任何方式将它们组合在一起。

改变边框和角(Changing borders, corners)

您可以通过“hasControls”和“hasBorders”属性控制对象的边界和角的可见性。只要将它们设置为false,对象就会立即呈现为“裸露的”。

object.hasBorders = false;

hasBorders

object.hasControls = false;

hasControls
您还可以通过调整一些自定义属性“cornerDashArray”、“borderDashArry”、“borderColor”、“transparentCorners”、“cornerColor”“cornerStrokeColor”,“cornerStyle”、“selectionBackgroundColor”和“cornerSize”属性来更改它们的外观。

object.set({
  borderColor: 'red',
  cornerColor: 'green',
  cornerSize: 6
});

自定义01

  object.set({
    transparentCorners: false,
    cornerColor: 'blue',
    cornerStrokeColor: 'red',
    borderColor: 'red',
    cornerSize: 12,
    padding: 10,
    cornerStyle: 'circle',
    borderDashArray: [3, 3]
  });

自定义02

禁用选择(Disabling selection)

通过将画布的“selection”属性设置为false,可以禁用画布上的对象选择。这将阻止对画布上显示的所有内容进行选择。如果只需要使某些对象不可选择,则可以更改对象的“selectable”属性。只要将其设置为false,对象就会失去交互性。

自定义选择(Customizing selection)

现在,如果您不想禁用选择,而是想更改其外观,该怎么办?没问题。

画布上有4个属性可以控制它的呈现——“selectionColor”、“selectionBorderColor”,“selectionLineWidth”和“selectionDashArray”。这些应该很容易解释,所以让我们看一个例子:

canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));

canvas.selectionColor = 'rgba(0,255,0,0.3)';
canvas.selectionBorderColor = 'red';
canvas.selectionLineWidth = 5;

4_8
最后一个属性“selectionDashArray”并不是那么简单。它允许我们做的是使选择线虚线化。定义破折号模式的方法是通过数组指定间隔。因此,为了创建一个长破折号后面跟着一个短破折号的模式,我们可以使用[10,5]作为“selectionDashArray”。这将绘制一条10px长的线,然后跳过5px,再次绘制10px线,以此类推。如果我们使用[2,4,6]数组,则可以通过绘制2px线、跳过4px、绘制6px线和跳过2px、然后绘制4px线以及跳过6px等等来创建图案。你明白了。例如,这就是[5,10]模式的外观:

4_9

虚线描边(Dashed stroke)

与画布上的“selectionDashArray”类似,所有Fabric对象都有“strokeDashArray”属性,负责在对象上执行的任何笔划的虚线图案。

var rect = new fabric.Rect({
  fill: '#06538e',
  width: 125,
  height: 125,
  stroke: 'red',
  strokeDashArray: [5, 5]
});
canvas.add(rect);

4_13

可点击区域(Clickable area)

如您所知,所有Fabric对象都有边界框,当存在控件/角时,该边界框用于拖动对象或旋转和缩放对象。您可能已经注意到,即使单击对象边界框内的空白区域,也可以拖动对象。
4_14
默认情况下,画布上的所有Fabric对象都可以由边界框拖动。但是,如果您想要不同的行为——仅通过对象的实际内容单击/拖动对象,则可以在对象上使用“perPixelTargetFind”属性。只需将其设置为true即可获得所需的行为。

旋转点(Rotating point)

由于1.0版Fabric默认使用替代UI,因此无法同时缩放和旋转对象。相反,每个对象上都有一个单独的旋转控件。该控件的相应属性为“hasRotatingPoint”。您可以通过“rotatingPointOffset”数字属性自定义其相对于对象的偏移量。

4_10

对象变形(Object transformation)

自版本1.0以来,Fabric中还有许多其他与转换相关的属性。其中之一是画布实例上的“uniScaleTransform”。默认情况下为false,可用于启用对象的非均匀缩放;换句话说,它允许在拖动角时更改对象的比例。
4_15
然后是“centeredScaling”和“centered Rotation”属性(在v1.3.4之前是一个属性-“centerTransform”)。它们指定对象的中心是否应用作变换的原点。当两者都设置为true时,当对象始终从中心缩放/旋转时,它会复制1.0之前的行为。由于1.0变换的原点是动态的,因此可以在缩放对象时进行更精细的控制。

最后一对新属性是“originX”和“originY”。默认情况下,相应地设置为"left" 和"top",它们允许以编程方式更改对象的转换原点。当拖动对象的角时,这些属性在动态变化。

那么我们什么时候手动更改它们呢?例如,在处理文本对象时。当您动态更改文本,并且文本框尺寸增加时,“originX”和“originY”指示框的增长位置。所以,如果需要将文本对象居中,可以将originX设置为"center"。要使其向右移动,您需要将originX设置为“right”。这种行为类似于CSS中的“position:absolute”。

画布的背景和覆盖(Canvas background and overlay)

您可能还记得第一部分,您可以指定一种颜色来填充整个画布背景。只需将任何常规颜色值设置为画布的“backgroundColor”属性即可。

canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.backgroundColor = 'rgba(0,0,255,0.3)';
canvas.renderAll();

4_5
您可以更进一步,将图像指定为背景。为此,您需要使用setBackgroundImage方法,传递url和optiona完成回调。

canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.setBackgroundImage('../assets/pug.jpg', canvas.renderAll.bind(canvas));

需要注意的是,虽然属性名为“backgroundImage”,但它可以承载任何fabric对象类型。你可以设置一个fabric.Rect表示艺术板,也可以设置一组对象。下面的“overlayImage”或“backgroundColor”也一样,它可以承载任何填充,如渐变或图案。
4_6
最后,您还可以设置覆盖图像,在这种情况下,它将始终显示在画布上渲染的任何对象的顶部。只需使用setOverlayImage,传递url和可选的完成回调。

canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.setOverlayImage('../assets/jail_cell_bars.png', canvas.renderAll.bind(canvas));

4_7

Node.js上的Fabric

Fabric的一个独特方面是,它不仅可以在客户端、浏览器中工作,而且可以在服务器上工作!当您希望从客户端发送数据并在服务器上创建该数据的图像时,这可能很有用。或者,如果您只是想从控制台使用Fabric API,出于速度、方便或其他原因。

让我们看看如何设置Node环境并开始Fabric。

首先,如果你还没有安装Node.js,您需要先安装。根据平台的不同,安装Node的方法不多。您可以按照这些说明操作

一旦安装了Node,我们需要安装node-canvas库。node-canvas是NodeJS的canvas实现。它依赖于可以在Mac、Linux或Windows上运行的Cairo——一个2D图形库。node-canvas有专用的安装说明,具体取决于您选择的平台。

由于Fabric运行在Node之上,因此它作为NPM包提供。因此,下一步是安装NPM。您可以在其github repo中找到安装说明。

最后一步是使用NPM安装Fabric包。这只需运行npm install fabric(或npm install-g fabric来全局安装包)即可完成。

如果我们现在运行node控制台,我们应该可以使用node-canvas和Fabric:

> node
...
> typeof require('canvas'); // "function"
> typeof require('fabric'); // "object"

现在一切就绪,我们可以尝试一个简单的“hello world”测试。让我们创造一个helloworld.js文件:

var fs = require('fs'),
    fabric = require('fabric').fabric,
    out = fs.createWriteStream(__dirname + '/helloworld.png');

var canvas = new fabric.StaticCanvas(null, { width: 200, height: 200 });
var text = new fabric.Text('Hello world', {
  left: 100,
  top: 100,
  fill: '#f55',
  angle: 15
});
canvas.add(text);
canvas.renderAll();

var stream = canvas.createPNGStream();
stream.on('data', function(chunk) {
  out.write(chunk);
});

然后使用node helloworld.js命令运行。打开helloworld.png说明运行成功:
4_11
这是怎么回事?让我们回顾一下这段代码的重要部分。

首先,我们引入Fabric(fabric = require('fabric').fabric)。然后,我们创建了一个Fabric画布。

然后是熟悉的对象创建(new fabric.Text())和画布添加 (canvas.add(text))。

所有这些只需创建Fabric画布并将文本对象渲染到画布上。现在,如何创建画布上渲染的任何内容的图像?使用画布实例上可用的createPNGStream方法。createPNGStream返回Node的流对象,然后可以使用on('data')将其输出到图像文件中,并写入对应于图像文件的流中(fs.createWriteStream())。

fabric.Canvas#createPNGStream是Node特有的方法之一。其他一切都是一样的——您仍然可以像平常一样创建对象,将它们添加到画布上,修改、渲染等等。

Node服务器与Fabric

例如,让我们创建一个简单的Node服务器,它将侦听JSON格式的Fabric数据的传入请求,并输出该数据的图像。整个脚本只有25行!

var fabric = require('fabric').fabric, // or import { fabric } from 'fabric';
    http = require('http'),
    url = require('url'),
    PORT = 8124;

var server = http.createServer(function (request, response) {
  var params = url.parse(request.url, true);
  var canvas = new fabric.StaticCanvas(null, { width: 200, height: 200 });

  response.writeHead(200, { 'Content-Type': 'image/png' });

  canvas.loadFromJSON(params.query.data, function() {
    canvas.renderAll();

    var stream = canvas.createPNGStream();
    stream.on('data', function(chunk) {
      response.write(chunk);
    });
    stream.on('end', function() {
      response.end();
    });
  });
});

server.listen(PORT);

这个片段中的大部分代码应该已经很熟悉了。它的要点是内部服务器响应。我们正在创建Fabric画布,将JSON数据加载到画布上,进行渲染,并将最终结果作为服务器响应进行流式传输。

为了测试它,让我们取一个稍微旋转的绿色矩形的数据:

{"objects":[{"type":"rect","left":103.85,"top":98.85,"width":50,"height":50,"fill":"#9ae759","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1.39,"scaleY":1.39,"angle":30,"flipX":false,"flipY":false,"opacity":0.8,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}

URI编码:

%7B"objects"%3A%5B%7B"type"%3A"rect"%2C"left"%3A103.85%2C"top"%3A98.85%2C"width"%3A50%2C"height"%3A50%2C"fill"%3A"%239ae759"%2C"overlayFill"%3Anull%2C"stroke"%3Anull%2C"strokeWidth"%3A1%2C"strokeDashArray"%3Anull%2C"scaleX"%3A1.39%2C"scaleY"%3A1.39%2C"angle"%3A30%2C"flipX"%3Afalse%2C"flipY"%3Afalse%2C"opacity"%3A0.8%2C"selectable"%3Atrue%2C"hasControls"%3Atrue%2C"hasBorders"%3Atrue%2C"hasRotatingPoint"%3Afalse%2C"transparentCorners"%3Atrue%2C"perPixelTargetFind"%3Afalse%2C"rx"%3A0%2C"ry"%3A0%7D%5D%2C"background"%3A"rgba(0%2C%200%2C%200%2C%200)"%7D

并通过“data”查询参数传递给服务器。立即响应,返回“image/png”内容类型,如下所示:
4_12
如您所见,在服务器上使用Fabric非常简单。请随意尝试这个片段。也许可以从URL参数中更改画布尺寸,或者在返回图像作为响应之前修改客户端数据。

在Node环境自定义Fabric的字体

在Fabric中使用自定义字体之前,我们需要先加载它们。在浏览器(客户端)中,最常用的加载字体的方法是使用CSS3@font-face规则。在Fabric on Node(服务器端)中,我们可以使用Node canvas Font API,这使加载字体变得轻而易举。

下面的示例演示了如何加载和使用自定义字体。保存到customfont.js,并确保字体文件的路径正确。在这个例子中,我们使用Ubuntu作为我们的自定义字体。

var fs = require('fs'),
      fabric = require('fabric').fabric; // or import { fabric } from 'fabric';

  fabric.nodeCanvas.registerFont(__dirname + '/test/fixtures/Ubuntu-Regular.ttf', {
    family: 'Ubuntu', weight: 'regular', style: 'normal'
  });
  fabric.nodeCanvas.registerFont(__dirname + '/test/fixtures/Ubuntu-Bold.ttf', {
    family: 'Ubuntu', weight: 'bold', style: 'normal'
  });
  fabric.nodeCanvas.registerFont(__dirname + '/test/fixtures/Ubuntu-Italic.ttf', {
    family: 'Ubuntu', weight: 'regular', style: 'italic'
  });
  fabric.nodeCanvas.registerFont(__dirname + '/test/fixtures/Ubuntu-BoldItalic.ttf', {
    family: 'Ubuntu', weight: 'bold', style: 'italic'
  });

  var canvas = new fabric.StaticCanvas(null, { width: 300, height: 250 });

  var text = new fabric.Text('regular', {
      left: 0,
      top: 50,
      fontFamily: 'Ubuntu'
  });
  canvas.add(text);

  text = new fabric.Text('bold', {
      left: 0,
      top: 100,
      fontFamily: 'Ubuntu',
      fontWeight: 'bold'
  });
  canvas.add(text);

  text = new fabric.Text('italic', {
      left: 0,
      top: 150,
      fontFamily: 'Ubuntu',
      fontStyle: 'italic'
  });
  canvas.add(text);

  text = new fabric.Text('bold italic', {
      left: 0,
      top: 200,
      fontFamily: 'Ubuntu',
      fontWeight: 'bold',
      fontStyle: 'italic'
  });
  canvas.add(text);
  canvas.renderAll();
  var out = fs.createWriteStream(__dirname + '/customfont.png');
  var stream = canvas.createPNGStream();
  stream.on('data', function(chunk) {
      out.write(chunk);
  });

使用node customfont.js运行示例。创建的图像(customfont.png)如下所示:
4_16
让我们仔细看看发生了什么。在fabric.nodeCanvas暴露了JSDOM所需的node-canvas库,以将node-canvas与HTMLCanvas Api连接。对于要使用的每个字体文件,我们需要使用fabric.nodeCanvas.registerFont()注册该文件,方法是传递字体文件路径和指定字体属性的对象。请记住,这必须在创建画布本身之前发生。

现在我们可以通过设置fabric.TextfontFamily属性来使用字体。将文本对象设置为字体名称。结合fontWeightfontStyle属性,我们可以应用我们添加的字体。有关这些属性的更多信息,请参见第2部分(文本)
请注意,该示例演示了如何在创建新文本对象时使用自定义字体,但这也适用于通过JSON加载的文本对象。

因此,这将使我们结束关于Fabric的4部分系列。我希望你现在拥有足够的知识来创造有趣、酷、有用、有趣、有挑战性、令人兴奋的东西!

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值