iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 25
1
Modern Web

Fabricjs 筆記系列 第 25

Day 25 - Fabricjs 實作: 拼貼圖片

  • 分享至 

  • xImage
  •  

今天來實作一個圖片編輯常用的功能: 拼貼。

顧名思義就是能把自己圖片拼到已經設定好的框框中,而圖片可以在框框中調整要顯示的部分,也就是固定位置的裁切功能。

配合之前練習的拖拉圖片進入 canvas 來做到讓使用者自行上傳圖片,再將圖片拖曳進去 canvas 拼貼。

拖曳部分相關可參考 Day 18 - Fabricjs 實作: 圖片上傳並透過拖曳進入 canvas
這邊就不在重複解釋了

建立區域讓使用者知道哪邊可以匯入圖片

我的作法是想要直接讓之後設定的 clipPath 直接依據一開始所設定好的 Layout 做裁切。

首先先建出虛線矩形區塊讓使用者填入,並且將 selectable 設定為 false,只是要讓使用者觀看框框的範圍,所以就不需要讓使用者移動。

自訂 isClipFrame 屬性之後用配合 drop 事件,判斷使用者拖曳到的是不是我們設定的虛線框。

let clipPathTop = new fabric.Rect({
  // ...略
  fill: 'transparent',
  selectable: false,
  isClipFrame: true
})

let clipPathBottom = new fabric.Rect({
  width: 490,
  height:240,
  left: 5,
  top: 255,
  stroke: 'red',
  strokeWidth: 1,
  strokeDashArray: [5, 5],
  fill: 'transparent',
  selectable: false,
  isClipFrame: true
})

canvas.add(clipPathTop)
canvas.add(clipPathBottom)

拼貼動作函數

拖拉 Drap & drop 請參考 Day 18 - Fabricjs 實作: 圖片上傳並透過拖曳進入 canvas

這邊要做的動作分幾個步驟

  1. 判斷拖曳到的 target 是否為矩形虛線框
  2. 新增一張照片到舉行框內,並且設定裁切範圍同等於目標框 target
  3. 判斷長寬是否為滿版來做調整並鎖定移動 X 或 Y。

absolutePositioned 屬性

這邊可以做到這個功能,主要是靠 absolutePositioned 這個屬性,只要將裁切遮罩中的這屬性設成 true,此物件這時候 lefttop 屬性和一般裁切不同的地方在於此物件起始會回到 (0,0),而不是被裁切物件中心。

你可以想像成在 canvas 上挖洞固定在某個位置,而只有那個位置能夠顯示被裁切的物件。

clone 複製物件

這邊因為要做出裁切效果,之後為了更好擴充我們不直接寫死,改成複製一份目標框物件,再將複製出來的 absolutePositioned 屬性設定成 true

參考 fabricjs - copy & parse

  target.clone(cloned => clipPath = cloned)
  clipPath.absolutePositioned = true

判斷長寬並鎖定移動方向

這邊做的事情是比對原始圖片和框的大小是否適合,做出相對應的大小調整動作。

最後固定一軸的移動 X or Y,讓使用者對齊自行調整。

  // 判斷長寬是否為滿版來做調整並鎖定 X Y
  image.scaleToWidth(target.width)
  const isFullHeight = image.getScaledHeight() < target.height
  if (isFullHeight) image.scaleToHeight(target.height)
  image.lockMovementY = isFullHeight
  image.lockMovementX = !isFullHeight

完整函數拼貼動作函數

function dropImg (e) {
  let target = e.target
  if (!target.isClipFrame) return
    // 設定匯入圖塊
  target.clone(cloned => clipPath = cloned)
  clipPath.absolutePositioned = true
  const image = new fabric.Image(movingImage, {
    width: movingImage.naturalWidth,
    height: movingImage.naturalHeight,
    left: target.left,
    top: target.top,
    clipPath,
  })
  // 判斷長寬是否為滿版來做調整並鎖定 X Y
  image.scaleToWidth(target.width)
  const isFullHeight = image.getScaledHeight() < target.height
  if (isFullHeight) image.scaleToHeight(target.height)
  image.lockMovementY = isFullHeight
  image.lockMovementX = !isFullHeight
  
  image.clipPath = clipPath
  canvas.add(image)
}

最後再配合檔案上傳,讓使用者能夠上傳自己想要拼貼的圖片

檔案上傳部分相關可參考 Day 18 - Fabricjs 實作: 圖片上傳並透過拖曳進入 canvas

結果

更多形狀填入

因為我們是直接寫成複製虛線框物件來做裁切,這樣一來,我們就能夠更方便的拼貼圖片,只要我們先將預設的虛線框建出來就可以了!

任何形狀都能裁切!

接下來將預設好的 Layout 儲存起來,包成函數讓使用者可以透過按鈕來切換預設 Layout 。

使用 SVG

也能夠直接使用 SVG 來當作裁切的框,這樣一來可以做的變化就更多了!

function setLayoutStyle3 () {
  canvas.clear()
  const URL = 'https://upload.wikimedia.org/wikipedia/commons/4/42/Love_Heart_SVG.svg'

  fabric.loadSVGFromURL(URL, (objects, options) => {
    console.log(options)
    let svgClip = fabric.util.groupSVGElements(objects, options)
      svgClip.scaleToWidth(300)
      svgClip.set({
        left: 100,
        top: 100,
        stroke: 'red',
        strokeWidth: 1,
        strokeDashArray: [5, 5],
        fill: 'transparent',
        selectable: false,
        isClipFrame: true,
      })
    canvas.add(new fabric.Rect({
      ...
    }))
    canvas.add(new fabric.Rect({
      ...
    }))
    canvas.add(svgClip).renderAll()
  })
}

svg form Wikimedia Commons

今日小結

利用設定 absolutePositioned 固定畫布上的裁切位置。

並且基於這個方式實作出簡易拼貼圖片功能。

利用 SVG 做出更豐富的裁切框。

參考連結


上一篇
Day 24 - Fabricjs 實作: 自訂圖片裁切
下一篇
Day 26 - Fabricjs 進階自訂控制項
系列文
Fabricjs 筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言