feat: планиметрия — интерактивная геометрическая симуляция

- Новый файл frontend/js/labs/geometry.js (~1200 строк):
  GeoEngine (граф объектов с каскадным удалением),
  GeoViewport (система координат math↔canvas, зум/пан),
  GeoSim (полный движок: точки, отрезки, прямые, лучи,
  окружности, треугольники, многоугольники, привязка к сетке
  и точкам, undo/redo, экспорт PNG, classroom sync)
- frontend/lab.html: карточка, ctrl, sim-geometry секция,
  функции geoSetTool/geoToggle/_openGeometry, скрипт-тег
- frontend/admin.html: geometry в ADMIN_SIMS
- backend/src/db/migrate.js: таблицы geometry_tasks,
  geometry_submissions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-04-14 09:40:41 +03:00
parent b946a6a187
commit 35849cf231
4 changed files with 1580 additions and 2 deletions
+32
View File
@@ -2867,3 +2867,35 @@ db.exec(`
PRIMARY KEY (session_id, user_id)
)
`);
// ── Geometry (Planimetry) ────────────────────────────────────────────────────
// Saved geometry constructions (teacher-created tasks/templates)
db.exec(`
CREATE TABLE IF NOT EXISTS geometry_tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
teacher_id INTEGER NOT NULL REFERENCES users(id),
class_id INTEGER REFERENCES classes(id) ON DELETE SET NULL,
title TEXT NOT NULL DEFAULT 'Без названия',
description TEXT DEFAULT '',
state_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
db.exec('CREATE INDEX IF NOT EXISTS idx_geo_tasks_teacher ON geometry_tasks(teacher_id)');
// Student submissions for geometry tasks
db.exec(`
CREATE TABLE IF NOT EXISTS geometry_submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id INTEGER NOT NULL REFERENCES geometry_tasks(id) ON DELETE CASCADE,
student_id INTEGER NOT NULL REFERENCES users(id),
state_json TEXT NOT NULL DEFAULT '{}',
score REAL DEFAULT NULL,
feedback TEXT DEFAULT '',
submitted_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE(task_id, student_id)
)
`);
db.exec('CREATE INDEX IF NOT EXISTS idx_geo_subs_task ON geometry_submissions(task_id)');
db.exec('CREATE INDEX IF NOT EXISTS idx_geo_subs_student ON geometry_submissions(student_id)');