原文链接:

Fabric.js 是一个功能强大且简单的 HTML5 画布库,它给 canvas 上的元素提供了交互式对象模型。借助Fabric.js,你可以轻松地绘制各种图形线条图片,对它们进行拖拽、旋转、形变等操作,并且支持丰富的事件方法。

一、绘制图形

所有的绘制开始之前你需要先创建画布对象:

  1. <canvas id="canvas" width="600" height="600"></canvas>
  1. var canvas = new fabric.Canvas('canvas')

1.1 绘制圆形

  1. const circle = new fabric.Circle({
  2. radius: 100, // 半径大小
  3. left: 10, // 以画布左上角为顶点的横坐标
  4. top: 10, // 以画布左上角为顶点的纵坐标
  5. fill: 'yellow', // 对象的填充颜色
  6. strokeWidth: 2, // 外边框线宽度
  7. stroke: "red" // 外边框颜色
  8. })
  9. canvas.add(circle)
属性 作用
radius 半径大小
left 以画布左上角为顶点的横坐标
top 以画布左上角为顶点的纵坐标
fill 对象的填充颜色
strokeWidth 外边框线宽度
stroke 外边框颜色

Canvas神器: Fabric.js 实用指南 - 图1

1.2 绘制矩形

  1. const rect = new fabric.Rect({
  2. width: 200,
  3. height: 100,
  4. rx: 20, // 圆角半径(x轴方向)
  5. ry: 20, // 圆角半径(y轴方向)
  6. fill: '#FF4D4F',
  7. strokeWidth: 2,
  8. stroke: "#dedede"
  9. })
  10. canvas.add(rect) // 添加rectangle,即可绘制矩形

Canvas神器: Fabric.js 实用指南 - 图2
利用rx、ry这两个圆角属性你也可以通过 fabric.Rect 绘制圆形和椭圆形。

1.3 绘制三角形

  1. const triangle = new fabric.Triangle({
  2. width: 200,
  3. height: 300,
  4. fill: '#FF4D4F',
  5. strokeWidth: 2,
  6. stroke: "#dedede"
  7. })
  8. canvas.add(triangle)

Canvas神器: Fabric.js 实用指南 - 图3

二、画线

示例:绘制网格线

  1. const canvas = new fabric.Canvas('c')
  2. const grid = 30
  3. const lineStroke = '#C5C9CB'
  4. for (let i = 0; i < (canvas.width / grid); i++) {
  5. const lineX = new fabric.Line([ 0, i * grid, canvas.width, i * grid], {
  6. stroke: lineStroke,
  7. selectable: false, // 注:对象不可选中
  8. type: 'line'
  9. })
  10. const lineY = new fabric.Line([ i * grid, 0, i * grid, canvas.width], {
  11. stroke: lineStroke,
  12. selectable: false,
  13. type: 'line'
  14. })
  15. canvas.add(lineX)
  16. canvas.add(lineY)
  17. }

fabric.Line([50, 100, 200, 200] 的四个数值分别对应线起点和终点的横纵坐标,利用Line类我们可以实现网格线的绘制。selectable属性值为false的时候表示对象不可选中,type属性可以自定义对象类型。
Canvas神器: Fabric.js 实用指南 - 图4

三、添加文字

  1. const text = new fabric.IText('blackstar', {
  2. top: 100,
  3. left: 100,
  4. fontFamily: 'Calibri',
  5. fontSize: 18,
  6. angle: 45,
  7. originX: 'center',
  8. originY: 'center',
  9. centeredRotation: true,
  10. fill: '#000'
  11. })
  12. canvas.add(text)
属性 作用
fontFamily 字体
fontSize 文字大小
angle 角度
originX X轴中心点位置
originY Y轴中心点位置
centeredRotation 如果为true,则此对象将使用中心点作为旋转时的原点

注意文字内容必须为字符串类型,否则会报错。
Canvas神器: Fabric.js 实用指南 - 图5

四、绘制图片

  1. fabric.Image.fromURL('https://s2.ax1x.com/2019/08/18/mlm0Jg.jpg', function(oImg) {
  2. oImg.scale(0.5)
  3. canvas.add(oImg)
  4. })

Canvas神器: Fabric.js 实用指南 - 图6scale()方法用于控制对象的缩放

五、群组绘图

群组是 Fabric.js 最强大的功能之一。试想一下,如果你需要在一个方框中添加一些文字你该怎么做?先添加一个矩形,再把文字覆盖在上面吗?Fabric.js提供了Group类帮助我们将多个对象组成一个对象。像上面提到的需求我们就可以这样来实现:

  1. const rect = new fabric.Rect({
  2. width: 200,
  3. height: 100,
  4. rx: 20,
  5. ry: 20,
  6. fill: '#FF4D4F'
  7. })
  8. const text = new fabric.IText('blackstar', {
  9. fontFamily: 'Calibri',
  10. fontSize: 18,
  11. left: rect.width/2,
  12. top: rect.height/2,
  13. originX: 'center',
  14. originY: 'center',
  15. centeredRotation: true,
  16. fill: '#fff'
  17. })
  18. const block = new fabric.Group([rect,text], {
  19. left: 50,
  20. top: 50
  21. })
  22. canvas.add(block)

Canvas神器: Fabric.js 实用指南 - 图7
Group类接受对象数组将其组装在一个对象中,排在后面的绘制在上层。

文字垂直水平居中

在群组中设置文字垂直水平居中其实很简单,只需要将文字的坐标中心点通过originX、originY设置在正中央,横纵坐标分别设置为包裹区域宽高的一半就可以了

六、对象属性汇总

属性 作用
left 横坐标
top 纵坐标
width 宽度
height 高度
originX 对象转换的水平原点(‘left’,’right’,’center’)
originY 对象转换的垂直原点(‘left’,’right’,’center’)
angle 偏转角度
snapAngle 设置对象在旋转时锁定的角度。比如设置值为45则对象在旋转时只能以45度为一个单位
fill 对象的填充色
backgroundColor 对象的背景色
hasControls 值为false时无法对对象进行旋转和拉伸
selectable 对象是否可选中,false时无法选中
lockRotation true时无法旋转对象
lockMovementX true时对象无法水平移动
lockMovementY true时对象无法垂直移动
scaleX 水平方向缩放倍数
scaleY 垂直方向缩放倍数
stroke 线颜色
strokeWidth 线宽度
fontFamily 字体
fontSize 字号
type 标记对象类型

除了官方文档中给定的属性,你还可以根据需要自定义属性名。

七、对象常用方法

方法 作用
object.set() 设置对象属性,如rect.set({top: 50,left:100})
object.scale() 缩放对象
object.rotate() 旋转对象
object.getBoundingRect() 返回对象的边界矩形(左,顶部,宽度,高度)的坐标
object.setCoords() 当对象修改了坐标、长宽、缩放、角度、倾斜程度等可能改变对象位置的属性时需要通过该方法重新计算位置
object.intersectsWithObject(other) 检查对象是否与另一个对象相交

八、画布方法

方法 作用
canvas.setActiveObject(obj) 将给定对象设置为画布上唯一的活动对象
canvas.getObjects() 获取画布上的所有实例对象
canvas.add(obj) 添加实例对象
canvas.remove(obj) 移除对象
canvas.renderAll() 重新渲染画布
canvas.sendToBack(o) 将对象或多个选择的对象移动到绘制对象堆栈的底部
canvas.discardActiveObject() 丢弃当前的活动对象
canvas.clear() 清除实例的所有上下文
canvas.dispose() 清除canvas元素并删除所有事件侦听器
canvas.backgroundColor 设置画布背景色

九、事件监听

Fabric.js提供了全方位的事件监听机制:
Canvas神器: Fabric.js 实用指南 - 图8

常用的有以下几个:

  1. // 对象移动监听
  2. canvas.on('object:moving', function(e) {
  3. console.log(e.target)
  4. })
  5. // 对象缩放监听
  6. canvas.on('object:scaling', function(e) {
  7. console.log(e.target)
  8. })
  9. // 对象旋转监听
  10. canvas.on('object:rotating', function (e) {
  11. console.log(e.target)
  12. })
  13. // 对象变动监听,包括位置、大小、角度等变化的监听
  14. canvas.on('object:modified', function(e) {
  15. console.log(e.target)
  16. })
  17. // 点击事件监听
  18. canvas.on('mouse:down', function (e) {
  19. console.log(e.target)
  20. })
  21. canvas.on('mouse:up', function (e) {
  22. console.log(e.target)
  23. })

十、边界检测

在操作画布上的实例对象时我们并不希望它们超出画布的范围,那么就需要进行边界判断,控制对象不要越过指定区域。

  1. canvas.on('object:moving', function (e) {
  2. checkBoudningBox(e)
  3. })
  4. canvas.on('object:rotating', function (e) {
  5. checkBoudningBox(e)
  6. })
  7. canvas.on('object:scaling', function (e) {
  8. checkBoudningBox(e)
  9. })
  10. // 此为对象坐标原点设置在中心的情况
  11. function checkBoudningBox(e) {
  12. const obj = e.target
  13. if (!obj) {
  14. return
  15. }
  16. obj.setCoords()
  17. const objBoundingBox = obj.getBoundingRect()
  18. if (objBoundingBox.top < 0) {
  19. obj.set('top', objBoundingBox.height/2)
  20. obj.setCoords()
  21. }
  22. if (objBoundingBox.left > canvas.width - objBoundingBox.width) {
  23. obj.set('left', canvas.width - objBoundingBox.width/2)
  24. obj.setCoords()
  25. }
  26. if (objBoundingBox.top > canvas.height - objBoundingBox.height) {
  27. obj.set('top', canvas.height - objBoundingBox.height/2)
  28. obj.setCoords()
  29. }
  30. if (objBoundingBox.left < 0) {
  31. obj.set('left', objBoundingBox.width/2)
  32. obj.setCoords()
  33. }
  34. }

原理就是利用事件监听和对象边界矩形的顶点坐标,当坐标值超出画布范围时重置对象坐标