1.Fabric.js是什么?
Fabric.js 是一个可以简化 Canvas 程序编写的库。 Fabric.js 为 Canvas 提供所缺少的对象模型,svg parser,交互和一整套其他不可或缺的工具。
2.为什么要用Fabric.js?
Canvas 提供一个好的画布能力,但是 Api 不够友好。绘制简单图形其实还可以,不过做一些复杂的图形绘制,编写一些复杂的效果,就不是那么方便了。Fabric.js 就是为此而开发,它主要就是用对象的方式去编写代码。详细见中文文档
3.使用方式
// 通过npm进行安装
npm install fabric
// 在.vue中引用
import { fabric } from 'fabric'
// 声名画布 xxx画布id options初始化事件
canvas = new fabric.Canvas('xxx', options);
// 或者用 canvas 对对象属性进行修改
canvs.isDrawingMode = true;
// 使用 CDN
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.6.0/fabric.min.js"></script>
// react中使用
import React, { useEffect, useRef, useState } from 'react';
import { fabric } from 'fabric';
export default function App() {
const canvasRef = useRef(null);
const [canvas, setCanvas] = useState(null);
return (
<div>
<canvas ref={canvasRef}></canvas>
</div>
);
}
3.1 options对象属性
| 属性名 | 类型 | 注释 |
|---|---|---|
| stopContextMenu | Boolean | 禁止默认右键菜单 |
| controlsAboveOverlay | Boolean | 是否启用右键,右键默认button数字为3 |
| fireRightClick | Boolean | 超出clipPath后时候继续展示控制条 |
| imageSmoothingEnabled | Boolean | 解决文字导出后不清晰问题 |
| isDrawingMode | Boolean | 是否可以自由绘制(画笔) |
| selectable | Boolean | 控制是否可选择/是否可操作 |
| selection | Boolean | 时候显示画板被选中 |
| skipTargetFind | Boolean | 整个画板是否可被选中 |
| freeDrawingBrush | Object | 笔刷类型(SprayBrush:喷雾笔刷, circleBrush 圆形笔刷,texturePatternBrush 图案画笔, pencilBrush 铅笔笔刷默认) |
| setZoom(n:Number) | function | 设置画板缩放比例 |
| uniformScaling | Boolean | 是否强制按比例缩放 默认true |
| uniScaleKey | String | 哪个键切换统一缩放 |
| centeredScaling | Boolean | 该参数定义是否启用或禁用居中缩放.默认false |
| ps:更多请查看文档 |
//图案画笔使用
let img = new Image();//创建图像
img.src ='xxxx.png'
//必须图片加载完毕才可下一步
img.onload = function(){
// 创建图案画笔
let texturePatternBrush = new fabric.PatternBrush(canvas)
// 设置画笔的源指向图片
texturePatternBrush.source = img
// 使用图案画笔
canvas.freeDrawingBrush = texturePatternBrush
}
// 普通画笔使用
canvas.freeDrawingBrush = circleBrush;
3.2 freeDrawingBrush(画笔)对象属性
//使用方式
canvas.freeDrawingBrush.width = "200"
| 属性名 | 类型 | 注释 |
|---|---|---|
| color | String | 笔刷颜色设置 |
| width | Number | 设置画笔粗细 |
| strokeLineCap | String | 画笔结尾风格(roud, butt, square) 默认round |
| strokeLineJoin | String | 画笔角落风格(miter, bevel, round) 默认round |
| strokeMiterLimit | Number | 笔刷最大的斜接长度 |
| strokeDashArray | Array | 设置虚线(行程破折号数组) |
| shadow | Object | 设置阴影 |
| skipTargetFind | Boolean | 整个画板是否可被选中 |
| freeDrawingBrush | object | 笔刷工具属性设置 |
//设置阴影例子
canvas.freeDrawingBrush.shadow = new fabric.Shadow({
blur: 10, // 羽化程度
offsetX: 20, // x轴偏移量
offsetY: 20, // y轴偏移量
color: '#30e3ca' // 投影颜色
})
4.绘制图形
// 1.声名画布
let canvas= new fabric.Canvas('main');
// 2.设置矩形的属性
let options = {
left:100,
top:100,
fill:'red',
width:30,
height:30
}
// 3. 绘制矩形
let rect = new fabric.Rect(options);
canvas.add(rect);
其他规则图形
- 绘制矩形 let rect = new fabric.Rect
- 绘制圆形 let circle = new fabric.Circle
- 绘制三角形 let triangle = new fabric.Triangle
options属性
| 属性 | 类型 | 注释 |
|---|---|---|
| left | Number | 距离画布左侧的距离,单位是像素 |
| top | Number | 距离画布上边的距离,单位是像素 |
| fill | String | 填充的颜色 |
| width | Number | 图形的宽度 |
| height | Number | 图形的高度 |
| strokeWidth | Number | 描边宽度 |
| stroke | Number | 描边颜色 |
绘制不规则图形
使用fabric.Path( ) 方法
// M 代表移动 M 0 0 则代表将画笔移动到 0,0坐标点
// L 代表线 L 200 100 从0,0 坐标画到 200,100坐标位置
// Z 代表图形闭合路径
var path = new fabric.Path('M 0 0 L 200 100 L 170 200 z');
// set( )方法对三角形的位置、颜色、角度、透明度等属性进行设置。
path.set({ left: 120, top: 120,fill:'red' });
canvas.add(path); //添加进画布
使用fabric.Polygon 或者 fabric.Polyline
5.对图片的操作
# html
<input id="file" type="file" accept="image/* png/*" onclick="changefile(event)" />
# js
function changefile(e){
// 1.获取文件
let file = res.target.files[0];
// 2.转换成url 展示图片
// 3.1 new FileReader()方法
let reader = new FileReader();
reader.onload = function (e) {
imgurl.value = e.target.result;
drawimg(e.target.result);
}
reader.readAsDataURL(file);
// 3.2 window.URL.createObjectURL方法
let url = window.URL.createObjectURL(file);
drawImg(url);
}
function drawImg(file){
if (!file) throw new Error('file is undefined');
// 第一种
// fabric.Image.fromURL(file,function(oImg){
// oImg.set("name",'图片')
// canvas.add(oImg);
// })
// 第二种
const imgEl = document.createElement('img');
imgEl.src = file;
imgEl.onload = function (res) {
console.log(res);
const imgInstance = new fabric.Image(imgEl, {
name: '图片',
left: 0,
top: 0,
});
// canvas.add(imgInstance);
// 设置缩放
canvas.add(imgInstance);
canvas.setActiveObject(imgInstance);
canvas.renderAll(); //重新渲染
// 删除页面中的图片元素
imgEl.remove();
}
}
6.插入SVG
6.1 插入svg元素
// 获取文件 如图片插入那获取一致
........
drawSvg(url)
function drawSvg(url){
if (!file) throw new Error('file is undefined');
fabric.loadSVGFromURL(file, function (objects, options) {
const obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
}
6.2 插入svg字符串
//textcont.value 获取textarea输入的值
function comitSvg() {
if (textcont.value) {
fabric.loadSVGFromString(textcont.value, function (obj, options) {
let objs = fabric.util.groupSVGElements(obj, options);
objs.set('id', getID(objs))
objs.set('name', "路径")
canvas.add(objs).renderAll();
show1.value = false;
textcont.value = '';
})
} else {
alert("内容为空!");
}
}
7 画布的交互
| 事件 | 对象 | 注释 |
|---|---|---|
| mouse:down | 画布 | 鼠标按下时 |
| mouse:move | 画布 | 鼠标移动时 |
| mouse:up | 画布 | 鼠标抬起时 |
| after:render | 画布 | 画布重绘后 |
| object:selected | object | 对象被选中 |
| object:moving | object | 对象移动 |
| object:rotating | object | 对象被旋转 |
| object:added | object | 对象被加入 |
| object:removed | object | 对象被移除 |
// 画布交互
let canvas = new Fabric.Canvas('canvas');
canvas.on('mouse:down',function(options){
console.log(options)
})
// 画上上对象交互
let rect = new fabric.Rect({width:100,height:100,fill:'red'});
react.on("selected",function(options){
alert("我被选中了")
})
canvas.add(rect).renderAll()
8.序列化与反序列化
8.1 序列化
let canvas = new fabric.Canvas('canvas');
let rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'red'
})
canvas.add(rect).renderAll()
console.log(JSON.stringify(canvas.toJSON()));
8.2 反序列化
let canvas = new fabric.Canvas('canvas');
canvas.loadFromJSON('{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null}
]}')
9.文本
9.1 Text普通文本
let text = new fabric.Text("hello farbic", { //文本属性
fontSize:30, // 字体大小
originX: 'center', // x轴方向对齐方向
originy: 'cennter', // y轴方向对齐方向
font:'' // 自定义字体
})
canvas.add(text).renderAll();
9.2Itext可动态编辑文本
let text = new fabric.IText("hello world", {
fontFamily: 'ubuntu',
fontSize: 300,
textAlign: "center",
})
text.setControlsVisibility({ //控制文本的手柄
mt: false,
mr: false,
mb: false,
ml: false
});
canvas.add(text);
canvas.viewportCenterObject(text); // 画布中间
canvas.setActiveObject(text); // 活跃状态
text.enterEditing(); // 进入编辑状态
text.selectAll(); // 选中所有的文本
9.3 导入自定义字体
例子:vue项目
<style>
@font-face {
font-family: ali;
src: url('../../fonts/AlibabaPuHuiTi-2-35-Thin.ttf');
}
@font-face {
font-family: douyu;
src: url('../../fonts/douyu.ttf');
}
</style>
<script >
import {fontaceobserver} from 'fontfaceobserver.js' //字体加载工具
import {fabric} from 'fabric'
const font = new FontFaceObserver('ali')
const canvas = new fabric.Canvas('c')
font.load()
.then(() => {
const iText = new fabric.IText('hello world', {
fontFamily: 'ali'
})
canvas.add(iText)
})
function setFont(font) {
let fontFamily = new FontFaceObserver(font)
fontFamily.load()
.then(() => {
let target = canvas.getActiveObject()
if (target) {
target.set("fontFamily", font)
canvas.requestRenderAll()
}
})
.catch(() => {
console.error('字体加载失败')
})
}
</script>
10.笔记
10.1 方法
- add(object) 添加
- insertAt(object,index) 添加
- remove(object) 移除
- forEachObject 循环遍历
- getObjects() 获取所有对象
- item(int) 获取子项
- isEmpty() 判断是否空画板
- size() 画板元素个数
- contains(object) 查询是否包含某个元素
- fabric.util.cos cos函数
- fabric.util.sin sin函数
- fabric.util.drawDashedLine 绘制虚线
- getWidth() setWidth() 获取/设置宽度
- getHeight() 获取高度
- clear() 清空
- renderAll() 重绘
- requestRenderAll() 请求重新渲染
- rendercanvas() 重绘画板
- getCenter().top/left 获取中心坐标
- toDatalessJSON() 画板信息序列化成最小的json
- toJSON() 画板信息序列化成json
- moveTo(object,index) 移动
- dispose() 释放
- setCursor() 设置手势图标
- getSelectionContext()获取选中的context
- getSelectionElement()获取选中的元素
- getActiveObject() 获取选中的对象
- getActiveObjects() 获取选中的多个对象
- discardActiveObject()取消当前选中对象
- isType() 图片的类型
- setColor(color) = canvas.set("full",""); 填充颜色
- rotate() 设置旋转角度
- setCoords() 设置坐标
- setActiveObject() 对象被获取
10.2 事件
- object:added
- object:removed
- object:modified
- object:rotating
- object:scaling
- object:moving
- object:selected 这个方法v2已经废弃,使用selection:created替代,多选不会触发
- before:selection:cleared
- selection:cleared
- selection:updated
- selection:created
- path:created
- mouse:down
- mouse:move
- mouse:up
- mouse:over
- mouse:out
- mouse:dblclick