iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
1
Modern Web

Fabricjs 筆記系列 第 22

Day 22 - Fabricjs 圖形裁切基礎介紹

裁切功能在一般圖片編輯軟體相當的常見,這邊也能夠透過 Fabricjs 來做圖片裁切的功能,甚至可以做出讓使用者自行決定裁切的位置,切出他們想要留下的範圍,或是用一些特別的圖形來做特別的裁切效果。

Fabricjs 提供的裁切功能,就在最近發布的 2.4.0 版本之後,能夠直接使用 Fabricjs 創建出來的物件和物件重疊,再決定裁切的效果要如何。

而在 2.4.0 版本之前則需要使用物件中的 clipTo 屬性,必須使用原生 canvas 的語法來做裁切的效果。

2.4.0 版本之後的這個改動,能夠讓我們更加簡單的去使用 fabricjs 所提供的裁切功能,且不須要太多原生知識就能夠執行了,不過還是保留了 2.4.0 版本之前的 clipTo 提供了更彈性的使用方法。

clipTo 屬性介紹 (2.4.0 版本之前)

這邊先來簡單介紹一下 2.4.0 以前 clipTo 屬性的使用,其實使用方法也很簡單,只要將 clipTo 屬性設定為 callBack function ,並且使用 ctx 來做繪畫,使用 canvas 原生的繪圖方式畫出一個形狀之後,fabricjs render 時就會自動做裁切了。

const imgEl = document.createElement('img')
imgEl.crossOrigin = 'Anonymous'
imgEl.src = 'https://i.imgur.com/1k9XjUn.jpg'
imgEl.onload = () => {
  const image = new fabric.Image(imgEl, {
    scaleX: 0.5,
    scaleY: 0.5,
    angle: 15,
    top: 60,
    left: 300,
    clipTo: function (ctx) {
      ctx.arc(0, 0, 200, 0, Math.PI * 2, true)
    }
  })
  canvas.add(image)
}

clipPath 屬性介紹 (2.4.0 版本之後)

2.4.0 版本後,若要做裁切的功能,可以先新增一個物件暫存起來,再加入到想要裁切的物件中的 clipPath 屬性中。

讓我們來實作這部分。

先設定一個圓形來準備做裁切

這邊因為是要來拿做裁切的物件,所以它的 top left 屬性視參照於被裁切的物件,且被裁切物件起始點為物件的中心。

// 以被裁切物件的中心為起始點
const clipPath = new fabric.Circle({
  radius: 200,
  top: -200, // 被裁切物件中心點為基準的 -200
  left: -200 // 被裁切物件中心點為基準的 -200
})

設定 clipPath

透過設定被裁切物件的 clipPath 屬性,指定為 clipPath 為上面新增的圓形,這樣一來,就能做出裁切的效果,圖片只顯示圓形半徑為 200 的部分,也就是兩個物件所重疊的部分。

imgEl.onload = () => {
  const image = new fabric.Image(imgEl, {
    scaleX: 0.5,
    scaleY: 0.5,
    top: 60,
    left: 300,
    clipPath // 這個 clipPath 為設定裁切的關鍵
  })
  canvas.add(image)
}

結果會同上

使用群組裁切

新的裁切功能,可以更自由的使用裁切,能夠透過群組物件 (group) ,作為裁切或是被裁切的物件。

接下來會來試試使用群組當做裁切遮罩,以及讓群組被裁切。

裁切群組

做出組合當作裁切遮罩

如果你想要把裁切遮罩完美的對齊正中間,請將 originX originY 設定成 'center',且不需要再額外設定 left top

const groupClip = new fabric.Group([
  new fabric.Rect({ width: 50, height: 50 }),
  new fabric.Rect({ width: 50, height: 50, angle: 45 }),
  new fabric.Rect({ width: 50, height: 50, angle: 90 }),
  new fabric.Rect({ width: 50, height: 50, angle: 135 }),
  new fabric.Rect({ width: 50, height: 50, angle: 180 }),
  new fabric.Rect({ width: 50, height: 50, angle: 225 }),
  new fabric.Rect({ width: 50, height: 50, angle: 270 }),
  new fabric.Rect({ width: 50, height: 50, angle: 315 })
], {
  scaleX: 3,
  scaleY: 3,
  originX: 'center',
  originY: 'center'
})

再來一樣設定 clipPath 指定為 groupClip 物件。

  const groupImage = new fabric.Image(imgEl, {
    scaleX: 0.5,
    scaleY: 0.5,
    clipPath: groupClip
  })
  canvas.add(groupImage)

OK 完成

群組切群組

依照上面的邏輯,可以很間單的做出群組切群組的功能,只要好好地將 clipPath 設定好就行了。

const circleClip = new fabric.Group([
  new fabric.Circle({ radius: 50, top: -50, left: -50 }),
  new fabric.Line([0, 0, 100, 100], { strokeWidth: 5, fill: 'black', stroke: 'black' }),
  new fabric.Line([0, 0, 100, 100], { strokeWidth: 5, fill: 'black', stroke: 'black', angle: 90 }),
  new fabric.Line([0, 0, 100, 100], { strokeWidth: 5, fill: 'black', stroke: 'black', angle: 180 }),
  new fabric.Line([0, 0, 100, 100], { strokeWidth: 5, fill: 'black', stroke: 'black', angle: 270 })
])
const group = new fabric.Group([
    new fabric.Rect({ width: 100, height: 100, fill: 'red' }),
    new fabric.Rect({ width: 100, height: 100, fill: 'yellow', left: 100 }),
    new fabric.Rect({ width: 100, height: 100, fill: 'blue', top: 100 }),
    new fabric.Rect({ width: 100, height: 100, fill: 'green', left: 100, top: 100 })
  ], {
  clipPath: circleClip
})
canvas.add(group)

本日小結

今天介紹了幾種裁切物件的方式,個人覺得在 2.4.0 版本過後 Fabricjs 所提供的 clipPath 實在是相當簡單易用,尤其在群組裁切的部分,不需要自己再去用 canvas 原生 api 刻出複雜的圖形,透過搭配 fabric.Group 功能就可以做到很方便的裁切。

本日 - codepen

參考資料

  • 可參考之前文章

Day 4 -認識各種 Fabricjs 提供的物件型態
Day 13 - 把物件群組起來


上一篇
Day 21 - Fabricjs Zoom in & Zoom out
下一篇
Day 23 - Fabricjs 圖形裁切進階
系列文
Fabricjs 筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言