HTML+JavaScriptだけでブラウザに図形描画(3) - Canvas API -

2012年10月11日(木)
山田 祥寛(YAMADA, Yoshihiro)

TIPS 032:マウスポインタの座標に応じて図形を描画する

マウスイベントやタッチイベントを利用することで、ユーザーの操作に応じてキャンバスを操作することもできます。以下は、マウスポインタの動きに応じてキャンバス上に曲線を描く、簡易な落書き帳アプリの例です。

[リスト05]マウスポインタの動きに応じて曲線を描画するコード(pointer.html)

window.addEventListener('DOMContentLoaded',
  function() {
    if (HTMLCanvasElement) {
      // ひとつ前のマウス座標(o_x、o_y)、マウスボタンが押されているか(flag)
      var o_x = 0, o_y = 0, flag = false;
      var cv = document.querySelector('#cv');
      var c = cv.getContext('2d');
 
      // 現在のマウス座標を求めるcoords関数(1)
      var coords = function(e) {
        var r = e.target.getBoundingClientRect();
        return { x: e.clientX - r.left, y: e.clientY - r.top};
      };
 
      // キャンバスでマウスボタンが押下された場合の処理(2)
      cv.addEventListener('mousedown', function(e) {
        // マウスボタンが押された(フラグをオン)
        flag = true;
        // 現在のマウス位置を変数o_x、o_yに保存
        var cd = coords(e);
        o_x = cd.x;
        o_y = cd.y;
      }, false);
 
      // キャンバスでマウスボタンが離された場合の処理(3)
      cv.addEventListener('mouseup', function(e) {
        // マウスボタンを離した(フラグをオフ)
        flag = false;
      }, false);
 
      // キャンバスでマウスポインタが移動した時の処理(4)
      cv.addEventListener('mousemove', function(e) {
        // マウスボタンが押されている場合のみ処理
        if (flag) {
          // 現在の座標を変数x, yに設定
          var cd = coords(e);
          x = cd.x;
          y = cd.y;
          // (o_x, o_y)~(x, y)の直線を描画
          c.beginPath();
          c.moveTo(o_x, o_y);
          c.lineTo(x, y);
          c.stroke();
          // 現在の作業を変数o_x、o_yに退避
          o_x = x;
          o_y = y;
        }
      }, false);
    }
  }
);
図7:マウス操作に合わせてキャンバス上に曲線を描画(クリックで拡大)

マウス操作に合わせて曲線を描画するには、以下のようなしくみを準備しています。

  • (a)マウスボタン押下時に現在の座標を記録
  • (b)マウスポインタ移動時に、(a)で記録した基点から現在の座標位置まで直線を描画
  • (c)さらに移動したら、(b)の位置から現在位置まで直線を描画
  • (d)(b)~(c)を繰り返す

要は、内部的には細かな直線の集合として、疑似的に曲線を表現しているわけです。これを念頭に、サンプルの細かなコードを追っていきます。

まず、マウスボタンを押した時の処理です(2)。この時の座標を変数o_x、o_yに記録しておきます。変数flagは、マウスボタンが押された状態であるかを管理するためのフラグです。マウスボタンが押された時にフラグをオン(true)とし、離した時にオフ(false)とすることで(3)、「マウスボタンが押されている時だけ曲線を描画」できるようになります。こうしたフラグ管理をしていないと、マウスボタンを離した状態でポインタを動かしただけでも、キャンバスに曲線が描かれてしまうので要注意です。

なお、現在のマウス座標を取得する際には、やや注意が必要です。というのも、イベントオブジェクトeのclientX、clientYプロパティで取得できるのは、ページ左上からの座標なので、キャンバスの上/左余白の分だけ座標がずれてしまうのです。そこでキャンバスの左上の座標を取得するのが、e.target.getBoundingClientRectメソッドです。戻り値はオブジェクトで、X座標をleftプロパティ、Y座標をtopプロパティで取得できます。

この値をそれぞれclientX/clientYプロパティから差し引くことで、キャンバス上の正しいマウス座標を取得できるのです。この計算は典型的ですので、サンプルでもcoords関数として設定しています(1)。

そして、(4)が実際に曲線を描画する実処理です。ifブロックでflagのオンオフをチェックし、オンの場合のみ元の座標(o_x, o_y)から現在の座標(x, y)まで直線を描画します。描画のあとは、続けて次の直線をひくために、変数o_x、o_yに現在の座標をセットしておきます。

TIPS 033:キャンバス上の図形をData URL形式で保存する

キャンバスで描画した図形はData URLという形式に変換することで、ファイルやデータベースに保存したり、要素で表示したりすることが可能になります。

例えば、以下はTIPS 032で作成した落書き帳の内容をData URL形式に変換し、タグで再描画する例です。

[リスト06]落書き帳の内容を保存するコード(pointer.html)

window.addEventListener('DOMContentLoaded',
  function() {
    if (HTMLCanvasElement) {
      ...中略...
      // [コピー]ボタンクリック時の処理を定義
      document.querySelector('#save').addEventListener('click', function(e) {
  
        // キャンバスの内容をもとに画像を生成
        var img = new Image();
        img.src = cv.toDataURL();  // Data URL形式の取得(1)
        // 画像が生成できたら、ページ末尾にImageオブジェクトを貼り付け
        img.addEventListener('load', function(e) {
          document.body.appendChild(img);
        });
      }, false);
    }
  }
);
...中略...
<canvas id="cv" width="400" height="300">
Canvas機能に対応したブラウザでアクセスしてください。
</canvas>
<input id="save" type="button" value="コピー" />
図8:[コピー]ボタンをクリックすると、キャンバスの下に同じ画像が表示(クリックで拡大)

Data URL形式とは、URLに直接、画像や音声などのデータを埋め込むための表現で、一般的には以下のように表せます。

data:コンテンツタイプ;base64,データ本体

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAYAAADtt+...

Data URL形式のデータは、要素のsrc属性、要素のhref属性にそのまま埋め込むことができますので、データをいちいちファイルに落とし込む必要がないのが特長です。

キャンバス上の図形をData URL形式に変換するには、toDataURLメソッドを呼び出すだけです(1)。取得したData URL形式のデータは、そのままImageオブジェクトのsrcプロパティにセットし、ページに追加できます。

サンプルを実行し、ページ下の画像がブラウザの保存機能で画像ファイルとしても保存できることを確認してみましょう。

  • Canvas APIを使ってブラウザに図形を描画するサンプル(3)

著者
山田 祥寛(YAMADA, Yoshihiro)
WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表:山田祥寛)。おもな活動は、Web開発分野の書籍/雑誌/Web記事の執筆。ほかに海外記事の翻訳、講演なども幅広く手がける。2011年3月時点での登録メンバは36名で、現在もプロジェクトメンバーを募集中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています