cleaning
This commit is contained in:
@@ -24,6 +24,10 @@
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
-1
|
||||
],
|
||||
[
|
||||
0,
|
||||
-1
|
||||
|
||||
@@ -8,75 +8,80 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🏁 Редактор карт</h1>
|
||||
<p class="subtitle">Гонки на бумаге / Paper Racing</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="editor.html">🏁 Редактор карт</a>
|
||||
<a href="player.html">🎬 Визуализатор решений</a>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
<h3>📐 Размеры карты</h3>
|
||||
<div class="size-inputs">
|
||||
<div class="input-wrapper">
|
||||
<label for="width">Ширина:</label>
|
||||
<input type="number" id="width" min="5" max="100" value="15">
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="height">Высота:</label>
|
||||
<input type="number" id="height" min="5" max="100" value="15">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="btn-primary" onclick="resizeMap()">Применить</button>
|
||||
<button class="btn-danger" onclick="clearMap()">Очистить</button>
|
||||
</div>
|
||||
<div class="header">
|
||||
<div class="header-title">
|
||||
<h1>🏁 Гонки на бумаге</h1>
|
||||
<p class="subtitle">Редактор карт</p>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>🎨 Тип ячейки</h3>
|
||||
<div class="palette">
|
||||
<div class="cell-type road active" data-type="0" onclick="selectCellType(0)">
|
||||
<span>Дорога</span>
|
||||
<span class="code">(0)</span>
|
||||
</div>
|
||||
<div class="cell-type stone" data-type="1" onclick="selectCellType(1)">
|
||||
<span>Камень</span>
|
||||
<span class="code">(1)</span>
|
||||
</div>
|
||||
<div class="cell-type snow" data-type="2" onclick="selectCellType(2)">
|
||||
<span>Снег</span>
|
||||
<span class="code">(2)</span>
|
||||
</div>
|
||||
<div class="cell-type ice" data-type="3" onclick="selectCellType(3)">
|
||||
<span>Лёд</span>
|
||||
<span class="code">(3)</span>
|
||||
</div>
|
||||
<div class="cell-type checkpoint" data-type="4" onclick="selectCellType(4)">
|
||||
<span>Чекпоинт</span>
|
||||
<span class="code">(4)</span>
|
||||
</div>
|
||||
<div class="cell-type start" data-type="5" onclick="selectCellType(5)">
|
||||
<span>Старт</span>
|
||||
<span class="code">(5)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>💾 Импорт / Экспорт</h3>
|
||||
<div class="buttons">
|
||||
<button class="btn-success" onclick="exportMap()">📥 Экспорт JSON</button>
|
||||
<button class="btn-warning" onclick="document.getElementById('fileInput').click()">📤 Импорт JSON</button>
|
||||
</div>
|
||||
<input type="file" id="fileInput" accept=".json" onchange="importMap(event)">
|
||||
<div class="nav-links">
|
||||
<a href="editor.html" class="active">🏁 Редактор карт</a>
|
||||
<a href="player.html">🎬 Визуализатор решений</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="canvas-wrapper">
|
||||
<canvas id="mapCanvas"></canvas>
|
||||
<div class="main-content">
|
||||
<div class="sidebar">
|
||||
<div class="control-group">
|
||||
<h3>📐 Размеры карты</h3>
|
||||
<div class="size-inputs">
|
||||
<div class="input-wrapper">
|
||||
<label for="width">Ширина:</label>
|
||||
<input type="number" id="width" min="5" max="1000" value="15">
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="height">Высота:</label>
|
||||
<input type="number" id="height" min="5" max="1000" value="15">
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="btn-primary" onclick="resizeMap()">Применить</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>💾 Импорт / Экспорт</h3>
|
||||
<div class="buttons">
|
||||
<button class="btn-success" onclick="exportMap()">📥 Экспорт JSON</button>
|
||||
<button class="btn-success" onclick="document.getElementById('fileInput').click()">📤 Импорт JSON</button>
|
||||
<button class="btn-danger" onclick="clearMap()">Очистить</button>
|
||||
</div>
|
||||
<input type="file" id="fileInput" accept=".json" onchange="importMap(event)">
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>🎨 Тип ячейки</h3>
|
||||
<div class="palette">
|
||||
<div class="cell-type road active" data-type="0" onclick="selectCellType(0)">
|
||||
<span>Дорога</span>
|
||||
<span class="code">(0)</span>
|
||||
</div>
|
||||
<div class="cell-type stone" data-type="1" onclick="selectCellType(1)">
|
||||
<span>Камень</span>
|
||||
<span class="code">(1)</span>
|
||||
</div>
|
||||
<div class="cell-type snow" data-type="2" onclick="selectCellType(2)">
|
||||
<span>Снег</span>
|
||||
<span class="code">(2)</span>
|
||||
</div>
|
||||
<div class="cell-type ice" data-type="3" onclick="selectCellType(3)">
|
||||
<span>Лёд</span>
|
||||
<span class="code">(3)</span>
|
||||
</div>
|
||||
<div class="cell-type checkpoint" data-type="4" onclick="selectCellType(4)">
|
||||
<span>Чекпоинт</span>
|
||||
<span class="code">(4)</span>
|
||||
</div>
|
||||
<div class="cell-type start" data-type="5" onclick="selectCellType(5)">
|
||||
<span>Старт</span>
|
||||
<span class="code">(5)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="canvas-wrapper">
|
||||
<canvas id="mapCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
@@ -86,36 +91,6 @@
|
||||
• Экспортируйте карту в JSON для использования в игре<br>
|
||||
• Для визуализации решений используйте <a href="player.html" style="color: #0d47a1; font-weight: bold;">Визуализатор решений</a>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>📖 Легенда цветов</h3>
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<div class="legend-color road"></div>
|
||||
<span>Дорога (0)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color stone"></div>
|
||||
<span>Камень (1)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color snow"></div>
|
||||
<span>Снег (2)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color ice"></div>
|
||||
<span>Лёд (3)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color checkpoint"></div>
|
||||
<span>Чекпоинт (4)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color start"></div>
|
||||
<span>Старт (5)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="common.js"></script>
|
||||
|
||||
@@ -8,64 +8,105 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🎬 Визуализатор решений</h1>
|
||||
<p class="subtitle">Гонки на бумаге / Paper Racing</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="editor.html">🏁 Редактор карт</a>
|
||||
<a href="player.html">🎬 Визуализатор решений</a>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<div class="control-group">
|
||||
<h3>📂 Загрузка файлов</h3>
|
||||
<div class="buttons">
|
||||
<button class="btn-primary" id="loadMapBtn" onclick="document.getElementById('mapInput').click()">📂 Загрузить карту</button>
|
||||
<button class="btn-success" id="loadSolutionBtn" onclick="document.getElementById('solutionInput').click()">🎬 Загрузить решение</button>
|
||||
</div>
|
||||
<input type="file" id="mapInput" accept=".json" onchange="loadMap(event)">
|
||||
<input type="file" id="solutionInput" accept=".json" onchange="loadSolution(event)">
|
||||
<div class="header">
|
||||
<div class="header-title">
|
||||
<h1>🎬 Гонки на бумаге</h1>
|
||||
<p class="subtitle">Визуализатор решений</p>
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<a href="editor.html">🏁 Редактор карт</a>
|
||||
<a href="player.html" class="active">🎬 Визуализатор решений</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="canvas-wrapper">
|
||||
<canvas id="mapCanvas"></canvas>
|
||||
</div>
|
||||
<div class="main-content">
|
||||
<div class="sidebar">
|
||||
<div class="control-group">
|
||||
<h3>📂 Загрузка файлов</h3>
|
||||
<div class="buttons">
|
||||
<button class="btn-primary" id="loadMapBtn" onclick="document.getElementById('mapInput').click()">📂 Загрузить карту</button>
|
||||
<button class="btn-success" id="loadSolutionBtn" onclick="document.getElementById('solutionInput').click()">🎬 Загрузить решение</button>
|
||||
</div>
|
||||
<input type="file" id="mapInput" accept=".json" onchange="loadMap(event)">
|
||||
<input type="file" id="solutionInput" accept=".json" onchange="loadSolution(event)">
|
||||
</div>
|
||||
|
||||
<div id="playbackControls" class="visualization-panel hidden">
|
||||
<h3>🎮 Управление воспроизведением</h3>
|
||||
|
||||
<div class="playback-controls">
|
||||
<button class="playback-btn" onclick="playVisualization()" id="playBtn">▶ Play</button>
|
||||
<button class="playback-btn" onclick="pauseVisualization()" id="pauseBtn" disabled>⏸ Pause</button>
|
||||
<button class="playback-btn" onclick="resetVisualization()">⏮ Reset</button>
|
||||
<button class="playback-btn" onclick="stepBackward()">⏪ Back</button>
|
||||
<button class="playback-btn" onclick="stepForward()">⏩ Forward</button>
|
||||
|
||||
<div class="speed-control">
|
||||
<label for="speedSlider">Скорость:</label>
|
||||
<input type="range" id="speedSlider" min="1" max="10" value="5" onchange="updateSpeed()">
|
||||
<span id="speedValue">5x</span>
|
||||
<div id="playbackControls" class="visualization-panel">
|
||||
<h3>🎮 Управление воспроизведением</h3>
|
||||
|
||||
<div class="playback-controls">
|
||||
<button class="playback-btn" onclick="playVisualization()" id="playBtn" disabled>▶ Воспроизвести</button>
|
||||
<button class="playback-btn" onclick="pauseVisualization()" id="pauseBtn" disabled>⏸ Пауза</button>
|
||||
<button class="playback-btn" onclick="resetVisualization()" id="resetBtn" disabled>⏮ Сброс</button>
|
||||
<button class="playback-btn" onclick="stepBackward()" id="backBtn" disabled>⏪ Назад</button>
|
||||
<button class="playback-btn" onclick="stepForward()" id="forwardBtn" disabled>⏩ Вперёд</button>
|
||||
|
||||
<div class="speed-control">
|
||||
<div class="speed-control-header">
|
||||
<label for="speedSlider">Скорость:</label>
|
||||
<span id="speedValue">5x</span>
|
||||
</div>
|
||||
<input type="range" id="speedSlider" min="1" max="10" value="5" onchange="updateSpeed()" disabled>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="stepInfo" class="step-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">Шаг</span>
|
||||
<span class="info-value" id="stepNumber">0 / 0</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Позиция (x, y)</span>
|
||||
<span class="info-value" id="positionValue">(0, 0)</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Скорость (vx, vy)</span>
|
||||
<span class="info-value" id="velocityValue">(0, 0)</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Ускорение (ax, ay)</span>
|
||||
<span class="info-value" id="accelerationValue">(0, 0)</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Очки</span>
|
||||
<span class="info-value" id="scoreValue">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>📖 Легенда цветов</h3>
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<div class="legend-color road"></div>
|
||||
<span>Дорога (0)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color stone"></div>
|
||||
<span>Камень (1)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color snow"></div>
|
||||
<span>Снег (2)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color ice"></div>
|
||||
<span>Лёд (3)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color checkpoint"></div>
|
||||
<span>Чекпоинт (4)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color start"></div>
|
||||
<span>Старт (5)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="stepInfo" class="step-info hidden">
|
||||
<div class="info-item">
|
||||
<span class="info-label">Шаг</span>
|
||||
<span class="info-value" id="stepNumber">0 / 0</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Позиция (x, y)</span>
|
||||
<span class="info-value" id="positionValue">(0, 0)</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Скорость (vx, vy)</span>
|
||||
<span class="info-value" id="velocityValue">(0, 0)</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Ускорение (ax, ay)</span>
|
||||
<span class="info-value" id="accelerationValue">(0, 0)</span>
|
||||
<div class="canvas-wrapper">
|
||||
<canvas id="mapCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -78,36 +119,6 @@
|
||||
• 🔴 Красный круг - текущая позиция<br>
|
||||
• ➡️ Красная стрелка - направление и скорость движения
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<h3>📖 Легенда цветов</h3>
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<div class="legend-color road"></div>
|
||||
<span>Дорога (0)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color stone"></div>
|
||||
<span>Камень (1)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color snow"></div>
|
||||
<span>Снег (2)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color ice"></div>
|
||||
<span>Лёд (3)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color checkpoint"></div>
|
||||
<span>Чекпоинт (4)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color start"></div>
|
||||
<span>Старт (5)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="common.js"></script>
|
||||
|
||||
@@ -26,6 +26,8 @@ function init() {
|
||||
initMap();
|
||||
resizeCanvas();
|
||||
drawMap();
|
||||
updateControlsState();
|
||||
updateStepInfo();
|
||||
}
|
||||
|
||||
// Инициализация пустой карты
|
||||
@@ -148,9 +150,11 @@ function simulateTrajectory(accelerations, start) {
|
||||
let y = start.y;
|
||||
let vx = 0;
|
||||
let vy = 0;
|
||||
let passedCheckpoints = new Set();
|
||||
let totalSteps = accelerations.length;
|
||||
|
||||
// Начальная позиция
|
||||
traj.push({ x, y, vx, vy, ax: 0, ay: 0 });
|
||||
traj.push({ x, y, vx, vy, ax: 0, ay: 0, passedCheckpoints: 0, score: 0 });
|
||||
|
||||
// Применяем каждое ускорение
|
||||
for (let i = 0; i < accelerations.length; i++) {
|
||||
@@ -164,7 +168,21 @@ function simulateTrajectory(accelerations, start) {
|
||||
x += vx;
|
||||
y += vy;
|
||||
|
||||
traj.push({ x, y, vx, vy, ax, ay });
|
||||
// Проверяем, попали ли на чекпоинт
|
||||
const checkpointKey = `${Math.floor(x)},${Math.floor(y)}`;
|
||||
if (map[Math.floor(y)] && map[Math.floor(y)][Math.floor(x)] === 4) {
|
||||
passedCheckpoints.add(checkpointKey);
|
||||
}
|
||||
|
||||
// Вычисляем очки по формуле: 100 * количество пройденных чекпоинтов ^ 1.3 / количество шагов
|
||||
const checkpointCount = passedCheckpoints.size;
|
||||
const score = totalSteps > 0 ? Math.round(100 * Math.pow(checkpointCount, 1.3) / totalSteps) : 0;
|
||||
|
||||
traj.push({
|
||||
x, y, vx, vy, ax, ay,
|
||||
passedCheckpoints: checkpointCount,
|
||||
score: score
|
||||
});
|
||||
}
|
||||
|
||||
return traj;
|
||||
@@ -237,11 +255,8 @@ function loadSolution(event) {
|
||||
trajectory = simulateTrajectory(solution, startPosition);
|
||||
currentStep = 0;
|
||||
|
||||
// Показываем панель визуализации
|
||||
document.getElementById('playbackControls').classList.remove('hidden');
|
||||
document.getElementById('stepInfo').classList.remove('hidden');
|
||||
|
||||
// Обновляем информацию
|
||||
// Обновляем состояние кнопок и информацию
|
||||
updateControlsState();
|
||||
updateStepInfo();
|
||||
drawMap();
|
||||
|
||||
@@ -261,9 +276,28 @@ function loadSolution(event) {
|
||||
event.target.value = '';
|
||||
}
|
||||
|
||||
// Обновление состояния элементов управления
|
||||
function updateControlsState() {
|
||||
const hasTrajectory = trajectory && trajectory.length > 0;
|
||||
|
||||
document.getElementById('playBtn').disabled = !hasTrajectory;
|
||||
document.getElementById('pauseBtn').disabled = !hasTrajectory || !isPlaying;
|
||||
document.getElementById('resetBtn').disabled = !hasTrajectory;
|
||||
document.getElementById('backBtn').disabled = !hasTrajectory;
|
||||
document.getElementById('forwardBtn').disabled = !hasTrajectory;
|
||||
document.getElementById('speedSlider').disabled = !hasTrajectory;
|
||||
}
|
||||
|
||||
// Обновление информации о текущем шаге
|
||||
function updateStepInfo() {
|
||||
if (!trajectory || trajectory.length === 0) return;
|
||||
if (!trajectory || trajectory.length === 0) {
|
||||
document.getElementById('stepNumber').textContent = '0 / 0';
|
||||
document.getElementById('positionValue').textContent = '(0, 0)';
|
||||
document.getElementById('velocityValue').textContent = '(0, 0)';
|
||||
document.getElementById('accelerationValue').textContent = '(0, 0)';
|
||||
document.getElementById('scoreValue').textContent = '0';
|
||||
return;
|
||||
}
|
||||
|
||||
const current = trajectory[currentStep];
|
||||
|
||||
@@ -271,6 +305,7 @@ function updateStepInfo() {
|
||||
document.getElementById('positionValue').textContent = `(${current.x}, ${current.y})`;
|
||||
document.getElementById('velocityValue').textContent = `(${current.vx}, ${current.vy})`;
|
||||
document.getElementById('accelerationValue').textContent = `(${current.ax}, ${current.ay})`;
|
||||
document.getElementById('scoreValue').textContent = current.score || 0;
|
||||
}
|
||||
|
||||
// Воспроизведение визуализации
|
||||
@@ -278,8 +313,7 @@ function playVisualization() {
|
||||
if (!trajectory || trajectory.length === 0) return;
|
||||
|
||||
isPlaying = true;
|
||||
document.getElementById('playBtn').disabled = true;
|
||||
document.getElementById('pauseBtn').disabled = false;
|
||||
updateControlsState();
|
||||
|
||||
playbackInterval = setInterval(() => {
|
||||
if (currentStep < trajectory.length - 1) {
|
||||
@@ -295,8 +329,7 @@ function playVisualization() {
|
||||
// Пауза воспроизведения
|
||||
function pauseVisualization() {
|
||||
isPlaying = false;
|
||||
document.getElementById('playBtn').disabled = false;
|
||||
document.getElementById('pauseBtn').disabled = true;
|
||||
updateControlsState();
|
||||
|
||||
if (playbackInterval) {
|
||||
clearInterval(playbackInterval);
|
||||
@@ -354,9 +387,8 @@ function clearVisualization() {
|
||||
currentStep = 0;
|
||||
startPosition = null;
|
||||
|
||||
document.getElementById('playbackControls').classList.add('hidden');
|
||||
document.getElementById('stepInfo').classList.add('hidden');
|
||||
|
||||
updateControlsState();
|
||||
updateStepInfo();
|
||||
drawMap();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,77 +18,100 @@ body {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
padding: 30px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: calc(100vh - 40px);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 10px;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 2em;
|
||||
margin-bottom: 2px;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.9em;
|
||||
font-size: 0.8em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
margin: 0 15px;
|
||||
padding: 10px 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
background: #e9ecef;
|
||||
color: #495057;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
display: inline-block;
|
||||
font-size: 0.9em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: #dee2e6;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
.nav-links a.active {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
box-shadow: 0 3px 10px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.nav-links a.active:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.5);
|
||||
}
|
||||
|
||||
.control-group {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
border: 2px solid #e9ecef;
|
||||
}
|
||||
|
||||
.sidebar .control-group {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.control-group h3 {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 12px;
|
||||
color: #495057;
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
padding-bottom: 8px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.size-inputs {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
gap: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@@ -119,38 +142,39 @@ h1 {
|
||||
}
|
||||
|
||||
.palette {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
gap: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.cell-type {
|
||||
padding: 15px;
|
||||
border: 3px solid #dee2e6;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
border: 2px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cell-type:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
transform: translateX(-3px);
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.cell-type.active {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
|
||||
transform: scale(1.05);
|
||||
border-width: 3px;
|
||||
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.cell-type .code {
|
||||
font-size: 0.8em;
|
||||
font-size: 0.75em;
|
||||
color: #6c757d;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.road { background: #f8f9fa; color: #495057; }
|
||||
@@ -166,6 +190,14 @@ h1 {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sidebar .buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar .buttons button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 12px 24px;
|
||||
@@ -213,22 +245,55 @@ button:disabled {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 15px;
|
||||
flex: 1;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.canvas-wrapper {
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
min-height: 1000px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
flex-shrink: 0;
|
||||
overflow-y: auto;
|
||||
max-height: 100%;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-thumb {
|
||||
background: #667eea;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
canvas {
|
||||
border: 3px solid #dee2e6;
|
||||
border: 2px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
cursor: crosshair;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
|
||||
@@ -237,12 +302,13 @@ canvas {
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
margin-top: 15px;
|
||||
padding: 12px;
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #2196f3;
|
||||
border-radius: 8px;
|
||||
color: #0d47a1;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.info strong {
|
||||
@@ -261,42 +327,49 @@ canvas {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.sidebar .legend {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
gap: 8px;
|
||||
padding: 6px;
|
||||
background: white;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 4px;
|
||||
border: 2px solid #dee2e6;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Стили для визуализатора */
|
||||
.playback-controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.playback-btn {
|
||||
padding: 10px 20px;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
min-width: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.playback-btn:hover {
|
||||
@@ -312,20 +385,44 @@ canvas {
|
||||
|
||||
.speed-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.speed-control-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.speed-control input[type="range"] {
|
||||
width: 150px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.speed-control input[type="range"]:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.speed-control label {
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.speed-control #speedValue {
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.step-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 15px;
|
||||
padding: 15px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
}
|
||||
@@ -342,7 +439,7 @@ canvas {
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 1.2em;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
@@ -352,15 +449,15 @@ canvas {
|
||||
}
|
||||
|
||||
.visualization-panel {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12px;
|
||||
border: 2px solid #dee2e6;
|
||||
}
|
||||
|
||||
.visualization-panel h3 {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 10px;
|
||||
color: #495057;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user