静岡理工科大学 菅沼ホーム JavaScript目次 索引

CANVAS 要素と JavaScript

  HTML に対する説明においては,CANVAS 要素の利用方法について全く説明しませんでした.それは,この要素を使用するためには,JavaScript に対する知識が必要だったからです.ここでは,CANVAS 要素について詳細に説明していきます.
      1. 描画とイベント処理
        1. 描画の基本
        2. イベント処理
          1. イベント処理の基本
          2. 色の変更
          3. お絵かき
      2. アニメーション
        1. アニメーションの基本(円の描画)
        2. アニメーションの例
          1. ランニング(複数の外部画像の利用)
          2. アニメーション+イベント処理(外部画像)
          3. アニメーション+イベント処理(描画)
          4. ピクセル値の操作
      3. ゲーム
        1. シューティングゲーム
        2. ぷよぷよ(テトリス)
      4. グラフの描画
        1. データベースと表&グラフ
        2. 一般的なグラフ
  1. 描画とイベント処理

    1. 描画の基本

        CANVAS 要素に描画するためには,CANVAS のメソッド getContext によって,CANVAS に描画するための API にアクセスできるオブジェクト(コンテキスト,下の例では,ctx )を取得し,そのオブジェクトから API (下の例では,beginPath など)を使用して描画します.以下の例においても同様ですが,API の詳細については,「DOM 及び CANVAS 関係の JavaScript のプロパティとメソッド」の中の「 CANVAS 」を参考にして下さい.表示例では,左側に Path を使用して矩形と円を描き,中央に外部画像を描き(中央の円が表示されない場合は,再読み込みをしてみて下さい),また,右側にはピクセル値を直接操作して矩形を描いています.

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>CANVAS の例(描画)</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
      07		<SCRIPT TYPE="text/javascript">
      08			function draw() {
      09				let canvas    = document.getElementById('canvas_e');
      10				canvas.width  = 420;   // キャンバス要素の幅
      11				canvas.height = 140;   // キャンバス要素の高さ
      12				let ctx       = canvas.getContext('2d');
      13						// 矩形を描く
      14				ctx.beginPath();
      15				ctx.moveTo(20, 20);
      16				ctx.lineTo(120, 20);
      17				ctx.lineTo(120, 120);
      18				ctx.lineTo(20, 120);
      19				ctx.closePath();
      20				ctx.stroke();
      21						// 円を描く
      22				ctx.beginPath();
      23				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
      24				ctx.stroke();
      25						// 外部画像を描く
      26				let img = new Image();
      27				img.src = "ball.gif";
      28				ctx.drawImage(img, 170, 30);
      29						// ピクセル値の操作
      30				let wid = 80;
      31				let hei = 80;
      32				let im  = ctx.createImageData(wid, hei);
      33				for (let i1 = 0; i1 < hei/2; i1++) {
      34					for (let i2 = 0; i2 < wid; i2++) {
      35						let k = 4 * (wid * i1 + i2);
      36						im.data[k]   = 0x00;
      37						im.data[k+1] = 0xff;
      38						im.data[k+2] = 0x00;
      39						im.data[k+3] = 0xff;   // 透明度
      40					}
      41				}
      42				for (let i1 = hei/2; i1 < hei; i1++) {
      43					for (let i2 = 0; i2 < wid; i2++) {
      44						let k = 4 * (wid * i1 + i2);
      45						im.data[k]   = 0x00;
      46						im.data[k+1] = 0x00;
      47						im.data[k+2] = 0xff;
      48						im.data[k+3] = 0xff;   // 透明度
      49					}
      50				}
      51				ctx.putImageData(im, 310, 30);
      52			}
      53		</SCRIPT>
      54	</HEAD>
      55	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
      56		<H1>簡単な描画</H1>
      57		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="420" HEIGHT="140"></CANVAS>
      58	</BODY>
      59	</HTML>
      				
      09 行目

        ID 属性の値が canvas_e である要素( 57 行目の CANVAS 要素)を取得している.

      10 行目~ 11 行目

        キャンバスの幅を 420 ピクセル,高さを 140 ピクセルに設定している.

      12 行目

        CANVAS に描画するための API にアクセスできるオブジェクト(コンテキスト)を取得

      14 行目~ 20 行目

        矩形を描く処理である.
      • 14 行目: 現在のサブパスをリセットし,新しいサブパスを開始
      • 15 行目: 点 (20, 20) に移動
      • 16 行目: 直前の点 (20, 20) と点 (120, 20) を直線で結ぶ
      • 17 行目: 直前の点 (120, 20) と点 (120, 120) を直線で結ぶ
      • 18 行目: 直前の点 (120, 120) と点 (20, 120) を直線で結ぶ
      • 19 行目: 現在のサブパスの最後の点 (20, 120) と最初の点 (20, 20) を結びパスを閉じる.そして,閉じたサブパスの最初の点に基づき新しいサブパスを生成
      • 20 行目: サブパスの輪郭を表示

      22 行目~ 24 行目

        円を描く処理である.
      • 22 行目: 現在のサブパスをリセットし,新しいサブパスを開始
      • 23 行目: 点 (70, 70) を中心とした半径 40 の円弧を 0 から 2π まで,時計回り( false )に描く
      • 24 行目: サブパスの輪郭を表示

      26 行目~ 28 行目

        外部画像を描く処理である.
      • 26 行目: Image オブジェクトを生成
      • 27 行目: Image オブジェクトの src プロパティ(画像ファイル名)を指定
      • 28 行目: Image オブジェクトを指定した位置 (170, 30) に描画.なお,描画位置は,画像の左上に相当する.

      30 行目~ 51 行目

        ピクセル値を直接操作して矩形を描く処理である.
      • 30 行目~ 31 行目: 矩形の大きさを設定
      • 32 行目: 指定された大きさの ImageData オブジェクトを生成
      • 33 行目~ 41 行目: 矩形の上半分の領域を緑に設定
      • 42 行目~ 50 行目: 矩形の下半分の領域を青に設定
      • 51 行目: ImageData オブジェクトを指定した位置 (310, 30) に描画.なお,描画位置は,画像の左上に相当する.

      55 行目

        このページがロードされると,関数 draw が呼ばれる.

      57 行目

        CANVAS 要素の定義.ここで定義した幅と高さを,10 行目~ 11 行目と同じにしておいた方が良い.

        上の例では,HTML ファイル内にあらかじめ CANVAS 要素を定義していましたが,下に示す例では,div 要素の中に DOM のメソッド createElementappendChild によって,CANVAS 要素を生成,追加しています.

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>CANVAS の例(描画)</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
      07		<SCRIPT TYPE="text/javascript">
      08			function draw() {
      09				let area    = document.getElementById("canvas_e");   // キャンバスを挿入する場所
      10				let canvas1 = document.createElement("canvas");   // キャンバス要素を生成
      11				canvas1.style.backgroundColor = "#eeffee";   // キャンバスの背景色
      12				canvas1.width  = 420;   // キャンバス要素の幅
      13				canvas1.height = 140;   // キャンバス要素の高さ
      14				area.appendChild(canvas1);   // キャンバス要素を追加
      15				let ctx = canvas1.getContext('2d');
      16						// 矩形を描く
      17				ctx.beginPath();
      18				ctx.moveTo(20, 20);
      19				ctx.lineTo(120, 20);
      20				ctx.lineTo(120, 120);
      21				ctx.lineTo(20, 120);
      22				ctx.closePath();
      23				ctx.stroke();
      24						// 円を描く
      25				ctx.beginPath();
      26				ctx.arc(70, 70, 40, 0, Math.PI*2, false);
      27				ctx.stroke();
      28						// 外部画像を描く
      29				let img = new Image();
      30				img.src = "ball.gif";
      31				ctx.drawImage(img, 170, 30);
      32						// ピクセル値の操作
      33				let wid = 80;
      34				let hei = 80;
      35				let im  = ctx.createImageData(wid, hei);
      36				for (let i1 = 0; i1 < hei/2; i1++) {
      37					for (let i2 = 0; i2 < wid; i2++) {
      38						let k = 4 * (wid * i1 + i2);
      39						im.data[k]   = 0x00;
      40						im.data[k+1] = 0xff;
      41						im.data[k+2] = 0x00;
      42						im.data[k+3] = 0xff;   // 透明度
      43					}
      44				}
      45				for (let i1 = hei/2; i1 < hei; i1++) {
      46					for (let i2 = 0; i2 < wid; i2++) {
      47						let k = 4 * (wid * i1 + i2);
      48						im.data[k]   = 0x00;
      49						im.data[k+1] = 0x00;
      50						im.data[k+2] = 0xff;
      51						im.data[k+3] = 0xff;   // 透明度
      52					}
      53				}
      54				ctx.putImageData(im, 310, 30);
      55			}
      56		</SCRIPT>
      57	</HEAD>
      58	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
      59		<H1>簡単な描画</H1>
      60		<DIV ID="canvas_e"></DIV>
      61	</BODY>
      62	</HTML>
      				
      09 行目

        ID 属性の値が canvas_e である要素( 60 行目の DIV 要素)を取得している.

      10 行目

        CAMVAS 要素の生成

      11 行目

        CAMVAS 要素の背景色を #eeffee に設定

      12 行目~ 13 行目

        キャンバスの幅を 420 ピクセル,高さを 140 ピクセルに設定している.

      14 行目

        CANVAS 要素を 60 行目の DIV 要素内に追加

      60 行目

        この DIV 要素内に CANVAS 要素が追加される.

    2. イベント処理

      1. イベント処理の基本

          以下に示すいずれの例においても,「マウスでここをクリックして下さい」の箇所をクリックするとイベントが発生し,JavaScrip の alert 関数によって,クリックされた場所の x 座標及び y 座標が表示されます.「イベント処理(その1)」においては,SPAN 要素の中に,onClick 属性を使用して,クリックされた時の処理を行う関数を記述しています.

        イベント処理(その1)

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>要素内記述</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			function func(event)
        09			{
        10				alert("x: " + event.pageX + ", y: " + event.pageY);
        11			}
        12		</SCRIPT>
        13	</HEAD>
        14	<BODY CLASS="white">
        15		<H1 CLASS="center">イベント処理(<SPAN ID="test" onClick="func(event)">マウスでここをクリックして下さい</SPAN>)</H1>
        16	</BODY>
        17	</HTML>
        					
        08 行目~ 11 行目

          関数 func の定義であり,イベントが発生したとき(この場合は,マウスでクリックされたとき).クリックされた位置の x 座標と y 座標を出力している.

        15 行目

          SPAN 要素の onClick 属性を利用し,「マウスでここをクリックして下さい」の部分をクリックすると,関数 func が呼ばれるように設定している.

          「イベント処理(その2)」においては,SPAN 要素自体には onClick 属性が記述してありませんが,BODY 要素の中に,onLoad 属性が記述してあり,このページがロードされると関数 func が呼ばれます.関数 func の中で,ID 属性の値によって SPAN 要素を特定し( getElementById('test') ),そこにマウスクリックに対するイベント処理を行う関数を付加する( addEventListener("click", mouseClick) )ことによって,最初の例と同じイベント処理を実現しています.この方法は,ページが表示された当初からではなく,後ほど何らかの処理を行った後,イベント処理機能を追加したいような場合に利用できます.なお,getElementById 及び addEventListener については,「DOM 及び CANVAS 関係の JavaScript のプロパティとメソッド」の中の[DOM のメソッド]を参照してください.

        イベント処理(その2)

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>要素内記述</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			function func()
        09			{
        10				let hs = document.getElementById('test');
        11				hs.addEventListener("click", mouseClick);
        12			}
        13			function mouseClick(event)
        14			{
        15				alert("x: " + event.pageX + ", y: " + event.pageY);
        16			}
        17		</SCRIPT>
        18	</HEAD>
        19	<BODY CLASS="white" onLoad="func()">
        20		<H1 CLASS="center">イベント処理(<SPAN ID="test">マウスでここをクリックして下さい</SPAN>)</H1>
        21	</BODY>
        22	</HTML>
        					
        08 行目~ 12 行目

          関数 func の定義であり,10 行目で ID 属性の値が 'test' である要素を特定し( 20 行目の SPAN 要素),11 行目において,その要素がマウスでクリックされたとき( click ),関数 mouseClick を呼ぶように設定している.

        13 行目~ 16 行目

          マウスでクリックされたとき.クリックされた位置の x 座標と y 座標を出力している.

        19 行目

          BODY 要素の onLoad 属性を利用し,このページがロードされたとき,関数 func が呼ばれるように設定している.

        20 行目

          「マウスでここをクリックして下さい」の部分をクリックしたときの処理を追加するため,ID 属性を設定している.

      2. 色の変更

          最初の例では,ボタンをクリックすることによって CANVAS に描かれた円の色を変更しています.なお,関数 rgb の 3 つの引数は,それぞれ,赤(R),緑(G),及び,青(B)の強さを 0 ~ 255 の値で表しています.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>イベント処理( BUTTON 要素の属性)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			sw     = -1;
        11						// 初期設定と描画(ロード時)
        12			function draw()
        13			{
        14				canvas = document.getElementById('canvas_e');
        15				canvas.width  = 140;   // キャンバス要素の幅
        16				canvas.height = 140;   // キャンバス要素の高さ
        17				ctx = canvas.getContext('2d');
        18				s_color();
        19			}
        20						// 描画(ボタンがクリックされた時)
        21			function s_color()
        22			{
        23				ctx.clearRect(0, 0, canvas.width, canvas.height);
        24				ctx.beginPath();
        25				if (sw < 0)
        26					ctx.fillStyle = "rgb(0, 255, 0)";
        27				else
        28					ctx.fillStyle = "rgb(255, 0, 0)";
        29				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
        30				ctx.fill();
        31				sw *= -1;
        32			}
        33		</SCRIPT>
        34	</HEAD>
        35	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        36		<H1>イベント処理( BUTTON 要素の属性)</H1>
        37		<BUTTON STYLE="font-size:90%" onClick="s_color()">色の変更</BUTTON><BR><BR>
        38		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140"></CANVAS>
        39	</BODY>
        40	</HTML>
        					
        10 行目

          現在の色を保持するための変数.負の場合は赤,正の場合は緑を意味する.

        23 行目

          指定した領域(この場合は,キャンバス全体)をクリア

        24 行目

          現在のサブパスをリセットし,新しいサブパスを開始

        25 行目~ 28 行目

          円を塗りつぶす色を,変数 sw が負の場合は緑に,正の場合は赤に設定している.

        29 行目

          点 (70, 70) を中心とした半径 40 の円弧を 0 から 2π まで,時計回り( false )に描く

        30 行目

          サブパスを塗りつぶす.

        31 行目

          塗りつぶされている色を変更.

        37 行目

          このボタンをクリックすると,関数 s_color が呼ばれる.

          しかし,このままでは,CANVAS 上の特定の位置(この例の場合は,円)をクリックした時だけにある処理を行いたいような場合は,対応することができません.この問題は,CANVAS 要素に onClick 属性を付加し,クリックされたときの処理を行う関数 Click 内において,クリックされた位置と円の中心までの距離を Math オブジェクトのメソッド sqrt を使用して計算することによって解決できます.次に示す例では,CANVAS に描かれた円内をクリックした場合だけ,円の色が変わります.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>イベント処理( CANVAS 要素の属性)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			sw     = -1;
        11			x_base = -1;
        12			y_base = -1;
        13						// 初期設定と描画(ロード時)
        14			function draw()
        15			{
        16				canvas = document.getElementById('canvas_e');
        17				canvas.width  = 140;   // キャンバス要素の幅
        18				canvas.height = 140;   // キャンバス要素の高さ
        19				x_base = canvas.offsetLeft;   // キャンバスの左上のx座標
        20				y_base = canvas.offsetTop;   // キャンバスの左上のy座標
        21				ctx = canvas.getContext('2d');
        22				s_color();
        23			}
        24						// 描画(画像がクリックされた時)
        25			function s_color()
        26			{
        27				ctx.clearRect(0, 0, canvas.width, canvas.height);
        28				ctx.beginPath();
        29				if (sw < 0)
        30					ctx.fillStyle = "rgb(0, 255, 0)";
        31				else
        32					ctx.fillStyle = "rgb(255, 0, 0)";
        33				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
        34				ctx.fill();
        35				sw *= -1;
        36			}
        37						// クリックイベントの処理
        38			function Click(event)
        39			{
        40				let x_now = event.pageX - x_base;
        41				let y_now = event.pageY - y_base;
        42				let x1 = 70 - x_now;
        43				let y1 = 70 - y_now;
        44				let r  = Math.sqrt(x1 * x1 + y1 * y1);
        45				if (r < 40)
        46					s_color();
        47			}
        48		</SCRIPT>
        49	</HEAD>
        50	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        51		<H1>イベント処理( CANVAS 要素の属性)</H1>
        52		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140" onClick="Click(event)"></CANVAS>
        53	</BODY>
        54	</HTML>
        					
        11 行目~ 12 行目

          Window 上におけるキャンバスの位置(キャンバスの左上の座標)を保持するための変数

        19 行目~ 20 行目

          Window 上におけるキャンバスの位置(キャンバスの左上の座標)を取得

        40 行目~ 41 行目

          Window 上におけるマウスでクリックされた位置から,Window 上におけるキャンバスの位置を引き,キャンバス上におけるクリックされた位置を取得

        42 行目~ 44 行目

          円の中心からの距離を計算

        45 行目~ 46 行目

          上で計算した距離が円の半径より小さい場合は,色を変更する関数 s_color を呼ぶ.

        52 行目

          キャンバス内をクリックすると,関数 Click が呼ばれる.

          上に示した例においては,CANVAS 要素の onClick 属性を使用して,クリックイベントの処理を行っていましたが,以下に示す例においては(動作は上に示した例と同じ),イベント処理の基本において示した方法と同様,DOM のメソッド addEventListener を使用してイベント処理機能を追加しています.最初の段階からクリックイベントに対する処理を行うのではなく,途中からイベント処理を追加したいような場合はこの方法を使用する必要があります.その1その2との違いは,イベント処理メソッドを記述する場所の違いです.

          その1では,23 行目において,マウスでクリックされた( "click" )ときに処理を行う関数( Click,関数名は任意)を指定し,関数 Click 自体は,39 行目~ 49 行目に記述しています.しかし,その2では,24 行目~ 32 行目に,イベント処理を行う関数本体も記述しています.なお,当然のことながら,いずれの場合においても,54 行目,及び,51 行目の CANVAS 要素には,onClick 属性を記述していません.

        addEventListener の使用:その1

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>イベント処理( addEventListener 1)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			sw     = -1;
        11			x_base = -1;
        12			y_base = -1;
        13						// 初期設定と描画(ロード時)
        14			function draw()
        15			{
        16				canvas = document.getElementById('canvas_e');
        17				canvas.width  = 140;   // キャンバス要素の幅
        18				canvas.height = 140;   // キャンバス要素の高さ
        19				x_base = canvas.offsetLeft;   // キャンバスの左上のx座標
        20				y_base = canvas.offsetTop;   // キャンバスの左上のy座標
        21				ctx = canvas.getContext('2d');
        22				s_color();
        23				canvas.addEventListener("click", Click, false);   // クリックイベント
        24			}
        25						// イベント処理(画像がクリックされた時)
        26			function s_color()
        27			{
        28				ctx.clearRect(0, 0, canvas.width, canvas.height);
        29				ctx.beginPath();
        30				if (sw < 0)
        31					ctx.fillStyle = "rgb(0, 255, 0)";
        32				else
        33					ctx.fillStyle = "rgb(255, 0, 0)";
        34				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
        35				ctx.fill();
        36				sw *= -1;
        37			}
        38						// クリックイベントの処理
        39			function Click(event)
        40	//		Click = function(event)   // この記述でも良い
        41			{
        42				let x_now = event.pageX - x_base;
        43				let y_now = event.pageY - y_base;
        44				let x1 = 70 - x_now;
        45				let y1 = 70 - y_now;
        46				let r  = Math.sqrt(x1 * x1 + y1 * y1);
        47				if (r < 40)
        48					s_color();
        49			}
        50		</SCRIPT>
        51	</HEAD>
        52	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        53		<H1>イベント処理( addEventListener 1)</H1>
        54		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140"></CANVAS>
        55	</BODY>
        56	</HTML>
        					

        addEventListener の使用:その2

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>イベント処理( addEventListener 2)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			sw     = -1;
        11			x_base = -1;
        12			y_base = -1;
        13						// 初期設定と描画(ロード時)
        14			function draw()
        15			{
        16				canvas = document.getElementById('canvas_e');
        17				canvas.width  = 140;   // キャンバス要素の幅
        18				canvas.height = 140;   // キャンバス要素の高さ
        19				x_base = canvas.offsetLeft;   // キャンバスの左上のx座標
        20				y_base = canvas.offsetTop;   // キャンバスの左上のy座標
        21				ctx = canvas.getContext('2d');
        22				s_color();
        23						// クリックイベントの処理
        24				canvas.addEventListener("click", function(event) {
        25					let x_now = event.pageX - x_base;
        26					let y_now = event.pageY - y_base;
        27					let x1 = 70 - x_now;
        28					let y1 = 70 - y_now;
        29					let r  = Math.sqrt(x1 * x1 + y1 * y1);
        30					if (r < 40)
        31						s_color();
        32				}, false);
        33			}
        34						// イベント処理(画像がクリックされた時)
        35			function s_color()
        36			{
        37				ctx.clearRect(0, 0, canvas.width, canvas.height);
        38				ctx.beginPath();
        39				if (sw < 0)
        40					ctx.fillStyle = "rgb(0, 255, 0)";
        41				else
        42					ctx.fillStyle = "rgb(255, 0, 0)";
        43				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
        44				ctx.fill();
        45				sw *= -1;
        46			}
        47		</SCRIPT>
        48	</HEAD>
        49	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        50		<H1>イベント処理( addEventListener 2)</H1>
        51		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140"></CANVAS>
        52	</BODY>
        53	</HTML>
        					

      3. お絵かき

          イベント処理のあと一つの例として,簡単なお絵かきソフトを示します.最初の例は CANVAS 要素の属性を利用した場合,2 番目の例,及び,3 番目の例は,addEventListener を利用した場合です.いずれの例も,マウスでドラッグすることによって簡単な図を描くことができます.

        CANVAS 要素の属性の使用

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>お絵かき( CANVAS 要素の属性)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
        09			x_old  = -1;
        10			y_old  = -1;
        11			x_base = -1;
        12			y_base = -1;
        13			ctx    = null;
        14			function draw() {
        15				let canvas1 = document.getElementById('canvas_e');
        16				canvas1.width  = 200;   // キャンバス要素の幅
        17				canvas1.height = 150;   // キャンバス要素の高さ
        18				x_base = canvas1.offsetLeft;   // キャンバスの左上のx座標
        19				y_base = canvas1.offsetTop;   // キャンバスの左上のy座標
        20				ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
        21				ctx.lineWidth = 5;   // 線の太さ
        22			}
        23						// イベント処理
        24			function m_move(event) {   // マウス移動イベント
        25				if (navigator.appName.indexOf("Explorer") >= 0) {
        26					x_now = event.x - x_base;
        27					y_now = event.y - y_base;
        28				}
        29				else {
        30					x_now = event.pageX - x_base;
        31					y_now = event.pageY - y_base;
        32				}
        33				if (blush) {
        34					ctx.beginPath();
        35					ctx.moveTo(x_old, y_old);
        36					ctx.lineTo(x_now, y_now);
        37					ctx.stroke();
        38				}
        39				x_old = x_now;
        40				y_old = y_now;
        41			}
        42			function m_down(event) {   // マウスボタン押下イベント
        43				if (!blush) {
        44					if (navigator.appName.indexOf("Explorer") >= 0) {
        45						x_old = event.x - x_base;
        46						y_old = event.y - y_base;
        47					}
        48					else {
        49						x_old = event.pageX - x_base;
        50						y_old = event.pageY - y_base;
        51					}
        52					blush = true;   // 描ける状態
        53				}
        54			}
        55			function m_up(event) {   // マウスボタン離されたイベント
        56				blush = false;   // 描けない状態
        57			}
        58		</SCRIPT>
        59	</HEAD>
        60	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        61		<H1>お絵かき( CANVAS 要素の属性)</H1>
        62		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="200" HEIGHT="150" onMouseMove="m_move(event)" onMouseDown="m_down(event)" onMouseUp="m_up(event)"></CANVAS>
        63	</BODY>
        64	</HTML>
        					
        08 行目

          お絵かき用ブラシの状態.初期状態として絵を描けない状態に設定.

        09 行目~ 10 行目

          一つ前の点の座標

        21 行目

          線の太さを 5 ピクセルに設定

        25 行目~ 32 行目

          マウスの現在位置( x_now,y_now )を取得.なお,25 行目~ 28 行目は,ブラウザが IE である場合の処理である.

        33 行目~ 38 行目

          絵を描ける状態のときは,一つ前の点と現在位置を結ぶ直線を描く.

        39 行目~ 40 行目

          一つ前の点を,現在位置で置き換える.

        42 行目~ 54 行目

          マウスボタンが押し下げられたときの処理である.絵を描けない状態のときは,一つ前の点に現在位置を保存し,絵を描ける状態に変更する( 52 行目).

        55 行目~ 57 行目

          マウスボタンが離されたときの処理であり,絵を描けない状態に変更する.

        62 行目

          onMouseMove 属性(関数 m_move ),onMouseDown 属性(関数 m_down ),及び,onMouseUp 属性(関数 m_up )を指定している.

        addEventListener の使用:その1

        <!DOCTYPE HTML>
        <HTML>
        <HEAD>
        	<TITLE>お絵かき( addEventListener 1)</TITLE>
        	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        	<SCRIPT TYPE="text/javascript">
        		blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
        		x_old  = -1;
        		y_old  = -1;
        		x_base = -1;
        		y_base = -1;
        		ctx    = null;
        					// メイン
        		function draw() {
        			let canvas1 = document.getElementById('canvas_e');   // キャンバス要素を生成
        			canvas1.width  = 200;   // キャンバス要素の幅
        			canvas1.height = 150;   // キャンバス要素の高さ
        			x_base = canvas1.offsetLeft;   // キャンバスの左上のx座標
        			y_base = canvas1.offsetTop;   // キャンバスの左上のy座標
        			ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
        			ctx.lineWidth = 5;   // 線の太さ
        							// イベントリスナの追加
        			canvas1.addEventListener("mousemove", Move, false);   // マウス移動イベント
        			canvas1.addEventListener("mousedown", Down, false);   // マウスボタン押下イベント
        			canvas1.addEventListener("mouseup", Up, false);   // マウスボタン離されたイベント
        		}
        					// マウス移動イベント
        		function Move(event)
        //		Move = function(event)   // この記述でも良い
        		{
        			x_now = event.pageX - x_base;
        			y_now = event.pageY - y_base;
        			if (blush) {
        				ctx.beginPath();
        				ctx.moveTo(x_old, y_old);
        				ctx.lineTo(x_now, y_now);
        				ctx.stroke();
        			}
        			x_old = x_now;
        			y_old = y_now;
        		}
        					// マウスボタン押下イベント
        		function Down(event)
        //		Down = function(event)   // この記述でも良い
        		{
        			if (!blush) {
        				x_old = event.pageX - x_base;
        				y_old = event.pageY - y_base;
        				blush = true;   // 描ける状態
        			}
        		}
        					// マウスボタン離されたイベント
        		function Up(event)
        //		Up = function(event)   // この記述でも良い
        		{
        			blush = false;   // 描けない状態
        		}
        	</SCRIPT>
        </HEAD>
        <BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        	<H1>お絵かき( addEventListener 1)</H1>
        	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="200" HEIGHT="150"></CANVAS>
        </BODY>
        </HTML>
        					

        addEventListener の使用:その2

        <!DOCTYPE HTML>
        <HTML>
        <HEAD>
        	<TITLE>CANVAS の例</TITLE>
        	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        	<SCRIPT TYPE="text/javascript">
        		blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
        		x_old  = -1;
        		y_old  = -1;
        		x_base = -1;
        		y_base = -1;
        		function draw() {
        			let canvas1 = document.getElementById('canvas_e');   // キャンバス要素を生成
        			canvas1.width  = 200;   // キャンバス要素の幅
        			canvas1.height = 150;   // キャンバス要素の高さ
        			x_base  = canvas1.offsetLeft;   // キャンバスの左上のx座標
        			y_base  = canvas1.offsetTop;   // キャンバスの左上のy座標
        			let ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
        			ctx.lineWidth = 5;   // 線の太さ
        					// イベント処理(イベントリスナの追加と処理)
        			canvas1.addEventListener("mousemove", function(event) {   // マウス移動イベント
        				x_now = event.pageX - x_base;
        				y_now = event.pageY - y_base;
        				if (blush) {
        					ctx.beginPath();
        					ctx.moveTo(x_old, y_old);
        					ctx.lineTo(x_now, y_now);
        					ctx.stroke();
        				}
        				x_old = x_now;
        				y_old = y_now;
        			}, false);
        			canvas1.addEventListener("mousedown", function(event) {   // マウスボタン押下イベント
        				if (!blush) {
        					x_old = event.pageX - x_base;
        					y_old = event.pageY - y_base;
        					blush = true;   // 描ける状態
        				}
        			}, false);
        			canvas1.addEventListener("mouseup", function(event) {   // マウスボタン離されたイベント
        				blush = false;   // 描けない状態
        			}, false);
        		}
        	</SCRIPT>
        </HEAD>
        <BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        	<H1>イベント処理(お絵かき)</H1>
        	<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="200" HEIGHT="150"></CANVAS>
        </BODY>
        </HTML>
        					

          以下に示す例は,上で示した例にメニューを付加し,多少お絵かきソフトらしく修正したものです.始点と終点をクリックすることによって直線も描くことができます.また,線の太さや色の変更も可能です.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>CANVAS の例</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
        009			type   = 0;   // 0: 自由曲線,1: 直線
        010			img    = null;   // CANVAS 全体の ImageData オブジェクト
        011			x_old  = -1;
        012			y_old  = -1;
        013			x_base = -1;
        014			y_base = -1;
        015			ctx    = null;
        016			function draw() {
        017				let canvas1 = document.getElementById('canvas_e');
        018				canvas1.width  = 360;   // キャンバス要素の幅
        019				canvas1.height = 300;   // キャンバス要素の高さ
        020				x_base = canvas1.offsetLeft;   // キャンバスの左上のx座標
        021				y_base = canvas1.offsetTop;   // キャンバスの左上のy座標
        022				ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
        023				ctx.lineWidth = 5;   // 線の太さ
        024				ctx.strokeStyle = "rgb(255, 0, 0)";   // 線の色
        025			}
        026						// イベント処理
        027			function m_move(event) {   // マウス移動イベント
        028								// 自由曲線の描画
        029				if (type == 0) {
        030					x_now = event.pageX - x_base;
        031					y_now = event.pageY - y_base;
        032					if (blush) {
        033						ctx.beginPath();
        034						ctx.moveTo(x_old, y_old);
        035						ctx.lineTo(x_now, y_now);
        036						ctx.stroke();
        037					}
        038					x_old = x_now;
        039					y_old = y_now;
        040				}
        041			}
        042			function m_down(event) {   // マウスボタン押下イベント
        043								// 自由曲線の描画
        044				if (type == 0) {
        045					if (!blush) {
        046						x_old = event.pageX - x_base;
        047						y_old = event.pageY - y_base;
        048						blush = true;   // 描ける状態
        049					}
        050				}
        051								// 直線の描画
        052				else {
        053					if (!blush) {
        054						img = ctx.getImageData(0, 0, 360, 300);
        055						x_old = event.pageX - x_base;
        056						y_old = event.pageY - y_base;
        057						let o_l = ctx.lineWidth;
        058						let o_c = ctx.strokeStyle;
        059						ctx.lineWidth = 1;
        060						ctx.strokeStyle = "rgb(0, 0, 0)";
        061						ctx.beginPath();
        062						ctx.moveTo(x_old-10, y_old);
        063						ctx.lineTo(x_old+10, y_old);
        064						ctx.moveTo(x_old, y_old-10);
        065						ctx.lineTo(x_old, y_old+10);
        066						ctx.stroke();
        067						ctx.lineWidth = o_l;
        068						ctx.strokeStyle = o_c;
        069						blush = true;
        070					}
        071					else {
        072						ctx.putImageData(img, 0, 0);
        073						let x_new = event.pageX - x_base;
        074						let y_new = event.pageY - y_base;
        075						ctx.beginPath();
        076						ctx.moveTo(x_old, y_old);
        077						ctx.lineTo(x_new, y_new);
        078						ctx.stroke();
        079						blush = false;
        080					}
        081				}
        082			}
        083			function m_up(event) {   // マウスボタン離されたイベント
        084								// 自由曲線の描画
        085				if (type == 0)
        086					blush = false;   // 描けない状態
        087			}
        088			function c_type(sw) {   // タイプの変更
        089				if (!blush)
        090					type = sw;
        091			}
        092			function c_color(sw) {   // 線の色の変更
        093				if (sw < 0)
        094					ctx.strokeStyle = "rgb(255, 0, 0)";
        095				else
        096					ctx.strokeStyle = "rgb(0, 255, 0)";
        097			}
        098			function c_width(sw) {   // 線の太さの変更
        099				if (sw < 0)
        100					ctx.lineWidth = 1;
        101				else
        102					ctx.lineWidth = 5;
        103			}
        104		</SCRIPT>
        105	</HEAD>
        106	<BODY CLASS="white" STYLE="text-align: center; background-color: #ccffcc" onLoad="draw()">
        107		<H1>イベント処理(お絵かき)</H1>
        108		<DIV STYLE="width: 500px; height: 300px; background-color: #eeffee; margin-right: auto; margin-left: auto">
        109			<DIV ID="control" STYLE="text-align: center; background-color: #eeffee; width: 140px; height: 300px; float: left">
        110				<BUTTON STYLE="width: 50px" onClick="c_type(0)">曲線</BUTTON>
        111				<BUTTON STYLE="width: 50px" onClick="c_type(1)">直線</BUTTON>
        112				<BUTTON STYLE="width: 50px; background-color: #ff0000" onClick="c_color(-1)">赤</BUTTON>
        113				<BUTTON STYLE="width: 50px; background-color: #00ff00" onClick="c_color(1)">緑</BUTTON>
        114				<BUTTON STYLE="width: 50px" onClick="c_width(-1)">細い</BUTTON>
        115				<BUTTON STYLE="width: 50px" onClick="c_width(1)">太い</BUTTON>
        116			</DIV>
        117			<CANVAS ID="canvas_e" STYLE="background-color: #ffffff; float: right" WIDTH="360" HEIGHT="300" onMouseMove="m_move(event)" onMouseDown="m_down(event)" onMouseUp="m_up(event)"></CANVAS>
        118		</DIV>
        119	</BODY>
        120	</HTML>
        					
        009 行目

          自由曲線を描くモードか,直線を描くモードかを設定する変数

        010 行目

          CANVAS 全体を ImageData オブジェクトとして保存するための変数

        023 行目~ 024 行目

          線の太さと色の初期設定

        053 行目~ 070 行目

          直線を描くには,その始点と終点を指定する必要がある.この箇所は,マウスボタンのクリックにより始点を指定したときの処理であり,直線を描くモードで,かつ,絵を描けない状態にあるとき実行される.
        • 054 行目: 現時点における描画状態を ImageData オブジェクトに保存
        • 057 行目~ 058 行目: 現在の線の太さと色を保存
        • 059 行目~ 066 行目: 黒い細い線で始点に十字を描く.
        • 067 行目~ 068 行目: 現在の線の太さと色を復元
        • 069 行目: 絵を描けるモードに変更する

        071 行目~ 080 行目

          直線を描くモードにおいて,マウスボタンのクリックにより終点を指定したときの処理である.
        • 072 行目: キャンバスを,直線の始点である十字を描く前の状態に戻す.
        • 073 行目~ 078 行目: 視点から現在位置までの直線を描く
        • 079 行目: 絵を描けないモードに変更する

        088 行目~ 091 行目

          110 行目,または,111 行目のボタンがクリックされたときの処理であり,自由曲線を描くモード,または,直線を描くモードに変更する.

        092 行目~ 097 行目

          112 行目,または,113 行目のボタンがクリックされたときの処理であり,線の色を変更する.

        098 行目~ 103 行目

          114 行目,または,115 行目のボタンがクリックされたときの処理であり,線の太さを変更する.

  2. アニメーション

    1. アニメーションの基本(円の描画)

        CANVAS 要素を使用してアニメーションを作成するためには,window オブジェクトの setInterval メソッド,または,setTimeout メソッドを使用します.ここで示すアニメーションでは,半径の異なる円を順に描き,10 個の円を描き終わると再び最初から繰り返し,さらに,この繰り返しを 5 回実行すると停止します.まず,最初に,setInterval メソッドを利用した例を示します.

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>アニメーション( setInterval )</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
      07		<SCRIPT TYPE="text/javascript">
      08			count1  = 0;   // 10 個の円を描くためのカウンタ
      09			count2  = 0;   // 5 回繰り返すためのカウンタ
      10			r       = 10;   // 円の半径の初期値
      11			canvas  = null;
      12			ctx     = null;
      13			timerID = -1;
      14						// 開始
      15			function start()
      16			{
      17				canvas  = document.getElementById('canvas_e');   // キャンバス要素の取得
      18				ctx     = canvas.getContext('2d');   // キャンバスからコンテキストを取得
      19				timerID = setInterval('draw()',100);
      20			}
      21						// 描画
      22			function draw() {
      23				count1++;
      24				if (count1 > 10) {
      25					count2++;
      26					if (count2 > 4)
      27						stop();
      28					else {
      29						r      = 10;
      30						count1 = 1;
      31						ctx.clearRect(0, 0, canvas.width, canvas.height);
      32					}
      33				}
      34				ctx.beginPath();
      35				ctx.arc(0, 0, r, Math.PI*1.5, Math.PI*2, true);
      36				ctx.stroke();
      37				r = 1.5 * r;
      38			}
      39						// 停止
      40			function stop()
      41			{
      42				clearInterval(timerID);
      43				ctx.clearRect(0, 0, canvas.width, canvas.height);
      44				timerID = -1;
      45			}
      46		</SCRIPT>
      47	</HEAD>
      48	<BODY CLASS="eeffee" onLoad="start()">
      49		<H1>アニメーション( setInterval )</H1>
      50		<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="250" HEIGHT="150"></CANVAS>
      51	</BODY>
      52	</HTML>
      				
      19 行目

        100 ms 毎に,関数 draw が実行されるように設定.なお,この関数 start は,48 行目の設定により,ページがロードされると実行される.

      23 行目

        描いた円の数を示すカウンタを増加させる

      24 行目~ 33 行目

        描いた円の数が 10 個以上になった場合の処理である
      • 25 行目: 繰り返しの回数を示すカウンタを増加させる
      • 26 行目~ 27 行目: 繰り返し回数が 4 を越えた場合は,関数 stop を呼び,描画を停止する.
      • 29 行目~ 30 行目: 半径と描いた円の数を示すカウンタの初期設定
      • 31 行目: キャンバスをクリアする

      34 行目~ 36 行目

        点 (0, 0) を中心とした半径 r の円弧を 1.5π から 2π まで,反時計回り( true )に描く

      37 行目

        円の半径を 1.5 倍する.

      40 行目~ 45 行目

        描画を停止するための関数であり,タイマーを停止( 42 行目)し,キャンバス領域をクリア( 43 行目)している.

        次に示すのは,同じアニメーションに対して,setTimeout メソッドを利用した例です.setInterval メソッドを利用した方法と異なるのは,19 行目,38 行目,39 行目,及び,44 行目だけです.

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>アニメーション( setTimeout )</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
      07		<SCRIPT TYPE="text/javascript">
      08			count1  = 0;   // 10 個の円を描くためのカウンタ
      09			count2  = 0;   // 5 回繰り返すためのカウンタ
      10			r       = 10;   // 円の半径の初期値
      11			canvas  = null;
      12			ctx     = null;
      13			timerID = -1;
      14						// 開始
      15			function start()
      16			{
      17				canvas  = document.getElementById('canvas_e');   // キャンバス要素の取得
      18				ctx     = canvas.getContext('2d');   // キャンバスからコンテキストを取得
      19				timerID = setTimeout("draw()", 100);
      20			}
      21						// 描画
      22			function draw() {
      23				count1++;
      24				if (count1 > 10) {
      25					count2++;
      26					if (count2 > 4)
      27						stop();
      28					else {
      29						r      = 10;
      30						count1 = 1;
      31						ctx.clearRect(0, 0, canvas.width, canvas.height);
      32					}
      33				}
      34				ctx.beginPath();
      35				ctx.arc(0, 0, r, Math.PI*1.5, Math.PI*2, true);
      36				ctx.stroke();
      37				r = 1.5 * r;
      38				clearTimeout(timerID);
      39				timerID = setTimeout("draw()", 100);
      40			}
      41				// 停止
      42			function stop()
      43			{
      44				clearTimeout(timerID);
      45				ctx.clearRect(0, 0, canvas.width, canvas.height);
      46				timerID = -1;
      47			}
      48		</SCRIPT>
      49	</HEAD>
      50	<BODY CLASS="eeffee" onLoad="start()">
      51		<H1>アニメーション( setTimeout )</H1>
      52		<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="250" HEIGHT="150"></CANVAS>
      53	</BODY>
      54	</HTML>
      				

    2. アニメーションの例

      1. ランニング(複数の外部画像の利用)

          このアニメーションでは,複数の画像ファイルを読み込み,それらを適切な順序で,適切な位置に表示させることによってアニメーションを作成しています.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>ランニング</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			x          = 0;   // 描画する画像位置の x 座標
        009			y          = 0;   // 描画する画像位置の y 座標
        010			now_id     = 0;   // 描画する画像番号
        011			canvas     = null;
        012			ctx        = null;
        013			img        = new Array();
        014			img[0]     = new Image();
        015			img[0].src = "fig0.gif";
        016			img[1]     = new Image();
        017			img[1].src = "fig1.gif";
        018			img[2]     = new Image();
        019			img[2].src = "fig2.gif";
        020			img[3]     = new Image();
        021			img[3].src = "fig3.gif";
        022			img[4]     = new Image();
        023			img[4].src = "fig4.gif";
        024			img[5]     = new Image();
        025			img[5].src = "fig5.gif";
        026						// 開始
        027			function start()
        028			{
        029				canvas        = document.getElementById('canvas_e');
        030				canvas.width  = 600;   // キャンバス要素の幅
        031				canvas.height = 400;   // キャンバス要素の高さ
        032				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        033				timerID       = setInterval('draw()', 100);
        034			}
        035						// 描画
        036			function draw() {
        037				ctx.clearRect(0, 0, canvas.width, canvas.height);
        038				if (now_id == 0) {
        039					x = -20;
        040					y = 200 - 238 / 2;
        041				}
        042				else if (now_id == 1) {
        043					x = 5;
        044					y = 200 - 249 / 2;
        045				}
        046				else if (now_id == 2) {
        047					x = 70;
        048					y = 200 - 258 / 2;
        049				}
        050				else if (now_id == 3) {
        051					x = 140;
        052					y = 200 - 258 / 2;
        053				}
        054				else if (now_id == 4) {
        055					x = 150;
        056					y = 200 - 258 / 2;
        057				}
        058				else if (now_id == 5) {
        059					x = 160;
        060					y = 200 - 247 / 2;
        061				}
        062				else if (now_id == 6) {
        063					x = 200;
        064					y = 200 - 238 / 2;
        065				}
        066				else if (now_id == 7) {
        067					x = 225;
        068					y = 200 - 249 / 2;
        069				}
        070				else if (now_id == 8) {
        071					x = 290;
        072					y = 200 - 258 / 2;
        073				}
        074				else if (now_id == 9) {
        075					x = 360;
        076					y = 200 - 258 / 2;
        077				}
        078				else if (now_id == 10) {
        079					x = 370;
        080					y = 200 - 258 / 2;
        081				}
        082				else if (now_id == 11) {
        083					x = 380;
        084					y = 200 - 247 / 2;
        085				}
        086				else if (now_id == 12) {
        087					x = 420;
        088					y = 200 - 238 / 2;
        089				}
        090				else if (now_id == 13) {
        091					x = 445;
        092					y = 200 - 249 / 2;
        093				}
        094				else if (now_id == 14) {
        095					x = 510;
        096					y = 200 - 258 / 2;
        097				}
        098				else if (now_id == 15) {
        099					x = 580;
        100					y = 200 - 258 / 2;
        101				}
        102				else if (now_id == 16) {
        103					x = 590;
        104					y = 200 - 258 / 2;
        105				}
        106				else {
        107					x = 600;
        108					y = 200 - 247 / 2;
        109				}
        110				ctx.drawImage(img[now_id%6], x, y);
        111				now_id++;
        112				if (now_id > 17)
        113					now_id = 0;
        114			}
        115		</SCRIPT>
        116	</HEAD>
        117	<BODY CLASS="eeffee" onLoad="start()">
        118		<H1>ランニング(複数の外部画像)</H1>
        119		<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="600" HEIGHT="400"></CANVAS>
        120	</BODY>
        121	</HTML>
        					
        013 行目~ 025 行目

          6 個の Image オブジェクトを記憶する配列を定義し,画像 fig0.gif ~ fig5.gif を記憶している.

        033 行目

          100 ms 毎に関数 draw が実行されるように設定している.

        037 行目

          キャンバス画面のクリア

        038 行目~ 109 行目

          now_id の値によって,画像を描くべき位置を設定している.

        110 行目

          画像の描画.6 枚ごとに同じ画像を繰り返している.

        111 行目~ 113 行目

          画像番号を増加させ,その値が 17 より大きくなった場合は,0 に戻している.

      2. アニメーション+イベント処理(外部画像)

          このアニメーションでは,1 つの画像ファイルを読み込み,それの表示位置を適切に制御することによってアニメーションを作成しています.また,表示された円をクリックすると動きが止まり,再びクリックすると,再度動き出します.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>CANVAS の例</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			g      = 9.8;   // y 軸方向の加速度
        09			v0     = 0;   // y 軸方向の初期速度
        10			v      = 0;   // y 軸方向の現在速度
        11			t      = 0;   // 時間の初期値
        12			h0     = 0;   // ボールの初期位置の y 座標(上が正,初期高さ)
        13			x      = 0;   // ボールの現在位置の x 座標
        14			y      = 0;   // ボールの現在位置の y 座標(上が正)
        15			sw     = 1;   // ボールの状態( 0:停止している,1:動いている)
        16			canvas = null;
        17			ctx    = null;
        18			img    = null;
        19			x_base = -1;
        20			y_base = -1;
        21						// 開始
        22			function start()
        23			{
        24				canvas        = document.getElementById('canvas_e');
        25				canvas.width  = 600;   // キャンバス要素の幅
        26				canvas.height = 400;   // キャンバス要素の高さ
        27				h0            = canvas.height;   // ボールの初期高さの設定
        28				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        29				x_base        = canvas.offsetLeft;   // キャンバスの左上のx座標
        30				y_base        = canvas.offsetTop;   // キャンバスの左上のy座標
        31				img           = new Image();
        32				img.src       = "ball.gif";
        33				timerID       = setInterval('draw()', 33);
        34				canvas.addEventListener("click", Click);   // クリックイベント
        35			}
        36						// 描画
        37			function draw() {
        38				if (x < canvas.width + 40 && sw > 0) {
        39					ctx.clearRect(0, 0, canvas.width, canvas.height);
        40					x += 1.5;
        41					t += 0.1;
        42					v  = -g * t + v0;
        43					y  = canvas.height - (-0.5 * g * t * t + v0 * t + h0);
        44					if (y >= canvas.height - 40 && v < 0) {
        45						y  = canvas.height - 40;
        46						v0 = -0.8 * v;
        47						h0 = 40;
        48						t  = 0;
        49					}
        50					ctx.drawImage(img, x-40, y-40);
        51				}
        52			}
        53						// クリックイベント
        54			function Click(event)
        55			{
        56				let x_now = event.pageX - x_base;
        57				let y_now = event.pageY - y_base;
        58				let x1    = x - x_now;
        59				let y1    = y - y_now;
        60				let r     = Math.sqrt(x1 * x1 + y1 * y1);
        61				if (r < 40) {
        62					if (sw > 0)
        63						sw = 0;
        64					else
        65						sw = 1;
        66				}
        67			}
        68		</SCRIPT>
        69	</HEAD>
        70	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        71		<H1>アニメーション+イベント処理</H1>
        72		<H3>(円をクリックすると止まり,再度クリックすると動き出す)</H3>
        73		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="400"></CANVAS>
        74	</BODY>
        75	</HTML>
        					
        31 行目~ 32 行目

          Image オブジェクトを生成し,その src プロパティに ball.gif を指定している(画像の読み込み).

        34 行目

          画面をクリックすると,関数 Click を呼ぶように設定している.

        38 行目~ 51 行目

          ボールが動いており( sw > 0 ),かつ,キャンバス内に存在したときの処理である.
        • 39 行目: キャンバスをクリアする
        • 40 行目: ボールの x 座標の変更( 1.5 ピクセル / 33 ms )
        • 41 行目: 時間の変更( 0.1 秒 / 33 ms )
        • 42 行目: ボールの速度の変更
        • 43 行目: ボールの y 座標の変更.画面座標に合うように座標変換も行っている.
        • 44 行目~ 49 行目: ボールが地面に落ちたときの跳ね返り処理を行っている.その際,速度が 0.8 倍される.
        • 50 行目: ボールの描画

        54 行目~ 67 行目

          34 行目に対応した処理であり,画面をクリックすると呼ばれる.ただし,クリックした場所がボールの外側である場合は何も行われない.ボールの内側であるときは,ボールが動いている場合は停止,停止している場合は再び動かす.

      3. アニメーション+イベント処理(描画)

          このアニメーションは,基本的に上と同じアニメーションですが,画像ファイルを使用せず,円を描いています.先のプログラムとの基本的な違いは,外部画像を読み込まず,46 行目~ 50 行目において,円を描いている点だけです.ただし,イベント処理を行う関数を,73 行目の CANVAS 要素の onClick 属性によって設定しています.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>CANVAS の例</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			g      = 9.8;   // y 軸方向の加速度
        09			v0     = 0;   // y 軸方向の初期速度
        10			v      = 0;   // y 軸方向の現在速度
        11			t      = 0;   // 時間の初期値
        12			h0     = 0;   // ボールの初期位置の y 座標(上が正,初期高さ)
        13			x      = 0;   // ボールの現在位置の x 座標
        14			y      = 0;   // ボールの現在位置の y 座標(上が正)
        15			sw     = 1;   // ボールの状態( 0:停止している,1:動いている)
        16			canvas = null;
        17			ctx    = null;
        18			x_base = -1;
        19			y_base = -1;
        20						// 開始
        21			function start()
        22			{
        23				canvas        = document.getElementById('canvas_e');
        24				canvas.width  = 600;   // キャンバス要素の幅
        25				canvas.height = 400;   // キャンバス要素の高さ
        26				h0            = canvas.height;   // ボールの初期高さの設定
        27				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        28				x_base        = canvas.offsetLeft;   // キャンバスの左上のx座標
        29				y_base        = canvas.offsetTop;   // キャンバスの左上のy座標
        30				timerID       = setInterval('draw()', 33);
        31			}
        32						// 描画
        33			function draw() {
        34				if (x < canvas.width + 40 && sw > 0) {
        35					ctx.clearRect(0, 0, canvas.width, canvas.height);
        36					x += 1.5;
        37					t += 0.1;
        38					v  = -g * t + v0;
        39					y  = canvas.height - (-0.5 * g * t * t + v0 * t + h0);
        40					if (y >= canvas.height - 40 && v < 0) {
        41						y  = canvas.height - 40;
        42						v0 = -0.8 * v;
        43						h0 = 40;
        44						t  = 0;
        45					}
        46					ctx.strokeStyle = 'rgb(0, 255, 0)';
        47					ctx.fillStyle   = 'rgb(0, 255, 0)';
        48					ctx.beginPath();
        49					ctx.arc(x, y, 40, 0, Math.PI*2, false);
        50					ctx.fill();
        51				}
        52			}
        53						// クリックイベント
        54			function Click(event)
        55			{
        56				let x_now = event.pageX - x_base;
        57				let y_now = event.pageY - y_base;
        58				let x1    = x - x_now;
        59				let y1    = y - y_now;
        60				let r     = Math.sqrt(x1 * x1 + y1 * y1);
        61				if (r < 40) {
        62					if (sw > 0)
        63						sw = 0;
        64					else
        65						sw = 1;
        66				}
        67			}
        68		</SCRIPT>
        69		</HEAD>
        70	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        71		<H1>アニメーション+イベント処理</H1>
        72		<H3>(円をクリックすると止まり,再度クリックすると動き出す)</H3>
        73		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="400" onClick="Click(event)"></CANVAS>
        74	</BODY>
        75	</HTML>
        					

      4. ピクセル値の操作

          ピクセル値を直接操作し,それを画像に変換し,表示位置を変化させることによってもアニメーションを作成することができます.最初の例は,描画の基本の節で説明した矩形を左から右に移動させているだけのものです. .

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>簡単な例(ピクセル操作)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas  = null;
        09			ctx     = null;
        10			im      = null;
        11			timerID = -1;
        12			x       = 0;   // 矩形の初期位置の x 座標
        13			y       = 30;   // 矩形の初期位置の y 座標
        14						// 開始
        15			function start() {
        16				canvas = document.getElementById('canvas_e');
        17				canvas.width  = 420;   // キャンバス要素の幅
        18				canvas.height = 140;   // キャンバス要素の高さ
        19				ctx = canvas.getContext('2d');
        20						// ピクセル値の操作
        21				let wid = 80;
        22				let hei = 80;
        23				im  = ctx.createImageData(wid, hei);
        24				for (let i1 = 0; i1 < hei/2; i1++) {
        25					for (let i2 = 0; i2 < wid; i2++) {
        26						let k = 4 * (wid * i1 + i2);
        27						im.data[k]   = 0x00;
        28						im.data[k+1] = 0xff;
        29						im.data[k+2] = 0x00;
        30						im.data[k+3] = 0xff;   // 透明度
        31					}
        32				}
        33				for (let i1 = hei/2; i1 < hei; i1++) {
        34					for (let i2 = 0; i2 < wid; i2++) {
        35						let k = 4 * (wid * i1 + i2);
        36						im.data[k]   = 0x00;
        37						im.data[k+1] = 0x00;
        38						im.data[k+2] = 0xff;
        39						im.data[k+3] = 0xff;   // 透明度
        40					}
        41				}
        42				timerID = setInterval('draw()',100);
        43			}
        44						// 描画
        45			function draw() {
        46				ctx.clearRect(0, 0, canvas.width, canvas.height);
        47				ctx.putImageData(im, x, y);
        48				x += 5;
        49				if (x > canvas.width-80)
        50					stop();
        51			}
        52						// 停止
        53			function stop()
        54			{
        55				clearInterval(timerID);
        56				timerID = -1;
        57			}
        58		</SCRIPT>
        59	</HEAD>
        60	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        61		<H1>簡単な例(ピクセル操作)</H1>
        62		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="420" HEIGHT="140"></CANVAS>
        63	</BODY>
        64	</HTML>
        					
        21 行目~ 23 行目

          幅 80 ピクセル,高さ 80 ピクセルの ImageData オブジェクトを生成.

        24 行目~ 32 行目

          ImageData オブジェクトの上半分を緑に設定.

        33 行目~ 41 行目

          ImageData オブジェクトの下半分を青に設定.

        46 行目

          キャンバスをクリア.

        47 行目

          ImageData オブジェクトを描画

        48 行目~ 50 行目

          矩形の x 座標を変更し,矩形がキャンバスの右端に到達した場合はアニメーションを終了(関数 stop を呼ぶ)

          次の例は,もう少し複雑な例です.花火と同じような情景を描いています.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>花火(ピクセル操作)</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas = null;
        009			ctx    = null;
        010			max    = 20;   // 花火の数
        011			m_pr   = 7;   // 打ち上げ間隔の最大値
        012			m_cl   = 10;   // 花火の色の最大値,花火の輪の数
        013			f_l    = 300;   // 花火の直径
        014			size   = 0;   // ImageData オブジェクトの大きさ
        015			count  = 0;   // カウンタ
        016			next   = 0;   // 次の打ち上げ時期
        017			x      = new Array();   // 花火のx座標
        018			y      = new Array();   // 花火のy座標
        019			cl     = new Array();   // 花火の色
        020			k      = new Array();   // 花火の状態
        021								   // (-1:打ち上げ前,0:打ち上げ当初,>0:描いた輪の数)
        022			for (let i1 = 0; i1 < max; i1++)
        023				k[i1] = -1;
        024			color = new Array;
        025			for (let i1 = 0; i1 < m_cl; i1++)
        026				color[i1] = new Array;
        027			color[0][0] = 0xff;   // 赤
        028			color[0][1] = 0x00;   // 緑
        029			color[0][2] = 0x00;   // 青
        030			color[0][3] = 0xff;   // 透明度
        031			color[1][0] = 0x00;
        032			color[1][1] = 0xff;
        033			color[1][2] = 0x00;
        034			color[1][3] = 0xff;
        035			color[2][0] = 0x00;
        036			color[2][1] = 0x00;
        037			color[2][2] = 0xff;
        038			color[2][3] = 0xff;
        039			color[3][0] = 0xff;
        040			color[3][1] = 0xff;
        041			color[3][2] = 0x00;
        042			color[3][3] = 0xff;
        043			color[4][0] = 0xff;
        044			color[4][1] = 0x00;
        045			color[4][2] = 0xff;
        046			color[4][3] = 0xff;
        047			color[5][0] = 0x00;
        048			color[5][1] = 0xff;
        049			color[5][2] = 0xff;
        050			color[5][3] = 0xff;
        051			color[6][0] = 0xee;
        052			color[6][1] = 0xff;
        053			color[6][2] = 0xee;
        054			color[6][3] = 0xff;
        055			color[7][0] = 0xff;
        056			color[7][1] = 0xaa;
        057			color[7][2] = 0xaa;
        058			color[7][3] = 0xff;
        059			color[8][0] = 0xaa;
        060			color[8][1] = 0xff;
        061			color[8][2] = 0xaa;
        062			color[8][3] = 0xff;
        063			color[9][0] = 0xaa;
        064			color[9][1] = 0xaa;
        065			color[9][2] = 0xff;
        066			color[9][3] = 0xff;
        067						// 開始
        068			function start()
        069			{
        070				canvas        = document.getElementById('canvas_e');
        071				canvas.width  = 600;   // キャンバス要素の幅
        072				canvas.height = 400;   // キャンバス要素の高さ
        073				size          = 4 * 600 * 400;
        074				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        075				timerID       = setInterval('draw()', 200);
        076			}
        077						// 描画
        078			function draw() {
        079				ctx.clearRect(0, 0, canvas.width, canvas.height);
        080				let im = ctx.createImageData(canvas.width, canvas.height);
        081	
        082				for (let i1 = 0; i1 < max; i1++) {
        083					if (k[i1] < 0) {
        084							// 新しい花火
        085						let sw = 0;
        086						if (count >= next && sw == 0) {
        087							sw     = 1;
        088							count  = 0;
        089							cl[i1] = Math.floor(m_cl * Math.random());
        090							if (cl[i1] >= m_cl)
        091								cl[i1] = m_cl - 1;
        092							x[i1] = Math.floor(canvas.width * Math.random());
        093							y[i1] = Math.floor(canvas.height * Math.random());
        094							k[i1] = 0;
        095							next  = Math.floor(m_pr * Math.random());
        096							if (next <= 0)
        097								next = 1;
        098						}
        099					}
        100					else {
        101						k[i1]++;
        102							// 花火の消去
        103						if (k[i1] > m_pr)
        104							k[i1] = -1;
        105					}
        106				}
        107							// 花火の現在の状態
        108				let st = new Array();
        109				for (let i1 = 0; i1 < max; i1++)
        110					st[i1] = -1;
        111				let n = 0;
        112				while (n >= 0) {
        113					n = -1;
        114					for (let i1 = 0; i1 < max; i1++) {
        115						if (st[i1] < 0) {
        116							if (k[i1] <= 0)
        117								st[i1] = 1;
        118							else {
        119								if (n < 0 || k[i1] > k[n])
        120									n = i1;
        121							}
        122						}
        123					}
        124					if (n >= 0) {
        125						st[n] = 1;
        126						let s = Math.PI / 6;
        127						for (let i0 = 1; i0 <= k[n]; i0++) {
        128							let ang = 0;
        129							for (let i1 = 0; i1 < 12; i1++) {
        130								let kxf = x[n] + 20 * i0 * Math.cos(ang);
        131								let kyf = y[n] + 20 * i0 * Math.sin(ang);
        132								if (kxf >= 0.0 && kxf <= canvas.width && kyf >= 0.0 && kyf <= canvas.height) {
        133											// 矩形の描画
        134									let kx = Math.floor(kxf);
        135									let ky = Math.floor(kyf);
        136									for (let i2 = kx-5; i2 < kx+5; i2++) {
        137										for (let i3 = ky-5; i3 < ky+5; i3++) {
        138											let kxy = 4 * (canvas.width * i3 + i2);
        139											if (kxy >= 0 && kxy < size) {
        140												im.data[kxy]   = color[cl[n]][0];
        141												im.data[kxy+1] = color[cl[n]][1];
        142												im.data[kxy+2] = color[cl[n]][2];
        143												im.data[kxy+3] = color[cl[n]][3];
        144											}
        145										}
        146									}
        147											// 矩形を円形に近くする
        148									let k1 = 4 * (canvas.width * (ky - 6) + kx - 1);
        149									if (k1 >= 0 && k1 < size) {
        150										im.data[k1]   = color[cl[n]][0];
        151										im.data[k1+1] = color[cl[n]][1];
        152										im.data[k1+2] = color[cl[n]][2];
        153										im.data[k1+3] = color[cl[n]][3];
        154									}
        155									k1 = 4 * (canvas.width * (ky - 6) + kx);
        156									if (k1 >= 0 && k1 < size) {
        157										im.data[k1]   = color[cl[n]][0];
        158										im.data[k1+1] = color[cl[n]][1];
        159										im.data[k1+2] = color[cl[n]][2];
        160										im.data[k1+3] = color[cl[n]][3];
        161									}
        162									k1 = 4 * (canvas.width * (ky - 6) + kx + 1);
        163									if (k1 >= 0 && k1 < size) {
        164										im.data[k1]   = color[cl[n]][0];
        165										im.data[k1+1] = color[cl[n]][1];
        166										im.data[k1+2] = color[cl[n]][2];
        167										im.data[k1+3] = color[cl[n]][3];
        168									}
        169									k1 = 4 * (canvas.width * (ky + 5) + kx - 1);
        170									if (k1 >= 0 && k1 < size) {
        171										im.data[k1]   = color[cl[n]][0];
        172										im.data[k1+1] = color[cl[n]][1];
        173										im.data[k1+2] = color[cl[n]][2];
        174										im.data[k1+3] = color[cl[n]][3];
        175									}
        176									k1 = 4 * (canvas.width * (ky + 5) + kx);
        177									if (k1 >= 0 && k1 < size) {
        178										im.data[k1]   = color[cl[n]][0];
        179										im.data[k1+1] = color[cl[n]][1];
        180										im.data[k1+2] = color[cl[n]][2];
        181										im.data[k1+3] = color[cl[n]][3];
        182									}
        183									k1 = 4 * (canvas.width * (ky + 5) + kx + 1);
        184									if (k1 >= 0 && k1 < size) {
        185										im.data[k1]   = color[cl[n]][0];
        186										im.data[k1+1] = color[cl[n]][1];
        187										im.data[k1+2] = color[cl[n]][2];
        188										im.data[k1+3] = color[cl[n]][3];
        189									}
        190									k1 = 4 * (canvas.width * (ky - 1) + kx - 6);
        191									if (k1 >= 0 && k1 < size) {
        192										im.data[k1]   = color[cl[n]][0];
        193										im.data[k1+1] = color[cl[n]][1];
        194										im.data[k1+2] = color[cl[n]][2];
        195										im.data[k1+3] = color[cl[n]][3];
        196									}
        197									k1 = 4 * (canvas.width * ky + kx - 6);
        198									if (k1 >= 0 && k1 < size) {
        199										im.data[k1]   = color[cl[n]][0];
        200										im.data[k1+1] = color[cl[n]][1];
        201										im.data[k1+2] = color[cl[n]][2];
        202										im.data[k1+3] = color[cl[n]][3];
        203									}
        204									k1 = 4 * (canvas.width * (ky + 1) + kx - 6);
        205									if (k1 >= 0 && k1 < size) {
        206										im.data[k1]   = color[cl[n]][0];
        207										im.data[k1+1] = color[cl[n]][1];
        208										im.data[k1+2] = color[cl[n]][2];
        209										im.data[k1+3] = color[cl[n]][3];
        210									}
        211									k1 = 4 * (canvas.width * (ky - 1) + kx + 5);
        212									if (k1 >= 0 && k1 < size) {
        213										im.data[k1]   = color[cl[n]][0];
        214										im.data[k1+1] = color[cl[n]][1];
        215										im.data[k1+2] = color[cl[n]][2];
        216										im.data[k1+3] = color[cl[n]][3];
        217									}
        218									k1 = 4 * (canvas.width * ky + kx + 5);
        219									if (k1 >= 0 && k1 < size) {
        220										im.data[k1]   = color[cl[n]][0];
        221										im.data[k1+1] = color[cl[n]][1];
        222										im.data[k1+2] = color[cl[n]][2];
        223										im.data[k1+3] = color[cl[n]][3];
        224									}
        225									k1 = 4 * (canvas.width * (ky + 1) + kx + 5);
        226									if (k1 >= 0 && k1 < size) {
        227										im.data[k1]   = color[cl[n]][0];
        228										im.data[k1+1] = color[cl[n]][1];
        229										im.data[k1+2] = color[cl[n]][2];
        230										im.data[k1+3] = color[cl[n]][3];
        231									}
        232								}
        233								ang += s;
        234							}
        235						}
        236					}
        237				}
        238				count++;
        239								// 花火の描画
        240				ctx.putImageData(im, 0, 0);
        241			}
        242		</SCRIPT>
        243	</HEAD>
        244	<BODY CLASS="eeffee" onLoad="start()">
        245		<H1>花火(ピクセル操作)</H1>
        246		<CANVAS ID="canvas_e" STYLE="background-color: #000000;" WIDTH="600" HEIGHT="400"></CANVAS>
        247	</BODY>
        248	</HTML>
        					
        022 行目~ 023 行目

          すべての花火を打ち上げ前の状態に設定

        024 行目~ 066 行目

          10 種類の色を RGB 値と透明度で設定

        073 行目

          ImageData オブジェクトの大きさを設定(幅×高さ×4).1 ピクセル当たり 4 つの情報(赤,緑,青,透明度)が必要であるため 4 倍している

        079 行目

          キャンバスをクリア

        080 行目

          キャンバスの大きさに相当した ImageData オブジェクトを生成

        083 行目~ 099 行目

          花火が打ち上げ前の状態( k[i1] < 0 )であるときの処理である.カウンタ count の値が 次の打ち上げ時刻 next 以降であり,かつ,次の花火の打ち上げ時刻が設定されていない場合( sw == 0 )は,新しい花火を打ち上げるために,以下の処理が行われる.
        • 087 行目: 次の花火の打ち上げ時刻設定済み
        • 088 行目: カウンタの初期設定
        • 089 行目~ 091 行目: 花火の色をランダムに選択
        • 092 行目~ 093 行目: 花火の位置をランダムに選択
        • 094 行目: 花火を打ち上げた状態に設定
        • 095 行目~ 097 行目: 次の打ち上げ時刻をランダムに選択

        100 行目~ 105 行目

          花火を打ち上げた後の処理であり,101 行目において描画する輪の数を増加させ,その数が指定の数( m_pr )より大きくなった場合は,花火を消去する(描画されないようにする).

        108 行目~ 110 行目

          各花火の描画状態を示す配列.112 行目~ 237 行目が,花火を描画する( ImageData オブジェクトの値を変更する)処理であるが,ここでは,初期設定として,すべての花火に対して描画されていない状態を設定している.

        113 行目~ 123 行目

          描画する花火を,最も大きな輪を描くべき花火から順に選択している.

        134 行目~ 146 行目

          指定した輪の数だけ( for (let i0 = 1; i0 <= k[n]; i0++) ),半径を 20 ピクセルずつ変化させ,かつ,円周を 12 等分した位置( for (let i1 = 0; i1 < 12; i1++) )に 幅 9 ピクセル,高さ 9 ピクセル( 136,137 行目)の矩形を描いている.

        148 行目~ 231 行目

          上で描いた矩形に多少丸みを付けるための処理であり,必ずしも必要ない.

        233 行目

          次の角度(方位)

        238 行目

          カウンタ(時間)の増加処理

        240 行目

          実際に,画面上に花火を表示する.

  3. ゲーム

      ゲームに関しては,JavaScript によるゲームプログラミングも参考にして下さい.より多くのゲームに対し,より詳細な説明をしています.

    1. シューティングゲーム

        このプログラムは,キーイベントを使用した簡単なシューティング風ゲームです.左右の矢印キーによって下中央に描かれた黒い矩形(砲台)を左右に動かすことができます.Shift キーをクリックするとレーザ砲が発射され,ターゲット(緑の円)に命中すると,ターゲットの色が一時的にピンクに変化し消滅します.また,ターゲットが,黒い矩形に当たるとゲームオーバーになります.

        ここでは,複数人で作成する大きなプログラムではなく,一人で比較的小さなプログラムを作成する場合について,その作成手順について考えてみます.少なくとも,すべてのプログラムを作成してから実行してみるといった方法はあまり良い方法ではありません.作成するプログラムにもよりますが,私は,部分的な機能を実現するプログラムを作成し,その機能を確認した後,新しい機能を追加していくといった方法をよく利用します.たとえば,この例の場合は,以下のような手順になります.

      1. ターゲットと砲台の表示:  単に,ターゲットと砲台を表示しているだけです.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>シューティング風ゲーム(ステップ1)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			x      = 0;   // 砲台のx座標
        11			y      = 0;   // 砲台のy座標
        12			xt     = 20;   // ターゲットのx座標
        13			yt     = 50;   // ターゲットのy座標
        14			r      = 25;   // ターゲットの半径
        15						//
        16						// 開始
        17						//
        18			function start()
        19			{
        20				canvas        = document.getElementById('canvas_e');
        21				canvas.width  = 500;   // キャンバス要素の幅
        22				canvas.height = 300;   // キャンバス要素の高さ
        23				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        24				x             = canvas.width / 2 - 10;
        25				y             = canvas.height - 20;
        26				timerID       = setInterval('draw()', 33);
        27			}
        28						//
        29						// 描画
        30						//
        31			function draw() {
        32								// 画面のクリア
        33				ctx.clearRect(0, 0, canvas.width, canvas.height);
        34								// 砲台の表示
        35				ctx.fillStyle  = 'rgb(0, 0, 0)';
        36				ctx.fillRect(x, y, 20, 20);
        37								// ターゲットの表示
        38				ctx.fillStyle  = 'rgb(0, 255, 0)';
        39				ctx.beginPath();
        40				ctx.arc(xt, yt, r, 0, Math.PI*2, false);
        41				ctx.fill();
        42			}
        43		</SCRIPT>
        44	</HEAD>
        45	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        46		<H2 STYLE="text-align: center">シューティング風ゲーム(ステップ1)</H2>
        47		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="500" HEIGHT="300"></CANVAS>
        48	</BODY>
        49	</HTML>
        					
        35 行目~ 36 行目

          砲台(塗りつぶした黒の矩形)の描画

        38 行目~ 41 行目

          ターゲット(塗りつぶした緑の円)の描画

      2. ターゲットの移動:  33 ms 毎に,ターゲットを下方向へ移動してみます.前のステップで作成したプログラムを少し変更するだけですが,アニーションの機能を確認することができます.また,このプログラムでは,変数 game を false に設定することによって,ゲームオーバー画面も確認することができます.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>シューティング風ゲーム(ステップ2)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			x      = 0;   // 砲台のx座標
        11			y      = 0;   // 砲台のy座標
        12			xt     = 20;   // ターゲットのx座標
        13			yt     = 50;   // ターゲットのy座標
        14			r      = 25;   // ターゲットの半径
        15			sp     = 5;   // ターゲットの速度
        16			game   = true;   // ゲーム実行中か否か
        17						//
        18						// 開始
        19						//
        20			function start()
        21			{
        22				canvas        = document.getElementById('canvas_e');
        23				canvas.width  = 500;   // キャンバス要素の幅
        24				canvas.height = 300;   // キャンバス要素の高さ
        25				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        26				x             = canvas.width / 2 - 10;
        27				y             = canvas.height - 20;
        28				timerID       = setInterval('draw()', 33);
        29			}
        30						//
        31						// 描画
        32						//
        33			function draw() {
        34								// ゲーム中
        35				if (game) {
        36										// 画面のクリア
        37					ctx.clearRect(0, 0, canvas.width, canvas.height);
        38										// 砲台の表示
        39					ctx.fillStyle  = 'rgb(0, 0, 0)';
        40					ctx.fillRect(x, y, 20, 20);
        41										// ターゲットの表示
        42					yt += sp;
        43					ctx.fillStyle  = 'rgb(0, 255, 0)';
        44					ctx.beginPath();
        45					ctx.arc(xt, yt, r, 0, Math.PI*2, false);
        46					ctx.fill();
        47				}
        48								// ゲームオーバ
        49				else {
        50					ctx.font = "50px 'MS ゴシック'";
        51					let met  = ctx.measureText("Game Over");
        52					let px   = canvas.width / 2 - met.width / 2;
        53					let py   = canvas.height / 2;
        54					ctx.fillText("Game Over", px, py);
        55				}
        56			}
        57		</SCRIPT>
        58	</HEAD>
        59	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        60		<H2 STYLE="text-align: center">シューティング風ゲーム(ステップ2)</H2>
        61		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="500" HEIGHT="300"></CANVAS>
        62	</BODY>
        63	</HTML>
        					
        15 行目

          ターゲットの速度

        16 行目

          ゲーム実行中か否かを示す変数

        37 行目~ 46 行目

          ゲームを実行中の処理である.基本的に,先のプログラムと同じであるが,42 行目において,ターゲットの y 座標を変更している.

        50 行目~ 54 行目

          ゲームオーバーになったときの処理である.画面中央に,「 Game Over 」と表示している.なお,50 行目~51 行目では,文字列を画面中央に表示するため,文字列の実際の幅と高さを取得している.

      3. ターゲットの生成・移動・消滅:  ターゲットは,

        • 画面上に存在し,移動している状態( target = 1 )
        • 画面上に存在しない状態( target = 0 )
        • 命中し色が変わった状態( target = 2 )

        という 3 つの状態のいずれかになります.その状態を記憶しているのが変数 t_exist です.ここでは,ターゲットを画面上部の任意の場所に生成し,画面の外に出たら消滅するように変更します.消滅すると,再び,新しいターゲットが生成されます.また,移動方向は,π/4 ~ 3π/4 の間の値からランダムに選択します.なお,位置や方向をランダムにするために,Math オブジェクトのメソッド random() を使用しています.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>シューティング風ゲーム(ステップ3)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas  = null;
        09			ctx     = null;
        10			x       = 0;   // 砲台のx座標
        11			y       = 0;   // 砲台のy座標
        12			xt      = 20;   // ターゲットのx座標
        13			yt      = 50;   // ターゲットのy座標
        14			r       = 25;   // ターゲットの半径
        15			sp      = 5;   // ターゲットの速度
        16			vx      = 0;   // ターゲットのx方向の速度
        17			vy      = 0;   // ターゲットのy方向の速度
        18			t_exist = 0;   // ターゲットの存在(1:存在,0:存在しない)
        19			game    = true;   // ゲーム実行中か否か
        20						//
        21						// 開始
        22						//
        23			function start()
        24			{
        25				canvas        = document.getElementById('canvas_e');
        26				canvas.width  = 500;   // キャンバス要素の幅
        27				canvas.height = 300;   // キャンバス要素の高さ
        28				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        29				x             = canvas.width / 2 - 10;
        30				y             = canvas.height - 20;
        31				timerID       = setInterval('draw()', 33);
        32			}
        33						//
        34						// 描画
        35						//
        36			function draw() {
        37								// ゲーム中
        38				if (game) {
        39										// 画面のクリア
        40					ctx.clearRect(0, 0, canvas.width, canvas.height);
        41										// ターゲットの移動と消滅
        42					if (t_exist == 1) {
        43						xt += vx;
        44						yt += vy;
        45						if (xt < -2*r || xt > canvas.width+r || yt > canvas.height+r)
        46							t_exist = 0;
        47					}
        48										// ターゲットの生成
        49					else {
        50						xt      = 2 * r + Math.floor((canvas.width - 4 * r) * Math.random());
        51						yt      = 0;
        52						let ang = 0.5 * Math.PI * Math.random() + 0.25 * Math.PI;
        53						vx      = Math.floor(sp * Math.cos(ang));
        54						vy      = Math.floor(sp * Math.sin(ang));
        55						t_exist = 1;
        56					}
        57										// 砲台の表示
        58					ctx.fillStyle  = 'rgb(0, 0, 0)';
        59					ctx.fillRect(x, y, 20, 20);
        60										// ターゲットの表示
        61					ctx.fillStyle  = 'rgb(0, 255, 0)';
        62					ctx.beginPath();
        63					ctx.arc(xt, yt, r, 0, Math.PI*2, false);
        64					ctx.fill();
        65				}
        66								// ゲームオーバ
        67				else {
        68					ctx.font = "50px 'MS ゴシック'";
        69					let met  = ctx.measureText("Game Over");
        70					let px   = canvas.width / 2 - met.width / 2;
        71					let py   = canvas.height / 2;
        72					ctx.fillText("Game Over", px, py);
        73				}
        74			}
        75		</SCRIPT>
        76	</HEAD>
        77	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        78		<H2 STYLE="text-align: center">シューティング風ゲーム(ステップ3)</H2>
        79		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="500" HEIGHT="300"></CANVAS>
        80	</BODY>
        81	</HTML>
        					
        16 行目~ 17 行目

          ターゲットの x 軸方向,及び,y 軸方向の速度

        18 行目

          ターゲットが存在する場合は 1,存在しない場合は 0 となる変数

        43 行目~ 46 行目

          ターゲットが存在する場合の処理である.各軸方向の速度を利用して,ターゲットの x 座標,及び,y 座標の値を変化させ,画面外に出た場合は消滅させる.

        50 行目~ 55 行目

          ターゲットが存在しないときの処理であり,新しいターゲットを生成している.50 行目~ 51 行目において,ターゲットの初期位置を決めている.ただし,x 座標はランダムに選択される.また,52 行目において,ターゲットが進む方向がランダムに選択され,53 行目~ 54 行目において,その角度から各軸方向の速度を計算している.最後に,変数 t_exist の値を 1 に設定している.

      4. ゲームオーバー:  このゲームでは,ターゲットと砲台が衝突するとゲームオーバーとなります.ここでは,その判定を追加します.まだ,砲台を移動できませんので,砲台に衝突するようなターゲットが現れるまでしばらく待ち,機能を確認します.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>シューティング風ゲーム(ステップ4)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas  = null;
        09			ctx     = null;
        10			x       = 0;   // 砲台のx座標
        11			y       = 0;   // 砲台のy座標
        12			xt      = 20;   // ターゲットのx座標
        13			yt      = 50;   // ターゲットのy座標
        14			r       = 25;   // ターゲットの半径
        15			sp      = 5;   // ターゲットの速度
        16			vx      = 0;   // ターゲットのx方向の速度
        17			vy      = 0;   // ターゲットのy方向の速度
        18			t_exist = 0;   // ターゲットの存在(1:存在,0:存在しない)
        19			game    = true;   // ゲーム実行中か否か
        20						//
        21						// 開始
        22						//
        23			function start()
        24			{
        25				canvas        = document.getElementById('canvas_e');
        26				canvas.width  = 500;   // キャンバス要素の幅
        27				canvas.height = 300;   // キャンバス要素の高さ
        28				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        29				x             = canvas.width / 2 - 10;
        30				y             = canvas.height - 20;
        31				timerID       = setInterval('draw()', 33);
        32			}
        33						//
        34						// 描画
        35						//
        36			function draw() {
        37								// ゲーム中
        38				if (game) {
        39										// 画面のクリア
        40					ctx.clearRect(0, 0, canvas.width, canvas.height);
        41										// ターゲットの移動と消滅
        42					if (t_exist == 1) {
        43												// ゲームオーバ
        44						let x1 = xt - (x + 10);
        45						let y1 = yt - (y + 10);
        46						if (Math.sqrt(x1*x1+y1*y1) < r+10)
        47							game = false;
        48												// ゲームオーバでない
        49						else {
        50							xt += vx;
        51							yt += vy;
        52							if (xt < -2*r || xt > canvas.width+r || yt > canvas.height+r)
        53								t_exist = 0;
        54						}
        55					}
        56										// ターゲットの生成
        57					else {
        58						xt      = 2 * r + Math.floor((canvas.width - 4 * r) * Math.random());
        59						yt      = 0;
        60						let ang = 0.5 * Math.PI * Math.random() + 0.25 * Math.PI;
        61						vx      = Math.floor(sp * Math.cos(ang));
        62						vy      = Math.floor(sp * Math.sin(ang));
        63						t_exist = 1;
        64					}
        65										// 砲台とターゲットの表示
        66					if (game) {
        67												// 砲台の表示
        68						ctx.fillStyle  = 'rgb(0, 0, 0)';
        69						ctx.fillRect(x, y, 20, 20);
        70												// ターゲットの表示
        71						ctx.fillStyle  = 'rgb(0, 255, 0)';
        72						ctx.beginPath();
        73						ctx.arc(xt, yt, r, 0, Math.PI*2, false);
        74						ctx.fill();
        75					}
        76				}
        77								// ゲームオーバ-
        78				else {
        79					ctx.fillStyle  = 'rgb(0, 0, 0)';
        80					ctx.font = "50px 'MS ゴシック'";
        81					let met  = ctx.measureText("Game Over");
        82					let px   = canvas.width / 2 - met.width / 2;
        83					let py   = canvas.height / 2;
        84					ctx.fillText("Game Over", px, py);
        85				}
        86			}
        87		</SCRIPT>
        88	</HEAD>
        89	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        90		<H2 STYLE="text-align: center">シューティング風ゲーム(ステップ4)</H2>
        91		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="500" HEIGHT="300"></CANVAS>
        92	</BODY>
        93	</HTML>
        					
        44 行目~ 47 行目

          ターゲットが砲台に衝突したか否かの判定を行い,衝突した場合は,ゲームオーバーにしている.

        66 行目

          ゲーム中だけ,砲台とターゲットを描画する

        79 行目

          線の色を黒に設定

      5. キーイベント:  最後に,キーイベントに対する処理を追加します.左矢印または右矢印キーを押すと,砲台が左または右に 20 ピクセルだけ移動します.また,Shift キーを押すと,レーザ光が発射されます(変数 fire を 1 にする).

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>シューティング風ゲーム</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas  = null;
        009			ctx     = null;
        010			x       = 0;   // 砲台のx座標
        011			y       = 0;   // 砲台のy座標
        012			xt      = 20;   // ターゲットのx座標
        013			yt      = 50;   // ターゲットのy座標
        014			r       = 25;   // ターゲットの半径
        015			sp      = 5;   // ターゲットの速度
        016			vx      = 0;   // ターゲットのx方向の速度
        017			vy      = 0;   // ターゲットのy方向の速度
        018			t_exist = 0;   // ターゲットの状態(0:存在しない,1:移動中,2:命中)
        019			fire    = 0;   // レーザ砲の発射
        020			game    = true;   // ゲーム実行中か否か
        021						//
        022						// 開始
        023						//
        024			function start()
        025			{
        026				canvas        = document.getElementById('canvas_e');
        027				canvas.width  = 500;   // キャンバス要素の幅
        028				canvas.height = 300;   // キャンバス要素の高さ
        029				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        030				x             = canvas.width / 2 - 10;
        031				y             = canvas.height - 20;
        032				timerID       = setInterval('draw()', 33);
        033			}
        034						//
        035						// 描画
        036						//
        037			function draw() {
        038								// ゲーム中
        039				if (game) {
        040										// 画面のクリア
        041					ctx.clearRect(0, 0, canvas.width, canvas.height);
        042										// ターゲットの移動と消滅
        043					if (t_exist == 1) {
        044												// ゲームオーバー
        045						let x1 = xt - (x + 10);
        046						let y1 = yt - (y + 10);
        047						if (Math.sqrt(x1*x1+y1*y1) < r+10)
        048							game = false;
        049												// ゲームオーバーでない
        050						else {
        051														// レーザ砲の発射
        052																// 命中
        053							if (fire > 0) {
        054								fire++;
        055								if (fire > 2) {
        056									fire = 0;
        057									if (Math.abs(xt-x-10) < r) {
        058										t_exist = 2;
        059										ctx.fillStyle  = 'rgb(255, 192, 203)';
        060										ctx.beginPath();
        061										ctx.arc(xt, yt, r, 0, Math.PI*2, false);
        062										ctx.fill();
        063									}
        064								}
        065							}
        066																// 命中でない
        067							else if (t_exist < 2) {
        068								xt += vx;
        069								yt += vy;
        070								if (xt < -2*r || xt > canvas.width+r || yt > canvas.height+r)
        071									t_exist = 0;
        072							}
        073						}
        074					}
        075										// ターゲットの生成
        076					else {
        077						xt      = 2 * r + Math.floor((canvas.width - 4 * r) * Math.random());
        078						yt      = 0;
        079						let ang = 0.5 * Math.PI * Math.random() + 0.25 * Math.PI;
        080						vx      = Math.floor(sp * Math.cos(ang));
        081						vy      = Math.floor(sp * Math.sin(ang));
        082						t_exist = 1;
        083					}
        084										// 砲台とターゲットの表示
        085					if (game) {
        086												// 砲台の表示
        087						ctx.fillStyle  = 'rgb(0, 0, 0)';
        088						ctx.fillRect(x, y, 20, 20);
        089												// ターゲットの表示
        090						if (t_exist != 2) {
        091							ctx.fillStyle = 'rgb(0, 255, 0)';
        092							ctx.beginPath();
        093							ctx.arc(xt, yt, r, 0, Math.PI*2, false);
        094							ctx.fill();
        095							if (fire > 0) {
        096								ctx.fillStyle  = 'rgb(255, 0, 0)';
        097								ctx.fillRect(x+9, 0, 3, y);
        098							}
        099						}
        100					}
        101				}
        102								// ゲームオーバ
        103				else {
        104					ctx.fillStyle  = 'rgb(0, 0, 0)';
        105					ctx.font = "50px 'MS ゴシック'";
        106					let met  = ctx.measureText("Game Over");
        107					let px   = canvas.width / 2 - met.width / 2;
        108					let py   = canvas.height / 2;
        109					ctx.fillText("Game Over", px, py);
        110				}
        111			}
        112						//
        113						// キーイベントの処理
        114						//
        115			function keyDown(e) {
        116				if (e.keyCode == 37)  // 左矢印
        117					x -= 20;
        118				else if (e.keyCode == 39)   // 右矢印
        119					x += 20;
        120				if (e.shiftKey) {   // Shift キー
        121					ctx.fillStyle  = 'rgb(255, 0, 0)';
        122					ctx.fillRect(x+9, 0, 3, y);
        123					fire = 1;
        124				}
        125			}
        126		</SCRIPT>
        127	</HEAD>
        128	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()" onKeyDown="keyDown(event)">
        129		<H2 STYLE="text-align: center">シューティング風ゲーム</H2>
        130		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="500" HEIGHT="300"></CANVAS>
        131	</BODY>
        132	</HTML>
        					
        018 行目

          ターゲットの状態を,コメントにあるように,3 つの状態を表すように変更

        019 行目

          レーザ砲の発射状態を表す変数

        053 行目~ 065 行目

          レーザ砲が発射されているときの処理である.変数 fire の値を増加させ( 054 行目),その値が 2 より大きい場合は,レーザ砲の発射を停止し(変数 fire を 0 に設定,056 行目),命中判定を行っている( 057 行目).命中した場合は,変数 t_exist の値を 2 に設定した後,ターゲットの色をピンクにしている( 058 行目~ 062 行目).

        096 行目~ 097 行目

          レーザビームの表示である.

        115 行目~ 125 行目

          キーが押されたときの処理である.左矢印キーのときは,砲台を 20 ピクセルだけ左に,また,右矢印キーのときは,砲台を 20 ピクセルだけ右に移動させる.さらに,シフトキーのときは,レーザビームを描き,レーザ砲を発射状態に設定する.

        128 行目

          BODY 要素に onKeyDown 属性を追加し,キーイベントを受け付けるように設定している.

    2. ぷよぷよ(テトリス)

        このプログラムは,キーイベントを使用した簡単なぷよぷよ風ゲームです.左右の矢印キーによって落下してくるピースを左右に動かすことができます.また,下矢印キーで90度,または,-90度の回転,上矢印キーで左右,または,上下の色を交換できます.

        ここでは,複数人で作成する大きなプログラムではなく,一人で比較的小さなプログラムを作成する場合について,その作成手順について考えてみます.少なくとも,すべてのプログラムを作成してから実行してみるといった方法はあまり良い方法ではありません.作成するプログラムにもよりますが,私は,部分的な機能を実現するプログラムを作成し,その機能を確認した後,新しい機能を追加していくといった方法をよく利用します.たとえば,この例の場合は,以下のような手順になります.

      1. ピースの表示:  このプログラムでは,画面を格子状に区切り,この格子を配列に対応させ,各要素の値によってピースの色を制御しています( 0 の場合は,ピースが存在しない).どのような位置に,どのような色で表示しても構いませんが,後からのことを考えると,位置や色に対する一般的な処理を行っておいた方がよいと思います.なお,変数 p_x 及び p_y はピースの位置を表すための変数です.

        01	<!DOCTYPE HTML>
        02	<HTML>
        03	<HEAD>
        04		<TITLE>ぷよぷよ風ゲーム(ステップ1)</TITLE>
        05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        07		<SCRIPT TYPE="text/javascript">
        08			canvas = null;
        09			ctx    = null;
        10			p      = new Array();   // ピースの色(0の時は存在しない)
        11			row    = 12;   // 行の数
        12			col    = 5;   // 列の数
        13			p_x    = -1;   // 動いているピースの位置(列)
        14			p_y    = -1;   // 動いているピースの位置(行)
        15			p_wh   = 30;   // ピースの幅と高さ
        16			game   = true;   // ゲーム中か否か
        17						//
        18						// 開始
        19						//
        20			function start()
        21			{
        22				canvas        = document.getElementById('canvas_e');
        23				canvas.width  = 270;   // キャンバス要素の幅
        24				canvas.height = 380;   // キャンバス要素の高さ
        25				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        26				ctx.fillStyle = 'rgb(255, 255, 255)';
        27				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        28								// ピースの配置
        29				for (let i1 = 0; i1 < row; i1++) {
        30					p[i1] = new Array();
        31					for (let i2 = 0; i2 < col; i2++)
        32						p[i1][i2] = 0;
        33				}
        34								// ピースの選択
        35				p_y           = 3;
        36				p_x           = 1;
        37				p[p_y][p_x]   = 2;   // rgb(255, 215, 0)
        38				p[p_y][p_x+1] = 3;   // rgb(0, 255, 255)
        39				piece();
        40			}
        41						//
        42						// ピースの描画
        43						//
        44			function piece() {
        45				for (let i1 = 0; i1 < row; i1++) {
        46					for (let i2 = 0; i2 < col; i2++) {
        47						if (p[i1][i2] > 0) {
        48							switch (p[i1][i2]) {
        49								case 1:
        50									ctx.fillStyle  = 'rgb(255, 0, 0)';
        51									break;
        52								case 2:
        53									ctx.fillStyle  = 'rgb(255, 215, 0)';
        54									break;
        55								case 3:
        56									ctx.fillStyle  = 'rgb(0, 255, 255)';
        57									break;
        58								case 4:
        59									ctx.fillStyle  = 'rgb(173, 255, 47)';
        60									break;
        61							}
        62							let kx = 10 + p_wh * i2;
        63							let ky = 10 + p_wh * i1;
        64							ctx.fillRect(kx, ky, p_wh, p_wh);
        65						}
        66					}
        67				}
        68			}
        69		</SCRIPT>
        70	</HEAD>
        71	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        72		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム(ステップ1)</H2>
        73		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
        74	</BODY>
        75	</HTML>
        					
        26 行目~ 27 行目

          白い背景色で,ピースを表示する領域(矩形)を描画

        29 行目~ 33 行目

          ピースの存在を示す 2 次元配列 p を定義し,すべて 0 で初期設定している(ピースが存在しない状態).

        35 行目~ 38 行目

          配列 p の 4 行 2 列に rgb(255, 215, 0) 色のピース,また,4 行 3 列に rgb(0, 255, 255) 色のピースを配置

        39 行目

          ピースを描画する関数 piece の呼び出し

        48 行目~ 61 行目

          描画するピースの色を決定

        62 行目~ 64 行目

          指定された色で,指定された位置に矩形を描画

      2. ピースの落下:  先ほど表示したピースを,一定時間毎( この例では,500 ms )に落下させてみます.setInterval メソッドを利用して,ピースの位置を配列の 1 要素分だけ下に移動させています.前のステップで作成したプログラムを少し変更するだけですが,setInterval メソッドを利用したアニーションの機能を確認することができます.また,このプログラムでは,変数 game を false に設定することによって,ゲームオーバー画面も確認することができます.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>ぷよぷよ風ゲーム(ステップ2)</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas = null;
        009			ctx    = null;
        010			p      = new Array();   // ピースの色(0の時は存在しない)
        011			row    = 12;   // 行の数
        012			col    = 5;   // 列の数
        013			p_x    = -1;   // 動いているピースの位置(列)
        014			p_y    = -1;   // 動いているピースの位置(行)
        015			p_wh   = 30;   // ピースの幅と高さ
        016			game   = true;   // ゲーム中か否か
        017						//
        018						// 開始
        019						//
        020			function start()
        021			{
        022				canvas        = document.getElementById('canvas_e');
        023				canvas.width  = 270;   // キャンバス要素の幅
        024				canvas.height = 380;   // キャンバス要素の高さ
        025				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        026				ctx.fillStyle = 'rgb(255, 255, 255)';
        027				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        028								// ピースの配置
        029				for (let i1 = 0; i1 < row; i1++) {
        030					p[i1] = new Array();
        031					for (let i2 = 0; i2 < col; i2++)
        032						p[i1][i2] = 0;
        033				}
        034								// ピースの選択
        035				p_y           = 3;
        036				p_x           = 1;
        037				p[p_y][p_x]   = 2;   // rgb(255, 215, 0)
        038				p[p_y][p_x+1] = 3;   // rgb(0, 255, 255)
        039				piece();
        040	
        041				timerID = setInterval('draw()', 500);
        042			}
        043						//
        044						// 一定時間毎の処理
        045						//
        046			function draw() {
        047								// ゲーム中
        048				if (game) {
        049										// ピースの落下
        050					if (p_y < row-1) {
        051						p[p_y+1][p_x]   = p[p_y][p_x];
        052						p[p_y+1][p_x+1] = p[p_y][p_x+1];
        053						p[p_y][p_x]     = 0;
        054						p[p_y][p_x+1]   = 0;
        055						let kx = 10 + p_wh * p_x;
        056						let ky = 10 + p_wh * p_y;
        057						ctx.fillStyle  = 'rgb(255, 255, 255)';
        058						ctx.fillRect(kx, ky, p_wh, p_wh);
        059						kx = 10 + p_wh * (p_x + 1);
        060						ctx.fillRect(kx, ky, p_wh, p_wh);
        061						p_y++;
        062						piece();
        063					}
        064				}
        065								// ゲームオーバー
        066				else {
        067					ctx.fillStyle  = 'rgb(255, 255, 255)';
        068					ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        069					ctx.fillStyle  = 'rgb(0, 0, 0)';
        070					ctx.font = "50px 'MS ゴシック'";
        071					let met  = ctx.measureText("Game");
        072					let px   = 10 + p_wh * col / 2 - met.width / 2;
        073					let py   = 10 + p_wh * row / 2 - p_wh;
        074					ctx.fillText("Game", px, py);
        075					met = ctx.measureText("Over!");
        076					px  = 10 + p_wh * col / 2 - met.width / 2;
        077					py  = 10 + p_wh * row / 2 + p_wh;
        078					ctx.fillText("Over!", px, py);
        079				}
        080			}
        081						//
        082						// ピースの描画
        083						//
        084			function piece() {
        085				for (let i1 = 0; i1 < row; i1++) {
        086					for (let i2 = 0; i2 < col; i2++) {
        087						if (p[i1][i2] > 0) {
        088							switch (p[i1][i2]) {
        089								case 1:
        090									ctx.fillStyle  = 'rgb(255, 0, 0)';
        091									break;
        092								case 2:
        093									ctx.fillStyle  = 'rgb(255, 215, 0)';
        094									break;
        095								case 3:
        096									ctx.fillStyle  = 'rgb(0, 255, 255)';
        097									break;
        098								case 4:
        099									ctx.fillStyle  = 'rgb(173, 255, 47)';
        100									break;
        101							}
        102							let kx = 10 + p_wh * i2;
        103							let ky = 10 + p_wh * i1;
        104							ctx.fillRect(kx, ky, p_wh, p_wh);
        105						}
        106					}
        107				}
        108			}
        109		</SCRIPT>
        110	</HEAD>
        111	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        112		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム(ステップ2)</H2>
        113		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
        114	</BODY>
        115	</HTML>
        					
        041 行目

          500 ms 毎に,関数 draw を実行するように設定

        051 行目~ 062 行目

          ピースを落下させる処理である.ピースが最下段に到着する前だけに実行され( 050 行目の条件),最下段に到着すると停止する.
        • 051 行目~ 054 行目: 配列 p 上で,ピースを一つ下に移動
        • 055 行目~ 060 行目: 落下する前にピースが存在した場所に白い矩形を描く
        • 061 行目: 現在のピース位置を表す y 座標を変更
        • 062 行目: ピースの描画

        067 行目~ 078 行目

          ゲームオーバーになったときの処理である.
        • 067 行目~ 068 行目: ピース表示領域を白い矩形で塗りつぶす
        • 069 行目~ 070 行目: 文字色とフォントの設定
        • 071 行目~ 078 行目: measureText メソッドを使用して,各文字の実際の幅及び高さを取得した後,「 Game 」,及び,「 Over! 」を画面中央に描く

      3. ピースの生成と落下:  ピースを画面上部(水平位置はランダム)に発生させ,落下させます.ランダムな値を設定するために,Math オブジェクトのメソッド random() を使用しています.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>ぷよぷよ風ゲーム(ステップ3)</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas = null;
        009			ctx    = null;
        010			p      = new Array();   // ピースの色(0の時は存在しない)
        011			row    = 12;   // 行の数
        012			col    = 5;   // 列の数
        013			p_x    = -1;   // 動いているピースの位置(列)
        014			p_y    = -1;   // 動いているピースの位置(行)
        015			p_wh   = 30;   // ピースの幅と高さ
        016			game   = true;   // ゲーム中か否か
        017						//
        018						// 開始
        019						//
        020			function start()
        021			{
        022				canvas        = document.getElementById('canvas_e');
        023				canvas.width  = 270;   // キャンバス要素の幅
        024				canvas.height = 380;   // キャンバス要素の高さ
        025				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        026				ctx.fillStyle = 'rgb(255, 255, 255)';
        027				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        028								// ピースの配置
        029				for (let i1 = 0; i1 < row; i1++) {
        030					p[i1] = new Array();
        031					for (let i2 = 0; i2 < col; i2++)
        032						p[i1][i2] = 0;
        033				}
        034								// ピースの選択
        035				select();
        036	
        037				timerID = setInterval('draw()', 500);
        038			}
        039						//
        040						// 一定時間毎の処理
        041						//
        042			function draw()
        043			{
        044								// ゲーム中
        045				if (game) {
        046										// ピースの落下
        047					if (p_y < row-1) {
        048						p[p_y+1][p_x]   = p[p_y][p_x];
        049						p[p_y+1][p_x+1] = p[p_y][p_x+1];
        050						p[p_y][p_x]     = 0;
        051						p[p_y][p_x+1]   = 0;
        052						let kx = 10 + p_wh * p_x;
        053						let ky = 10 + p_wh * p_y;
        054						ctx.fillStyle  = 'rgb(255, 255, 255)';
        055						ctx.fillRect(kx, ky, p_wh, p_wh);
        056						kx = 10 + p_wh * (p_x + 1);
        057						ctx.fillRect(kx, ky, p_wh, p_wh);
        058						p_y++;
        059						piece();
        060					}
        061					else
        062						select();
        063				}
        064								// ゲームオーバー
        065				else {
        066					ctx.fillStyle  = 'rgb(255, 255, 255)';
        067					ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        068					ctx.fillStyle  = 'rgb(0, 0, 0)';
        069					ctx.font = "50px 'MS ゴシック'";
        070					let met  = ctx.measureText("Game");
        071					let px   = 10 + p_wh * col / 2 - met.width / 2;
        072					let py   = 10 + p_wh * row / 2 - p_wh;
        073					ctx.fillText("Game", px, py);
        074					met = ctx.measureText("Over!");
        075					px  = 10 + p_wh * col / 2 - met.width / 2;
        076					py  = 10 + p_wh * row / 2 + p_wh;
        077					ctx.fillText("Over!", px, py);
        078				}
        079			}
        080						//
        081						// ピースの描画
        082						//
        083			function piece()
        084			{
        085				for (let i1 = 0; i1 < row; i1++) {
        086					for (let i2 = 0; i2 < col; i2++) {
        087						if (p[i1][i2] > 0) {
        088							switch (p[i1][i2]) {
        089								case 1:
        090									ctx.fillStyle  = 'rgb(255, 0, 0)';
        091									break;
        092								case 2:
        093									ctx.fillStyle  = 'rgb(255, 215, 0)';
        094									break;
        095								case 3:
        096									ctx.fillStyle  = 'rgb(0, 255, 255)';
        097									break;
        098								case 4:
        099									ctx.fillStyle  = 'rgb(173, 255, 47)';
        100									break;
        101							}
        102							let kx = 10 + p_wh * i2;
        103							let ky = 10 + p_wh * i1;
        104							ctx.fillRect(kx, ky, p_wh, p_wh);
        105						}
        106					}
        107				}
        108			}
        109						//
        110						// ピースの選択
        111						//
        112			function select()
        113			{
        114				p_y = 0;
        115				p_x = Math.floor(Math.random() * (col - 1));
        116				if (p_x > col-2)
        117					p_x = col - 2;
        118	
        119				let color = Math.floor(Math.random() * 4) + 1;
        120				if (color > 4)
        121					color = 4;
        122				p[0][p_x] = color;
        123				color = Math.floor(Math.random() * 4) + 1;
        124				if (color > 4)
        125					color = 4;
        126				p[0][p_x+1] = color;
        127	
        128				piece();
        129			}
        130		</SCRIPT>
        131	</HEAD>
        132	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        133		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム(ステップ3)</H2>
        134		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
        135	</BODY>
        136	</HTML>
        					
        035 行目

          ピースの初期位置や色をランダムに選択する関数 select を呼んでいる.

        061 行目~ 062 行目

          ピースが最下段に到達した場合は,次のピースの選択に移る.

        114 行目~ 117 行目

          ピースの初期位置(水平方向)をランダムに選択

        119 行目~ 126 行目

          2 つのピースの色をランダムに選択

        128 行目

          ピースの描画

      4. キーイベント:  キーイベントに対する処理を追加します.移動や回転を行う場合は,移動や回転が可能か否かのチェックが必要となります.変数 rot の値が 0 の時は横並び,1 の時は縦並びであることを意味します.当然,rot の値によって,一番下に到着したか否かのチェック方法も異なってきますので,ピースの落下を制御する部分も変更する必要があります.また,一番下に到着すると,変数 ok を false に設定し,キーイベントを受け付けないようにしています.なお,以下に示すようなキー設定を行っています.

        • 左矢印: 左移動
        • 右矢印: 右移動
        • 上矢印: 上下または左右入れ替え
        • 下矢印: 90 度または -90 度回転

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>ぷよぷよ風ゲーム(ステップ4)</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas = null;
        009			ctx    = null;
        010			p      = new Array();   // ピースの色(0の時は存在しない)
        011			row    = 12;   // 行の数
        012			col    = 5;   // 列の数
        013			p_x    = -1;   // 動いているピースの位置(列)
        014			p_y    = -1;   // 動いているピースの位置(行)
        015			p_wh   = 30;   // ピースの幅と高さ
        016			rot    = 0;   // 横か縦か(0:横,1:縦)
        017			game   = true;   // ゲーム中か否か
        018			ok     = true;   // キーイベントを受け付けるか否か
        019						//
        020						// 開始
        021						//
        022			function start()
        023			{
        024				canvas        = document.getElementById('canvas_e');
        025				canvas.width  = 270;   // キャンバス要素の幅
        026				canvas.height = 380;   // キャンバス要素の高さ
        027				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        028				ctx.fillStyle = 'rgb(255, 255, 255)';
        029				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        030								// ピースの配置
        031				for (let i1 = 0; i1 < row; i1++) {
        032					p[i1] = new Array();
        033					for (let i2 = 0; i2 < col; i2++)
        034						p[i1][i2] = 0;
        035				}
        036								// ピースの選択
        037				select();
        038	
        039				timerID = setInterval('draw()', 500);
        040			}
        041						//
        042						// 一定時間毎の処理
        043						//
        044			function draw()
        045			{
        046								// ゲーム中
        047				if (game) {
        048										// ピースの落下
        049					let ct = 0;   // ct が 0 であることは,ピースの動きが止まったことを示す
        050												// 横並び
        051					if (rot == 0) {
        052						if (p_y < row-1) {
        053							ct              = 1;
        054							p[p_y+1][p_x]   = p[p_y][p_x];
        055							p[p_y+1][p_x+1] = p[p_y][p_x+1];
        056							p[p_y][p_x]     = 0;
        057							p[p_y][p_x+1]   = 0;
        058							let kx = 10 + p_wh * p_x;
        059							let ky = 10 + p_wh * p_y;
        060							ctx.fillStyle = 'rgb(255, 255, 255)';
        061							ctx.fillRect(kx, ky, p_wh, p_wh);
        062							kx = 10 + p_wh * (p_x + 1);
        063							ctx.fillRect(kx, ky, p_wh, p_wh);
        064							p_y++;
        065							piece();
        066						}
        067						else
        068							ok = false;
        069					}
        070												// 縦並び
        071					else {
        072						if (p_y < row-2) {
        073							ct            = 1;
        074							p[p_y+2][p_x] = p[p_y+1][p_x];
        075							p[p_y+1][p_x] = p[p_y][p_x];
        076							p[p_y][p_x]   = 0;
        077							let kx = 10 + p_wh * p_x;
        078							let ky = 10 + p_wh * p_y;
        079							ctx.fillStyle = 'rgb(255, 255, 255)';
        080							ctx.fillRect(kx, ky, p_wh, p_wh);
        081							p_y++;
        082							piece();
        083						}
        084						else
        085							ok = false;
        086					}
        087										// 消去と次のピース
        088					if (ct == 0)
        089						select();
        090				}
        091								// ゲームオーバー
        092				else {
        093					ctx.fillStyle = 'rgb(255, 255, 255)';
        094					ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        095					ctx.fillStyle = 'rgb(0, 0, 0)';
        096					ctx.font = "50px 'MS ゴシック'";
        097					let met  = ctx.measureText("Game");
        098					let px   = 10 + p_wh * col / 2 - met.width / 2;
        099					let py   = 10 + p_wh * row / 2 - p_wh;
        100					ctx.fillText("Game", px, py);
        101					met = ctx.measureText("Over!");
        102					px  = 10 + p_wh * col / 2 - met.width / 2;
        103					py  = 10 + p_wh * row / 2 + p_wh;
        104					ctx.fillText("Over!", px, py);
        105				}
        106			}
        107						//
        108						// キーが押されたときの処理
        109						//
        110			function keyDown(e) {
        111				if (ok) {
        112					if (e.keyCode == 37) {   // 左矢印(左移動)
        113						if (p_x > 0) {
        114							if (rot == 0 && p[p_y][p_x-1] == 0) {
        115								p[p_y][p_x-1] = p[p_y][p_x];
        116								p[p_y][p_x]   = p[p_y][p_x+1];
        117								p[p_y][p_x+1] = 0;
        118								let kx = 10 + p_wh * (p_x + 1);
        119								let ky = 10 + p_wh * p_y;
        120								ctx.fillStyle = 'rgb(255, 255, 255)';
        121								ctx.fillRect(kx, ky, p_wh, p_wh);
        122								p_x--;
        123								piece();
        124							}
        125							else if (p[p_y][p_x-1] == 0 && p[p_y+1][p_x-1] == 0) {
        126								p[p_y][p_x-1]   = p[p_y][p_x];
        127								p[p_y+1][p_x-1] = p[p_y+1][p_x];
        128								p[p_y][p_x]     = 0;
        129								p[p_y+1][p_x]   = 0;
        130								let kx = 10 + p_wh * p_x;
        131								let ky = 10 + p_wh * p_y;
        132								ctx.fillStyle = 'rgb(255, 255, 255)';
        133								ctx.fillRect(kx, ky, p_wh, p_wh);
        134								ky = 10 + p_wh * (p_y + 1);
        135								ctx.fillRect(kx, ky, p_wh, p_wh);
        136								p_x--;
        137								piece();
        138							}
        139						}
        140					}
        141					else if (e.keyCode == 39) {   // 右矢印(右移動)
        142						if (rot == 0) {
        143							if (p_x < col-2 && p[p_y][p_x+2] == 0) {
        144								p[p_y][p_x+2] = p[p_y][p_x+1];
        145								p[p_y][p_x+1] = p[p_y][p_x];
        146								p[p_y][p_x]   = 0;
        147								let kx = 10 + p_wh * p_x;
        148								let ky = 10 + p_wh * p_y;
        149								ctx.fillStyle = 'rgb(255, 255, 255)';
        150								ctx.fillRect(kx, ky, p_wh, p_wh);
        151								p_x++;
        152								piece();
        153							}
        154						}
        155						else {
        156							if (p_x < col-1 && p[p_y][p_x+1] == 0 && p[p_y+1][p_x+1] == 0) {
        157								p[p_y][p_x+1]   = p[p_y][p_x];
        158								p[p_y+1][p_x+1] = p[p_y+1][p_x];
        159								p[p_y][p_x]     = 0;
        160								p[p_y+1][p_x]   = 0;
        161								let kx = 10 + p_wh * p_x;
        162								let ky = 10 + p_wh * p_y;
        163								ctx.fillStyle   = 'rgb(255, 255, 255)';
        164								ctx.fillRect(kx, ky, p_wh, p_wh);
        165								ky = 10 + p_wh * (p_y + 1);
        166								ctx.fillRect(kx, ky, p_wh, p_wh);
        167								p_x++;
        168								piece();
        169							}
        170						}
        171					}
        172					else if (e.keyCode == 38) {   // 上矢印(上下または左右入れ替え)
        173						if (rot == 0) {
        174							let k = p[p_y][p_x];
        175							p[p_y][p_x]   = p[p_y][p_x+1];
        176							p[p_y][p_x+1] = k;
        177						}
        178						else {
        179							let k = p[p_y][p_x];
        180							p[p_y][p_x]   = p[p_y+1][p_x];
        181							p[p_y+1][p_x] = k;
        182						}
        183						piece();
        184					}
        185					else if (e.keyCode == 40) {   // 下矢印(90度または-90度回転)
        186						if (rot == 0 && p[p_y+1][p_x] == 0) {
        187							if (p_y < row-1) {
        188								p[p_y+1][p_x] = p[p_y][p_x+1];
        189								p[p_y][p_x+1] = 0;
        190								let kx = 10 + p_wh * (p_x + 1);
        191								let ky = 10 + p_wh * p_y;
        192								ctx.fillStyle = 'rgb(255, 255, 255)';
        193								ctx.fillRect(kx, ky, p_wh, p_wh);
        194								rot = 1;
        195								piece();
        196							}
        197						}
        198						else {
        199							if (p_x < col-1 && p[p_y][p_x+1] == 0) {
        200								p[p_y][p_x+1] = p[p_y+1][p_x];
        201								p[p_y+1][p_x] = 0;
        202								let kx = 10 + p_wh * p_x;
        203								let ky = 10 + p_wh * (p_y + 1);
        204								ctx.fillStyle = 'rgb(255, 255, 255)';
        205								ctx.fillRect(kx, ky, p_wh, p_wh);
        206								rot = 0;
        207								piece();
        208							}
        209						}
        210					}
        211				}
        212			}
        213						//
        214						// ピースの描画
        215						//
        216			function piece()
        217			{
        218				for (let i1 = 0; i1 < row; i1++) {
        219					for (let i2 = 0; i2 < col; i2++) {
        220						if (p[i1][i2] > 0) {
        221							switch (p[i1][i2]) {
        222								case 1:
        223									ctx.fillStyle  = 'rgb(255, 0, 0)';
        224									break;
        225								case 2:
        226									ctx.fillStyle  = 'rgb(255, 215, 0)';
        227									break;
        228								case 3:
        229									ctx.fillStyle  = 'rgb(0, 255, 255)';
        230									break;
        231								case 4:
        232									ctx.fillStyle  = 'rgb(173, 255, 47)';
        233									break;
        234							}
        235							let kx = 10 + p_wh * i2;
        236							let ky = 10 + p_wh * i1;
        237							ctx.fillRect(kx, ky, p_wh, p_wh);
        238						}
        239					}
        240				}
        241			}
        242						//
        243						// ピースの選択
        244						//
        245			function select()
        246			{
        247				ok  = true;
        248				rot = 0;
        249				p_y = 0;
        250				p_x = Math.floor(Math.random() * (col - 1));
        251				if (p_x > col-2)
        252					p_x = col - 2;
        253	
        254				let color = Math.floor(Math.random() * 4) + 1;
        255				if (color > 4)
        256					color = 4;
        257				p[0][p_x] = color;
        258				color = Math.floor(Math.random() * 4) + 1;
        259				if (color > 4)
        260					color = 4;
        261				p[0][p_x+1] = color;
        262	
        263				piece();
        264			}
        265		</SCRIPT>
        266	</HEAD>
        267	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()" onKeyDown="keyDown(event)">
        268		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム(ステップ4)</H2>
        269		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
        270	</BODY>
        271	</HTML>
        					
        072 行目~ 085 行目

          ピースが縦並びの場合の落下処理.横並びの場合も同様であるが,最下段に到達したときは,キーイベントを受け付けないようにしている( 085 行目)

        114 行目~ 124 行目

          左矢印キーが押され,ピースが横並びであった場合の処理である.左側に他のピースが存在しない場合は,左側に移動する.

        125 行目~ 138 行目

          左矢印キーが押され,ピースが縦並びであった場合の処理である.左側に他のピースが存在しない場合は,左側に移動する.

        141 行目~ 171 行目

          右矢印キーによって右移動するための処理である.左矢印キーが押された場合と同様の処理を行っている.

        172 行目~ 184 行目

          上矢印キーが押された場合の処理であり,上下,または,左右の色を入れ替えている.

        185 行目~ 210 行目

          下矢印キーが押された場合の処理であり,回転可能な場合は,回転させる処理を行っている.

      5. ピースの積み上げ:  このままでは,ピースが積み上がっていきません.落下しているピースが,他のピースの上に乗ったらそこで止めるための処理が必要になります.特に,横並びの場合,一つのピースだけが他のピースの上に乗った場合,キーイベントの処理を受け付けないようにした後(変数 ok を false ),乗っていないピースだけを落下させる処理が必要になる点に注意して下さい.また,上まで積み上がるとゲームオーバーになる処理も追加しています.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>ぷよぷよ風ゲーム(ステップ5)</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas = null;
        009			ctx    = null;
        010			p      = new Array();   // ピースの色(0の時は存在しない)
        011			row    = 12;   // 行の数
        012			col    = 5;   // 列の数
        013			p_x    = -1;   // 動いているピースの位置(列)
        014			p_y    = -1;   // 動いているピースの位置(行)
        015			p_wh   = 30;   // ピースの幅と高さ
        016			rot    = 0;   // 横か縦か(0:横,1:縦)
        017			game   = true;   // ゲーム中か否か
        018			ok     = true;   // キーイベントを受け付けるか否か
        019						//
        020						// 開始
        021						//
        022			function start()
        023			{
        024				canvas        = document.getElementById('canvas_e');
        025				canvas.width  = 270;   // キャンバス要素の幅
        026				canvas.height = 380;   // キャンバス要素の高さ
        027				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        028				ctx.fillStyle = 'rgb(255, 255, 255)';
        029				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        030								// ピースの配置
        031				for (let i1 = 0; i1 < row; i1++) {
        032					p[i1] = new Array();
        033					for (let i2 = 0; i2 < col; i2++)
        034						p[i1][i2] = 0;
        035				}
        036								// ピースの選択
        037				select();
        038	
        039				timerID = setInterval('draw()', 500);
        040			}
        041						//
        042						// 一定時間毎の処理
        043						//
        044			function draw()
        045			{
        046								// ゲーム中
        047				if (game) {
        048										// ピースの落下
        049					let ct = 0;   // ct が 0 であることは,ピースの動きが止まったことを示す
        050												// 横並び
        051					if (rot == 0) {
        052						if (p_y < row-1) {
        053							if (ok) {
        054														// 分離しない
        055								if (p[p_y+1][p_x] == 0 && p[p_y+1][p_x+1] == 0) {
        056									ct              = 1;
        057									p[p_y+1][p_x]   = p[p_y][p_x];
        058									p[p_y+1][p_x+1] = p[p_y][p_x+1];
        059									p[p_y][p_x]     = 0;
        060									p[p_y][p_x+1]   = 0;
        061									let kx = 10 + p_wh * p_x;
        062									let ky = 10 + p_wh * p_y;
        063									ctx.fillStyle = 'rgb(255, 255, 255)';
        064									ctx.fillRect(kx, ky, p_wh, p_wh);
        065									kx = 10 + p_wh * (p_x + 1);
        066									ctx.fillRect(kx, ky, p_wh, p_wh);
        067									p_y++;
        068									piece();
        069								}
        070														// 分離
        071								else {
        072									ok = false;
        073									if (p[p_y+1][p_x] == 0) {
        074										ct            = 1;
        075										p[p_y+1][p_x] = p[p_y][p_x];
        076										p[p_y][p_x]   = 0;
        077										let kx = 10 + p_wh * p_x;
        078										let ky = 10 + p_wh * p_y;
        079										ctx.fillStyle = 'rgb(255, 255, 255)';
        080										ctx.fillRect(kx, ky, p_wh, p_wh);
        081										p_y++;
        082										piece();
        083									}
        084									else if (p[p_y+1][p_x+1] == 0) {
        085										ct              = 1;
        086										p[p_y+1][p_x+1] = p[p_y][p_x+1];
        087										p[p_y][p_x+1]   = 0;
        088										let kx = 10 + p_wh * (p_x + 1);
        089										let ky = 10 + p_wh * p_y;
        090										ctx.fillStyle = 'rgb(255, 255, 255)';
        091										ctx.fillRect(kx, ky, p_wh, p_wh);
        092										p_x++;
        093										p_y++;
        094										piece();
        095									}
        096								}
        097							}
        098							else {
        099								if (p[p_y+1][p_x] == 0) {
        100									ct            = 1;
        101									p[p_y+1][p_x] = p[p_y][p_x];
        102									p[p_y][p_x]   = 0;
        103									let kx = 10 + p_wh * p_x;
        104									let ky = 10 + p_wh * p_y;
        105									ctx.fillStyle = 'rgb(255, 255, 255)';
        106									ctx.fillRect(kx, ky, p_wh, p_wh);
        107									p_y++;
        108									piece();
        109								}
        110							}
        111						}
        112						else
        113							ok = false;
        114					}
        115												// 縦並び
        116					else {
        117						if (p_y < row-2 && p[p_y+2][p_x] == 0) {
        118							ct            = 1;
        119							p[p_y+2][p_x] = p[p_y+1][p_x];
        120							p[p_y+1][p_x] = p[p_y][p_x];
        121							p[p_y][p_x]   = 0;
        122							let kx = 10 + p_wh * p_x;
        123							let ky = 10 + p_wh * p_y;
        124							ctx.fillStyle = 'rgb(255, 255, 255)';
        125							ctx.fillRect(kx, ky, p_wh, p_wh);
        126							p_y++;
        127							piece();
        128						}
        129						else
        130							ok = false;
        131					}
        132										// 消去と次のピース
        133					if (ct == 0)
        134						select();
        135				}
        136								// ゲームオーバー
        137				else {
        138					ctx.fillStyle = 'rgb(255, 255, 255)';
        139					ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        140					ctx.fillStyle = 'rgb(0, 0, 0)';
        141					ctx.font = "50px 'MS ゴシック'";
        142					let met  = ctx.measureText("Game");
        143					let px   = 10 + p_wh * col / 2 - met.width / 2;
        144					let py   = 10 + p_wh * row / 2 - p_wh;
        145					ctx.fillText("Game", px, py);
        146					met = ctx.measureText("Over!");
        147					px  = 10 + p_wh * col / 2 - met.width / 2;
        148					py  = 10 + p_wh * row / 2 + p_wh;
        149					ctx.fillText("Over!", px, py);
        150				}
        151			}
        152						//
        153						// キーが押されたときの処理
        154						//
        155			function keyDown(e) {
        156				if (ok) {
        157					if (e.keyCode == 37) {   // 左矢印(左移動)
        158						if (p_x > 0) {
        159							if (rot == 0 && p[p_y][p_x-1] == 0) {
        160								p[p_y][p_x-1] = p[p_y][p_x];
        161								p[p_y][p_x]   = p[p_y][p_x+1];
        162								p[p_y][p_x+1] = 0;
        163								let kx = 10 + p_wh * (p_x + 1);
        164								let ky = 10 + p_wh * p_y;
        165								ctx.fillStyle = 'rgb(255, 255, 255)';
        166								ctx.fillRect(kx, ky, p_wh, p_wh);
        167								p_x--;
        168								piece();
        169							}
        170							else if (p[p_y][p_x-1] == 0 && p[p_y+1][p_x-1] == 0) {
        171								p[p_y][p_x-1]   = p[p_y][p_x];
        172								p[p_y+1][p_x-1] = p[p_y+1][p_x];
        173								p[p_y][p_x]     = 0;
        174								p[p_y+1][p_x]   = 0;
        175								let kx = 10 + p_wh * p_x;
        176								let ky = 10 + p_wh * p_y;
        177								ctx.fillStyle = 'rgb(255, 255, 255)';
        178								ctx.fillRect(kx, ky, p_wh, p_wh);
        179								ky = 10 + p_wh * (p_y + 1);
        180								ctx.fillRect(kx, ky, p_wh, p_wh);
        181								p_x--;
        182								piece();
        183							}
        184						}
        185					}
        186					else if (e.keyCode == 39) {   // 右矢印(右移動)
        187						if (rot == 0) {
        188							if (p_x < col-2 && p[p_y][p_x+2] == 0) {
        189								p[p_y][p_x+2] = p[p_y][p_x+1];
        190								p[p_y][p_x+1] = p[p_y][p_x];
        191								p[p_y][p_x]   = 0;
        192								let kx = 10 + p_wh * p_x;
        193								let ky = 10 + p_wh * p_y;
        194								ctx.fillStyle = 'rgb(255, 255, 255)';
        195								ctx.fillRect(kx, ky, p_wh, p_wh);
        196								p_x++;
        197								piece();
        198							}
        199						}
        200						else {
        201							if (p_x < col-1 && p[p_y][p_x+1] == 0 && p[p_y+1][p_x+1] == 0) {
        202								p[p_y][p_x+1]   = p[p_y][p_x];
        203								p[p_y+1][p_x+1] = p[p_y+1][p_x];
        204								p[p_y][p_x]     = 0;
        205								p[p_y+1][p_x]   = 0;
        206								let kx = 10 + p_wh * p_x;
        207								let ky = 10 + p_wh * p_y;
        208								ctx.fillStyle = 'rgb(255, 255, 255)';
        209								ctx.fillRect(kx, ky, p_wh, p_wh);
        210								ky = 10 + p_wh * (p_y + 1);
        211								ctx.fillRect(kx, ky, p_wh, p_wh);
        212								p_x++;
        213								piece();
        214							}
        215						}
        216					}
        217					else if (e.keyCode == 38) {   // 上矢印(上下または左右入れ替え)
        218						if (rot == 0) {
        219							let k = p[p_y][p_x];
        220							p[p_y][p_x]   = p[p_y][p_x+1];
        221							p[p_y][p_x+1] = k;
        222						}
        223						else {
        224							let k = p[p_y][p_x];
        225							p[p_y][p_x]   = p[p_y+1][p_x];
        226							p[p_y+1][p_x] = k;
        227						}
        228						piece();
        229					}
        230					else if (e.keyCode == 40) {   // 下矢印(90度または-90度回転)
        231						if (rot == 0 && p[p_y+1][p_x] == 0) {
        232							if (p_y < row-1) {
        233								p[p_y+1][p_x] = p[p_y][p_x+1];
        234								p[p_y][p_x+1] = 0;
        235								let kx = 10 + p_wh * (p_x + 1);
        236								let ky = 10 + p_wh * p_y;
        237								ctx.fillStyle = 'rgb(255, 255, 255)';
        238								ctx.fillRect(kx, ky, p_wh, p_wh);
        239								rot = 1;
        240								piece();
        241							}
        242						}
        243						else {
        244							if (p_x < col-1 && p[p_y][p_x+1] == 0) {
        245								p[p_y][p_x+1] = p[p_y+1][p_x];
        246								p[p_y+1][p_x] = 0;
        247								let kx = 10 + p_wh * p_x;
        248								let ky = 10 + p_wh * (p_y + 1);
        249								ctx.fillStyle = 'rgb(255, 255, 255)';
        250								ctx.fillRect(kx, ky, p_wh, p_wh);
        251								rot = 0;
        252								piece();
        253							}
        254						}
        255					}
        256				}
        257			}
        258						//
        259						// ピースの描画
        260						//
        261			function piece()
        262			{
        263				for (let i1 = 0; i1 < row; i1++) {
        264					for (let i2 = 0; i2 < col; i2++) {
        265						if (p[i1][i2] > 0) {
        266							switch (p[i1][i2]) {
        267								case 1:
        268									ctx.fillStyle  = 'rgb(255, 0, 0)';
        269									break;
        270								case 2:
        271									ctx.fillStyle  = 'rgb(255, 215, 0)';
        272									break;
        273								case 3:
        274									ctx.fillStyle  = 'rgb(0, 255, 255)';
        275									break;
        276								case 4:
        277									ctx.fillStyle  = 'rgb(173, 255, 47)';
        278									break;
        279							}
        280							let kx = 10 + p_wh * i2;
        281							let ky = 10 + p_wh * i1;
        282							ctx.fillRect(kx, ky, p_wh, p_wh);
        283						}
        284					}
        285				}
        286			}
        287						//
        288						// ピースの選択
        289						//
        290			function select()
        291			{
        292				ok  = true;
        293				rot = 0;
        294				p_y = 0;
        295				p_x = Math.floor(Math.random() * (col - 1));
        296				if (p_x > col-2)
        297					p_x = col - 2;
        298	
        299				if (p[0][p_x] == 0 && p[0][p_x+1] ==0 ) {
        300					let color = Math.floor(Math.random() * 4) + 1;
        301					if (color > 4)
        302						color = 4;
        303					p[0][p_x] = color;
        304					color = Math.floor(Math.random() * 4) + 1;
        305					if (color > 4)
        306						color = 4;
        307					p[0][p_x+1] = color;
        308				}
        309				else
        310					game = false;
        311	
        312				piece();
        313			}
        314		</SCRIPT>
        315	</HEAD>
        316	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()" onKeyDown="keyDown(event)">
        317		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム(ステップ5)</H2>
        318		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
        319	</BODY>
        320	</HTML>
        					
        055 行目~ 069 行目

          ピースが横並びで,かつ,2 つのピースが同時に落下する場合の処理である.

        072 行目

          071 行目~ 096 行目は,左右いずれかのピースが他のピースの上に乗った場合の処理である.ここでは,変数 ok を false に設定し,イベントを受け付けないようにしている.従って,ok が false であることは,ピースが最下段に到達するか,または,横並びの 2 つのピースが分離し,1 つのピースだけが落下している状態であることを意味する.

        073 行目~ 083 行目

          右側のピースが他のピースの上に乗り,左側のピースだけが落下する状態を開始する処理である.

        084 行目~ 095 行目

          上と同様,左側のピースが他のピースの上に乗り,右側のピースだけが落下する状態を開始する処理である.

        099 行目~ 109 行目

          1 つのピースだけが落下している場合に対する処理である.

        117 行目~ 130 行目

          ピースが縦に並んでいる場合に対する落下処理である.

        299 行目,309 行目~ 310 行目

          ピースを生成した位置に,他のピースが存在した場合は,ゲームオーバーにしている..

      6. ピースの削除:  最後に行わなければならないのがピースの削除です.同じ色のピースが縦横 4 個以上並んだ場合,それらを削除し,それらの上に乗っていたピースを可能なところまで落下させます.メソッド search で同じ色のピースを数え,メソッド delete で削除しています.

        001	<!DOCTYPE HTML>
        002	<HTML>
        003	<HEAD>
        004		<TITLE>ぷよぷよ風ゲーム</TITLE>
        005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
        006		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        007		<SCRIPT TYPE="text/javascript">
        008			canvas = null;
        009			ctx    = null;
        010			p      = new Array();   // ピースの色(0の時は存在しない)
        011			pp     = new Array();   // ピースの色(作業域)
        012			row    = 12;   // 行の数
        013			col    = 5;   // 列の数
        014			p_x    = -1;   // 動いているピースの位置(列)
        015			p_y    = -1;   // 動いているピースの位置(行)
        016			p_wh   = 30;   // ピースの幅と高さ
        017			rot    = 0;   // 横か縦か(0:横,1:縦)
        018			game   = true;   // ゲーム中か否か
        019			ok     = true;   // キーイベントを受け付けるか否か
        020						//
        021						// 開始
        022						//
        023			function start()
        024			{
        025				canvas        = document.getElementById('canvas_e');
        026				canvas.width  = 270;   // キャンバス要素の幅
        027				canvas.height = 380;   // キャンバス要素の高さ
        028				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
        029				ctx.fillStyle = 'rgb(255, 255, 255)';
        030				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        031								// ピースの配置
        032				for (let i1 = 0; i1 < row; i1++) {
        033					p[i1]  = new Array();
        034					pp[i1] = new Array();
        035					for (let i2 = 0; i2 < col; i2++) {
        036						p[i1][i2]  = 0;
        037						pp[i1][i2] = 0;
        038					}
        039				}
        040								// ピースの選択
        041				select();
        042	
        043				timerID = setInterval('draw()', 500);
        044			}
        045						//
        046						// 一定時間毎の処理
        047						//
        048			function draw()
        049			{
        050								// ゲーム中
        051				if (game) {
        052										// ピースの落下
        053					let ct = 0;   // ct が 0 であることは,ピースの動きが止まったことを示す
        054												// 横並び
        055					if (rot == 0) {
        056						if (p_y < row-1) {
        057							if (ok) {
        058														// 分離しない
        059								if (p[p_y+1][p_x] == 0 && p[p_y+1][p_x+1] == 0) {
        060									ct              = 1;
        061									p[p_y+1][p_x]   = p[p_y][p_x];
        062									p[p_y+1][p_x+1] = p[p_y][p_x+1];
        063									p[p_y][p_x]     = 0;
        064									p[p_y][p_x+1]   = 0;
        065									let kx = 10 + p_wh * p_x;
        066									let ky = 10 + p_wh * p_y;
        067									ctx.fillStyle = 'rgb(255, 255, 255)';
        068									ctx.fillRect(kx, ky, p_wh, p_wh);
        069									kx = 10 + p_wh * (p_x + 1);
        070									ctx.fillRect(kx, ky, p_wh, p_wh);
        071									p_y++;
        072									piece();
        073								}
        074														// 分離
        075								else {
        076									ok = false;
        077									if (p[p_y+1][p_x] == 0) {
        078										ct            = 1;
        079										p[p_y+1][p_x] = p[p_y][p_x];
        080										p[p_y][p_x]   = 0;
        081										let kx = 10 + p_wh * p_x;
        082										let ky = 10 + p_wh * p_y;
        083										ctx.fillStyle = 'rgb(255, 255, 255)';
        084										ctx.fillRect(kx, ky, p_wh, p_wh);
        085										p_y++;
        086										piece();
        087									}
        088									else if (p[p_y+1][p_x+1] == 0) {
        089										ct              = 1;
        090										p[p_y+1][p_x+1] = p[p_y][p_x+1];
        091										p[p_y][p_x+1]   = 0;
        092										let kx = 10 + p_wh * (p_x + 1);
        093										let ky = 10 + p_wh * p_y;
        094										ctx.fillStyle = 'rgb(255, 255, 255)';
        095										ctx.fillRect(kx, ky, p_wh, p_wh);
        096										p_x++;
        097										p_y++;
        098										piece();
        099									}
        100								}
        101							}
        102							else {
        103								if (p[p_y+1][p_x] == 0) {
        104									ct            = 1;
        105									p[p_y+1][p_x] = p[p_y][p_x];
        106									p[p_y][p_x]   = 0;
        107									let kx = 10 + p_wh * p_x;
        108									let ky = 10 + p_wh * p_y;
        109									ctx.fillStyle = 'rgb(255, 255, 255)';
        110									ctx.fillRect(kx, ky, p_wh, p_wh);
        111									p_y++;
        112									piece();
        113								}
        114							}
        115						}
        116						else
        117							ok = false;
        118					}
        119												// 縦並び
        120					else {
        121						if (p_y < row-2 && p[p_y+2][p_x] == 0) {
        122							ct            = 1;
        123							p[p_y+2][p_x] = p[p_y+1][p_x];
        124							p[p_y+1][p_x] = p[p_y][p_x];
        125							p[p_y][p_x]   = 0;
        126							let kx = 10 + p_wh * p_x;
        127							let ky = 10 + p_wh * p_y;
        128							ctx.fillStyle = 'rgb(255, 255, 255)';
        129							ctx.fillRect(kx, ky, p_wh, p_wh);
        130							p_y++;
        131							piece();
        132						}
        133						else
        134							ok = false;
        135					}
        136										// 消去と次のピース
        137					if (ct == 0) {
        138						ct = 4;
        139						while (ct >= 4) {
        140							ct = 0;
        141							for (let i1 = row-1; i1 >= 0 && ct < 4; i1--) {
        142								for (let i2 = 0; i2 < col && ct < 4; i2++) {
        143									for (let i3 = 0; i3 < row; i3++) {
        144										for (let i4 = 0; i4 < col; i4++)
        145											pp[i3][i4] = 0;
        146									}
        147									if (p[i1][i2] > 0) {
        148										pp[i1][i2] = 1;   // 同じ色であることを示す
        149										ct         = search(i1, i2, 1);
        150									}
        151								}
        152							}
        153							if (ct >= 4)
        154								p_delete();
        155						}
        156						piece();
        157						select();
        158					}
        159				}
        160								// ゲームオーバー
        161				else {
        162					ctx.fillStyle = 'rgb(255, 255, 255)';
        163					ctx.fillRect(10, 10, p_wh*col, p_wh*row);
        164					ctx.fillStyle = 'rgb(0, 0, 0)';
        165					ctx.font = "50px 'MS ゴシック'";
        166					let met  = ctx.measureText("Game");
        167					let px   = 10 + p_wh * col / 2 - met.width / 2;
        168					let py   = 10 + p_wh * row / 2 - p_wh;
        169					ctx.fillText("Game", px, py);
        170					met = ctx.measureText("Over!");
        171					px  = 10 + p_wh * col / 2 - met.width / 2;
        172					py  = 10 + p_wh * row / 2 + p_wh;
        173					ctx.fillText("Over!", px, py);
        174				}
        175			}
        176						//
        177						// キーが押されたときの処理
        178						//
        179			function keyDown(e) {
        180				if (ok) {
        181					if (e.keyCode == 37) {   // 左矢印(左移動)
        182						if (p_x > 0) {
        183							if (rot == 0 && p[p_y][p_x-1] == 0) {
        184								p[p_y][p_x-1] = p[p_y][p_x];
        185								p[p_y][p_x]   = p[p_y][p_x+1];
        186								p[p_y][p_x+1] = 0;
        187								let kx = 10 + p_wh * (p_x + 1);
        188								let ky = 10 + p_wh * p_y;
        189								ctx.fillStyle = 'rgb(255, 255, 255)';
        190								ctx.fillRect(kx, ky, p_wh, p_wh);
        191								p_x--;
        192								piece();
        193							}
        194							else if (p[p_y][p_x-1] == 0 && p[p_y+1][p_x-1] == 0) {
        195								p[p_y][p_x-1]   = p[p_y][p_x];
        196								p[p_y+1][p_x-1] = p[p_y+1][p_x];
        197								p[p_y][p_x]     = 0;
        198								p[p_y+1][p_x]   = 0;
        199								let kx = 10 + p_wh * p_x;
        200								let ky = 10 + p_wh * p_y;
        201								ctx.fillStyle = 'rgb(255, 255, 255)';
        202								ctx.fillRect(kx, ky, p_wh, p_wh);
        203								ky = 10 + p_wh * (p_y + 1);
        204								ctx.fillRect(kx, ky, p_wh, p_wh);
        205								p_x--;
        206								piece();
        207							}
        208						}
        209					}
        210					else if (e.keyCode == 39) {   // 右矢印(右移動)
        211						if (rot == 0) {
        212							if (p_x < col-2 && p[p_y][p_x+2] == 0) {
        213								p[p_y][p_x+2] = p[p_y][p_x+1];
        214								p[p_y][p_x+1] = p[p_y][p_x];
        215								p[p_y][p_x]   = 0;
        216								let kx = 10 + p_wh * p_x;
        217								let ky = 10 + p_wh * p_y;
        218								ctx.fillStyle = 'rgb(255, 255, 255)';
        219								ctx.fillRect(kx, ky, p_wh, p_wh);
        220								p_x++;
        221								piece();
        222							}
        223						}
        224						else {
        225							if (p_x < col-1 && p[p_y][p_x+1] == 0 && p[p_y+1][p_x+1] == 0) {
        226								p[p_y][p_x+1]   = p[p_y][p_x];
        227								p[p_y+1][p_x+1] = p[p_y+1][p_x];
        228								p[p_y][p_x]     = 0;
        229								p[p_y+1][p_x]   = 0;
        230								let kx = 10 + p_wh * p_x;
        231								let ky = 10 + p_wh * p_y;
        232								ctx.fillStyle = 'rgb(255, 255, 255)';
        233								ctx.fillRect(kx, ky, p_wh, p_wh);
        234								ky = 10 + p_wh * (p_y + 1);
        235								ctx.fillRect(kx, ky, p_wh, p_wh);
        236								p_x++;
        237								piece();
        238							}
        239						}
        240					}
        241					else if (e.keyCode == 38) {   // 上矢印(上下または左右入れ替え)
        242						if (rot == 0) {
        243							let k = p[p_y][p_x];
        244							p[p_y][p_x]   = p[p_y][p_x+1];
        245							p[p_y][p_x+1] = k;
        246						}
        247						else {
        248							let k = p[p_y][p_x];
        249							p[p_y][p_x]   = p[p_y+1][p_x];
        250							p[p_y+1][p_x] = k;
        251						}
        252						piece();
        253					}
        254					else if (e.keyCode == 40) {   // 下矢印(90度または-90度回転)
        255						if (rot == 0 && p[p_y+1][p_x] == 0) {
        256							if (p_y < row-1) {
        257								p[p_y+1][p_x] = p[p_y][p_x+1];
        258								p[p_y][p_x+1] = 0;
        259								let kx = 10 + p_wh * (p_x + 1);
        260								let ky = 10 + p_wh * p_y;
        261								ctx.fillStyle = 'rgb(255, 255, 255)';
        262								ctx.fillRect(kx, ky, p_wh, p_wh);
        263								rot = 1;
        264								piece();
        265							}
        266						}
        267						else {
        268							if (p_x < col-1 && p[p_y][p_x+1] == 0) {
        269								p[p_y][p_x+1] = p[p_y+1][p_x];
        270								p[p_y+1][p_x] = 0;
        271								let kx = 10 + p_wh * p_x;
        272								let ky = 10 + p_wh * (p_y + 1);
        273								ctx.fillStyle = 'rgb(255, 255, 255)';
        274								ctx.fillRect(kx, ky, p_wh, p_wh);
        275								rot = 0;
        276								piece();
        277							}
        278						}
        279					}
        280				}
        281			}
        282						//
        283						// ピースの描画
        284						//
        285			function piece()
        286			{
        287				for (let i1 = 0; i1 < row; i1++) {
        288					for (let i2 = 0; i2 < col; i2++) {
        289						if (p[i1][i2] > 0) {
        290							switch (p[i1][i2]) {
        291								case 1:
        292									ctx.fillStyle  = 'rgb(255, 0, 0)';
        293									break;
        294								case 2:
        295									ctx.fillStyle  = 'rgb(255, 215, 0)';
        296									break;
        297								case 3:
        298									ctx.fillStyle  = 'rgb(0, 255, 255)';
        299									break;
        300								case 4:
        301									ctx.fillStyle  = 'rgb(173, 255, 47)';
        302									break;
        303							}
        304							let kx = 10 + p_wh * i2;
        305							let ky = 10 + p_wh * i1;
        306							ctx.fillRect(kx, ky, p_wh, p_wh);
        307						}
        308					}
        309				}
        310			}
        311						//
        312						// ピースの選択
        313						//
        314			function select()
        315			{
        316				ok  = true;
        317				rot = 0;
        318				p_y = 0;
        319				p_x = Math.floor(Math.random() * (col - 1));
        320				if (p_x > col-2)
        321					p_x = col - 2;
        322	
        323				if (p[0][p_x] == 0 && p[0][p_x+1] ==0 ) {
        324					let color = Math.floor(Math.random() * 4) + 1;
        325					if (color > 4)
        326						color = 4;
        327					p[0][p_x] = color;
        328					color = Math.floor(Math.random() * 4) + 1;
        329					if (color > 4)
        330						color = 4;
        331					p[0][p_x+1] = color;
        332				}
        333				else
        334					game = false;
        335	
        336				piece();
        337			}
        338						//
        339						// 同じ色のピースを探す
        340						//
        341			function search(k1, k2, c1)
        342			{
        343				let c2 = c1;
        344	
        345				if (k1 > 0 && p[k1-1][k2] == p[k1][k2] && pp[k1-1][k2] == 0) {
        346					pp[k1-1][k2] = 1;
        347					c2           = search(k1-1, k2, c2+1);
        348				}
        349				if (k1 < row-1 && p[k1+1][k2] == p[k1][k2] && pp[k1+1][k2] == 0) {
        350					pp[k1+1][k2] = 1;
        351					c2           = search(k1+1, k2, c2+1);
        352				}
        353				if (k2 > 0 && p[k1][k2-1] == p[k1][k2] && pp[k1][k2-1] == 0) {
        354					pp[k1][k2-1] = 1;
        355					c2           = search(k1, k2-1, c2+1);
        356				}
        357				if (k2 < col-1 && p[k1][k2+1] == p[k1][k2] && pp[k1][k2+1] == 0) {
        358					pp[k1][k2+1] = 1;
        359					c2           = search(k1, k2+1, c2+1);
        360				}
        361	
        362				return c2;
        363			}
        364						//
        365						// ピースの削除
        366						//
        367			function p_delete()
        368			{
        369								// 削除
        370				for (let i1 = 0; i1 < row; i1++) {
        371					for (let i2 = 0; i2 < col; i2++) {
        372						if (pp[i1][i2] > 0) {
        373							p[i1][i2] = 0;
        374							let kx = 10 + p_wh * i2;
        375							let ky = 10 + p_wh * i1;
        376							ctx.fillStyle = 'rgb(255, 255, 255)';
        377							ctx.fillRect(kx, ky, p_wh, p_wh);
        378						}
        379					}
        380				}
        381								// 詰める
        382				for (let i1 = 0; i1 < col; i1++) {
        383					let k1 = 1;
        384					for (let i2 = row-1; i2 > 0 && k1 >= 0; i2--) {
        385						if (p[i2][i1] == 0) {
        386							k1 = -1;
        387							for (let i3 = i2-1; i3 >= 0 && k1 < 0; i3--) {
        388								if (p[i3][i1] > 0)
        389									k1 = i3;
        390							}
        391							if (k1 >= 0) {
        392								let k2 = i2;
        393								while (k1 >= 0) {
        394									p[k2][i1] = p[k1][i1];
        395									if (p[k1][i1] > 0) {
        396										p[k1][i1] = 0;
        397										let kx = 10 + p_wh * i1;
        398										let ky = 10 + p_wh * k1;
        399										ctx.fillStyle = 'rgb(255, 255, 255)';
        400										ctx.fillRect(kx, ky, p_wh, p_wh);
        401									}
        402									k1--;
        403									k2--;
        404								}
        405								k1++;
        406							}
        407						}
        408					}
        409				}
        410			}
        411		</SCRIPT>
        412	</HEAD>
        413	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()" onKeyDown="keyDown(event)">
        414		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム</H2>
        415		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
        416	</BODY>
        417	</HTML>
        					
        032 行目~ 039 行目

          ピースの存在を示す 2 次元配列 p を定義すると共に,作業域として使用するため,同じ大きさの配列 pp を定義している.

        137 行目~ 158 行目

          ピースが再下端に達するか,または,他のピースの上に乗って停止した場合に対する処理である.141 行目~ 152 行目において,関数 search によって,ピース p[i1][i2] と隣り合っている同じ色のピースの数を調べ,その値が 4 以上である場合は,関数 p_delete によってそれらのピースを削除している.これら全体を 139 行目の while 文によって繰り返しているのは,削除の結果,再び同じ色のピースが繋がる可能性があるからである.

        341 行目~ 363 行目

          ピース p[k1][k2] の上下左右に同じ色のピースがあるか否かを,再帰呼び出しを利用して調べている.最終的に,隣り合った同じ色のピースの数が返される.

        370 行目~ 380 行目

          隣り合った同じ色のピースを削除している.

        382 行目~ 409 行目

          ピースが存在しない空白を詰める処理である.
        • 385 行目: p[i2][i1] が空白のとき以下の処理が行われる
        • 386 行目~ 390 行目: 空白の上にピースが存在するか否かを調べている.存在する場合は,その行番号が変数 k1 に設定され,392 行目以降が実行される.
        • 392 行目~ 405 行目: k2 行,及び,k2 行から k1 行の間にある空白を詰める.

  4. グラフの描画

    1. データベースと表&グラフ

        データベースの内容を表やグラフで表したい場合がしばしば発生します.表&グラフ(ソースプログラム database.php は以下に示すとおり)は,データベースに保存されている内容を取り出し,その結果を表とグラフで表現しています.このプログラムでは,データベースのテーブルを作成し,データを挿入する操作を行っていますが,これは,あくまでテスト用であり,一般的には必要ありません.なお,PHP に関しては,「 PHP 」を参照して下さい.

      database.php

      001	<!DOCTYPE HTML>
      002	<HTML>
      003	<HEAD>
      004		<TITLE>表&グラフ</TITLE>
      005		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      006		<LINK REL="stylesheet" TYPE="text/css" HREF="master.css">
      007		<SCRIPT TYPE="text/javascript" SRC="graph.js"></SCRIPT>
      008	</HEAD>
      009	<BODY CLASS="white" STYLE="text-align: center">
      010		<H1 CLASS="center">表&グラフ</H3>
      011	<?php
      012						// データベースへの追加
      013		$db = mysql_connect("*****", "*****", "*****");
      014		if (!$db)
      015			exit("<h1>データベースへ接続できません</h1>\n");
      016						// テーブルの削除
      017		mysql_select_db("WEB_SHOP", $db);
      018		$result = mysql_query("SHOW TABLES", $db);
      019		if (mysql_num_rows($result) > 0) {
      020			while ($row = mysql_fetch_row($result)) {
      021				if (strcmp($row[0], "commodity") == 0) {
      022					mysql_query("DROP TABLE commodity", $db);
      023					break;
      024				}
      025			}
      026			mysql_free_result($result);
      027		}
      028						// テーブルの生成とデータの追加
      029		$str = "(id INT AUTO_INCREMENT PRIMARY KEY,itemname varchar(100) not null,stock INT NOT NULL)";
      030		mysql_query("CREATE TABLE commodity ".$str, $db);
      031		if (mysql_errno($db) != 0)
      032			exit("<h1>テーブル commodity を作成できません</h1>\n");
      033		mysql_query("INSERT INTO commodity VALUES(NULL,'商品1',10)", $db);
      034		mysql_query("INSERT INTO commodity VALUES(NULL,'商品2',20)", $db);
      035		mysql_query("INSERT INTO commodity VALUES(NULL,'商品3',4)", $db);
      036		mysql_query("INSERT INTO commodity VALUES(NULL,'商品4',40)", $db);
      037		mysql_query("INSERT INTO commodity VALUES(NULL,'商品5',35)", $db);
      038		mysql_query("INSERT INTO commodity VALUES(NULL,'商品6',4)", $db);
      039		mysql_query("INSERT INTO commodity VALUES(NULL,'商品7',3)", $db);
      040		mysql_query("INSERT INTO commodity VALUES(NULL,'商品8',2)", $db);
      041		mysql_query("INSERT INTO commodity VALUES(NULL,'商品9',15)", $db);
      042		mysql_query("INSERT INTO commodity VALUES(NULL,'商品10',20)", $db);
      043						// データの削除とすべてのデータの出力
      044		mysql_query("DELETE FROM commodity WHERE id IN (1,8)", $db);
      045		$result = mysql_query("SELECT * FROM commodity", $db);
      046		echo "id = 1, 8 を削除\n";
      047		echo "	<DL>\n";
      048		while ($row = mysql_fetch_row($result))
      049			echo "<DT>".$row[0]." ".$row[1]." ".$row[2]."<BR>\n";
      050		echo "	</DL><P>\n";
      051						// データの追加とすべてのデータの出力
      052		mysql_query("INSERT INTO commodity VALUES(NULL,'商品1',10)", $db);
      053		$result = mysql_query("SELECT * FROM commodity", $db);
      054		echo "商品 1 を追加\n";
      055		echo "	<DL>\n";
      056		while ($row = mysql_fetch_row($result))
      057			echo "<DT>".$row[0]." ".$row[1]." ".$row[2]."<BR>\n";
      058		echo "	</DL><P>\n";
      059						// データの修正とすべてのデータの出力
      060		mysql_query("UPDATE commodity SET stock = 50 WHERE id = 11", $db);
      061		$result = mysql_query("SELECT * FROM commodity", $db);
      062		echo "商品 1 のデータを修正\n";
      063		echo "	<DL>\n";
      064		while ($row = mysql_fetch_row($result))
      065			echo "<DT>".$row[0]." ".$row[1]." ".$row[2]."<BR>\n";
      066		echo "	</DL><P>\n";
      067						// データの出力
      068								// グラフ表示の準備
      069		$gp      = "0,在庫の多い商品,商品名,商品在庫,1,在庫";
      070		$x_title = array();
      071		$data    = array();
      072		$n       = 0;
      073		$max     = 0;
      074								// 表の作成
      075		echo "	<TABLE BORDER='1' STYLE='margin-right: auto; margin-left: auto'>\n";
      076		echo "		<TR>\n";
      077		echo "			<TH>商品名</TH>\n";
      078		echo "			<TH>商品在庫</TH>\n";
      079		echo "		</TR>\n";
      080		$result = mysql_query("SELECT * FROM commodity WHERE stock >= 10 ORDER BY stock", $db);
      081		while ($row = mysql_fetch_row($result)) {
      082			echo "		<TR>\n";
      083			echo "			<TD>".$row[1]."</TD>\n";
      084			echo "			<TD>".$row[2]."</TD>\n";
      085			echo "		</TR>\n";
      086			$x_title[$n] = $row[1];
      087			$data[$n] = $row[2];
      088			if ($row[2] > $max)
      089				$max = $row[2];
      090			$n++;
      091		}
      092		echo "	</TABLE>\n";
      093	
      094		mysql_free_result($result);
      095								// グラフ表示データの作成
      096		$gp = $gp.",".$n;   // データの数
      097		for ($i1 = 0; $i1 < $n; $i1++)
      098			$gp = $gp.",".$x_title[$i1];   // x軸タイトル
      099		if ($max > 50) {
      100			$step = 20;
      101			$max  = 100;
      102		}
      103		else {
      104			$step = 10;
      105			$max  = 50;
      106		}
      107		$gp = $gp.",0,".$max.",".$step.",0";  // 最小値,最大値,刻み幅,小数点以下桁数
      108		for ($i1 = 0; $i1 < $n; $i1++)
      109			$gp = $gp.",".$data[$i1];   // データ
      110		$gp = $gp.",1,0";   // グラフタイトルと凡例の表示
      111						// データベースへの接続を切る
      112		mysql_close ($db);
      113	?>
      114		<BR>
      115		<DIV ID="cl_line" STYLE="text-align: center; display: none">
      116			<FORM>
      117				<DIV ID="c0">
      118					<INPUT ID="rgb0" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      119					赤<INPUT ID="r0" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(0)"> 
      120					緑<INPUT ID="g0" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(0)"> 
      121					青<INPUT ID="b0" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(0)">
      122				</DIV>
      123				<DIV ID="c1">
      124					<INPUT ID="rgb1" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      125					赤<INPUT ID="r1" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(1)"> 
      126					緑<INPUT ID="g1" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(1)"> 
      127					青<INPUT ID="b1" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(1)">
      128				</DIV>
      129				<DIV ID="c2">
      130					<INPUT ID="rgb2" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      131					赤<INPUT ID="r2" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(2)"> 
      132					緑<INPUT ID="g2" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(2)"> 
      133					青<INPUT ID="b2" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(2)">
      134				</DIV>
      135				<DIV ID="c3">
      136					<INPUT ID="rgb3" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      137					赤<INPUT ID="r3" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(3)"> 
      138					緑<INPUT ID="g3" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(3)"> 
      139					青<INPUT ID="b3" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(3)">
      140				</DIV>
      141				<DIV ID="c4">
      142					<INPUT ID="rgb4" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      143					赤<INPUT ID="r4" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(4)"> 
      144					緑<INPUT ID="g4" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(4)"> 
      145					青<INPUT ID="b4" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(4)">
      146				</DIV>
      147				<DIV ID="c5">
      148					<INPUT ID="rgb5" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      149					赤<INPUT ID="r5" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(5)"> 
      150					緑<INPUT ID="g5" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(5)"> 
      151					青<INPUT ID="b5" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(5)">
      152				</DIV>
      153				<DIV ID="c6">
      154					<INPUT ID="rgb6" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      155					赤<INPUT ID="r6" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(6)"> 
      156					緑<INPUT ID="g6" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(6)"> 
      157					青<INPUT ID="b6" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(6)">
      158				</DIV>
      159				<DIV ID="c7">
      160					<INPUT ID="rgb7" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      161					赤<INPUT ID="r7" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(7)"> 
      162					緑<INPUT ID="g7" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(7)"> 
      163					青<INPUT ID="b7" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(7)">
      164				</DIV>
      165				<DIV ID="c8">
      166					<INPUT ID="rgb8" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      167					赤<INPUT ID="r8" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(8)"> 
      168					緑<INPUT ID="g8" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(8)"> 
      169					青<INPUT ID="b8" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(8)">
      170				</DIV>
      171				<DIV ID="c9">
      172					<INPUT ID="rgb9" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      173					赤<INPUT ID="r9" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(9)"> 
      174					緑<INPUT ID="g9" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(9)"> 
      175					青<INPUT ID="b9" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(9)">
      176				</DIV>
      177				<DIV ID="line_m">
      178					マーク:<INPUT ID="l_m1" TYPE="radio" NAME="mark" STYLE="font-size: 90%" CHECKED>付ける 
      179					<INPUT ID="l_m2" TYPE="radio" NAME="mark" STYLE="font-size: 90%">付けない
      180				</DIV>
      181				<DIV ID="line_w">
      182					線の太さ:<INPUT ID="l_w" TYPE="text" SIZE="3" STYLE="font-size: 90%" VALUE="2">
      183				</DIV>
      184				<DIV>
      185					<SPAN STYLE="background-color: pink; font-size: 100%" onClick="D_Change()">OK</SPAN>
      186				</DIV>
      187			</FORM>
      188		</DIV>
      189		<BR>
      190		<DIV STYLE="text-align: center">
      191			<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="900" HEIGHT="600" onClick="Click(event)"></CANVAS>
      192		</DIV>
      194		<SCRIPT TYPE="text/javascript">
      194			graph("<?php echo $gp ?>");
      195		</SCRIPT>
      196	</BODY>
      197	</HTML>
      				
      013 行目

        MySQL と接続している.

      017 行目~ 027 行目

        データベース WEB_SHOP に,テーブル commodity が存在した場合は,それを削除している.このプログラムで,テーブルの生成やデータの追加方法を示したいために行っている処理であり,一般的には必要ない.

      029 行目~ 030 行目

        テーブル commodity を作成している.この処理も,一般的には必要ない.

      033 行目~ 042 行目

        テーブル commodity にデータを追加している.この処理も,一般的には必要ない.

      044 行目~ 050 行目

        id が 1 と 8 であるデータを削除し,その結果を表示している.他のデータの id は変化していないことに注意すること.この処理も,一般的には必要ない.

      052 行目~ 058 行目

        上で削除した商品1に対するデータを追加し,その結果を表示している.追加されたデータの id に注意すること.この処理も,一般的には必要ない.

      060 行目~ 066 行目

        商品1に対するデータを修正し,その結果を表示している.この処理も,一般的には必要ない.

      069 行目

        194 行目において呼んでいる関数 graph は,グラフを描画するために必要な情報をカンマ「 , 」で区切った文字列として受け取り,その内容に従って様々なグラフを描画する.変数 $gp には,グラフを描画するために必要な情報が設定される.ここでは,「グラフの種類( 0 は棒グラフを示す),グラフタイトル, x 軸タイトル, y 軸タイトル,グラフの数,各グラフのタイトル(グラフの数だけ入力)」を設定している.

      070 行目~ 073 行目

        このプログラムでは,在庫数が多い商品に対して,商品毎の在庫数を棒グラフで表すことを目的としている.配列変数 $x_title には各商品の商品名,配列変数 $data にはその在庫数,変数 $n には商品の数,及び,変数 $max には最大在庫数が入る.

      075 行目~ 092 行目

        080 行目の SQL 文によって,在庫数が 10 以上の商品を選び,上で述べた変数に必要なデータを設定すると共に,商品名とその在庫数を表で表している.

      096 行目

        データ数(商品数)を変数 $gp に追加している.

      097 行目~ 098 行目

        各商品の商品名を変数 $gp に追加している.

      099 行目~ 106 行目

        $max の値に基づき,縦軸に対する刻み幅と最大値を設定している.

      107 行目

        変数 $gp に,「縦軸の最小値,縦軸の最大値,縦軸の刻み幅,縦軸に表示する数値の小数点以下桁数」を追加している.

      108 行目~ 109 行目

        各商品に対する在庫数を変数 $gp に追加している.グラフの数が複数の場合は,その数だけ,これらの行を繰り返すことになる.

      110 行目

        変数 $gp に,「グラフタイトルを表示するか否か( 1:表示,0:表示しない),凡例を表示するか否か( 1:表示,0:表示しない)」を追加している.

      115 行目~ 188 行目

        色や線の太さ等を修正するためのエリアであり,初期状態では表示されず,グラフ内の「色」ボタンをクリックすると表示される.

      194 行目

        変数 $gp に設定された内容を引数として,関数 graph を呼んでいる.

        上記のプログラムにおいて使用している関数 graph は,与えられた引数に基づき,必要なグラフを描くための汎用関数です.graph では,グラフの種類によって異なるプログラムを呼び出し,グラフを描くことになります.以下に示すように,graph.js には,graph,及び,様々なグラフを描くための関数が定義されています.以下のプログラムを見れば,描きたいグラフによって,どのようなデータを,どのような順番で引数として渡される文字列に記述すべきかが分かると思います.

      canvas  = null;
      ctx     = null;
      title   = null;   // グラフタイトル, x軸タイトル, y軸タイトル
      n_g     = 0;   // グラフの数
      g_title = null;   // 各グラフのタイトル(凡例)
      n_p     = 0;   // データの数
      x_title = null;   // x軸への表示内容
      x_scale = null;   // x軸の最小値, y軸の最大値, y軸の刻み幅
      xx_scale = null;   // x_scale の対数値
      place_x = 0;   // x軸の小数点以下桁数
      y_scale = null;   // y軸の最小値, y軸の最大値, y軸の刻み幅
      place_y = 0;   // y軸の小数点以下桁数
      data_x  = null;   // データ(x軸,n_g×n_p個)
      data_y  = null;   // データ(y軸,n_g×n_p個)
      data_xx = null;   // data_x の対数値
      d_t     = true;   // グラフタイトル表示の有無
      d_g     = true;   // 凡例表示の有無
      kind    = 0;   // グラフの種類
      ver     = true;   // 縦か横か( true が縦)
      cx      = 0;   // 表示切り替えボタンのx座標
      cy      = 0;   // 表示切り替えボタンのy座標
      cw      = 0;   // 表示切り替えボタンの幅
      ch      = 0;   // 表示切り替えボタンの高さ
      x_base  = 0;   // キャンバスの左上のx座標
      y_base  = 0;   // キャンバスの左上のy座標
      cl      = new Array(10);   // グラフの色
      cl[0]   = "rgb(0, 0, 0)";
      cl[1]   = "rgb(255, 0, 255)";
      cl[2]   = "rgb(0, 0, 255)";
      cl[3]   = "rgb(128, 0, 128)";
      cl[4]   = "rgb(0, 255, 255)";
      cl[5]   = "rgb(0, 128, 128)";
      cl[6]   = "rgb(0, 128, 0)";
      cl[7]   = "rgb(192, 192, 192)";
      cl[8]   = "rgb(255, 0, 0)";
      cl[9]   = "rgb(128, 0, 0)";
      clr = new Array (0, 255, 0, 128, 0, 0, 0, 192, 255, 128);
      clg = new Array (0, 0, 0, 0, 255, 128, 128, 192, 0, 0);
      clb = new Array (0, 255, 255, 128, 255, 128, 0, 192, 0, 0);
      change = "";   // 表示切り替えボタン
      line_w = 2;   // 折れ線グラフ等の線の太さ
      line_m = true;   // 折れ線グラフ等にマークを付けるか否か
      gpp = null;
      
      /****************************/
      /* グラフの描画             */
      /*      coded by Y.Suganuma */
      /****************************/
      function graph(gp)
      {
      	canvas        = document.getElementById('canvas_e');
      	canvas.width  = 900;   // キャンバス要素の幅
      	canvas.height = 600;   // キャンバス要素の高さ
      	ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
      	x_base        = canvas.offsetLeft;   // キャンバスの左上のx座標
      	y_base        = canvas.offsetTop;   // キャンバスの左上のy座標
      	gpp           = gp;
      					// データの分離とグラフの選択
      	let a = gp.split(",");
      	kind = parseInt(a[0]);   // グラフの種類
      	let k = 1;
      							//
      							// 棒グラフ
      							//
      	if (kind == 0) {
      		change = "縦 色";   // 表示切り替えボタン
      		title = new Array(3);   // グラフタイトル, x軸タイトル, y軸タイトル
      		for (let i1 = 0; i1 < 3; i1++) {
      			title[i1] = a[k];
      			k++;
      		}
      		n_g = parseInt(a[k]);   // グラフの数
      		g_title = new Array(n_g);   // 各グラフのタイトル(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			g_title[i1] = a[k];
      			k++;
      		}
      		n_p = parseInt(a[k]);   // データの数
      		x_title = new Array(n_p);   // x軸への表示内容
      		k++;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			x_title[i1] = a[k];
      			k++;
      		}
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		data_y = new Array(n_g);   // データ(n_g×n_p個)
      		for (let i1 = 0; i1 < n_g; i1++) {
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		if (parseInt(a[k+1]) == 0)   // 凡例の表示
      			d_g = false;
      		set();
      		BarGraph();
      	}
      							//
      							// 折れ線グラフ(1)
      							//
      	else if (kind == 1) {
      		change = "縦 色";   // 表示切り替えボタン
      		title = new Array(3);   // グラフタイトル, x軸タイトル, y軸タイトル
      		for (let i1 = 0; i1 < 3; i1++) {
      			title[i1] = a[k];
      			k++;
      		}
      		n_g = parseInt(a[k]);   // グラフの数
      		g_title = new Array(n_g);   // 各グラフのタイトル(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			g_title[i1] = a[k];
      			k++;
      		}
      		n_p = parseInt(a[k]);   // データの数
      		x_title = new Array(n_p);   // x軸への表示内容
      		k++;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			x_title[i1] = a[k];
      			k++;
      		}
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		data_y = new Array(n_g);   // データ(n_g×n_p個)
      		for (let i1 = 0; i1 < n_g; i1++) {
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		if (parseInt(a[k+1]) == 0)   // 凡例の表示
      			d_g = false;
      		set();
      		LineGraph1();
      	}
      							//
      							// 折れ線グラフ(2)
      							//
      	else if (kind == 2) {
      		change = "縦 色";   // 表示切り替えボタン
      		title = new Array(3);   // グラフタイトル, x軸タイトル, y軸タイトル
      		for (let i1 = 0; i1 < 3; i1++) {
      			title[i1] = a[k];
      			k++;
      		}
      		n_g = parseInt(a[k]);   // グラフの数
      		g_title = new Array(n_g);   // 各グラフのタイトル(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			g_title[i1] = a[k];
      			k++;
      		}
      		x_scale = new Array(3);   // x軸の最小値, x軸の最大値, x軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			x_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_x = parseInt(a[k]);   // x軸の小数点以下桁数
      		k++;
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		n_p = parseInt(a[k]);   // データの数
      		k++;
      		data_x = new Array(n_g);   // x軸のデータ(n_g×n_p個)
      		data_y = new Array(n_g);   // y軸のデータ(n_g×n_p個)
      		for (let i1 = 0; i1 < n_g; i1++) {
      			data_x[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_x[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		if (parseInt(a[k+1]) == 0)   // 凡例の表示
      			d_g = false;
      		set();
      		LineGraph2();
      	}
      							//
      							// 積み上げ棒グラフ
      							//
      	else if (kind == 3) {
      		change = "縦 色";   // 表示切り替えボタン
      		title = new Array(3);   // グラフタイトル, x軸タイトル, y軸タイトル
      		for (let i1 = 0; i1 < 3; i1++) {
      			title[i1] = a[k];
      			k++;
      		}
      		n_g = parseInt(a[k]);   // グラフの数
      		g_title = new Array(n_g);   // 各グラフのタイトル(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			g_title[i1] = a[k];
      			k++;
      		}
      		n_p = parseInt(a[k]);   // データの数
      		x_title = new Array(n_p);   // x軸への表示内容(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			x_title[i1] = a[k];
      			k++;
      		}
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		data_y = new Array(n_g);   // データ(n_g×n_p個)
      		for (let i1 = 0; i1 < n_g; i1++) {
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		if (parseInt(a[k+1]) == 0)   // 凡例の表示
      			d_g = false;
      		set();
      		StackGraph();
      	}
      							//
      							// 円グラフ
      							//
      	else if (kind == 4) {
      		change = " 色 ";   // 表示切り替えボタン
      		title = new Array();   // グラフタイトル
      		title[0] = a[k];
      		k++;
      		n_p = parseInt(a[k]);   // データの数
      		x_title = new Array(n_p);   // 凡例
      		k++;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			x_title[i1] = a[k];
      			k++;
      		}
      		data_y = new Array();   // データ(n_p個)
      		for (let i1 = 0; i1 < n_p; i1++) {
      			data_y[i1] = parseFloat(a[k]);
      			k++;
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		set();
      		PieGraph();
      	}
      							//
      							// 散布図
      							//
      	else if (kind == 5) {
      		title = new Array(3);   // グラフタイトル, x軸タイトル, y軸タイトル
      		for (let i1 = 0; i1 < 3; i1++) {
      			title[i1] = a[k];
      			k++;
      		}
      		x_scale = new Array(3);   // x軸の最小値, x軸の最大値, x軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			x_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_x = parseInt(a[k]);   // x軸の小数点以下桁数
      		k++;
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		n_p = parseInt(a[k]);   // データの数
      		k++;
      		data_y = new Array(2);   // データ(2×n_p個)
      		for (let i1 = 0; i1 < 2; i1++) {
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		ScatterDiagram();
      	}
      							//
      							// レーダーチャート
      							//
      	else if (kind == 6) {
      		change = " 色 ";   // 表示切り替えボタン
      		title    = new Array(1);   // グラフタイトル
      		title[0] = a[k];
      		k++;
      		n_g = parseInt(a[k]);   // グラフの数
      		g_title = new Array(n_g);   // 各グラフのタイトル(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			g_title[i1] = a[k];
      			k++;
      		}
      		n_p = parseInt(a[k]);   // データの数
      		x_title = new Array(n_p);   // x軸への表示内容
      		k++;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			x_title[i1] = a[k];
      			k++;
      		}
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		data_y = new Array(n_g);   // データ(n_g×n_p個)
      		for (let i1 = 0; i1 < n_g; i1++) {
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		if (parseInt(a[k+1]) == 0)   // 凡例の表示
      			d_g = false;
      		set();
      		RadarChart();
      	}
      							//
      							// ボード線図(片対数グラフ)
      							//
      	else {
      		change = " 色 ";   // 表示切り替えボタン
      		title = new Array(3);   // グラフタイトル, x軸タイトル, y軸タイトル
      		for (let i1 = 0; i1 < 3; i1++) {
      			title[i1] = a[k];
      			k++;
      		}
      		n_g = parseInt(a[k]);   // グラフの数
      		g_title = new Array(n_g);   // 各グラフのタイトル(凡例)
      		k++;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			g_title[i1] = a[k];
      			k++;
      		}
      		x_scale = new Array(3);   // x軸の最小値, x軸の最大値, x軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			x_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_x = parseInt(a[k]);   // x軸の小数点以下桁数
      		k++;
      		y_scale = new Array(3);   // y軸の最小値, y軸の最大値, y軸の刻み幅
      		for (let i1 = 0; i1 < 3; i1++) {
      			y_scale[i1] = parseFloat(a[k]);
      			k++;
      		}
      		place_y = parseInt(a[k]);   // y軸の小数点以下桁数
      		k++;
      		n_p = parseInt(a[k]);   // データの数
      		k++;
      		data_x = new Array(n_g);   // x軸のデータ(n_g×n_p個)
      		data_y = new Array(n_g);   // y軸のデータ(n_g×n_p個)
      		for (let i1 = 0; i1 < n_g; i1++) {
      			data_x[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_x[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      			data_y[i1] = new Array(n_p);
      			for (let i2 = 0; i2 < n_p; i2++) {
      				data_y[i1][i2] = parseFloat(a[k]);
      				k++;
      			}
      		}
      		if (parseInt(a[k]) == 0)   // グラフタイトルの表示
      			d_t = false;
      		if (parseInt(a[k+1]) == 0)   // 凡例の表示
      			d_g = false;
      		set();
      		Bode();
      	}
      }
      
      /****************************/
      /* 表示変更エリアの設定     */
      /*      coded by Y.Suganuma */
      /****************************/
      function set()
      {
      	let rgb ="rgb";
      	let r ="r";
      	let g ="g";
      	let b ="b";
      	for (let i1 = 0; i1 < 10; i1++) {
      		let rgb1 = rgb + i1;
      		document.getElementById(rgb1).style.backgroundColor = cl[i1];
      		let r1 = r + i1;
      		document.getElementById(r1).value = clr[i1];
      		let g1 = g + i1;
      		document.getElementById(g1).value = clg[i1];
      		let b1 = b + i1;
      		document.getElementById(b1).value = clb[i1];
      	}
      }
      
      /****************************/
      /* 棒グラフの描画           */
      /*      coded by Y.Suganuma */
      /****************************/
      function BarGraph()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx = x_r - met.width - 5;
      	cy = y_u;
      	cw = met.width + 5;
      	ch = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let met = ctx.measureText(g_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		let k  = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(g_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// x軸及びy軸のタイトルの表示
      					//
      							// 縦表示
      	ctx.fillStyle = 'rgb(0, 0, 0)';
      	if (ver) {
      		if (title[1].length > 0 && title[1] != "-") {
      			let met = ctx.measureText(title[1]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[1], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[2], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      							// 横表示
      	else {
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[2], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[1].length > 0 && title[1].localeCompare("-") != 0) {
      			let met = ctx.measureText(title[1]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[1], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      	y_u += 10;
      					//
      					// x軸,y軸,及び,各軸の目盛り
      					//
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font  = f_size + "px 'MS 明朝'";
      	y_d      -= (f_size + 5);
      							// 縦表示
      	if (ver) {
      									// y軸
      		let y1  = y_scale[0];
      		let k   = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let len = 0;
      		let b   = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let yy = Math.round(y1 * b).toString();
      			if (place_y == 0)
      				tx[i1] = yy;
      			else {
      				if (yy.length < place_y+1) {
      					let n = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				tx[i1] = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(tx[i1]);
      			if (met.width > len)
      				len = met.width;
      			y1 += y_scale[2];
      		}
      		ctx.moveTo(x_l+len+10, y_u);
      		ctx.lineTo(x_l+len+10, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		y1 = y_scale[0];
      		let x1 = y_d;
      		let sp = (y_d - y_u) / k;
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let ky  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(tx[i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(tx[i1], px, py);
      			ctx.moveTo(x_l+len+10, ky);
      			ctx.lineTo(x_r, ky);
      			y1 += y_scale[2];
      			x1 -= sp;
      		}
      		x_l += (len + 10);
      									// x軸
      		sp  = (x_r - x_l) / n_p;
      		x1  = x_l + sp / 2.0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let kx  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(x_title[i1]);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + 11 * f_size / 10;
      			ctx.fillText(x_title[i1], px, py);
      			ctx.moveTo(kx, y_d);
      			ctx.lineTo(kx, y_d-5);
      			x1 += sp;
      		}
      	}
      							// 横表示
      	else {
      									// y軸
      		let len = 0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let met = ctx.measureText(x_title[i1]);
      			if (met.width > len)
      				len = met.width;
      		}
      		ctx.moveTo(x_l+len+5, y_u);
      		ctx.lineTo(x_l+len+5, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		let sp = (y_d - y_u) / n_p;
      		let y1 = y_d - sp / 2.0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let ky  = Math.floor(Math.round(y1));
      			let met = ctx.measureText(x_title[n_p-1-i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(x_title[n_p-1-i1], px, py);
      			ctx.moveTo(x_l+len+5, ky);
      			ctx.lineTo(x_l+len+10, ky);
      			y1 -= sp;
      		}
      		ctx.moveTo(x_l+len+5, y_u);
      		ctx.lineTo(x_r, y_u);
      		ctx.moveTo(x_l+len+5, y_d);
      		ctx.lineTo(x_r, y_d);
      		x_l += (len + 5);
      									// x軸
      		let k  = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let x1 = y_scale[0];
      		y1 = x_l;
      		sp = (x_r - x_l) / k;
      		let b = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let kx = Math.floor(Math.round(y1));
      			let yy = Math.round(x1 * b).toString();
      			let st;
      			if (place_y == 0)
      				st = yy;
      			else {
      				if (yy.length < place_y+1) {
      					n = place_y + 1 - yy.length;
      					for (i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				st = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(st);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + f_size;
      			ctx.fillText(st, px, py);
      			if (i1 < k) {
      				ctx.moveTo(kx, y_d);
      				ctx.lineTo(kx, y_u);
      			}
      			x1 += y_scale[2];
      			y1 += sp;
      		}
      	}
      	ctx.stroke();
      					//
      					// グラフの表示
      					//
      							// 縦表示
      	if (ver) {
      		let g_w = Math.floor(0.8 * (x_r - x_l) / (n_g * n_p));
      		let sp  = (x_r - x_l) / n_p;
      		let x1  = x_l + sp / 2.0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let kx = Math.floor(Math.round(x1));
      			let k1 = 0;
      			let k2 = kx - n_g * g_w / 2;
      			for (let i2 = 0; i2 < n_g; i2++) {
      				let ky = y_d - Math.floor((y_d - y_u) * (data_y[i2][i1] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      				ctx.fillStyle = cl[k1];
      				ctx.fillRect(k2, ky, g_w, y_d-ky);
      				k2 += g_w;
      				k1++;
      				if (k1 > 9)
      					k1 = 0;
      			}
      			x1 += sp;
      		}
      	}
      							// 横表示
      	else {
      		let g_w = Math.floor(0.8 * (y_d - y_u) / (n_g * n_p));
      		let sp  = (y_d - y_u) / n_p;
      		let y1  = y_d - sp / 2.0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let ky = Math.floor(Math.round(y1));
      			let k1 = 0;
      			let k2 = ky - n_g * g_w / 2;
      			for (let i2 = 0; i2 < n_g; i2++) {
      				let kx = Math.floor((x_r - x_l) * (data_y[i2][n_p-1-i1] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      				ctx.fillStyle = cl[k1];
      				ctx.fillRect(x_l, k2, kx, g_w);
      				k2 += g_w;
      				k1++;
      				if (k1 > 9)
      					k1 = 0;
      			}
      			y1 -= sp;
      		}
      	}
      }
      
      /****************************/
      /* 折れ線グラフ(1)の描画 */
      /*      coded by Y.Suganuma */
      /****************************/
      function LineGraph1()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx  = x_r - met.width - 5;
      	cy  = y_u;
      	cw  = met.width + 5;
      	ch  = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let met = ctx.measureText(g_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		let k  = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(g_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// x軸及びy軸のタイトルの表示
      					//
      							// 縦表示
      	ctx.fillStyle = 'rgb(0, 0, 0)';
      	if (ver) {
      		if (title[1].length > 0 && title[1] != "-") {
      			let met = ctx.measureText(title[1]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[1], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[2], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      							// 横表示
      	else {
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[2], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[1].length > 0 && title[1].localeCompare("-") != 0) {
      			let met = ctx.measureText(title[1]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[1], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      	y_u += 10;
      					//
      					// x軸,y軸,及び,各軸の目盛り
      					//
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font  = f_size + "px 'MS 明朝'";
      	y_d      -= (f_size + 5);
      							// 縦表示
      	if (ver) {
      									// y軸
      		let y1  = y_scale[0];
      		let k   = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let len = 0;
      		let b   = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let yy = Math.round(y1 * b).toString();
      			if (place_y == 0)
      				tx[i1] = yy;
      			else {
      				if (yy.length < place_y+1) {
      					let n = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				tx[i1] = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(tx[i1]);
      			if (met.width > len)
      				len = met.width;
      			y1 += y_scale[2];
      		}
      		ctx.moveTo(x_l+len+10, y_u);
      		ctx.lineTo(x_l+len+10, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		y1 = y_scale[0];
      		let x1 = y_d;
      		let sp = (y_d - y_u) / k;
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let ky  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(tx[i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(tx[i1], px, py);
      			ctx.moveTo(x_l+len+10, ky);
      			ctx.lineTo(x_r, ky);
      			y1 += y_scale[2];
      			x1 -= sp;
      		}
      		x_l += (len + 10);
      									// x軸
      		sp  = (x_r - x_l) / n_p;
      		x1  = x_l + sp / 2.0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let kx  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(x_title[i1]);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + 11 * f_size / 10;
      			ctx.fillText(x_title[i1], px, py);
      			ctx.moveTo(kx, y_d);
      			ctx.lineTo(kx, y_d-5);
      			x1 += sp;
      		}
      	}
      							// 横表示
      	else {
      									// y軸
      		let len = 0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let met = ctx.measureText(x_title[i1]);
      			if (met.width > len)
      				len = met.width;
      		}
      		ctx.moveTo(x_l+len+5, y_u);
      		ctx.lineTo(x_l+len+5, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		let sp = (y_d - y_u) / n_p;
      		let y1 = y_d - sp / 2.0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let ky  = Math.floor(Math.round(y1));
      			let met = ctx.measureText(x_title[n_p-1-i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(x_title[n_p-1-i1], px, py);
      			ctx.moveTo(x_l+len+5, ky);
      			ctx.lineTo(x_l+len+10, ky);
      			y1 -= sp;
      		}
      		ctx.moveTo(x_l+len+5, y_u);
      		ctx.lineTo(x_r, y_u);
      		ctx.moveTo(x_l+len+5, y_d);
      		ctx.lineTo(x_r, y_d);
      		x_l += (len + 5);
      									// x軸
      		let k  = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let x1 = y_scale[0];
      		y1 = x_l;
      		sp = (x_r - x_l) / k;
      		let b = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let kx = Math.floor(Math.round(y1));
      			let yy = Math.round(x1 * b).toString();
      			let st;
      			if (place_y == 0)
      				st = yy;
      			else {
      				if (yy.length < place_y+1) {
      					nlet  = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				st = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(st);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + f_size;
      			ctx.fillText(st, px, py);
      			if (i1 < k) {
      				ctx.moveTo(kx, y_d);
      				ctx.lineTo(kx, y_u);
      			}
      			x1 += y_scale[2];
      			y1 += sp;
      		}
      	}
      	ctx.stroke();
      					//
      					// グラフの表示
      					//
      	ctx.lineWidth = line_w;
      	let cr = line_w / 2 + 3;
      									// 縦表示
      	if (ver) {
      		let sp = (x_r - x_l) / n_p;
      		let k1 = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let x1  = x_l + sp / 2.0;
      			let kx1 = 0;
      			let ky1 = 0;
      			ctx.strokeStyle = cl[k1];  
      			ctx.fillStyle   = cl[k1];
      			for (let i2 = 0; i2 < n_p; i2++) {
      				let kx = Math.floor(Math.round(x1));
      				let ky = y_d - Math.floor((y_d - y_u) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      				if (line_m) {
      					ctx.beginPath();
      					ctx.arc(kx, ky, cr, 0, 2*Math.PI, false);
      					ctx.fill();
      				}
      				if (i2 > 0) {
      					ctx.beginPath();
      					ctx.moveTo(kx1, ky1);
      					ctx.lineTo(kx, ky);
      					ctx.stroke();
      				}
      				kx1  = kx;
      				ky1  = ky;
      				x1  += sp;
      			}
      			k1++;
      			if (k1 > 9)
      				k1 = 0;
      		}
      	}
      									// 横表示
      	else {
      		let sp = (y_d - y_u) / n_p;
      		let k1 = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let y1  = y_d - sp / 2.0;
      			let kx1 = 0;
      			let ky1 = 0;
      			ctx.strokeStyle = cl[k1];  
      			ctx.fillStyle   = cl[k1];
      			for (let i2 = 0; i2 < n_p; i2++) {
      				let ky = Math.floor(Math.round(y1));
      				let kx = x_l + Math.floor((x_r - x_l) * (data_y[i1][n_p-1-i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      				if (line_m) {
      					ctx.beginPath();
      					ctx.arc(kx, ky, cr, 0, 2*Math.PI, false);
      					ctx.fill();
      				}
      				if (i2 > 0) {
      					ctx.beginPath();
      					ctx.moveTo(kx1, ky1);
      					ctx.lineTo(kx, ky);
      					ctx.stroke();
      				}
      				kx1  = kx;
      				ky1  = ky;
      				y1  -= sp;
      			}
      			k1++;
      			if (k1 > 9)
      				k1 = 0;
      		}
      	}
      	ctx.lineWidth = 1;
      }
      
      /****************************/
      /* 折れ線グラフ(2)の描画 */
      /*      coded by Y.Suganuma */
      /****************************/
      function LineGraph2()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx  = x_r - met.width - 5;
      	cy  = y_u;
      	cw  = met.width + 5;
      	ch  = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let met = ctx.measureText(g_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		let k  = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(g_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// x軸及びy軸のタイトルの表示
      					//
      							// 縦表示
      	ctx.fillStyle = 'rgb(0, 0, 0)';
      	if (ver) {
      		if (title[1].length > 0 && title[1] != "-") {
      			let met = ctx.measureText(title[1]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[1], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[2], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      							// 横表示
      	else {
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[2], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[1].length > 0 && title[1].localeCompare("-") != 0) {
      			let met = ctx.measureText(title[1]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[1], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      	y_u += 10;
      					//
      					// x軸,y軸,及び,各軸の目盛り
      					//
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font  = f_size + "px 'MS 明朝'";
      	y_d      -= (f_size + 5);
      							// 縦表示
      	if (ver) {
      									// y軸
      		let y1  = y_scale[0];
      		let k   = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let len = 0;
      		let b   = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let yy = Math.round(y1 * b).toString();
      			if (place_y == 0)
      				tx[i1] = yy;
      			else {
      				if (yy.length < place_y+1) {
      					let n = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				tx[i1] = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(tx[i1]);
      			if (met.width > len)
      				len = met.width;
      			y1 += y_scale[2];
      		}
      		ctx.moveTo(x_l+len+10, y_u);
      		ctx.lineTo(x_l+len+10, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		y1 = y_scale[0];
      		let x1 = y_d;
      		let sp = (y_d - y_u) / k;
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let ky  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(tx[i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(tx[i1], px, py);
      			ctx.moveTo(x_l+len+10, ky);
      			ctx.lineTo(x_r, ky);
      			y1 += y_scale[2];
      			x1 -= sp;
      		}
      		x_l += (len + 10);
      									// x軸
      		k  = Math.floor((x_scale[1] - x_scale[0]) / (0.99 * x_scale[2]));
      		x1 = x_scale[0];
      		y1 = x_l;
      		sp = (x_r - x_l) / k;
      		b  = Math.pow(10, place_x);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let kx = Math.floor(Math.round(y1));
      			let yy = Math.round(x1 * b).toString();
      			let st;
      			if (place_x == 0)
      				st = yy;
      			else {
      				if (yy.length < place_x+1) {
      					let n = place_x + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				st = yy.substr(0,yy.length-place_x) + "." + yy.substr(yy.length-place_x,place_x);
      			}
      			met = ctx.measureText(st);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + f_size;
      			ctx.fillText(st, px, py);
      			if (i1 < k) {
      				ctx.moveTo(kx, y_d);
      				ctx.lineTo(kx, y_u);
      			}
      			x1 += x_scale[2];
      			y1 += sp;
      		}
      	}
      							// 横表示
      	else {
      									// y軸
      		let y1  = x_scale[0];
      		let k   = Math.floor((x_scale[1] - x_scale[0]) / (0.99 * x_scale[2]));
      		let len = 0;
      		let b   = Math.pow(10, place_x);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let yy = Math.round(y1 * b).toString();
      			if (place_x == 0)
      				tx[i1] = yy;
      			else {
      				if (yy.length < place_x+1) {
      					let n = place_x + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				tx[i1] = yy.substr(0,yy.length-place_x) + "." + yy.substr(yy.length-place_x,place_x);
      			}
      			let met = ctx.measureText(tx[i1]);
      			if (met.width > len)
      				len = met.width;
      			y1 += x_scale[2];
      		}
      		ctx.moveTo(x_l+len+10, y_u);
      		ctx.lineTo(x_l+len+10, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		y1 = x_scale[0];
      		let x1 = y_d;
      		let sp = (y_d - y_u) / k;
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let ky  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(tx[i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(tx[i1], px, py);
      			ctx.moveTo(x_l+len+10, ky);
      			ctx.lineTo(x_r, ky);
      			y1 += x_scale[2];
      			x1 -= sp;
      		}
      		x_l += (len + 10);
      									// x軸
      		k  = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		x1 = y_scale[0];
      		y1 = x_l;
      		sp = (x_r - x_l) / k;
      		b  = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let kx = Math.floor(Math.round(y1));
      			let yy = Math.round(x1 * b).toString();
      			let st;
      			if (place_y == 0)
      				st = yy;
      			else {
      				if (yy.length < place_y+1) {
      					let n = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				st = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(st);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + f_size;
      			ctx.fillText(st, px, py);
      			if (i1 < k) {
      				ctx.moveTo(kx, y_d);
      				ctx.lineTo(kx, y_u);
      			}
      			x1 += y_scale[2];
      			y1 += sp;
      		}
      	}
      	ctx.stroke();
      					//
      					// グラフの表示
      					//
      	ctx.lineWidth = line_w;
      	let cr = line_w / 2 + 3;
      							// 縦表示
      	if (ver) {
      		let k1 = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let kx1 = 0;
      			let ky1 = 0;
      			ctx.strokeStyle = cl[k1];  
      			ctx.fillStyle   = cl[k1];
      			for (let i2 = 0; i2 < n_p; i2++) {
      				let kx = x_l + Math.floor((x_r - x_l) * (data_x[i1][i2] - x_scale[0]) / (x_scale[1] - x_scale[0]));
      				let ky = y_d - Math.floor((y_d - y_u) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      				if (line_m) {
      					ctx.beginPath();
      					ctx.arc(kx, ky, cr, 0, 2*Math.PI, false);
      					ctx.fill();
      				}
      				if (i2 > 0) {
      					ctx.beginPath();
      					ctx.moveTo(kx1, ky1);
      					ctx.lineTo(kx, ky);
      					ctx.stroke();
      				}
      				kx1 = kx;
      				ky1 = ky;
      			}
      			k1++;
      			if (k1 > 9)
      				k1 = 0;
      		}
      	}
      							// 横表示
      	else {
      		let k1  = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let kx1 = 0;
      			let ky1 = 0;
      			ctx.strokeStyle = cl[k1];  
      			ctx.fillStyle   = cl[k1];
      			for (let i2 = 0; i2 < n_p; i2++) {
      				let kx = x_l + Math.floor((x_r - x_l) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      				let ky = y_d - Math.floor((y_d - y_u) * (data_x[i1][i2] - x_scale[0]) / (x_scale[1] - x_scale[0]));
      				if (line_m) {
      					ctx.beginPath();
      					ctx.arc(kx, ky, cr, 0, 2*Math.PI, false);
      					ctx.fill();
      				}
      				if (i2 > 0) {
      					ctx.beginPath();
      					ctx.moveTo(kx1, ky1);
      					ctx.lineTo(kx, ky);
      					ctx.stroke();
      				}
      				kx1 = kx;
      				ky1 = ky;
      			}
      			k1++;
      			if (k1 > 9)
      				k1 = 0;
      		}
      	}
      	ctx.lineWidth = 1;
      }
      
      /****************************/
      /* 積み上げ棒グラフの描画   */
      /*      coded by Y.Suganuma */
      /****************************/
      function StackGraph()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx  = x_r - met.width - 5;
      	cy  = y_u;
      	cw  = met.width + 5;
      	ch  = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let met = ctx.measureText(x_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		let k  = 0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(x_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// x軸及びy軸のタイトルの表示
      					//
      							// 縦表示
      	ctx.fillStyle = 'rgb(0, 0, 0)';
      	if (ver) {
      		if (title[1].length > 0 && title[1] != "-") {
      			let met = ctx.measureText(title[1]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[1], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[2], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      							// 横表示
      	else {
      		if (title[2].length > 0 && title[2] != "-") {
      			let met = ctx.measureText(title[2]);
      			let px  = (x_l + x_r) / 2 - met.width / 2;
      			let py  = y_d - 5;
      			ctx.fillText(title[2], px, py);
      			y_d -= (f_size + 5);
      		}
      		if (title[1].length > 0 && title[1].localeCompare("-") != 0) {
      			let met = ctx.measureText(title[1]);
      			let px  = x_l;
      			let py  = y_u + 4 * f_size / 5;
      			ctx.fillText(title[1], px, py);
      			y_u += 4 * f_size / 5;
      		}
      	}
      	y_u += 10;
      					//
      					// x軸,y軸,及び,各軸の目盛り
      					//
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font  = f_size + "px 'MS 明朝'";
      	y_d      -= (f_size + 5);
      							// 縦表示
      	if (ver) {
      									// y軸
      		let y1  = y_scale[0];
      		let k   = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let len = 0;
      		let b   = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let yy = Math.round(y1 * b).toString();
      			if (place_y == 0)
      				tx[i1] = yy;
      			else {
      				if (yy.length < place_y+1) {
      					let n = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				tx[i1] = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(tx[i1]);
      			if (met.width > len)
      				len = met.width;
      			y1 += y_scale[2];
      		}
      		ctx.moveTo(x_l+len+10, y_u);
      		ctx.lineTo(x_l+len+10, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		y1 = y_scale[0];
      		let x1 = y_d;
      		let sp = (y_d - y_u) / k;
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let ky  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(tx[i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(tx[i1], px, py);
      			ctx.moveTo(x_l+len+10, ky);
      			ctx.lineTo(x_r, ky);
      			y1 += y_scale[2];
      			x1 -= sp;
      		}
      		x_l += (len + 10);
      									// x軸
      		sp  = (x_r - x_l) / n_g;
      		x1  = x_l + sp / 2.0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let kx  = Math.floor(Math.round(x1));
      			let met = ctx.measureText(g_title[i1]);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + 11 * f_size / 10;
      			ctx.fillText(g_title[i1], px, py);
      			ctx.moveTo(kx, y_d);
      			ctx.lineTo(kx, y_d-5);
      			x1 += sp;
      		}
      	}
      							// 横表示
      	else {
      									// y軸
      		let len = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let met = ctx.measureText(g_title[i1]);
      			if (met.width > len)
      				len = met.width;
      		}
      		ctx.moveTo(x_l+len+5, y_u);
      		ctx.lineTo(x_l+len+5, y_d);
      		ctx.moveTo(x_r, y_u);
      		ctx.lineTo(x_r, y_d);
      		let sp = (y_d - y_u) / n_g;
      		let y1 = y_d - sp / 2.0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let ky  = Math.floor(Math.round(y1));
      			let met = ctx.measureText(g_title[n_g-1-i1]);
      			let k1  = met.width;
      			let px  = x_l + len - k1;
      			let py  = ky + 2 * f_size / 5;
      			ctx.fillText(g_title[n_g-1-i1], px, py);
      			ctx.moveTo(x_l+len+5, ky);
      			ctx.lineTo(x_l+len+10, ky);
      			y1 -= sp;
      		}
      		ctx.moveTo(x_l+len+5, y_u);
      		ctx.lineTo(x_r, y_u);
      		ctx.moveTo(x_l+len+5, y_d);
      		ctx.lineTo(x_r, y_d);
      		x_l += (len + 5);
      									// x軸
      		let k  = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      		let x1 = y_scale[0];
      		y1 = x_l;
      		sp = (x_r - x_l) / k;
      		let b = Math.pow(10, place_y);
      		for (let i1 = 0; i1 < k+1; i1++) {
      			let kx = Math.floor(Math.round(y1));
      			let yy = Math.round(x1 * b).toString();
      			let st;
      			if (place_y == 0)
      				st = yy;
      			else {
      				if (yy.length < place_y+1) {
      					let n = place_y + 1 - yy.length;
      					for (let i2 = 0; i2 < n; i2++)
      						yy = "0" + yy;
      				}
      				st = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      			}
      			let met = ctx.measureText(st);
      			let k1  = met.width;
      			let px  = kx - k1 / 2;
      			let py  = y_d + f_size;
      			ctx.fillText(st, px, py);
      			if (i1 < k) {
      				ctx.moveTo(kx, y_d);
      				ctx.lineTo(kx, y_u);
      			}
      			x1 += y_scale[2];
      			y1 += sp;
      		}
      	}
      	ctx.stroke();
      					//
      					// グラフの表示
      					//
      							// 縦表示
      	if (ver) {
      		let g_w = Math.floor(0.8 * (x_r - x_l) / n_g);
      		let sp  = (x_r - x_l) / n_g;
      		let x1  = x_l + sp / 2.0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let kx = Math.round(x1);
      			let k1 = 0;
      			let y1 = y_d;
      			for (let i2 = 0; i2 < n_p; i2++) {
      				let ky = Math.round(y1);
      				let y2 = (y_d - y_u) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]);
      				let k2 = Math.round(y2);
      				ctx.fillStyle = cl[k1];
      				ctx.fillRect(kx-g_w/2, ky-k2, g_w, k2);
      				y1 -= y2;
      				k1++;
      				if (k1 > 9)
      					k1 = 0;
      			}
      			x1 += sp;
      		}
      	}
      							// 横表示
      	else {
      		let g_w = Math.floor(0.8 * (y_d - y_u) / n_g);
      		let sp  = (y_d - y_u) / n_g;
      		let y1  = y_d - sp / 2.0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let ky = Math.round(y1);
      			let k1 = 0;
      			let x1 = x_l;
      			for (let i2 = 0; i2 < n_p; i2++) {
      				let kx = Math.round(x1);
      				let y2 = (x_r - x_l) * (data_y[n_g-1-i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]);
      				let k2 = Math.round(y2);
      				ctx.fillStyle = cl[k1];
      				ctx.fillRect(kx, ky-g_w/2, k2, g_w);
      				x1 += y2;
      				k1++;
      				if (k1 > 9)
      					k1 = 0;
      			}
      			y1 -= sp;
      		}
      	}
      }
      
      /****************************/
      /* 円グラフの描画           */
      /*      coded by Y.Suganuma */
      /****************************/
      function PieGraph()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx  = x_r - met.width - 5;
      	cy  = y_u;
      	cw  = met.width + 5;
      	ch  = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	let k = 0;
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			let met = ctx.measureText(x_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		for (let i1 = 0; i1 < n_p; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(x_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// グラフの表示
      					//
      	let k1;
      	if (x_r-x_l < y_d-y_u)
      		k1 = x_r - x_l;
      	else
      		k1 = y_d - y_u;
      	let len = 9 * k1 / 20;
      	let kx  = (x_r + x_l) / 2;
      	let ky  = (y_d + y_u) / 2;
      	let a1  = 90;
      	let a2  = a1 + Math.round(3.60 * data_y[n_p-1]);
      	k--;
      	if (k < 0)
      		k = 9;
      	for (let i1 = 0; i1 < n_p; i1++) {
      		let x1 = kx + len * Math.cos(Math.PI * a1 / 180.0);
      		let y1 = ky - len * Math.sin(Math.PI * a1 / 180.0);
      		ctx.beginPath();
      		ctx.moveTo(kx, ky);
      		ctx.fillStyle   = cl[k];
      		ctx.strokeStyle = cl[k];
      		ctx.lineTo(x1, y1);
      		for (let a = a1+1; a <= a2; a++) {
      			x1 = kx + len * Math.cos(Math.PI * a / 180.0);
      			y1 = ky - len * Math.sin(Math.PI * a / 180.0);
      			ctx.lineTo(x1, y1);
      		}
      		ctx.closePath();
      		ctx.fill();
      		if (i1 < n_p-1) {
      			a1 = a2;
      			a2 = a1 + Math.round(3.60 * data_y[n_p-2-i1]);
      			k--;
      			if (k < 0)
      				k = 9;
      		}
      	}
      }
      
      /****************************/
      /* 散布図の描画             */
      /*      coded by Y.Suganuma */
      /****************************/
      function ScatterDiagram()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// x軸及びy軸のタイトルの表示
      					//
      	x_r    -= Math.floor(0.03 * (x_r - x_l));
      	f_size  = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font      = f_size + "px 'MS ゴシック'";
      	ctx.fillStyle = 'rgb(0, 0, 0)';
      	if (title[1].length > 0 && title[1] != "-") {
      		let met = ctx.measureText(title[1]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d - 5;
      		ctx.fillText(title[1], px, py);
      		y_d -= (f_size + 5);
      	}
      	if (title[2].length > 0 && title[2] != "-") {
      		let met = ctx.measureText(title[2]);
      		let px  = x_l;
      		let py  = y_u + 4 * f_size / 5;
      		ctx.fillText(title[2], px, py);
      		y_u += 7 * f_size / 5;
      	}
      					//
      					// x軸,y軸,及び,各軸の目盛り
      					//
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	ctx.fillStyle   = "rgb(0, 0, 0)";
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font  = f_size + "px 'MS 明朝'";
      	y_d      -= (f_size + 5);
      							// y軸
      	let y1  = y_scale[0];
      	let k   = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      	let len = 0;
      	let b   = Math.pow(10, place_y);
      	for (let i1 = 0; i1 < k+1; i1++) {
      		let yy = Math.round(y1 * b).toString();
      		if (place_y == 0)
      			tx[i1] = yy;
      		else {
      			if (yy.length < place_y+1) {
      				let n = place_y + 1 - yy.length;
      				for (let i2 = 0; i2 < n; i2++)
      					yy = "0" + yy;
      			}
      			tx[i1] = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      		}
      		let met = ctx.measureText(tx[i1]);
      		if (met.width > len)
      			len = met.width;
      		y1 += y_scale[2];
      	}
      	ctx.moveTo(x_l+len+10, y_u);
      	ctx.lineTo(x_l+len+10, y_d);
      	ctx.moveTo(x_r, y_u);
      	ctx.lineTo(x_r, y_d);
      	y1 = y_scale[0];
      	let x1 = y_d;
      	let sp = (y_d - y_u) / k;
      	for (let i1 = 0; i1 < k+1; i1++) {
      		let ky  = Math.floor(Math.round(x1));
      		let met = ctx.measureText(tx[i1]);
      		let k1  = met.width;
      		let px  = x_l + len - k1;
      		let py  = ky + 2 * f_size / 5;
      		ctx.fillText(tx[i1], px, py);
      		ctx.moveTo(x_l+len+10, ky);
      		ctx.lineTo(x_r, ky);
      		y1 += y_scale[2];
      		x1 -= sp;
      	}
      	x_l += (len + 10);
      							// x軸
      	k  = Math.floor((x_scale[1] - x_scale[0]) / (0.99 * x_scale[2]));
      	x1 = x_scale[0];
      	y1 = x_l;
      	sp = (x_r - x_l) / k;
      	b  = Math.pow(10, place_x);
      	for (let i1 = 0; i1 < k+1; i1++) {
      		let kx = Math.floor(Math.round(y1));
      		let yy = Math.round(x1 * b).toString();
      		let st;
      		if (place_x == 0)
      			st = yy;
      		else {
      			if (yy.length < place_x+1) {
      				let n = place_x + 1 - yy.length;
      				for (let i2 = 0; i2 < n; i2++)
      					yy = "0" + yy;
      			}
      			st = yy.substr(0,yy.length-place_x) + "." + yy.substr(yy.length-place_x,place_x);
      		}
      		let met = ctx.measureText(st);
      		let k1  = met.width;
      		let px  = kx - k1 / 2;
      		let py  = y_d + f_size;
      		ctx.fillText(st, px, py);
      		if (i1 < k) {
      			ctx.moveTo(kx, y_d);
      			ctx.lineTo(kx, y_u);
      		}
      		x1 += x_scale[2];
      		y1 += sp;
      	}
      	ctx.stroke();
      					//
      					// グラフの表示
      					//
      	let cr = f_size / 4;
      	if (cr == 0)
      		cr = 1;
      	for (let i1 = 0; i1 < n_p; i1++) {
      		let kx = x_l + Math.floor((x_r - x_l) * (data_y[0][i1] - x_scale[0]) / (x_scale[1] - x_scale[0]));
      		let ky = y_d - Math.floor((y_d - y_u) * (data_y[1][i1] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      		ctx.beginPath();
      		ctx.arc(kx, ky, cr, 0, 2*Math.PI, false);
      		ctx.fill();
      	}
      					//
      					// 相関係数
      					//
      	let vii = 0.0;
      	let vjj = 0.0;
      	let vij = 0.0;
      	let mi  = 0.0;
      	let mj  = 0.0;
      	for (let i1 = 0; i1 < n_p; i1++) {
      		mi += data_y[0][i1];
      		mj += data_y[1][i1];
      	}
      	mi /= n_p;
      	mj /= n_p;
      	for (let i1 = 0; i1 < n_p; i1++) {
      		vii += (data_y[0][i1] - mi) * (data_y[0][i1] - mi);
      		vjj += (data_y[1][i1] - mj) * (data_y[1][i1] - mj);
      		vij += (data_y[0][i1] - mi) * (data_y[1][i1] - mj);
      	}
      	vii /= (n_p - 1);
      	vjj /= (n_p - 1);
      	vij /= (n_p - 1);
      	x1 = vij / (Math.sqrt(vii) * Math.sqrt(vjj));
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let yy = Math.round(x1 * 1000);
      	yy /= 1000;
      	let st  = "相関係数: " + yy;
      	let met = ctx.measureText(st);
      	let k1  = met.width;
      	let px  = x_r - met.width;
      	let py  = y_u - f_size;
      	ctx.fillText(st, px, py);
      }
      
      /****************************/
      /* レーダーチャートの描画   */
      /*      coded by Y.Suganuma */
      /****************************/
      function RadarChart()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx  = x_r - met.width - 5;
      	cy  = y_u;
      	cw  = met.width + 5;
      	ch  = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let met = ctx.measureText(g_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		let k  = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(g_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// 軸,及び,軸の目盛り
      					//
      							// フォントサイズ
      	f_size = Math.floor(0.7 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS 明朝'";
      							// 大きさの決定
      	let a   = 0.5 * Math.PI;
      	let aa  = 2.0 * Math.PI / n_p;
      	let x11 = 0.0;
      	let x12 = 0.0;
      	let x21 = 0.0;
      	let x22 = 0.0;
      	let y11 = 0.0;
      	let y12 = 0.0;
      	let y21 = 0.0;
      	let y22 = 0.0;
      	for (let i1 = 0; i1 < n_p; i1++) {
      		let xx  = 100 * Math.cos(a);
      		let yy  = 100 * Math.sin(a);
      		let met = ctx.measureText(x_title[i1]);
      		let k1  = met.width;
      		if (i1 == 0) {
      			x12 = 0.5 * k1;
      			x22 = x12;
      			y11 = 100.0;
      			y12 = 5.0 * f_size / 4.0;
      		}
      		else if (Math.abs(xx) < 1.0e-5) {
      			let x0 = 0.5 * k1;
      			if (x0 > x12)
      				x12 = x0;
      			if (x0 > x22)
      				x22 = x0;
      			y21 = 100.0;
      			y22 = f_size + 5.0;
      		}
      		else {
      			if (yy < 0.0) {
      				let y0 = -yy + 0.5 * f_size;
      				if (y0 > y21+y22) {
      					y21 = -yy;
      					y22 = 0.5 * f_size;
      				}
      			}
      			if (xx > 0.0) {
      				let x0 = xx + k1 + 5.0;
      				if (x0 > x21+x22) {
      					x21 = xx;
      					x22 = k1 + 5.0;
      				}
      			}
      			else {
      				let x0 = -xx + k1 + 5.0;
      				if (x0 > x11+x12) {
      					x11 = -xx;
      					x12 = k1 + 5.0;
      				}
      			}
      		}
      		a += aa;
      	}
      	let x0 = x12 + x22;
      	let xx = (x_r - x_l - x0 - 10) / (x11 + x21);
      	let y0 = y12 + y22;
      	let yy = (y_d - y_u - y0 - 10) / (y11 + y21);
      	r = (xx < yy) ? xx : yy;
      	let cr = Math.floor(100 * r);
      	xx = x_l + r * x11 + x12 + 5.0;
      	let cxx = Math.floor(xx + (x_r - x_l - r * x11 - x12 - r * x21 - x22 - 5) / 2);
      	yy = y_u + r * y11 + y12 + 5.0;
      	let cyy = Math.floor(yy + (y_d - y_u - r * y11 - y12 - r * y21 - y22 - 5) / 2);
      							// 軸とタイトルの描画
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	let k = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2])) + 1;
      	xx = cr / k;
      	a  = 0.5 * Math.PI;
      	aa = 2.0 * Math.PI / n_p;
      	for (let i1 = 0; i1 < n_p; i1++) {
      		let kx  = Math.round(cr * Math.cos(a));
      		let ky  = Math.round(cr * Math.sin(a));
      		let met = ctx.measureText(x_title[i1]);
      		let k1  = met.width;
      		ctx.moveTo(cxx, cyy);
      		ctx.lineTo(cxx+kx, cyy-ky);
      		yy = xx;
      		for (let i2 = 0; i2 < k; i2++) {
      			let kx0 = cxx + Math.round(yy * Math.cos(a));
      			let ky0 = cyy - Math.round(yy * Math.sin(a));
      			let kx1 = kx0 + Math.round(3 * Math.cos(a+0.5*Math.PI));
      			let ky1 = ky0 - Math.round(3 * Math.sin(a+0.5*Math.PI));
      			let kx2 = kx0 + Math.round(3 * Math.cos(a-0.5*Math.PI));
      			let ky2 = ky0 - Math.round(3 * Math.sin(a-0.5*Math.PI));
      			ctx.moveTo(kx1, ky1);
      			ctx.lineTo(kx2, ky2);
      			yy += xx;
      		}
      		if (i1 == 0) {
      			let met = ctx.measureText(x_title[i1]);
      			ctx.fillText(x_title[i1], cxx+kx-k1/2, cyy-ky-4*f_size/5);
      			yy = xx;
      			let sp = y_scale[0];
      			for (let i2 = 0; i2 < k; i2++) {
      				let kx0 = cxx + Math.round(yy * Math.cos(a)) + 5;
      				let ky0 = cyy - Math.floor(Math.round(yy * Math.sin(a)) - 3 * f_size / 10);
      				let b   = Math.pow(10, place_y);
      				let zz  = Math.round(sp * b).toString();
      				if (place_y == 0)
      					tx[i2] = zz;
      				else {
      					if (zz.length < place_y+1) {
      						let n = place_y + 1 - zz.length;
      						for (let i2 = 0; i2 < n; i2++)
      							zz = "0" + zz;
      					}
      					tx[i2] = zz.substr(0,zz.length-place_y) + "." + zz.substr(zz.length-place_y,place_y);
      				}
      				let met = ctx.measureText(tx[i2]);
      				ctx.fillText(tx[i2], kx0, ky0);
      				yy += xx;
      				sp += y_scale[2];
      			}
      		}
      		else {
      			let met = ctx.measureText(x_title[i1]);
      			let px;
      			let py;
      			if (kx == 0) {
      				px = cxx + kx - k1 / 2;
      				py = cyy - ky + 5 * f_size / 4;
      			}
      			else if (kx > 0) {
      				px = cxx + kx + 5;
      				py = cyy - ky + 3 * f_size / 10;
      			}
      			else {
      				px = cxx + kx - k1 - 10;
      				py = cyy - ky + 3 * f_size / 10;
      			}
      			ctx.fillText(x_title[i1], px, py);
      		}
      		a += aa;
      	}
      	ctx.stroke();
      					//
      					// グラフの表示
      					//
      	ctx.lineWidth = line_w;
      	let pt = line_w / 2 + 3;
      
      	let k1 = 0;
      	for (let i1 = 0; i1 < n_g; i1++) {
      		ctx.strokeStyle = cl[k1];
      		ctx.fillStyle   = cl[k1];
      		a   = 0.5 * Math.PI;
      		aa  = 2.0 * Math.PI / n_p;
      		let kx1 = 0;
      		let ky1 = 0;
      		let kx2 = 0;
      		let ky2 = 0;
      		for (let i2 = 0; i2 < n_p; i2++) {
      			yy = xx + (cr - xx) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]);
      			let kx = cxx + Math.round(yy * Math.cos(a));
      			let ky = cyy - Math.round(yy * Math.sin(a));
      			if (line_m) {
      				ctx.beginPath();
      				ctx.arc(kx, ky, pt, 0, 2*Math.PI, false);
      				ctx.fill();
      			}
      			if (i2 == 0) {
      				kx2 = kx;
      				ky2 = ky;
      			}
      			else {
      				ctx.beginPath();
      				ctx.moveTo(kx1, ky1);
      				ctx.lineTo(kx, ky);
      				ctx.stroke();
      				if (i2 == n_p-1) {
      					ctx.beginPath();
      					ctx.moveTo(kx2, ky2);
      					ctx.lineTo(kx, ky);
      					ctx.stroke();
      				}
      			}
      			kx1  = kx;
      			ky1  = ky;
      			a   += aa;
      		}
      		k1++;
      		if (k1 > 9)
      			k1 = 0;
      	}
      	ctx.lineWidth = 1;
      }
      
      /****************************/
      /* ボード線図の描画         */
      /*      coded by Y.Suganuma */
      /****************************/
      function Bode()
      {
      	let tx = new Array();
      					//
      					// 描画領域の設定
      					//
      	ctx.fillStyle  = 'rgb(255, 255, 255)';
      	ctx.fillRect(10, 10, canvas.width-20, canvas.height-20);
      	let x_l = 15;
      	let x_r = canvas.width - 15;
      	let y_u = 15;
      	let y_d = canvas.height - 15;
      					//
      					// グラフタイトルの表示
      					//
      	let r      = 0.05;   // タイトル領域の割合
      	let f_size = ((y_d - y_u) < (x_r - x_l)) ? Math.floor((y_d - y_u) * r) : Math.floor((x_r - x_l) * r);
      	if (f_size < 5)
      		f_size = 5;
      	if (d_t) {
      		ctx.fillStyle  = 'rgb(0, 0, 0)';
      		ctx.font = f_size + "px 'MS ゴシック'";
      		let met = ctx.measureText(title[0]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d;
      		ctx.fillText(title[0], px, py);
      		y_d -= f_size;
      	}
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      					//
      					// 表示切り替えボタンの設置
      					//
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font = f_size + "px 'MS ゴシック'";
      	let met = ctx.measureText(change);
      	cx  = x_r - met.width - 5;
      	cy  = y_u;
      	cw  = met.width + 5;
      	ch  = f_size + 5;
      	ctx.fillStyle  = 'rgb(255, 215, 0)';
      	ctx.fillRect(cx, cy, cw, ch);
      	ctx.fillStyle  = 'rgb(0, 0, 0)';
      	let px = cx + 2;
      	let py = cy + f_size;
      	ctx.fillText(change, px, py);
      					//
      					// 凡例の表示
      					//
      	if (d_g) {
      		let han = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			let met = ctx.measureText(g_title[i1]);
      			if (met.width > han)
      				han = met.width;
      		}
      		han += 15;
      		r    = 0.2;   // 凡例領域の割合
      		let k1 = Math.floor((x_r - x_l) * r);
      		if (han > k1)
      			han = k1;
      		let kx = x_r - han;
      		let ky = y_u + 2 * f_size;
      		let k  = 0;
      		for (let i1 = 0; i1 < n_g; i1++) {
      			ctx.fillStyle  = cl[k];
      			ctx.fillRect(kx, ky-1, 10, 7);
      			ctx.fillStyle  = 'rgb(0, 0, 0)';
      			ctx.fillText(g_title[i1], kx+15, ky+2*f_size/5);
      			k++;
      			if (k > 9)
      				k = 0;
      			ky += (f_size + 5);
      		}
      		x_r -= (han + 10);
      	}
      	else
      		x_r -= Math.floor(0.03 * (x_r - x_l));
      					//
      					// x軸の対数
      					//
      	x_scale_org = x_scale[0];
      	xx_scale    = new Array(3);
      	xx_scale[0] = Math.log(x_scale[0]) / Math.log(10.0);
      	xx_scale[1] = Math.log(x_scale[1]) / Math.log(10.0);
      	xx_scale[2] = 1.0;
      	data_xx     = new Array(n_g);
      	for (let i1 = 0; i1 < n_g; i1++) {
      		data_xx[i1] = new Array(n_p);
      		for (let i2 = 0; i2 < n_p; i2++)
      			data_xx[i1][i2] = Math.log(data_x[i1][i2]) / Math.log(10.0);
      	}
      					//
      					// x軸及びy軸のタイトルの表示
      					//
      	ctx.fillStyle = 'rgb(0, 0, 0)';
      	if (title[1].length > 0 && title[1] != "-") {
      		let met = ctx.measureText(title[1]);
      		let px  = (x_l + x_r) / 2 - met.width / 2;
      		let py  = y_d - 5;
      		ctx.fillText(title[1], px, py);
      		y_d -= (f_size + 5);
      	}
      	else
      		y_d -= (f_size / 2 + 5);
      	if (title[2].length > 0 && title[2] != "-") {
      		let met = ctx.measureText(title[2]);
      		let px  = x_l;
      		let py  = y_u + 4 * f_size / 5;
      		ctx.fillText(title[2], px, py);
      		y_u += 4 * f_size / 5;
      	}
      					//
      					// x軸,y軸,及び,各軸の目盛り
      					//
      	ctx.lineWidth   = 1;
      	ctx.strokeStyle = "rgb(0, 0, 0)";
      	f_size = Math.floor(0.8 * f_size);
      	if (f_size < 5)
      		f_size = 5;
      	ctx.font  = f_size + "px 'MS 明朝'";
      	y_d     -= 5 * f_size / 4;
      	y_u     += 10;
      	x_l     += f_size;
      							// y軸
      	let k_y = Math.floor((y_scale[1] - y_scale[0]) / (0.99 * y_scale[2]));
      	let y1  = y_scale[0];
      	let len = 0;
      	let b   = Math.pow(10, place_y);
      	for (let i1 = 0; i1 < k_y+1; i1++) {
      		let yy = Math.round(y1 * b).toString();
      		if (place_y == 0)
      			tx[i1] = yy;
      		else {
      			if (yy.length < place_y+1) {
      				let n = place_y + 1 - yy.length;
      				for (let i2 = 0; i2 < n; i2++)
      					yy = "0" + yy;
      			}
      			tx[i1] = yy.substr(0,yy.length-place_y) + "." + yy.substr(yy.length-place_y,place_y);
      		}
      		let met = ctx.measureText(tx[i1]);
      		if (met.width > len)
      			len = met.width;
      		y1 += y_scale[2];
      	}
      	ctx.moveTo(x_l+len+5, y_u);
      	ctx.lineTo(x_l+len+5, y_d);
      	ctx.moveTo(x_r, y_u);
      	ctx.lineTo(x_r, y_d);
      	ctx.stroke();
      	y1 = y_scale[0];
      	let x1 = y_d;
      	let sp = (y_d - y_u) / k_y;
      	for (let i1 = 0; i1 < k_y+1; i1++) {
      		let ky  = Math.round(x1);
      		let met = ctx.measureText(tx[i1]);
      		let k1  = met.width;
      		let px  = x_l + len - k1;
      		let py  = ky + 3 * f_size / 10;
      		ctx.fillText(tx[i1], px, py);
      		ctx.moveTo(x_l+len+5, ky);
      		ctx.lineTo(x_r, ky);
      		ctx.stroke();
      		y1 += y_scale[2];
      		x1 -= sp;
      	}
      	x_l += (len + 5);
      							// x軸
      	let k_x = Math.floor((xx_scale[1] - xx_scale[0]) / (0.99 * xx_scale[2]));
      	x1  = x_scale_org;
      	sp  = (x_r - x_l) / k_x;
      	y1 = x_l;
      	b  = Math.pow(10, place_x);
      	for (let i1 = 0; i1 < k_x+1; i1++) {
      		let kx = Math.round(y1);
      		let yy = Math.round(x1 * b).toString();
      		if (place_x == 0)
      			tx[i1] = yy;
      		else {
      			if (yy.length < place_x+1) {
      				let n = place_x + 1 - yy.length;
      				for (let i2 = 0; i2 < n; i2++)
      					yy = "0" + yy;
      			}
      			tx[i1] = yy.substr(0,yy.length-place_x) + "." + yy.substr(yy.length-place_x,place_x);
      		}
      		let met = ctx.measureText(tx[i1]);
      		let k1  = met.width;
      		let px  = kx - k1 / 2;
      		let py  = y_d + f_size + 3;
      		ctx.fillText(tx[i1], px, py);
      		ctx.moveTo(kx, y_d);
      		ctx.lineTo(kx, y_u);
      		ctx.stroke();
      		if (i1 != k_x) {
      			ctx.beginPath();
      			ctx.strokeStyle = 'rgb(128, 128, 128)';
      			for (let i2 = 2; i2 <= 9; i2++) {
      				let y2 = Math.log(x1 * i2) / Math.log(10.0);
      				let kx = x_l + Math.round(((x_r - x_l) * (y2 - xx_scale[0]) / (xx_scale[1] - xx_scale[0])));
      				ctx.moveTo(kx, y_d);
      				ctx.lineTo(kx, y_u);
      				ctx.stroke();
      			}
      			ctx.beginPath();
      			ctx.strokeStyle = 'rgb(0, 0, 0)';
      		}
      		x1 *= 10.0;
      		y1 += sp;
      	}
      					//
      					// グラフの表示
      					//
      	ctx.lineWidth = line_w;
      	let k1 = 0;
      	for (let i1 = 0; i1 < n_g; i1++) {
      		ctx.beginPath();
      		ctx.strokeStyle = cl[k1];
      		let kx1 = 0;
      		let ky1 = 0;
      		for (let i2 = 0; i2 < n_p; i2++) {
      			let kx = x_l + Math.floor((x_r - x_l) * (data_xx[i1][i2] - xx_scale[0]) / (xx_scale[1] - xx_scale[0]));
      			let ky = y_d - Math.floor((y_d - y_u) * (data_y[i1][i2] - y_scale[0]) / (y_scale[1] - y_scale[0]));
      			if (i2 > 0) {
      				ctx.moveTo(kx1, ky1);
      				ctx.lineTo(kx, ky);
      				ctx.stroke();
      			}
      			kx1 = kx;
      			ky1 = ky;
      		}
      		k1++;
      		if (k1 >= cl.length)
      			k1 = 0;
      	}
      }
      
      /**********************************/
      /* 表示の切り替えボタンのクリック */
      /**********************************/
      function Click(event)
      {
      	let x_now;
      	let y_now;
      	if (navigator.appName.indexOf("Explorer") >= 0) {
      		x_now = event.x - x_base;
      		y_now = event.y - y_base;
      	}
      	else {
      		x_now = event.pageX - x_base;
      		y_now = event.pageY - y_base;
      	}
      					// 縦表示,横表示の変更
      	if (kind <= 3 && x_now > cx && x_now < cx+cw/2 && y_now > cy && y_now < cy+ch) {
      		if (ver) {
      			ver    = false;
      			change = "縦 色";
      		}
      		else {
      			ver    = true;
      			change = "横 色";
      		}
      
      		ctx.beginPath();
      		ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      		if (kind == 0)
      			BarGraph();
      		else if (kind == 1)
      			LineGraph1();
      		else if (kind == 2)
      			LineGraph2();
      		else
      			StackGraph();
      	}
      					// 色や線の太さの変更
      	else if (kind <= 3 && x_now > cx+cw/2 && x_now < cx+cw && y_now > cy && y_now < cy+ch ||
                   (kind == 4 || kind >= 6) && x_now > cx && x_now < cx+cw && y_now > cy && y_now < cy+ch) {
      		let n = n_g;
      		if (kind == 3 || kind == 4)
      			n = n_p;
      		if (n > 10)
      			n = 10;
      		document.getElementById('cl_line').style.display = "";
      		for (let i1 = 0; i1 < n; i1++) {
      			let id = "c" + i1;
      			document.getElementById(id).style.display = "";
      		}
      		for (let i1 = n; i1 < 10; i1++) {
      			let id = "c" + i1;
      			document.getElementById(id).style.display = "none";
      		}
      		if (kind == 1 || kind == 2 || kind == 6 || kind == 7)
      			document.getElementById('line_w').style.display = "";
      		else
      			document.getElementById('line_w').style.display = "none";
      		if (kind == 1 || kind == 2 || kind == 6)
      			document.getElementById('line_m').style.display = "";
      		else
      			document.getElementById('line_m').style.display = "none";
      	}
      }
      
      /********************************************************/
      /* 「OK」ボタンがクリックされたとき(線の太さ等の設定) */
      /********************************************************/
      function D_Change()
      {
      					// 線の太さ
      	if (kind == 1 || kind == 2 || kind == 6 || kind == 7)
      		line_w = parseInt(document.getElementById('l_w').value);
      					// マーク
      	if (kind == 1 || kind == 2 || kind == 6)
      		line_m = document.getElementById('l_m1').checked ? true : false;
      					// 再描画
      	document.getElementById('cl_line').style.display = "none";
      	graph(gpp);
      }
      
      /******************************************/
      /* TextField が変更されたとき(色の変更) */
      /******************************************/
      function c_change(sw)
      {
      	let rgb1 = "rgb(";
      	let str = "r" + sw;
      	let r1 = document.getElementById(str).value;
      	if (r1 == "")
      		r1 = "0";
      	rgb1 = rgb1 + r1 + ",";
      	str = "g" + sw;
      	let g1 = document.getElementById(str).value;
      	if (g1 == "")
      		g1 = "0";
      	rgb1 = rgb1 + g1 + ",";
      	str = "b" + sw;
      	let b1 = document.getElementById(str).value;
      	if (b1 == "")
      		b1 = "0";
      	rgb1 = rgb1 + b1 + ")";
      	cl[sw] = rgb1;
      	clr[sw] = r1;
      	clg[sw] = g1;
      	clb[sw] = b1;
      	str = "rgb" + sw;
      	document.getElementById(str).style.backgroundColor = cl[sw];
      }
      				

    2. 一般的なグラフ

        上の例では,棒グラフだけを描きましたが,graph.js に定義してある関数を利用すると,様々なグラフを描くことができます.下に示すページ( graph.htm )は,どのようなグラフが描けるのかを示すためのページです.このページにおいてグラフを選択すると,指定したグラフが表示されます.なお,このページでは,グラフを描くために必要なデータは,関数 sel においてあらかじめ設定されています.

        グラフの右上の「横」または「縦」の部分をクリックすると,グラフの縦表示,横表示が切り替わります.また,「色」の部分をクリックするとグラフの色や線の太さ等を設定するための領域が表示されます.色を変更する場合,RGB の値を設定した後,他の箇所にフォーカスを移動すると,右側に示した色が変化します.適当に設定した後,「OK」ボタンをクリックすれば,指定された通りにグラフが表示されます.なお,「OK」ボタンをクリックした後でないと,「縦」「横」「色」の部分に対するマウスクリックは有効になりません.

      graph.htm

      <!DOCTYPE HTML>
      <HTML>
      <HEAD>
      	<TITLE>グラフの表示</TITLE>
      	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
      	<SCRIPT TYPE="text/javascript" SRC="graph.js"></SCRIPT>
      	<SCRIPT TYPE="text/javascript">
      		function sel(kind)
      		{
      			let gp = "";
      					// 棒グラフ
      			if (kind == 0)
      				gp = "0,棒グラフの例,x軸タイトル,y軸タイトル,6,自己啓発,目的意識,国際感覚,実行力,創造力,交渉力,5,非常に重視する,やや重視する,普通,あまり考慮しない,全く考慮しない,0.0,200.0,50.0,0,114,146,40,0,0,144,130,24,0,1,10,56,160,36,15,179,100,21,0,0,101,141,46,0,1,131,104,60,1,0,1,1";
      					// 折れ線グラフ(1)
      			else if (kind == 1)
      				gp = "1,折れ線グラフの例(1),x軸タイトル,y軸タイトル,6,自己啓発,目的意識,国際感覚,実行力,創造力,交渉力,5,非常に重視する,やや重視する,普通,あまり考慮しない,全く考慮しない,0.0,200.0,50.0,0,114,146,40,0,0,144,130,24,0,1,10,56,160,36,15,179,100,21,0,0,101,141,46,0,1,131,104,60,1,0,1,1";
      					// 折れ線グラフ(2)
      			else if (kind == 2)
      				gp = "2,折れ線グラフの例(2),x軸タイトル,y軸タイトル,3,グラフ1,グラフ2,グラフ3,0.0,100.0,20.0,1,0.0,200.0,50.0,0,4,0,14,40,100,179,100,21,0,0,30,34,100,101,141,46,10,0,56,60,100,131,104,60,100,1,1";
      					// 積み上げ棒グラフ
      			else if (kind == 3) {
      				gp = "3,積み上げ棒グラフの例(全体:300人),x軸タイトル,y軸タイトル,21,自己啓発,目的意識,国際感覚,実行力,創造力,交渉力,情報収集力,プレゼンテーション能力,積極性・自主性・チャレンジ精神,柔軟性・協調性,好奇心・探求心,持続力・忍耐力,責任感,明朗さ,真面目さ,基礎学力(数学・物理等),専門知識,専門技術,日本語(文章読解・文章作成),英語,コンピュータ・情報処理,5,非常に重視する,やや重視する,普通,あまり考慮しない,全く考慮しない,0.0,100.0,20.0,0";
      				data_y    = new Array();
      				data_y[0] = new Array();
      				data_y[0][0] = 114;
      				data_y[0][1] = 146;
      				data_y[0][2] = 40;
      				data_y[0][3] = 0;
      				data_y[0][4] = 0;
      				data_y[1] = new Array();
      				data_y[1][0] = 144;
      				data_y[1][1] = 130;
      				data_y[1][2] = 24;
      				data_y[1][3] = 0;
      				data_y[1][4] = 1;
      				data_y[2] = new Array();
      				data_y[2][0] = 10;
      				data_y[2][1] = 56;
      				data_y[2][2] = 160;
      				data_y[2][3] = 36;
      				data_y[2][4] = 15;
      				data_y[3] = new Array();
      				data_y[3][0] = 179;
      				data_y[3][1] = 100;
      				data_y[3][2] = 21;
      				data_y[3][3] = 0;
      				data_y[3][4] = 0;
      				data_y[4] = new Array();
      				data_y[4][0] = 101;
      				data_y[4][1] = 141;
      				data_y[4][2] = 46;
      				data_y[4][3] = 0;
      				data_y[4][4] = 1;
      				data_y[5] = new Array();
      				data_y[5][0] = 131;
      				data_y[5][1] = 104;
      				data_y[5][2] = 60;
      				data_y[5][3] = 1;
      				data_y[5][4] = 0;
      				data_y[6] = new Array();
      				data_y[6][0] = 55;
      				data_y[6][1] = 122;
      				data_y[6][2] = 107;
      				data_y[6][3] = 5;
      				data_y[6][4] = 1;
      				data_y[7] = new Array();
      				data_y[7][0] = 43;
      				data_y[7][1] = 95;
      				data_y[7][2] = 132;
      				data_y[7][3] = 13;
      				data_y[7][4] = 3;
      				data_y[8] = new Array();
      				data_y[8][0] = 215;
      				data_y[8][1] = 75;
      				data_y[8][2] = 11;
      				data_y[8][3] = 0;
      				data_y[8][4] = 0;
      				data_y[9] = new Array();
      				data_y[9][0] = 115;
      				data_y[9][1] = 142;
      				data_y[9][2] = 41;
      				data_y[9][3] = 0;
      				data_y[9][4] = 0;
      				data_y[10] = new Array();
      				data_y[10][0] = 87;
      				data_y[10][1] = 139;
      				data_y[10][2] = 61;
      				data_y[10][3] = 2;
      				data_y[10][4] = 1;
      				data_y[11] = new Array();
      				data_y[11][0] = 116;
      				data_y[11][1] = 141;
      				data_y[11][2] = 39;
      				data_y[11][3] = 0;
      				data_y[11][4] = 1;
      				data_y[12] = new Array();
      				data_y[12][0] = 172;
      				data_y[12][1] = 107;
      				data_y[12][2] = 23;
      				data_y[12][3] = 0;
      				data_y[12][4] = 1;
      				data_y[13] = new Array();
      				data_y[13][0] = 106;
      				data_y[13][1] = 122;
      				data_y[13][2] = 67;
      				data_y[13][3] = 2;
      				data_y[13][4] = 1;
      				data_y[14] = new Array();
      				data_y[14][0] = 115;
      				data_y[14][1] = 107;
      				data_y[14][2] = 68;
      				data_y[14][3] = 3;
      				data_y[14][4] = 1;
      				data_y[15] = new Array();
      				data_y[15][0] = 43;
      				data_y[15][1] = 116;
      				data_y[15][2] = 121;
      				data_y[15][3] = 12;
      				data_y[15][4] = 3;
      				data_y[16] = new Array();
      				data_y[16][0] = 44;
      				data_y[16][1] = 104;
      				data_y[16][2] = 124;
      				data_y[16][3] = 13;
      				data_y[16][4] = 7;
      				data_y[17] = new Array();
      				data_y[17][0] = 41;
      				data_y[17][1] = 99;
      				data_y[17][2] = 125;
      				data_y[17][3] = 16;
      				data_y[17][4] = 8;
      				data_y[18] = new Array();
      				data_y[18][0] = 32;
      				data_y[18][1] = 98;
      				data_y[18][2] = 150;
      				data_y[18][3] = 6;
      				data_y[18][4] = 3;
      				data_y[19] = new Array();
      				data_y[19][0] = 9;
      				data_y[19][1] = 48;
      				data_y[19][2] = 158;
      				data_y[19][3] = 50;
      				data_y[19][4] = 17;
      				data_y[20] = new Array();
      				data_y[20][0] = 46;
      				data_y[20][1] = 106;
      				data_y[20][2] = 128;
      				data_y[20][3] = 13;
      				data_y[20][4] = 1;
      				for (i1 = 0; i1 < 21; i1++) {
      					s = 0;
      					for (i2 = 0; i2 < 5; i2++)
      						s += data_y[i1][i2];
      					for (i2 = 0; i2 < 5; i2++) {
      						data_y[i1][i2] = data_y[i1][i2] / s * 100;
      						gp = gp + "," + data_y[i1][i2];
      					}
      				}
      				gp = gp + ",1,1";
      			}
      					// 円グラフ
      			else if (kind == 4) {
      				gp = "4,円グラフの例(全体:277人),5,非常に重視する,やや重視する,普通,あまり考慮しない,全く考慮しない";
      				x = new Array();
      				x[0] = 10;
      				x[1] = 56;
      				x[2] = 160;
      				x[3] = 36;
      				x[4] = 15;
      				s    = 0;
      				for (i1 = 0; i1 < 5; i1++)
      					s += x[i1];
      				for (i1 = 0; i1 < 5; i1++) {
      					x[i1] = x[i1] / s * 100;
      					gp = gp + "," + x[i1];
      				}
      				gp = gp + ",1";
      			}
      					// 散布図
      			else if (kind == 5)
      				gp = "5,散布図の例,x軸タイトル,y軸タイトル,0.0,150.0,30.0,0,0.0,200.0,50.0,0,10,11,146,40,70,100,120,50,130,80,130,17,170,21,80,140,100,80,190,60,180,1";
      					// レーダーチャート
      			else if (kind == 6)
      				gp = "6,レーダーチャートの例,2,重要度,評価,21,自己啓発,目的意識,国際感覚,実行力,創造力,交渉力・調整力・コミュニケーション,情報収集力,プレゼンテーション能力,積極性・自主性・チャレンジ精神,柔軟性・協調性,好奇心・探求心,持続力・忍耐力,責任感,明朗さ,真面目さ,基礎学力(数学・物理等),専門知識,専門技術,日本語(文章読解・文章作成),英語,コンピュータ・情報処理,1.0,5.0,1.0,1,4.2,4.4,3.0,4.5,4.2,4.2,3.8,3.6,4.7,4.2,4.1,4.2,4.5,4.1,4.1,3.6,3.6,3.5,3.5,2.9,3.6,3.4,3.5,2.7,3.5,3.2,3.2,3.1,2.9,3.4,3.6,3.3,3.6,3.8,3.5,4.0,3.3,3.2,3.2,3.1,2.7,3.4,1,1";
      					// ボード線図(片対数グラフ)
      			else
      				gp = "7,ボード線図の例,角周波数,ゲイン(dB),2,一次遅れ要素,二次遅れ要素,0.01,100.0,1.0,2,-80.0,20.0,20.0,0,101,0.01,0.0109647819614318,0.0120226443461741,0.013182567385564,0.0144543977074592,0.0158489319246111,0.0173780082874937,0.0190546071796325,0.0208929613085404,0.0229086765276777,0.0251188643150958,0.0275422870333817,0.0301995172040202,0.0331131121482591,0.0363078054770102,0.0398107170553498,0.0436515832240167,0.0478630092322639,0.0524807460249773,0.0575439937337158,0.0630957344480195,0.0691830970918938,0.0758577575029186,0.0831763771102673,0.0912010839355912,0.1,0.109647819614318,0.120226443461741,0.131825673855641,0.144543977074593,0.158489319246111,0.173780082874938,0.190546071796325,0.208929613085404,0.229086765276778,0.251188643150959,0.275422870333817,0.301995172040202,0.331131121482592,0.363078054770102,0.398107170553498,0.436515832240167,0.47863009232264,0.524807460249774,0.575439937337159,0.630957344480195,0.691830970918939,0.758577575029186,0.831763771102674,0.912010839355913,1,1.09647819614318,1.20226443461741,1.31825673855641,1.44543977074593,1.58489319246111,1.73780082874938,1.90546071796325,2.08929613085404,2.29086765276778,2.51188643150958,2.75422870333817,3.01995172040202,3.31131121482592,3.63078054770102,3.98107170553498,4.36515832240167,4.7863009232264,5.24807460249774,5.75439937337159,6.30957344480195,6.91830970918939,7.58577575029186,8.31763771102674,9.12010839355913,10,10.9647819614318,12.0226443461741,13.1825673855641,14.4543977074593,15.8489319246112,17.3780082874938,19.0546071796325,20.8929613085404,22.9086765276778,25.1188643150959,27.5422870333818,30.1995172040203,33.1131121482592,36.3078054770103,39.8107170553499,43.6515832240168,47.8630092322641,52.4807460249775,57.543993733716,63.0957344480196,69.183097091894,75.8577575029188,83.1763771102676,91.2010839355915,100,-0.00043427276862636,-0.000522105424932322,-0.000627701152241214,-0.000754651740749838,-0.000907275005683991,-0.00109076142866441,-0.00131135036701045,-0.0015765417703246,-0.00189535052688523,-0.00227861197648364,-0.00273934881496565,-0.00329321162892171,-0.00395900769500453,-0.00475933552387765,-0.00572134599940977,-0.00687765494318666,-0.00826743661415132,-0.00993773312918616,-0.0119450211581656,-0.014357084593869,-0.017255250287929,-0.0207370534016865,-0.0249194093944646,-0.0299423809918071,-0.0359736402894658,-0.0432137378264255,-0.051902300972248,-0.0623252917208117,-0.0748234565761777,-0.0898020952083107,-0.10774225511957,-0.129213420154599,-0.154887692755856,-0.185555362732532,-0.222141596415848,-0.265723755961027,-0.317548557029209,-0.379047887154574,-0.451851641314966,-0.537795410636778,-0.6389203414338,-0.757462064101649,-0.895825422443528,-1.05654200302736,-1.2422083724146,-1.45540463109294,-1.69859540490393,-1.97401850619972,-2.2835697095824,-2.62869465226149,-3.01029995663982,-3.42869465226149,-3.8835697095824,-4.37401850619973,-4.89859540490394,-5.45540463109295,-6.04220837241461,-6.65654200302738,-7.29582542244354,-7.95746206410166,-8.63892034143381,-9.33779541063679,-10.0518516413149,-10.7790478871545,-11.5175485570292,-12.265723755961,-13.0221415964158,-13.7855553627325,-14.5548876927558,-15.3292134201546,-16.1077422551196,-16.8898020952083,-17.6748234565762,-18.4623252917208,-19.2519023009722,-20.0432137378264,-20.8359736402895,-21.6299423809918,-22.4249194093944,-23.2207370534017,-24.0172552502879,-24.8143570845939,-25.6119450211582,-26.4099377331292,-27.2082674366141,-28.0068776549432,-28.8057213459994,-29.6047593355239,-30.403959007695,-31.2032932116289,-32.002739348815,-32.8022786119765,-33.6018953505269,-34.4015765417703,-35.201311350367,-36.0010907614287,-36.8009072750057,-37.6007546517408,-38.4006277011522,-39.2005221054249,-40.0004342727686,0.01,0.0109647819614318,0.0120226443461741,0.013182567385564,0.0144543977074592,0.0158489319246111,0.0173780082874937,0.0190546071796325,0.0208929613085404,0.0229086765276777,0.0251188643150958,0.0275422870333817,0.0301995172040202,0.0331131121482591,0.0363078054770102,0.0398107170553498,0.0436515832240167,0.0478630092322639,0.0524807460249773,0.0575439937337158,0.0630957344480195,0.0691830970918938,0.0758577575029186,0.0831763771102673,0.0912010839355912,0.1,0.109647819614318,0.120226443461741,0.131825673855641,0.144543977074593,0.158489319246111,0.173780082874938,0.190546071796325,0.208929613085404,0.229086765276778,0.251188643150959,0.275422870333817,0.301995172040202,0.331131121482592,0.363078054770102,0.398107170553498,0.436515832240167,0.47863009232264,0.524807460249774,0.575439937337159,0.630957344480195,0.691830970918939,0.758577575029186,0.831763771102674,0.912010839355913,1,1.09647819614318,1.20226443461741,1.31825673855641,1.44543977074593,1.58489319246111,1.73780082874938,1.90546071796325,2.08929613085404,2.29086765276778,2.51188643150958,2.75422870333817,3.01995172040202,3.31131121482592,3.63078054770102,3.98107170553498,4.36515832240167,4.7863009232264,5.24807460249774,5.75439937337159,6.30957344480195,6.91830970918939,7.58577575029186,8.31763771102674,9.12010839355913,10,10.9647819614318,12.0226443461741,13.1825673855641,14.4543977074593,15.8489319246112,17.3780082874938,19.0546071796325,20.8929613085404,22.9086765276778,25.1188643150959,27.5422870333818,30.1995172040203,33.1131121482592,36.3078054770103,39.8107170553499,43.6515832240168,47.8630092322641,52.4807460249775,57.543993733716,63.0957344480196,69.183097091894,75.8577575029188,83.1763771102676,91.2010839355915,100,0.000760038415382399,0.000913772766359686,0.00109860460812431,0.00132082497033832,0.0015879978301257,0.00190921780497035,0.00229542006615489,0.00275975307888415,0.00331802694011069,0.00398925269639393,0.00479629117620189,0.00576663367903434,0.0069333414679863,0.00833617658612594,0.0100229632730993,0.0120512274603127,0.0144901717990999,0.0174230558361977,0.0209500658109257,0.0251917767617845,0.0302933320307221,0.0364294929122781,0.043810745501032,0.0526906945590592,0.0633750278465736,0.0762324020119698,0.0917076870782207,0.11033811653403,0.132773031837264,0.159798094398276,0.192365079368509,0.231628683657635,0.278992202428454,0.336164489672405,0.405231365272613,0.488745617523805,0.589841028229403,0.712377430460434,0.861125568145392,1.0420019107726,1.26236286023883,1.53136003903385,1.86032983314904,2.26310269847673,2.7558619659877,3.35544406114777,4.07285867859558,4.8930591948081,5.71985312756973,6.26638529740493,6.02059991327959,4.66638529740486,2.51985312756961,0.0930591948079767,-2.32714132140453,-4.64455593885234,-6.84413803401239,-8.93689730152335,-10.939670166851,-12.8686399609662,-14.7376371397612,-16.5579980892274,-18.3388744318546,-20.0876225695396,-21.8101589717706,-23.5112543824762,-25.1947686347274,-26.8638355103276,-28.5210077975716,-30.1683713163424,-31.8076349206315,-33.4402019056017,-35.0672269681628,-36.689661883466,-38.3082923129218,-39.9237675979881,-41.5366249721535,-43.147309305441,-44.756189254499,-46.3635705070877,-47.9697066679693,-49.5748082232382,-51.1790499341891,-52.7825769441638,-54.3855098282009,-55.9879487725397,-57.5899770367269,-59.1916638234139,-60.7930666585321,-62.394233366321,-63.9952037088238,-65.5960107473037,-67.1966819730599,-68.7972402469212,-70.3977045799339,-71.9980907821951,-73.5984120021699,-75.1986791750297,-76.7989013953919,-78.3990862272337,-79.9992399615847,1,1";
      			graph(gp);
      		}
      	</SCRIPT>
      </HEAD>
      <BODY CLASS="white">
      	<H3 STYLE="text-align: center">表示するグラフを選択してください</H3>
      	<FORM>
      		<DIV STYLE="text-align: center">
      			<TABLE STYLE="text-align: left; margin-right: auto; margin-left: auto">
      				<TR>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(0)">棒グラフ</TD>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(1)">折れ線グラフ(1)</TD>
      				<TR>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(2)">折れ線グラフ(2)</TD>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(3)">積み上げ棒グラフ</TD>
      				</TR>
      				<TR>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(4)">円グラフ</TD>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(5)">散布図</TD>
      				</TR>
      				<TR>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(6)">レーダーチャート</TD>
      					<TD><INPUT TYPE="radio" NAME="g_type" onClick="sel(7)">ボード線図(片対数グラフ)</TD>
      				</TR>
      			</TABLE>
      		</DIV>
      	</FORM>
      	<BR>
      	<DIV ID="cl_line" STYLE="text-align: center; display: none">
      		<FORM>
      			<DIV ID="c0">
      				<INPUT ID="rgb0" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r0" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(0)"> 
      				緑<INPUT ID="g0" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(0)"> 
      				青<INPUT ID="b0" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(0)">
      			</DIV>
      			<DIV ID="c1">
      				<INPUT ID="rgb1" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r1" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(1)"> 
      				緑<INPUT ID="g1" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(1)"> 
      				青<INPUT ID="b1" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(1)">
      			</DIV>
      			<DIV ID="c2">
      				<INPUT ID="rgb2" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r2" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(2)"> 
      				緑<INPUT ID="g2" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(2)"> 
      				青<INPUT ID="b2" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(2)">
      			</DIV>
      			<DIV ID="c3">
      				<INPUT ID="rgb3" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r3" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(3)"> 
      				緑<INPUT ID="g3" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(3)"> 
      				青<INPUT ID="b3" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(3)">
      			</DIV>
      			<DIV ID="c4">
      				<INPUT ID="rgb4" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r4" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(4)"> 
      				緑<INPUT ID="g4" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(4)"> 
      				青<INPUT ID="b4" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(4)">
      			</DIV>
      			<DIV ID="c5">
      				<INPUT ID="rgb5" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r5" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(5)"> 
      				緑<INPUT ID="g5" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(5)"> 
      				青<INPUT ID="b5" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(5)">
      			</DIV>
      			<DIV ID="c6">
      				<INPUT ID="rgb6" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r6" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(6)"> 
      				緑<INPUT ID="g6" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(6)"> 
      				青<INPUT ID="b6" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(6)">
      			</DIV>
      			<DIV ID="c7">
      				<INPUT ID="rgb7" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r7" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(7)"> 
      				緑<INPUT ID="g7" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(7)"> 
      				青<INPUT ID="b7" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(7)">
      			</DIV>
      			<DIV ID="c8">
      				<INPUT ID="rgb8" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r8" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(8)"> 
      				緑<INPUT ID="g8" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(8)"> 
      				青<INPUT ID="b8" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(8)">
      			</DIV>
      			<DIV ID="c9">
      				<INPUT ID="rgb9" TYPE="text" SIZE="3" STYLE="font-size: 90%"> 
      				赤<INPUT ID="r9" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(9)"> 
      				緑<INPUT ID="g9" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(9)"> 
      				青<INPUT ID="b9" TYPE="text" SIZE="1" STYLE="font-size: 90%" onblur="c_change(9)">
      			</DIV>
      			<DIV ID="line_m">
      				マーク:<INPUT ID="l_m1" TYPE="radio" NAME="mark" STYLE="font-size: 90%" CHECKED>付ける 
      				<INPUT ID="l_m2" TYPE="radio" NAME="mark" STYLE="font-size: 90%">付けない
      			</DIV>
      			<DIV ID="line_w">
      				線の太さ:<INPUT ID="l_w" TYPE="text" SIZE="3" STYLE="font-size: 90%" VALUE="2">
      			</DIV>
      			<DIV>
      				<SPAN STYLE="background-color: pink; font-size: 100%" onClick="D_Change()">OK</SPAN>
      			</DIV>
      		</FORM>
      	</DIV>
      	<BR>
      	<DIV STYLE="text-align: center">
      		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="900" HEIGHT="600" onClick="Click(event)"></CANVAS>
      	</DIV>
      </BODY>
      </HTML>
      				

静岡理工科大学 菅沼ホーム JavaScript目次 索引