背景:
在实际工作中,接触到整体的一个作业批改的流程。所以对作业的批改有部分了解,
故做此分享,希望能够抛砖引玉,大家共同探讨
1、什么是Fabric.js
一个功能强大的Javascript库,使使用HTML5 canvas变得轻而易举。
Fabric.js为Canvas提供所缺少的对象模型, 交互和一整套其他不可或缺的工具
2、为什么要用它而不用其他的
首先,Canvas提供了一个画布的能力, 但是api不够友好。我们在pc端的批改是用的原生canvas,但应用到小程序经过调研发现并不合适。canvas.绘制简单图形其实还可以, 不过做一些复杂的图形绘制, 编写一些复杂的效果,就不是那么方便了。所以,我们决定使用Fabric.js来开发
它主要就是用对象的方式去编写代码。
3、原生: canvas 和fabric的对比
同样条件下绘制一个矩形
- a.原生canvas
var canvasEl = document.getElementById('c');
var ctx = canvasEl.getContext('2d');
ctx.fillStyle =‘红色'; //在100,100点处创建20x20尺寸的矩形
ctx.fillRect(100,100,20,20);
- b.fabric.js
var canvas = new fabric.Canvas('c');//创建一个矩形对象
var rect = new fabric.Rect({
left:100,
top:100
fill:“红色”,
width:20,
Height:20
});//在画布上“添加”矩形
canvas.add(rect);
使用自由画笔
- a.原生canvas
const drawLine = (x1, y1, x2, y2) =>
{
const { ctx } = getCanvas();
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.fillStyle = 'red';
ctx.strokeStyle = 'red';
ctx.moveTo(x1, y1); // lineTo(x, y) 绘制一条从当前位置到指定x以及y位置的直线
ctx.lineTo(x2, y2); // 通过线条来绘制图形轮廓
ctx.stroke();
ctx.closePath();
};
使用fabric 不仅仅是因为他是以对象的形式来绘制图形,更重要的是它集成了十分强大的交互功能。
b.使用Fabric.js
freeDraw() { canvasCtx.isDrawingMode = true; canvasCtx.freeDrawingBrush.color = 'red'; canvasCtx.freeDrawingBrush.width = 2; };
4、如何使用
引入:
1、npm安装: npm install fabric --save
2、通过CDN引入:
3、项目中引入使用: import { fabric } from 'fabric'
创建实例:
js:
canvasCtx = new fabric.Canvas('my-canvas', {
enableRetinaScaling: true,
perPixelTargetFind: true, // 对象基于像素检测
skipTargetFind: true,
selection: false,
selectable: false
});
dom:
创建完实例后,fabric.js会构建两层 canvas 元素:lower-canvas 和 upper-canvas
lower-canvas: 只负责渲染元素
upper-canvas: 负责所有的事件处理
5、事件绑定
mouseEvent() {
canvasCtx.on('mouse:down', (options) => {
TODO:获取点坐标
});
canvasCtx.on('mouse:move', (options) => {
TODO:
});
canvasCtx.on('mouse:up', (options) => {
TODO:
};
}
最新版本的Fabric已经不需要判断手动还是点击事件,兼容的Events.js能够兼容在移动端的手势操作:
根据下图可以看到,在不同平台下所触发的事件是不同的,所以可以开箱即用。
pc端:
6、绘制图片
creatImg() {
const imageUrl = new Image();
imageUrl.setAttribute('crossOrigin', 'Anonymous'); // 图片跨域
imageUrl.src = object.url;
imageUrl.onload = () => {
const imageBg = new fabric.Image(imageUrl, {
angle: 90, // 旋转角度
hasBorders: false, // 去掉边框,可以正常操作
selectable: false,
hasControls: false, // 只能移动不能(编辑)操作
crossOrigin: 'Anonymous' // 图片跨域
});
canvasCtx.add(imageBg);
};
}
7、移动图片
handleMoveCnavas(options) {
const {
x, y
} = movePosition;
const delta = new fabric.Point(options.x - x, options.y - y);
canvasCtx.relativePan(delta);
movePosition = options;
}
### 8、缩放事件
下图为在移动端的示意图:
// options --- 坐标点
// targetTouches 双指触发,长度为2
handleDoubleFinger(options) {
const {
clientX: finger1X,
clientY: finger1Y
} = options.e.targetTouches[0];
const {
clientX: finger2X,
clientY: finger2Y
} = options.e.targetTouches[1];
const powX = (finger2X - finger1X) * (finger2X - finger1X);
const powY = (finger2Y - finger1Y) * (finger2Y - finger1Y);
// 计算两个手指之间的距离
const distance = Math.sqrt(powX + powY);
// 每次缩放的比例
let ratio = -0.05;
if (distance > preDistance) {
ratio = 0.05;
}
preDistance = distance;
const x = scaleCenter.x || (Math.abs(finger1X + finger2X)) / 2;
const y = scaleCenter.y || (Math.abs(finger1Y + finger2Y)) / 2;
scaleCenter = {
x, y
};
// 计算当前缩放的大小
let zoom = ratio + canvasCtx.getZoom(); // 获取当前缩放比
zoom = Math.max(0.5, zoom);
zoom = Math.min(3, zoom);
const zoomPoint = new fabric.Point(x, y);
canvasCtx.zoomToPoint(zoomPoint, zoom);
}
9、旋转保存
旋转前:
总结:
fabric主要是canvas基础上的一次创新,能够解决很多原生canvas处理处理起来特别麻烦的地方,在整个实例对象下,有一个_objects数组,是用来存储在画板上的所有元素,元素的数量直接决定数组的长度,在启用撤销功能时,本质上是维护这个数组来实现。当然,Fabric的功能远不止这些,更深一层的理解需要日后不断的积累与总结
附录:
常用的一些API
add(object) 添加
insertAt(object,index) 添加
remove(object) 移除
forEachObject 循环遍历
getObjects() 获取所有对象
item(int) 获取子项
isEmpty() 判断是否空画板
size() 画板元素个数
fabric.util.drawDashedLine 绘制虚线
clear() 清空
renderAll() 重绘
requestRenderAll() 请求重新渲染
rendercanvas() 重绘画板
getCenter().top/left 获取中心坐标
toDatalessJSON() 画板信息序列化成最小的json
toJSON() 画板信息序列化成json
moveTo(object,index) 移动
setCursor() 设置手势图标
getSelectionContext()获取选中的context
getSelectionElement()获取选中的元素
getActiveObject() 获取选中的对象
getActiveObjects() 获取选中的多个对象
discardActiveObject()取消当前选中对象
rotate() 设置旋转角度
setCoords() 设置坐标