JavaScript プログラミング講座

 

キャンバスについて

 


■キャンバスについて


<CANVAS> タグを使用すると、キャンバスを表示することができます。
 
キャンバス内では、任意の描画が可能です。
 
<CANVAS> タグを使用してインラインフレームを設置する

<html>
  <body>

    <canvas width="640" height="480" >
    	対応していません。
    </canvas>

  </body>
</html>
 

■ HTMLCanvasElement インターフェースについて

 
<CANVAS> タグに相当します。
 
エレメントの一種です。
 
■ HTMLCanvasElement インターフェースの派生について
 
Object
↓派生
EventTarget
↓派生
Node
↓派生
Element
↓派生
HTMLElement
↓派生
HTMLCanvasElement
 


 

キャンバスを作成する

 
 


■キャンバスを作成する

 
■ HTMLCanvasElement オブジェクトを作成する
 
document.createElement() メソッドを使用します。
 
引数に、"canvas" を指定します。
 
動的に HTMLCanvasElement オブジェクトを作成する

// HTMLCanvasElement オブジェクトを作成する
var canvas = document.createElement("canvas");

// 出力テスト
console.log(canvas);
 

■キャンバスをブラウザに表示する

 
■ HTMLCanvasElement オブジェクトを、ブラウザに表示する
 
 
キャンバスを動的に作成して、ノードリストに登録する

// HTMLCanvasElement オブジェクトを作成する
var canvas = document.createElement("canvas");

// BODY のノードリストに登録する
document.body.appendChild(canvas);
 

■HTMLCanvasElement オブジェクトを取得する

 
■静的な <CANVAS> タグから取得する
 
任意のエレメントを取得する方法は、こちらで解説しています。
 
静的な <CANVAS> タグから、HTMLCanvasElement オブジェクトを取得する

<html>
  <body>

    <canvas id="aaa" width="640" height="480" ></canvas>

    <script type="text/javascript">
    <!--
	// "aaa" という ID 属性のエレメントを取得する
	var canvas = document.getElementById("aaa");

	// 出力テスト
	console.log(canvas);

    //-->
    </script>

  </body>
</html>
 


 

キャンバスのサイズを設定する

 
 


■キャンバスのサイズについて

 
キャンバスは、1枚のビットマップ領域を保有しています。
 
ビットマップ領域には、任意の描画が可能です。
 
キャンバスのサイズは、後から変更できます。
 
変更した場合、ビットマップ領域はクリアされます。
 
キャンバスのサイズと、スタイルシートのサイズは異なります。
 
<IMG> 要素のように、拡大縮小して表示する事ができます。
 
常に等倍で表示される訳ではありません。
 

■キャンバスのサイズを設定する

 
以下のプロパティを使用します。
 
プロパティ名説明
widthNumberキャンバスの幅を設定する(単位:ピクセル)
heightNumberキャンバスの高さを設定する(単位:ピクセル)
 
■設定例
 
キャンバスのサイズを変更する

// ------------------------------------------------------------
// HTMLCanvasElement オブジェクトを作成する
// ------------------------------------------------------------
var canvas = document.createElement("canvas");

// BODY のノードリストに登録する
document.body.appendChild(canvas);

// ------------------------------------------------------------
// キャンバスのサイズを変更する
// ------------------------------------------------------------
canvas.width  = 320;
canvas.height = 240;

// ------------------------------------------------------------
// スタイルシートのサイズを変更する
// ------------------------------------------------------------
// CSSStyleSheet オブジェクトを取得する
var style = canvas.style;

// スタイルシートのサイズを変更する
style.width  = (640) + "px";
style.height = (480) + "px";
 

■ブラウザのリサイズを監視する

 
onresize イベントを使用します。
 
■使用例
 
キャンバスのサイズを等倍に補正する例です。
 
キャンバスのサイズを等倍に補正する

<html>
  <body>

    <canvas id="aaa" width="640" height="480" style="width:100%; height:100%;" ></canvas>

    <script type="text/javascript">
    <!--

	// ------------------------------------------------------------
	// キャンバスのサイズを等倍に補正する関数
	// ------------------------------------------------------------
	function CanvasResizeToSame(canvas){
		var style = canvas.ownerDocument.defaultView.getComputedStyle(canvas,"");
		canvas.width  = Math.round(parseFloat(style.width ));
		canvas.height = Math.round(parseFloat(style.height));
	}

	// ------------------------------------------------------------
	// "aaa" という ID 属性のエレメントを取得する
	// ------------------------------------------------------------
	var canvas = document.getElementById("aaa");

	// ------------------------------------------------------------
	// CanvasRenderingContext2D オブジェクトを取得する
	// ------------------------------------------------------------
	var context = canvas.getContext("2d");

	// ------------------------------------------------------------
	// リサイズされるたびに実行されるイベント
	// ------------------------------------------------------------
	window.onresize = function (){

		var x;
		var y;
		var w;
		var h;

		// ------------------------------------------------------------
		// キャンバスのサイズを等倍に補正する
		// ------------------------------------------------------------
		CanvasResizeToSame(canvas);

		// ------------------------------------------------------------
		// クリア
		// ------------------------------------------------------------
		w = canvas.width;
		h = canvas.height;
		context.clearRect( 0 , 0 , w , h );

		// ------------------------------------------------------------
		// グリッドを描画する
		// ------------------------------------------------------------
		// 描画パスをクリア
		context.beginPath();

		for(x=0.5;x < w;x+=3){
			// サブパスを開始(開始位置)
			context.moveTo(x , 0);
			// サブパスを追加(直線追加)
			context.lineTo(x , h);
		}

		for(y=0.5;y < h;y+=3){
			// サブパスを開始(開始位置)
			context.moveTo(0 , y);
			// サブパスを追加(直線追加)
			context.lineTo(w , y);
		}

		// 累積された描画パスを使って、実際に線を描画する
		context.stroke();
	};

	// 1回実行
	window.onresize();

    //-->
    </script>

  </body>
</html>
 


 

キャンバスに描画する

 


■キャンバスに描画する

 
キャンバスには、描画を行うための機能はありません。
 
別途、RenderingContext オブジェクトが必要です。
 
■ RenderingContext オブジェクトを取得する
 
getContext() メソッドを使用します。
 
HTMLCanvasElement.getContext ( "contextId" ) :*
第01引数 StringcontextId を指定。
戻り値 *第01引数に該当する Context オブジェクトが得られる
 
■第01引数(contextId)
 
以下の種類があります。
 
使い方については、リンク先で解説しています。
 
サポートしていない場合、戻り値は null となります。
 
第01引数戻り値の型説明
"2d"CanvasRenderingContext2D2D 用の描画 API(Canvas 2D Context)
"webgl"WebGLRenderingContext3D 用の描画 API(WebGL)
 
■Canvas 2D Context の取得例
 
CanvasRenderingContext2D オブジェクトを取得して、描画する

// ------------------------------------------------------------
// HTMLCanvasElement オブジェクトを作成する
// ------------------------------------------------------------
var canvas = document.createElement("canvas");

// BODY のノードリストに登録する
document.body.appendChild(canvas);

// ------------------------------------------------------------
// CanvasRenderingContext2D オブジェクトを取得する
// ------------------------------------------------------------
var context = canvas.getContext("2d");

// ------------------------------------------------------------
// 線の描画スタイルを設定する
// ------------------------------------------------------------
// 線の塗りを設定する(単一色)
context.strokeStyle = "#aa0000";

// 線の太さを設定する
context.lineWidth = 10.0;

// ------------------------------------------------------------
// 面の描画スタイルを設定する
// ------------------------------------------------------------
// 面の塗りを設定する(単一色)
context.fillStyle = "#ff8888";

// ------------------------------------------------------------
// 描画パスをクリア
// ------------------------------------------------------------
context.beginPath();

// ------------------------------------------------------------
// 描画パスを追加
// ------------------------------------------------------------
// 矩形追加
context.rect(  10 ,  10 , 120 , 100 );
// 矩形追加
context.rect(  50 ,  30 , 120 , 100 );

// ------------------------------------------------------------
// 累積された描画パスを使って、実際に描画
// ------------------------------------------------------------
// 面描画
context.fill();
// 線描画
context.stroke();
 


 

画像ファイルを出力する

 
 


■画像ファイルを出力する(Data URI Scheme 形式)

 
toDataURL() メソッドを使用します。
 
このメソッドは、同期実行です。
 
キャンバスが巨大であるほど、時間が掛かります。
 
HTMLCanvasElement.toDataURL ( "type" , ... ) :String
第01引数(略可)String出力時のコンテンツタイプを指定。
可変引数(略可)*オプション情報を指定。
戻り値 StringData URI Scheme 文字列が得られる。
 
■第01引数(コンテンツタイプ)
 
以下の種類があります。
 
デフォルトは、"image/png" です。
 
指定したタイプをサポートしていない場合、デフォルトの PNG 形式となります。
 
第01引数可変引数説明
"image/png"なしPNG 画像フォーマット
"image/jpeg"第02引数:品質(0.0 ~ 1.0)JPEG 画像フォーマット
 
■戻り値(Data URI Scheme)
 
Data URI Scheme 文字列が得られます。
 
Data URI Scheme については、こちらで解説しています。
 
■使用例
 
Data URI Scheme 文字列を出力する

<html>
  <body>

    <br>─── CANVAS ───<br>
    <canvas id="my_canvas" width="400" height="200" style="border:1px solid #000;" ></canvas> <br>

    <br>─── IMAGE ───<br>
    <img id="my_image" width="400" height="200" style="border:1px solid #000;" > <br>

    <input id="my_button" type="button" value="出力" > <br>

    <script type="text/javascript">
    <!--

	// ------------------------------------------------------------
	// 各エレメントを取得する
	// ------------------------------------------------------------
	var canvas = document.getElementById("my_canvas");
	var image  = document.getElementById("my_image");
	var button = document.getElementById("my_button");

	// ------------------------------------------------------------
	// CanvasRenderingContext2D オブジェクトを取得する
	// ------------------------------------------------------------
	var context = canvas.getContext("2d");

	// ------------------------------------------------------------
	// 線の描画スタイルを設定する
	// ------------------------------------------------------------
	// 線の色を設定する
	context.strokeStyle = "#0000aa";

	// 線の太さを設定する
	context.lineWidth = 10.0;

	// ------------------------------------------------------------
	// 面の描画スタイルを設定する
	// ------------------------------------------------------------
	// 面の色を設定する
	context.fillStyle = "#8888ff";

	// ------------------------------------------------------------
	// 円を描画
	// ------------------------------------------------------------
	context.beginPath();
	context.arc(  250 , 150 , 180 , 0 * (Math.PI / 180) , 360 * (Math.PI / 180) );
	context.fill();
	context.stroke();

	context.beginPath();
	context.arc( 100 , 100 , 80 , 0 * (Math.PI / 180) , 360 * (Math.PI / 180) );
	context.fill();
	context.stroke();

	// ------------------------------------------------------------
	// ボタンをクリックすると実行されるイベント
	// ------------------------------------------------------------
	button.onclick = function(){

		// ------------------------------------------------------------
		// Data URI Scheme 文字列を出力する
		// ------------------------------------------------------------
		var data_uri = canvas.toDataURL( "image/jpeg" , 1.0 );

		// 出力テスト
		console.log(data_uri);

		// ------------------------------------------------------------
		// イメージ要素にセットする
		// ------------------------------------------------------------
		image.src = data_uri;

	};

    //-->
    </script>

  </body>
</html>
 

■キャプチャのセキュリティについて

 
■生成元(オリジン)について
 
生成元(オリジン)とは、自身のリソースが格納されている場所です。
 
プロトコルドメインポート番号」の3つを合わせたものです。
 
 
■クロスオリジンデータについて
 
現在開いているページとは異なるオリジンに格納されているリソースを、クロスオリジンデータと言います。
 
■キャンバスの汚染について
 
画像やビデオなどのリソースは、テクスチャとして利用する事ができます。
 
クロスオリジンテータを使って描画した場合、キャンバスは汚染します。
 
origin-clean フラグが false に変化します。
 
クロスオリジンデータを、汚染を回避して利用する方法はありません。
 
また、汚染したキャンバスを、回復させる方法もありません。
 
■キャンバスが汚染した場合
 
キャプチャ処理を試みると、セキュリティエラーが発生して失敗します。
 


 

座標の相互変換について

 


■「クライアント座標」と「キャンバス座標」を相互変換する

 
マウスなどのクライアント座標を、キャンバスの座標系に変換します。
 
■「クライアント座標」から「キャンバス座標」に変換
 
「クライアント座標」から「キャンバス座標」に変換する関数

// ------------------------------------------------------------
// 「クライアント座標」から「キャンバス座標」に変換する関数
// ------------------------------------------------------------
function CanvasGetPositionFromClient(canvas,x,y){
	var d = canvas.ownerDocument;
	var w = d.defaultView;
	var r = canvas.getBoundingClientRect();
	var s = w.getComputedStyle(canvas,"");
	var px = parseFloat(s.paddingLeft);
	var py = parseFloat(s.paddingTop);
	var bx = parseFloat(s.borderLeftWidth);
	var by = parseFloat(s.borderTopWidth);
	var sx = canvas.width / parseFloat(s.width);
	var sy = canvas.height / parseFloat(s.height);
	return {
		x:(x - bx - px - r.left) * (sx),
		y:(y - by - py - r.top ) * (sy)
	};
}
 
■「キャンバス座標」から「クライアント座標」に変換
 
「キャンバス座標」から「クライアント座標」に変換する関数

// ------------------------------------------------------------
// 「キャンバス座標」から「クライアント座標」に変換する関数
// ------------------------------------------------------------
function CanvasGetPositionToClient(canvas,x,y){
	var d = canvas.ownerDocument;
	var w = d.defaultView;
	var r = canvas.getBoundingClientRect();
	var s = w.getComputedStyle(canvas,"");
	var px = parseFloat(s.paddingLeft);
	var py = parseFloat(s.paddingTop);
	var bx = parseFloat(s.borderLeftWidth);
	var by = parseFloat(s.borderTopWidth);
	var sx = parseFloat(s.width) / canvas.width;
	var sy = parseFloat(s.height) / canvas.height;
	return {
		x:(x * sx) + (bx + px + r.left),
		y:(y * sy) + (by + py + r.top )
	};
}
 
■使用例
 
マウス座標を「キャンバス座標」に変換する

<html>
  <head>
    <style type="text/css">
    <!--
	#aaa {
		padding-left:0px;
		padding-top :0px;

		border:0px solid #000;
		border-left-width:0px;
		border-top-width :0px;

		margin-left:0px;
		margin-top :0px;

		background-color:#eee;
		width :100%;
		height:100%;
	}
    //-->
    </style>

  </head>
  <body>

    <canvas id="aaa" width="640" height="480" ></canvas>

    <script type="text/javascript">
    <!--

	// ------------------------------------------------------------
	// 「クライアント座標」から「キャンバス座標」に変換する関数
	// ------------------------------------------------------------
	function CanvasGetPositionFromClient(canvas,x,y){
		var d = canvas.ownerDocument;
		var w = d.defaultView;
		var r = canvas.getBoundingClientRect();
		var s = w.getComputedStyle(canvas,"");
		var px = parseFloat(s.paddingLeft);
		var py = parseFloat(s.paddingTop);
		var bx = parseFloat(s.borderLeftWidth);
		var by = parseFloat(s.borderTopWidth);
		var sx = canvas.width / parseFloat(s.width);
		var sy = canvas.height / parseFloat(s.height);
		return {
			x:(x - bx - px - r.left) * (sx),
			y:(y - by - py - r.top ) * (sy)
		};
	}

	// ------------------------------------------------------------
	// "aaa" という ID 属性のエレメントを取得する
	// ------------------------------------------------------------
	var canvas = document.getElementById("aaa");

	// ------------------------------------------------------------
	// CanvasRenderingContext2D オブジェクトを取得する
	// ------------------------------------------------------------
	var context = canvas.getContext("2d");

	// ------------------------------------------------------------
	// 線の描画スタイルを設定する
	// ------------------------------------------------------------
	// 線の太さを設定する
	context.lineWidth = 4.0;

	// ------------------------------------------------------------
	// マウスを移動するたびに実行されるイベント
	// ------------------------------------------------------------
	window.addEventListener( "mousemove" , function (e){

		// ------------------------------------------------------------
		// マウス座標をキャンバス座標系に変換する
		// ------------------------------------------------------------
		var pos = CanvasGetPositionFromClient(canvas , e.clientX , e.clientY);

		// 出力テスト
		console.log("x:" + pos.x + " y:" + pos.y);

		// ------------------------------------------------------------
		// クリア
		// ------------------------------------------------------------
		context.clearRect( 0 , 0 , canvas.width , canvas.height );

		// ------------------------------------------------------------
		// 十字カーソルを描画する
		// ------------------------------------------------------------
		// 描画パスをクリア
		context.beginPath();

		// サブパスを開始(開始位置)
		context.moveTo(pos.x - 10 , pos.y);
		// サブパスを追加(直線追加)
		context.lineTo(pos.x + 10 , pos.y);
		// サブパスを開始(開始位置)
		context.moveTo(pos.x , pos.y - 10);
		// サブパスを追加(直線追加)
		context.lineTo(pos.x , pos.y + 10);

		// 累積された描画パスを使って、実際に線を描画する
		context.stroke();
	});

    //-->
    </script>

  </body>
</html>