ブラウザいっぱいにCanvasを表示してあれこれやりたい

デモ, コード

スマホ用にビューポートを設定する

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

htmlのbodyにマージンが入ってしまうのを抑制する

body {
  margin: 0;
}

JavaScriptでキャンバスを作成する

  • window.innerWidth, window.innerHeight でブラウザの表示領域のサイズが取得できる
  • Canvasのサイズは2種類ある
    • canvas.style.width が実際の表示サイズ(CSSで指定する場合と同じく、px指定)
    • canvas.width が内部のサイズ
  • Retinaディレスプレイの場合、window.devicePixelRatioが1より大きな値になっているので、 内部サイズをそれに合わせて大きくしてやるとボケずにすむ
  • それらを使って、document.createElementで生成したキャンバスの設定をする
var canvas = document.createElement('canvas');
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
canvas.width = window.innerWidth * window.devicePixelRatio;
canvas.height = window.innerHeight * window.devicePixelRatio;

キャンバスを配置するdiv要素を作る

ウィンドウと同じサイズのキャンバスをそのままhtmlのbodyに配置してしまうと、キャンバスの下に 勝手に謎の余白が追加されてしまい上下にスクロールできてしまう(要素がcanvasの場合だけ)。 これを防止するためにキャンバスを配置するdiv要素を作り、それをbodyに配置する。 divにはoverflow: hiddenを指定する(そうしないと同様に謎の余白が発生する)。

// キャンバスを配置するdiv要素を作成し、bodyに追加
var container = document.createElement('div');
container.style.width = window.innerWidth + 'px';
container.style.height = window.innerHeight + 'px';
container.style.overflow = 'hidden';
container.appendChild(canvas);
document.body.appendChild(container);

ドラッグ(スワイプ)による上下スクロール(バウンス)を防止する

iPhoneなどではスワイプで上下に動いてしまう。それを防止するために、touchstartイベントで event.preventDefault()を呼び出す。それによってブラウザのデフォルト動作が抑制され、 上下スクロールしなくなる。

// スワイプによるスクロールを禁止させる
document.body.addEventListener('touchstart', function(event) {
  event.preventDefault();
});

デモ

ss.png

問題点

  • ブラウザのサイズを変更した時や、スマホでデバイスを回転させた時に追従しない
    • これに関してはリサイズやorientationchangeをハンドルすればよいでしょう
  • あるAndroidではwindow.innerWidthが公称されている解像度よりも大きな値が入っていて、 さらにdevicePixelRatioが1.5となっているため、ロードした段階で3倍くらいで表示される。 どうしたらいいんだろう…。

Resizing the HTML5 Canvas Dynamically as the Browser Window is Resized - HTML Cheats これで動く?