Fabric.js简介

​在实际工作中,接触到整体的一个作业批改的流程。所以对作业的批改有部分了解,
​故做此fabric的使用总结,希望能够抛砖引玉,大家共同探讨

什么是Fabric.js

​ 一个功能强大的Javascript库,使使用HTML5 canvas变得轻而易举。
​ Fabric.js为Canvas提供所缺少的对象模型, 交互和一整套其他不可或缺的工具

为什么要用它而不用其他的

首先,Canvas提供了一个画布的能力, 但是api不够友好。我们在pc端的批改是用的原生canvas,但应用到小程序经过调研发现并不合适。canvas.绘制简单图形其

实还可以, 不过做一些复杂的图形绘制, 编写一些复杂的效果,就不是那么方便了。所以,我们决定使用Fabric.js来开发

它主要就是用对象的方式去编写代码。

原生: canvas 和fabric的对比

同样条件下绘制一个矩形

  • a.原生canvas
1
2
3
4
var canvasEl = document.getElementById('c');
var ctx = canvasEl.getContext('2d');
ctx.fillStyle =‘红色'; //在100,100点处创建20x20尺寸的矩形
ctx.fillRect(100,100,20,20);
  • b.fabric.js
1
2
3
4
5
6
7
8
var canvas = new fabric.Canvas('c');//创建一个矩形对象
var rect = new fabric.Rect({
left:100
top:100
fill:“红色”,
width:20
Height:20
});//在画布上“添加”矩形canvas.add(rect);

使用自由画笔

  • a.原生canvas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const drawLine = (x1, y1, x2, y2) =>
{
const { ctx } = getCanvas();
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.fillStyle = 'red';
ctx.strokeStyle = 'red';
ctx.moveTo(x1, y1); // lineTo(x, y) 绘制一条从当前位置到指定x以及y位置的直线
ctx.lineTo(x2, y2); // 通过线条来绘制图形轮廓
ctx.stroke();
ctx.closePath();
};

  • b.使用Fabric.js
1
2
3
4
5
freeDraw() {
canvasCtx.isDrawingMode = true;
canvasCtx.freeDrawingBrush.color = 'red';
canvasCtx.freeDrawingBrush.width = 2;
};

如何使用

引入:

1
2
3
    1、npm安装: npm install fabric --save
​ 2、通过CDN引入:<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>
​ 3、项目中引入使用: import { fabric } from 'fabric'

创建实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
js:
canvasCtx = new fabric.Canvas('my-canvas', {
enableRetinaScaling: true,
perPixelTargetFind: true, // 对象基于像素检测
skipTargetFind: true,
selection: false,
selectable: false
});

dom:
<canvas
id="my-canvas"
className="canvas"
width=375
height=650
></canvas>


由图可知,创建完实例后,fabric.js会构建两层 canvas 元素:lower-canvas 和 upper-canvas

lower-canvas: 只负责渲染元素

upper-canvas: 负责所有的事件处理

事件绑定

// 事件绑定

1
2
3
4
5
6
7
8
9
10
11
mouseEvent() {
canvasCtx.on('mouse:down', (options) => {
TODO:获取点坐标
});
canvasCtx.on('mouse:move', (options) => {
TODO:
});
canvasCtx.on('mouse:up', (options) => {
TODO:
};
}

​ 最新版本的Fabric已经不需要判断手动还是点击事件,兼容的Events.js能够兼容在移动端的手势操作:

根据下图对比可以看到,在不同平台下所触发的事件是不同的,所以可以开箱即用。

  • 移动端

  • PC端

绘制图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
creatImg() {
const imageUrl = new Image();
imageUrl.setAttribute('crossOrigin', 'Anonymous'); // 图片跨域
imageUrl.src = object.url;
imageUrl.onload = () => {
const imageBg = new fabric.Image(imageUrl, {
angle: 90, // 旋转角度
hasBorders: false, // 去掉边框,可以正常操作
selectable: false,
hasControls: false, // 只能移动不能(编辑)操作
crossOrigin: 'Anonymous' // 图片跨域
});
canvasCtx.add(imageBg);
};
}

移动图片

1
2
3
4
5
6
7
8
9
handleMoveCnavas(options) {
const {
x, y
} = movePosition;
const delta = new fabric.Point(options.x - x, options.y - y);
canvasCtx.relativePan(delta);
movePosition = options;
}

缩放事件

​ 下图为在移动端的示意图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// options --- 坐标点
// targetTouches 双指触发,长度为2
handleDoubleFinger(options) {
this.setOperationType('');
const {
clientX: finger1X,
clientY: finger1Y
} = options.e.targetTouches[0];
const {
clientX: finger2X,
clientY: finger2Y
} = options.e.targetTouches[1];
const powX = (finger2X - finger1X) * (finger2X - finger1X);
const powY = (finger2Y - finger1Y) * (finger2Y - finger1Y);
// 计算两个手指之间的距离
const distance = Math.sqrt(powX + powY);
// 每次缩放的比例
let ratio = -0.05;
if (distance > preDistance) {
ratio = 0.05;
}
preDistance = distance;
const x = scaleCenter.x || (Math.abs(finger1X + finger2X)) / 2;
const y = scaleCenter.y || (Math.abs(finger1Y + finger2Y)) / 2;
scaleCenter = {
x, y
};
// 计算当前缩放的大小
let zoom = ratio + canvasCtx.getZoom(); // 获取当前缩放比
zoom = Math.max(0.5, zoom);
zoom = Math.min(3, zoom);
const zoomPoint = new fabric.Point(x, y);
canvasCtx.zoomToPoint(zoomPoint, zoom);
}


旋转保存

  • 旋转前

  • 旋转后

总结:

fabric主要是canvas基础上的一次创新,能够解决很多原生canvas处理处理起来特别麻烦的地方,在整个实例对象下,

有一个_objects数组,是用来存储在画板上的所有元素,元素的数量直接决定数组的长度,在启用撤销功能时,本质上是维护

这个数组来实现。当然,Fabric的功能远不止这些,更深一层的理解需要日后不断的积累与总结。

附录:

常用的一些API

​ add(object) 添加
​ insertAt(object,index) 添加
​ remove(object) 移除
​ forEachObject 循环遍历
​ getObjects() 获取所有对象
​ item(int) 获取子项
​ isEmpty() 判断是否空画板
​ size() 画板元素个数
​ fabric.util.drawDashedLine 绘制虚线
​ clear() 清空
​ renderAll() 重绘
​ requestRenderAll() 请求重新渲染
​ rendercanvas() 重绘画板?
​ getCenter().top/left 获取中心坐标
​ toDatalessJSON() 画板信息序列化成最小的json
​ toJSON() 画板信息序列化成json
​ moveTo(object,index) 移动
​ setCursor() 设置手势图标
​ getSelectionContext()获取选中的context
​ getSelectionElement()获取选中的元素
​ getActiveObject() 获取选中的对象
​ getActiveObjects() 获取选中的多个对象
​ discardActiveObject()取消当前选中对象
​ rotate() 设置旋转角度
​ setCoords() 设置坐标

fabric.js官方文档: [fabric.js官方文档]