點燈坊

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

使用 Canvas 繪製 RWD 圖片

Sam Xiao's Avatar 2021-10-22

由於 Canvas 是直接使用 JavaScript 繪製,若要實現 RWD,則必須從 Resize Event 下手。

Version

Vue 3.2

RWD Canvas

rwd000

在 Vue 完全以 Canvas 繪製圖片。

rwd001

調整 browser 會自動 RWD 調整圖片。

<script setup>
import { onMounted, onBeforeUnmount } from 'vue'

let canvas = $ref (null)

let onResize = _ => {
  let ratio = canvas.width / canvas.height
  
  let canvasHeight = innerHeight
  let canvasWidth = canvasHeight * ratio
  
  if (canvasWidth > innerWidth) {
    canvasWidth = innerWidth
    canvasHeight = canvasWidth / ratio
  }
  
  canvas.style.width = canvasWidth + 'px'
  canvas.style.height = canvasHeight + 'px'
}

onMounted (_ => {
  let context = canvas.getContext('2d')

  let img = new Image
  img.src = 'https://picsum.photos/1920/1080/?random=10'

  img.onload = _ => {
    context.canvas.width = img.width
    context.canvas.height = img.height
    context.drawImage (img, 0, 0)
    onResize ()
  }
  
  addEventListener ('resize', onResize)
})

onBeforeUnmount (_ => removeEventListener ('resize', onResize))
</script>

<template>
  <canvas ref="canvas"/>
</template>

41 行

<canvas ref="canvas"/>

在 HTML 內使用 <canvas> 繪製圖片,因為要由 Vue 控制,特別使用 ref 定義名稱。

第 4 行

let canvas = $ref (null)

使用 $ref 定義 canvas 初始值為 null

21 行

onMounted (_ => {
  let context = canvas.getContext('2d')

  let img = new Image
  img.src = 'https://picsum.photos/1920/1080/?random=10'

  img.onload = _ => {
    context.canvas.width = img.width
    context.canvas.height = img.height
    context.drawImage (img, 0, 0)
    onResize ()
  }
  
  addEventListener ('resize', onResize)
})
  • canvas.getContext 取得 2D 的 context
  • 將圖片建立在 Image Object,當 Object 建立成功後會觸發 onload event,可在此取得圖片長寬,並使用 contextdrawImagecanvas ref 繪圖
  • onload 內呼叫 onResize 重新根據目前 browser 長寬調整圖片

若要一開始就使用 Canvas 繪圖,則一定要寫在 onMounted 內,因為此時 DOM 才準備好,Canvas 才能夠繪圖

14 行

addEventListener ('resize', onResize)

註冊 resize event 綁定到 onResize

第 7 行

let ratio = canvas.width / canvas.height

Browser 長寬改變後不能破壞原本圖片比例,因此先使用 cavas.width 除以 canvas.height 計算出原圖片比例。

第 9 行

let canvasHeight = innerHeight
let canvasWidth = canvasHeight * ratio

if (canvasWidth > innerWidth) {
  canvasWidth = innerWidth
  canvasHeight = canvasWidth / ratio
}
  • 使用 innerHeight 取得目前 browser 高度,成為新圖片 height

  • 根據之前 ratio 計算出新圖片 width

  • 如果新圖片 width 比目前 browser 寬度大,則反過來以 browser 寬度根據 ratio 計算出新圖片高度

17 行

canvas.style.width = canvasWidth + 'px'
canvas.style.height = canvasHeight + 'px'

將新圖片 width 與 height 指定給 style,透過 CSS 改變圖片長寬達成 RWD。

37 行

onBeforeUnmount (_ => removeEventListener ('resize', onResize))

取消 resize event 註冊。

Conclusion

  • Canvas 繪製圖片亦可實現 RWD,唯必須透過 resize event 手動計算出長寬