【HTML5・javascript】canvasで読み込んだ画像を親要素の幅に合わせ高さを調整する方法
canvasを使って読み込んだ画像が親要素の幅に合わせて画像の比率を保ったままいい感じにできないかなぁって思い調べた時の備忘録
参考:ソース周り丸々参考にした
ほぼソースコードについてはここのサイトの使わせてもらった
ただ、めちゃくちゃ参考になったんだけど親要素の高さをCSSのpadding-topで固定しているね
そうじゃなくて親の幅を取得して画像の比率にうまいこと合わせたかったので一部分修正した
それと、どこがどういう処理しているのか勉強がてら調べた
ソースコード
勉強がてらes6で書き直したりしてる
See the Pen
【HTML5・javascript】canvasで読み込んだ画像を親要素の幅に合わせ高さを調整する方法 by twotone (@twotone-me)
on CodePen.
<div id="canvas-container">
<canvas id="canvas"></canvas>
</div>
<script>
const parent = document.getElementById('canvas-container');
const canvas = document.getElementById('canvas');
// 2次元の描画を行うメソッド
const ctx = canvas.getContext('2d');
// リサイズ時の判定用変数
let isInit = false;
// img要素を生成
const img = new Image();
// 読み込み用の画像をimg要素に挿入
img.src = "https://source.unsplash.com/xGy_DKmPYEk/";
// 描画用関数
let render = () => {
// 比率格納用変数
let scale = 0;
if(isInit){// ブラウザをリサイズ時したときの処理
// canvasを再描画するために既存の画像を消す
ctx.clearRect(0, 0, canvas.width, canvas.height);
}else{
isInit = true;
}
// 画像の元のサイズ取得
let img_w = img.naturalWidth;
let img_h = img.naturalHeight;
// 親の幅を取得
let parent_w = parent.clientWidth;
// 親の幅をcanvasに反映
canvas.width = parent_w;
// 横幅の比率から画像の高さを割り出す
canvas.height = img_h * (parent_w / img_w);
// 比率を求める
scale = canvas.width / img.width;
// 比率を元に描画される画像サイズを調整
ctx.setTransform(scale, 0, 0, scale, 0, 0);
// canvasに描画
ctx.drawImage(img, 0, 0);
}
// リサイズ用関数
let main = () => {
img.addEventListener('load', render, false);
window.addEventListener('resize', render, false);
}
main();
</script>
一度描画したコンテンツを消すのにclearRect
を使うみたいね
clearRect(x座標, y座標, width, height)
setTransform()
でcanvas内に描画する画像のサイズを調整してる
今回のソースコードでcanvas自体はブラウザ幅に合わせてリサイズされるけど、中に描画される画像自体はリサイズされないからこのメソッドで調整する必要性があるみたい
// 初期値:setTransform(1, 0, 0, 1, 0, 0)
setTransform(伸縮x, 傾斜y, 傾斜x, 伸縮y, 移動x, 移動y)
参考:比率計算
比率の計算は、
[元の高さ]×([今の横幅]÷[元の横幅])で計算できるみたい
640×480pxの画像があって、親の幅が320pxだったら
[元の高さ]×([今の横幅]÷[元の横幅])
480 × (320 ÷ 640) = 240
だから合ってるね、高さはこれで調整した
メモ:addEventListenerについて
addEventListener()
あんまり使ったことなかった
// addEventListener(イベント, 関数, オプション);
addEventListener('load', render, false);
上記の書き方だと、ロードしたらrender関数を実行するって処理みたいね
オプションのfalse
で子要素から親要素にイベント伝播して、親要素のイベントを先に拾うときはtrue
にすればいいみたい
メモ:drawImage()でサイズの調整できない?
drawImage()
は画像を描画するためのメソッド
最低限の引数で設定を行おうとすると
// フル:drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
// 最低限:drawImage(image, dx(x座標), dy(y座標)
drawImage(img, 0, 0)
drawImage()
は引数めっちゃあるんだけど、引数の意味よくわかんなかったから実際に触って感じたことまとめておく
image | img要素、canvas要素、video要素を指定できる 形としては <img src="画像URL"> を引数に指定する必要があるっぽいね |
---|---|
sx | 画像上のx座標(基本0にする) 0以外を指定するとその数値分トリミングされちゃうね |
sy | 画像上のy座標(基本0にする) 0以外を指定するとその数値分トリミングされちゃうね |
sw | 画像の幅(初期値は画像本来の幅) 画像本来のサイズより数値を小さくするとsx、syで指定した位置から指定した数値分をトリミングして表示、大きくするとその数値分余白が一緒に出力される |
sh | 画像の高さ(初期値は画像本来の高さ) 画像本来のサイズより数値を小さくするとsx、syで指定した位置から指定した数値分をトリミングして表示、大きくするとその数値分余白が一緒に出力される |
dx | 描画するx座標(純粋なcanvas上の座標) |
dy | 描画するy座標(純粋なcanvas上の座標) |
dw | 画像の幅を何pxで表示するか(初期値は画像本来の幅) 数値を画像本来のサイズより小さくするとつぶれて、大きくすると伸びる |
dh | 画像の高さを何pxで表示するか(初期値は画像本来の高さ) 数値を画像本来のサイズより小さくするとつぶれて、大きくすると伸びる |
で、setTransform()
を使って画像のサイズ調整を行わず
drawImage()
で描画するタイミングでサイズ調整すればよくね?
って実際に書くとこうなるわ
ctx.drawImage(img, 0, 0, img_w, img_h, 0, 0, parent_w, img_h * (parent_w / img_w));
これだったらsetTransform()
使わなくてもいける
実際、長くなって可読性下がりそうだし分けた方が良いのかもね
とりあえず、勉強になった
メモ:clientWidthは純粋な見えてるコンテンツ領域
clientWidth
はpaddingとwidthは含んでborderやmargin、スクロールバーは含まないみたい
borderも含めたかったらoffsetWidth
を使ったほうがいいね
clientWidth clientHeight |
widht + padding border、margin含まない |
---|---|
offsetWidth offsetHeight |
widht + padding + border |