650 lines
18 KiB
HTML
650 lines
18 KiB
HTML
|
<html>
|
||
|
<head>
|
||
|
<div style="height:0">
|
||
|
|
||
|
<div id="cubic1">
|
||
|
{{3.13,2.74}, {1.08,4.62}, {3.71,0.94}, {2.01,3.81}}
|
||
|
{{6.71,3.14}, {7.99,2.75}, {8.27,1.96}, {6.35,3.57}}
|
||
|
{{9.45,10.67}, {10.05,5.78}, {13.95,7.46}, {14.72,5.29}}
|
||
|
{{3.34,8.98}, {1.95,10.27}, {3.76,7.65}, {4.96,10.64}}
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<script type="text/javascript">
|
||
|
|
||
|
var testDivs = [
|
||
|
cubic1,
|
||
|
];
|
||
|
|
||
|
var scale, columns, rows, xStart, yStart;
|
||
|
|
||
|
var ticks = 10;
|
||
|
var at_x = 13 + 0.5;
|
||
|
var at_y = 23 + 0.5;
|
||
|
var decimal_places = 3;
|
||
|
var tests = [];
|
||
|
var testTitles = [];
|
||
|
var testIndex = 0;
|
||
|
var ctx;
|
||
|
var minScale = 1;
|
||
|
var subscale = 1;
|
||
|
var curveT = -1;
|
||
|
var xmin, xmax, ymin, ymax;
|
||
|
|
||
|
var mouseX, mouseY;
|
||
|
var mouseDown = false;
|
||
|
|
||
|
var draw_deriviatives = false;
|
||
|
var draw_endpoints = true;
|
||
|
var draw_hodo = false;
|
||
|
var draw_hodo2 = false;
|
||
|
var draw_hodo_origin = true;
|
||
|
var draw_midpoint = false;
|
||
|
var draw_tangents = true;
|
||
|
var draw_sequence = true;
|
||
|
|
||
|
function parse(test, title) {
|
||
|
var curveStrs = test.split("{{");
|
||
|
if (curveStrs.length == 1)
|
||
|
curveStrs = test.split("=(");
|
||
|
var pattern = /[a-z$=]?-?\d+\.*\d*e?-?\d*/g;
|
||
|
var curves = [];
|
||
|
for (var c in curveStrs) {
|
||
|
var curveStr = curveStrs[c];
|
||
|
var points = curveStr.match(pattern);
|
||
|
var pts = [];
|
||
|
for (var wd in points) {
|
||
|
var num = parseFloat(points[wd]);
|
||
|
if (isNaN(num)) continue;
|
||
|
pts.push(num);
|
||
|
}
|
||
|
if (pts.length > 2)
|
||
|
curves.push(pts);
|
||
|
}
|
||
|
if (curves.length >= 1) {
|
||
|
tests.push(curves);
|
||
|
testTitles.push(title);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function init(test) {
|
||
|
var canvas = document.getElementById('canvas');
|
||
|
if (!canvas.getContext) return;
|
||
|
canvas.width = window.innerWidth - 20;
|
||
|
canvas.height = window.innerHeight - 20;
|
||
|
ctx = canvas.getContext('2d');
|
||
|
xmin = Infinity;
|
||
|
xmax = -Infinity;
|
||
|
ymin = Infinity;
|
||
|
ymax = -Infinity;
|
||
|
for (var curves in test) {
|
||
|
var curve = test[curves];
|
||
|
var last = curve.length;
|
||
|
for (var idx = 0; idx < last; idx += 2) {
|
||
|
xmin = Math.min(xmin, curve[idx]);
|
||
|
xmax = Math.max(xmax, curve[idx]);
|
||
|
ymin = Math.min(ymin, curve[idx + 1]);
|
||
|
ymax = Math.max(ymax, curve[idx + 1]);
|
||
|
}
|
||
|
}
|
||
|
xmin -= 1;
|
||
|
var testW = xmax - xmin;
|
||
|
var testH = ymax - ymin;
|
||
|
subscale = 1;
|
||
|
while (testW * subscale < 0.1 && testH * subscale < 0.1) {
|
||
|
subscale *= 10;
|
||
|
}
|
||
|
while (testW * subscale > 10 && testH * subscale > 10) {
|
||
|
subscale /= 10;
|
||
|
}
|
||
|
calcFromScale();
|
||
|
}
|
||
|
|
||
|
function hodograph(cubic) {
|
||
|
var hodo = [];
|
||
|
hodo[0] = 3 * (cubic[2] - cubic[0]);
|
||
|
hodo[1] = 3 * (cubic[3] - cubic[1]);
|
||
|
hodo[2] = 3 * (cubic[4] - cubic[2]);
|
||
|
hodo[3] = 3 * (cubic[5] - cubic[3]);
|
||
|
hodo[4] = 3 * (cubic[6] - cubic[4]);
|
||
|
hodo[5] = 3 * (cubic[7] - cubic[5]);
|
||
|
return hodo;
|
||
|
}
|
||
|
|
||
|
function hodograph2(cubic) {
|
||
|
var quad = hodograph(cubic);
|
||
|
var hodo = [];
|
||
|
hodo[0] = 2 * (quad[2] - quad[0]);
|
||
|
hodo[1] = 2 * (quad[3] - quad[1]);
|
||
|
hodo[2] = 2 * (quad[4] - quad[2]);
|
||
|
hodo[3] = 2 * (quad[5] - quad[3]);
|
||
|
return hodo;
|
||
|
}
|
||
|
|
||
|
function quadraticRootsReal(A, B, C, s) {
|
||
|
if (A == 0) {
|
||
|
if (B == 0) {
|
||
|
s[0] = 0;
|
||
|
return C == 0;
|
||
|
}
|
||
|
s[0] = -C / B;
|
||
|
return 1;
|
||
|
}
|
||
|
/* normal form: x^2 + px + q = 0 */
|
||
|
var p = B / (2 * A);
|
||
|
var q = C / A;
|
||
|
var p2 = p * p;
|
||
|
if (p2 < q) {
|
||
|
return 0;
|
||
|
}
|
||
|
var sqrt_D = 0;
|
||
|
if (p2 > q) {
|
||
|
sqrt_D = sqrt(p2 - q);
|
||
|
}
|
||
|
s[0] = sqrt_D - p;
|
||
|
s[1] = -sqrt_D - p;
|
||
|
return 1 + s[0] != s[1];
|
||
|
}
|
||
|
|
||
|
function add_valid_ts(s, realRoots, t) {
|
||
|
var foundRoots = 0;
|
||
|
for (var index = 0; index < realRoots; ++index) {
|
||
|
var tValue = s[index];
|
||
|
if (tValue >= 0 && tValue <= 1) {
|
||
|
for (var idx2 = 0; idx2 < foundRoots; ++idx2) {
|
||
|
if (t[idx2] != tValue) {
|
||
|
t[foundRoots++] = tValue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return foundRoots;
|
||
|
}
|
||
|
|
||
|
function quadraticRootsValidT(a, b, c, t) {
|
||
|
var s = [];
|
||
|
var realRoots = quadraticRootsReal(A, B, C, s);
|
||
|
var foundRoots = add_valid_ts(s, realRoots, t);
|
||
|
return foundRoots != 0;
|
||
|
}
|
||
|
|
||
|
function find_cubic_inflections(cubic, tValues)
|
||
|
{
|
||
|
var Ax = src[2] - src[0];
|
||
|
var Ay = src[3] - src[1];
|
||
|
var Bx = src[4] - 2 * src[2] + src[0];
|
||
|
var By = src[5] - 2 * src[3] + src[1];
|
||
|
var Cx = src[6] + 3 * (src[2] - src[4]) - src[0];
|
||
|
var Cy = src[7] + 3 * (src[3] - src[5]) - src[1];
|
||
|
return quadraticRootsValidT(Bx * Cy - By * Cx, (Ax * Cy - Ay * Cx),
|
||
|
Ax * By - Ay * Bx, tValues);
|
||
|
}
|
||
|
|
||
|
function dx_at_t(cubic, t) {
|
||
|
var one_t = 1 - t;
|
||
|
var a = cubic[0];
|
||
|
var b = cubic[2];
|
||
|
var c = cubic[4];
|
||
|
var d = cubic[6];
|
||
|
return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
|
||
|
}
|
||
|
|
||
|
function dy_at_t(cubic, t) {
|
||
|
var one_t = 1 - t;
|
||
|
var a = cubic[1];
|
||
|
var b = cubic[3];
|
||
|
var c = cubic[5];
|
||
|
var d = cubic[7];
|
||
|
return 3 * ((b - a) * one_t * one_t + 2 * (c - b) * t * one_t + (d - c) * t * t);
|
||
|
}
|
||
|
|
||
|
function x_at_t(cubic, t) {
|
||
|
var one_t = 1 - t;
|
||
|
var one_t2 = one_t * one_t;
|
||
|
var a = one_t2 * one_t;
|
||
|
var b = 3 * one_t2 * t;
|
||
|
var t2 = t * t;
|
||
|
var c = 3 * one_t * t2;
|
||
|
var d = t2 * t;
|
||
|
return a * cubic[0] + b * cubic[2] + c * cubic[4] + d * cubic[6];
|
||
|
}
|
||
|
|
||
|
function y_at_t(cubic, t) {
|
||
|
var one_t = 1 - t;
|
||
|
var one_t2 = one_t * one_t;
|
||
|
var a = one_t2 * one_t;
|
||
|
var b = 3 * one_t2 * t;
|
||
|
var t2 = t * t;
|
||
|
var c = 3 * one_t * t2;
|
||
|
var d = t2 * t;
|
||
|
return a * cubic[1] + b * cubic[3] + c * cubic[5] + d * cubic[7];
|
||
|
}
|
||
|
|
||
|
function calcFromScale() {
|
||
|
xStart = Math.floor(xmin * subscale) / subscale;
|
||
|
yStart = Math.floor(ymin * subscale) / subscale;
|
||
|
var xEnd = Math.ceil(xmin * subscale) / subscale;
|
||
|
var yEnd = Math.ceil(ymin * subscale) / subscale;
|
||
|
var cCelsW = Math.floor(ctx.canvas.width / 10);
|
||
|
var cCelsH = Math.floor(ctx.canvas.height / 10);
|
||
|
var testW = xEnd - xStart;
|
||
|
var testH = yEnd - yStart;
|
||
|
var scaleWH = 1;
|
||
|
while (cCelsW > testW * scaleWH * 10 && cCelsH > testH * scaleWH * 10) {
|
||
|
scaleWH *= 10;
|
||
|
}
|
||
|
while (cCelsW * 10 < testW * scaleWH && cCelsH * 10 < testH * scaleWH) {
|
||
|
scaleWH /= 10;
|
||
|
}
|
||
|
|
||
|
columns = Math.ceil(xmax * subscale) - Math.floor(xmin * subscale) + 1;
|
||
|
rows = Math.ceil(ymax * subscale) - Math.floor(ymin * subscale) + 1;
|
||
|
|
||
|
var hscale = ctx.canvas.width / columns / ticks;
|
||
|
var vscale = ctx.canvas.height / rows / ticks;
|
||
|
minScale = Math.floor(Math.min(hscale, vscale));
|
||
|
scale = minScale * subscale;
|
||
|
}
|
||
|
|
||
|
function drawLine(x1, y1, x2, y2) {
|
||
|
var unit = scale * ticks;
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(xoffset + x1 * unit, yoffset + y1 * unit);
|
||
|
ctx.lineTo(xoffset + x2 * unit, yoffset + y2 * unit);
|
||
|
ctx.stroke();
|
||
|
}
|
||
|
|
||
|
function drawPoint(px, py) {
|
||
|
var unit = scale * ticks;
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
var _px = px * unit + xoffset;
|
||
|
var _py = py * unit + yoffset;
|
||
|
ctx.beginPath();
|
||
|
ctx.arc(_px, _py, 3, 0, Math.PI*2, true);
|
||
|
ctx.closePath();
|
||
|
ctx.stroke();
|
||
|
}
|
||
|
|
||
|
function drawPointSolid(px, py) {
|
||
|
drawPoint(px, py);
|
||
|
ctx.fillStyle = "rgba(0,0,0, 0.4)";
|
||
|
ctx.fill();
|
||
|
}
|
||
|
|
||
|
function drawLabel(num, px, py) {
|
||
|
ctx.beginPath();
|
||
|
ctx.arc(px, py, 8, 0, Math.PI*2, true);
|
||
|
ctx.closePath();
|
||
|
ctx.strokeStyle = "rgba(0,0,0, 0.4)";
|
||
|
ctx.lineWidth = num == 0 || num == 3 ? 2 : 1;
|
||
|
ctx.stroke();
|
||
|
ctx.fillStyle = "black";
|
||
|
ctx.font = "normal 10px Arial";
|
||
|
// ctx.rotate(0.001);
|
||
|
ctx.fillText(num, px - 2, py + 3);
|
||
|
// ctx.rotate(-0.001);
|
||
|
}
|
||
|
|
||
|
function drawLabelX(ymin, num, loc) {
|
||
|
var unit = scale * ticks;
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
var px = loc * unit + xoffset;
|
||
|
var py = ymin * unit + yoffset - 20;
|
||
|
drawLabel(num, px, py);
|
||
|
}
|
||
|
|
||
|
function drawLabelY(xmin, num, loc) {
|
||
|
var unit = scale * ticks;
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
var px = xmin * unit + xoffset - 20;
|
||
|
var py = loc * unit + yoffset;
|
||
|
drawLabel(num, px, py);
|
||
|
}
|
||
|
|
||
|
function drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY) {
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(hx, hy - 100);
|
||
|
ctx.lineTo(hx, hy);
|
||
|
ctx.strokeStyle = hMinY < 0 ? "green" : "blue";
|
||
|
ctx.stroke();
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(hx, hy);
|
||
|
ctx.lineTo(hx, hy + 100);
|
||
|
ctx.strokeStyle = hMaxY > 0 ? "green" : "blue";
|
||
|
ctx.stroke();
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(hx - 100, hy);
|
||
|
ctx.lineTo(hx, hy);
|
||
|
ctx.strokeStyle = hMinX < 0 ? "green" : "blue";
|
||
|
ctx.stroke();
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(hx, hy);
|
||
|
ctx.lineTo(hx + 100, hy);
|
||
|
ctx.strokeStyle = hMaxX > 0 ? "green" : "blue";
|
||
|
ctx.stroke();
|
||
|
}
|
||
|
|
||
|
function logCurves(test) {
|
||
|
for (curves in test) {
|
||
|
var curve = test[curves];
|
||
|
if (curve.length != 8) {
|
||
|
continue;
|
||
|
}
|
||
|
var str = "{{";
|
||
|
for (i = 0; i < 8; i += 2) {
|
||
|
str += curve[i].toFixed(2) + "," + curve[i + 1].toFixed(2);
|
||
|
if (i < 6) {
|
||
|
str += "}, {";
|
||
|
}
|
||
|
}
|
||
|
str += "}}";
|
||
|
console.log(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function scalexy(x, y, mag) {
|
||
|
var length = Math.sqrt(x * x + y * y);
|
||
|
return mag / length;
|
||
|
}
|
||
|
|
||
|
function drawArrow(x, y, dx, dy) {
|
||
|
var unit = scale * ticks;
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
var dscale = scalexy(dx, dy, 1);
|
||
|
dx *= dscale;
|
||
|
dy *= dscale;
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(xoffset + x * unit, yoffset + y * unit);
|
||
|
x += dx;
|
||
|
y += dy;
|
||
|
ctx.lineTo(xoffset + x * unit, yoffset + y * unit);
|
||
|
dx /= 10;
|
||
|
dy /= 10;
|
||
|
ctx.lineTo(xoffset + (x - dy) * unit, yoffset + (y + dx) * unit);
|
||
|
ctx.lineTo(xoffset + (x + dx * 2) * unit, yoffset + (y + dy * 2) * unit);
|
||
|
ctx.lineTo(xoffset + (x + dy) * unit, yoffset + (y - dx) * unit);
|
||
|
ctx.lineTo(xoffset + x * unit, yoffset + y * unit);
|
||
|
ctx.strokeStyle = "rgba(0,75,0, 0.4)";
|
||
|
ctx.stroke();
|
||
|
}
|
||
|
|
||
|
function draw(test, title) {
|
||
|
ctx.fillStyle = "rgba(0,0,0, 0.1)";
|
||
|
ctx.font = "normal 50px Arial";
|
||
|
ctx.fillText(title, 50, 50);
|
||
|
ctx.font = "normal 10px Arial";
|
||
|
var unit = scale * ticks;
|
||
|
// ctx.lineWidth = "1.001"; "0.999";
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
|
||
|
for (curves in test) {
|
||
|
var curve = test[curves];
|
||
|
if (curve.length != 8) {
|
||
|
continue;
|
||
|
}
|
||
|
ctx.lineWidth = 1;
|
||
|
if (draw_tangents) {
|
||
|
ctx.strokeStyle = "rgba(0,0,255, 0.3)";
|
||
|
drawLine(curve[0], curve[1], curve[2], curve[3]);
|
||
|
drawLine(curve[2], curve[3], curve[4], curve[5]);
|
||
|
drawLine(curve[4], curve[5], curve[6], curve[7]);
|
||
|
}
|
||
|
if (draw_deriviatives) {
|
||
|
var dx = dx_at_t(curve, 0);
|
||
|
var dy = dy_at_t(curve, 0);
|
||
|
drawArrow(curve[0], curve[1], dx, dy);
|
||
|
dx = dx_at_t(curve, 1);
|
||
|
dy = dy_at_t(curve, 1);
|
||
|
drawArrow(curve[6], curve[7], dx, dy);
|
||
|
if (draw_midpoint) {
|
||
|
var midX = x_at_t(curve, 0.5);
|
||
|
var midY = y_at_t(curve, 0.5);
|
||
|
dx = dx_at_t(curve, 0.5);
|
||
|
dy = dy_at_t(curve, 0.5);
|
||
|
drawArrow(midX, midY, dx, dy);
|
||
|
}
|
||
|
}
|
||
|
ctx.beginPath();
|
||
|
ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit);
|
||
|
ctx.bezierCurveTo(
|
||
|
xoffset + curve[2] * unit, yoffset + curve[3] * unit,
|
||
|
xoffset + curve[4] * unit, yoffset + curve[5] * unit,
|
||
|
xoffset + curve[6] * unit, yoffset + curve[7] * unit);
|
||
|
ctx.strokeStyle = "black";
|
||
|
ctx.stroke();
|
||
|
if (draw_endpoints) {
|
||
|
drawPoint(curve[0], curve[1]);
|
||
|
drawPoint(curve[2], curve[3]);
|
||
|
drawPoint(curve[4], curve[5]);
|
||
|
drawPoint(curve[6], curve[7]);
|
||
|
}
|
||
|
if (draw_midpoint) {
|
||
|
var midX = x_at_t(curve, 0.5);
|
||
|
var midY = y_at_t(curve, 0.5);
|
||
|
drawPointSolid(midX, midY);
|
||
|
}
|
||
|
if (draw_hodo) {
|
||
|
var hodo = hodograph(curve);
|
||
|
var hMinX = Math.min(0, hodo[0], hodo[2], hodo[4]);
|
||
|
var hMinY = Math.min(0, hodo[1], hodo[3], hodo[5]);
|
||
|
var hMaxX = Math.max(0, hodo[0], hodo[2], hodo[4]);
|
||
|
var hMaxY = Math.max(0, hodo[1], hodo[3], hodo[5]);
|
||
|
var hScaleX = hMaxX - hMinX > 0 ? ctx.canvas.width / (hMaxX - hMinX) : 1;
|
||
|
var hScaleY = hMaxY - hMinY > 0 ? ctx.canvas.height / (hMaxY - hMinY) : 1;
|
||
|
var hUnit = Math.min(hScaleX, hScaleY);
|
||
|
hUnit /= 2;
|
||
|
var hx = xoffset - hMinX * hUnit;
|
||
|
var hy = yoffset - hMinY * hUnit;
|
||
|
ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
|
||
|
ctx.quadraticCurveTo(
|
||
|
hx + hodo[2] * hUnit, hy + hodo[3] * hUnit,
|
||
|
hx + hodo[4] * hUnit, hy + hodo[5] * hUnit);
|
||
|
ctx.strokeStyle = "red";
|
||
|
ctx.stroke();
|
||
|
if (draw_hodo_origin) {
|
||
|
drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
|
||
|
}
|
||
|
}
|
||
|
if (draw_hodo2) {
|
||
|
var hodo = hodograph2(curve);
|
||
|
var hMinX = Math.min(0, hodo[0], hodo[2]);
|
||
|
var hMinY = Math.min(0, hodo[1], hodo[3]);
|
||
|
var hMaxX = Math.max(0, hodo[0], hodo[2]);
|
||
|
var hMaxY = Math.max(0, hodo[1], hodo[3]);
|
||
|
var hScaleX = hMaxX - hMinX > 0 ? ctx.canvas.width / (hMaxX - hMinX) : 1;
|
||
|
var hScaleY = hMaxY - hMinY > 0 ? ctx.canvas.height / (hMaxY - hMinY) : 1;
|
||
|
var hUnit = Math.min(hScaleX, hScaleY);
|
||
|
hUnit /= 2;
|
||
|
var hx = xoffset - hMinX * hUnit;
|
||
|
var hy = yoffset - hMinY * hUnit;
|
||
|
ctx.moveTo(hx + hodo[0] * hUnit, hy + hodo[1] * hUnit);
|
||
|
ctx.lineTo(hx + hodo[2] * hUnit, hy + hodo[3] * hUnit);
|
||
|
ctx.strokeStyle = "red";
|
||
|
ctx.stroke();
|
||
|
drawHodoOrigin(hx, hy, hMinX, hMinY, hMaxX, hMaxY);
|
||
|
}
|
||
|
if (draw_sequence) {
|
||
|
var ymin = Math.min(curve[1], curve[3], curve[5], curve[7]);
|
||
|
for (var i = 0; i < 8; i+= 2) {
|
||
|
drawLabelX(ymin, i >> 1, curve[i]);
|
||
|
}
|
||
|
var xmin = Math.min(curve[0], curve[2], curve[4], curve[6]);
|
||
|
for (var i = 1; i < 8; i+= 2) {
|
||
|
drawLabelY(xmin, i >> 1, curve[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function drawTop() {
|
||
|
init(tests[testIndex]);
|
||
|
redraw();
|
||
|
}
|
||
|
|
||
|
function redraw() {
|
||
|
ctx.beginPath();
|
||
|
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||
|
ctx.fillStyle="white";
|
||
|
ctx.fill();
|
||
|
draw(tests[testIndex], testTitles[testIndex]);
|
||
|
}
|
||
|
|
||
|
function doKeyPress(evt) {
|
||
|
var char = String.fromCharCode(evt.charCode);
|
||
|
switch (char) {
|
||
|
case '2':
|
||
|
draw_hodo2 ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 'd':
|
||
|
draw_deriviatives ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 'e':
|
||
|
draw_endpoints ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 'h':
|
||
|
draw_hodo ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 'N':
|
||
|
testIndex += 9;
|
||
|
case 'n':
|
||
|
if (++testIndex >= tests.length)
|
||
|
testIndex = 0;
|
||
|
drawTop();
|
||
|
break;
|
||
|
case 'l':
|
||
|
logCurves(tests[testIndex]);
|
||
|
break;
|
||
|
case 'm':
|
||
|
draw_midpoint ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 'o':
|
||
|
draw_hodo_origin ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 'P':
|
||
|
testIndex -= 9;
|
||
|
case 'p':
|
||
|
if (--testIndex < 0)
|
||
|
testIndex = tests.length - 1;
|
||
|
drawTop();
|
||
|
break;
|
||
|
case 's':
|
||
|
draw_sequence ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
case 't':
|
||
|
draw_tangents ^= true;
|
||
|
redraw();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function calcXY() {
|
||
|
var e = window.event;
|
||
|
var tgt = e.target || e.srcElement;
|
||
|
var left = tgt.offsetLeft;
|
||
|
var top = tgt.offsetTop;
|
||
|
var unit = scale * ticks;
|
||
|
mouseX = (e.clientX - left - Math.ceil(at_x) + 1) / unit + xStart;
|
||
|
mouseY = (e.clientY - top - Math.ceil(at_y)) / unit + yStart;
|
||
|
}
|
||
|
|
||
|
var lastX, lastY;
|
||
|
var activeCurve = [];
|
||
|
var activePt;
|
||
|
|
||
|
function handleMouseClick() {
|
||
|
calcXY();
|
||
|
}
|
||
|
|
||
|
function initDown() {
|
||
|
var unit = scale * ticks;
|
||
|
var xoffset = xStart * -unit + at_x;
|
||
|
var yoffset = yStart * -unit + at_y;
|
||
|
var test = tests[testIndex];
|
||
|
var bestDistance = 1000000;
|
||
|
activePt = -1;
|
||
|
for (curves in test) {
|
||
|
var testCurve = test[curves];
|
||
|
if (testCurve.length != 8) {
|
||
|
continue;
|
||
|
}
|
||
|
for (var i = 0; i < 8; i += 2) {
|
||
|
var testX = testCurve[i];
|
||
|
var testY = testCurve[i + 1];
|
||
|
var dx = testX - mouseX;
|
||
|
var dy = testY - mouseY;
|
||
|
var dist = dx * dx + dy * dy;
|
||
|
if (dist > bestDistance) {
|
||
|
continue;
|
||
|
}
|
||
|
activeCurve = testCurve;
|
||
|
activePt = i;
|
||
|
bestDistance = dist;
|
||
|
}
|
||
|
}
|
||
|
if (activePt >= 0) {
|
||
|
lastX = mouseX;
|
||
|
lastY = mouseY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function handleMouseOver() {
|
||
|
if (!mouseDown) {
|
||
|
activePt = -1;
|
||
|
return;
|
||
|
}
|
||
|
calcXY();
|
||
|
if (activePt < 0) {
|
||
|
initDown();
|
||
|
return;
|
||
|
}
|
||
|
var unit = scale * ticks;
|
||
|
var deltaX = (mouseX - lastX) /* / unit */;
|
||
|
var deltaY = (mouseY - lastY) /*/ unit */;
|
||
|
lastX = mouseX;
|
||
|
lastY = mouseY;
|
||
|
activeCurve[activePt] += deltaX;
|
||
|
activeCurve[activePt + 1] += deltaY;
|
||
|
redraw();
|
||
|
}
|
||
|
|
||
|
function start() {
|
||
|
for (i = 0; i < testDivs.length; ++i) {
|
||
|
var title = testDivs[i].id.toString();
|
||
|
var str = testDivs[i].firstChild.data;
|
||
|
parse(str, title);
|
||
|
}
|
||
|
drawTop();
|
||
|
window.addEventListener('keypress', doKeyPress, true);
|
||
|
window.onresize = function() {
|
||
|
drawTop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
</script>
|
||
|
</head>
|
||
|
|
||
|
<body onLoad="start();">
|
||
|
<canvas id="canvas" width="750" height="500"
|
||
|
onmousedown="mouseDown = true"
|
||
|
onmouseup="mouseDown = false"
|
||
|
onmousemove="handleMouseOver()"
|
||
|
onclick="handleMouseClick()"
|
||
|
></canvas >
|
||
|
</body>
|
||
|
</html>
|