const canvas = document.getElementById('graphCanvas'); const ctx = canvas.getContext('2d'); const width = canvas.width; const height = canvas.height; const center = width / 2; // середина — точка (0,0) (150px) const R_PIXELS = 100; // Длина R в пикселях на канвасе для отрисовки // Элементы формы const form = document.getElementById('point-form'); const yInput = document.getElementById('y-input'); const yError = document.getElementById('y-error'); const rHidden = document.getElementById('r-hidden'); const rError = document.getElementById('r-error'); const rButtons = document.querySelectorAll('.r-button'); const checkboxes = document.querySelectorAll('input[name="xval"]'); const submitBtn = document.getElementById('submit-btn'); const globalError = document.getElementById('global-error'); const resultsBody = document.getElementById('results-body'); // Б - безопасность const STORAGE_KEY = 'web_lab1_history'; let history = []; let currentR = null; try { const rawData = JSON.parse(localStorage.getItem(STORAGE_KEY)); if (Array.isArray(rawData)) { // Проверяем LocalStorage (вдруг врёт) history = rawData.filter(rec => { if (typeof rec !== 'object' || rec === null) return false; if (![1, 2, 3, 4, 5].includes(rec.r)) return false; if (![-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2].includes(rec.x)) return false; if (typeof rec.y !== 'number' || isNaN(rec.y) || ((rec.y < -3 || rec.y > 5) && rec.y !== 81)) return false; return true; }); } } catch (e) { history = []; // Миша, всё херня, начинай сначала. } // Пошло поехало window.addEventListener('DOMContentLoaded', () => { renderHistory(); drawGraph(); validateForm(); }); rButtons.forEach(btn => { btn.addEventListener('click', () => { rButtons.forEach(b => b.classList.remove('active')); btn.classList.add('active'); rHidden.value = btn.getAttribute('data-val'); currentR = parseFloat(rHidden.value); rError.textContent = ''; validateForm(); drawGraph(); }); }); checkboxes.forEach(cb => { cb.addEventListener('change', validateForm); }); yInput.addEventListener('input', () => { validateY(); validateForm(); }); function checkHit(x, y, r) { // Первая четверть (X >= 0, Y >= 0): Четверть круга (R) if (x >= 0 && y >= 0) { return (x * x + y * y) <= (r * r); } // Вторая четверть (X <= 0, Y >= 0): Прямоугольник (ширина R, высота R/2) if (x <= 0 && y >= 0) { return x >= -r && y <= (r / 2); } // Третья четверть (X <= 0, Y <= 0): Пустота if (x <= 0 && y <= 0) { return false; } // Четвертая четверть (X >= 0, Y <= 0): Треугольник (проходит через (R, 0) и (0, -R/2)) // Уравнение прямой: y = x/2 - r/2 => точка внутри если y >= x/2 - r/2 if (x >= 0 && y <= 0) { return y >= (x / 2) - (r / 2); } return false; } function validateY() { const valStr = yInput.value.trim().replace(',', '.'); if (valStr === '') { yError.textContent = 'Поле Y обязательно к заполнению.'; return false; } const y = Number(valStr); if (isNaN(y)) { yError.textContent = 'Y должно быть числом (буквы недопустимы).'; return false; } if ((y < -3 || y > 5) && y !== 81) { yError.textContent = 'Значение Y должно принадлежать диапазону от -3 до 5 включительно.'; return false; } yError.textContent = ''; return true; } function validateForm() { let isValid = true; if (!validateY()) isValid = false; const validRValues = [1, 2, 3, 4, 5]; if (!rHidden.value) { rError.textContent = 'Необходимо выбрать значение R.'; isValid = false; } else if (!validRValues.includes(parseFloat(rHidden.value))) { rError.textContent = 'Обнаружена подмена значения R!'; isValid = false; } else { rError.textContent = ''; } const validXValues = [-2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2]; let xChecked = false; let xSpoofed = false; checkboxes.forEach(cb => { if (cb.checked) { xChecked = true; if (!validXValues.includes(parseFloat(cb.value))) { xSpoofed = true; } } }); if (!xChecked) { globalError.textContent = 'Выберите хотя бы одно значение X.'; isValid = false; } else if (xSpoofed) { globalError.textContent = 'Ошибка: передано недопустимое значение X!'; isValid = false; } else { globalError.textContent = ''; } submitBtn.disabled = !isValid; return isValid; } form.addEventListener('submit', (e) => { e.preventDefault(); if (!validateForm()) return; const y = parseFloat(yInput.value.trim().replace(',', '.')); // пасхалка if (y === 81) { const egg = document.getElementById('oscar-easter-egg'); if (egg) { egg.classList.add('show'); setTimeout(() => egg.classList.remove('show'), 1000); } yInput.value = ''; validateForm(); return; } const r = parseFloat(rHidden.value); // Дата, время и тд const dateString = new Date().toLocaleString("ru-RU", { timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone, year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' }); checkboxes.forEach(cb => { if (cb.checked) { const x = parseFloat(cb.value); const hit = checkHit(x, y, r); history.push({ x: x, y: y, r: r, hit: hit, time: dateString }); } }); localStorage.setItem(STORAGE_KEY, JSON.stringify(history)); renderHistory(); drawGraph(); }); function renderHistory() { resultsBody.innerHTML = ''; [...history].reverse().forEach(rec => { const tr = document.createElement('tr'); tr.innerHTML = `