こんにちは、橋本です。
今回はHTML5シリーズ第二弾ということで、canvasを使ってお絵かきしてみました。
今回は前編で、基本的な機能について触れてみたいと思います。
さっそくサンプルコードを以下に。
canvas_sample.html
<html lang="ja">
<head>
<meta charset="UTF-8">
<script src="js/canvas.js" type="text/javascript"></script>
<link media="all" rel="stylesheet" href="css/main.css" type="text/css" />
<title>canvas test</title>
</head>
<body>
<div id="container">
<div id="leftContainer" class="clearfix">
<canvas id="layer0" class="canvas" style="position: absolute; top: 0; left: 0; border: 10px solid #dddddd;" width="900px" height="600px"></canvas>
</div>
<div id="rightContainer">
<div id="controler">
<section id="color">
<ul>
<li>
<label for="red">R:</label>
<input id="red" class="colorBar" type="range" min="0" max="255">
</li>
<li>
<label for="green">G:</label>
<input id="green" class="colorBar" type="range" min="0" max="255">
</li>
<li>
<label for="blue">B:</label>
<input id="blue" class="colorBar" type="range" min="0" max="255">
</li>
<li>
<label for="alpha">A:</label>
<input id="alpha" class="colorBar" type="range" min="0" max="100">
</li>
<li>
<canvas id="colorSample" height="30px" width="30px"></canvas>
<input id="colorText" type="text" value="" readonly="true">
</li>
</ul>
</section>
<section id="line">
<ul>
<li>
<label for="lineWidthRange">line width:</label>
<input id="lineWidthRange" type="range" min="0" max="50">
</li>
<li>
<canvas id="lineSample" width="50" height="50"></canvas>
</li>
</ul>
</section>
<section id="other">
<ul>
<li>
<label for="erase">erase mode:</label>
<input id="erase" type="checkbox" />
</li>
</ul>
</section>
</div>
</div>
</div>
</body>
</html>
canvas.js
(function(){
var canvas,context = null;
var beforeX, beforeY = null;
var isDrawing = false;
var selectedColor;
var colorVars;
var colorText;
var colorSample;
var erase;
var restore;
var lineWidthRange;
var lineWidth;
var lineSample;
var isErase;
window.addEventListener("load", function (event){
canvas = document.getElementById("layer0");
context = canvas.getContext("2d");
erase = document.getElementById("erase");
restore = document.getElementById("restore");
lineWidthRange = document.getElementById("lineWidthRange");
// イベントリスナーの設定
canvas.addEventListener("mousemove", canvas_mouseMoveHandler, false);
canvas.addEventListener("mouseup", canvas_mouseUpHandler, false);
canvas.addEventListener("mousedown", canvas_mouseDownHandler, false);
canvas.addEventListener("mouseout", canvas_mouseOutHandler, false);
erase.addEventListener("click", erase_clickHandler, false);
lineWidthRange.addEventListener("change", lineWidthRange_changeHandler, false);
//controlerの設定
colorBars = document.getElementsByClassName("colorBar");
var obj = {};
length = colorBars.length;
for (var i = 0; i < length; i++)
{
var bar = colorBars[i];
bar.value = bar.id == "alpha" ? 100 : 0;
bar.addEventListener("change", colorBar_changeHandler, false);
obj[bar.id] = bar.value;
}
colorSample = document.getElementById("colorSample");
colorText = document.getElementById("colorText");
var colorStr = convertColorObjToStr(obj);
setColorText(colorStr);
setSelectedColor(colorStr);
setColorSample();
lineWidthRange.value = 10;
lineWidth = 10;
lineSample = document.getElementById("lineSample");
setLineSample();
}, false);
function convertColorObjToStr(obj)
{
return obj["red"] + ", " + obj["green"] + ", " + obj["blue"] + ", " + (obj["alpha"] / 100);
}
function setColorSample()
{
var context = colorSample.getContext("2d");
context.beginPath();
context.strokeStyle = selectedColor;
context.fillStyle = selectedColor;
context.fillRect(0, 0, colorSample.width, colorSample.height);
}
function setLineSample()
{
var context = lineSample.getContext("2d");
// 今の状態をリセット
context.clearRect(0, 0, lineSample.width, lineSample.height);
context.beginPath();
context.arc(lineSample.width / 2, lineSample.height / 2, lineWidth / 2, 0, Math.PI*2, false);
if (isErase)
{
context.strokeStyle = "rgba(0, 0, 0, 1)";
context.stroke();
}
else
{
context.strokeStyle = selectedColor;
context.fillStyle = selectedColor;
context.fill();
}
}
function setColorText(colorStr)
{
colorText.value = colorStr;
}
function setSelectedColor(colorStr)
{
selectedColor = "rgba(" + colorStr + ")";
}
function colorBar_changeHandler(event)
{
var obj = {};
length = colorBars.length;
for (var i = 0; i < length; i++)
{
var bar = colorBars[i];
obj[bar.id] = bar.value;
};
var colorStr = convertColorObjToStr(obj);
setColorText(colorStr);
setSelectedColor(colorStr);
setColorSample();
setLineSample();
}
function canvas_mouseOutHandler(event)
{
isDrawing = false;
}
function canvas_mouseDownHandler(event)
{
isDrawing = true;
beforeX = event.clientX - 10;
beforeY = event.clientY - 10;
}
function canvas_mouseUpHandler(event)
{
isDrawing = false;
}
function canvas_mouseMoveHandler(event)
{
if (!isDrawing)
{
return;
}
isErase ? eraseLine(event) : drawLine(event);
}
function drawLine(event)
{
var fixedX = event.clientX - 10;
var fixedY = event.clientY - 10;
context.beginPath();
context.strokeStyle = selectedColor;
context.lineWidth = lineWidth;
context.lineCap = 'round';
context.lineJoin = 'round';
context.moveTo(beforeX, beforeY);
context.lineTo(fixedX, fixedY);
context.stroke();
context.closePath();
beforeX = fixedX;
beforeY = fixedY;
}
function eraseLine(event)
{
var x = event.clientX - 10 - lineWidth / 2;
var y = event.clientY - 10 - lineWidth / 2;
context.clearRect(x, y, lineWidth, lineWidth);
}
function erase_clickHandler(event)
{
isErase = event.target.value;
setLineSample();
}
function lineWidthRange_changeHandler(event)
{
lineWidth = event.target.value;
setLineSample();
}
})();
*cssは略
JSのコードが結構汚いんですが、サンプルってことで華麗にスルーしていただけると幸いです。(次回までに綺麗にしておきます;)
実際のサンプルはこちら
まず、canvasで画像を描画する際には、対象のcanvasのcontextを取得します。
canvas = document.getElementById("layer0");
context = canvas.getContext("2d");
contextに対して処理を行うことで、画像を描画することが出来ます。
次に基本的な線を引く処理。
線を引くためには、以下の手順を踏みます。
// 1. 線を描きますよーと宣言
context.beginPath();
// 2. 線の設定(しなくてもOK)
context.strokeStyle = selectedColor; // 線の色
context.lineWidth = lineWidth; // 線の太さ
context.lineCap = 'round'; // 線の始点、終点の形
context.lineJoin = 'round'; // 線のつなぎ目の形
// 3. 線の始点を設定
context.moveTo(beforeX, beforeY);
// 4. 線の終点を設定
context.lineTo(fixedX, fixedY);
// 5. 線を描く
context.stroke();
// 6. 線が書き終わりましたよーという宣言
context.closePath();
線の各種設定については、以下のページに詳しく載ってるので参照してください。
HTML5.jp-Canvasリファレンス
今回のサンプルでは、連続した線を引くために、線を引き終わった座標を、beforeX, beforeYに格納し、次の線を描き始めるときの始点として指定しています。
次に四角形を描く処理。
四角形を描くためには、以下の手順を踏みます。
// 1.線を描きますよーの宣言
context.beginPath();
// 2. 設定
context.strokeStyle = selectedColor; // 線の色
context.fillStyle = selectedColor; // 塗りつぶしの色
// 3. 四角形を描く
context.fillRect(0, 0, colorSample.width, colorSample.height);
上記サンプルのfillRectは、塗りつぶした四角形を描くメソッドです。
引数は、書き始めるx座標、書き始めるy座標、四角形の幅、四角形の高さとなっています。
座標は、左上が(0, 0)です。これは、canvas全体共通です。
ちなみに、枠だけの四角形を描きたいときは、strokeRect()、四角形を消したいときは、clearRect()メソッドを使います。今回のサンプルでは、消しゴムを実装するために、clearRect()メソッドを使っています。
次は円を描く処理です。
円を描くためには以下の手順。
// 1. 例のやつ
context.beginPath();
// 2. 円の形を指定
context.arc(lineSample.width / 2, lineSample.height / 2, lineWidth / 2, 0, Math.PI*2, false);
// 3. オプションを指定
context.strokeStyle = selectedColor;
context.fillStyle = selectedColor;
// 4. 描く
context.fill();
まず、arc()メソッドを使って円の設定をします。
引数は、円の中心のx座標、円の中心のy座標、円の半径、円を書き始める角度、円を書き終える角度、円を描く向きとなっています。最後の引数の円を描く向きは、trueを指定すると、反時計回り、falseを指定すると、時計回りになります。
今回は普通の円なので、最後の指定はあまり意味がないのですが、一部が欠けている円を描きたい時には、向きが重要になってくると思います。
ちなみに、枠だけの円を描きたいときは、最後のfill()をstroke()に変更すればOKです。
今回はとりあえず、ここまで。
次回後編では、グラデーション、画像の取り込みなどについて触れていきたいと思います。