feat(trigcircle): Фаза 1 — работа с углами + обзор (тренажёр тригонометрии)
План тренажёра в plans/trig-circle/PLAN.md (всё по теме на окружности, кроме графиков функций). Фаза 1 (аддитивно к рабочему режиму): - Ввод угла в градусах (поле + Enter/кнопка) → goToAngle (нормализует, показывает котерминальность). Подсказка «+360°·k» в бейдже угла. - Тумблер «График/функции» — скрыть график (тема «функции») → круг на всю ширину (переиспользует существующий слой graph + _layout). - Полная сетка табличных углов (16: 0…330°) вместо 8. - Опорный (острый) угол к оси Ox в выводе (основа формул приведения) + знаки sin/cos/tg по текущей четверти. stats() расширен полями refAngle/refDeg. Verified: node --check; headless-смоук (vm + canvas-Proxy) 9/9 — опорный угол 30/150/210→30°, 300→60°, 90→90°, 0→0; знаки по четвертям (II: sin+ cos− tg−; IV: sin− cos+); новые глобальные glue-функции определены. Эмодзи нет (стрелка — inline SVG .ic, tg-неопр. — em-dash). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,7 +130,16 @@ class TrigCircleSim {
|
||||
const ct = Math.abs(s) > 1e-9 ? co / s : undefined;
|
||||
const deg = a * 180 / Math.PI;
|
||||
const q = a < Math.PI/2 ? 1 : a < Math.PI ? 2 : a < 3*Math.PI/2 ? 3 : 4;
|
||||
return { angle: a, deg, radLabel: this._radLbl(a), sin: s, cos: co, tan: t, cot: ct, quadrant: q };
|
||||
// Опорный (острый) угол — к ближайшей оси Ox: основа формул приведения.
|
||||
let ref;
|
||||
if (a <= Math.PI / 2) ref = a;
|
||||
else if (a <= Math.PI) ref = Math.PI - a;
|
||||
else if (a <= 3 * Math.PI/2) ref = a - Math.PI;
|
||||
else ref = 2 * Math.PI - a;
|
||||
return {
|
||||
angle: a, deg, radLabel: this._radLbl(a), sin: s, cos: co, tan: t, cot: ct, quadrant: q,
|
||||
refAngle: ref, refDeg: ref * 180 / Math.PI,
|
||||
};
|
||||
}
|
||||
|
||||
/* ═══ Layout ═══════════════════════════════════════════════════════ */
|
||||
@@ -1029,6 +1038,26 @@ if (typeof window !== 'undefined') window.TrigCircleSim = TrigCircleSim;
|
||||
if (window.LabFX) LabFX.sound.play('click');
|
||||
}
|
||||
|
||||
/* Ввод угла в градусах (поле + Enter/кнопка). Принимает любое число (включая <0 и >360),
|
||||
goToAngle нормализует — заодно демонстрирует котерминальность. */
|
||||
function trigSetAngleDeg(inp) {
|
||||
if (!trigSim || !inp) return;
|
||||
const v = parseFloat(String(inp.value || '').replace(',', '.'));
|
||||
if (!isFinite(v)) return;
|
||||
trigSim.goToAngle(v * Math.PI / 180);
|
||||
}
|
||||
function trigAngleKey(e, inp) { if (e && (e.key === 'Enter' || e.keyCode === 13)) trigSetAngleDeg(inp); }
|
||||
|
||||
/* Показать/скрыть график функций (тема «функции» — по умолчанию можно убрать,
|
||||
круг займёт всю ширину). Переиспользует существующий слой 'graph'. */
|
||||
function trigToggleGraph(rowEl) {
|
||||
if (!trigSim) return;
|
||||
const on = rowEl.classList.toggle('active');
|
||||
trigSim.toggleLayer('graph', on);
|
||||
const fns = document.getElementById('trig-graph-fns');
|
||||
if (fns) fns.style.display = on ? '' : 'none';
|
||||
}
|
||||
|
||||
function _trigUpdateUI(s) {
|
||||
const _f = v => {
|
||||
if (v === undefined) return '—';
|
||||
@@ -1050,9 +1079,22 @@ if (typeof window !== 'undefined') window.TrigCircleSim = TrigCircleSim;
|
||||
document.getElementById('trig-v-tan').textContent = _f(s.tan);
|
||||
document.getElementById('trig-v-cot').textContent = _f(s.cot);
|
||||
|
||||
// Angle badge
|
||||
// Angle badge + котерминальные углы (+360°·k)
|
||||
document.getElementById('trig-angle-badge').innerHTML =
|
||||
`${degStr} = ${s.radLabel}<br><span style="font-size:0.72rem;opacity:0.6">${s.angle.toFixed(4)} рад</span>`;
|
||||
`${degStr} = ${s.radLabel}<br><span style="font-size:0.72rem;opacity:0.6">${s.angle.toFixed(4)} рад</span>` +
|
||||
`<br><span style="font-size:0.68rem;opacity:0.5">+ 360°·k (котерминальные)</span>`;
|
||||
|
||||
// Опорный (острый) угол — guarded (панель может не иметь элемента)
|
||||
const refEl = document.getElementById('trig-ref');
|
||||
if (refEl) refEl.textContent = (Math.round(s.refDeg * 10) / 10) + '°';
|
||||
// Знаки функций в текущей четверти
|
||||
const signsEl = document.getElementById('trig-signs');
|
||||
if (signsEl) {
|
||||
const sg = v => (v > 1e-9 ? '+' : v < -1e-9 ? '−' : '0');
|
||||
signsEl.innerHTML =
|
||||
`<b style="color:#EF476F">sin ${sg(s.sin)}</b> · <b style="color:#06D6E0">cos ${sg(s.cos)}</b> · ` +
|
||||
`<b style="color:#FFD166">tg ${s.tan === undefined ? '—' : sg(s.tan)}</b>`;
|
||||
}
|
||||
|
||||
// Stats bar (nice fractions)
|
||||
document.getElementById('trigbar-angle').textContent = degStr;
|
||||
|
||||
@@ -506,6 +506,16 @@
|
||||
<!-- left panel -->
|
||||
<div class="proj-panel" style="width:240px;gap:0">
|
||||
|
||||
<!-- Angle input -->
|
||||
<div class="gp-section-title" style="margin-bottom:8px">Угол, °</div>
|
||||
<div style="display:flex;gap:6px;margin-bottom:14px">
|
||||
<input id="trig-angle-input" type="number" step="1" placeholder="напр. 150"
|
||||
onkeydown="trigAngleKey(event,this)"
|
||||
style="flex:1;min-width:0;padding:7px 10px;border:1.5px solid var(--border-h);border-radius:8px;background:#fff;color:var(--text);font-family:'Manrope',sans-serif;font-size:0.82rem;outline:none" />
|
||||
<button class="preset-btn" style="flex-shrink:0;padding:7px 12px" title="Перейти к углу"
|
||||
onclick="trigSetAngleDeg(document.getElementById('trig-angle-input'))"><svg class="ic" viewBox="0 0 24 24" style="width:14px;height:14px"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg></button>
|
||||
</div>
|
||||
|
||||
<!-- Function toggles -->
|
||||
<div class="gp-section-title" style="margin-bottom:10px">Отрезки</div>
|
||||
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
|
||||
@@ -535,9 +545,14 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Graph function selector -->
|
||||
<div class="gp-section-title" style="margin-bottom:8px">График</div>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px">
|
||||
<!-- Graph (functions) — optional, can be hidden to focus on the circle -->
|
||||
<label class="tri-layer-row active" style="margin-bottom:8px" onclick="trigToggleGraph(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-graph-fns" style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px">
|
||||
<button class="trig-fn-btn active" onclick="trigSetGraphFn('sin',this)" style="--fc:#EF476F">sin</button>
|
||||
<button class="trig-fn-btn" onclick="trigSetGraphFn('cos',this)" style="--fc:#06D6E0">cos</button>
|
||||
<button class="trig-fn-btn" onclick="trigSetGraphFn('tan',this)" style="--fc:#FFD166">tg</button>
|
||||
@@ -553,6 +568,16 @@
|
||||
<span class="tri-stat-k" style="color:#7BF5A4">ctg</span><span class="tri-stat-v" id="trig-v-cot">—</span>
|
||||
</div>
|
||||
|
||||
<!-- Reference (acute) angle + signs by quadrant -->
|
||||
<div class="gp-section-title" style="margin-bottom:8px">Опорный угол · знаки</div>
|
||||
<div style="display:flex;flex-direction:column;gap:6px;margin-bottom:14px">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;font-size:0.78rem">
|
||||
<span style="color:var(--text-3)">острый угол к оси</span>
|
||||
<span id="trig-ref" style="font-weight:800;color:var(--violet)">—</span>
|
||||
</div>
|
||||
<div id="trig-signs" style="text-align:center;font-size:0.72rem;color:var(--text-2)">—</div>
|
||||
</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">
|
||||
@@ -562,8 +587,16 @@
|
||||
<button class="preset-btn" onclick="trigGoTo(Math.PI/3)">60°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(Math.PI/2)">90°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(2*Math.PI/3)">120°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(3*Math.PI/4)">135°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(5*Math.PI/6)">150°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(Math.PI)">180°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(7*Math.PI/6)">210°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(5*Math.PI/4)">225°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(4*Math.PI/3)">240°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(3*Math.PI/2)">270°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(5*Math.PI/3)">300°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(7*Math.PI/4)">315°</button>
|
||||
<button class="preset-btn" onclick="trigGoTo(11*Math.PI/6)">330°</button>
|
||||
</div>
|
||||
|
||||
<!-- Angle info -->
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Тригонометрическая окружность — план улучшения (тренажёр темы, без функций)
|
||||
|
||||
Цель: симуляция `frontend/js/labs/trigcircle.js` + панель `frontend/labs-bodies.html` (#sim-trigcircle)
|
||||
покрывает всю школьную тригонометрию НА ОКРУЖНОСТИ. Графики y=f(x) («функции») — вне темы:
|
||||
существующий showGraph оставляем опциональным/скрываемым.
|
||||
|
||||
Архитектура: рукописный canvas-sim (класс TrigCircleSim) + HTML-панель в labs-bodies.html +
|
||||
glue-функции (`_openTrigCircle`, `trigToggle`, `trigGoTo`, `trigReset`, `_trigUpdateUI`) внизу
|
||||
trigcircle.js; регистрация в `_register-all.js` (`trigcircle`). KaTeX, LabFX, _tasks.js доступны.
|
||||
⛔ без eval, без эмодзи (inline SVG .ic), всё аддитивно (не ломать текущий режим).
|
||||
|
||||
## Уже есть
|
||||
Окружность, перетаскиваемая точка, угол °/рад (метки π/6…), sin/cos/tan/cot отрезками (слои),
|
||||
треугольник sin-cos, касательная/котангенс, 16 табличных углов + snap, подсветка четверти,
|
||||
значения дробями (½,√2/2,√3/2,√3/3,√3), stat-bar, опциональный график (= «функции»).
|
||||
|
||||
## Фазы
|
||||
- **Ф1 — Углы и обзор**: тумблер скрыть график (фокус на круге); ввод угла (° и π-доли);
|
||||
полная сетка табличных кнопок (16); опорный (острый) угол; знаки по четвертям в выводе;
|
||||
подсказка котерминальности (+360°k / +2πk).
|
||||
- **Ф2 — Определения / 6 функций**: подписи sin=y, cos=x на осях; слой sec/csc; Пифагор
|
||||
sin²+cos²=1 (гипотенуза=1) с формулой; тумблер «формула значения» (KaTeX).
|
||||
- **Ф3 — Знаки**: режим со знаками +/− sin/cos/tg по четвертям, мнемоника, таблица.
|
||||
- **Ф4 — Особые углы / таблица значений**: оверлей-таблица 0/30/45/60/90… с подсветкой текущего.
|
||||
- **Ф5 — Симметрии и формулы приведения**: чётность (α→−α), приведение (π±α, π/2±α, 2π−α)
|
||||
с анимацией отражения/поворота + KaTeX; период tg/ctg = π.
|
||||
- **Ф6 — Простейшие уравнения**: задаёшь значение → все решения на круге + общая формула
|
||||
(sin α=½ → π/6+2πk, 5π/6+2πk); для tg — шаг π; связка с arcsin/arccos геометрически.
|
||||
- **Ф7 — Два угла (опц.)**: вторая точка β → α±β, формулы сложения.
|
||||
- **Сквозное**: режимы-вкладки (Углы·Определения·Знаки·Особые·Приведение·Уравнения) с краткой
|
||||
теорией и кнопкой «Задание» через _tasks.js; шпаргалка (значения+знаки+тождества+приведение).
|
||||
|
||||
## Проверка каждой фазы
|
||||
node --check; headless-смоук математики (опорный угол, знаки, решения уравнений, приведение)
|
||||
в vm с стабом canvas; коммит+push, без эмодзи, lint.
|
||||
Reference in New Issue
Block a user