點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Vue-konva 繪製圖片

Sam Xiao's Avatar 2020-07-16

Vue-konva 除了能繪製圖形外,也能繪製圖片,讓我們以更靈活方式控制圖片。

Version

macOS Catalina 10.15.5
WebStorm 2020.1.3
Vue 2.6.11
Vue-konva 2.1.3

Draw Image

image000

除了使用 <img> 顯示圖片外,我們也可使用 Vue-konva 繪製圖片。

Vue-konva

<template>
  <v-stage :config="stageConfig">
    <v-layer>
      <v-image :config="imageConfig"></v-image>
    </v-layer>
  </v-stage>
</template>

<script>
let width = window.innerWidth
let height = window.innerHeight

let mounted = function() {
  let image = new Image
  image.src = 'https://konvajs.org/assets/yoda.jpg'
  image.onload = _ => {
    this.imageConfig = {
      'image': image
    }
  }
}

export default {
  name: 'App',
  data: _ => ({
    stageConfig: {
      width, height
    },
    imageConfig: {}
  }),
  mounted
}
</script>

第 2 行

<v-stage :config="stageConfig">
  <v-layer>
    <v-image :config="imageConfig"></v-image>
  </v-layer>
</v-stage>

Vue-konva 提供了 <v-image> 讓我們繪製圖片,依然只要提供繪圖資訊給 config property 即可。

14 行

let image = new Image
image.src = 'https://konvajs.org/assets/yoda.jpg'
image.onload = _ => {
  this.imageConfig = {
    'image': image
  }
}

要繪製圖片比較特殊,必須使用 Image Object,但 Image Object 以 asynchronous 提供 image,必須在 load event 才能得到完整 image 寫入 imageConfig side effect。

Promise

<template>
  <v-stage :config="stageConfig">
    <v-layer>
      <v-image :config="imageConfig"></v-image>
    </v-layer>
  </v-stage>
</template>

<script>
let width = window.innerWidth
let height = window.innerHeight

let toImage = src => new Promise((resolve, reject) => {
  let image = new Image
  image.src = src
  image.onload = _ => resolve({ image })
  image.onerror = e => reject(e)
})

let mounted = async function() {
  let src = 'https://konvajs.org/assets/yoda.jpg'

  toImage(src)
    .then(x => this.imageConfig = x)
    .catch(console.log)
}

export default {
  name: 'App',
  data: _ => ({
    stageConfig: {
      width, height
    },
    imageConfig: {}
  }),
  mounted
}
</script>

13 行

let toImage = src => new Promise((resolve, reject) => {
  let image = new Image
  image.src = src
  image.onload = _ => resolve({ image })
  image.onerror = e => reject(e)
})

若覺得 Image Object 使用 event-based API 實現 asynchronous 不舒服,也可自行實作 toImage() 以 Promise 實現。

load event 以 resolve() 回傳 imageConfig object,並在 error event 提供 Rejected Promise。

23 行

toImage(src)
  .then(x => this.imageConfig = x)
  .catch(console.log)

由於 toImage() 回傳 Promise,因此可在 Promise Chain 中寫入 side effect 與 error handling。

Conclusion

  • Vue-konva 在繪製圖片時與一般圖形不同,需使用 Image Object,因此勢必以 code 建立
  • Image Object 為 asynchronous,在 load event 才能提供完整 image,除了在 load event 寫入 side effect 外,也可改用 Promise 方式

Reference

Vue-konva, How to Draw Image on Canvas with Vue ?