お絵描き①(フリー描画)

概  要

HTML5 CANVASを使う(①~④)でCANVASを使いましたが、今回はマウス操作でCANVAS上にお絵描きする検討をしてみたいと思います。先回までの投稿ではjQuery Sortableを用いて写真リストの並べ替え等を検討しましたが、写真に直接ちょっとしたコメントを加えて保存出来たら更に良いかな(?)と考えました。
CANVASの使い方、マウスイベント取得,描画など、過去の投稿と重複しますが、ほとんど忘れてしまっているので、復習も兼ねて改めて勉強したいと思います。

マウス  お絵描きツール

今回、テスト的に作成したプログラムは下の図の様にマウス操作で、CANVAS上にお絵描きするツールです。
(→テストプログラムにリンク
最上段に画面を初期化する「消去」ボタン、2段目に左から順番に、色選択ボタン,透明度・線太さ設定用の入力エリアがあります。これらの条件設定後、マウス左ボタンを押した状態で移動することによって描画を行います。直線を補間し、描画しているので、前の直線の終点と次の直線の始点が同じ位置になり、透明色を使うと重なった部分の色が通常より濃くなってしまいます。

プログラム概要

プログラムについてメモしておきます。
(→テストプログラムにリンク
行番95の“onLoad”で、関数 “draw_begin()”(行番20~31)を指定し、ページ読み込み後、最初に実行します。行番21~26では、CANVASのデバイスコンテキスト取得、初期化を行います。行番28~30では、addEventListener を設定し、今回使用するCANVAS上で発生するマウス関連イベントを検知し、関数を実行できる様にしています。
今回、マウスの右ボタンを押した時に発生する”mousedown”イベント,マウス移動で連続的に発生する”mousemove”イベント,マウス右ボタンを離した時に発生する”mouseup”イベントの3つのマウス操作を使用します。
先ず描画の最初は、”mousedown”イベント発生時に関数(”mouse_dn”(行番34~48))を実行します。この関数では行番37~40でCANVAS上のマウス現在位置を描画開始位置として取得し、描画開始を示す“f_b ”を“true”に設定します。行番42~44では、設定された透明度,線の色,線の太さを取得し、行番46で描画に反映される様にします。
次に”mousemove”イベントで実際に描画を行います。描画開始を示す“f_b ” が  “true” の時に行番53~58を実行します。行番53~55では、マウスの現在座標を取得します。次に関数“draw_line()”(行番69~74)を呼び出し、前座標(始点)と現在座標間の直線を描画します。描画後、行番58では現在座標を前座標変数に格納し、次の描画の始点とします。この様に”mousemove”イベント発生のタイミングで連続的に描画を繰り返すことでお絵かきを実現します。
最後に”mouseup”イベント発生時に“f_b ” を “false” に設定し、一連の描画を終了します。
線の色変更について説明します。行番102~111で各色に対応するINPUTボタンを配置し、ボタンがクリックされると、chng_col()関数(行番87~90)を呼び出し、デバイスコンテキストの“strokeStyle”属性の値を設定します。設定した値が判る様に行番89で透明度・線太さ設定用の入力エリアの背景色を変更しています。INPUTタグのtype属性を “color” にするとgoogle chrome ではカラーパレットから色選択できる様になるのですが、IE11では動かない様です。他にもライブラリを少し調べましたが、全般に高機能です。とりあえずシンプルにしたかったので、今回の方式にしています。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>DRAWING TEST</title>

    <style>
	input { height:30px; }
	#select-color input { width:26px; height:36px; }
    </style>

    <script>

	var cvs_drw ; var ctx_drw ;
	var cvs_wdt ; var cvs_hgt ;
	var x_b , y_b , x_c , y_c ;
	var f_b ;

	function draw_begin(){
	    cvs_wdt = 600 ; cvs_hgt = 450 ;
	    cvs_drw = document.getElementById("CANVAS_DRW") ; 
	    ctx_drw = cvs_drw.getContext("2d") ;
	    
	    cvs_drw.width = cvs_wdt ; cvs_drw.height = cvs_hgt ;
	    cvs_drw_init() ;

	    cvs_drw.addEventListener( "mousedown" , mouse_dn , false ) ;
	    cvs_drw.addEventListener( "mousemove" , mouse_mv , false ) ;
	    cvs_drw.addEventListener( "mouseup", mouse_up , false ) ;
	}

	//▼▼▼▼▼▼ マウス検知 ▼▼▼▼▼▼
	function mouse_dn(event){
	    var l_thkn = 1 ; var t_rate = 1 ; var l_colr = "#333333" ;

	    var rect = event.target.getBoundingClientRect() ;
	    x_b = event.clientX-rect.left ;
	    y_b = event.clientY-rect.top ;
	    f_b = true ;

	    t_rate = document.getElementById("s_transparency").value/100 ;
	    l_colr = document.getElementById("select-color").style.backgroundColor ;
	    l_thkn = document.getElementById("l_thickness").value ;

	    ctx_drw.globalAlpha = t_rate ; ctx_drw.strokeStyle = l_colr ; ctx_drw.lineWidth = l_thkn ;
	    ctx_drw.lineJoin = "round" ; ctx_drw.lineCap = "round" ;
	}


	function mouse_mv(event){
	    if(f_b){
		var rect = event.target.getBoundingClientRect() ;
		x_c = event.clientX-rect.left ;
		y_c = event.clientY-rect.top ;

		draw_line() ;
		x_b = x_c ; y_b = y_c ;
	    }
	}

	function mouse_up(event){ 
	    f_b=false;
	}
	//▲▲▲▲▲▲ マウス検知 ▲▲▲▲▲▲


	// 自由線を引く
	function draw_line(){
	    ctx_drw.beginPath() ;
	    ctx_drw.moveTo(x_b,y_b) ;
	    ctx_drw.lineTo(x_c,y_c) ;
	    ctx_drw.stroke() ;
	}

	// 描画 CANVAS 初期化
	function cvs_drw_init(){
	    ctx_drw.globalAlpha = 1 ; 
	    ctx_drw.lineWidth = 1 ;
	    chng_col("#000000") ;

	    ctx_drw.clearRect( 0 , 0 , cvs_wdt , cvs_hgt ) ;
	    ctx_drw.strokeRect( 0 , 0 , cvs_wdt , cvs_hgt ) ;
	}

	// 描画色変更
	function chng_col(gColor){ 
	    ctx_drw.strokeStyle = gColor ;
	    document.getElementById("select-color").style.backgroundColor = gColor ;
	}

    </script>
</head>

<body onLoad="draw_begin()">
    <TABLE><TR>
    <TD><input type="button" value="消去" id="ClearCVS" onclick="cvs_drw_init()"></TD>
    </TR></TABLE>

    <TABLE><TR>
    <TD>
	<input type="button" style="background-color:#000000;" onclick="chng_col('#000000')">
	<input type="button" style="background-color:#008000;" onclick="chng_col('#008000')">
	<input type="button" style="background-color:#00ff00;" onclick="chng_col('#00ff00')">
	<input type="button" style="background-color:#0000ff;" onclick="chng_col('#0000ff')">
	<input type="button" style="background-color:#00ffff;" onclick="chng_col('#00ffff')">
	<input type="button" style="background-color:#fffacf;" onclick="chng_col('#fffacf')">
	<input type="button" style="background-color:#ffff00;" onclick="chng_col('#ffff00')">
	<input type="button" style="background-color:#ffa500;" onclick="chng_col('#ffa500')">
	<input type="button" style="background-color:#ff00ff;" onclick="chng_col('#ff00ff')">
	<input type="button" style="background-color:#ff0000;" onclick="chng_col('#ff0000')">
    </TD>
    <TD style="width:5px;"></TD>
    <TD id="select-color">
	<select id="s_transparency" style="height:28px; text-align:center; font-size:16px; margin:0 3px;">
	<option value="100">100</option><option value="80">80</option><option value="60">60</option>
	<option value="40">40</option><option value="20">20</option></select>

	<input type="number" id="l_thickness" min="1" max="500" value="3" style="height:23px; width:50px; text-align:center; font-size:16px; margin:0 3px;">
    </TD>
    </TR></TABLE>

    <div id="cvs-layer">
	<canvas id="CANVAS_DRW"></canvas>
    </div>

</body> 

</html>
今回のまとめ

INPUTタグのtype属性を “color” に設定しても、IE11で機能しないのは少し残念でした。少し前に“date”に設定しカレンダーを表示させようとした時もIE11では動かなかった記憶があります。最初にうまく動いたときに感動が大きい分、他のブラウザーで動かないことを知った時の落胆も大きいです。
気持ちを改めて次回は、矢印(→)、円(○)、長方形(□)などをマウス操作で追加する方法について検討したいと思っています。