发布日期 » 2019年1月17日 星期四

版权声明 » 自媒体人·陈帅华原创内容,转载请注明出处

Fabric.js进阶—事件驱动

Fabric进阶部分包括:

  • 动画
  • 图像滤镜
  • 颜色
  • 渐变
  • 字符排版
  • 事件

创建动画

如果你还记得如何更新组件的状态,那么你一定不难理解如何创建动画。

rect.set('angle', 45)
canvas.renderAll()

rect.animate('angle', 45, {
  onChange: canvas.renderAll.bind(canvas)
})

set() 方法立即更新组件的状态,而 animate() 方法将组件从当前状态平滑的过渡到目标状态。

仅此而已。

如果我们不关心组件的目标状态如何,仅关心组件的变化量,只需:

rect.animate('left', '+=100', {
  onChange: canvas.renderAll.bind(canvas)
})

细心的你注意到 animate() 方法的最后一个对象参数,除了 onChange 这一事件钩子函数之外,还有:

  • from 覆盖动画的开始状态
  • duration 过渡时长
  • onComplete 完成动画后触发
  • onChange 动画过程中每次改变状态时触发
  • easing 缓动函数

图像滤镜

Fabric预设了几个常见滤镜,例如:

  • 除白色背景
  • 灰阶
  • 反色
  • 变亮、变暗
  • 混色
  • 噪点

每一个 fabric.Image 的实例中都包含一个叫做 filters 的属性,默认是一个空数组。

该数组中的每一个元素都是一枚滤镜。

为图像应用滤镜:

fabric.Image.fromURL('pug.jpg', (img)=>{
  img.filters.push(new fabric.Image.filters.Grayscale())
  img.applyFilters()
  canvas.add(img)
})

该滤镜数组支持所有对数组元素增加或删除的操作:

  • remove : pop splice shift
  • add : push splice unshift

并将新的滤镜组合应用到数组。

Fabric支持开发者创建自定义滤镜,原理是对图像进行像素级操作。

颜色

作为前端众所周知,表示颜色的格式多种多样:

  • #f55
  • #123123
  • 356735
  • rgb(100, 0, 100)
  • rgba(10, 20, 30, .5)

由于长期使用习惯的养成与固化,开发者会青睐书写特定的颜色格式表示颜色。

Fabric包容开发者的任性,轻松转换颜色格式:

new fabric.Color('#f55').roRgb() // rgb(255,85,85)
new fabric.Color('rgb(100,100,100)').toHex() // "646464"

甚至:

let redish = new fabric.Color('#f55')
let greenish = new fabric.Color('#5f5')

redish.overlayWith(greenish).toHex() // "AAAA55"
redish.toGrayscale().toHex() // "A1A1A1"

渐变

Fabric通过 setGradient 方法实现对设置渐变色的支持,使用方法同设置纯色的步骤类似:

let circle = new fabric.Circle({
  left: 100,
  top: 100,
  radius: 50
})

circle.setGradient('fill', {
  x1: 0,
  y1: 0,
  x2: 0,
  y2: circle.height,
  colorStops: {
    0: 'red',
    1: 'blue'
  }
})

0与1之间存在不止一百万种可能。

字符排版

除了图像和颜色外,一副只包含文字的海报,经过别出心裁的设计排版,也能强烈反应创作者要表达的态度,引众人拍案称绝。

  • 字体的选用
  • 字号的控制
  • 字形
  • 文字颜色
  • 文件间距与段落行高

每一处细小的调整都影响这作品的视觉效果。而Fabric已经为我们考虑到了!

Fabric为文字提供更多支持:

  • 多行支持
  • 段落居中方式:左对齐、右对齐、居中对齐
  • 文本背景
  • 文本装饰:上、下划线,删除线
  • 段落行高
  • 字符间距
  • 文本区域级操作
  • 支持表情符号
  • 文本编辑所见即所得

事件驱动

用户按下了鼠标?新的对象添加到画布上了?画布被重新渲染了?

你没必要事事操心,订阅感兴趣的事件,在事件发生的时自会知晓。

canvas.on('mouse:down', function(options){
  if(options.target){
    console.log('an object was clicked!', options.target.type)
  }
})

canvas实例的可订阅事件:

  • 鼠标 mouse:down mouse:move mouse:up
  • 渲染 after:render
  • 选中 before:selection:cleared selection:created selection:cleared
  • 对象 object:modified object:selected object:moving object:scaling object:rotating object:added object:removed

订阅对象事件:

let rect = new fabric.Rect({ width: 100, height: 50, fill: 'green'})
rect.on('selected', function(){
  console.log('selected a rectangle')
})

想象一款不能再简单的城市建造类H5小游戏。

一所小房子,一个三角形作为屋顶,一个矩形作为墙壁,一个矩形作为门。用户可自定义小房子的屋顶、墙壁、门的颜色还有小房子的位置与大小。

用户拖拽小房子以改变其位置,拉伸四周以等比缩放其大小…

Fabric中的 fabric.Group将对歌对象分为同一组,便于批量操作:

let circle = new fabric.Circle({
  radius: 50,
  fill: 'red'
  scaleY: .5,
  originX: 'center'
  originY: 'center'
})
let text = new fabric.Text('Hello world', {
  fontSize: 30,
  originX: 'center',
  originY: 'center'
})
let group = new fabric.Group([circle, text], {
  left: 150,
  top: 100,
  angle: -10
})
canvas.add(group)

对象组和canvas 很类似,所拥有的方法也可类比:

  • getObjects()
  • size()
  • item()
  • forEachObject()
  • add()
  • remove()