情報学部 菅沼ホーム 目次 索引

CANVAS 要素と JavaScript

  CANVAS 要素は,図を描く領域を確保するために使用される HTML の要素です.実際に図を描くには,以下に示すような JavaScript のメソッドが使用されます.また,先に述べた DOM のプロパティやメソッドを使用する場合も多いと思います.

  1. CANVAS のメソッド

    1. getContext(contextId)  CANVAS に描画するための API にアクセスできるオブジェクト(コンテキスト)を返す(使用例 1使用例 2
    2. toDataURL("MIME タイプ")  CANVAS 画面のピクセル情報を data URL 形式(文字列)に変換( MIME タイプのデフォルトは png 形式).変換された文字列を IMG 要素の SRC 属性に設定することによって,CANVAS 内で作成した画像を IMG 要素に反映することが可能.(使用例 3

  2. 2d コンテキストのプロパティとメソッド
    1. インタフェース

    2. interface CanvasRenderingContext2D {
      
        // back-reference to the canvas
        readonly attribute HTMLCanvasElement canvas;
      
        // state
        void save(); // push state on state stack
        void restore(); // pop state stack and restore state
      
        // transformations (default transform is the identity matrix)
                 attribute SVGMatrix currentTransform;
        void scale(unrestricted double x, unrestricted double y);
        void rotate(unrestricted double angle);
        void translate(unrestricted double x, unrestricted double y);
        void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
        void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
        void resetTransform();
      
        // compositing
                 attribute unrestricted double globalAlpha; // (default 1.0)
                 attribute DOMString globalCompositeOperation; // (default source-over)
      
        // image smoothing
                 attribute boolean imageSmoothingEnabled; // (default true)
      
        // colors and styles (see also the CanvasDrawingStyles interface)
                 attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black)
                 attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black)
        CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
        CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
        CanvasPattern createPattern((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, DOMString repetition);
      
        // shadows
                 attribute unrestricted double shadowOffsetX; // (default 0)
                 attribute unrestricted double shadowOffsetY; // (default 0)
                 attribute unrestricted double shadowBlur; // (default 0)
                 attribute DOMString shadowColor; // (default transparent black)
      
        // rects
        void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
        void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
        void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
      
        // path API (see also CanvasPathMethods)
        void beginPath();
        void fill();
        void fill(Path path);
        void stroke();
        void stroke(Path path);
        void drawSystemFocusRing(Element element);
        void drawSystemFocusRing(Path path, Element element);
        boolean drawCustomFocusRing(Element element);
        boolean drawCustomFocusRing(Path path, Element element);
        void scrollPathIntoView();
        void scrollPathIntoView(Path path);
        void clip();
        void clip(Path path);
        void resetClip();
        boolean isPointInPath(unrestricted double x, unrestricted double y);
        boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
      
        // text (see also the CanvasDrawingStyles interface)
        void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
        void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
        TextMetrics measureText(DOMString text);
      
        // drawing images
        void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double dx, unrestricted double dy);
        void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh);
        void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh);
      
        // hit regions
        void addHitRegion(HitRegionOptions options);
        void removeHitRegion(HitRegionOptions options);
      
        // pixel manipulation
        ImageData createImageData(double sw, double sh);
        ImageData createImageData(ImageData imagedata);
        ImageData createImageDataHD(double sw, double sh);
        ImageData getImageData(double sx, double sy, double sw, double sh);
        ImageData getImageDataHD(double sx, double sy, double sw, double sh);
        void putImageData(ImageData imagedata, double dx, double dy);
        void putImageData(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight);
        void putImageDataHD(ImageData imagedata, double dx, double dy);
        void putImageDataHD(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight);
      };
      CanvasRenderingContext2D implements CanvasDrawingStyles;
      CanvasRenderingContext2D implements CanvasPathMethods;
      
      [NoInterfaceObject]
      interface CanvasDrawingStyles {
        // line caps/joins
                 attribute unrestricted double lineWidth; // (default 1)
                 attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
                 attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
                 attribute unrestricted double miterLimit; // (default 10)
      
        // dashed lines
        void setLineDash(sequence segments); // default empty
        sequence getLineDash();
                 attribute unrestricted double lineDashOffset;
      
        // text
                 attribute DOMString font; // (default 10px sans-serif)
                 attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
                 attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
      };
      
      [NoInterfaceObject]
      interface CanvasPathMethods {
        // shared path API methods
        void closePath();
        void moveTo(unrestricted double x, unrestricted double y);
        void lineTo(unrestricted double x, unrestricted double y);
        void quadraticCurveTo(unrestricted double cpx, unrestricted double cpy, unrestricted double x, unrestricted double y);
        void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y);
        void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius); 
        void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation); 
        void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
        void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); 
        void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, boolean anticlockwise); 
      };
      
      interface CanvasGradient {
        // opaque object
        void addColorStop(double offset, DOMString color);
      };
      
      interface CanvasPattern {
        // opaque object
        void setTransform(SVGMatrix transform);
      };
      
      interface TextMetrics {
        // x-direction
        readonly attribute double width; // advance width
        readonly attribute double actualBoundingBoxLeft;
        readonly attribute double actualBoundingBoxRight;
      
        // y-direction
        readonly attribute double fontBoundingBoxAscent;
        readonly attribute double fontBoundingBoxDescent;
        readonly attribute double actualBoundingBoxAscent;
        readonly attribute double actualBoundingBoxDescent;
        readonly attribute double emHeightAscent;
        readonly attribute double emHeightDescent;
        readonly attribute double hangingBaseline;
        readonly attribute double alphabeticBaseline;
        readonly attribute double ideographicBaseline;
      };
      
      dictionary HitRegionOptions {
        Path? path = null;
        DOMString id = "";
        DOMString? parentID = null;
        DOMString cursor = "inherit";
        // for control-backed regions:
        Element? control = null;
        // for unbacked regions:
        DOMString? label = null;
        DOMString? role = null;
      };
      
      interface ImageData {
        readonly attribute unsigned long width;
        readonly attribute unsigned long height;
        readonly attribute Uint8ClampedArray data;
      };
      
      [Constructor(optional Element scope)]
      interface DrawingStyle { };
      DrawingStyle implements CanvasDrawingStyles;
      
      [Constructor,
       Constructor(Path path),
       Constructor(DOMString d)]
      interface Path {
        void addPath(Path path, SVGMatrix? transformation);
        void addPathByStrokingPath(Path path, CanvasDrawingStyles styles, SVGMatrix? transformation);
        void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
        void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
        void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path path, optional unrestricted double maxWidth);
        void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path path, optional unrestricted double maxWidth);
      };
      Path implements CanvasPathMethods;
      			
    3. CANVAS の状態

      • context.restore()  状態の復元(使用例 4
      • context.save()  以下に示す状態を保存(使用例 4
        • 変換マトリックス
        • 切り抜き領域
        • 以下の属性の現在値: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, imageSmoothingEnabled.
        • dash list
    4. パスの生成と描画

    5.   CANVAS 上に描かれた画像(オブジェクト)はパスから構成されている.各パスは,0 個以上のサブパスからなっている(初期値は 0 ).各々のサブパスは,直線又は曲線で結ばれた 1 つ以上の点とそのサブパスが閉じられているか否かの情報から構成されている.閉じられたサブパスでは,サブパスの最後の点は最初の点と直線で結ばれている.また,1 個以下の点から構成されているサブパスは描画の際無視される.

      • context.arc(x, y, radius, startAngle, endAngle [, anticlockwise ] )  与えられた点を中心とした半径 radius の円弧を startAngle から endAngle まで,指定された方向に描く(デフォルトは,anticlockwise = false であるので,時計回りに描く)(使用例 7
      • context.arcTo(x1, y1, x2, y2, radius)  直前の点 (x0, y0) と直線で結ばれた円弧(直線 (x0, y0) - (x1, y1) と直線 (x1, y1) - (x2, y2) との角を円弧にする)(使用例 7
      • context.beginPath()  現在のサブパスをリセット(使用例 5
      • context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)  与えられた点と直前の点を,制御点を利用して 3 次ベジェ曲線で結ぶ(使用例 6
      • context.clearRect(x, y, w, h)  指定した矩形領域をクリア(使用例 9
      • context.clip()  呼び出される直前までに生成されたサブパスの図形で,切り抜き窓がセットされる.以後,切り抜き窓内だけが表示されるようになる.新規の切り抜き領域を指定した場合には,現在の切り抜き領域と置き換えられる.また,コンテキストを初期化すると,CANVAS 全体が切り抜き領域として設定される.(使用例 10
      • context.closePath()  現在のサブパスの最後の点と最初の点を結びパスを閉じる.そして,閉じたサブパスの最初の点に基づき新しいサブパスを生成(使用例 5
      • context.fill()  サブパスを塗りつぶす(使用例 7使用例 8
      • context.fillRect(x, y, w, h)  指定した位置(矩形の左上)に塗りつぶした矩形を描く( stroke や fill メソッドを必要としない)(使用例 9
      • context.isPointInPath(x, y)  与えられた点がパス内にあるか否かを判定する(使用例 5
      • context.lineTo(x, y)  与えられた点と直前の点を直線で結ぶ(使用例 5
      • context.moveTo(x, y)  与えられた座標に基づき,新しいサブパスの生成(使用例 5
      • context.quadraticCurveTo(cpx, cpy, x, y)  与えられた点と直前の点を,制御点を利用して 2 次ベジェ曲線で結ぶ(使用例 6
      • context.rect(x, y, w, h)  指定した位置(矩形の左上)に矩形を描く(使用例 8
      • context.stroke()  サブパスの輪郭を表示する(使用例 5
      • context.strokeRect(x, y, w, h)  指定した位置(矩形の左上)に矩形を描く( stroke や fill メソッドを必要としない)(使用例 9
    6. line,fill,stroke スタイル

      • context.fillStyle [ = value ]  塗りつぶしの色や図形内部のスタイル(グラデーション,背景パターン)を指定(使用例 13使用例 14
      • context.lineCap [ = value ]  線端の形状(使用例 11
        • butt: 先端でそのまま終了(デフォルト)
        • round: 先端に半円を追加
        • square: 先端に線幅の半分の長方形を追加

      • context.lineJoin [ = value ]  線の接合箇所の形状(使用例 12
        • miter: 面取りしない(デフォルト)
        • round: 丸くする
        • bevel: 面取りする

      • context.lineWidth [ = value ]  線の太さ(使用例 11
      • context.miterLimit [ = value ]  線の接合箇所を miter 表示にする限界.先端の長さが線幅にこの値を乗じたものより長くなると,面取りされる.(使用例 12
      • context.strokeStyle [ = value ]  線の色,または,グラデーションを指定(使用例 15
      • gradient = context.createLinearGradient(x0, y0, x1, y1)  開始点 (x0, y0) と終了点 (x1, y1) を指定し,2 点間を結ぶ線形グラデーションを定義(使用例 15
      • gradient = context.createRadialGradient(x0, y0, r0, x1, y1, r1)  中心 (x0, y0),半径 r0 の円から,中心 (x1, y1),半径 r1 を指定し,2 つの円を結ぶ円形グラデーションを定義(使用例 13
      • gradient.addColorStop(offset, color)  開始点から offset だけ離れた点の色 color を指定(使用例 13使用例 15
      • pattern = context.createPattern(image, repetition)  背景パターンとその繰り返し方法を指定.imageは,背景パターンに使用するイメージデータ( canvas,img,video ).repetition は以下に示すいずれかの値をとる.(使用例 14
        • repeat: 水平・垂直の両方向に繰り返す(デフォルト)
        • repeat-x: 水平方向にのみ繰り返す
        • repeat-y: 垂直方向にのみ繰り返す
        • no-repeat: 繰り返さない
    7. テキストスタイルと描画

      • context.fillText(text, x, y [, maxWidth ] )  塗りつぶしのテキストを指定位置に描く(使用例 16
      • context.font [ = value ]  フォントの設定(使用例 16
      • context.strokeText(text, x, y [, maxWidth ] )  テキストの輪郭を指定位置に描く(使用例 16
      • context.textAlign [ = value ]  テキストの揃え位置(横位置)(使用例 16
        • start: 指定した位置から開始(デフォルト)
        • end: 文字列の最後が指定位置
        • left: 文字列の左が指定位置(左揃え)
        • right: 文字列の右が指定位置(右揃え)
        • center: 文字列の中央が指定位置(中央揃え)

      • context.textBaseline [ = value ]  テキストのベースライン(縦位置)(使用例 16
        • alphabetic: 文字列のほぼ下端(デフォルト)
        • ideographic: 文字列のほぼ下端( alphabetic より少し下)
        • bottom: 文字列のほぼ下端( ideographic より少し下)
        • hanging: 文字列のほぼ上端
        • top: 文字列のほぼ上端( hanging より少し上)
        • middle: 文字列の中央

      • metrics = context.measureText(text)  テキストのメトリックス(描画幅などの性質)を取得(使用例 17
        • metrics.width: 文字列の長さ

    8. 画像の描画とピクセル操作

      • context.drawImage(image, dx, dy)  画像( img,canvas,video )を指定した位置に描く(使用例10使用例 18
      • context.drawImage(image, dx, dy, dw, dh)  幅と高さを指定して,画像( img,canvas,video )を指定した位置に描く(使用例 18
      • context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)  画像( img,canvas,video )の指定した範囲( sx, sy, sw, sh )を,指定した位置( dx, dy )に指定した大きさ( dw, dh )で描く(使用例 18
      • ImageData = context.getImageData(sx, sy, sw, sh)  CANVAS から,指定範囲の ImageData オブジェクトを取得(使用例 3使用例 18使用例 19
        • ImageData.width: ImageDataオ ブジェクトの幅
        • ImageData.height: ImageData オブジェクトの高さ
        • ImageData.data: RGBA 順の一次配列データ

      • ImageData = context.createImageData(sw, sh)  指定された大きさの ImageData オブジェクトを生成(使用例 3使用例 18使用例 19
      • ImageData = context.createImageData(imagedata)  引数と同じ大きさの ImageData オブジェクトを生成(使用例 3使用例 18
      • context.putImageData(imagedata, dx, dy [, dirtyX, dirtyY, dirtyWidth, dirtyHeight ])  ImageData オブジェクトを指定した位置に描画する.省略可能部分は,ImageData オブジェクトの描画範囲であり,省略すると全体を描画する.(使用例 3使用例 18使用例 19
    9. 影の付加

      • context.shadowBlur [ = value ]  影のぼかしレベル(使用例 20
      • context.shadowColor [ = value ]  影の色(使用例 20
      • context.shadowOffsetX [ = value ]  影の水平方向のオフセット(使用例 20
      • context.shadowOffsetY [ = value ]  影の垂直方向のオフセット(使用例 20
    10. 透明度と合成

      • context.globalAlpha [ = value ]  図形やイメージの透明度(使用例 21
      • context.globalCompositeOperation [ = value ]  合成方法
        • source-atop: 既に描いたイメージの領域のみが描画され,source-atop 属性を指定して新しく描いたイメージと重なった部分には,新しく描いたイメージが表示され,新規イメージとなる(使用例 22

        • source-in: source-in 属性を指定して新しく描いたイメージの,既に描いたイメージの領域と重なった部分だけが新規イメージとして描画される(使用例 23

        • source-out: source-out 属性を指定して新しく描いたイメージの,既に描いたイメージの領域と重ならない部分だけが描画される(使用例 24

        • source-over: 既に描いたイメージの上に,source-over 属性を指定して新しく描いたイメージが描画され,重なった部分は新規イメージとなる(デフォルト)(使用例 25

        • destination-atop: destination-atop 属性を指定して新しく描いた領域のみが描画され,既に描いたイメージと重なった部分には,既に描いたイメージが表示され,新規イメージとなる(使用例 26

        • destination-in: 既に描いたイメージの,destination-in 属性を指定して新しく描いた領域と重なった部分だけが現在イメージとして描画される(使用例 27

        • destination-out: 既に描いたイメージの,destination-out 属性を指定して新しく描いた領域と重ならない部分だけが現在イメージとして描画される(使用例 28

        • destination-over: destination-over 属性を指定して新しく描いたイメージの上に,既に描いたイメージが描画され,重なった部分は現在イメージとなる(使用例 29

        • lighter: lighter 属性を指定して新しく描いたイメージと,既に描いたイメージが描画され,重なった部分は混色して描画される(使用例 30

        • copy: copy 属性を指定して新しく描いた領域のみが描画され,既に描いたイメージと重なった部分には,新しく描いたイメージが表示され,新規イメージとなる(使用例 31

        • xor: xor 属性を指定して新しく描いたイメージと既に描いたイメージの両方が表示され,重なった部分は表示されない(使用例 32

    11. 回転,移動,拡大・縮小

      • context.rotate(angle)  与えられた角度(ラジアン)だけ座標軸を回転する(使用例 34
      • context.scale(x, y)  x 及び y 軸の拡大縮小係数を与え,座標軸を拡大・縮小する(使用例 33
      • context.setTransform(a, b, c, d, e, f)  今までの変換マトリックスをリセットし,新しい変換マトリックスを利用して座標軸を変換する(使用例 36
        • 旧座標軸による座標を p_old = [x1, y1], 新座標軸による座標を p_new = [x2, y2] とすると,以下に示すような関係がある.
             [x2, y2, 1]T = A [x1, y1, 1]T
        • 拡大縮小: scale(x, y) = transform(x, 0, 0, y, 0, 0)
        • 回転: rotate(angle) = transform(Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0, 0)
        • 移動: translate(x, y) = transform(1, 0, 0, 1, x, y)
        • 変換しない(元の状態に戻す): setTransform(1, 0, 0, 1, 0, 0)

      • context.transform(a, b, c, d, e, f)  変換マトリックスを利用して座標軸を変換する(使用例 36
      • context.translate(x, y)  座標軸の原点を指定された位置に移動する(使用例 35
  3. 使用例のまとめ

  4. CANVAS の応用例

    1. 描画とイベント処理

      1. 描画の基本

          CANVAS 要素に描画するためには,CANVAS のメソッド getContext によって,CANVAS に描画するための API にアクセスできるオブジェクト(コンテキスト,下の例では,ctx )を取得し,そのオブジェクトから API (下の例では,beginPath など)を使用して描画します.表示例では,左側に 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
        07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
        08		<SCRIPT TYPE="text/javascript">
        09			function draw() {
        10				let canvas    = document.getElementById('canvas_e');
        11				canvas.width  = 420;   // キャンバス要素の幅
        12				canvas.height = 140;   // キャンバス要素の高さ
        13				let ctx       = canvas.getContext('2d');
        14						// 矩形を描く
        15				ctx.beginPath();
        16				ctx.moveTo(20, 20);
        17				ctx.lineTo(120, 20);
        18				ctx.lineTo(120, 120);
        19				ctx.lineTo(20, 120);
        20				ctx.closePath();
        21				ctx.stroke();
        22						// 円を描く
        23				ctx.beginPath();
        24				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
        25				ctx.stroke();
        26						// 外部画像を描く
        27				let img = new Image();
        28				img.src = "ball.gif";
        29				ctx.drawImage(img, 170, 30);
        30						// ピクセル値の操作
        31				let wid = 80;
        32				let hei = 80;
        33				let im  = ctx.createImageData(wid, hei);
        34				for (let i1 = 0; i1 < hei/2; i1++) {
        35					for (let i2 = 0; i2 < wid; i2++) {
        36						let k = 4 * (wid * i1 + i2);
        37						im.data[k]   = 0x00;
        38						im.data[k+1] = 0xff;
        39						im.data[k+2] = 0x00;
        40						im.data[k+3] = 0xff;   // 透明度
        41					}
        42				}
        43				for (let i1 = hei/2; i1 < hei; i1++) {
        44					for (let i2 = 0; i2 < wid; i2++) {
        45						let k = 4 * (wid * i1 + i2);
        46						im.data[k]   = 0x00;
        47						im.data[k+1] = 0x00;
        48						im.data[k+2] = 0xff;
        49						im.data[k+3] = 0xff;   // 透明度
        50					}
        51				}
        52				ctx.putImageData(im, 310, 30);
        53			}
        54		</SCRIPT>
        55	</HEAD>
        56	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
        57		<H1>簡単な描画</H1>
        58		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="420" HEIGHT="140"></CANVAS>
        59	</BODY>
        60	</HTML>
        					
        10 行目

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

        11 行目~ 12 行目

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

        13 行目

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

        15 行目~ 21 行目

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

        23 行目~ 25 行目

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

        27 行目~ 29 行目

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

        31 行目~ 52 行目

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

        56 行目

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

        58 行目

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

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

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

        11 行目

          CAMVAS 要素の生成

        12 行目

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

        13 行目~ 14 行目

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

        15 行目

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

        61 行目

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

      2. イベント処理

        • イベント処理の基本

            以下に示すいずれの例においても,「マウスでここをクリックして下さい」の箇所をクリックするとイベントが発生し,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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			function func(event)
          10			{
          11				alert("x: " + event.pageX + ", y: " + event.pageY);
          12			}
          13		</SCRIPT>
          14	</HEAD>
          15	<BODY CLASS="white">
          16		<H1 CLASS="center">イベント処理(<SPAN ID="test" onClick="func(event)">マウスでここをクリックして下さい</SPAN>)</H1>
          17	</BODY>
          18	</HTML>
          						
          09 行目~ 12 行目

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

          16 行目

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

            「イベント処理(その2)」においては,SPAN 要素自体には onClick 属性が記述してありませんが,BODY 要素の中に,onLoad 属性が記述してあり,このページがロードされると関数 func が呼ばれます.関数 func の中で,ID 属性の値によって SPAN 要素を特定し( getElementById ( 'test' ) ),そこにマウスクリックに対するイベント処理を行う関数を付加する( addEventListener ( "click", mouseClick ) )ことによって,最初の例と同じイベント処理を実現しています.この方法は,ページが表示された当初からではなく,後ほど何らかの処理を行った後,イベント処理機能を追加したいような場合に利用できます.なお,getElementById 及び addEventListener については,「 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			function func()
          10			{
          11				let hs = document.getElementById('test');
          12				hs.addEventListener("click", mouseClick);
          13			}
          14			function mouseClick(event)
          15			{
          16				alert("x: " + event.pageX + ", y: " + event.pageY);
          17			}
          18		</SCRIPT>
          19	</HEAD>
          20	<BODY CLASS="white" onLoad="func()">
          21		<H1 CLASS="center">イベント処理(<SPAN ID="test">マウスでここをクリックして下さい</SPAN>)</H1>
          22	</BODY>
          23	</HTML>
          						
          09 行目~ 13 行目

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

          14 行目~ 17 行目

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

          20 行目

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

          21 行目

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

        • 色の変更

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

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

          24 行目

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

          25 行目

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

          26 行目~ 29 行目

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

          30 行目

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

          31 行目

            サブパスを塗りつぶす.

          32 行目

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

          38 行目

            このボタンをクリックすると,関数 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			canvas = null;
          10			ctx    = null;
          11			sw     = -1;
          12			x_base = -1;
          13			y_base = -1;
          14						// 初期設定と描画(ロード時)
          15			function draw()
          16			{
          17				canvas = document.getElementById('canvas_e');
          18				canvas.width  = 140;   // キャンバス要素の幅
          19				canvas.height = 140;   // キャンバス要素の高さ
          20				x_base = canvas.offsetLeft;   // キャンバスの左上のx座標
          21				y_base = canvas.offsetTop;   // キャンバスの左上のy座標
          22				ctx = canvas.getContext('2d');
          23				s_color();
          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			{
          41				let x_now = event.pageX - x_base;
          42				let y_now = event.pageY - y_base;
          43				let x1 = 70 - x_now;
          44				let y1 = 70 - y_now;
          45				let r  = Math.sqrt(x1 * x1 + y1 * y1);
          46				if (r < 40)
          47					s_color();
          48			}
          49		</SCRIPT>
          50	</HEAD>
          51	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
          52		<H1>イベント処理( CANVAS 要素の属性)</H1>
          53		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140" onClick="Click(event)"></CANVAS>
          54	</BODY>
          55	</HTML>
          						
          12 行目~ 13 行目

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

          20 行目~ 21 行目

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

          41 行目~ 42 行目

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

          43 行目~ 45 行目

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

          46 行目~ 47 行目

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

          53 行目

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

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

            その1では,24 行目において,マウスでクリックされた( "click" )ときに処理を行う関数( Click,関数名は任意)を指定し,関数 Click 自体は,40 行目~ 50 行目に記述しています.しかし,その2では,25 行目~ 33 行目に,イベント処理を行う関数本体も記述しています.なお,当然のことながら,いずれの場合においても,55 行目,及び,52 行目の 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			canvas = null;
          10			ctx    = null;
          11			sw     = -1;
          12			x_base = -1;
          13			y_base = -1;
          14						// 初期設定と描画(ロード時)
          15			function draw()
          16			{
          17				canvas = document.getElementById('canvas_e');
          18				canvas.width  = 140;   // キャンバス要素の幅
          19				canvas.height = 140;   // キャンバス要素の高さ
          20				x_base = canvas.offsetLeft;   // キャンバスの左上のx座標
          21				y_base = canvas.offsetTop;   // キャンバスの左上のy座標
          22				ctx = canvas.getContext('2d');
          23				s_color();
          24				canvas.addEventListener("click", Click, false);   // クリックイベント
          25			}
          26						// イベント処理(画像がクリックされた時)
          27			function s_color()
          28			{
          29				ctx.clearRect(0, 0, canvas.width, canvas.height);
          30				ctx.beginPath();
          31				if (sw < 0)
          32					ctx.fillStyle = "rgb(0, 255, 0)";
          33				else
          34					ctx.fillStyle = "rgb(255, 0, 0)";
          35				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
          36				ctx.fill();
          37				sw *= -1;
          38			}
          39						// クリックイベントの処理
          40			function Click(event)
          41	//		Click = function(event)   // この記述でも良い
          42			{
          43				let x_now = event.pageX - x_base;
          44				let y_now = event.pageY - y_base;
          45				let x1 = 70 - x_now;
          46				let y1 = 70 - y_now;
          47				let r  = Math.sqrt(x1 * x1 + y1 * y1);
          48				if (r < 40)
          49					s_color();
          50			}
          51		</SCRIPT>
          52	</HEAD>
          53	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
          54		<H1>イベント処理( addEventListener 1)</H1>
          55		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140"></CANVAS>
          56	</BODY>
          57	</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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			canvas = null;
          10			ctx    = null;
          11			sw     = -1;
          12			x_base = -1;
          13			y_base = -1;
          14						// 初期設定と描画(ロード時)
          15			function draw()
          16			{
          17				canvas = document.getElementById('canvas_e');
          18				canvas.width  = 140;   // キャンバス要素の幅
          19				canvas.height = 140;   // キャンバス要素の高さ
          20				x_base = canvas.offsetLeft;   // キャンバスの左上のx座標
          21				y_base = canvas.offsetTop;   // キャンバスの左上のy座標
          22				ctx = canvas.getContext('2d');
          23				s_color();
          24						// クリックイベントの処理
          25				canvas.addEventListener("click", function(event) {
          26					let x_now = event.pageX - x_base;
          27					let y_now = event.pageY - y_base;
          28					let x1 = 70 - x_now;
          29					let y1 = 70 - y_now;
          30					let r  = Math.sqrt(x1 * x1 + y1 * y1);
          31					if (r < 40)
          32						s_color();
          33				}, false);
          34			}
          35						// イベント処理(画像がクリックされた時)
          36			function s_color()
          37			{
          38				ctx.clearRect(0, 0, canvas.width, canvas.height);
          39				ctx.beginPath();
          40				if (sw < 0)
          41					ctx.fillStyle = "rgb(0, 255, 0)";
          42				else
          43					ctx.fillStyle = "rgb(255, 0, 0)";
          44				ctx.arc(70, 70, 40, 0, 2*Math.PI, false);
          45				ctx.fill();
          46				sw *= -1;
          47			}
          48		</SCRIPT>
          49	</HEAD>
          50	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
          51		<H1>イベント処理( addEventListener 2)</H1>
          52		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="140" HEIGHT="140"></CANVAS>
          53	</BODY>
          54	</HTML>
          						

        • お絵かき

            イベント処理のあと一つの例として,簡単なお絵かきソフトを示します.最初の例は 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
          10			x_old  = -1;
          11			y_old  = -1;
          12			x_base = -1;
          13			y_base = -1;
          14			ctx    = null;
          15			function draw() {
          16				let canvas1 = document.getElementById('canvas_e');
          17				canvas1.width  = 200;   // キャンバス要素の幅
          18				canvas1.height = 150;   // キャンバス要素の高さ
          19				x_base = canvas1.offsetLeft;   // キャンバスの左上のx座標
          20				y_base = canvas1.offsetTop;   // キャンバスの左上のy座標
          21				ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
          22				ctx.lineWidth = 5;   // 線の太さ
          23			}
          24						// イベント処理
          25			function m_move(event, sw) {   // マウス移動イベント
          26				if (sw > 0) {
          27					event.preventDefault();
          28					x_now = event.changedTouches[0].pageX - x_base;
          29					y_now = event.changedTouches[0].pageY - y_base;
          30				}
          31				else {
          32					x_now = event.pageX - x_base;
          33					y_now = event.pageY - y_base;
          34				}
          35				if (blush) {
          36					ctx.beginPath();
          37					ctx.moveTo(x_old, y_old);
          38					ctx.lineTo(x_now, y_now);
          39					ctx.stroke();
          40				}
          41				x_old = x_now;
          42				y_old = y_now;
          43			}
          44	
          45			function m_down(event, sw) {   // マウスボタン押下イベント
          46				if (!blush) {
          47					if (sw > 0) {
          48						x_old = event.changedTouches[0].pageX - x_base;
          49						y_old = event.changedTouches[0].pageY - y_base;
          50					}
          51					else {
          52						x_old = event.pageX - x_base;
          53						y_old = event.pageY - y_base;
          54					}
          55					blush = true;   // 描ける状態
          56				}
          57			}
          58	
          59			function m_up(event) {   // マウスボタン離されたイベント
          60				blush = false;   // 描けない状態
          61			}
          62		</SCRIPT>
          63	</HEAD>
          64	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
          65		<H1>お絵かき( CANVAS 要素の属性)</H1>
          66		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="200" HEIGHT="150" onMouseMove="m_move(event, 0)" onTouchMove="m_move(event, 1)" onMouseDown="m_down(event, 0)" onTouchStart="m_down(event, 1)" onMouseUp="m_up(event)" onTouchEnd="m_up(event)"></CANVAS>
          67	</BODY>
          68	</HTML>
          						
          09 行目

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

          10 行目~ 11 行目

            一つ前の点の座標

          22 行目

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

          25 行目~ 43 行目

            マウス(指)が移動している場合の処理である.26 行目~ 34 行目においては,マウスの現在位置( x_now,y_now )を取得している.sw が正の場合は,スマホやタブレットの場合に相当する.27 行目では,デフォルトのイベントを禁止している(この例の場合は,必ずしも必要としない).スマホ等の場合,指の位置が配列 changedTouches に入っており,changedTouches[0] は,1 本指で操作する場合に相当する.

            35 行目~ 40 行目においては,絵を描ける状態のとき,一つ前の点と現在位置を結ぶ直線を描いている.

            41 行目~ 42 行目において,一つ前の点を,現在位置で置き換えている.

          45 行目~ 57 行目

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

          59 行目~ 61 行目

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

          66 行目

            パソコンとスマホに対応するため,onMouseMove 属性(関数 m_move ),onMouseDown 属性(関数 m_down ),onMouseUp 属性(関数 m_up ),及び,onTouchMove 属性(スマホ対応,関数 m_move ),onTouchStart 属性(スマホ対応,関数 m_down ),onTouchEnd 属性(スマホ対応,関数 m_up ) を指定している.

          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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
          10			x_old  = -1;
          11			y_old  = -1;
          12			x_base = -1;
          13			y_base = -1;
          14			ctx    = null;
          15						// メイン
          16			function draw() {
          17				let canvas1 = document.getElementById('canvas_e');   // キャンバス要素を生成
          18				canvas1.width  = 200;   // キャンバス要素の幅
          19				canvas1.height = 150;   // キャンバス要素の高さ
          20				x_base = canvas1.offsetLeft;   // キャンバスの左上のx座標
          21				y_base = canvas1.offsetTop;   // キャンバスの左上のy座標
          22				ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
          23				ctx.lineWidth = 5;   // 線の太さ
          24								// イベントリスナの追加
          25				canvas1.addEventListener("mousemove", Move, false);   // マウス移動イベント
          26				canvas1.addEventListener("touchmove", Move1, false);   // マウス移動イベント
          27				canvas1.addEventListener("mousedown", Down, false);   // マウスボタン押下イベント
          28				canvas1.addEventListener("touchstart", Down1, false);   // マウスボタン押下イベント
          29				canvas1.addEventListener("mouseup", Up, false);   // マウスボタン離されたイベント
          30				canvas1.addEventListener("touchend", Up, false);   // マウスボタン離されたイベント
          31			}
          32						// マウス移動イベント
          33			function Move1(event) {
          34				Move(event, 1);
          35			}
          36			function Move(event, sw = 0)
          37	//		Move = function(event)   // この記述でも良い
          38			{
          39				if (sw > 0) {
          40					event.preventDefault();
          41					x_now = event.changedTouches[0].pageX - x_base;
          42					y_now = event.changedTouches[0].pageY - y_base;
          43				}
          44				else {
          45					x_now = event.pageX - x_base;
          46					y_now = event.pageY - y_base;
          47				}
          48				if (blush) {
          49					ctx.beginPath();
          50					ctx.moveTo(x_old, y_old);
          51					ctx.lineTo(x_now, y_now);
          52					ctx.stroke();
          53				}
          54				x_old = x_now;
          55				y_old = y_now;
          56			}
          57						// マウスボタン押下イベント
          58			function Down1(event) {
          59				Down(event, 1);
          60			}
          61			function Down(event, sw = 0)
          62	//		Down = function(event)   // この記述でも良い
          63			{
          64				if (!blush) {
          65					if (sw > 0) {
          66						x_old = event.changedTouches[0].pageX - x_base;
          67						y_old = event.changedTouches[0].pageY - y_base;
          68					}
          69					else {
          70						x_old = event.pageX - x_base;
          71						y_old = event.pageY - y_base;
          72					}
          73					blush = true;   // 描ける状態
          74				}
          75			}
          76						// マウスボタン離されたイベント
          77			function Up(event)
          78	//		Up = function(event)   // この記述でも良い
          79			{
          80				blush = false;   // 描けない状態
          81			}
          82		</SCRIPT>
          83	</HEAD>
          84	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
          85		<H1>お絵かき( addEventListener;その1)</H1>
          86		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="200" HEIGHT="150"></CANVAS>
          87	</BODY>
          88	</HTML>
          						

          addEventListener の使用:その2

          01	<!DOCTYPE HTML>
          02	<HTML>
          03	<HEAD>
          04		<TITLE>CANVAS の例</TITLE>
          05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
          06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          08		<SCRIPT TYPE="text/javascript">
          09			blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
          10			x_old  = -1;
          11			y_old  = -1;
          12			x_base = -1;
          13			y_base = -1;
          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				let ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
          21				ctx.lineWidth = 5;   // 線の太さ
          22						// イベント処理(イベントリスナの追加と処理)
          23				canvas1.addEventListener("touchmove", function(event) {   // マウス移動イベント
          24					event.preventDefault();
          25					x_now = event.changedTouches[0].pageX - x_base;
          26					y_now = event.changedTouches[0].pageY - y_base;
          27					if (blush) {
          28						ctx.beginPath();
          29						ctx.moveTo(x_old, y_old);
          30						ctx.lineTo(x_now, y_now);
          31						ctx.stroke();
          32					}
          33					x_old = x_now;
          34					y_old = y_now;
          35				}, false);
          36				canvas1.addEventListener("mousemove", function(event) {   // マウス移動イベント
          37					x_now = event.pageX - x_base;
          38					y_now = event.pageY - y_base;
          39					if (blush) {
          40						ctx.beginPath();
          41						ctx.moveTo(x_old, y_old);
          42						ctx.lineTo(x_now, y_now);
          43						ctx.stroke();
          44					}
          45					x_old = x_now;
          46					y_old = y_now;
          47				}, false);
          48	
          49				canvas1.addEventListener("touchstart", function(event) {   // マウスボタン押下イベント
          50					if (!blush) {
          51						x_old = event.changedTouches[0].pageX - x_base;
          52						y_old = event.changedTouches[0].pageY - y_base;
          53						blush = true;   // 描ける状態
          54					}
          55				}, false);
          56				canvas1.addEventListener("mousedown", function(event) {   // マウスボタン押下イベント
          57					if (!blush) {
          58						x_old = event.pageX - x_base;
          59						y_old = event.pageY - y_base;
          60						blush = true;   // 描ける状態
          61					}
          62				}, false);
          63	
          64				canvas1.addEventListener("touchend", function(event) {   // マウスボタン離されたイベント
          65					blush = false;   // 描けない状態
          66				}, false);
          67				canvas1.addEventListener("mouseup", function(event) {   // マウスボタン離されたイベント
          68					blush = false;   // 描けない状態
          69				}, false);
          70			}
          71		</SCRIPT>
          72	</HEAD>
          73	<BODY CLASS="white" STYLE="text-align: center" onLoad="draw()">
          74		<H1>お絵かき( addEventListener;その2)</H1>
          75		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="200" HEIGHT="150"></CANVAS>
          76	</BODY>
          77	</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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          007		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          008		<SCRIPT TYPE="text/javascript">
          009			blush  = false;   // お絵かき用ブラシの状態(絵を描けない状態)
          010			type   = 0;   // 0: 自由曲線,1: 直線
          011			img    = null;   // CANVAS 全体の ImageData オブジェクト
          012			x_old  = -1;
          013			y_old  = -1;
          014			x_base = -1;
          015			y_base = -1;
          016			ctx    = null;
          017			function draw() {
          018				let canvas1 = document.getElementById('canvas_e');
          019				canvas1.width  = 360;   // キャンバス要素の幅
          020				canvas1.height = 300;   // キャンバス要素の高さ
          021				x_base = canvas1.offsetLeft;   // キャンバスの左上のx座標
          022				y_base = canvas1.offsetTop;   // キャンバスの左上のy座標
          023				ctx = canvas1.getContext('2d');   // キャンバスからコンテキストを取得
          024				ctx.lineWidth = 5;   // 線の太さ
          025				ctx.strokeStyle = "rgb(255, 0, 0)";   // 線の色
          026			}
          027						// イベント処理
          028			function m_move(event, sw) {   // マウス移動イベント
          029								// 自由曲線の描画
          030				if (type == 0) {
          031					if (sw > 0) {
          032						x_now = event.changedTouches[0].pageX - x_base;
          033						y_now = event.changedTouches[0].pageY - y_base;
          034					}
          035					else {
          036						x_now = event.pageX - x_base;
          037						y_now = event.pageY - y_base;
          038					}
          039					if (blush) {
          040						ctx.beginPath();
          041						ctx.moveTo(x_old, y_old);
          042						ctx.lineTo(x_now, y_now);
          043						ctx.stroke();
          044					}
          045					x_old = x_now;
          046					y_old = y_now;
          047				}
          048			}
          049			function m_down(event, sw) {   // マウスボタン押下イベント
          050								// 自由曲線の描画
          051				event.preventDefault();
          052				if (type == 0) {
          053					if (!blush) {
          054						if (sw > 0) {
          055							x_old = event.changedTouches[0].pageX - x_base;
          056							y_old = event.changedTouches[0].pageY - y_base;
          057						}
          058						else {
          059							x_old = event.pageX - x_base;
          060							y_old = event.pageY - y_base;
          061						}
          062						blush = true;   // 描ける状態
          063					}
          064				}
          065								// 直線の描画
          066				else {
          067					if (!blush) {
          068						img = ctx.getImageData(0, 0, 360, 300);
          069						if (sw > 0) {
          070							x_old = event.changedTouches[0].pageX - x_base;
          071							y_old = event.changedTouches[0].pageY - y_base;
          072						}
          073						else {
          074							x_old = event.pageX - x_base;
          075							y_old = event.pageY - y_base;
          076						}
          077						let o_l = ctx.lineWidth;
          078						let o_c = ctx.strokeStyle;
          079						ctx.lineWidth = 1;
          080						ctx.strokeStyle = "rgb(0, 0, 0)";
          081						ctx.beginPath();
          082						ctx.moveTo(x_old-10, y_old);
          083						ctx.lineTo(x_old+10, y_old);
          084						ctx.moveTo(x_old, y_old-10);
          085						ctx.lineTo(x_old, y_old+10);
          086						ctx.stroke();
          087						ctx.lineWidth = o_l;
          088						ctx.strokeStyle = o_c;
          089						blush = true;
          090	//					if (sw > 0)
          091	//						alert("直線描画開始");
          092					}
          093					else {
          094						ctx.putImageData(img, 0, 0);
          095						let x_new = -1
          096						let y_new = -1;
          097						if (sw > 0) {
          098							x_new = event.changedTouches[0].pageX - x_base;
          099							y_new = event.changedTouches[0].pageY - y_base;
          100						}
          101						else {
          102							x_new = event.pageX - x_base;
          103							y_new = event.pageY - y_base;
          104						}
          105						ctx.beginPath();
          106						ctx.moveTo(x_old, y_old);
          107						ctx.lineTo(x_new, y_new);
          108						ctx.stroke();
          109						blush = false;
          110	//					if (sw > 0)
          111	//						alert("直線描画終了");
          112					}
          113				}
          114			}
          115			function m_up(event) {   // マウスボタン離されたイベント
          116								// 自由曲線の描画
          117				if (type == 0)
          118					blush = false;   // 描けない状態
          119			}
          120			function c_type(sw) {   // タイプの変更
          121				if (!blush)
          122					type = sw;
          123			}
          124			function c_color(sw) {   // 線の色の変更
          125				if (sw < 0)
          126					ctx.strokeStyle = "rgb(255, 0, 0)";
          127				else
          128					ctx.strokeStyle = "rgb(0, 255, 0)";
          129			}
          130			function c_width(sw) {   // 線の太さの変更
          131				if (sw < 0)
          132					ctx.lineWidth = 1;
          133				else
          134					ctx.lineWidth = 5;
          135			}
          136		</SCRIPT>
          137	</HEAD>
          138	<BODY CLASS="white" STYLE="text-align: center; background-color: #ccffcc" onLoad="draw()">
          139		<H1>イベント処理(お絵かき)</H1>
          140		<DIV STYLE="width: 500px; height: 300px; background-color: #eeffee; margin-right: auto; margin-left: auto">
          141			<DIV ID="control" STYLE="text-align: center; background-color: #eeffee; width: 140px; height: 300px; float: left">
          142				<BUTTON STYLE="width: 50px" onClick="c_type(0)">曲線</BUTTON>
          143				<BUTTON STYLE="width: 50px" onClick="c_type(1)">直線</BUTTON>
          144				<BUTTON STYLE="width: 50px; background-color: #ff0000" onClick="c_color(-1)">赤</BUTTON>
          145				<BUTTON STYLE="width: 50px; background-color: #00ff00" onClick="c_color(1)">緑</BUTTON>
          146				<BUTTON STYLE="width: 50px" onClick="c_width(-1)">細い</BUTTON>
          147				<BUTTON STYLE="width: 50px" onClick="c_width(1)">太い</BUTTON>
          148			</DIV>
          149			<CANVAS ID="canvas_e" STYLE="background-color: #ffffff; float: right" WIDTH="360" HEIGHT="300" onMouseDown="m_down(event, 0)" onTouchStart="m_down(event, 1)" onMouseMove="m_move(event, 0)" onTouchMove="m_move(event, 1)" onMouseUp="m_up(event)" onTouchEnd="m_up(event)"></CANVAS>
          150		</DIV>
          151	</BODY>
          152	</HTML>
          						
          010 行目

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

          011 行目

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

          024,025 行目

            線の太さと色の初期設定

          068 行目~ 089 行目

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

          094 行目~ 109 行目

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

          120 行目~ 123 行目

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

          124 行目~ 129 行目

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

          130 行目~ 135 行目

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

        • GA のステップ実行

            ここで紹介するプログラムは,遺伝的アルゴリズム( GA )の基本的な流れを理解してもらうために,GA をステップごとに実行するものです.このプログラムでは,ビット列にある 1 の数を適応度として実行しています.従って,世代が進むほど,ビット列の中の 1 の数が増加していくはずです.2 組の親をランダムに選択して 1 点交叉を行い,淘汰方法としては,エリート選択を使用しています.

            なお,親や交叉位置の選択は,人間が行うことになりますので,できるだけ無作為に選択してみてください.1 の数が,世代毎に多くなっていくのが確認できると思います.

          001	<!DOCTYPE HTML>
          002	
          003	<HTML>
          004	<HEAD>
          005	
          006		<TITLE>遺伝的アルゴリズム</TITLE>
          007		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
          008		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          009		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
          010	
          011		<SCRIPT TYPE="text/javascript">
          012			sw  = 0;
          013			gen = 1;
          014			ch  = 5;
          015			str = new Array(9);   // 個体( 0 と 1 の並び)
          016			pi  = new Array(9);   // 各個体の適応度
          017			k1  = 0;
          018			k2  = 0;
          019			k3  = 0;
          020			k4  = 0;
          021						// 初期設定
          022			function set() {
          023				for (var i1 = 0; i1 < 10; i1++)
          024					str[i1] = "";
          025				document.getElementById("gen").innerHTML = "第 " + gen + " 世代";
          026				for (var i1 = 0; i1 < 5; i1++) {
          027					pi[i1] = 0;
          028					for (var i2 = 0; i2 < 10; i2++) {
          029						if (Math.random() < 0.5)
          030							str[i1] = str[i1] + "0";
          031						else {
          032							str[i1] = str[i1] + "1";
          033							pi[i1]++;
          034						}
          035					}
          036					document.getElementById("ind"+(i1+1)).innerHTML = "(" + (i1+1) + ") " + str[i1] + "  適合度 " + pi[i1];
          037				}
          038			}
          039						// ボタンクリック時の処理
          040			function next() {
          041								// 交叉(親の選択)
          042				if (sw == 0 || sw == 2) {
          043					if (sw == 2) {
          044						document.getElementById("ind"+k1).style.backgroundColor = "white";
          045						document.getElementById("ind"+k2).style.backgroundColor = "white";
          046						document.getElementById("ind"+k3).style.backgroundColor = "white";
          047						document.getElementById("ind"+k4).style.backgroundColor = "white";
          048					}
          049					if (document.getElementById("in1").value == "" || document.getElementById("in2").value == "")
          050						alert("親を選択してください!");
          051					else {
          052						k1 = parseInt(document.getElementById("in1").value);
          053						k2 = parseInt(document.getElementById("in2").value);
          054						if (k1 < 1 || k1 > ch || k2 < 1 || k2 > ch)
          055							alert("正しく親を選択してください!");
          056						else {
          057							sw++;
          058							document.getElementById("ind"+k1).style.backgroundColor = "cyan";
          059							document.getElementById("ind"+k2).style.backgroundColor = "cyan";
          060							document.getElementById("msg").innerHTML = "交叉位置を入力してください( 1 ~ 9 )";
          061							document.getElementById("in1").value = "";
          062							document.getElementById("in2").style.display = "none";
          063						}
          064					}
          065				}
          066								// 交叉(交叉の実行)
          067				else if (sw == 1 || sw == 3) {
          068					if (document.getElementById("in1").value == "")
          069						alert("交叉位置を入力してください!");
          070					else {
          071						var p = parseInt(document.getElementById("in1").value);
          072						if (p < 1 || p > 9)
          073							alert("正しく交叉位置を入力してください!");
          074						else {
          075							sw++;
          076							k3 = ch + 1;
          077							k4 = ch + 2;
          078							str[k3-1] = str[k1-1].substr(0, p) + str[k2-1].substr(p, 10-p);
          079							str[k4-1] = str[k2-1].substr(0, p) + str[k1-1].substr(p, 10-p);
          080							pi[k3-1] = 0;
          081							for (var i1 = 0; i1 < 10; i1++) {
          082								if (str[k3-1].charAt(i1) == "1")
          083									pi[k3-1]++;
          084							}
          085							pi[k4-1] = 0;
          086							for (var i1 = 0; i1 < 10; i1++) {
          087								if (str[k4-1].charAt(i1) == "1")
          088									pi[k4-1]++;
          089							}
          090							document.getElementById("ind"+k3).innerHTML = "(" + k3 + ") " + str[k3-1] + "  適合度 " + pi[k3-1];
          091							document.getElementById("ind"+k4).innerHTML = "(" + k4 + ") " + str[k4-1] + "  適合度 " + pi[k4-1];
          092							document.getElementById("ind"+k3).style.backgroundColor = "pink";
          093							document.getElementById("ind"+k4).style.backgroundColor = "pink";
          094							document.getElementById("ind"+k3).style.display = "";
          095							document.getElementById("ind"+k4).style.display = "";
          096										// 次の交叉
          097							if (sw == 2) {
          098								ch = 7;
          099								document.getElementById("msg").innerHTML = "親を 2 つ選んでください( 1 ~ 7 )";
          100								document.getElementById("in1").value = "";
          101								document.getElementById("in2").value = "";
          102								document.getElementById("in2").style.display = "";
          103							}
          104										// 淘汰
          105							else {
          106								document.getElementById("msg").innerHTML = "確認後,ボタンをクリックしてください(淘汰へ)";
          107								document.getElementById("in1").style.display = "none";
          108								document.getElementById("in2").style.display = "none";
          109							}
          110						}
          111					}
          112				}
          113								// 淘汰
          114				else {
          115					sw = 0;
          116					ch = 5;
          117					gen++;
          118					document.getElementById("gen").innerHTML = "第 " + gen + " 世代";
          119					str1 = new Array(9);
          120					pi1  = new Array(9);
          121					for (var i1 = 0; i1 < 9; i1++) {
          122						str1[i1] = str[i1];
          123						pi1[i1]  = pi[i1];
          124					}
          125					for (var i1 = 0; i1 < 5; i1++) {
          126						var max = -1;
          127						var k   = 0;
          128						for (var i2 = 0; i2 < 9; i2++) {
          129							if (pi1[i2] >= 0 && pi1[i2] > max) {
          130								max = pi1[i2];
          131								k   = i2;
          132							}
          133						}
          134						str[i1] = str1[k];
          135						pi[i1]  = pi1[k];
          136						pi1[k]  = -1;
          137					}
          138					for (var i1 = 0; i1 < 5; i1++) {
          139						document.getElementById("ind"+(i1+1)).innerHTML = "(" + (i1+1) + ") " + str[i1] + "  適合度 " + pi[i1];
          140						document.getElementById("ind"+(i1+1)).style.backgroundColor = "white";
          141					}
          142					for (var i1 = 5; i1 < 9; i1++) {
          143						document.getElementById("ind"+(i1+1)).style.backgroundColor = "white";
          144						document.getElementById("ind"+(i1+1)).style.display = "none";
          145					}
          146					document.getElementById("msg").innerHTML = "親を 2 つ選んでください( 1 ~ 5 )";
          147					document.getElementById("in1").value = "";
          148					document.getElementById("in2").value = "";
          149					document.getElementById("in1").style.display = "";
          150					document.getElementById("in2").style.display = "";
          151				}
          152			}
          153		</SCRIPT>
          154	
          155	</HEAD>
          156	
          157	<BODY CLASS="white" onLoad="set()">
          158	
          159		<P CLASS="center"><DIV CLASS="dotted_free" STYLE="margin-right: auto; margin-left: auto; width:400px">
          160			<DIV ID="gen" CLASS="center">第 1 世代</DIV>
          161			<P>
          162			<DIV ID="ind1" CLASS="center">(1) 0101010101  適合度 5</DIV>
          163			<P>
          164			<DIV ID="ind2" CLASS="center">(2) 0101010101  適合度 5</DIV>
          165			<P>
          166			<DIV ID="ind3" CLASS="center">(3) 0101010101  適合度 5</DIV>
          167			<P>
          168			<DIV ID="ind4" CLASS="center">(4) 0101010101  適合度 5</DIV>
          169			<P>
          170			<DIV ID="ind5" CLASS="center">(5) 0101010101  適合度 5</DIV>
          171			<P>
          172			<DIV ID="ind6" CLASS="center" STYLE="display: none">(6) 0101010101  適合度 5</DIV>
          173			<P>
          174			<DIV ID="ind7" CLASS="center" STYLE="display: none">(7) 0101010101  適合度 5</DIV>
          175			<P>
          176			<DIV ID="ind8" CLASS="center" STYLE="display: none">(8) 0101010101  適合度 5</DIV>
          177			<P>
          178			<DIV ID="ind9" CLASS="center" STYLE="display: none">(9) 0101010101  適合度 5</DIV>
          179			<P>
          180			<DIV ID="msg" CLASS="center">親を 2 つ選んでください( 1 ~ 5 )</DIV>
          181			<P CLASS="center">
          182				<INPUT ID="in1" TYPE="text" SIZE="1" STYLE="font-size: 90%" VALUE=""> 
          183				<INPUT ID="in2" TYPE="text" SIZE="1" STYLE="font-size: 90%" VALUE=""> 
          184				<BUTTON ID="ok" STYLE="font-size: 90%" onClick="next()">OK</BUTTON>
          185			</P>
          186		</DIV></P>
          187	
          188	</BODY>
          189	
          190	</HTML>
          						
          022 行目~ 038 行目

            Math オブジェクトの random() メソッドを使用して,5 個の個体と各個体の適応度( 1 の数)を計算しています.

          042 行目~ 065 行目

            2 つの親を選択してもらい,その妥当性をチェックしています.

          67 行目~ 112 行目

            交叉の実行です.1 回目の交叉の場合は,再び親を選んでもらいます.

          115 行目~ 150 行目

            淘汰を実行し,次世代に移動します.

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

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

        24 行目

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

        25 行目~ 34 行目

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

        35 行目~ 37 行目

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

        38 行目

          円の半径を 1.5 倍する.

        41 行目~ 46 行目

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

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

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

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

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

        35 行目

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

        39 行目~ 52 行目

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

        55 行目~ 68 行目

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

      3. アニメーション(描画)

          このアニメーションは,基本的に上と同じアニメーションですが,画像ファイルを使用せず,円を描いています.先のプログラムとの基本的な違いは,外部画像を読み込まず,47 行目~ 51 行目において,円を描いている点だけです.ただし,イベント処理を行う関数を,74 行目の 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
        07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
        08		<SCRIPT TYPE="text/javascript">
        09			g      = 9.8;   // y 軸方向の加速度
        10			v0     = 0;   // y 軸方向の初期速度
        11			v      = 0;   // y 軸方向の現在速度
        12			t      = 0;   // 時間の初期値
        13			h0     = 0;   // ボールの初期位置の y 座標(上が正,初期高さ)
        14			x      = 0;   // ボールの現在位置の x 座標
        15			y      = 0;   // ボールの現在位置の y 座標(上が正)
        16			sw     = 1;   // ボールの状態( 0:停止している,1:動いている)
        17			canvas = null;
        18			ctx    = 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				timerID       = setInterval('draw()', 33);
        32			}
        33						// 描画
        34			function draw() {
        35				if (x < canvas.width + 40 && sw > 0) {
        36					ctx.clearRect(0, 0, canvas.width, canvas.height);
        37					x += 1.5;
        38					t += 0.1;
        39					v  = -g * t + v0;
        40					y  = canvas.height - (-0.5 * g * t * t + v0 * t + h0);
        41					if (y >= canvas.height - 40 && v < 0) {
        42						y  = canvas.height - 40;
        43						v0 = -0.8 * v;
        44						h0 = 40;
        45						t  = 0;
        46					}
        47					ctx.strokeStyle = 'rgb(0, 255, 0)';
        48					ctx.fillStyle   = 'rgb(0, 255, 0)';
        49					ctx.beginPath();
        50					ctx.arc(x, y, 40, 0, Math.PI*2, false);
        51					ctx.fill();
        52				}
        53			}
        54						// クリックイベント
        55			function Click(event)
        56			{
        57				let x_now = event.pageX - x_base;
        58				let y_now = event.pageY - y_base;
        59				let x1    = x - x_now;
        60				let y1    = y - y_now;
        61				let r     = Math.sqrt(x1 * x1 + y1 * y1);
        62				if (r < 40) {
        63					if (sw > 0)
        64						sw = 0;
        65					else
        66						sw = 1;
        67				}
        68			}
        69		</SCRIPT>
        70		</HEAD>
        71	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
        72		<H1>アニメーション+イベント処理</H1>
        73		<H3>(円をクリックすると止まり,再度クリックすると動き出す)</H3>
        74		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="600" HEIGHT="400" onClick="Click(event)"></CANVAS>
        75	</BODY>
        76	</HTML>
        					

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

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

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

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

        034 行目

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

        038 行目

          キャンバス画面のクリア

        039 行目~ 110 行目

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

        111 行目

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

        112 行目~ 114 行目

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

      5. ピクセル値の操作

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

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

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

        25 行目~ 33 行目

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

        34 行目~ 42 行目

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

        47 行目

          キャンバスをクリア.

        48 行目

          ImageData オブジェクトを描画

        49 行目~ 51 行目

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

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

        025 行目~ 067 行目

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

        074 行目

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

        080 行目

          キャンバスをクリア

        081 行目

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

        084 行目~ 100 行目

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

        101 行目~ 106 行目

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

        109 行目~ 111 行目

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

        114 行目~ 124 行目

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

        135 行目~ 147 行目

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

        149 行目~ 232 行目

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

        234 行目

          次の角度(方位)

        239 行目

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

        241 行目

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

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

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

          39 行目~ 42 行目

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

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

            ターゲットの速度

          17 行目

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

          38 行目~ 47 行目

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

          51 行目~ 55 行目

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

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

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

          19 行目

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

          44 行目~ 47 行目

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

          51 行目~ 56 行目

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

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

          67 行目

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

          80 行目

            線の色を黒に設定

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

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

          020 行目

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

          054 行目~ 066 行目

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

          097 行目~ 098 行目

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

          116 行目~ 126 行目

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

          129 行目

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

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

          30 行目~ 34 行目

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

          36 行目~ 39 行目

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

          40 行目

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

          49 行目~ 62 行目

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

          63 行目~ 65 行目

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

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

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

          052 行目~ 063 行目

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

          068 行目~ 079 行目

            ゲームオーバーになったときの処理である.
          • 068 行目~ 069 行目: ピース表示領域を白い矩形で塗りつぶす
          • 070 行目~ 071 行目: 文字色とフォントの設定
          • 072 行目~ 079 行目: 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		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
          007		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../../master.css">
          008		<SCRIPT TYPE="text/javascript">
          009			canvas = null;
          010			ctx    = null;
          011			p      = new Array();   // ピースの色(0の時は存在しない)
          012			row    = 12;   // 行の数
          013			col    = 5;   // 列の数
          014			p_x    = -1;   // 動いているピースの位置(列)
          015			p_y    = -1;   // 動いているピースの位置(行)
          016			p_wh   = 30;   // ピースの幅と高さ
          017			game   = true;   // ゲーム中か否か
          018						//
          019						// 開始
          020						//
          021			function start()
          022			{
          023				canvas        = document.getElementById('canvas_e');
          024				canvas.width  = 270;   // キャンバス要素の幅
          025				canvas.height = 380;   // キャンバス要素の高さ
          026				ctx           = canvas.getContext('2d');   // キャンバスからコンテキストを取得
          027				ctx.fillStyle = 'rgb(255, 255, 255)';
          028				ctx.fillRect(10, 10, p_wh*col, p_wh*row);
          029								// ピースの配置
          030				for (let i1 = 0; i1 < row; i1++) {
          031					p[i1] = new Array();
          032					for (let i2 = 0; i2 < col; i2++)
          033						p[i1][i2] = 0;
          034				}
          035								// ピースの選択
          036				select();
          037	
          038				timerID = setInterval('draw()', 500);
          039			}
          040						//
          041						// 一定時間毎の処理
          042						//
          043			function draw()
          044			{
          045								// ゲーム中
          046				if (game) {
          047										// ピースの落下
          048					if (p_y < row-1) {
          049						p[p_y+1][p_x]   = p[p_y][p_x];
          050						p[p_y+1][p_x+1] = p[p_y][p_x+1];
          051						p[p_y][p_x]     = 0;
          052						p[p_y][p_x+1]   = 0;
          053						let kx = 10 + p_wh * p_x;
          054						let ky = 10 + p_wh * p_y;
          055						ctx.fillStyle  = 'rgb(255, 255, 255)';
          056						ctx.fillRect(kx, ky, p_wh, p_wh);
          057						kx = 10 + p_wh * (p_x + 1);
          058						ctx.fillRect(kx, ky, p_wh, p_wh);
          059						p_y++;
          060						piece();
          061					}
          062					else
          063						select();
          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			{
          086				for (let i1 = 0; i1 < row; i1++) {
          087					for (let i2 = 0; i2 < col; i2++) {
          088						if (p[i1][i2] > 0) {
          089							switch (p[i1][i2]) {
          090								case 1:
          091									ctx.fillStyle  = 'rgb(255, 0, 0)';
          092									break;
          093								case 2:
          094									ctx.fillStyle  = 'rgb(255, 215, 0)';
          095									break;
          096								case 3:
          097									ctx.fillStyle  = 'rgb(0, 255, 255)';
          098									break;
          099								case 4:
          100									ctx.fillStyle  = 'rgb(173, 255, 47)';
          101									break;
          102							}
          103							let kx = 10 + p_wh * i2;
          104							let ky = 10 + p_wh * i1;
          105							ctx.fillRect(kx, ky, p_wh, p_wh);
          106						}
          107					}
          108				}
          109			}
          110						//
          111						// ピースの選択
          112						//
          113			function select()
          114			{
          115				p_y = 0;
          116				p_x = Math.floor(Math.random() * (col - 1));
          117				if (p_x > col-2)
          118					p_x = col - 2;
          119	
          120				let color = Math.floor(Math.random() * 4) + 1;
          121				if (color > 4)
          122					color = 4;
          123				p[0][p_x] = color;
          124				color = Math.floor(Math.random() * 4) + 1;
          125				if (color > 4)
          126					color = 4;
          127				p[0][p_x+1] = color;
          128	
          129				piece();
          130			}
          131		</SCRIPT>
          132	</HEAD>
          133	<BODY CLASS="white" STYLE="text-align: center" onLoad="start()">
          134		<H2 STYLE="text-align: center">ぷよぷよ風ゲーム(ステップ3)</H2>
          135		<CANVAS ID="canvas_e" STYLE="background-color: #eeffee;" WIDTH="270" HEIGHT="380"></CANVAS>
          136	</BODY>
          137	</HTML>
          						
          036 行目

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

          062 行目~ 063 行目

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

          115 行目~ 118 行目

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

          120 行目~ 127 行目

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

          129 行目

            ピースの描画

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

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

          115 行目~ 125 行目

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

          126 行目~ 139 行目

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

          142 行目~ 172 行目

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

          173 行目~ 185 行目

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

          186 行目~ 211 行目

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

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

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

          073 行目

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

          074 行目~ 084 行目

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

          085 行目~ 096 行目

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

          100 行目~ 110 行目

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

          118 行目~ 131 行目

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

          300 行目,310 行目~ 311 行目

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

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

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

          138 行目~ 159 行目

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

          342 行目~ 364 行目

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

          371 行目~ 381 行目

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

          383 行目~ 410 行目

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

    4. グラフの描画

        データベースを検索した結果など,ネット上で得られた結果を即座に表やグラフで表したい場合がしばしば発生します.以下に示すファイル graph.js 内に定義してある関数は,そのような目的で作成されています.この中で,多くのグローバル変数が使用されていますので,クラスまたはオブジェクトを使用して書き直した方が良いかと思います.

      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];
      }
      				

        グラフの表示例は,上に述べた関数を使用してどのようなグラフを描けるのか,また,どのような機能が存在するのかを示すためのものです.graph.htm においてグラフの選択とそのグラフを描画するために必要なデータを作成した後,そのデータをパラメータとして graph_js.htm に渡し,上記の関数を利用してグラフを描画しています.なお,グラフを描くために必要なデータは,適当に設定されたものであり,データそのものには全く意味がありません.

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

      --- graph.htm ---

      <!DOCTYPE HTML>
      <HTML>
      <HEAD>
      	<TITLE>グラフの表示例</TITLE>
      	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      	<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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "棒グラフ", "width=950, height=700");
      			}
      					// 折れ線グラフ(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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "折れ線グラフ(1)", "width=950, height=700");
      			}
      					// 折れ線グラフ(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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "折れ線グラフ(2)", "width=950, height=700");
      			}
      					// 積み上げ棒グラフ
      			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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "積み上げ棒グラフ", "width=950, height=700");
      			}
      					// 円グラフ
      			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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "円グラフ", "width=950, height=700");
      			}
      					// 散布図
      			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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "散布図", "width=950, height=700");
      			}
      					// レーダーチャート
      			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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "レーダーチャート", "width=950, height=700");
      			}
      					// ボード線図(片対数グラフ)
      			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";
      				str = "graph_js.htm?gp=" + gp;
      				open(str, "ボード線図(片対数グラフ)", "width=950, height=700");
      			}
      		}
      	</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>
      </BODY>
      </HTML>
      				

      --- graph_js.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 GetParameter()
      		{
      			let result = new Array();
      			if(1 < window.location.search.length) {
      							// 最初の1文字 (?記号) を除いた文字列を取得する
      				let str = window.location.search.substring(1);
      							// 区切り記号 (&) で文字列を配列に分割する
      				let param = str.split('&');
      				for(let i1 = 0; i1 < param.length; i1++ ) {
      							// パラメータ名とパラメータ値に分割する
      					let element = param[i1].split('=');
      					let Name = decodeURIComponent(element[0]);
      					let Value = decodeURIComponent(element[1]);
      							// パラメータ名をキーとして連想配列に追加する
      					result[Name] = Value;
      				}
      			}
      			return result;
      		}
      	</SCRIPT>
      </HEAD>
      <BODY CLASS="white" STYLE="text-align: center">
      	<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>
      	<SCRIPT TYPE="text/javascript">
      		let result = GetParameter();
      		graph(result['gp']);
      	</SCRIPT>
      </BODY>
      </HTML>
      				

情報学部 菅沼ホーム 目次 索引