課題7 Canvas

課題7-1

課題6に引き続き、今回もJavaScriptを使ったページを作る。今回は主に図形の描画に関わる命令を扱う。

  1. Terapadを起動する。
  2. 「表示」→「オプション」でタブの幅を4文字分にし、タブと空白文字を表示する設定に変更する。


  3. デスクトップに「課題7」フォルダーを作り、さらにその中に「1」フォルダーを作る。
  4. Terapadで「文字/改行コード指定保存」で、文字コードを「UTF-8N」にして、「1」フォルダーの中に「index.html」という名前で保存する。
  5. 以下のコードをコピー&ペーストして上書き保存する。
  6. <!DOCTYPE html>
    <html>
    <head>
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    	<link rel="stylesheet" type="text/css" href="main.css">
    	<script type="text/javascript" src="program.js"></script>
    	<title>課題7. Canvas</title>
    </head>
    <body onload="clearCanvas();">
    <span class="header">JavaScriptによる描画</span>
    <div class="main">
    	<canvas id="maincanvas" width="800" height="600"></canvas>
    	<br>
    	<input type="button" value="線" onClick="drawLines(1);">
    	<input type="button" value="折れ線2本" onClick="drawLines(2);">
    	<input type="button" value="折れ線3本" onClick="drawLines(3);">
    	<input type="button" value="長方形" onClick="drawRect();">
    	<input type="button" value="グラデーション長方形" onClick="drawGradientRect();">
    	<input type="button" value="円" onClick="drawCircle();">
    	<input type="button" value="グラデーション円" onClick="drawGradientCircle();">
    	<input type="button" value="クリア" onClick="clearCanvas();">
    </div>
    </body>
    </html>

  7. 「ファイル」→「新規作成」でもう一枚TeraPadを開く。
  8. 「文字/改行コード指定保存」で、文字コードを「UTF-8N」にして、「1」フォルダーの中に「main.css」という名前で保存する。


  9. 以下のコードをコピー&ペーストして上書き保存する。
  10. /* 画像とキャンバス */
    img, canvas {
    	max-width: 100%; /* 最大幅をブラウザの幅にする */
    }
    /* 見出し用 */
    .header {
    	font-size: 2.0em;/* 2倍サイズ */
    	font-weight: bold;/* 太字 */
    }
    /* 本文用字下げ */
    div.main {
    	margin-left: 10px;/* 左をあける */
    }

  11. 「文字/改行コード指定保存」で、文字コードを「UTF-8N」にして、「1」フォルダーの中に「program.js」という名前で保存する。


  12. 以下のコードをコピー&ペーストして上書き保存する。
  13. var canvas;
    var ctx;
    
    /* キャンバスをクリアする */
    function clearCanvas() {
    	canvas = document.getElementById("maincanvas"); /* html側の描画対象取得 */
    	if (canvas.getContext){ /* 取得に成功したら */
    		ctx = canvas.getContext('2d');
    		ctx.fillStyle = "gray"; /* 描画色を灰色にする */
    		ctx.fillRect(0, 0, canvas.width, canvas.height);
    	}
    }
    
    /* ランダムな色を返す */
    function getRandomColor(){
    	var r = parseInt(Math.random() * 256);
    	var g = parseInt(Math.random() * 256);
    	var b = parseInt(Math.random() * 256);
    	return "rgb(" + r +"," + g + "," + b +")";
    }
    
    /* n本連続したランダムな線を描く */
    function drawLines(n) {
    }
    
    /* ランダムな位置に長方形を描く */
    function drawRect() {
    }
    
    /* ランダムな位置にグラデーションがかかった長方形を描く */
    function drawGradientRect() {
    }
    
    /* ランダムな位置に円を描く */
    function drawCircle() {
    }
    
    /* ランダムな位置にグラデーションがかかった円を描く */
    function drawGradientCircle() {
    }
    このように「1」フォルダに3つのファイルができていて、TeraPadも3枚開いていればOK。

  14. index.htmlをFireFoxで開くと、以下のようなものが表示される。
  15. (ブラウザの横幅を小さくすると、キャンバス (灰色のエリア) はそれに合わせて小さくなる。これは main.css の2行目を「img, canvas」としたため。画像と同様にキャンバスの最大幅がブラウザに納まるようになっている)
    (表示がこうなっていることを確認したら main.css は閉じておく)
    (今後変更を加えるのは program.js だけ。index.html はブラウザ更新用にだけ使う)
    index.html の13行目に、800x600のキャンバスをつくる命令が書かれている。
    index.html の10行目を「<body onload="clearCanvas();">」としたことで、このページを読み込んだときに自動的にclearCanvas関数が実行される。
    program.jsにあるこの関数では、キャンバス全体を灰色で塗りつぶす命令が実行される。

    getRandomColorはこの時点では未使用の、ランダムな色を返す関数。
    下のボタンを押したときに実行される関数は program.jsに記述されているが、この時点ではどれも空っぽなので、クリックしても何も起きない。

  16. program.js の drawLines関数の中に以下のコードを追加して上書きしてからブラウザを更新し、「線」「折れ線2本」「折れ線3本」を押して図のようになることを確認する (「クリア」ですべての線が消える)。
  17. 	ctx.strokeStyle = getRandomColor(); /* 線の色をランダムにする */
    	ctx.lineWidth = 5; /* 線の太さを5ピクセルにする */
    	var x = Math.random() * canvas.width;  /* 始点の横位置 */
    	var y = Math.random() * canvas.height; /* 始点の縦位置 */
    	ctx.beginPath(); /* 描画開始 */
    	ctx.moveTo(x, y); /* 始点に移動 */
    	for (var i=0; i<n; i++){
    		x = Math.random() * canvas.width;  /* 次の点の横位置 */
    		y = Math.random() * canvas.height; /* 次の点の縦位置 */
    		ctx.lineTo(x, y); /* 次の点まで線を描く */
    	}
    	ctx.stroke(); /* 線描画確定 */
    「線」「折れ線2本」「折れ線3本」では、それぞれこの関数の引数 n に 1, 2, 3の値を渡して呼び出している。
    Processingとは異なり、関数の引数には型は書かない (Processingなら、例えば「void drawLines(int n){・・・}」のようになる)。

    beginPath, moveTo, lineTo, stroke の意味はコメント文の通り。
    for文でこれを n回繰り返すことで、n本の折れ線を描いている。

  18. program.js の drawRect関数の中に以下のコードを追加して上書きしてからブラウザを更新し、「長方形」を押して図のようになることを確認する。
  19. 	var x1 = Math.random() * canvas.width;  /* 頂点1の横位置 */
    	var y1 = Math.random() * canvas.height; /* 頂点1の縦位置 */
    	var x2 = Math.random() * canvas.width;  /* 頂点2の横位置 */
    	var y2 = Math.random() * canvas.height; /* 頂点2の縦位置 */
    	ctx.strokeStyle = "black"; /* 線の色を黒にする */
    	ctx.lineWidth = 5; /* 線の太さを5ピクセルにする */
    	ctx.beginPath(); /* 描画開始 */
    	ctx.rect(x1, y1, x2-x1, y2-y1); /* 長方形を描画 */
    	ctx.stroke(); /* 線描画確定 */
    	ctx.fillStyle = getRandomColor(); /* 塗りつぶし色をランダムにする */
    	ctx.fill(); /* 中を塗りつぶす */
    「rect」で四角形の枠を表示している。第1, 第2引数が一つの頂点の座標、第3, 第4引数が幅・高さの指定。第3, 第4引数をこのようにすることで、(x1, y1), (x2, y2) を対角線の頂点とする長方形になる。
    最後に「fill」を実行することで中を塗りつぶしている。

    ここでは枠描画と塗りつぶしを別々に行ったが、「fillRect」を使えばこれを同時に行うこともできる。

  20. program.js の drawGradientRect関数の中に以下のコードを追加して上書きしてからブラウザを更新し、「グラデーション長方形」を押して図のようになることを確認する。
  21. 	var x1 = Math.random() * canvas.width;  /* 頂点1の横位置 */
    	var y1 = Math.random() * canvas.height; /* 頂点1の縦位置 */
    	var x2 = Math.random() * canvas.width;  /* 頂点2の横位置 */
    	var y2 = Math.random() * canvas.height; /* 頂点2の縦位置 */
    	ctx.strokeStyle = "black"; /* 線の色を黒にする */
    	ctx.lineWidth = 5; /* 線の太さを5ピクセルにする */
    	ctx.beginPath(); /* 描画開始 */
    	ctx.rect(x1, y1, x2-x1, y2-y1); /* 長方形を描画 */
    	ctx.stroke(); /* 線描画確定 */
    	var g = ctx.createLinearGradient(x1, y1, x2, y2); /* グラデーションの始点と終点を指定 */
    	g.addColorStop(0, getRandomColor()); /* 始点の色指定 */
    	g.addColorStop(1, getRandomColor()); /* 終点の色指定 */
    	ctx.fillStyle = g; /* グラデーション設定 */
    	ctx.fill(); /* 中を塗りつぶす */
    gifアニメ画像の性質上色の境目の線が見えているが、実際はなめらかなグラデーションになる。

    「createLinearGradient」でグラデーションをかける位置の始点と終点を指定している。ここでは長方形の対角線上の頂点にしているが、別の場所にすることもできる。
    「addColorStop」で始点と終点の色を決めている。ここではこの2色を指定しているだけだが、たとえば「g.addColorStop(0.5, 別の色);」のようにすれば、頂点から中間、中間から別の頂点のように順に色が変わっていくようにすることもできる。

  22. program.js の drawCircle関数の中に以下のコードを追加して上書きしてからブラウザを更新し、「円」を押して図のようになることを確認する。
  23. 	var x = Math.random() * canvas.width;  /* 中心の横位置 */
    	var y = Math.random() * canvas.height; /* 中心の縦位置 */
    	var r = Math.random() * canvas.height/2; /* 半径 */
    	ctx.strokeStyle = "black"; /* 線の色を黒にする */
    	ctx.lineWidth = 5; /* 線の太さを5ピクセルにする */
    	ctx.beginPath(); /* 描画開始 */
    	ctx.arc(x, y, r, 0, Math.PI*2); /* 円を描画 */
    	ctx.stroke(); /* 線描画確定 */
    	ctx.fillStyle = getRandomColor(); /* 塗りつぶし色をランダムにする */
    	ctx.fill(); /* 中を塗りつぶす */
    
    「arc」で円を表示させている。「rect」と同様、こちらも円の枠を描いているだけ。塗りつぶしは最後の「fill」で行っている。

    引数は順に中心の横位置、中心の縦位置、半径、開始角度、終了角度を表わす。最後の2つの引数を0と2π、つまり360°にすることで円になる。
    これらを半端な値にすれば円弧になる。

  24. program.js の drawGradientCircle関数の中に以下のコードを追加して上書きしてからブラウザを更新し、「グラデーション円」を押して図のようになることを確認する。
  25. 	var x = Math.random() * canvas.width;  /* 中心の横位置 */
    	var y = Math.random() * canvas.height; /* 中心の縦位置 */
    	var r1 = Math.random() * canvas.height/4; /* 内側の円の半径 */
    	var r2 = r1+Math.random() * canvas.height/4; /* 外側の円の半径 */
    	ctx.strokeStyle = "black"; /* 線の色を黒にする */
    	ctx.lineWidth = 5; /* 線の太さを5ピクセルにする */
    	ctx.beginPath(); /* 描画開始 */
    	ctx.arc(x, y, r2, 0, Math.PI*2); /* 円を描画 */
    	ctx.stroke(); /* 線描画確定 */
    	var g = ctx.createRadialGradient(x, y, r1, x, y, r2); /* 円形のグラデーションの中心と半径を指定 */
    	g.addColorStop(0, getRandomColor()); /* 内側の円の色指定 */
    	g.addColorStop(1, getRandomColor()); /* 外側の円の色指定 */
    	ctx.fillStyle = g; /* グラデーション設定 */
    	ctx.fill(); /* 中を塗りつぶす */
    gifアニメ画像の性質上色の境目の線が見えているが、実際はなめらかなグラデーションになる。

    「createRadialGradient」でグラデーションをかける内側と外側の円の位置と半径を指定している。
    引数は順に内側の円の中心の横位置、縦位置、半径、外側の円の中心の横位置、縦位置、半径を表わす。
    ここでは中心を同じにしているが、別の位置にすることもできる。

    「addColorStop」で内側と外側の円の円周の位置での色を決めている。
    直線的なグラデーションのときと同様、0と1の間のところでの色を指定すれば、複雑な色の変わり方をさせることもできる。

課題7-2

  1. 課題7-1の結果表示用のFireFoxのタブ、すべてのTeraPadを閉じる。
  2. 「課題7」フォルダの中に「2」フォルダを作る。
  3. 「2」フォルダの中にindex.htmlファイルを作る (cssファイルや別のhtmlファイルを入れてもよい)。
  4. それらのファイルを編集し、オリジナルのページを作る。

課題の条件
注意 (この課題限定ではなく、Webページ全般について)
以下に例を挙げるが、これらはあくまで参考用。全く同じものはNG。

例1 (main.cssは課題7-1と同じ)
index.html
(10行目で、ページ読み込み時に自動的にdrawFlags関数が実行されるようにしているため、ボタンは配置していない)
(どちらの国旗も公式で横・縦の比が3:2なので、キャンバスのサイズもそれに合わせてある)


program.js
(関数がこれしかないので、課題7-1では先頭にあったcanvas, ctxは関数の中で宣言している)




例2 (main.cssは課題7-1と同じ)
index.html
(selectタグで囲んだものの中にoptionタグで囲んだ選択肢を書いてセレクトボックスを作っている)
(16行目に「selected」を入れることで、ページ読み込み時にこの項目「三角形」が選ばれた状態になる)
(セレクトボックスで何かを選び直すと、onchangeプロパティに入れた関数が実行される)


program.js
(多角形の頂点の座標 (x, y) を三角関数で計算し、lineToでつないでいる)
(29行目のclosePathを実行することで、終点と始点をつなぐ線が描かれる)




例3 (main.cssは課題7-1と同じ)
index.html
(10行目で、ページ読み込み時に自動的にdrawFlag関数が実行されるようにしているため、ボタンは配置していない)
(星条旗の縦横比は10:19なので、キャンバスのサイズをそれに合わせている)


program.js
(例2のdrawPolygon関数をちょっと変えて星を描く関数drawStarを作っている。五角形との違いは41, 42行目に「*2」があること。これのおかげで頂点を1つずつ飛ばすので星形になる)
(drawFlag関数では白の塗りつぶしのあと、赤い横線、左上の青い長方形を描いて、for文で位置をずらしながらdrawStar関数を呼び出している)


提出

inserted by FC2 system