共计 4397 个字符,预计需要花费 11 分钟才能阅读完成。
简介
Fabric.js 是一个可以简化 Canvas 程序编写的库。Fabric.js 为 Canvas 提供所缺少的对象模型, svg parser, 交互和一整套其他不可或缺的工具。Fabric.js 可以做很多事情,如下:
- 在 Canvas 上创建、填充图形(包括图片、文字、规则图形和复杂路径组成图形)。
- 给图形填充渐变颜色。
- 组合图形(包括组合图形、图形文字、图片等)。
- 设置图形动画集用户交互。
- 生成 JSON, SVG 数据等。
- 生成 Canvas 对象自带拖拉拽功能。
使用教程
安装
npm 安装
npm install fabric --save
cdn 引用
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>// 貌似国外相对较慢
可以在 https://www.bootcdn.cn/fabric… 找到更快的 CDN 来源
在使用前,先看下我做的总体效果如下:
初始化
创建了一个基本的画布
<canvas id="canvas" width="350" height="200"></canvas> | |
const card = new fabric.Canvas('canvas') | |
// ... 这里可以写 canvas 对象的一些配置,后面将会介绍 | |
// 如果 <canvas> 标签没设置宽高,可以通过 js 动态设置 | |
card.setWidth(350) | |
card.setHeight(200) |
对画布的交互
常用监听事件如下:
- mouse:down:鼠标按下时
- mouse:move:鼠标移动时
- mouse:up:鼠标抬起时
var canvas = new fabric.Canvas('canvas'); | |
canvas.on('mouse:down', function(options) {console.log(options.e.clientX, options.e.clientY) | |
}) |
监听画布对象事件以便“上下一步”的神操作
以下为常用的事件:
- object:added 添加图层
- object:modified 编辑图层
- object:removed 移除图层
- selection:created 初次选中图层
- selection:updated 图层选择变化
- selection:cleared 清空图层选中
下面是原文,更多参考__fabricjs 官网事件__:
So which other events are available in Fabric? Well, from mouse-level ones there are “mouse:down”, “mouse:move”, and “mouse:up”. From generic ones, there are “after:render”. Then there are selection-related events: “before:selection:cleared”, “selection:created”, “selection:cleared”. And finally, object ones: “object:modified”, “object:selected”, “object:moving”, “object:scaling”, “object:rotating”, “object:added”, and “object:removed”
设置画布背景
// 读取图片地址,设置画布背景 | |
fabric.Image.fromURL('xx/xx/bg.jpg', (img) => { | |
img.set({ | |
// 通过 scale 来设置图片大小,这里设置和画布一样大 | |
scaleX: card.width / img.width, | |
scaleY: card.height / img.height, | |
}); | |
// 设置背景 | |
card.setBackgroundImage(img, card.renderAll.bind(card)); | |
card.renderAll();}); |
向画布添加图层对象
fabric.js 提供了很多对象,除了基本的 Rect,Circle,Line,Ellipse,Polygon,Polyline,Triangle 对象外,还有如 Image,Textbox,Group 等更高级的对象,这些都是继承自 Fabric 的 Object 对象。
/** | |
* 如何向画布添加一个 Image 对象?*/ | |
// 方式一(通过 img 元素添加)const imgElement = document.getElementById('my-image'); | |
const imgInstance = new fabric.Image(imgElement, { | |
left: 100, // 图片相对画布的左侧距离 | |
top: 100, // 图片相对画布的顶部距离 | |
angle: 30, // 图片旋转角度 | |
opacity: 0.85, // 图片透明度 | |
// 这里可以通过 scaleX 和 scaleY 来设置图片绘制后的大小,这里为原来大小的一半 | |
scaleX: 0.5, | |
scaleY: 0.5 | |
}); | |
// 添加对象后, 如下图 | |
card.add(imgInstance); |
/** | |
* 如何向画布添加一个 Textbox 对象?*/ | |
const textbox = new fabric.Textbox('这是一段文字', { | |
left: 50, | |
top: 50, | |
width: 150, | |
fontSize: 20, // 字体大小 | |
fontWeight: 800, // 字体粗细 | |
// fill: 'red', // 字体颜色 | |
// fontStyle: 'italic', // 斜体 | |
// fontFamily: 'Delicious', // 设置字体 | |
// stroke: 'green', // 描边颜色 | |
// strokeWidth: 3, // 描边宽度 | |
hasControls: false, | |
borderColor: 'orange', | |
editingBorderColor: 'blue' // 点击文字进入编辑状态时的边框颜色 | |
}); | |
// 添加文字后,如下图 | |
card.add(textbox); |
获取当前选中的图层对象
// 方式一 | |
this.selectedObj = card.getActiveObject(); // 返回当前画布中被选中的图层 | |
// 方式二 | |
card.on('selection:created', (e) => { | |
// 选中图层事件触发时,动态更新赋值 | |
this.selectedObj = e.target | |
}) |
常规操作
this.selectedObj.rotate(angle); // 旋转图层
this.selectedObj.set({
scaleX: -this.selectedObj.scaleX, // 水平翻转
})
card.remove(this.selectedObj) // 传入需要移除的 object
this.selectedObj.bringForward();// 上移图层
this.selectedObj.sendBackwards();// 下移图层
card.moveTo(object, index);// 也可以使用 canvas 对象的 moveTo 方法,移至图层到指定位置
// 所有图层的操作之后,都需要调用这个方法
card.renderAll()
手机相册拍照图片尺寸太大导致拖动麻烦
主要是在添加图片对象的时候,有两个参数可以应用起来,分别是 scaleX,scaleY 参数,通过这两个参数,可以对应地缩放图片大小,方便图片能完整地在 canvas 画布体现出来。
先将手机图片加载完毕,算出宽和高,根据自己的画布纵横对比重新算出 图片的缩放参数即可。
new Promise(function(res,rej){let img = new Image(); | |
img.onload = function(){console.log(img.width,img.height); | |
res([img.width,img.height]); | |
} | |
img.src = file.content; | |
}).then(function(response){let width = response[0]; | |
let height = response[1]; | |
let xYRet = 0.61; //300/490 纵横对比 | |
let targetRepix = 1; | |
if(height > 490) | |
{targetRepix = (490/height).toFixed(2); | |
} | |
if(width > 300) | |
{targetRepix = (300/width).toFixed(2); | |
} | |
fabric.Image.fromURL(file.content, (img) => { | |
img.set({ | |
top:30, | |
left:30, | |
scaleX: targetRepix, | |
scaleY: targetRepix, | |
hasControls: true, // 是否开启图层的控件 | |
borderColor: 'orange', // 图层控件边框的颜色 | |
}); | |
// 添加对象后, 如下图 | |
card.add(img); | |
}); | |
}) |
文字粗细和颜色随意设
// 其中 selectedObj 是当前选中的文字对象
this.selectedObj.set({fontWeight:xxx // 改变粗细}); | |
this.selectedObj.set({fill:xxx // 改变颜色}); |
更改选中对象的框样式
card.on('selection:updated', (e) => {console.log('selection:updated', e.target) | |
this.setSelectedObj(e.target) | |
// 通过选中的对象更改样式 | |
e.target.set({ | |
transparentCorners: false, | |
cornerColor: 'blue', | |
cornerStrokeColor: 'red', | |
borderColor: 'red', | |
cornerSize: 12, | |
padding: 10, | |
cornerStyle: 'circle', | |
borderDashArray: [3, 3] | |
}); | |
}) |
效果如下图:
画布序列化与反序列化————记录状态记录
框架提供了如 toJSON 和 loadFromJSON 方法,作用分别为导出当前画布的 json 信息,加载 json 画布信息来还原画布状态。
// 导出当前画布信息 | |
const currState = card.toJSON(); // 导出的 Json 如下图 | |
// 加载画布信息 | |
card.loadFromJSON(lastState, () => {card.renderAll(); | |
}); |
将画布导出成图片
const dataURL = card.toDataURL({ | |
format: 'jpeg', // jpeg 或 png | |
quality: 0.8 // 图片质量,仅 jpeg 时可用 | |
// 截取指定位置和大小 | |
//left: 100, | |
//top: 100, | |
//width: 200, | |
//height: 200 | |
}); |