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

什么是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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模拟qq斗地主-准备发牌抢地主都是农民下一轮准备

为什么要搞这样一个项目?? 1,满足自己的java网络多线程编程的欲望!因为之前一直都是搞web开发,服务器和客户端数据交流人家web服务器早就给你搞好了,比如tomcat,jetty...等等,其实之前脑子里就有…

rube3xxx_Rube GoldbergSpring整合

rube3xxxSpring Integration为集成系统所涉及的一些复杂性提供了非常好的抽象-Spring Integration从Integration的角度完美地满足了Facade的定义-简化了对复杂基础系统的访问。 为了说明这一点,请考虑一个简单的系统,该系统仅接收一条消息,然…

纯CSS实现React Logo图形,内含详细解析

以上是将要实现的效果&#xff0c;Javascript框架React的Logo图形&#xff0c;首先我们来拆解下&#xff0c;它包括三个交叉的椭圆和中间一个圆点&#xff0c;所以我们Html元素可以用以下代码实现&#xff1a;<div class"main"><div class"ellipse ell…

二次优化大招(由泰勒公式推出最值条件)

经过前两篇的铺垫&#xff0c;这一篇迎来了高潮。先说一句&#xff1a;特征值大法好&#xff01; 在开始正文之前&#xff0c;先看以下简单的推导 有了这些&#xff0c;理解下面的泰勒公式推出最值条件就容易了 转载于:https://www.cnblogs.com/Mr-ZeroW/p/7764916.html

前端自动化测试浅析

前言&#xff1a;测试简介前端常见的问题&#xff1a;修改某个模块功能时&#xff0c;其它模块也受影响&#xff0c;很难快速定位bug多人开发代码越来越难以维护不方便迭代&#xff0c;代码无法重构代码质量差增加自动化测试后&#xff1a;我们为核心功能编写测试后可以保障项目…

使用SpringData出现java.lang.AbstractMethodError

最近学习一下SpringData&#xff0c;在添加SpringData支持的时候&#xff0c;出现了这样的问题&#xff1a; SpringData需要的jar有:spring-data-jpa.jar spring-data-commons.jar slf4j-api.jar 没有添加slf4j也会出现一个异常&#xff0c;不过那个异常说的非常明确&#xf…

2021这份电子书单请收好(品类齐全)!

2021年已经快过去一个月了&#xff0c;今年的读书计划有没有安排上&#xff0c;这里有份长长的书单&#xff0c;多年的积累&#xff0c;品类齐全&#xff0c;赶快从中挑几本加入今年的读书计划里。•《货币战争2&#xff1a;金权天下》 - 宋鸿兵.mobi•《圣经》中英对照豪华版 …

在Kotlin中使用libGDX

最近&#xff0c;我一直在阅读有关不同语言的信息&#xff0c;以及它们可以为已经拥挤的软件开发人员带来什么&#xff0c;而一种语言对我来说很突出&#xff1a;Kotlin。 &#xff08; https://kotlinlang.org/ &#xff09; 这是一种相对较新的语言&#xff08;成立于2011年…

【重学JS系列】slice用法大合集

让我们回顾下slice的日常用法slice 工作原理在深入研究一些更高级的用法之前&#xff0c;让我们看一下slice方法的基础知识。如MDN文档&#xff0c;slice 是数组上的一个方法&#xff0c;它最多有两个参数:arr.slice([begin[, end]])begin从该索引处开始提取原数组中的元素,如果…

【Github开源】一站搞定各种开发文档

开发者的苦恼&#xff1a;经常要在多个API文档中切换&#xff0c;浏览器书签栏收藏各种语言相关的接口说明文档。无意中在Github上发现DevDocs[1]这个开源项目&#xff0c;它是一个把所有开发相关的文档以web的形式做了一个综合的网站&#xff0c;并提供搜索&#xff0c;离线访…

javafx 表单_JavaFX 2:创建登录表单

javafx 表单在本教程中&#xff0c;我将使用JavaFX 2和CSS设计一个外观漂亮的Login Form 。 它是经典的登录表单&#xff0c;带有用户名和密码以及登录按钮。 为了遵循本教程&#xff0c;我强烈建议您查看以下这些教程&#xff1a; Eclipse IDE中的JavaFX 2入门 JavaFX 2&…

【详细教程】教你如何使用Node + Express + Typescript开发一个应用

Express是nodejs开发中普遍使用的一个框架&#xff0c;下面要谈的是如何结合Typescript去使用。 目标 我们的目标是能够使用Typescript快速开发我们的应用程序&#xff0c;而最终我们的应用程序却是编译为原始的JavaScript代码&#xff0c;以由nodejs运行时来执行。 初始化设置…

结构型模式 适配器模式

结构型模式 适配器模式 适用于&#xff1a; 是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 /*** 结构型模式 适配器模式* Adapter模式也叫适配器模式&#xff0c;是构造型模式之一&#xff0c;通过Adapter模式可…

乐哥学AI_Python(二):Numpy索引,切片,常用函数

Numpy的索引和切片 ndarray对象的内容可以通过索引和切片查看和修改。 索引&#xff1a;ndarray对象中的元素索引基于0开始 切片&#xff1a;对数组里某个片段区域的描述 数组的切片也可以理解为原始数组的局部视图&#xff0c;都是指向内存中的原始数组&#xff0c;所以不同于…

仅使用HTML和CSS实现的标签云效果

标签云的效果在博客和网站上不难见到&#xff0c;它其实就是带有超链接的某些关键字&#xff0c;为了达到强调主题的作用。通常出现概率比较大或者受欢迎的标签文字显示比较大&#xff0c;相反的就显示的小。来源于TagCrowd.com我们就不去深入研究标签云带来的效率上的提升和可…

捍卫Java

因此&#xff0c;我们不时发布了一本电子书&#xff0c;名为“十大Java性能问题” 。 毫无例外&#xff0c;一些人回答说“问题是您正在使用Java”。 显然&#xff0c;Java一直在受到批评&#xff0c;人们已经预测了它的消亡已有一段时间了。 当然&#xff0c;它不像Python&am…

vuex的使用二

1.先看项目的目录结构 2.在main.js里需要引入store这个文件并挂在实例上 import store from ./store/store ............new Vue({el: #app,router,store,template: <App/>,components: { App } }) 3.store.js里引入action.js和mutation.js文件 // 状态管理器 import Vue…

收到短信验证码自动填充到表单,竟然是这么玩的

苹果系统上的App和网站可以实现来自短信的验证码自动填充表单的功能&#xff0c;通常你是怎么实现这个功能的&#xff1f;有一种实现方式可能你不知道&#xff0c;单纯的HTML标签就能实现&#xff0c;不需要任何的Javascript代码该特性第一次发布是在 WWDC 2018[1]&#xff1a;…

web实现数据交互的几种常见方式

前言在当今社会&#xff0c;作为一名前端程序猿&#xff0c;并不是一昧的去制作静态页面就可以满足滴&#xff1b;你说你会制作网页&#xff0c;好吧&#xff0c;只能说你算是一个前端程序猿。但这是你作为一个程序猿最基本的能力&#xff0c;并不会为你进行加分&#xff1b; 我…

【超详细教程】如何使用TypeScript和GraphQL开发应用

GraphQL是一个专为构建灵活的API而生的强大的查询语言。它允许您为数据定义类型系统&#xff0c;因此在执行查询时&#xff0c;它仅返回所需的数据。与TypeScript一起使用时&#xff0c;GraphQL可以为开发人员提供更好的体验&#xff0c;因为它们都是类型语言。TypeScript是Jav…