feat(trigcircle): Фаза 5 — чётность/нечётность (−α) + периоды

Тумблер «Чётность (−α)»: на окружности рисуется зеркальная точка −α (отражение через
ось Ox, пунктир P↔−α) — наглядно нечётность sin и чётность cos. Блок-справка на KaTeX
(строится один раз): sin(−α)=−sin α, cos(−α)=cos α, tg(−α)=−tg α, периоды
T_sin=T_cos=2π, T_tg=T_ctg=π. (Формулы приведения для текущего угла — уже Фаза 2.)

Аддитивно: this.showParity + _drawParity + хук в draw(); glue trigToggleParity;
тумблер + #trig-parity в панели.

Verified: node --check; headless-смоук 9/9 (_drawParity без throw для 30/150/210/300;
toggle строит блок один раз с верными тождествами+периодами, показ/скрытие). Эмодзи нет.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-24 10:51:55 +03:00
parent fe6df8fb98
commit 48158ea88d
2 changed files with 46 additions and 0 deletions
+37
View File
@@ -54,6 +54,7 @@ class TrigCircleSim {
this.snapToNotable = true;
this.animating = false;
this.eq = null; // режим уравнения: { fn:'sin'|'cos'|'tg', a:Number, sols:[рад] } | null
this.showParity = false; // показать зеркальную точку −α (чётность/нечётность)
this._cx = 0; this._cy = 0; this._r = 0;
this._gx = 0; this._gw = 0; this._gh = 0; this._gy = 0;
@@ -98,6 +99,7 @@ class TrigCircleSim {
this._drawBg(c);
this._drawCircle(c);
if (this.eq) this._drawEquation(c);
if (this.showParity) this._drawParity(c);
if (this.showGraph) { this._drawDivider(c); this._drawGraph(c); }
this._drawParticles(c);
if (window.LabFX) LabFX.particles.draw(c);
@@ -153,6 +155,22 @@ class TrigCircleSim {
c.restore();
}
/* Зеркальная точка −α (отражение через ось Ox): наглядно чётность cos и нечётность sin. */
_drawParity(c) {
const cx = this._cx, cy = this._cy, r = this._r, a = this.angle;
const px = cx + r * Math.cos(a), py = cy - r * Math.sin(a);
const mx = cx + r * Math.cos(-a), my = cy - r * Math.sin(-a);
c.save();
c.strokeStyle = _tcRgba(_TC.violet, 0.4); c.setLineDash([4, 4]); c.lineWidth = 1;
c.beginPath(); c.moveTo(px, py); c.lineTo(mx, my); c.stroke(); c.setLineDash([]);
c.strokeStyle = _TC.violet; c.lineWidth = 2; c.fillStyle = 'rgba(155,93,229,0.15)';
c.beginPath(); c.arc(mx, my, 6, 0, Math.PI * 2); c.fill(); c.stroke();
c.font = 'bold 11px Manrope,sans-serif'; c.fillStyle = _TC.violet;
c.textAlign = 'center'; c.textBaseline = 'middle';
c.fillText('-α', mx + (Math.cos(-a) >= 0 ? 14 : -14), my);
c.restore();
}
goToAngle(rad) {
this._animTarget = this._norm(rad);
if (!this.animating) this._startAnim();
@@ -1194,6 +1212,25 @@ if (typeof window !== 'undefined') window.TrigCircleSim = TrigCircleSim;
else el.style.display = 'none';
}
/* ── Чётность/нечётность + периоды (статический KaTeX-блок, строится один раз) ── */
function trigToggleParity(rowEl) {
if (!trigSim) return;
const on = rowEl.classList.toggle('active');
trigSim.showParity = on;
trigSim.draw();
const pEl = document.getElementById('trig-parity');
if (!pEl) return;
pEl.style.display = on ? '' : 'none';
if (on && !pEl.dataset.built) {
pEl.innerHTML =
`<div>${_tex('\\sin(-\\alpha) = -\\sin\\alpha')}</div>` +
`<div>${_tex('\\cos(-\\alpha) = \\cos\\alpha')}</div>` +
`<div>${_tex('\\operatorname{tg}(-\\alpha) = -\\operatorname{tg}\\alpha')}</div>` +
`<div style="margin-top:6px;color:var(--text-3);font-size:0.7rem">${_tex('T_{\\sin}=T_{\\cos}=2\\pi,\\quad T_{\\operatorname{tg}}=T_{\\operatorname{ctg}}=\\pi')}</div>`;
pEl.dataset.built = '1';
}
}
function _trigUpdateUI(s) {
const _f = v => {
if (v === undefined) return '—';
+9
View File
@@ -608,6 +608,15 @@
</label>
<div id="trig-table" style="display:none;margin-bottom:14px;background:rgba(155,93,229,0.05);border:1px solid rgba(155,93,229,0.13);border-radius:10px;padding:6px 8px;overflow-x:auto"></div>
<!-- Parity (−α) + periods toggle -->
<label class="tri-layer-row" style="margin-bottom:8px" onclick="trigToggleParity(this)">
<span class="tri-dot" style="background:var(--violet);box-shadow:0 0 5px var(--violet)"></span>
<span class="tri-layer-name">Чётность (−α)</span>
<span class="tri-layer-hint" style="color:var(--text-3)">симметрия</span>
<span class="tri-toggle"></span>
</label>
<div id="trig-parity" style="display:none;margin-bottom:14px;font-size:0.82rem;color:var(--text);line-height:1.7;background:rgba(155,93,229,0.05);border:1px solid rgba(155,93,229,0.13);border-radius:10px;padding:8px 11px"></div>
<!-- Notable angles -->
<div class="gp-section-title" style="margin-bottom:8px">Табличные углы</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:14px">