HTML5のcanvasを使ったお絵かきツール詳説

HTML5のcanvasを使ったお絵かきツール詳説

Posted at January 17,2012 1:55 AM
Tag:[canvas, HTML5, jQuery]

HTML5のcanvasを使ったお絵かきツールを勉強がてら作ってみました。下記の画像リンクをクリックすればサンプルページにジャンプします。

サンプル
Canvasサンプル

以下、サンプルのHTMLとJavaScript(jQuery)を使って、canvasのお絵かきツールについて解説します。

探しきれてないだけと思いますが、お絵かきツールのjQueryでの実装が見つからなかったので、自力で書いてみました。いろいろ間違ってたらすいません。

1.HTML

サンプルのHTMLは次のようになっています。

<canvas width="500" height="400">お使いのブラウザはHTML5のCanvas要素に対応していません。</canvas>
<ul>
<li style="background-color:#000"></li>
<li style="background-color:#f00"></li>
<li style="background-color:#0f0"></li>
<li style="background-color:#00f"></li>
<li style="background-color:#ff0"></li>
</ul>
<div id="button">
<input type="button" id="save" value="画像で保存" />
<input type="button" id="clear" value="消去" />
</div>

1行目のcanvas要素はブラウザ上に図を描くためのものです。width属性・height属性でcanvas要素のサイズを設定します。

canvas要素はフォールバック(問題発生時の代替手段)も考慮されており、HTML5のcanvas要素に対応していないブラウザなどでは要素のコンテンツを出力します。

そのあとにあるli要素は、Canvas上で色を変更するためのものです。また、input要素でcanvasに描画された内容の消去と保存を行えるようにしています。

2.JavaScript

とりあえず全体のコードです。jQueryで書いてますがjQueryの解説は割愛しますので、分からない方は他のサイトや書籍等で調べてください。

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
    var offset = 5;
    var startX;
    var startY;
    var flag = false;
    var canvas = $('canvas').get(0);
    if (canvas.getContext) {
        var context = canvas.getContext('2d');
    }
 
    $('canvas').mousedown(function(e) {
        flag = true;
        startX = e.pageX - $(this).offset().left - offset;
        startY = e.pageY - $(this).offset().top - offset;
        return false; // for chrome
    });
 
    $('canvas').mousemove(function(e) {
        if (flag) {
            var endX = e.pageX - $('canvas').offset().left - offset;
            var endY = e.pageY - $('canvas').offset().top - offset;
            context.lineWidth = 2;
            context.beginPath();
            context.moveTo(startX, startY);
            context.lineTo(endX, endY);
            context.stroke();
            context.closePath();
            startX = endX;
            startY = endY;
        }
    });
 
    $('canvas').on('mouseup', function() {
        flag = false;
    });
 
    $('canvas').on('mouseleave', function() {
        flag = false;
    });
 
    $('li').click(function() {
        context.strokeStyle = $(this).css('background-color');
    });
 
    $('#clear').click(function(e) {
        e.preventDefault();
        context.clearRect(0, 0, $('canvas').width(), $('canvas').height());
    });
 
    $('#save').click(function() {
        var d = canvas.toDataURL('image/png');
        d = d.replace('image/png', 'image/octet-stream');
        window.open(d, 'save');
    });
});
</script>

変数定義・初期化

最初に変数の定義と初期化を行います。

    var offset = 5;
    var startX;
    var startY;
    var flag = false;

offsetは、描画するときに描画線がマウスカーソルの左上になるようにするための補正値です。startX/startYは描画の開始位置、flagは描画要否を示すフラグです。

描画コンテキストの取得

HTML5のcanvas要素の描画コンテキストをgetElementById()の代わりにjQueryで取得する」でも紹介しましたが、以下の部分で「2D描画コンテキスト」を取得します。

    var canvas = $('canvas').get(0);
    if (canvas.getContext) {
        var context = canvas.getContext('2d');
    }

この部分はcanvasを利用するときのおまじないと思っておけばよいでしょう。

mousedownイベントでの動作

mousedownイベント(マウスボタンをクリック)で次の処理を行います。

    $('canvas').mousedown(function(e) {
        flag = true;
        startX = e.pageX - $(this).offset().left - offset;
        startY = e.pageY - $(this).offset().top - offset;
        return false; // for chrome
    });

flagに「true」を設定します。この値はマウスを動かしたときに利用します。startXにマウスをクリックしたカーソル位置のX座標、startYにY座標を設定します。

「pageX」は、ブラウザの左端からの位置(もっと厳格な定義があるかもしれません)、「offset().left」はブラウザの左端からcanvas要素の左端のオフセットです。例えば、「pageX」が200、「offset().left」が20であれば、X座標のカーソル位置は180になり、そこからさらに補正値のoffsetを減算します。

「return false;」は、Google chromeでcanvas上でmousedownした後カーソルが「cursor:text」の形状になってしまうので、それを回避するための設定です。

mousemoveイベントでの動作

mousemoveイベント(マウスをクリックした状態で移動)で次の処理を行います。

    $('canvas').mousemove(function(e) {
        if (flag) {
            var endX = e.pageX - $('canvas').offset().left - offset;
            var endY = e.pageY - $('canvas').offset().top - offset;
            context.lineWidth = 2;
            context.beginPath();
            context.moveTo(startX, startY);
            context.lineTo(endX, endY);
            context.stroke();
            startX = endX;
            startY = endY;
        }
    });

mousedownイベントで設定したflagを判定して、trueの場合のみ処理を続行します。これは、たとえばcanvasの外側からマウスをクリックした状態でcanvasに進入してきた場合に描画動作を行わないようにするためです。

endX/endYはさきほどのstartX/startYと同じです、マウスをクリックした位置よりも僅かでもマウスが動くとこのmousemoveが発動して、endX/endYを取得します。

次に、描画コンテキストに値を設定します。lineWidthは描画線の太さ、beginPath()は現在のパスをリセットします。

moveTo()で新しいサブパスの開始点を座標指定し、lineTo()で直前の座標と指定座標を結ぶ直線を引きます。stroke()は現在の線のスタイルでサブパスを輪郭表示するためのものです。さきほど設定したlineWidthがスタイルに該当します。

描画を終えたら次のmousemoveイベントに備えて、endX/endYの値をstartX/startYに設定します。

これで大体お分かりと思いますが、お絵かきツールは短い線の描画の集合ということです。

mousemoveイベント・mouseleaveイベントでの動作

mouseupイベント(マウスのクリックをやめたとき)またはmouseleaveイベント(マウスがcanvas要素からはずれたとき)で次の処理を行います。

    $('canvas').on('mouseup', function() {
        flag = false;
    });
 
    $('canvas').on('mouseleave', function() {
        flag = false;
    });

flagに「false」を設定して、その状態でcanvas要素上でマウスを動かしても描画されないようにします。

描画色の変更

次のコードで描画色の変更をできるようにします。

    $('li').click(function() {
        context.strokeStyle = $(this).css('background-color');
    });

li要素で用意した背景色の部分をクリックすることで、その色を描画コンテキストのstrokeStyleに設定します。strokeStyleは線や輪郭の色などを指定するためのものです。

canvasのクリア

id属性「clear」のinput要素のclickイベントを契機にcanvasのクリアを行います。

    $('#clear').click(function(e) {
        e.preventDefault();
        context.clearRect(0, 0, $('canvas').width(), $('canvas').height());
    });

preventDefaultはイベントのキャンセルを通知するメソッドです。clearRect()は、引数で指定したcanvas上の矩形のすべてのピクセルを背景色でクリアします。

canvasの描画を画像で保存

canvasの内容は画像で保存できるようです。id属性「save」のinput要素のclickイベントを契機に画像の保存を行います。

    $('#save').click(function() {
        var d = canvas.toDataURL('image/png');
        d = d.replace('image/png', 'image/octet-stream');
        window.open(d, 'save');
    });

toDataURL()は、canvasのイメージに対するdata:URLを返却(=ピクセルデータをBase64形式に変換)します。replace()でMIME形式の「image/png」を「image/octet-stream」に変換して、window.open()することでファイルとして出力できます。

保存したあとは、ファイル名に拡張子「.png」を付与してください。

3.参考サイト

参考サイトは下記です。ありがとうございました。

関連記事
zenback
人気エントリー
トラックバックURL


コメント

ホワイトのペンがあれば消しゴム替わりに使えて、お絵描きツールとして更に良かったかも、と思いました。

[1] Posted by 3K1 : January 17, 2012 8:09 PM

>3K1さん
こんばんは。
コメントありがとうございました。
サンプルに白を追加しました。

[2] Posted by yujiro logo : January 17, 2012 11:31 PM
コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)