LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

强大的Canvas开源库Fabric.js简介与开发指南

admin
2023年5月23日 15:50 本文热度 2575


什么是Fabric.js

Fabric.js 是一个强大且简单的Javascript HTML5 Canvas库。

官网地址:http://fabricjs.com/

为什么要使用Fabric.js?

Canvas提供一个好的画布能力, 但是Api不够友好。绘制简单图形其实还可以, 不过做一些复杂的图形绘制, 编写一些复杂的效果,就不是那么方便了。Fabric.js就是为此而开发,它主要用对象的方式去编写代码。

Fabric.js能做的事情

  • 在Canvas上创建、填充图形(包括图片、文字、规则图形和复杂路径组成图形)。

  • 给图形填充渐变颜色。

  • 组合图形(包括组合图形、图形文字、图片等)。

  • 设置图形动画及用户交互。

  • 生成JSON、SVG数据等。

  • 生成Canvas对象自带拖拉拽功能。

它提供了灵活丰富的Api和可配置化参数轻松实现复杂的效果,该开源库已被许多开发者用于项目实践中,广受好评。

下载趋势图


项目开发实战

这里基于React框架为基础,介绍Fabric.js开发实战实例。

1、安装Fabric.js

npm install fabric --save

yarn add fabric

官网还支持按需模块定制构建,在你需要的特性模块前面勾选,然后一键构建。这样可以使得你整体的代码量减少。


2、引入Fabric.js
import {fabric} from 'fabric';
3、initCanvas 画布初始化

//创建画布

let canvasObj = new fabric.Canvas('snackCanvas');

//设置画布背景色

canvasObj.setBackgroundColor('#d5d5d5');

//设置画布宽度

canvasObj.setWidth(this.state.canvasWidth);

//设置画布高度

canvasObj.setHeight(this.state.canvasHeight);

//标识画布中元素选中时,是否还按原有的层级位置展示

canvasObj.preserveObjectStacking = true;/**

* 设置元素选中框的样式

*/

//边角节点背景透明 false

fabric.Object.prototype.transparentCorners = false;

//边角节点大小

fabric.Object.prototype.cornerSize = 6;

//边框颜色

fabric.Object.prototype.borderColor = 'rgba(83,152,248,1)';

//角节点内部颜色

fabric.Object.prototype.cornerColor = 'white';

//角节点边框颜色

fabric.Object.prototype.cornerStrokeColor = 'rgba(83,152,248,1)';/**

* 设置对象位置Left/Top的基准参考位置为自身中心点

* 默认 对象采用相对自身中心点旋转,即centeredRotation=true

*/

fabric.Object.prototype.originX = 'center';

fabric.Object.prototype.originY = 'center';this.editor = canvasObj;

4、画布事件监听

//元素点击选中事件处理

canvasObj.on('selection:created', function(options) {

  //console.log('selection:created');

  //console.log(options);

  if (options.target) {

    // TODO

  }

}

//元素选中更新事件处理

canvasObj.on('selection:updated', function(options) {

  //console.log('selection:updated');

  //console.log(options);

  if (options.target) {

    // TODO

  }

}

//元素取消选中事件处理

canvasObj.on('selection:cleared', function(options) {

  //console.log('selection:cleared');

}

//对象移动完毕事件处理

canvasObj.on('object:moved', function(options) {

  //console.log('moved');

  //console.log(options);

  if (options.target) {}

}

//对象旋转完成事件处理

canvasObj.on('object:rotated', function(options) {

  //console.log('rotated');

  //console.log(options);

  if (options.target) {

    // TODO

  }

}

//对象缩放完成事件处理

canvasObj.on('object:scaled', function(options) {

  //console.log('scaled');

  //console.log(options);

  if (options.target) {}

}

//对文本编辑修改后

canvasObj.on('text:changed', function(options) {

  //console.log('text:changed');

  //console.log(options);

  if (options.target) {}

}

5、画布拖拽事件处理

/**

* 拖拽事件处理 start

*/

document.addEventListener('dragstart', function(e){

  //拖拽图片,并传递对象

  if(e.target.className == 'img'){

    scope.mouseX = e.offsetX;scope.mouseY = e.offsetY;

    //拖拽数据

    let sourceStr = e.target.dataset.source;

    if(sourceStr){scope.dragData = JSON.parse(sourceStr);}

    scope.figureType = e.target.className;

  }

}, false);

document.addEventListener('dragover', function(e){e.preventDefault();}, false);

//拖拽动作

this.dragObj('drop');

dragObj(eventName){

  let scope = this;

  this.editor.on(eventName, function(opt){if((opt.e.target.className).trim() == 'upper-canvas'){scope.dragEvt(eventName, opt);}});

}

dragEvt(eventName, opt){

  let scope = this;

  if(eventName == 'dragover'){opt.e.preventDefault();}else if(eventName == 'drop'){//拖拽结束opt.e.preventDefault();//console.log(this.dragData);////对拖拽数据进行业务处理//}

}

/**

* 拖拽事件处理 end 

*/

6、画布中的图片加载

const dragImageUrl = this.dragData.imageUrl;

fabric.Image.fromURL(dragImageUrl, function(image){

  image.set({id: getUUID(),left: imageLeft, top: imageTop,width: nodeWidth,height: nodeHeight,classname: 'img',source: scope.dragData,selectable,hasContorls}).scale(scope.state.canvasScale, scope.state.canvasScale).setCoords();

  //添加到画布

  scope.editor.add(image);

  //设置当前素材为选中状态

  scope.editor.setActiveObject(image);

  //重新渲染

  scope.editor.requestRenderAll();

});

7、画布中的字体库加载

//加载字体库数据, 默认load()方法 超时时长默认为3秒钟

loadAndUse(object, fontName, scope) {

  let myfont = new FontFaceObserver(fontName);

  myfont.load(null, 5000).then(function() {

    // when font is loaded, use it.

    if(object){

      object.source.fontFamily = fontName;

      object.set("fontFamily", fontName).setCoords();

      scope.editor.requestRenderAll();

    }

  }).catch(function(e){console.log(e);alert('字体 ' + fontName + ' 加载失败。');});

}

//字体方法的使用

this.loadAndUse(null, '宋体', this);

8、画布内容转换成图片保存到后台

saveData(){

  ... 省略其他代码 ...

  let paramData = new FormData();

  let dataUrl = this.editor.toDataURL();

  let blobImage = this.dataURLtoBlob(dataUrl);

  blobImage.contentType = 'application/octet-stream';

  paramData.append("file", blobImage);

  ... 省略其他代码 ...

}

//数据类型转换

dataURLtoBlob(dataurl){

  let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);

  while(n--){u8arr[n] = bstr.charCodeAt(n);}

  return new Blob([u8arr], {type:'application/octet-stream'});

}

9、画布Canvas绘制的元素合并为一组

将两个元素深深地绑定在一起,任何操作同时对两个有效,这里叫组的概念

const circle = new fabric.Circle({radius: 100,fill: '#eef',scaleY: 0.5,originX: 'center',originY: 'center'});

const text = new fabric.Text('hello world', {fontSize: 30,originX: 'center',originY: 'center'});

const group = new fabric.Group([circle, text], {left: 150,top: 100,angle: -10});

9、Canvas画布中将两个元素之间建立BOSS关系

怎么理解就是将一个元素变为另一个元素的boss,boss元素拖动旋转操作,另一个元素跟着同样变,但是反过来就不行

bindMinionToBoss(canvas: fabric.Canvas, boss: fabric.Group): void {

  const minions = canvas.getObjects().filter((o: any) => o !== boss);const bossTransform = boss.calcTransformMatrix();

  const invertedBossTransform = fabric.util.invertTransform(bossTransform);

  minions.forEach((o: any) => {const desiredTransform = fabric.util.multiplyTransformMatrices(invertedBossTransform,o.calcTransformMatrix());o.relationship = desiredTransform;});

  boss.on("moving", () => {

    minions.forEach((o: any) => {

    if (!o.relationship) return;

    const newTransform = fabric.util.multiplyTransformMatrices(boss.calcTransformMatrix(),o.relationship);const opt = fabric.util.qrDecompose(newTransform);const point = new fabric.Point(opt.translateX, opt.translateY);o.setPositionByOrigin(point, "center", "center");o.set(opt);o.setCoords();

    });

  });

}

其他详细Api请参见:

http://fabricjs.com/docs/

另外还有很多好玩有趣的功能等着我们去发现,可以参照官网的例子:

http://fabricjs.com/demos/

如果使用中出现常见问题,优先参考:

http://fabricjs.com/fabric-gotchas


该文章在 2024/11/26 12:00:30 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved