Home | History | Annotate | Download | only in Intersection
      1 <html>
      2 <head>
      3 <div style="height:0">
      4 
      5 <div id="cubic1">
      6 {{3.13,2.74}, {1.08,4.62}, {3.71,0.94}, {2.01,3.81}} 
      7 {{6.71,3.14}, {7.99,2.75}, {8.27,1.96}, {6.35,3.57}} 
      8 {{9.45,10.67}, {10.05,5.78}, {13.95,7.46}, {14.72,5.29}} 
      9 {{3.34,8.98}, {1.95,10.27}, {3.76,7.65}, {4.96,10.64}} 
     10 </div>
     11 
     12 </div>
     13 
     14 <script type="text/javascript">
     15 
     16 var testDivs = [
     17     cubic1,
     18 ];
     19 
     20 var scale, columns, rows, xStart, yStart;
     21 
     22 var ticks = 10;
     23 var at_x = 13 + 0.5;
     24 var at_y = 23 + 0.5;
     25 var decimal_places = 3;
     26 var tests = [];
     27 var testTitles = [];
     28 var testIndex = 0;
     29 var ctx;
     30 var minScale = 1;
     31 var subscale = 1;
     32 var curveT = -1;
     33 var xmin, xmax, ymin, ymax;
     34 
     35 var mouseX, mouseY;
     36 var mouseDown = false;
     37 
     38 var draw_deriviatives = false;
     39 var draw_endpoints = true;
     40 var draw_hodo = false;
     41 var draw_hodo2 = false;
     42 var draw_hodo_origin = true;
     43 var draw_midpoint = false;
     44 var draw_tangents = true;
     45 var draw_sequence = true;
     46 
     47 function parse(test, title) {
     48     var curveStrs = test.split("{{");
     49     if (curveStrs.length == 1)
     50         curveStrs = test.split("=(");
     51     var pattern = /[a-z$=]?-?\d+\.*\d*e?-?\d*/g;
     52     var curves = [];
     53     for (var c in curveStrs) {
     54         var curveStr = curveStrs[c];
     55         var points = curveStr.match(pattern);
     56         var pts = [];
     57         for (var wd in points) {
     58             var num = parseFloat(points[wd]);
     59             if (isNaN(num)) continue;
     60             pts.push(num);
     61         }
     62         if (pts.length > 2)
     63             curves.push(pts);
     64     }
     65     if (curves.length >= 1) {
     66         tests.push(curves);
     67         testTitles.push(title);
     68     }
     69 }
     70 
     71 function init(test) {
     72     var canvas = document.getElementById('canvas');
     73     if (!canvas.getContext) return;
     74     canvas.width = window.innerWidth - 20;
     75     canvas.height = window.innerHeight - 20;
     76     ctx = canvas.getContext('2d');
     77     xmin = Infinity;
     78     xmax = -Infinity;
     79     ymin = Infinity;
     80     ymax = -Infinity;
     81     for (var curves in test) {
     82         var curve = test[curves];
     83         var last = curve.length;
     84         for (var idx = 0; idx < last; idx += 2) {
     85             xmin = Math.min(xmin, curve[idx]);
     86             xmax = Math.max(xmax, curve[idx]);
     87             ymin = Math.min(ymin, curve[idx + 1]);
     88             ymax = Math.max(ymax, curve[idx + 1]);
     89         }
     90     }
     91     xmin -= 1;
     92     var testW = xmax - xmin;
     93     var testH = ymax - ymin;
     94     subscale = 1;
     95     while (testW * subscale < 0.1 && testH * subscale < 0.1) {
     96         subscale *= 10;
     97     }
     98     while (testW * subscale > 10 && testH * subscale > 10) {
     99         subscale /= 10;
    100     }
    101     calcFromScale();
    102 }
    103 
    104 function hodograph(cubic) {
    105     var hodo = [];
    106     hodo[0] = 3 * (cubic[2] - cubic[0]);
    107     hodo[1] = 3 * (cubic[3] - cubic[1]);
    108     hodo[2] = 3 * (cubic[4] - cubic[2]);
    109     hodo[3] = 3 * (cubic[5] - cubic[3]);
    110     hodo[4] = 3 * (cubic[6] - cubic[4]);
    111     hodo[5] = 3 * (cubic[7] - cubic[5]);
    112     return hodo;
    113 }
    114 
    115 function hodograph2(cubic) {
    116     var quad = hodograph(cubic);
    117     var hodo = [];
    118     hodo[0] = 2 * (quad[2] - quad[0]);
    119     hodo[1] = 2 * (quad[3] - quad[1]);
    120     hodo[2] = 2 * (quad[4] - quad[2]);
    121     hodo[3] = 2 * (quad[5] - quad[3]);
    122     return hodo;
    123 }
    124 
    125 function quadraticRootsReal(A, B, C, s) {
    126     if (A == 0) {
    127         if (B == 0) {
    128             s[0] = 0;
    129             return C == 0;
    130         }
    131         s[0] = -C / B;
    132         return 1;
    133     }
    134     /* normal form: x^2 + px + q = 0 */
    135     var p = B / (2 * A);
    136     var q = C / A;
    137     var p2 = p * p;
    138     if (p2 < q) {
    139         return 0;
    140     }
    141     var sqrt_D = 0;
    142     if (p2 > q) {
    143         sqrt_D = sqrt(p2 - q);
    144     }
    145     s[0] = sqrt_D - p;
    146     s[1] = -sqrt_D - p;
    147     return 1 + s[0] != s[1];
    148 }
    149 
    150 function add_valid_ts(s, realRoots, t) {
    151     var foundRoots = 0;
    152     for (var index = 0; index < realRoots; ++index) {
    153         var tValue = s[index];
    154         if (tValue >= 0 && tValue <= 1) {
    155             for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
    156                 if (t[idx2] != tValue) {
    157                     t[foundRoots++] = tValue;
    158                 }
    159             }
    160         }
    161     }
    162     return foundRoots;
    163 }
    164 
    165 function quadraticRootsValidT(a, b, c, t) {
    166     var s = [];
    167     var realRoots = quadraticRootsReal(A, B, C, s);
    168     var foundRoots = add_valid_ts(s, realRoots, t);
    169     return foundRoots != 0;
    170 }
    171 
    172 function find_cubic_inflections(cubic, tValues)
    173 {
    174     var Ax = src[2] - src[0];
    175     var Ay = src[3] - src[1];
    176     var Bx = src[4] - 2 * src[2] + src[0];
    177     var By = src[5] - 2 * src[3] + src[1];
    178     var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
    179     var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
    180     return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
    181             Ax * By - Ay * Bx, tValues);
    182 }
    183 
    184 function dx_at_t(cubic, t) {
    185     var one_t = 1 - t;
    186     var a = cubic[0];
    187     var b = cubic[2];
    188     var c = cubic[4];
    189     var d = cubic[6];
    190     return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
    191 }
    192 
    193 function dy_at_t(cubic, t) {
    194     var one_t = 1 - t;
    195     var a = cubic[1];
    196     var b = cubic[3];
    197     var c = cubic[5];
    198     var d = cubic[7];
    199     return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
    200 }
    201 
    202 function x_at_t(cubic, t) {
    203     var one_t = 1 - t;
    204     var one_t2 = one_t * one_t;
    205     var a = one_t2 * one_t;
    206     var b = 3 * one_t2 * t;
    207     var t2 = t * t;
    208     var c = 3 * one_t * t2;
    209     var d = t2 * t;
    210     return a * cubic[0] + b * cubic[2] + c * cubic[4] + d * cubic[6];
    211 }
    212 
    213 function y_at_t(cubic, t) {
    214     var one_t = 1 - t;
    215     var one_t2 = one_t * one_t;
    216     var a = one_t2 * one_t;
    217     var b = 3 * one_t2 * t;
    218     var t2 = t * t;
    219     var c = 3 * one_t * t2;
    220     var d = t2 * t;
    221     return a * cubic[1] + b * cubic[3] + c * cubic[5] + d * cubic[7];
    222 }
    223 
    224 function calcFromScale() {
    225     xStart = Math.floor(xmin * subscale) / subscale;
    226     yStart = Math.floor(ymin * subscale) / subscale;
    227     var xEnd = Math.ceil(xmin * subscale) / subscale;
    228     var yEnd = Math.ceil(ymin * subscale) / subscale;
    229     var cCelsW = Math.floor(ctx.canvas.width / 10);
    230     var cCelsH = Math.floor(ctx.canvas.height / 10);
    231     var testW = xEnd - xStart;
    232     var testH = yEnd - yStart; 
    233     var scaleWH = 1;
    234     while (cCelsW > testW * scaleWH * 10 && cCelsH > testH * scaleWH * 10) {
    235         scaleWH *= 10;
    236     }
    237     while (cCelsW * 10 < testW * scaleWH && cCelsH * 10 < testH * scaleWH) {
    238         scaleWH /= 10;
    239     }
    240     
    241     columns = Math.ceil(xmax * subscale) - Math.floor(xmin * subscale) + 1;
    242     rows = Math.ceil(ymax * subscale) - Math.floor(ymin * subscale) + 1;
    243     
    244     var hscale = ctx.canvas.width / columns / ticks;
    245     var vscale = ctx.canvas.height / rows / ticks;
    246     minScale = Math.floor(Math.min(hscale, vscale));
    247     scale = minScale * subscale;
    248 }
    249 
    250 function drawLine(x1, y1, x2, y2) {
    251     var unit = scale * ticks;
    252     var xoffset = xStart * -unit + at_x;
    253     var yoffset = yStart * -unit + at_y;
    254     ctx.beginPath();
    255     ctx.moveTo(xoffset + x1 * unit, yoffset + y1 * unit);
    256     ctx.lineTo(xoffset + x2 * unit, yoffset + y2 * unit);
    257     ctx.stroke();
    258 }
    259 
    260 function drawPoint(px, py) {
    261     var unit = scale * ticks;
    262     var xoffset = xStart * -unit + at_x;
    263     var yoffset = yStart * -unit + at_y;
    264     var _px = px * unit + xoffset;
    265     var _py = py * unit + yoffset;
    266     ctx.beginPath();
    267     ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
    268     ctx.closePath();
    269     ctx.stroke();
    270 }
    271 
    272 function drawPointSolid(px, py) {
    273     drawPoint(px, py);
    274     ctx.fillStyle = "rgba(0,0,0, 0.4)";
    275     ctx.fill();
    276 }
    277 
    278 function drawLabel(num, px, py) {
    279     ctx.beginPath();
    280     ctx.arc(px, py, 8, 0, Math.PI*2, true);
    281     ctx.closePath();
    282     ctx.strokeStyle = "rgba(0,0,0, 0.4)";
    283     ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
    284     ctx.stroke();
    285     ctx.fillStyle = "black";
    286     ctx.font = "normal 10px Arial";
    287   //  ctx.rotate(0.001);
    288     ctx.fillText(num, px - 2, py + 3);
    289   //  ctx.rotate(-0.001);
    290 }
    291 
    292 function drawLabelX(ymin, num, loc) {
    293     var unit = scale * ticks;
    294     var xoffset = xStart * -unit + at_x;
    295     var yoffset = yStart * -unit + at_y;
    296     var px = loc * unit + xoffset;
    297     var py = ymin * unit + yoffset  - 20;
    298     drawLabel(num, px, py);
    299 }
    300 
    301 function drawLabelY(xmin, num, loc) {
    302     var unit = scale * ticks;
    303     var xoffset = xStart * -unit + at_x;
    304     var yoffset = yStart * -unit + at_y;
    305     var px = xmin * unit + xoffset - 20;
    306     var py = loc * unit + yoffset;
    307     drawLabel(num, px, py);
    308 }
    309 
    310 function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
    311     ctx.beginPath();
    312     ctx.moveTo(hx, hy - 100);
    313     ctx.lineTo(hx, hy);
    314     ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
    315     ctx.stroke();
    316     ctx.beginPath();
    317     ctx.moveTo(hx, hy);
    318     ctx.lineTo(hx, hy + 100);
    319     ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
    320     ctx.stroke();
    321     ctx.beginPath();
    322     ctx.moveTo(hx - 100, hy);
    323     ctx.lineTo(hx, hy);
    324     ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
    325     ctx.stroke();
    326     ctx.beginPath();
    327     ctx.moveTo(hx, hy);
    328     ctx.lineTo(hx + 100, hy);
    329     ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
    330     ctx.stroke();
    331 }
    332 
    333 function logCurves(test) {
    334     for (curves in test) {
    335         var curve = test[curves];
    336         if (curve.length != 8) {
    337             continue;
    338         }
    339         var str = "{{";
    340         for (i = 0; i < 8; i += 2) {
    341             str += curve[i].toFixed(2) + "," + curve[i + 1].toFixed(2);
    342             if (i < 6) {
    343                 str += "}, {";
    344             }
    345         }
    346         str += "}}";
    347         console.log(str);
    348     }
    349 }
    350 
    351 function scalexy(x, y, mag) {
    352     var length = Math.sqrt(x * x + y * y);
    353     return mag / length;
    354 }
    355 
    356 function drawArrow(x, y, dx, dy) {
    357     var unit = scale * ticks;
    358     var xoffset = xStart * -unit + at_x;
    359     var yoffset = yStart * -unit + at_y;
    360     var dscale = scalexy(dx, dy, 1);
    361     dx *= dscale;
    362     dy *= dscale;
    363     ctx.beginPath();
    364     ctx.moveTo(xoffset + x * unit, yoffset + y * unit);
    365     x += dx;
    366     y += dy;
    367     ctx.lineTo(xoffset + x * unit, yoffset + y * unit);
    368     dx /= 10;
    369     dy /= 10;
    370     ctx.lineTo(xoffset + (x - dy) * unit, yoffset + (y + dx) * unit);
    371     ctx.lineTo(xoffset + (x + dx * 2) * unit, yoffset + (y + dy * 2) * unit);
    372     ctx.lineTo(xoffset + (x + dy) * unit, yoffset + (y - dx) * unit);
    373     ctx.lineTo(xoffset + x * unit, yoffset + y * unit);
    374     ctx.strokeStyle = "rgba(0,75,0, 0.4)";
    375     ctx.stroke();
    376 }
    377 
    378 function draw(test, title) {
    379     ctx.fillStyle = "rgba(0,0,0, 0.1)";
    380     ctx.font = "normal 50px Arial";
    381     ctx.fillText(title, 50, 50);
    382     ctx.font = "normal 10px Arial";
    383     var unit = scale * ticks;
    384   //  ctx.lineWidth = "1.001"; "0.999";
    385     var xoffset = xStart * -unit + at_x;
    386     var yoffset = yStart * -unit + at_y;
    387 
    388     for (curves in test) {
    389         var curve = test[curves];
    390         if (curve.length != 8) {
    391             continue;
    392         }
    393         ctx.lineWidth = 1;
    394         if (draw_tangents) {
    395             ctx.strokeStyle = "rgba(0,0,255, 0.3)";
    396             drawLine(curve[0], curve[1], curve[2], curve[3]);
    397             drawLine(curve[2], curve[3], curve[4], curve[5]);
    398             drawLine(curve[4], curve[5], curve[6], curve[7]);
    399         }
    400         if (draw_deriviatives) {
    401             var dx = dx_at_t(curve, 0);
    402             var dy = dy_at_t(curve, 0);
    403             drawArrow(curve[0], curve[1], dx, dy);
    404             dx = dx_at_t(curve, 1);
    405             dy = dy_at_t(curve, 1);
    406             drawArrow(curve[6], curve[7], dx, dy);
    407             if (draw_midpoint) {
    408                 var midX = x_at_t(curve, 0.5);
    409                 var midY = y_at_t(curve, 0.5);
    410                 dx = dx_at_t(curve, 0.5);
    411                 dy = dy_at_t(curve, 0.5);
    412                 drawArrow(midX, midY, dx, dy);
    413             }
    414         }
    415         ctx.beginPath();
    416         ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit);
    417         ctx.bezierCurveTo(
    418             xoffset + curve[2] * unit, yoffset + curve[3] * unit,
    419             xoffset + curve[4] * unit, yoffset + curve[5] * unit,
    420             xoffset + curve[6] * unit, yoffset + curve[7] * unit);
    421         ctx.strokeStyle = "black";
    422         ctx.stroke();
    423         if (draw_endpoints) {
    424             drawPoint(curve[0], curve[1]);
    425             drawPoint(curve[2], curve[3]);
    426             drawPoint(curve[4], curve[5]);
    427             drawPoint(curve[6], curve[7]);
    428         }
    429         if (draw_midpoint) {
    430             var midX = x_at_t(curve, 0.5);
    431             var midY = y_at_t(curve, 0.5);
    432             drawPointSolid(midX, midY);
    433         }
    434         if (draw_hodo) {
    435             var hodo = hodograph(curve);
    436             var hMinX = Math.min(0, hodo[0], hodo[2], hodo[4]);
    437             var hMinY = Math.min(0, hodo[1], hodo[3], hodo[5]);
    438             var hMaxX = Math.max(0, hodo[0], hodo[2], hodo[4]);
    439             var hMaxY = Math.max(0, hodo[1], hodo[3], hodo[5]);
    440             var hScaleX = hMaxX - hMinX > 0 ? ctx.canvas.width / (hMaxX - hMinX) : 1;
    441             var hScaleY = hMaxY - hMinY > 0 ? ctx.canvas.height / (hMaxY - hMinY) : 1;
    442             var hUnit = Math.min(hScaleX, hScaleY);
    443             hUnit /= 2;
    444             var hx = xoffset - hMinX * hUnit;
    445             var hy = yoffset - hMinY * hUnit;
    446             ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
    447             ctx.quadraticCurveTo(
    448                 hx + hodo[2] * hUnit, hy + hodo[3] * hUnit,
    449                 hx + hodo[4] * hUnit, hy + hodo[5] * hUnit);
    450             ctx.strokeStyle = "red";
    451             ctx.stroke();
    452             if (draw_hodo_origin) {
    453                 drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
    454             }
    455         }
    456         if (draw_hodo2) {
    457             var hodo = hodograph2(curve);
    458             var hMinX = Math.min(0, hodo[0], hodo[2]);
    459             var hMinY = Math.min(0, hodo[1], hodo[3]);
    460             var hMaxX = Math.max(0, hodo[0], hodo[2]);
    461             var hMaxY = Math.max(0, hodo[1], hodo[3]);
    462             var hScaleX = hMaxX - hMinX > 0 ? ctx.canvas.width / (hMaxX - hMinX) : 1;
    463             var hScaleY = hMaxY - hMinY > 0 ? ctx.canvas.height / (hMaxY - hMinY) : 1;
    464             var hUnit = Math.min(hScaleX, hScaleY);
    465             hUnit /= 2;
    466             var hx = xoffset - hMinX * hUnit;
    467             var hy = yoffset - hMinY * hUnit;
    468             ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
    469             ctx.lineTo(hx + hodo[2] * hUnit, hy + hodo[3] * hUnit);
    470             ctx.strokeStyle = "red";
    471             ctx.stroke();
    472             drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
    473         }
    474         if (draw_sequence) {
    475             var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
    476             for (var i = 0; i < 8; i+= 2) {
    477                 drawLabelX(ymin, i >> 1, curve[i]);
    478             }
    479             var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
    480             for (var i = 1; i < 8; i+= 2) {
    481                 drawLabelY(xmin, i >> 1, curve[i]);
    482             }
    483         }
    484     }
    485 }
    486 
    487 function drawTop() {
    488     init(tests[testIndex]);
    489     redraw();
    490 }
    491 
    492 function redraw() {
    493     ctx.beginPath();
    494     ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
    495     ctx.fillStyle="white";
    496     ctx.fill();
    497     draw(tests[testIndex], testTitles[testIndex]);
    498 }
    499 
    500 function doKeyPress(evt) {
    501     var char = String.fromCharCode(evt.charCode);
    502     switch (char) {
    503     case '2':
    504         draw_hodo2 ^= true;
    505         redraw();
    506         break;
    507     case 'd':
    508         draw_deriviatives ^= true;
    509         redraw();
    510         break;
    511     case 'e':
    512         draw_endpoints ^= true;
    513         redraw();
    514         break;
    515     case 'h':
    516         draw_hodo ^= true;
    517         redraw();
    518         break;
    519     case 'N':
    520         testIndex += 9;
    521     case 'n':
    522         if (++testIndex >= tests.length)
    523             testIndex = 0;
    524         drawTop();
    525         break;
    526     case 'l':
    527         logCurves(tests[testIndex]);
    528         break;
    529     case 'm':
    530         draw_midpoint ^= true;
    531         redraw();
    532         break;
    533     case 'o':
    534         draw_hodo_origin ^= true;
    535         redraw();
    536         break;
    537     case 'P':
    538         testIndex -= 9;
    539     case 'p':
    540         if (--testIndex < 0)
    541             testIndex = tests.length - 1;
    542         drawTop();
    543         break;
    544     case 's':
    545         draw_sequence ^= true;
    546         redraw();
    547         break;
    548     case 't':
    549         draw_tangents ^= true;
    550         redraw();
    551         break;
    552     }
    553 }
    554 
    555 function calcXY() {
    556     var e = window.event;
    557 	var tgt = e.target || e.srcElement;
    558     var left = tgt.offsetLeft;
    559     var top = tgt.offsetTop;
    560     var unit = scale * ticks;
    561     mouseX = (e.clientX - left - Math.ceil(at_x) + 1) / unit + xStart;
    562     mouseY = (e.clientY - top - Math.ceil(at_y)) / unit + yStart;
    563 }
    564 
    565 var lastX, lastY;
    566 var activeCurve = [];
    567 var activePt;
    568 
    569 function handleMouseClick() {
    570     calcXY();
    571 }
    572 
    573 function initDown() {
    574     var unit = scale * ticks;
    575     var xoffset = xStart * -unit + at_x;
    576     var yoffset = yStart * -unit + at_y;
    577     var test = tests[testIndex];
    578     var bestDistance = 1000000;
    579     activePt = -1;
    580     for (curves in test) {
    581         var testCurve = test[curves];
    582         if (testCurve.length != 8) {
    583             continue;
    584         }
    585         for (var i = 0; i < 8; i += 2) {
    586             var testX = testCurve[i];
    587             var testY = testCurve[i + 1];
    588             var dx = testX - mouseX;
    589             var dy = testY - mouseY;
    590             var dist = dx * dx + dy * dy;
    591             if (dist > bestDistance) {
    592                 continue;
    593             }
    594             activeCurve = testCurve;
    595             activePt = i;
    596             bestDistance = dist;
    597         }
    598     }
    599     if (activePt >= 0) {
    600         lastX = mouseX;
    601         lastY = mouseY;
    602     }
    603 }
    604 
    605 function handleMouseOver() {
    606     if (!mouseDown) {
    607         activePt = -1;
    608         return;
    609     }
    610     calcXY();
    611     if (activePt < 0) {
    612         initDown();
    613         return;
    614     }
    615     var unit = scale * ticks;
    616     var deltaX = (mouseX - lastX) /* / unit */;
    617     var deltaY = (mouseY - lastY) /*/ unit */;
    618     lastX = mouseX;
    619     lastY = mouseY;
    620     activeCurve[activePt] += deltaX;
    621     activeCurve[activePt + 1] += deltaY;
    622     redraw();
    623 }
    624 
    625 function start() {
    626     for (i = 0; i < testDivs.length; ++i) {
    627         var title = testDivs[i].id.toString();
    628         var str = testDivs[i].firstChild.data;
    629         parse(str, title);
    630     }
    631     drawTop();
    632     window.addEventListener('keypress', doKeyPress, true);
    633     window.onresize = function() {
    634         drawTop();
    635     }
    636 }
    637 
    638 </script>
    639 </head>
    640 
    641 <body onLoad="start();">
    642 <canvas id="canvas" width="750" height="500"
    643     onmousedown="mouseDown = true"
    644     onmouseup="mouseDown = false"
    645     onmousemove="handleMouseOver()"
    646     onclick="handleMouseClick()"
    647     ></canvas >
    648 </body>
    649 </html>
    650