前言

因为这次接到的需求是要做一个可视化的图片编辑工具,所以经过选型和竟品调研,最终确定用fabric.js来实现,其和要实现的功能匹配度很高,下面简单对fabric.js进行下介绍。

简介

Fabric.js is a framework that makes it easy to work with HTML5 canvas element. It is an interactive object model on top of canvas element. It is also an SVG-to-canvas parser.

Fabric.js是一个可以简化canvas开发的框架。 Fabric.js为canvas提供所缺少的对象模型,同时也是一个svg解析器。

Example

官网给出的例子,功能比较全:demo

特点

非常强大的底层画布能力

用对象的方式去编写代码

可以自定义模块

用法

安装fabric.js,前提要先安装canvas依赖,安装canvas出错的时候可以按照这个装下

npm install fabric —save

安装成功后,先画个简单的正方形
let canvas = new fabric.Canvas('main') // id为main的canvas元素
// 可以在dom中直接设置canvas的宽高,也可以在js里动态改变宽高
canvas.setDimensions({
  width: 1000,
  height: 600
})
let rect = new fabric.Rect({
  left: 100,
  top: 100,
  fill: 'red',
  width: 200,
  height: 200,
})
canvas.add(rect) // 把object加到canvas中

fabricjs设置画布 fabric.js使用教程_fabricjs设置画布

一些通用的属性:

position: left, top

dimension: width, height

render: fill, opacity, stroke, strokeWidth

scale & rotate: scaleX, scaleY, angle

flip: flipX, flipY

常用的几种fabric.js class:
  1. fabric.Rect:矩形
  2. fabric.Circle:圆形
  3. fabric.Triangle:三角形
  4. fabric.Ellipse:椭圆
  5. fabric.Line:线
  6. fabric.Polygon:多边形
  7. fabric.Polyline:折线
下面附上代码:
// 椭圆
let ellipse = new fabric.Ellipse({
  left: 320,
  top: 100,
  originX: 'left', // 横向基准点
  originY: 'top', // 垂直基准点
  rx: 150, // 横轴
  ry: 100, // 竖轴
  angle: 0,
  fill: '',
  stroke: 'red',
  strokeWidth: 3,
})
canvas.add(ellipse)

// 线
let line = new fabric.Line([ 260, 125, 260, 375 ], {
  fill: 'red',
  stroke: 'red',
  strokeWidth: 5,
  selectable: false
})
canvas.add(line)

// 多边形
// 各个顶点
let points = [
  {x: 0, y: 42},
  {x: 155, y: 0},
  {x: 155, y: 243},
  {x: 0, y: 256}
]
let polygon = new fabric.Polygon(points, {
  left: 0,
  top: 0,
  fill: 'purple',
})
canvas.add(polygon)

// 折线
let polylinePoint = []
// fabric提供的random方法
let random = fabric.util.getRandomInt
polylinePoint.push(new fabric.Point(random(100, 200), random(200, 300)))
polylinePoint.push(new fabric.Point(random(200, 300), random(100, 200)))
polylinePoint.push(new fabric.Point(random(200, 250), random(150, 200)))
let polyline = new fabric.Polyline(polylinePoint, {
  stroke: 'black',
  fill: ''
})
canvas.add(polyline)

let circle = new fabric.Circle({
  radius: 20,
  fill: 'green',
  left: 100,
  top: 100
})

let triangle = new fabric.Triangle({
  width: 20,
  height: 30,
  fill: 'blue',
  left: 50,
  top: 50
})
canvas.add(circle, triangle)

运行结果:

fabricjs设置画布 fabric.js使用教程_ci_02

还有path,不过感觉用到的比较少

// M代表MoveTo,L代表LineTo,Z代表closePath
let path = new fabric.Path('M 0 0 L 50 0 M 0 0 L 4 -3 M 0 0 L 4 3 Z', {
  left: 380,
  top: 70,
  stroke: 'red',
  strokeWidth: 2,
  fill: false
})
canvas.add(path)

运行结果:

fabricjs设置画布 fabric.js使用教程_fabricjs设置画布_03

文本

分为普通文本(Text)和可编辑的文本(IText)

let iText = new fabric.IText('hello\nworld', {
  left: 50,
  top: 50,
  fontFamily: 'Helvetica',
  fill: '#333',
  lineHeight: 1.1,
  // 可以单独设置每个字符的style
  styles: {
    0: {
      0: { fontSize: 80 },
      1: { textBackgroundColor: 'red' }
    },
    1: {
      0: { textBackgroundColor: 'rgba(0,255,0,0.5)' },
      4: { fontSize: 20 }
    }
  }
})
canvas.add(iText)

运行结果:

fabricjs设置画布 fabric.js使用教程_Image_04

说完了基础的创建对象的方法,下面说一些其他特性
动画
// 第一个参数是要改变的属性,第二个参数是改变的值,支持在原来的基础上做改变,第三个参数是回调函数
rect.animate('left', '+=500', {
  onChange: canvas.renderAll.bind(canvas),
  duration: 2000, // 动画持续时间
  easing: fabric.util.ease.easeOutBounce // fabric提供了很多种动画方式
})
渐变色
circle.setGradient('fill', {
  // 色标的位置
  x1: 0,
  y1: 0,
  x2: circle.width,
  y2: circle.height,
  // 渐变的颜色
  colorStops: {
    0: 'red',
    0.2: 'orange',
    0.4: 'yellow',
    0.6: 'green',
    0.8: 'blue',
    1: 'purple'
  }
})

结果:

fabricjs设置画布 fabric.js使用教程_Image_05

group
// 也可以嵌套组
let group = new fabric.Group([circle, triangle], {
  left: 150,
  top: 100,
  angle: 10
})
canvas.add(group)

结果:

fabricjs设置画布 fabric.js使用教程_滤镜_06

下面说下图片的加载
let imgElement = document.querySelector('.img') // dom中的img元素
let imgInstance = new fabric.Image(imgElement, {
  left: 200,
  top: 100,
  angle: -10,
  opacity: 0.85
})
canvas.add(imgInstance)

实际应用中很少会这样写,因为还需要在dom中写img标签,一般来说都是引用url来加载图片

fabric.Image.fromURL('url', image => {
  image.set({
    left: 200,
    top: 100,
    width: 200,
    height: 200 // 这里的宽高会是裁剪图片,不是缩放,是fabric object的宽高
  })
    // .scale(1.2, 1.2) // 缩放图片x、y轴
    .scaleToWidth(200) // 按需要缩放到固定的宽或高
    .setCoords()
  canvas.add(image)
}, { crossOrigin: 'anonymous' })

fabric还支持给图片加滤镜

fabric.Image.fromURL('url', img => {
  img.set({
    left: 500,
    top: 100,
  })
  // 支持多个滤镜效果叠加
  img.filters.push(
    new fabric.Image.filters.Noise({noise: 200}), // 噪声滤镜
    new fabric.Image.filters.Invert(), // 反转
    new fabric.Image.filters.Sepia(), // 深褐色
    new fabric.Image.filters.Brownie() // 棕镜
  )
  // 加载滤镜到图片上
  img.applyFilters()
  canvas.add(img)
}, { crossOrigin: 'anonymous' })

fabric提供了好多种滤镜,可以自己根据需求选用,还支持矩阵来自定义滤镜(Convolute)

fabricjs设置画布 fabric.js使用教程_ci_07

加载SVG,其实和加载图片差不多
fabric.loadSVGFromURL('test.svg', (objects, options) => {
  let loadedObject = fabric.util.groupSVGElements(objects, options)
  loadedObject.set({
    left: 500,
    top: 200
  })
    .setCoords()
  canvas.add(loadedObject)
  // loadedObject.sourcePath = 'test.svg'
  // let json = canvas.toJSON(['test'])
  // let lessJson = canvas.toDatalessJSON(['test'])
  // console.log(json)
  // console.log(lessJson)
})

在这里顺便说下toJSON方法,就是把整个canvas都转换成JSON对象,以便需要的时候使用,可以直接用loadFromJSON载入。

上面还写了一个toDatalessJSON,这个一般用在svg比较多的时候,因为svg载入之后是以object-path来保存的,所以大的svg会有很多的path,toJSON之后会过长,所以toDatalessJSON可以把path用路径来代替,不过需要手动设置下sourcePath,以便下次使用的时候能找到。

fabric.js也提供了很多事件以供使用:

fabricjs设置画布 fabric.js使用教程_滤镜_08

一些配置
canvas.preserveObjectStacking = true // 选中的时候是否显示在最上层
canvas.selection = false // 是否支持多选
// 选中框的一些设置
fabric.Object.prototype.set({
  transparentCorners: false,
  borderColor: 'rgba(32,160,255,1)',
  cornerColor: 'rgba(32,160,255,1)',
  cornerStrokeColor: 'rgba(32,160,255,1)',
  padding: 0,
  cornerSize: 5,
  rotatingPointOffset: 20,
})

配置项太多了,需要的自己看下API吧

小结

fabric.js用起来还是很简单的,不过也比较底层,实际应用起来还是需要自己封装很多东西。

基础用法就写这些了,进阶用法等有时间再写一写。

ps. 官方文档和API看的是真头疼。。。