canvasのレスポンシブ対応


canvasのレスポンシブ対応に関する備忘録

ちなみにclassはハイフン、idはキャメルケース。CSSではclassのみ利用し、jsではidのみを利用する。という規則になっています。

<div class="canvas-parent" id="canvasParent">
    <canvas id="canvas"></canvas>
</div>

こんな感じで、canvas要素に対し親となるdivを定義し、div要素に対しでサイズを指定します。

.canvas-parent {
    width: 80%;
    height: 50vh;
}

jsでcanvasのサイズをcanvasParentのサイズに合わせるための処理を書いていきます。

let canvasParent = document.getElementById("canvasParent");
let canvas = document.getElementById("canvas");

let resize = () => {
    canvas.width = canvasParent.clientWidth;
    canvas.height = canvasParent.clientHeight;
};

setInterval(() => resize(), 0);

canvasとcanvasParentを取得し、canvasのwidth|heightにcanvasParentのwidth|heightを代入するだけの手続きresizeを作ります。

その後、setIntervalを用いてresizeを呼び出し続けます。

これにより、常にcanvasのサイズがcanvasParentの、view portや%で指定された曖昧なサイズに適宜修正されていきます。

これだけでは、0msecでcanvasのサイズを修正していくのでリソースを無駄に使っているように見えたり、canvasはサイズが変わるとcanvas内のオブジェクトをクリアするという性質に対応できなくなってしまいます。

ですので、少し修正しましょう。

const FRAMERATE = 60;
let canvasParent = document.getElementById("canvasParent");
let canvas = document.getElementById("canvas");

let resize = () => {
    canvas.width = canvasParent.clientWidth;
    canvas.height = canvasParent.clientHeight;
};

let draw = () => {
    let context = canvas.getContext("2d");
    context.fillRect(100, 100, 80, 80);
};

let world = () => {
    resize();
    draw();
};

setInterval(() => world(), 1000/FRAMERATE);

80x80の正方形を描画するだけの手続きdrawを作成し、resizeとdrawを呼び出すworldも作成します。

setIntervalでは、このworldを呼び出すようにします。

また、intervalの時間は1000/FRAMERATEとなっています。FRAMERATEには60が入っていますが、こう書く事でcanvasが60FPSで動作するようになります。

このsetIntervalの1行setInterval(() => world(), 1000/FRAMERATE);が重要なポイントです。

これにより、ただ描画しろと命令され"画像"を画面上に表示するだけだったcanvasが、一気に動画やゲーム画面として扱えるエリアに進化します。