Fabric.js 是一个基于 HTML5 canvas 的开源JavaScript工具库。
fabric.js的使用
Fabric提供了7种基础图形api
const canvas = new fabric.Canvas("canvas", {
backgroundColor: "green",
selectionColor: "red",
selectionLineWidth: 1,
});
- fabric.Circle 圆
var circle = new fabric.Circle({
radius: 50, fill: 'red', left: 10, top: 10
});
canvas.add(circle);
- fabric.Ellipse椭圆
var Ellipse = fabric.Ellipse({
rx:number,//指定水平半径
ry:number,//指定垂直半径
fill:string,//指定填充椭圆的颜色。
});
canvas.add(Ellipse);
- fabric.Line线段
let line = new fabric.Line([10, 10, 100, 100], {
fill: 'green', //填充颜色
stroke: 'green', //边框颜色
strokeWidth: 2, //宽度
})
canvas.add(line)
- fabric.Polygon多边形
// 多边形
let polygon = new fabric.Polygon(
[
{
x: 100,
y: 10,
},
{
x: 250,
y: 10,
},
{
x: 250,
y: 180,
},
{
x: 150,
y: 180,
},
],
{
left: 100,
top: 50,
fill: "red",
strokeWidth: 4,
stroke: "green",
perPixelTargetFind: true,
}
);
canvas.add(polygon);
- fabric.Polyline 多段线
var polygon = new fabric.Polyline(
[
{ x: 0, y: 0 },
{ x: 50, y: 0 },
{ x: 50, y: 50 },
{ x: 0, y: 50 },
],
{
top: 50,
left: 50,
fill: "green",
}
);
canvas.add(polygon);
- fabric.Rect矩形
var rect = new fabric.Rect({
fill: 'yellow',
width: 10,
height: 10,
});
canvas.add(rect);
- fabric.Triangle三角形
var triangle = new fabric.Triangle({
width: 20, height: 30, fill: 'blue', left: 50, top: 50
});
canvas.add(triangle);
fabric中的获取默认属性
var rect = new fabric.Rect(); // 这里没有传递任何参数
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
fabric对象常用属性
- 定位:
top,left。 - 尺寸:
width,height。 - 渲染:
fill,opacity,stroke,strokeWidth。 - 缩放和旋转:
scaleX,scaleY,angle; - 翻转:
flipX,flipY。 - 歪斜:
skewX,skewY。
var rect = new fabric.Rect({
left: 10,
top: 10,
fill: 'yellow',
width: 10,
height: 10,
angle: 120 //需要旋转我们只需要配置即可
});
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);
属性set还支持链式调用,并且,在canvas.add(triangle);之前或者之后调用,都是可以的: triangle.set("fill", "red").set("stroke", "red");//改变某个形状的填充和边框颜色 或者obj.set传入属性对象也是可以的 obj.set({属性名:属性值})
我们想在画布上画一个黄色的矩形。
var canvas = new fabric.Canvas('idkey');
// 创建一个矩形对象
var rect = new fabric.Rect({
left: 10,
top: 10,
fill: 'yellow',
width: 10,
height: 10,
angle: 120 //需要旋转我们只需要配置即可
});
// 然后再将矩形添加到画布上
canvas.add(rect);
我们想在画布上创建一个包含两个Fabric对象的组合,圆和文本
var circle = new fabric.Circle({
radius: 100,
fill: '#eef',
scaleY: 0.5,
originX: 'center',
originY: 'center'
});
var text = new fabric.Text('hello world', {
fontSize: 30,
originX: 'center',
originY: 'center'
});
var group = new fabric.Group([ circle, text ], {
left: 150,
top: 100,
angle: -10
});
canvas.add(group);
我们想要修改让canvas画布上的这个组合
group.item(0).setFill('green');
group.item(1).set({
text: 'not hello',
fill: 'black'
});
组合时可能用到的方法
- getObjects()————返回一个包含组合中所有对象的数组
- size()————返回组合中所有对象的数量。
- contains()————可以检查某个对象是否在组合中。
- item()————可以检索组中的特定对象。
- forEachObject————可以遍历每个组合中的对象。
- add()————组合中添加对象。
- remove()————组合中删除对象。
group.add(new fabric.Rect({
...
originX: 'center',
originY: 'center'
}));
group.addWithUpdate(new fabric.Rect({
...
left: group.get('left')+10,
top: group.get('top')+10,
originX: 'center',
originY: 'center'
}));
和原生canvas对比起来,在fabric中,我们只需要操作对象,实例化,改属性,添加就可以实现。 使用fabric.js 在需要编辑之前,我们不再需要清除画布。我们只需更改对象属性,然后重新绘制画布即可。
使用fabric加载图片
加载多个图片,要考虑到前面图片加载完毕的情况。
fabric.Image.fromURL('1.png', function(img) {
let img1 = img.scale(0.5).set({ left: 10, top: 10 });
fabric.Image.fromURL('2.png', function(img) {
let img2 = img.scale(0.5).set({ left: 100, top: 100 });
fabric.Image.fromURL('3.png', function(img) {
let img3 = img.scale(0.5).set({ left: 200, top: 200 });
canvas.add(new fabric.Group([ img1, img2, img3], { left: 100, top: 100 }))
});
});
});
fabric中的canvas序列化方法
- toObject()
- toJSON()
我们先来看一个简单的例子
let canvas = new fabric.Canvas('id');
canvas.backgroundColor = 'red';
JSON.stringify(canvas);
// '{"objects":[],"background":"red'
我们使用ES5的JSON.stringify()方法,如果toJSON方法存在,则会隐性调用。
因为fabric中的canvas实例已经具有toJSON方法,就相当于我们调用了canvas.toJSON()。
// 创建一个矩形对象
var rect = new fabric.Rect({
left: 10,
top: 10,
fill: 'yellow',
width: 10,
height: 10,
angle: 120
});
canvas.add(rect);
console.log(JSON.stringify(canvas));
//{"objects":[{"type":"rect","left":10,"top":10,"width":10,"height":10,"fill":"yellow","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":120,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}
console.log(canvas.toObject())
//{ "background" : "rgba(0, 0, 0, 0)",
"objects" : [
{
"angle" : 120,
"fill" : "yellow",
"flipX" : false,
"flipY" : false,
"hasBorders" : true,
"hasControls" : true,
"hasRotatingPoint" : false,
"height" : 10,
"left" : 10,
"opacity" : 1,
"overlayFill" : null,
"perPixelTargetFind" : false,
"scaleX" : 1,
"scaleY" : 1,
"selectable" : true,
"stroke" : null,
"strokeDashArray" : null,
"strokeWidth" : 1,
"top" : 10,
"transparentCorners" : true,
"type" : "rect",
"width" : 10
}
]
}
转SVG图
canvas.add(new fabric.Rect({
left: 10,
top: 10,
height:10,
width: 10,
fill: 'red'
}));
console.log(canvas.toSVG());//直接调用toSVG即可。
输出结果:
'<?xml version="1.0" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800" height="700" xml:space="preserve"><desc>Created with Fabric.js 0.9.21</desc><rect x="-10" y="-10" rx="0" ry="0" width="10" height="10" style="stroke: none; stroke-width: 1; stroke-dasharray: ; fill: red; opacity: 1;" transform="translate(10 10)" /></svg>'
反序列化,SVG解析
如果反序列表是json时使用canvas.loadFromJSON和canvas.loadFromDatalessJSON
var canvas = new fabric.Canvas();
canvas.loadFromJSON('{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0},{"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}');
如果反序列表是svg时使用fabric.loadSVGFromURL和fabric.loadSVGFromString
fabric.loadSVGFromURL('要加载的svg地址', (objects, options) => {
let img1 = fabric.util.groupSVGElements(objects, options);
img1.set({
left: 100,
top: 100,
});
canvasContainer.add(img1);
});
fabric.loadSVGFromString('./1.svg', function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
fabric的子类
在 fabric.js 中创建类,可以使用 fabric.util.createClass() 方法。
let Point = fabric.util.createClass({
initialize: function(x, y) {
this.x = x || 0
this.y = y || 0
},
toString: function() {
return `${this.x}/${this.y}`
}
})
fabric.util.createClass 接受一个对象参数,并基于该对象的配置创建一个“类”。
需要留意的是 initialize 属性,initialize 的值是一个方法,用于初始化。
在 initialize 中接收实例化时传进来的参数。
let point = new Point(10, 20)
console.log(point.x) // 10
console.log(point.y) // 20
console.log(point.toString()) // "10/20"
在创建类时,只需在 fabric.util.createClass 中传入1个对象即可。
如果创建子类时需要继承某个父类,则要在 fabric.util.createClass 中传入2个参数。
fabric.util.createClass(parentopt, propertiesopt)
parentopt: 父类propertiesopt创建子类的对象(和前面创建类的对象一样) 在前面的创建类时,我们创建了一个Point的类,这个类只接受x和y属性以及内部的toString()方法。
假设需要在 Point 类的基础上再创建一个 jcPoint 类(也就是 jcPoint 继承 Point),可以这样写。
let jcPoint = fabric.util.createClass(
// 参数1:父类
Point,
// 参数2:子类
{
initialize: function(x, y, color) {
this.callSuper('initialize', x, y) // 传给父类的
this.color = color || '#000' // 新增的 color 属性
}
}
)
此时 jcPoint 就继承了 Point ,并在 Point 的基础上多了 color 属性了。
let redPoint = new jcPoint(10, 10, 'red')
console.log(redPoint.x) // 10
console.log(redPoint.y) // 10
console.log(redPoint.color) // "red"
console.log(redPoint.toString()) // "10/10"
Point 里有 toString() 方法, redPoint.toString() 会先 jcPoint 找,找不到就从 Point 找。一层层往上找。
如果在 jcPoint 中又定义了 toString() 方法,就会覆盖 Point 里定义的。
// 父类
let Point = new fabric.util.createClass({
initialize(x, y) {...},
toString() {
return this.x + '/' + this.y
}
})
// 子类
let jcPoint = fabric.util.createClass(
// 参数1:父类
Point,
// 参数2:子类
{
initialize(x, y, color) {...},
toString() {
return 'hello'
}
}
)
// 实例化
let redPoint = new jcPoint(15, 33, '#f55')
console.log(redPoint.toString()) // "hello"
如果在子类中想继承父类的方法可以使用 callSuper 。
// 父类
let Point = new fabric.util.createClass({...})
// 省略部分代码
let jcPoint = fabric.util.createClass(
// 参数1:父类
Point,
// 参数2:子类
{
initialize(x, y, color) {...},
toString() {
return this.callSuper('toString')
}
}
)
// let redPoint = new jcPoint(12, 13, 'red')
console.log(redPoint.toString()) // "12/13"