コンピューティング実習第3部(HTML+Javascript編)

社会情報学部

version 0.1

1 ボタンとJavascriptの連携 braproアイコン

第3部では初学者用Webページ開発環境(pikeplace - kenya)を使って,HTMLとJavascriptを使い,ブラウザで動くプログラムを作ることを学習します.

本章では,htmlとJavascriptの基本を学びます.

1.1 ボタンを作る braproアイコン

htmlを使ってボタンを作るには,buttonタグを使います.

<button>[ボタンのラベル]</button>

source c

result

<html>

<head>
</head>

<body>
    <button>A</button>
</body>

</html>

まだ,ボタンを押しても何も起こりません.

1.2 Javascriptを埋め込む braproアイコン

htmlにJavascriptプログラムを埋め込むには,scriptタグを使います. scriptタグの中にJavascriptのプログラムを書きます.

<html>

<head>
    <script>
        [Javascriptのプログラム]
    </script>
</head>

<body>
</body>

</html>

1.3 ボタンが押されたときにJavascriptプログラムを動かす braproアイコン

ボタンが押されたときにJavascriptプログラムを動かすようにするには,buttonタグの属性onclickに関数呼び出しのプログラムを書き,scriptタグの中で定義している関数を呼び出します.

<button onclick="a()">A</button>

scriptタグの中には,これまでタートルグラフィックス編で学習してきたJavascriptの構文が概ね利用できますが, タートルグラフィックスの専用命令で利用できないものもあります.利用できるものとできないものを下記にまとめました.

ここで,ボタンが押されたときにHello, world!と表示されるプログラムを作りたいのですが,タートルではないJavascriptでは,print()命令は使えません.代わりにこのプログラムでは,以下の2つの命令でメッセージを表示しています.

window.alert命令は,ダイアログにメッセージを出力します.

window.alert("メッセージ")

console.log(“メッセージ”)命令は,コンソールにメッセージを出力します.

console.log("メッセージ")

source c

result

<html>

<head>
    <script>
        function a() {
            window.alert('hello, world');
            console.log('こんにちは!');
        }
    </script>
</head>

<body>
    <button onclick="a()">A</button>
</body>

</html>

1.3.1 コンソールを表示する braproアイコン

console.log()命令で指定したメッセージを表示したり,エラーをみたりするには,ブラウザのコンソール機能を利用します.

コンソールを開くには,

1.4 ボタンを2つ作る braproアイコン

ボタンを2つ作ることもできます.異なる2つの機能を実現するために,2つの関数を用意して,2つのボタンそれぞれが機能に対応する関数を呼ぶように設計します.

source c

result

<html>

<head>
    <script>
        function a() {
            window.alert('A!');
        }
        function b() {
            window.alert('B!');
        }            
    </script>
</head>

<body>
    <button onclick="a()">A</button>
    <button onclick="b()">B</button>
</body>

</html>

1.5 乱数(おみくじ)braproアイコン

タートルグラフィックス編でも作成したおみくじを作ってみましょう.

タートルではないJavascriptでは,random()関数は使えません. 代わりに,Math.random()関数を使います. Math.random()関数は,0以上1未満の小数を生成し,戻り値として返します.

したがって,例えば0〜3までの数字を生成したければ

var x = Math.floor(Math.random() * 4)

1〜6までの数字を生成したければ

var x = Math.floor(Math.random() * 6) + 1

というようにプログラムします.

source c

result

<html>

<head>
    <script>
        function a() {
            //0, 1の乱数を生成する
            var x = Math.floor(Math.random() * 2)
            if (x == 0) {
                window.alert('あたり!');
            } else {
                window.alert('はずれ.');
            }
        }         
    </script>
</head>

<body>
    <h1>おみくじプログラム</h1>
    <button onclick="a()">A</button>
</body>

</html>

2 テキストフィールドとJavaScriptの連携 braproアイコン

本章では,テキストフィールドへの入出力を学びます.

2.1 テキストフィールドを作る braproアイコン

htmlを使ってテキストフィールドを作るには,inputタグを使います.

<input type="text">

source c

result

<html>

<head>
</head>

<body>
    <input type="text">
</body>

</html>

2.2 テキストフィールドの初期値を設定する braproアイコン

テキストフィールドの初期値を指定するには,value属性を使います.

<input type="text" value="2">

source c

result

<html>

<head>
</head>

<body>
    <input type="text" value="2">
</body>

</html>

2.3 テキストフィールドから値を取得する braproアイコン

テキストフィールドに記入された文字を取得するには,

var x = document.getElementById('[id名]').value;

プログラムを使います.

document.getElementById('[id名]')

でbodyタグの中身から,[id名]のついた要素(タグ)を探し,そのタグの属性であるvalueを

.value

で取得し,変数xに格納します.

source c

result

<html>

<head>
    <script>
        function a() {
            var x = document.getElementById('textfield1').value;
            window.alert('入力されたのは' + x + 'です.');
        } 
    </script>
</head>

<body>
    <input id="textfield1" type="text">
    <button onclick="a()">A</button>
</body>

</html>

2.4 テキストフィールドに値を入力する braproアイコン

テキストフィールドに値を入力するには,

document.getElementById('[id名]').value = x;

(xは定義済みの変数)プログラムを使います.

source c

result

<html>

<head>
    <script>
        function a() {
            var x = document.getElementById('textfield1').value;
            document.getElementById('textfield2').value = x;
        } 
    </script>
</head>

<body>
    <input id="textfield1" type="text">
    <input id="textfield2" type="text">
    <button onclick="a()">A</button>
</body>

</html>

2.5 テキストフィールドから取得した文字列を数字に変換し,計算を行う braproアイコン

テキストフィールドから入力された値は,文字列になっています.したがって,入力された値を利用して計算をするには,数字の変数に変換する必要があります.

文字列を数字に変換するには,

x = Number(x);

(xは事前に定義しておくこと)プログラムを使います.

Number関数で,文字列を数字に変えることができます. さあ,足し算プログラムを作ってみましょう.

source c

result

<html>

<head>
    <script>
        function calc() {
            var a = document.getElementById('textfield1').value;
            a = Number(a);
            var b = document.getElementById('textfield2').value;
            b = Number(b);
            var c = a + b;
            document.getElementById('textfield3').value = c;
        } 
    </script>
</head>

<body>
    <input id="textfield1" type="text">
    +
    <input id="textfield2" type="text">
    <button onclick="calc()">=</button>
    <input id="textfield3" type="text">

</body>

</html>

3 JavascriptによるHTMLの生成 braproアイコン

本章では,JavascriptでHTMLを生成し,リストや表を作る方法を学びます.

3.1 タグの中身を書き換える(innerHTML) braproアイコン

document.getElementById(‘xx’)で取得したタグの中身を書き換えることができます.

document.getElementById('xx').innerHTML = 'hello, world';

document.getElementById(‘xx’)で取得したタグの中身を.innerHTMLで取得したり,書き換えたりすることができます.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            document.getElementById('hello').innerHTML = 'hello, world!'
        }
    </script>
</head>

<body>
    <h1 id="hello">Title</h1>
    <button onclick="buttonAPressed()">A</button>
</body>

</html>

3.1.1 hint

先週習ったテキストフィールドの書き換えでは,valueの属性値を書き換えたので,

document.getElementById('xx').value = 'xx';

という記述になりました.タグの中身を書き換える場合はinnerHTMLを使います. 間違えやすいので注意.

3.2 リスト(箇条書き)の要素を加える braproアイコン

innerHTMLにセットする文字列には,HTMLを含めることができます.

document.getElementById('xx').innerHTML = '<li>りんご</li>'

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            document.getElementById('fruits').innerHTML = '<li>りんご</li>';
        }
    </script>
</head>

<body>
    <h1>箇条書き</h1>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <ul id="fruits">
    </ul>
</body>

</html>

3.2.1 hint

番号なしリストはulタグ,リストの要素は,liタグを使うのでしたね.

3.3 複数の要素を加える braproアイコン

複数の要素を加えるには,まず

var html = '';

で,文字列型の変数を用意して,

html = html + 'つなげたい文字列';

というプログラムを書くことで,文字列を次々に連結していきます.

最後に,innerHTML属性を使うことで,作られた文字列を指定されたidのタグにセットします.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var html = '';
            html = html + '<li>りんご</li>';
            html = html + '<li>みかん</li>';
            html = html + '<li>いちご</li>';
            document.getElementById('fruits').innerHTML = html;
        }
    </script>
</head>

<body>
    <h1>箇条書き</h1>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <ul id="fruits">
    </ul>
</body>

</html>

3.4 繰り返しプログラムで要素を加える braproアイコン

文字列を連結してHTML出力する方法がわかったら, 応用として,繰り返しプログラムでタグを生成してみましょう.

先程と同様に

var html = '';

で,文字列型の変数を用意し,繰り返しの中で

html = html + '<li>' + i + '</li>';

というプログラムを書くことで,数を数えるプログラムを作ることができます.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var html = '';
            for (var i = 1; i <= 10; i++) {
                html = html + '<li>' + i + '</li>';
            }
            document.getElementById('fruits').innerHTML = html;
        }
    </script>
</head>

<body>
    <h1>箇条書き</h1>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <ul id="fruits">
    </ul>
</body>

</html>

3.5 ボタンを押すたびに要素を追加する braproアイコン

先程までのプログラムでは,var html = ’’で文字列を初期化して,HTMLを生成していたので,ボタンを複数回押しても,出力される文字列は同様でしたが,一行目を次のように書き換えて

var html = document.getElementById('fruits').innerHTML;

ボタンを押すたびに追記されるように改造することができます.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var html = document.getElementById('fruits').innerHTML;
            html = html + '<li>めろん</li>';
            document.getElementById('fruits').innerHTML = html;
        }
        function buttonBPressed() {
            var li = document.createElement('li');
            li.innerHTML = 'めろん';
            document.getElementById('fruits').appendChild(li);
        }
    </script>
</head>

<body>
    <h1>箇条書き</h1>
    <button onclick="buttonAPressed()">A</button>
    <button onclick="buttonBPressed()">B</button>
    <hr>
    <ul id="fruits">
    </ul>
</body>

</html>

tips

ボタンBが押されたときの処理では,appendChildを使った別の書き方の例を載せてあります.

var li = document.createElement('li');
li.innerHTML = 'めろん';
document.getElementById('fruits').appendChild(li);

3.6 テキストフィールドから入力したものをリストに追加する braproアイコン

これまでの応用で,テキストフィールドから入力されたものをリストに追加するプログラムを作ることができます.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var fruit = document.getElementById('input-fruit').value;
            var html = document.getElementById('fruits').innerHTML;
            html = html + '<li>' + fruit + '</li>';
            document.getElementById('fruits').innerHTML = html;
            document.getElementById('input-fruit').value = '';
        }
    </script>
</head>

<body>
    <h1>箇条書き</h1>
    <input id="input-fruit" type="text">
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <ul id="fruits">
    </ul>
</body>

</html>

3.7 表の生成 braproアイコン

tableタグの中身を生成することで,表を生成することもできます.

表の一行はtrタグ,セルはtdタグで表現します.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var html = '';
            html = html + '<table border="1">';
            html = html + '<tr>';
            html = html + '<td>国語</td>';
            html = html + '<td>100</td>';
            html = html + '</tr>';
            html = html + '<tr>';
            html = html + '<td>算数</td>';
            html = html + '<td>90</td>';
            html = html + '</tr>';
            html = html + '</table>';
            document.getElementById('table1').innerHTML = html;
        }
    </script>
</head>

<body>
    <h1></h1>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <div id="table1"></div>
</body>

</html>

3.7.1 tips

ここでは,HTML部でtableタグを用意するのではなく,divタグを用意して,divタグの中身を生成するプログラムの最中で,tableタグを生成しています.この場合はどちらでも良いのですが,divタグを指定することによりより汎用的なプログラムを作ることができます.

4 HTML生成 応用編 braproアイコン

本章では,HTML生成に関する2つの応用プログラムを学びます.

4.1 プルダウンメニュー braproアイコン

プルダウンメニューを作成するには,selectタグを使います.

<select id="input-repeatnum">
    <option value="10">10回</option>
    <option value="15">15回</option>
</select>

selectタグの中のoptionタグで,選択肢を指定します. value属性は,その選択した選択されたときに取得される値(.valueで取得できる属性) で,optionタグの中身(10回,15回など)は,画面に表示されるテキストです.

選択された選択肢の値は,Javascriptからは次のようなプログラムで取得することができます.

var n = document.getElementById('xx').value;

テキストフィールドと同様の方法です.

このプログラムは,プルダウンメニューで指定された回数分,数を数えるプログラムです.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var n = document.getElementById('input-repeatnum').value;
            n = Number(n);
            var html = '';
            for (var i = 1; i <= n; i++) {
                html = html + '<li>' + i + '</li>';
            }
            document.getElementById('list1').innerHTML = html;
        }
    </script>
</head>

<body>
    <h1>1からNまでの数字を数えるプログラム</h1>
    数える回数(N):
    <select id="input-repeatnum">
        <option value="10">10回</option>
        <option value="15">15回</option>
        <option value="20">20回</option>
    </select>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <ul id="list1"></ul>
</body>

</html>

4.2 合計を求める braproアイコン

前の例題について,1からNまで数えるだけでなく,その数字までの総和を求めるプログラムに改造してみましょう.

9行目で,

var sum = 0;

と,総和を保存しておく変数を用意しておき,

11行目で

sum = sum + i;

と,保存してある総和に,今数えている数(iに保存されている)を加算します.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var n = document.getElementById('input-repeatnum').value;
            n = Number(n);
            var html = '';
            var sum = 0;
            for (var i = 1; i <= n; i++) {
                sum = sum + i;
                html = html + '<li>' + sum + '</li>';
            }
            document.getElementById('list1').innerHTML = html;
        }
    </script>
</head>

<body>
    <h1>1からNまでの総和を求めるプログラム</h1>
    求める回数(N):
    <select id="input-repeatnum">
        <option value="10">10回</option>
        <option value="15">15回</option>
        <option value="20">20回</option>
    </select>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <ul id="list1"></ul>
</body>

</html>

5 ローカル変数とグローバル変数 braproアイコン

本章では,ローカル変数とグローバル変数について学びます.

5.1 ローカル変数 braproアイコン

関数(function)内に定義された変数(var)が関数内でのみ有効であることは,第1部の教材「変数のスコープ」で学習しました.関数の中に定義した変数は関数ブロック内で有効なので,関数ブロックの外で変数を参照することはできません.

ここでは,次のようなプログラムで,ボタンが何度も押され,関数がその都度呼ばれる場面を考えてみましょう.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var x = 0;
            x = x + 1;
            document.getElementById('label1').innerHTML = x;
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <p id="label1">0</p>
</body>

</html>

buttonAPressed()関数内に変数xを定義し,0で初期化します.

var x = 0;

関数内で定義されたローカル変数(局所変数)は,関数の呼び出し毎に毎回保存領域が確保され,初期化され,関数が終わると消滅する呼び出し1回限り有効な変数です.したがって,ボタンを何度も押し,関数を何度実行しても,表示されるのは1のままです.

5.2 グローバル変数 braproアイコン

関数(function)の外側に定義された変数(var)は,すべての関数で有効なグローバル変数(広域変数)となります. グローバル変数はどの関数からもその値を読み書きすることができます.プログラムが読み込まれると同時に初期化されて,プログラムが終了するまで値を保持し続けます.

source c

result

<html>

<head>
    <script>
        var x = 0;

        function buttonAPressed() {
            x = x + 1;
            document.getElementById('label1').innerHTML = x;
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <p id="label1">0</p>
</body>

</html>

今度のプログラムでは,ボタンを何度押しても,前回の値が保存されているので,1ずつカウントアップするプログラムを作ることができました.

5.3 グローバル変数(2) braproアイコン

グローバル変数は関数間で値を共有し,どの関数からもその値を読み書きすることができます.

source c

result

<html>

<head>
    <script>
        var x = 0;

        function buttonAPressed() {
            x = x + 1;
            document.getElementById('label1').innerHTML = x;
        }

        function buttonBPressed() {
            x = 0;
            document.getElementById('label1').innerHTML = x;
        }
    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <button onclick="buttonBPressed()">B</button>
    <hr>
    <p id="label1">0</p>
</body>

</html>

もう一つの関数を用意して,カウントをリセットするボタンを作ることができました.

tips

このように,大変便利に見えるグローバル変数ですが,プログラムの保守という観点からは問題が多いので,極力控えてプログラムを作ることが推奨されています.簡単に説明すると,バグが起こったときに,ローカル変数ならばバグの範囲が限定しやすいのですが,グローバル変数が多いと,影響を与える関数(プログラム)の範囲が広大になってしまい,デバッグする範囲も広域に及びます.

6 canvas入門 braproアイコン

本章では,canvasの基本的な使い方を学びます.

6.1 canvasをつくり,四角形を書く braproアイコン

canvasタグ(要素)は,そこにJavascriptプログラムを使って図形や文字を書いたり,画像を描画することができるHTMLの要素です.

source c

result

<html>

<head>
    <script>

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            ctx.strokeStyle = '#0000FF';
            ctx.fillStyle = '#FF0000';

            ctx.strokeRect(200, 80, 100, 50);
            ctx.fillRect(20, 40, 50, 100);
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

canvasタグで,キャンパスを作ります.大きさを指定し,Javascriptから読み書きできるようにidをつけ,見分けがつくようにボーダー線をつけます.

<canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>

プログラムでは,1行目で,

var ctx = document.getElementById('canvas1').getContext('2d');

おなじみのgetElementById()関数を使い,idを指定して要素を取得し,2Dで書き込めるcontextオブジェクトを取得し,ctx変数に格納します.この行は,canvasに書き込むプログラムを作るときに毎回書くおまじないと思ってください.

次の行で,背景を塗りつぶします.前回になにか書いたものがあればこの行で消されます. ボタンが押されるたびにcanvasに追記していきたい場合はこの行を削除します.

ctx.clearRect(0, 0, 400, 300);

枠線と塗りつぶしの色を決めます.

ctx.strokeStyle = '#0000FF'; //枠線の色は青
ctx.fillStyle = '#FF0000'; //塗りつぶしの色は赤

strokeRect(x, y, w, h)関数は,x, y座標を基点に,幅w, 高さhの四角形を描画します.fillRectは塗りつぶしの四角形を描画します.

ctx.strokeRect(200, 80, 100, 50);
ctx.fillRect(20, 40, 50, 100);

6.2 円を書く braproアイコン

source c

result

<html>

<head>
    <script>

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            ctx.strokeStyle = '#0000FF';
            ctx.fillStyle = '#FF0000';

            ctx.beginPath();
            ctx.arc(100, 100, 50, 0, Math.PI * 2);
            ctx.stroke();

            ctx.beginPath();
            ctx.arc(200, 100, 50, 0, Math.PI * 2);
            ctx.fill();
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

円を書くには,まず,

ctx.beginPath();

でパス(図形を描画するとき一つ一つの動作でできる要素のことをパスと呼びます)を初期化します.

次に,

ctx.arc(100, 100, 50, 0, Math.PI * 2);

で,円弧を書きます.引数は(x, y, 半径, 開始角度(ラジアン), 終了角度(ラジアン))です.上記の例では,座標(100, 100)を中心に,半径50の円を書きます.

最後に,

ctx.stroke();

で,パスを終了し,図形を描画します.

円弧ではなく,塗りつぶすには

ctx.fill();

で,パスを終了し,図形を描画します.

hint

180°はラジアンでπ,360°はラジアンで2πとなります.

6.3 線を書く braproアイコン

source c

result

<html>

<head>
    <script>

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            ctx.strokeStyle = '#0000FF';
            ctx.fillStyle = '#FF0000';

            //100, 100から200, 200 へ線を引く
            ctx.beginPath();
            ctx.moveTo(100, 100);
            ctx.lineTo(200, 200);
            ctx.stroke();

            //3点を頂点とする三角形を描画する
            ctx.beginPath();
            ctx.moveTo(200, 200);
            ctx.lineTo(250, 100);
            ctx.lineTo(300, 200);
            ctx.closePath();
            ctx.stroke();
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

線を書くには,まずbeginPath();でパスを初期化し,

始点を

ctx.moveTo(100, 100);

で設定し,終点を

ctx.lineTo(200, 200);

で設定します.

最後に,

ctx.stroke();

で,パスを終了し,線を描画します.

lineToを2回以上呼び出して,3角形以上の多角形ができる場合には,始点と終点をつなぎ,多角形を作ります.

6.4 文字列を描画する braproアイコン

source c

result

<html>

<head>
    <script>

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            ctx.font = "30px sans-serif";
            ctx.fillText("hello, world!", 20, 75, 200);
            ctx.strokeText("hello, world!", 20, 175, 200);
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

文字列を描画するには,

ctx.font = "30px sans-serif";

で,フォントとその大きさを指定した後,

ctx.fillText("hello, world!", 20, 75, 200);

で,文字列を書き込みます.引数は(表示する文字列, x座標, y座標, 最大幅)です.

抜き文字を描画したい場合は,

ctx.strokeText("hello, world!", 20, 175, 200);

で描画します.

6.5 画像を描画する braproアイコン

source c

result

<html>

<head>
    <script>
        var img01 = new Image();
        img01.src = 'goo.png';

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            ctx.drawImage(img01, 10, 10, 100, 100);
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

画像を描画するには,まず,グローバル変数として,画像オブジェクトを生成し,ファイル名を指定して画像を読み込みます. この書き方も,意味は完全にわからなくて構いませんので,最初はこう書くものだと覚えてください.

var img01 = new Image();
img01.src = "goo.png";

読み込んだ画像をキャンパスに描くには,buttonAPressed関数内で,

ctx.drawImage(img01, 10, 10, 100, 100);

と記述し描画します.引数は(画像オブジェクト, x座標, y座標, 幅,高さ)です.

7 canvas 応用編 braproアイコン

本章では,canvasを使った3つの応用プログラムを学びます.

7.1 繰り返し図形 braproアイコン

canvasを使ったdrawXXXなどという記述は,Javascriptプログラムですから,これまでに習った基礎的なプログラミングテクニック(for文,if文)が応用できます.

source c

result

<html>

<head>
    <script>

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            for (var i = 0; i < 10; i++) {
                ctx.strokeRect(i * 15, 50, 10, 10);
            }
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

上記のプログラムで,四角形を横に並べて10個書くためには,x座標を工夫して

for (var i = 0; i < 10; i++) {
    ctx.strokeRect(i * 15, 50, 10, 10);
}

というように書くと,繰り返しを使って多くの同様の図形を書くことができます.

7.2 テキストフィールドと組み合わせる braproアイコン

canvasの外にあるテキストフィールドと組み合わせてプログラムを作ることもできます.

次のプログラムでは,テキストフィールドからx座標とy座標の入力を受け取り,その場所に四角形を描いています.

source c

result

<html>

<head>
    <script>
        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            var x = document.getElementById('x').value;
            x = Number(x);
            var y = document.getElementById('y').value;
            y = Number(y);

            ctx.strokeRect(x, y, 10, 10);
        }

    </script>
</head>

<body>
    X:<input id="x" type="text" value="0">Y:<input id="y" type="text" value="0">
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

7.3 じゃんけんプログラム braproアイコン

canvasの画像描画を応用して,じゃんけんプログラムを作ってみましょう. グー,チョキ,パーの画像を用意して,乱数を使い,どの手を出すのかを決めて,その画像を表示します.

source c

result

<html>

<head>
    <script>

        var img01 = new Image();
        img01.src = 'goo.png';
        var img02 = new Image();
        img02.src = 'choki.png';
        var img03 = new Image();
        img03.src = 'pa.png';

        function buttonAPressed() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            var x = Math.floor(Math.random() * 3) + 1;
            if (x == 1) {
                ctx.drawImage(img01, 10, 10, 100, 100);
            } else if (x == 2) {
                ctx.drawImage(img02, 10, 10, 100, 100);
            } else if (x == 3) {
                ctx.drawImage(img03, 10, 10, 100, 100);
            }
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

8 タイマー braproアイコン

本章では,タイマーの使い方を学びます.

8.1 タイマーから一定間隔で関数を呼び出す braproアイコン

これまでのプログラムを動作させるには,必ずユーザがなにか操作(ボタンを押すなど)をする必要がありましたが,キッチンタイマーなど,定期的に,自動的に動作するプログラムを作るときには,時を刻むタイマーが必要になります.

source c

result

<html>

<head>
    <script>
        var x = 0;

        function buttonAPressed() {
            setInterval(tick, 1000);
        }

        function tick() {
            x = x + 1;
            document.getElementById('time').innerHTML = x;
        }
    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <p id="time">0</p>
</body>

</html>

Javascriptでは,setInterval関数でタイマーを起動します.

setIntervalの書法は,次の通りです.

setInterval([関数名], [呼び出す間隔(ミリ秒)]);

例えば,

setInterval(tick, 1000);

という行では,tickという関数(下に定義してありますね)を,1000ミリ秒ごと,つまり1秒毎に呼び出すタイマーを起動する,という意味になります.Aボタンを押すと,setInterval関数が実行され,タイマーが起動して1秒毎にtick関数が実行されるようになります.

8.2 タイマーを停止する braproアイコン

source c

result

<html>

<head>
    <script>
        var x = 0;
        var timer;

        function buttonAPressed() {
            timer = setInterval(tick, 1000);
        }

        function buttonBPressed() {
            clearInterval(timer);
        }

        function tick() {
            x = x + 1;
            document.getElementById('time').innerHTML = x;
        }
    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <button onclick="buttonBPressed()">B</button>
    <hr>
    <p id="time">0</p>
</body>

</html>

タイマーを停止するには,

clearInterval([タイマー変数]);

関数を呼び出します.タイマー変数を記憶しておく必要があるので,グローバル変数として,

var timer;

を定義し,タイマーが起動したときに,setInterval関数の戻り値として得られるタイマー変数を記憶しておき,

timer = setInterval(tick, 1000);

clearInterval関数でタイマーを停止します.

clearInterval(timer);

8.3 タイマーの重複起動を回避する braproアイコン

一つ前のプログラムでは,タイマーの起動と停止を行うことができるようになりましたが, 何どもAボタンを押すと,タイマーがたくさん起動してしまい,停止もできなくなります(変数は一つのため,最後に起動したものしか停止できない).

タイマーの重複起動を回避するテクニックをはいくつかあるのですが,状態変数による場合分けのプログラムを作ってみましょう.

source c

result

<html>

<head>
    <script>
        var x = 0;
        var timer;
        var state = '停止中';

        function buttonAPressed() {
            if (state == '停止中') {
                timer = setInterval(tick, 1000);
                state = '動作中';
            }
        }

        function buttonBPressed() {
            if (state == '動作中') {
                clearInterval(timer);
                state = '停止中';
            }
        }

        function tick() {
            x = x + 1;
            document.getElementById('time').innerHTML = x;
        }
    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <button onclick="buttonBPressed()">B</button>
    <hr>
    <p id="time">0</p>
</body>

</html>

‘停止中’, か’起動中’かを記憶しておく変数stateをグローバル変数として定義します.

var state = '停止中';

buttonAPressed()関数は次のように書き換えます.

if (state == '停止中') {
    timer = setInterval(tick, 1000);
    state = '動作中';
}

このプログラムは,stateが「停止中」のときだけ,タイマーを起動し,起動したらstateを「動作中」に切り替えます.

buttonBPressed()関数は次のように書き換えます.

function buttonBPressed() {
    if (state == '動作中') {
        clearInterval(timer);
        state = '停止中';
    }
}

このプログラムは,stateが「動作中」のときだけ,タイマーを停止し,停止したらstateを「停止中」に切り替えます.

8.4 シンプルなインターフェイスに braproアイコン

state変数で状態を管理できるようになると,ボタンは一つでも同様の機能を実現できることに気づきます. AボタンとBボタンの動作について,Aボタン一つでその状態ごとに動作を分岐するようにして,Aボタンを押すたびに停止と実行を切り替えるプログラムを作ることができます.

source c

result

<html>

<head>
    <script>
        var x = 0;
        var timer;
        var state = '停止中';

        function buttonAPressed() {
            if (state == '停止中') {
                timer = setInterval(tick, 1000);
                state = '動作中';
            } else if (state == '動作中') {
                clearInterval(timer);
                state = '停止中';
            }
        }

        function tick() {
            x = x + 1;
            document.getElementById('time').innerHTML = x;
        }
    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <p id="time">0</p>
</body>

</html>

8.5 ストップウォッチ braproアイコン

タイマーのプログラムを応用して,ストップウォッチを作ってみましょう. 1/10秒の位と1秒の二桁の変数を用意して,100ミリ秒ごとに1/10秒の位をカウントアップし,1/10秒のくらいが10になったら,繰り上がりを実現します.

source c

result

<html>

<head>
    <script>
        var sec = 0;
        var oneof10sec = 0;
        var timer;
        var state = '停止中';

        function buttonAPressed() {
            if (state == '停止中') {
                timer = setInterval(tick, 100);
                state = '動作中';
            } else if (state == '動作中') {
                clearInterval(timer);
                state = '停止中';
            }
        }

        function tick() {
            oneof10sec = oneof10sec + 1;
            if (oneof10sec == 10) {
                sec = sec + 1;
                oneof10sec = 0;
            }
            document.getElementById('output-sec').innerHTML = sec;
            document.getElementById('output-oneof10sec').innerHTML = oneof10sec;
        }
    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <p><span id="output-sec">0</span>:<span id="output-oneof10sec">0</span></p>
</body>

</html>

tick()関数の次のプログラムに注目しましょう.

oneof10sec = oneof10sec + 1;
if (oneof10sec == 10) {
    sec = sec + 1;
    oneof10sec = 0;
}

9 タイマーとcanvasを使ったアニメーションの作成 braproアイコン

本章では,タイマーとcanvasを使って図形を動かすアニメーションを作成する方法を学びます.

9.1 四角形を動かすアニメーション braproアイコン

タイマーとcanvasを使って,図形を動かすアニメーションを作ることができます. tick()関数は,20ミリ秒ごとに呼ばれる関数で,この中で,毎回キャンパスを書き換えます. 毎回,少しずつ図形を動かしながら書くことで,物体が動いているように見えるアニメーションを作ることができます.

source c

result

<html>

<head>
    <script>
        var timer;
        var state = '停止中';

        function buttonAPressed() {
            if (state == '停止中') {
                timer = setInterval(tick, 20);
                state = '動作中';
            } else if (state == '動作中') {
                clearInterval(timer);
                state = '停止中';
            }
        }

        var x = 10;
        var y = 10;

        function tick() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            x = x + 2;
            ctx.strokeRect(x, y, 10, 10);
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

アニメーションを作るには,物体の位置を記憶しておく必要があるため,座標を記憶するグローバル変数を作成します.

var x = 10;
var y = 10;

20ミリ秒ごとに実行されるtick()関数では,毎回

x = x + 2;

というプログラムでxを2増やした後

ctx.strokeRect(x, y, 10, 10);

で,増やされたx変数の値を使ってx座標の位置に四角形を記述します.結果的に毎回,2ピクセルずつx座標を右に動かして描画します.これをタイマーで繰り返すと,物体が右に動いているように見えます.

9.2 四角形を動かすアニメーション(キャンパス外に出てしまった場合の処理) braproアイコン

先のプログラムでは,四角形は右に動いていきますが,やがてキャンパス右外に出てしまいます. キャンパス右橋と左端をつないで,右外に出た場合には左から入ってくるようにしてみましょう.

source c

result

<html>

<head>
    <script>
        var timer;
        var state = '停止中';

        function buttonAPressed() {
            if (state == '停止中') {
                timer = setInterval(tick, 20);
                state = '動作中';
            } else if (state == '動作中') {
                clearInterval(timer);
                state = '停止中';
            }
        }

        var x = 10;
        var y = 10;

        function tick() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            x = x + 2;
            if (x > 400) {
                x = 0;
            }
            ctx.strokeRect(x, y, 10, 10);
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

tick()関数で,x座標を増やしたときに,x座標がキャンバスサイズ(今回は400)より大きい場合を調べて,大きくなった場合にはx座標を0に戻すプログラムを次のように書きます.

if (x > 400) {
    x = 0;
}

9.3 パラパラ漫画アニメーション braproアイコン

タイマーを利用して,画像を次々と書き換えることもできます.これによってパラパラ漫画の要領でアニメーションを作ることができます.このプログラム例はじゃんけんのグー,チョキ,パーを切り替えるアニメーションです.

source c

result

<html>

<head>
    <script>

        var img01 = new Image();
        img01.src = 'goo.png';
        var img02 = new Image();
        img02.src = 'choki.png';
        var img03 = new Image();
        img03.src = 'pa.png';

        var timer;
        var state = '停止中';

        var x = 1;

        function buttonAPressed() {
            if (state == '停止中') {
                timer = setInterval(tick, 20);
                state = '動作中';
            } else if (state == '動作中') {
                clearInterval(timer);
                state = '停止中';
            }
        }

        function tick() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 400, 300);

            if (x == 1) {
                ctx.drawImage(img01, 10, 10, 100, 100);
            } else if (x == 2) {
                ctx.drawImage(img02, 10, 10, 100, 100);
            } else if (x == 3) {
                ctx.drawImage(img03, 10, 10, 100, 100);
            }

            if (x <= 2) {
                x = x + 1;
            } else {
                x = 1;
            }
        }

    </script>
</head>

<body>
    <button onclick="buttonAPressed()">A</button>
    <hr>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

現在の画像番号を保持する変数xをグローバル変数に定義します.

var x = 1;

3枚の画像があるため,変数は1, 2, 3と書き換えるようにします.

if (x <= 2) {
    x = x + 1;
} else {
    x = 1;
}

10 キーボードとマウス入力の処理

本章では,キーボード,マウスの入力を処理する方法を学びます.

10.1 キーボード入力の処理

10.1.1 初期化プログラムの書き方,イベントハンドラ登録の書き方

以下はキーボード入力を処理する最小のサンプルプログラム,キーボードハンドラのテストプログラムです.

source c

result

<html>

<head>
    <script>
        window.onload = function () {
            document.addEventListener('keydown', handleKeyDown);
        }

        function handleKeyDown(e) {
            console.log(e);
        }

    </script>
</head>

<body>
    <h1>キーボードハンドラのテスト</h1>
    <p>コンソールを開いてイベントを確認しましょう</p>
</body>

</html>

ブラウザにページが表示されたらすぐに実行したいプログラム(初期化プログラム)を書くには,window.onload変数に関数を登録します.書式は以下のとおりです.

window.onload = function(){
    【ページが表示されたらすぐに実行したいプログラム(初期化プログラム)を書く】
}

(この行の意味を理解するのは難しいので「こう書く」と覚えればよいです)

このプログラムでは,初期化プログラムとして,キーボードの入力を処理する「イベントハンドラ」を登録しています.

document.addEventListener('keydown', handleKeyDown);

(この行の意味も,意味を完全に理解するのは難しいので,ひとまずこのように書く,と覚えればよいです.)

‘keydown’ のところは,JavaScriptで決められているイベント名を書きます.本テキストでは以下の5つのイベントを紹介します.(この5つを組み合わせれば,大抵のことはできるはずです)

handleKeyDownのところは,登録する関数名を書きます. このプログラムでは,9-11行目に,以下のようなhandleKeyDown関数が定義されているので,この関数を登録することになります.

function handleKeyDown(e) {
    console.log(e);
}

登録された関数は,keydownというイベント,つまり,1回キーボードのなにかのキーが押されたときに1回実行されます. このプログラムでは,キーボードのなにかが押されると,コンソールにイベントが表示されるというわけです.

キーボードが押されたときの処理を行うように登録された関数(ここではhandleKeyDown関数)には,引数eにキーボードイベントが付与されて呼ばれます.console.log(e)では,そのイベントの内容を表示しています.

コンソールを開き,何かキーを押してみて,イベントを確認してみましょう.キーを押すたびにコンソールには以下のようなイベントが表示されます.

10.1.2 キーボードイベント内容をキャンパスに表示する

キーが押されるたびに,キーボードイベントの内容をキャンパスに表示するプログラムを作ってみましょう.

source c

result

<html>

<head>
    <script>
        window.onload = function () {
            document.addEventListener('keydown', handleKeyDown);
        }

        function handleKeyDown(e) {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 300, 400);
            ctx.font = "32px serif";
            ctx.fillText('key=' + e.key, 50, 50);
            ctx.fillText('keyCode=' + e.keyCode, 50, 100);
        }
    </script>
</head>

<body>
    <h1>キーボードイベント内容をキャンパスに表示する</h1>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>

</body>

</html>

handleKeyDown関数の引数eに与えられたキーボードイベントから,押されたキーなどの内容を調べることができます.

ここでは,よく利用されるe.keyと,e.keyCodeを表示しています.異なるキーを押すと,表示される内容が変わることを確認してみましょう.

このようにして取得できる,e.keyや,e.keyCodeを利用してキーボード入力を処理するプログラムを書くことができます.

10.1.3 キーボードで丸を動かす(その1)

キーボードの入力に応じて,canvas上の物を動かすプログラムを作ってみましょう.以下のプログラムでは,矢印キーを押すと丸の位置を変えることができます.

source c

result

<html>

<head>
    <script>
        var x = 100;
        var y = 100;

        window.onload = function () {
            document.addEventListener('keydown', handleKeyDown);
            draw();
        }

        function handleKeyDown(e) {
            if (e.keyCode == 38) { //up
                y = y - 5;
            } else if (e.keyCode == 40) { //down
                y = y + 5;
            } else if (e.keyCode == 37) { //left
                x = x - 5;
            } else if (e.keyCode == 39) { //right
                x = x + 5;
            }
            draw();
        }

        function draw() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 300, 400);
            ctx.beginPath();
            ctx.arc(x, y, 10, 0, Math.PI * 2);
            ctx.stroke();
        }
    </script>
</head>

<body>
    <h1>キーボードで丸を動かす(その1)</h1>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>

</body>

</html>

上下左右のキーのkeyCodeを調べて,キーに応じてx座標,y座標変えて,draw関数で丸の位置を書き直すプログラムにっています.

10.1.4 キーボードで丸を動かす(その2)

キーボードで丸を動かす(その1)では,一回一回のキーボード入力(押して離す)によってプログラムを動かしているので,ものを何度も動かすには,キーを連打する必要があります.押しっぱなしにすることによってキーボードのリピート機能(一定間隔で押したことになる)によって動かすことはできますが,なめらかではありません. また,その1では,同時押しにも対応していません.

ビデオゲームのように,滑らかに動かしたり,同時押しで斜めに動かしたりするためには,工夫が必要になります.その工夫をしたのが以下のプログラムです.

source c

result

<html>

<head>
    <script>
        var x = 100;
        var y = 100;

        var pressingUp = false;
        var pressingDown = false;
        var pressingRight = false;
        var pressingLeft = false;

        window.onload = function () {
            document.addEventListener('keydown', handleKeyDown);
            document.addEventListener('keyup', handleKeyUp);
            draw();
            setInterval(step, 50); //1秒20コマ
        }

        function step() {
            if (pressingUp) {
                y = y - 3;
            }
            if (pressingDown) {
                y = y + 3;
            }
            if (pressingLeft) {
                x = x - 3;
            }
            if (pressingRight) {
                x = x + 3;
            }
            draw();
        }

        function handleKeyDown(e) {
            if (e.keyCode == 38) { //up
                pressingUp = true;
            } else if (e.keyCode == 40) { //down
                pressingDown = true;
            } else if (e.keyCode == 37) { //left
                pressingLeft = true;
            } else if (e.keyCode == 39) { //right
                pressingRight = true;
            }
        }

        function handleKeyUp(e) {
            if (e.keyCode == 38) { //up
                pressingUp = false;
            } else if (e.keyCode == 40) { //down
                pressingDown = false;
            } else if (e.keyCode == 37) { //left
                pressingLeft = false;
            } else if (e.keyCode == 39) { //right
                pressingRight = false;
            }
        }

        function draw() {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 300, 400);
            ctx.beginPath();
            ctx.arc(x, y, 10, 0, Math.PI * 2);
            ctx.stroke();
        }
    </script>
</head>

<body>
    <h1>キーボードで丸を動かす(その2)</h1>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>

</body>

</html>

このプログラムでは,まず,step関数をsetInterval関数で登録して,1/20秒に一回,毎回更新処理を行うようにします.更新処理のときに,キーが押されているかを判断して,押されていたら移動の処理を行います.

step関数内では,else ifではなく,if文になっているところも大切なところです.これによって,同時に押されているときには,押されているキーすべての計算を行うようになり,結果として,斜めに動かせるようになります.

次に,「いま,各矢印キーが押されているかどうか」を調べるための仕組みを解説します.

まず,8行目から11行目で,押されているかどうかを保持しておく変数を定義します.次に,14行目,15行目,イベント登録として,keyupイベントも受け取るようにします.handleKeyDownとhandleKeyUpの2つの関数で,キーのダウンとアップを取得し,変数を書き換えています.

10.1.5 マウスハンドラのテスト

以下はマウス入力を処理する最小のサンプルプログラム,マウスハンドラのテストプログラムです.

source c

result

<html>

<head>
    <script>
        window.onload = function () {
            var canvas = document.getElementById('canvas1');
            canvas.addEventListener('mousedown', handleMousedown);
        }

        function handleMousedown(e) {
            console.log(e);
        }
    </script>
</head>

<body>
    <h1>マウスハンドラのテスト</h1>
    <p>コンソールを開いてイベントを確認しましょう</p>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

キーボード入力と仕組みは同じですが,キーボード入力と違い,(documentではなく,)canvasに対してハンドラを設定します.canvasが複数ある場合には,それぞれに対してハンドラを設定するとうまくいきます.

コンソールを開き,キャンバスの上をマウスでクリックしてみて,イベントを確認してみましょう.クリックするたびにコンソールには以下のようなイベントが表示されます.

10.1.6 マウスイベントの内容をキャンパスに書く

キーボード入力のときと同様に,マウスイベントの内容をキャンパスに書くプログラムを作ってみましょう.

source c

result

<html>

<head>
    <script>
        window.onload = function () {
            var canvas = document.getElementById('canvas1');
            canvas.addEventListener('mousedown', handleMousedown);
        }

        function handleMousedown(e) {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.clearRect(0, 0, 300, 400);
            ctx.font = "32px serif";
            ctx.fillText('offsetX=' + e.offsetX, 50, 50);
            ctx.fillText('offsetY=' + e.offsetY, 50, 100);
        }
    </script>
</head>

<body>
    <h1>マウスクリックで位置を書く</h1>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

</html>

マウスイベントで重要な情報はキャンパス上の座標です.キャンパス上の座標はe.offsetX, e.offsetYで取得することができます.キャンパス上のいくつかの点をクリックして,座標が正しく取得できていることを確認してみましょう.

10.1.7 マウスクリックで円を書く

座標取得のプログラムを応用して,マウスをクリックした位置に円を書くプログラムを作ってみましょう.

source c

result

<html>

<head>
    <script>
        window.onload = function () {
            var canvas = document.getElementById('canvas1');
            canvas.addEventListener('mousedown', handleMousedown);
        }

        function handleMousedown(e) {
            var ctx = document.getElementById('canvas1').getContext('2d');
            ctx.beginPath();
            ctx.arc(e.offsetX, e.offsetY, 10, 0, Math.PI * 2);
            ctx.stroke();
        }
    </script>
</head>

<body>
    <h1>マウスクリックで円を書く</h1>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

10.1.8 マウスドラッグで四角を書く

イベントを応用して,マウスドラッグで四角を書くプログラムを作ってみましょう.

source c

result

<html>

<head>
    <script>
        var dragging = false;
        var x1 = 0;
        var y1 = 0;

        window.onload = function () {
            var canvas = document.getElementById('canvas1');
            canvas.addEventListener('mousedown', handleMousedown);
            canvas.addEventListener('mouseup', handleMouseup);
            canvas.addEventListener('mousemove', handleMousemove);
        }

        function handleMousedown(e) {
            dragging = true;
            x1 = e.offsetX;
            y1 = e.offsetY;
        }

        function handleMouseup(e) {
            dragging = false;
        }

        function handleMousemove(e) {
            if (dragging) {
                var ctx = document.getElementById('canvas1').getContext('2d');
                ctx.clearRect(0, 0, 400, 300);
                ctx.beginPath();
                ctx.strokeRect(x1, y1, e.offsetX - x1, e.offsetY - y1);
                ctx.stroke();
            }
        }
    </script>
</head>

<body>
    <h1>マウスドラッグで四角を書く</h1>
    <canvas id="canvas1" width="400" height="300" style="border: solid 1px;"></canvas>
</body>

mousedownイベントのほかに,mosueupイベントやmousemoveイベントを受け取るようにして,ドラッグしている間はdragging変数がtrueになるようにプログラムします.

11 そのほか

本章では,最終作品制作に便利な機能をいくつか紹介します.

11.1 音を鳴らす

ゲームなどの作品では,BGMや効果音などが演出に欠かせません.ぜひ取り入れてみてください. 以下は,音を鳴らすサンプルプログラムです.

source c

result

<html>

<head>
    <script>
        var sound1 = new Audio('piko.mp3');
        sound1.preload = 'auto';
        sound1.volume = 1.0;

        var bgm1 = new Audio('menuette.mp3');
        bgm1.loop = true;
        bgm1.volume = 0.2;

        function buttonSoundPlayPressed() {
            sound1.pause();
            sound1.currentTime = 0;
            sound1.play();
        }

        function buttonBGMPlayBPressed() {
            bgm1.play();
        }

        function buttonBGMPausePressed() {
            bgm1.pause();
        }
    </script>

</head>

<body>
    <h1>音声再生</h1>
    <p>注意!音が出ます.</p>

    効果音:<button onclick="buttonSoundPlayPressed()">Play</button>
    <br>
    BGM:<button onclick="buttonBGMPlayBPressed()">Play</button>
    <button onclick="buttonBGMPausePressed()">Pause</button>

    <div style="height: 200px;"></div>
    <hr>
    <p>このサンプルプログラムには次のサイトのフリー音源を使用しました.</p>
    <ul>
        <li><a href="https://www.ne.jp/asahi/music/myuu/wave/wave.htm">フリーBGM Music with myuu</a></li>
        <li><a href="https://soundeffect-lab.info/sound/button/">効果音ラボ</a></li>
    </ul>
</body>

</html>

sound1は効果音のサンプルです.画像のときのように,まず,グローバル変数として,音声オブジェクトを生成し,ファイル名(mp3が良いと思います)を指定して音声を読み込みます.

var sound1 = new Audio('piko.mp3');
sound1.preload = 'auto';
sound1.volume = 1.0;

効果音は鳴るのが遅れると効果が上がらないので,preload属性ををautoにしておくとよいでしょう.volumeは0.0から1.0の間で設定できるので,必要に応じて設定してください.

次に,効果音の鳴らし方です.

function buttonSoundPlayPressed() {
    sound1.pause();
    sound1.currentTime = 0;
    sound1.play();
}

音声を鳴らすにはplay(),停止するにはpause()関数を使います.

sound1.play()だけでもいいのですが,連続して鳴らしたときに,直前に鳴らした音声が終わっていないと途中から再生することになり,タイミングによっては2回目は「鳴らない」ということになります. そこで,効果音は,毎回一旦停止し,currentTimeを0に戻す,つまり,再生位置を始め戻して再生する,ということをしています.これで,ボタンを連打してもしっかり音が鳴ることを確認してみましょう.

次に,BGMの鳴らし方です.

var bgm1 = new Audio('menuette.mp3');
bgm1.loop = true;
bgm1.volume = 0.2;

BGMも基本的には効果音と同じですが,ループ再生してほしいので,loop属性をtrueにしておきましょう.volumeは音声ファイルに応じて調整してください.

11.2 保存

Webアプリケーションは,読み込むたびに初期化されてしまうのですが,多くのアプリケーションでは,何かを保存しておけると便利です.ここでは,ブラウザに保存しておく簡単な方法を紹介します.

source c

result

<html>

<head>
    <script>
        function buttonSavePressed() {
            var text = document.getElementById('textArea1').value;
            localStorage.setItem('key-text', text);
        }

        function buttonLoadPressed() {
            var text = localStorage.getItem('key-text');
            document.getElementById('textArea1').value = text;
        }

    </script>

</head>

<body>
    <h1>テキストの保存</h1>
    <button onclick="buttonSavePressed()">Save</button>
    <button onclick="buttonLoadPressed()">Load</button>
    <br>
    <textarea id="textArea1" style="width:500px; height:300px;"></textarea>
</body>

</html>

このプログラムでは,saveボタンでtextareaの内容を保存し,loadボタンでtextareaに保存された内容を書き込みます.saveボタンを押して保存したあと,再読み込みをして初期化しても,loadボタンで内容を書き戻すことができることを確認してみましょう.

function buttonSavePressed() {
    var text = document.getElementById('textArea1').value;
    localStorage.setItem('key-text', text);
}

textarea要素(タグ)は,文字を複数行かけるHTML要素です..valueでテキストを取り出したり,設定したりすることができます.

lodalStorage.setItem(key, value)関数でブラウザに情報を書き込みます. localStorageには,key-valueストアと呼ばれるデータ構造でデータの読み書きをすることができます.keyはプログラマが自由に設定できます(変数のようなものです),各keyに対応するデータをvalueとして設定し,書き込みを行います.

function buttonLoadPressed() {
    var text = localStorage.getItem('key-text');
    document.getElementById('textArea1').value = text;
}

ここでは,localStorage.getItem(key)関数でブラウザから保存された情報を読み出しています. keyには書き込んだときと同じkeyを入力します.戻り値は保存された値になります. その次の行で,読み込まれたテキストをtextareaに設定しています.