Fabric.js 喷雾笔刷 从入门到放肆

2,598 阅读4分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第18篇文章,点击查看活动详情


本文简介

点赞 + 关注 + 收藏 = 学会了


喷雾笔刷 SprayBrushfabric.js 提供的一个很好玩的工具,而且 fabric.js 也封装好了很多非常方便的属性让我们配置,用起来非常简单的。

先看看效果:

01.gif



常规配置

喷雾笔刷作为一款笔刷工具,要使用它首先要让画布开启“绘画模式”。

isDrawingMode 设为 true 就可以开启。

02.gif

<canvas id="c" width="500" height="400" style="border: 1px solid #ccc;"></canvas>

<script>
  // 初始化
  const canvas = new fabric.Canvas('c', {
    isDrawingMode: true
  })
</script>

如果不在画布初始化时开启绘画模式,也可以之后再开启

canvas.isDrawingMode = true

如果想切换回普通模式,只需把 isDrawingMode 改回 false 即可。


注册喷雾笔刷

喷雾笔刷叫 SprayBrush

注册喷雾笔刷时需要把初始化的画布传进去,然后再赋值给 canvas.freeDrawingBrush

03.gif

// 省略部分代码

canvas.freeDrawingBrush = new fabric.SprayBrush(canvas)

// 更推荐的写法
let sprayBrush = new fabric.SprayBrush(canvas)
canvas.freeDrawingBrush = sprayBrush

我更推荐把 sprayBrush 保存到一个变量里,这样比较方便之后配置各种效果。


除了上面这种写法,也可以这样写:

// 省略部分代码

let sprayBrush = new fabric.SprayBrush()
sprayBrush.initialize(canvas)
canvas.freeDrawingBrush = sprayBrush

initialize()SprayBrush 初始化的一个方法,里面接收的参数是当前的画布 canvas


设置笔刷粗细

为了方便其他属性演示,所以先把笔刷的宽度设置大点。

04.gif

// 省略部分代码

sprayBrush.width = 200

width 属性就是用来设置画笔粗细的,数值越大画笔就越粗。


设置喷雾密度

可以使用 density 属性设置喷雾密度,数值越大密度就越大。

density 的默认值是 20。

05.gif

// 省略部分代码

sprayBrush.width = 200
sprayBrush.density = 100 // 设置喷雾密度

density 设置得小点对比一下

sprayBrush.width = 200
sprayBrush.density = 10

06.gif

很直观的看到差距了。


设置喷点大小

“喷点” 就是喷雾中的每一个点,设置喷点宽度的属性名叫 dotWidth

dotWidth 默认值是 1。数值越大,喷点就越大。

07.gif

// 省略部分代码

sprayBrush.width = 200 // 设置喷雾宽度

sprayBrush.dotWidth = 10 // 设置喷点大小

设置喷点方差

可以使用 dotWidthVariance 属性设置喷点的方差。

dotWidthVariance 可以在规定范围内随机生成大小不一的喷点。

dotWidthVariance 的默认值是1。数值越大,喷点随机大小就越大。

08.gif

// 省略部分代码

sprayBrush.width = 200
sprayBrush.dotWidthVariance = 10

设置了 dotWidthVariance 后,dotWidth 的意义就不大了。


防重叠

喷雾笔刷默认是会删除重叠的点,官方文档说这是处于性能考虑的原因。

如果不希望删除重叠的点,可以将 optimizeOverlapping 设为 false

// 省略部分代码

sprayBrush.optimizeOverlapping = false

设置喷点的随机不透明度

可以通过 randomOpacity 属性设置喷点的不透明度是否随机。

// 省略部分代码

sprayBrush.randomOpacity = true

设置喷雾阴影

在喷雾笔刷的文档里没提到阴影,但既然基础笔刷可以设置阴影,喷雾笔刷同样也可以设置阴影的。

09.gif

// 省略部分代码

sprayBrush.width = 200
sprayBrush.dotWidthVariance = 10

// 设置阴影效果
sprayBrush.shadow = new fabric.Shadow({
  blur: 10,
  offsetX: 10,
  offsetY: 10,
  color: '#30e3ca'
})

设置喷雾颜色

喷雾笔刷可以通过 color 设置喷雾颜色的,但官方文档好像忘了写这个属性了。

10.gif

// 省略部分代码

sprayBrush.color = 'pink'


事件

前面讲到 initialize() 方法可以初始化画笔,除此之外喷雾笔刷还有其他事件方法。


喷雾准备生成前和生成后

喷雾也是一种路径,所以可以监听 canvas 的路径生成时的周期。

在喷雾准备生成前,可以监听 before:path:created ;喷雾生成后,可以监听 path:created

// 省略部分代码

// 准备生成前
canvas.on('before:path:created', opt => {
  console.log(opt.path)
})

// 生成后
canvas.on('path:created', opt => {
  console.log(opt.path)
})

鼠标按下时 onMouseDown

sprayBrush.onMouseDown = function(t) {
  this.sprayChunks.length = 0,
  this.canvas.clearContext(this.canvas.contextTop),
  this._setShadow(),
  this.addSprayChunk(t),
  this.render(this.sprayChunkPoints)
}

鼠标移动时 onMouseMove

sprayBrush.onMouseMove = function(t) {
  !0 === this.limitedToCanvasSize && this._isOutSideCanvas(t) || (this.addSprayChunk(t),
  this.render(this.sprayChunkPoints))
}

松开鼠标时 onMouseUp

sprayBrush.onMouseUp = function() {
  var t = this.canvas.renderOnAddRemove;
  this.canvas.renderOnAddRemove = !1;
  for (var e = [], i = 0, r = this.sprayChunks.length; i < r; i++)
    for (var n = this.sprayChunks[i], s = 0, o = n.length; s < o; s++) {
      var a = new fabric.Rect({
        width: n[s].width,
        height: n[s].width,
        left: n[s].x + 1,
        top: n[s].y + 1,
        originX: "center",
        originY: "center",
        fill: this.color
      });
      e.push(a)
    }
  this.optimizeOverlapping && (e = this._getOptimizedRects(e));
  var c = new fabric.Group(e);
  this.shadow && c.set("shadow", new fabric.Shadow(this.shadow)),
  this.canvas.fire("before:path:created", {
    path: c
  }),
  this.canvas.add(c),
  this.canvas.fire("path:created", {
    path: c
  }),
  this.canvas.clearContext(this.canvas.contextTop),
  this._resetShadow(),
  this.canvas.renderOnAddRemove = t,
  this.canvas.requestRenderAll()
}

注意上面的注释,找到 circle 那段就是本例的重点




以上就是喷雾的基础用法,如果都搞明白了,那就做2个案例练练手呗~



🔴 修改喷点图形

喷雾的生成其实关键是在 onMouseUp 事件。

我们看到官方的代码中,生成喷雾使用了 Reat 元素作为喷点

我有个大胆的想法,如果把 Rect 改成其他元素是否可以生成其他图形的喷雾呢?

于是我用了 圆形 Circle

11.png

// 省略部分代码

sprayBrush.onMouseUp = function() {
  var t = this.canvas.renderOnAddRemove;
  this.canvas.renderOnAddRemove = !1;
  for (var e = [], i = 0, r = this.sprayChunks.length; i < r; i++)
    for (let n = this.sprayChunks[i], s = 0, o = n.length; s < o; s++) {

      // 改成圆形喷头 !!!!!!!!!!!!!!!!!
      const circle = new fabric.Circle({
        radius: n[s].width,
        top: n[s].y + 1,
        left: n[s].x + 1,
        originX: "center",
        originY: "center",
        fill: this.color
      })
      e.push(circle)
    }

  this.optimizeOverlapping && (e = this._getOptimizedRects(e));
  let c = new fabric.Group(e);
  this.shadow && c.set("shadow", new fabric.Shadow(this.shadow)),
  this.canvas.fire("before:path:created", {
    path: c
  }),
  this.canvas.add(c),
  this.canvas.fire("path:created", {
    path: c
  }),
  this.canvas.clearContext(this.canvas.contextTop),
  this._resetShadow(),
  this.canvas.renderOnAddRemove = t,
  this.canvas.requestRenderAll()
}

注意上面的代码注释,搜索 Circle 那行看看吧,这是修改喷点图形的关键点。

这个圆形喷雾是不是有点像 圆形笔刷 CircleBrush 的效果~


喷点除了改成圆形,还可以设置成其他图形,其他图形可以查看 Fabric.js 入门 - 基础图形

甚至还能自定义图形。

12.png

要实现这种自定义图形,可以查看 Fabric.js 自定义子类,创建属于自己的图形 ,然后在 onMouseUp() 事件中,把图形改成自己创建的那个即可。



🎨 随机色喷雾

理解了前面 “修改喷点图形” 的话,那要搞个随机色喷雾也是洒洒水啦~

只需把每个图形的 fill 设置成不一样就行了。

13.png

sprayBrush.onMouseUp = function() {
  var t = this.canvas.renderOnAddRemove;
  this.canvas.renderOnAddRemove = !1;
  for (var e = [], i = 0, r = this.sprayChunks.length; i < r; i++)
    for (let n = this.sprayChunks[i], s = 0, o = n.length; s < o; s++) {

      // 每个点都生成自己的随机色(rgb)!!!!!!!!!!!!!!!
      let r = Math.floor(Math.random() * 255)
      let g = Math.floor(Math.random() * 255)
      let b = Math.floor(Math.random() * 255)

      let rect = new fabric.Rect({
        width: n[s].width,
        height: n[s].width,
        left: n[s].x + 1,
        top: n[s].y + 1,
        originX: "center",
        originY: "center",
        fill: `rgb(${r}, ${g}, ${b})` // 每个图形的填充色都不一样了!!!!!!!!!!!
      });
      e.push(rect)
    }
  this.optimizeOverlapping && (e = this._getOptimizedRects(e));
  let c = new fabric.Group(e);
  this.shadow && c.set("shadow", new fabric.Shadow(this.shadow)),
  this.canvas.fire("before:path:created", {
    path: c
  }),
  this.canvas.add(c),
  this.canvas.fire("path:created", {
    path: c
  }),
  this.canvas.clearContext(this.canvas.contextTop),
  this._resetShadow(),
  this.canvas.renderOnAddRemove = t,
  this.canvas.requestRenderAll()
}

好了,上面这个案例其实只是提供一个思路。这种随机色的配色是真的丑。。。



代码仓库

喷雾笔刷



推荐阅读

👍《Fabric.js 从入门到_ _ _ _ _ _》

👍《Fabric.js 铅笔笔刷》

👍《Fabric.js 拖拽平移画布》

👍《Fabric.js 使用图片遮盖画布(前景图)》


点赞 + 关注 + 收藏 = 学会了