Fabric.js高級點的教程4--內嵌工做臺畫布

額。。這是我本身創造的名詞,內嵌工做臺畫布javascript

要實現什麼效果

如圖(http://fabricjs.com/kitchensink): java

首先想元素脫出畫布外一部分也能選中,如圖上面就無法選擇超出框外的內容。我想到的是如何在畫布中間加個畫布。周圍隱藏掉。json

實現思路

  1. 首先建立一個足夠大的畫布
  2. 設置一個padding
  3. 經過padding 計算中間白色區域四個角的座標
  4. 在周圍畫上四個矩形蓋住(也能夠畫一個大矩形,把中間的挖掉,因爲各類需求和測試問題沒有采用這種方式)
  5. 每次添加新的元素在上面的時候都保持周邊四個區域在最上面

其餘思路

  1. 使用clipPath,畫一個通道給中間區域。
  2. 畫兩個畫布一個再上面一個在下面 其實這些方法可能都能實現,可是問題的關鍵不是實現,而是如何兼容以後的諸多行爲,好比zoom,loadJson,redo, undo

代碼

1.先定義一個想要的外邊距padding,而後計算內部工做臺處於外部畫布的四個點的位置。canvas

// 獲取中間畫布的四個點的位置
function setXY(state, obj = {}) {
  // 最外邊整個畫布的寬 高
  const w = obj.currentWidth || state.currentWidth 
  const h = obj.currentHeight || state.currentHeight
  // 內部工做臺畫布的寬pannelW 高pannelH
  if (
    state.currentWidth / state.currentHeight >
    state.pannelW / state.pannelH
  ) {
    const height = h - state.padding
    // 縮放畫布,由於pannelW爲實際寬度,好比一張A4紙顯示在屏幕上,須要縮放一下,zoom後獲取到屏幕的寬度
    state.zoom = height / state.pannelH
    this.commit('zoomCanvas')
    const x2 = 0
    const y2 = 0

    const y0 = state.padding / state.zoom / 2 + y2
    const y1 = state.pannelH + y0
    const x0 = w / state.zoom / 2 - state.pannelW / 2 + x2
    const x1 = state.pannelW + x0
    state.arrX = [x0, x1, x2, w / state.zoom + x2]
    state.arrY = [y0, y1, y2, h / state.zoom + y2]
  } else {
    const width = w - state.padding
    state.zoom = width / state.pannelW
    this.commit('zoomCanvas')
    const x2 = 0
    const y2 = 0

    const x0 = state.padding / state.zoom / 2 + x2
    const x1 = state.pannelW + x0
    const y0 = h / state.zoom / 2 - state.pannelH / 2 + y2
    const y1 = state.pannelH + y0
    state.arrX = [x0, x1, x2, w / state.zoom]
    state.arrY = [y0, y1, y2, h / state.zoom]
  }
}

2.建立四周的遮罩,給中間的區域,畫個背景測試

function createMask(state) {

  const arrX = state.arrX
  const arrY = state.arrY

  const pathOption = {
    selectable: false,
    fill: '#ebeced',
    hoverCursor: 'default',
    evented: false,
    excludeFromExport: true,
    hasControls: false,
    perPixelTargetFind: false,
    strokeWidth: 0,
    stroke: null
  }

  const rect1 = new fabric.Rect({
    width: arrX[0] - arrX[2],
    height: arrY[3] - arrY[2]
  })
  const rect2 = new fabric.Rect({
    width: arrX[3] - arrX[0] + 2,
    height: arrY[0] - arrY[2]
  })
  const rect3 = new fabric.Rect({
    width: arrX[3] - arrX[1],
    height: arrY[1] - arrY[0] + 2
  })
  const rect4 = new fabric.Rect({
    width: arrX[3] - arrX[0],
    height: arrY[3] - arrY[1]
  })
  rect1.set({
    left: arrX[2],
    top: arrY[2],
    name: 'mask1',
    ...pathOption
  })
  rect2.set({
    left: arrX[0] - 1,
    top: arrY[2],
    name: 'mask2',
    ...pathOption
  })
  rect3.set({
    left: arrX[1],
    top: arrY[0] - 1,
    name: 'mask3',
    ...pathOption
  })
  rect4.set({
    left: arrX[0],
    top: arrY[1],
    name: 'mask4',
    ...pathOption
  })

  state.maskPath = new fabric.Group([rect1, rect2, rect3, rect4], {
    selectable: false,
    excludeFromExport: true,
    lockMovementX: true,
    lockMovementY: true,
    lockRotation: true,
    lockScalingX: true,
    lockScalingY: true,
    lockUniScaling: true,
    hoverCursor: 'auto',
    name: 'grid',
    left: arrX[2],
    top: arrY[2],
    type: 'sMask',
    evented: false
  })
  // 建立中間畫布的背景
  state.backgroundPanel = new fabric.Rect({
    left: arrX[0],
    top: arrY[0],
    selectable: false,
    evented: false,
    width: state.pannelW,
    height: state.pannelH,
    strokeWidth: 0,
    fill: !state.activePage ? '#ffffff' : 'rgba(0, 0, 0, 0)',
    objectCaching: false,
    hoverCursor: 'default',
    excludeFromExport: true,
    hasControls: false,
    type: 'sBg',
    perPixelTargetFind: false
  })
  state.canvas.remove(...state.canvas.getObjects('sMask'))
  state.canvas.remove(...state.canvas.getObjects('sBg'))
  state.canvas.add(state.maskPath)
  state.canvas.add(state.backgroundPanel)
  state.canvas.sendToBack(state.backgroundPanel)

  state.canvas.renderAll()
}

3.刷新畫布,或者加載數據的時候this

jsonDemo.objects.forEach((item) => {
    item.left += state.arrX[0]
    item.top += state.arrY[0]
 })

4.保存jsonspa

function saveJson(state) {

  // state.toJSONProperties 爲要保存的額外屬性
  const jsonStr = JSON.stringify(state.canvas.toJSON(state.toJSONProperties))
  const jsonObj = JSON.parse(jsonStr)

  jsonObj.objects.forEach((v) => {
    v.left = v.left - state.arrX[0]
    v.top = v.top - state.arrY[0]
  })

}
相關文章
相關標籤/搜索