20230729

Canvas 要搞清楚畫圖原點位置

就是這個,卡了快一個禮拜。主要要做到的事,是把上方用 CSS 調整過後的、眼睛看到的樣子,畫在下方 Canvas 裡,角度、旋轉、位移都要一樣。

function draw() {
  const c = document.getElementById("myCanvas");
  const ctx = c.getContext("2d");
  const img = document.getElementById("scream");
  document.getElementById("msg").innerHTML=img.offsetLeft;
  const scaleratio=1.5;
  const diffx=400 + img.width / 2;
  const diffy=0 + img.height / 2;
  
  ctx.translate(diffx,diffy);
  ctx.scale(scaleratio,scaleratio);
  ctx.rotate(Math.PI/180*45);
  ctx.drawImage(img,-img.width/2, -img.height/2, img.width, img.height);
}

首先算出 diffx and diffy, 這是為了要後來要將 Canvas 畫圖原點預設是在左上角,接下來要移到 img 的中心原點用的。畢竟上方 user 看到的畫面,都是以 img 中心來操作的(CSS transform) ,要說是拿左上角操作的話,大概只有 translate 可以說是拿左上角的點進行操作。

img 的中心 x 座標是 img.width / 2,要記得加上模擬的位移 400,同樣 img 的中心 y 座標是 img.height / 2,也要加上模擬位移 = 0。canvas scale 數值和 css scale 數值一樣,剩 canvas rotate 用的是弧度而不是角度,要記得換算。

真正重要的地方是在 ctx.translate(diffx, diffy) 這一步,把 canvas 原點移到跟 img 一樣是在中心的地方。本來以為先放大再位移會是一樣的結果,可是實驗結果就是不對,最後把數字印出來才發現,放大後不會更改座標數字,例如原本是 (1, 1) 在放大後取得的座標值也還是 (1, 1) ,但是會跑到看起來是 (1.5, 1.5) 的地方,因為 canvas scale 改了座標的單位,假設本來一個刻度是 1cm 的放大後一個刻度是 1.5cm 這樣,「先放大再旋轉」或「先旋轉再放大」好像就沒有差別了。

最後真正 drawImage 的時候,因為已經把中心移到跟 img 中心一樣在中間的位置了,所以要畫出左上角的話, dx = -img.width / 2, dy = -img.height / 2 才對,配上畫完整個 img 的寬度、高度。

23.08.09 update. 趁今天有空,寫在 codepen裡,免得下次我要畫圖的時候又忘記了。

0 comments:

張貼留言