| Fabric.js 简单介绍和使用
					当前位置:点晴教程→知识管理交流
					
					→『 技术文档交流 』
					
				 
 简介Fabric.js是一个可以简化canvas程序编写的库。 Fabric.js为canvas提供所缺少的对象模型, svg parser, 交互和一整套其他不可或缺的工具。基于MIT协议开源,在github上有许多人贡献代码。 Why fabric?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 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); 
 好的 其实并没有什么差别 不过我们试着旋转一下角度 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); 如果我们想重新调整位置 怎么办 var canvasEl = document.getElementById('c'); ... ctx.strokRect(100, 100, 20, 20); ... // erase entire canvas area ctx.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(); objects
 画一个三角形 和一个 圆形 // create a wrapper around native canvas element (with id="c") var canvas = new fabric.Canvas('c'); 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); 
 Manipulating objects可以简单的使用set来控制对象属性 rect.set('fill', 'red'); rect.set({ strokeWidth: 5, stroke: 'rgba(100,200,200,0.5)' }); rect.set('angle', 15).set('flipY', true); 
 有了set 其实也就有了get,对象可以创建时设置属性,也可以先实例化再赋值。 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.Rect是函数,大家可以使用class继承。 默认值var rect = new fabric.Rect(); // notice no options passed in rect.getWidth(); // 0 rect.getHeight(); // 0 rect.getLeft(); // 0 rect.getTop(); // 0 rect.getFill(); // rgb(0,0,0) rect.getStroke(); // null rect.getOpacity(); // 1 Hierarchy and Inheritancefabric.Object 是图像基类 你可以自己扩充方法 fabric.Object.prototype.getAngleInRadians = function() { return this.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; // true circle instanceof fabric.Object; // true Canvasfabric.Canvas 是canvas的wrapper 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 经典的设计 有options 有对象方法 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(){ /* ... */ }; // ... Images使用fabric.Image你可以轻松的加载一个图片 <canvas id="c"></canvas> <img src="my_image.png" id="my-image"> 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); 
 当然也可以通过url加载一张图片到canvas fabric.Image.fromURL('my_image.png', function(oImg) { canvas.add(oImg); }); 可以对加载的图片进行预处理 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); }); Path and PathGroup我们已经看了简单的形状,然后图像。更复杂、丰富的形状和内容呢? 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); 
 “M” 代表 “move” 命令, 告诉笔到 0, 0 点. ... 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); path也可以设置canvas属性 
 当然,太困然了,所以你可以使用 fabric.loadSVGfromString or fabric.loadSVGfromURL 方法。 Afterword看些demo吧。 上面我们学习了基础用法,现在我们开始一些好玩的。 Animation我们先回顾设置一下正方形角度方法 rect.set('angle', 45);这是没有动画的 Fabric object都有animate方法 rect.animate('angle', 45, {
  onChange: canvas.renderAll.bind(canvas)
});那么正方形会从0到45有一个动画过度 从左到右进行变动 rect.animate('left', '+=100', { onChange: canvas.renderAll.bind(canvas) });逆时针转5度 rect.animate('angle', '-=5', { onChange: canvas.renderAll.bind(canvas) });当然animate还支持这些方法 
 rect.animate('left', '+=100', {
    onChange: canvas.renderAll.bind(canvas),
    duration: 3000,
    easing: fabric.util.ease.easeOutBounce
});Image filters图片可以使用filter效果 fabric.Image.fromURL('pug.jpg', function(img) {
  // add filter
  img.filters.push(new fabric.Image.filters.Grayscale());
  // apply filters and re-render canvas when done
  img.applyFilters(canvas.renderAll.bind(canvas));
  // add image onto canvas
  canvas.add(img);
});filter一次可以使用多个效果 当然 你也可以自己定义filter fabric.Image.filters.Redify = fabric.util.createClass({
  type: 'Redify',
  applyTo: function(canvasEl) {    var context = canvasEl.getContext('2d'),
        imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
        data = imageData.data;
        for (var i = 0, len = data.length; i < len; i += 4) {
              data[i + 1] = 0;
              data[i + 2] = 0;
    }
    context.putImageData(imageData, 0, 0);
  }
});
fabric.Image.filters.Redify.fromObject = function(object) {
  return new fabric.Image.filters.Redify(object);
};Colorsfabric 支持 hex rgb rgba颜色 new fabric.Color('#f55');
new fabric.Color('#123123');
new fabric.Color('356735');
new fabric.Color('rgb(100,0,100)');
new fabric.Color('rgba(10, 20, 30, 0.5)');并且支持相互转换 new fabric.Color('#f55').toRgb(); // "rgb(255,85,85)"
new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
new fabric.Color('fff').toHex(); // "FFFFFF"两种颜色可以叠加 并且你可以使用一些特定效果 var redish = new fabric.Color('#f55');
var greenish = new fabric.Color('#5f5');
redish.overlayWith(greenish).toHex(); // "AAAA55"
redish.toGrayscale().toHex(); // "A1A1A1"Gradients可以使用渐变色 var circle = new fabric.Circle({  left: 100,  top: 100,  radius: 50});
circle.setGradient('fill', {
  x1: 0,  y1: -circle.height / 2,  x2: 0,  y2: circle.height / 2,  colorStops: {
    0: '#000',    1: '#fff'
  }
});首先确定两个点 在其距离中以百分比定位颜色 circle.setGradient('fill', {
  x1: -circle.width / 2,
  y1: 0,  x2: circle.width / 2,  y2: 0,  colorStops: {
      0: "red",    0.2: "orange",    0.4: "yellow",    0.6: "green",    0.8: "blue",    1: "purple"
  }
});Text
 如何添加文字 var text = new fabric.Text('hello world', { left: 100, top: 100 });
canvas.add(text);fontFamily var comicSansText = new fabric.Text("I'm in Comic Sans", {fontFamily: 'Comic Sans'});fontSize var text40 = new fabric.Text("I'm at fontSize 40", {fontSize: 40});
var text20 = new fabric.Text("I'm at fontSize 20", {fontSize: 20});fontWeight var normalText = new fabric.Text("I'm a normal text", {fontWeight: 'normal'});
var boldText = new fabric.Text("I'm at bold text", {fontWeight: 'bold'});textDecoration var underlineText = new fabric.Text("I'm an underlined text", {textDecoration: 'underline'});
var strokeThroughText = new fabric.Text("I'm a stroke-through text", {textDecoration: 'line-through'});
var overlineText = new fabric.Text("I'm an overline text", {textDecoration: 'overline'});shadow var shadowText1 = new fabric.Text("I'm a text with shadow", {  shadow: 'rgba(0,0,0,0.3) 5px 5px 5px'});
var shadowText2 = new fabric.Text("And another shadow", {  shadow: 'rgba(0,0,0,0.2) 0 0 5px'});
var shadowText3 = new fabric.Text("Lorem ipsum dolor sit", {  shadow: 'green -5px -5px 3px'});fontStyle var italicText = new fabric.Text("A very fancy italic text", {  fontStyle: 'italic',  fontFamily: 'Delicious'});
var anotherItalicText = new fabric.Text("another italic text", {  fontStyle: 'italic',  fontFamily: 'Hoefler Text'});stroke & strokeWidth var textWithStroke = new fabric.Text("Text with a stroke", {  stroke: '#ff1318',  strokeWidth: 1});
var loremIpsumDolor = new fabric.Text("Lorem ipsum dolor", {  fontFamily: 'Impact',  stroke: '#c3bfbf',  strokeWidth: 3});textAlign var text = 'this is\na multiline\ntext\naligned right!';
var alignedRightText = new fabric.Text(text, {  textAlign: 'right'});lineHeight var lineHeight3 = new fabric.Text('Lorem ipsum ...', {  lineHeight: 3});
var lineHeight1 = new fabric.Text('Lorem ipsum ...', {  lineHeight: 1});textBackgroundColor var text = 'this is\na multiline\ntext\nwith\ncustom lineheight\n&background';
var textWithBackground = new fabric.Text(text, {  textBackgroundColor: 'rgb(0,200,0)'});Events怎么可以没有事件呢 事件以on off使用 canvas 可以捕捉事件 mouseevent renderevent selectionevent objectevent var canvas = new fabric.Canvas('...');
canvas.on('mouse:down', function(options) {
    console.log(options.e.clientX, options.e.clientY);
});同样这些事件也可以用任何fabric对象监听 var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
rect.on('selected', function() {
 console.log('selected a rectangle');
});
var circle = new fabric.Circle({ radius: 75, fill: 'blue' });
circle.on('selected', function() {
 console.log('selected a circle');
});上面我们学习了基础和高级特性,现在介绍更神奇的东西。 Groups话说这个功能我最喜欢,组成群组可以统一修改其中所有组件属性,如何定义: 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);现在我们就可以对其中的对象集修改 group.item(0).setFill('red');
group.item(1).set({
  text: 'trololo',
  fill: 'white'
});group中的元素相对于group定位 但是由于要确保之前得到却切位置 所以要异步 fabric.Image.fromURL('/assets/pug.jpg', function(img) {
  var img1 = img.scale(0.1).set({ left: 100, top: 100 });
  fabric.Image.fromURL('/assets/pug.jpg', function(img) {
    var img2 = img.scale(0.1).set({ left: 175, top: 175 });
    fabric.Image.fromURL('/assets/pug.jpg', function(img) {
      var img3 = img.scale(0.1).set({ left: 250, top: 250 });
      canvas.add(new fabric.Group([ img1, img2, img3], { left: 200, top: 200 }))
    });
  });
});group 可以动态添加 group.add(new fabric.Rect({
  ...
  originX: 'center',
  originY: 'center'
}));添加并修改group group.addWithupdate(new fabric.Rect({
  ...
  left: group.getLeft(),
  top: group.getTop(),
  originX: 'center',
  originY: 'center'
}));当然 你可以使用canvas上已有的进行克隆 组合 // create a group with copies of existing (2) objects var group = new fabric.Group([ canvas.item(0).clone(), canvas.item(1).clone() ]); // remove all objects and re-render canvas.clear().renderAll(); // add group onto canvas canvas.add(group); Serialization序列化是为了相互传输 toObject, toJSONcanvas 实现了toJSON接口 可以被序列化 var canvas = new fabric.Canvas('c');
JSON.stringify(canvas); // '{"objects":[],"background":"rgba(0, 0, 0, 0)"}'canvas 可以随时被修改 json数据会被修改 canvas.backgroundColor = 'red';
JSON.stringify(canvas); // '{"objects":[],"background":"red"}'添加新对象 也会改变json数据 canvas.add(new fabric.Rect({  left: 50,  top: 50,  height: 20,  width: 20,  fill: 'green'}));
console.log(JSON.stringify(canvas));'{"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}],"background":"rgba(0, 0, 0, 0)"}'再添加一个 canvas.add(new fabric.Circle({  left: 100,  top: 100,  radius: 50,  fill: 'red'}));
console.log(JSON.stringify(canvas));'{"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)"}'toObject可以转化成js object对象 { "background" : "rgba(0, 0, 0, 0)",
  "objects" : [
    {
      "angle" : 0,
      "fill" : "green",
      "flipX" : false,
      "flipY" : false,
      "hasBorders" : true,
      "hasControls" : true,
      "hasRotatingPoint" : false,
      "height" : 20,
      "left" : 50,
      "opacity" : 1,
      "overlayFill" : null,
      "perPixelTargetFind" : false,
      "scaleX" : 1,
      "scaleY" : 1,
      "selectable" : true,
      "stroke" : null,
      "strokeDashArray" : null,
      "strokeWidth" : 1,
      "top" : 50,
      "transparentCorners" : true,
      "type" : "rect",
      "width" : 20
    }
  ]}每个fabric对象有toObject方法 这和toJSON 也有关 可以自定义 var rect = new fabric.Rect();
rect.toObject = function() {
  return { name: 'trololo' };
};
canvas.add(rect);
console.log(JSON.stringify(canvas));'{"objects":[{"name":"trololo"}],"background":"rgba(0, 0, 0, 0)"}'当然我们可以保留原有的数据 新增数据 var rect = new fabric.Rect();rect.toObject = (function(toObject) {
  return function() {
    return fabric.util.object.extend(toObject.call(this), {
      name: this.name
    });
  };
})(rect.toObject);
canvas.add(rect);rect.name = 'trololo';
console.log(JSON.stringify(canvas));'{"objects":[{"type":"rect","left":0,"top":0,"width":0,"height":0,"fill":"rgb(0,0,0)","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,"name":"trololo"}],"background":"rgba(0, 0, 0, 0)"}'toSvg怎么能不支持转成svg呢 canvas.add(new fabric.Rect({ left: 50,  top: 50,  height: 20,  width: 20,  fill: 'green'}));
console.log(canvas.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="20" height="20" style="stroke: none; stroke-width: 1; stroke-dasharray: ; fill: green; opacity: 1;" transform="translate(50 50)" /></svg>' Deserialization, SVG parserfabric.Canvas#loadfromJSON 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.Canvas#toDatalessJSON canvas.item(0).sourcePath = '/assets/dragon.svg'; console.log(JSON.stringify(canvas.toDatalessJSON())); {"objects":[{"type":"path","left":143,"top":143,"width":175,"height":151,"fill":"#231F20","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,"path":"/assets/dragon.svg"}],"background":"rgba(0, 0, 0, 0)"}Subclassing构造类 var Point = fabric.util.createClass({
  initialize: function(x, y) {    this.x = x || 0;    this.y = y || 0;
  },
  toString: function() {    return this.x + '/' + this.y;
  }
});继承类 var ColoredPoint = fabric.util.createClass(Point, {
  initialize: function(x, y, color) {    this.callSuper('initialize', x, y);    this.color = color || '#000';
  },
  toString: function() {    return this.callSuper('toString') + ' (color: ' + this.color + ')';
  }
});继承默认类 var LabeledRect = fabric.util.createClass(fabric.Rect, {
  type: 'labeledRect',
  initialize: function(options) {
    options || (options = { });    this.callSuper('initialize', options);    this.set('label', options.label || '');
  },
  toObject: function() {    return fabric.util.object.extend(this.callSuper('toObject'), {
      label: this.get('label')
    });
  },
  _render: function(ctx) {    this.callSuper('_render', ctx);
    ctx.font = '20px Helvetica';
    ctx.fillStyle = '#333';
    ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
  }
});不过其实没必要的。 该文章在 2023/5/23 16:49:36 编辑过 | 关键字查询 相关文章 正在查询... |