feat: режим аннотации поверх симуляции в онлайн-уроке + fix планиметрии (arcmark, triangle tools)
Онлайн-урок: - Кнопка «Рисовать» в баре симуляции (только учителю) - При активации: холст доски показывается поверх iframe (z-index), фон прозрачный - Учитель рисует прямо поверх симуляции обычными инструментами - Студенты видят то же самое через SSE (classroom_sim_annotate) - Выход из режима → кнопка «Вернуться к симуляции» Планиметрия (bugfix): - arcmark теперь рисуется всегда (не зависит от showAngles) - altitude/median: 1 клик на вершину треугольника (авто-находит противоположную сторону) - centroid/orthocenter: 1 клик внутри/на треугольник Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2007,6 +2007,55 @@
|
||||
background: #0D0D1A;
|
||||
}
|
||||
|
||||
/* ── Annotate-over-sim mode ───────────────────────────────────────────── */
|
||||
/* Board floats above the sim panel (sim visible behind transparent canvas) */
|
||||
.cr-board-area.annotate-active .cr-sim-panel { z-index: 1; }
|
||||
.cr-board-area.annotate-active .cr-board-wrap {
|
||||
z-index: 45;
|
||||
background: transparent !important;
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.cr-board-area.annotate-active .cr-board-wrap::before,
|
||||
.cr-board-area.annotate-active .cr-board-wrap::after { display: none !important; }
|
||||
/* Floating bar shown while annotating */
|
||||
.cr-annotate-bar {
|
||||
display: none;
|
||||
position: absolute; top: 0; left: 0; right: 0; z-index: 60;
|
||||
height: 40px; flex-shrink: 0;
|
||||
background: rgba(10,6,22,0.92);
|
||||
border-bottom: 1.5px solid rgba(241,91,181,0.4);
|
||||
backdrop-filter: blur(6px);
|
||||
align-items: center; gap: 8px; padding: 0 12px;
|
||||
}
|
||||
.cr-board-area.annotate-active .cr-annotate-bar { display: flex; }
|
||||
.cr-annotate-bar-label {
|
||||
font-size: 0.75rem; font-weight: 700; color: #F15BB5;
|
||||
display: flex; align-items: center; gap: 5px; flex: 1;
|
||||
}
|
||||
.cr-annotate-bar-label svg { width: 14px; height: 14px; stroke: #F15BB5; }
|
||||
.cr-annotate-exit {
|
||||
padding: 4px 12px; border-radius: 7px; border: 1px solid rgba(241,91,181,0.4);
|
||||
background: rgba(241,91,181,0.1); color: #F15BB5;
|
||||
font-family: 'Manrope',sans-serif; font-size: 0.72rem; font-weight: 700;
|
||||
cursor: pointer; transition: all .15s;
|
||||
}
|
||||
.cr-annotate-exit:hover { background: rgba(241,91,181,0.22); }
|
||||
/* "Draw" button in sim bar */
|
||||
.cr-sim-annotate-btn {
|
||||
display: none;
|
||||
padding: 3px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.12);
|
||||
background: transparent; color: rgba(255,255,255,0.5);
|
||||
font-family: 'Manrope',sans-serif; font-size: 0.7rem; font-weight: 700;
|
||||
cursor: pointer; transition: all .15s; align-items: center; gap: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.cr-sim-annotate-btn svg { width: 12px; height: 12px; flex-shrink: 0; }
|
||||
.cr-sim-annotate-btn:hover { color: rgba(255,255,255,0.8); border-color: rgba(241,91,181,0.4); }
|
||||
.cr-sim-annotate-btn.active { background: rgba(241,91,181,0.18); border-color: rgba(241,91,181,0.5); color: #F15BB5; }
|
||||
/* Show draw button only for teachers when sim is open */
|
||||
.cr-sim-panel.open .cr-sim-annotate-btn.teacher-ctrl { display: flex; }
|
||||
|
||||
/* ── Simulation picker modal ────────────────────────────────────────── */
|
||||
.cr-sim-picker-overlay {
|
||||
position: fixed; inset: 0; z-index: 200;
|
||||
@@ -2202,6 +2251,11 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18"/></svg>
|
||||
</div>
|
||||
<span class="cr-sim-bar-title" id="cr-sim-bar-title">Симуляция</span>
|
||||
<!-- Draw-over button (teacher only) -->
|
||||
<button class="cr-sim-annotate-btn teacher-ctrl" id="cr-sim-annotate-btn" onclick="crToggleAnnotate()" title="Рисовать поверх симуляции">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||||
Рисовать
|
||||
</button>
|
||||
<!-- Mode toggle (teacher only) -->
|
||||
<div class="cr-sim-mode" id="cr-sim-mode-toggle" style="display:none">
|
||||
<button class="cr-sim-mode-btn active" id="cr-sim-mode-demo" onclick="crSetSimMode('demo')" title="Все видят одно и то же">Демо</button>
|
||||
@@ -2215,6 +2269,14 @@
|
||||
<!-- Blocks student interaction in demo mode -->
|
||||
<div class="cr-sim-blocker" id="cr-sim-blocker"></div>
|
||||
</div>
|
||||
<!-- Annotate-mode floating bar (shown on top of sim when drawing) -->
|
||||
<div class="cr-annotate-bar" id="cr-annotate-bar">
|
||||
<span class="cr-annotate-bar-label">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||||
Режим аннотации
|
||||
</span>
|
||||
<button class="cr-annotate-exit" id="cr-annotate-exit-btn" onclick="crToggleAnnotate()">Вернуться к симуляции</button>
|
||||
</div>
|
||||
</div><!-- /.cr-board-area -->
|
||||
<!-- student nav: page nav + follow toggle -->
|
||||
<div class="cr-student-nav" id="cr-student-nav" style="display:none">
|
||||
@@ -3600,6 +3662,8 @@
|
||||
}
|
||||
} else if (data.type === 'classroom_sim_mode') {
|
||||
if (_sessionId == data.sessionId) onSimModeChange(data.mode);
|
||||
} else if (data.type === 'classroom_sim_annotate') {
|
||||
if (_sessionId == data.sessionId) _crApplyAnnotate(data.active);
|
||||
} else if (data.type === '_sse_reconnect') {
|
||||
// SSE reconnected after a drop — re-sync all real-time state to fill the gap
|
||||
if (_sessionId) resyncAfterReconnect();
|
||||
@@ -6867,6 +6931,9 @@
|
||||
const modeToggle = document.getElementById('cr-sim-mode-toggle');
|
||||
const blocker = document.getElementById('cr-sim-blocker');
|
||||
|
||||
// Exit annotate mode when sim closes
|
||||
if (_annotateActive) _crApplyAnnotate(false);
|
||||
|
||||
panel.classList.remove('open');
|
||||
if (modeToggle) modeToggle.style.display = 'none';
|
||||
if (blocker) blocker.classList.remove('active');
|
||||
@@ -6882,6 +6949,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
let _annotateActive = false;
|
||||
let _annotateTool = 'pencil'; // saved tool before entering annotate mode
|
||||
|
||||
async function crToggleAnnotate() {
|
||||
if (!_simActive) return;
|
||||
const isTeacher = _me && (_me.role === 'teacher' || _me.role === 'admin');
|
||||
const newVal = !_annotateActive;
|
||||
_crApplyAnnotate(newVal);
|
||||
// Only teacher broadcasts to students
|
||||
if (isTeacher && _sessionId) {
|
||||
try {
|
||||
await LS.post(`/api/classroom/${_sessionId}/sim/annotate`, { active: newVal });
|
||||
} catch (e) { /* non-critical */ }
|
||||
}
|
||||
}
|
||||
|
||||
function _crApplyAnnotate(active) {
|
||||
_annotateActive = active;
|
||||
const boardArea = document.getElementById('cr-board-area');
|
||||
const simBtn = document.getElementById('cr-sim-annotate-btn');
|
||||
const isTeacher = _me && (_me.role === 'teacher' || _me.role === 'admin');
|
||||
|
||||
boardArea?.classList.toggle('annotate-active', active);
|
||||
if (simBtn) simBtn.classList.toggle('active', active);
|
||||
|
||||
if (!_wb) return;
|
||||
_wb.setAnnotateMode(active);
|
||||
if (active) {
|
||||
// Remember current tool, switch to pencil for drawing
|
||||
_annotateTool = _wb._currentTool || 'pencil';
|
||||
if (isTeacher) {
|
||||
_wb.setTool('pencil');
|
||||
document.querySelectorAll('.cr-tool-btn').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById('cr-tool-pencil')?.classList.add('active');
|
||||
}
|
||||
} else {
|
||||
// Restore previous tool
|
||||
if (isTeacher) {
|
||||
_wb.setTool(_annotateTool);
|
||||
document.getElementById(`cr-tool-${_annotateTool}`)?.classList.add('active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function crSetSimMode(mode) {
|
||||
if (!_sessionId) return;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user