feat(math6): ещё 2 canvas-демо — прыжки по прямой (±) и машинка+график
Math6Anim расширен: numberLineWalk (анимированные стрелки-шаги a→b на числовой прямой для сложения рациональных) и carGraph (машина едет по дороге, а график «путь–время» вычерчивается синхронно; горизонталь = стоянка). Вшито: Гл.4 §4 (прыжки, ползунки a,b) и Гл.5 §2 (машинка+график). Headless-safe. Тесты math6: 19/19 (анимации в Гл.1/4/5/6 монтируются). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -174,4 +174,66 @@ M.areaModel = function (host, opts) {
|
||||
return { stop: L.stop, host: host };
|
||||
};
|
||||
|
||||
/* ============================ ДЕМО 4: ПРЫЖКИ ПО ЧИСЛОВОЙ ПРЯМОЙ (a + b) ============================ */
|
||||
M.numberLineWalk = function (host, opts) {
|
||||
opts = opts || {}; var a = opts.a != null ? opts.a : 3, b = opts.b != null ? opts.b : -5;
|
||||
var sum = a + b, W0 = 540, H0 = 150;
|
||||
var sc = sceneCanvas(host, W0, H0); var cap = caption(host, '');
|
||||
var min = Math.min(-3, 0, a, sum) - 1, max = Math.max(3, 0, a, sum) + 1, period = 4.2;
|
||||
function X(v) { var pad = 30; return pad + (v - min) / (max - min) * (W0 - 2 * pad); }
|
||||
function arrow(ctx, x1, x2, y, col) {
|
||||
ctx.strokeStyle = col; ctx.fillStyle = col; ctx.lineWidth = 3; ctx.lineCap = 'round';
|
||||
ctx.beginPath(); ctx.moveTo(x1, y); ctx.lineTo(x2, y); ctx.stroke();
|
||||
var d = x2 >= x1 ? 1 : -1; ctx.beginPath(); ctx.moveTo(x2, y); ctx.lineTo(x2 - d * 9, y - 5); ctx.lineTo(x2 - d * 9, y + 5); ctx.closePath(); ctx.fill();
|
||||
}
|
||||
function draw(t) {
|
||||
var ctx = sc.ctx; if (!ctx) return; var mut = cssVar('--muted', '#64748b'), acc = cssVar('--pri2', '#3730a3');
|
||||
var axisY = H0 - 50; ctx.clearRect(0, 0, W0, H0);
|
||||
ctx.strokeStyle = mut; ctx.lineWidth = 1.5; ctx.beginPath(); ctx.moveTo(15, axisY); ctx.lineTo(W0 - 15, axisY); ctx.stroke();
|
||||
ctx.font = '11px JetBrains Mono, monospace'; ctx.textAlign = 'center';
|
||||
for (var v = Math.ceil(min); v <= Math.floor(max); v++) { var x = X(v); ctx.strokeStyle = mut; ctx.beginPath(); ctx.moveTo(x, axisY - 5); ctx.lineTo(x, axisY + 5); ctx.stroke(); ctx.fillStyle = (v === 0 ? acc : mut); ctx.fillText(v, x, axisY + 20); }
|
||||
var p = (t % period) / period, p1 = Math.min(1, p / 0.4), p2 = Math.max(0, Math.min(1, (p - 0.45) / 0.4));
|
||||
arrow(ctx, X(0), X(0) + (X(a) - X(0)) * p1, axisY - 14, a >= 0 ? '#059669' : '#e11d48');
|
||||
if (p2 > 0) arrow(ctx, X(a), X(a) + (X(sum) - X(a)) * p2, axisY - 30, b >= 0 ? '#059669' : '#e11d48');
|
||||
if (p > 0.88) { ctx.fillStyle = '#e11d48'; ctx.beginPath(); ctx.arc(X(sum), axisY, 6, 0, 2 * Math.PI); ctx.fill(); ctx.fillStyle = acc; ctx.font = '14px Unbounded, sans-serif'; ctx.fillText('' + sum, X(sum), axisY - 42); }
|
||||
}
|
||||
var L = loop(host, draw);
|
||||
cap.innerHTML = '$' + a + ' + (' + b + ') = ' + sum + '$ — от нуля шагаем ' + (a >= 0 ? 'вправо' : 'влево') + ' на ' + Math.abs(a) + ', затем ' + (b >= 0 ? 'вправо' : 'влево') + ' на ' + Math.abs(b) + '.';
|
||||
if (W.renderMathInElement) try { W.renderMathInElement(cap, { delimiters: [{ left: '$', right: '$', display: false }], throwOnError: false }); } catch (e) {}
|
||||
return { stop: L.stop };
|
||||
};
|
||||
|
||||
/* ============================ ДЕМО 5: МАШИНКА + ГРАФИК «ПУТЬ–ВРЕМЯ» ============================ */
|
||||
M.carGraph = function (host, opts) {
|
||||
var W0 = 460, H0 = 330; var sc = sceneCanvas(host, W0, H0); var cap = caption(host, '');
|
||||
var J = [{ t: 0, s: 0 }, { t: 1, s: 40 }, { t: 2, s: 80 }, { t: 3, s: 80 }, { t: 4, s: 120 }, { t: 5, s: 160 }];
|
||||
var Tmax = 5, Smax = 160, period = 7;
|
||||
function sAt(tt) { for (var i = 0; i < J.length - 1; i++) { if (tt >= J[i].t && tt <= J[i + 1].t) { var f = (tt - J[i].t) / ((J[i + 1].t - J[i].t) || 1); return J[i].s + f * (J[i + 1].s - J[i].s); } } return J[J.length - 1].s; }
|
||||
function draw(t) {
|
||||
var ctx = sc.ctx; if (!ctx) return;
|
||||
var pri = cssVar('--pri', '#059669'), mut = cssVar('--muted', '#64748b'), bd = cssVar('--border', '#e2e8f0');
|
||||
var cur = (t % period) / period * Tmax;
|
||||
ctx.clearRect(0, 0, W0, H0);
|
||||
var roadY = 52, rx0 = 24, rx1 = W0 - 24;
|
||||
ctx.strokeStyle = bd; ctx.lineWidth = 8; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(rx0, roadY); ctx.lineTo(rx1, roadY); ctx.stroke();
|
||||
var carX = rx0 + (sAt(cur) / Smax) * (rx1 - rx0);
|
||||
ctx.fillStyle = pri; ctx.fillRect(carX - 13, roadY - 11, 26, 14);
|
||||
ctx.fillStyle = '#1e293b'; ctx.beginPath(); ctx.arc(carX - 7, roadY + 4, 4, 0, 6.3); ctx.arc(carX + 7, roadY + 4, 4, 0, 6.3); ctx.fill();
|
||||
ctx.fillStyle = mut; ctx.font = '13px Inter, sans-serif'; ctx.textAlign = 'center';
|
||||
ctx.fillText('время: ' + (Math.round(cur * 10) / 10) + ' ч · путь: ' + Math.round(sAt(cur)) + ' км', W0 / 2, 24);
|
||||
var gx0 = 46, gy0 = H0 - 28, gw = W0 - 70, gh = H0 - 120;
|
||||
function GX(tt) { return gx0 + (tt / Tmax) * gw; } function GY(ss) { return gy0 - (ss / Smax) * gh; }
|
||||
ctx.strokeStyle = mut; ctx.lineWidth = 1.5; ctx.beginPath(); ctx.moveTo(gx0, gy0 - gh); ctx.lineTo(gx0, gy0); ctx.lineTo(gx0 + gw, gy0); ctx.stroke();
|
||||
ctx.fillStyle = mut; ctx.font = '11px Inter, sans-serif'; ctx.textAlign = 'center'; ctx.fillText('t, ч', gx0 + gw, gy0 + 16); ctx.textAlign = 'left'; ctx.fillText('s, км', gx0 - 38, gy0 - gh + 4);
|
||||
ctx.strokeStyle = bd; ctx.lineWidth = 1.5; ctx.beginPath(); J.forEach(function (pt, i) { var x = GX(pt.t), y = GY(pt.s); if (i) ctx.lineTo(x, y); else ctx.moveTo(x, y); }); ctx.stroke();
|
||||
ctx.strokeStyle = pri; ctx.lineWidth = 3; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(GX(0), GY(0));
|
||||
for (var tt = 0; tt <= cur; tt += 0.04) ctx.lineTo(GX(tt), GY(sAt(tt)));
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = '#e11d48'; ctx.beginPath(); ctx.arc(GX(cur), GY(sAt(cur)), 5, 0, 2 * Math.PI); ctx.fill();
|
||||
}
|
||||
var L = loop(host, draw);
|
||||
cap.innerHTML = 'Машина едет — график «путь–время» вычерчивается сам. Где линия <b>горизонтальна</b> (с 2 до 3 ч) — машина <b>стоит</b>: время идёт, а путь не растёт.';
|
||||
return { stop: L.stop };
|
||||
};
|
||||
|
||||
})(window);
|
||||
|
||||
Reference in New Issue
Block a user