この記事では、JavaScript (JS) コードと ATS コードを組み合わせた例を紹介します。この実装は私にとって、改良を基本としたプログラミングを主張するための良い機会にもなりました。
次のコードは、典型的なアニメーションの実装です。
// extern fun drawAnim(): void extern fun drawAnim_init(): void extern fun drawAnim_loop(): void extern fun drawFrame (): void // implement drawAnim() = { val () = drawAnim_init () val () = drawAnim_loop () } implement drawAnim_loop() = { val () = drawFrame () val () = sleep (1(*sec*)) // HX: this needs to be fixed val () = drawAnim_loop () } //
このコードの内容は次のようなものです: [drawAnim] はアニメーションの実行を実行するのに呼び出されるメイン関数です。この関数はなんらかの初期化を行なう [drawAnim_init] を呼び出し、その後 [drawAnim_loop] を呼び出します。この [drawAnim_loop] は、[drawFrame] を呼び出してフレーム描画し、[sleep] を呼び出してスリープした後、ループします。
けれども、[drawAnim_loop] 中での [sleep] 呼び出しには問題があります。Web ブラウザの中でアニメーションを動作させたいとすると、もしサポートされていれば [sleep] 呼び出しは Web ブラウザ全体を停止させてしまうことを意味します。このような実装は許容できないでしょう。その代わりに、[drawAnim_loop] を次のように実装できます:
// implement drawAnim_loop() = { val () = drawFrame () val () = $extfcall (void, "setTimeout", drawAnim_loop, 1000(*ms*)) } //
本質的に、JS における外部関数 [setTimeout] 呼び出しは、1000 ミリ秒 (つまり 1 秒) 後にその呼び出しをスケジュールするように Web ブラウザに要求します。
上記のアニメーションを具体例を読者に理解してもらうために、次のような JS を使った [drawFrame] の単純な実装を示します:
%{$ // var canvas = document.getElementById ("Patsoptaas-Evaluate-canvas"); // var ctx2d = canvas.getContext( '2d' ); // var theToggle = 0 // function drawFrame() { var w = canvas.width; var h = canvas.height; if (theToggle) ctx2d.fillStyle = "#ffff00"; // yellow if (!theToggle) ctx2d.fillStyle = "#0000ff"; // blue theToggle = 1 - theToggle; ctx2d.rect(0, 0, w, h); ctx2d.fill(); } // jQuery(document).ready(function(){drawAnim();}); // %} // end of [%{$] //
ここでは JS コードの詳細を解説しません。 このコードは本質的に、文字列 "Patsoptaas-Evaluate-canvas" によって指定されたキャンバスを配置します。 [drawFrame] の実装は、キャンバス全体に青色と黄色を交互に描画します。 これまで示したコードの全体は Sierpinski-3angle-part.dats から入手できます。 このコードは オンライン ですぐにテストできます。
読者は、シェルピンスキーの三角形の描画アニメーションを オンライン で確認できます。
1つの自然数が与えられたとき、レベル n のシェルピンスキーの三角形は n における帰納的に定義できます。レベル 0 のシェルピンスキーの三角形は1つの正三角形です。正の数 n において、APR, PBQ, PQC の3つの三角形がレベル n-1 のシェルピンスキーの三角形ならば、三角形 ABC はレベル n におけるシェルピンスキーの三角形です。このとき、P, Q, R はそれぞれ、3辺 AB, BC, CA の中点です。
色を表わす抽象型 [color] と、JS において同様の名前で定義された2つの色を表わす [BLUE] と [YELLOW] を導入しましょう。
// abstype color // macdef BLUE = $extval(color, "BLUE") macdef YELLOW = $extval(color, "YELLOW") //
次のコードは、与えられた色で塗り潰された三角形 ABC を描画するために呼び出される関数 [drawTriangle] のインターフェイスです:
// extern fun drawTriangle ( c: color // color for filling , Ax: double, Ay: double // x-y-coordinates for A , Bx: double, By: double // x-y-coordinates for B , Cx: double, Cy: double // x-y-coordinates for C ) : void = "mac#" //
与えられば色でシェルピンスキーの三角形を描画する別の関数 [drawSTriangle] を導入しましょう。この関数を [drawTriangle] を使って実装します:
// extern fun drawSTriangle ( c: color , Ax: double, Ay: double // x-y-coordinates for A , Bx: double, By: double // x-y-coordinates for B , Cx: double, Cy: double // x-y-coordinates for C , level: int ) : void = "mac#" // implement drawSTriangle ( c, Ax, Ay, Bx, By, Cx, Cy, level ) = ( // if level > 0 then let val Px = (Ax + Bx) / 2 and Py = (Ay + By) / 2 val Qx = (Bx + Cx) / 2 and Qy = (By + Cy) / 2 val Rx = (Cx + Ax) / 2 and Ry = (Cy + Ay) / 2 // val () = drawTriangle (c, Px, Py, Qx, Qy, Rx, Ry) // val level1 = level - 1 val () = drawSTriangle (c, Ax, Ay, Px, Py, Rx, Ry, level1) val () = drawSTriangle (c, Px, Py, Bx, By, Qx, Qy, level1) val () = drawSTriangle (c, Rx, Ry, Qx, Qy, Cx, Cy, level1) in // nothing end // end of [then] else () // end of [else] // ) (* end of [drawSTriangle] *) //
関数 [drawFrame] は次のように実装できます:
// local // extern fun theLevel_getinc(): int = "mac#" // in // implement drawFrame () = { // val Ax = theAx_get() // x-coordinate of A val Ay = theAy_get() // y-coordinate of A val Bx = theBx_get() // x-coordinate of B val By = theBy_get() // y-coordinate of B val Cx = theCx_get() // x-coordinate of C val Cy = theCy_get() // y-coordinate of C // val level = theLevel_getinc () val ((*void*)) = drawTriangle (BLUE, Ax, Ay, Bx, By, Cx, Cy) val ((*void*)) = drawSTriangle (YELLOW, Ax, Ay, Bx, By, Cx, Cy, level) // } (* end of [drawFrame] *) // end // end of [local] //
描画するキャンバスを配置した後、そのキャンバス上にシェルピンスキーの三角形の頂点となる3つの点 A, B, C が選ばれます。JS で実装された [theAx_get] と [theAy_get] を呼び出すことで、A の xy 座標を取得できます。B と C の xy 座標についても同様に取得できます。関数 [theLevel_getinc] を使って、描画されるべきシェルピンスキーの三角形のレベルを得ます。[drawTriangle] の実装を含む JS コード側の詳細については次を見てください:
// %{$ // var canvas = document.getElementById ("Patsoptaas-Evaluate-canvas"); var ctx2d = canvas.getContext( '2d' ); // function theAx_get() { return 0; } function theAy_get() { return canvas.height; } function theBx_get() { return canvas.width/2; } function theBy_get() { return 0; } function theCx_get() { return canvas.width; } function theCy_get() { return canvas.height; } // var theLevel = 0; function theLevel_getinc() { var level = theLevel; theLevel = (level+1)%7; return level; } // function drawTriangle ( color, Ax, Ay, Bx, By, Cx, Cy ) { ctx2d.beginPath(); ctx2d.moveTo(Ax, Ay); ctx2d.lineTo(Bx, By); ctx2d.lineTo(Cx, Cy); ctx2d.closePath(); ctx2d.fillStyle = color; ctx2d.fill(); return; } // jQuery(document).ready(function(){drawAnim();}); // %} // end of [%{$] //
このシェルピンスキーの三角形のアニメーション描画実装のコード全体は Sierpinski-3angle-final.dats から入手でき、また オンライン 上で容易にテストできます。 もちろん、Sierpinski-3angle-final.dats をなんらかのC言語コードにコンパイルするために patsopt を使うこともできます。 その後、atscc2js を使って、そのC言語コードを JS コードにコンパイルすることもできます。 このコンパイル手順詳細は Makefile から知ることができます。 生成された JS コードは Sierpinski-3angle.html から入手できます。