點燈坊

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

如何建立能自動 RWD 的 Canvas ?

Sam Xiao's Avatar 2021-01-27

雖然能使用 JavaScript 動態由 Canvas 繪製圖片,但若要能讓 Canvas 也 RWD,則必須搭配一些 CSS 技巧。

Version

CSS 3

Canvas

canvas000

將圖片以 canvas 繪製。

<template>
  <canvas width="640" height="480" ref="canvas"/>
</template>

<script>
let mounted = function() {
  let context = this.$refs.canvas.getContext('2d')
  let image = new Image
  image.src = 'https://picsum.photos/640/480/?random=10'
  image.onload = () => context.drawImage(image, 0, 0)
}

export default {
  mounted
}
</script>

第 2 行

<canvas width="640" height="480" ref="canvas"/>

直接在 canvas 設定 widthheight

第 6 行

let mounted = function() {
  let context = this.$refs.canvas.getContext('2d')
  let image = new Image
  image.src = 'https://picsum.photos/640/480/?random=10'
  image.onload = () => context.drawImage(image, 0, 0)
}
  • canvas.getContext('2d') 取得 context
  • Imagesrc 建立 Image object,在其 onload event 呼叫 drawImage() 對 canvas 畫圖

目前雖然能將在 canvas 畫圖,卻無法支援 RWD

RWD

canvas001

Canvas 可隨著 browser 寬高改變而自動改變。

<template>
  <div class="box">
    <canvas width="640" height="480" ref="canvas"/>
  </div>
</template>

<script>
let mounted = function() {
  let context = this.$refs.canvas.getContext('2d')
  let image = new Image
  image.src = 'https://picsum.photos/640/480/?random=10'
  image.onload = () => context.drawImage(image, 0, 0)
}

export default {
  mounted
}
</script>

<style scoped>
.box {
  width: 63.5%;
  position: relative;
}

.box::before {
  content: '';
  display: block;
  width: 100%;
  padding-bottom: 75%;
}

.box canvas {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}
</style>

26 行

.box::before {
  content: '';
  display: block;
  width: 100%;
  padding-bottom: 75%;
}

使用 ::before 建立一個虛擬的 <div>

  • content: '':沒有任何內容故為 empty string
  • display: block:如 <div> 為 block element
  • width: 100%width 由 parent 的 width 決定,100% 表示跟 parent 的 width 相等
  • padding-bottom: 75%:在此 padding-bottom 相當於 height, 由於其亦由 parent 的 width 決定,目前 width 已經 100% 跟 parent 相等,padding-bottom 只要計算出 height/width 的百分比即可,也就是 480/640*100% = 75%

33 行

.box canvas {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

之前已經使用 ::before 建立出虛擬 <div> 建立空間,只要使用絕對定位將圖片覆蓋在虛擬 <div> 上即可。

  • width: 100%:取代原本 width640,改與 parent width 100% 相等
  • height: 100%:取代原本 height480,改與 parent height 100% 相等

21 行

.box {
  width: 63.5%;
  position: relative;
}

由於 ::before 所建立的 <div>.box canvas 都由 parent 的 width 決定,因此 .boxwidth 成為一開始顯示寬度的關鍵。

Conclusion

  • 這種方式可視為 pattern 使用,唯 padding-bottom 需根據實際 canvas 的 height / width 計算,且 box 的 width 也須視需求指定