Files
67 361c6baa8f feat: add relay-backed web radar sharing
- publish radar state/bootstrap snapshots to an HTTP relay
- add shared waypoint sync through relay APIs and SSE updates
- add remote Caddy/deploy tooling and mock relay push script
- add static POIs, topo-tile availability checks, and tile-load throttling
- add WASM 3D map engine and Python map data-prep pipeline
- update worn clothing reads to include slot metadata
- add grid controls, render perf HUD, and marker/label scaling tweaks
- remove embedded map resource generation in favor of disk/relay maps
2026-06-23 03:11:52 +08:00

248 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DayZ Web Radar</title>
<link rel="stylesheet" href="style.css?v=13">
</head>
<body>
<!-- ── Header bar ─────────────────────────────────────────────────── -->
<header class="app-header" id="appHeader">
<button class="header-btn" id="sidebarToggle" title="Toggle sidebar (Esc)"></button>
<div class="header-server">
<span class="conn-dot" id="connectionDot"></span>
<span class="header-server-name" id="serverBadge">connecting…</span>
</div>
<div class="header-counts">
<button class="count-badge" id="badge-players" data-key="showPlayers" title="Toggle players (P)">P <span></span></button>
<button class="count-badge" id="badge-zombies" data-key="showZombies" title="Toggle zombies (Z)">Z <span></span></button>
<button class="count-badge" id="badge-animals" data-key="showAnimals" title="Toggle animals (A)">A <span></span></button>
<button class="count-badge" id="badge-vehicles" data-key="showVehicles" title="Toggle vehicles (V)">V <span></span></button>
<button class="count-badge" id="badge-bullets" data-key="showBullets" title="Toggle bullets (B)">B <span></span></button>
<button class="count-badge" id="badge-loot" data-key="showLoot" title="Toggle loot (L)">L <span></span></button>
</div>
<button class="header-btn combat-btn" id="combatToggle" title="Combat mode (C)">⚔ Combat</button>
<button class="header-btn mode3d-btn" id="toggle3d" title="3D map mode" disabled>3D</button>
</header>
<!-- ── Sidebar ────────────────────────────────────────────────────── -->
<aside class="sidebar" id="sidebar">
<!-- Tab icons column -->
<nav class="sidebar-nav">
<button class="tab-btn active" data-tab="tab-map" title="Map">🗺</button>
<button class="tab-btn" data-tab="tab-entities" title="Entities">👤</button>
<button class="tab-btn" data-tab="tab-loot" title="Loot">📦</button>
<button class="tab-btn" data-tab="tab-settings" title="Settings"></button>
</nav>
<!-- Tab panels -->
<div class="sidebar-content" id="sidebarContent">
<!-- Tab: Map -------------------------------------------------- -->
<section class="tab-panel active" id="tab-map">
<div class="tab-status-row">
<span id="status" class="status-text">Connecting…</span>
</div>
<div id="serverInfo" class="server-info-text"></div>
<div class="tab-section">
<label class="toggle-row"><input type="checkbox" id="followPlayer"><span>Follow player <kbd>F</kbd></span></label>
<label class="toggle-row"><input type="checkbox" id="showLabels" checked><span>Labels</span></label>
<label class="toggle-row"><input type="checkbox" id="showPOIs" checked><span>Locations</span></label>
<label class="toggle-row"><input type="checkbox" id="showGrid"><span>Grid <kbd>G</kbd></span></label>
<label class="toggle-row"><input type="checkbox" id="showSatmap"><span>Satellite map</span></label>
<label class="toggle-row"><input type="checkbox" id="showDistanceRings"><span>Distance rings</span></label>
<label class="toggle-row"><input type="checkbox" id="showMinimap"><span>Minimap</span></label>
</div>
<div class="tab-section">
<div class="section-label">Distance filter</div>
<div class="range-with-value">
<input type="range" id="distanceFilter" min="0" max="5000" step="50" value="2000">
<span id="distanceValue" class="range-val">2000 m</span>
</div>
</div>
</section>
<!-- Tab: Entities --------------------------------------------- -->
<section class="tab-panel" id="tab-entities">
<div class="preset-bar">
<button class="preset-btn" data-preset="0" title="Load combat preset (1) — Shift+click to overwrite">Combat</button>
<button class="preset-btn" data-preset="1" title="Load loot run preset (2) — Shift+click to overwrite">Loot</button>
<button class="preset-btn" data-preset="2" title="Load full preset (3) — Shift+click to overwrite">Full</button>
<button class="preset-btn" data-preset="3" title="Load custom preset (4) — Shift+click to overwrite">Custom</button>
</div>
<div class="quick-bar">
<button class="quick-btn" id="showAllEntities">All</button>
<button class="quick-btn" id="hideAllEntities">None</button>
</div>
<div id="entityFilterList" class="filter-list"></div>
<div class="tab-section">
<div class="section-label">Players on server</div>
<div class="players-list" id="playersList"></div>
</div>
</section>
<!-- Tab: Loot ------------------------------------------------- -->
<section class="tab-panel" id="tab-loot">
<div class="loot-search-bar">
<input type="search" id="lootSearch" placeholder="Search loot…" autocomplete="off" spellcheck="false">
</div>
<div class="tab-section">
<label class="toggle-row"><input type="checkbox" id="showLoot" checked><span>Show all loot</span></label>
</div>
<div id="lootFilterList" class="filter-list loot-filter-list"></div>
<div class="tab-section">
<div id="lootInfo" class="loot-info-text"></div>
<div class="loot-list" id="lootList"></div>
</div>
</section>
<!-- Tab: Settings --------------------------------------------- -->
<section class="tab-panel" id="tab-settings">
<div class="tab-section">
<div class="section-label">Label placement</div>
<label class="setting-row">
<span class="setting-name">Ordinary loot spread</span>
<span id="ordinaryLootSpreadValue" class="setting-val">2.0x</span>
<input type="range" id="ordinaryLootSpread" min="1" max="4" step="0.1" value="2">
</label>
<label class="setting-row">
<span class="setting-name">Grouped loot spread</span>
<span id="groupedLootSpreadValue" class="setting-val">2.0x</span>
<input type="range" id="groupedLootSpread" min="1" max="4" step="0.1" value="2">
</label>
<label class="setting-row">
<span class="setting-name">Same-name merge radius</span>
<span id="sameLootMergeRadiusValue" class="setting-val">110 px</span>
<input type="range" id="sameLootMergeRadius" min="20" max="240" step="5" value="110">
</label>
<label class="setting-row">
<span class="setting-name">Line anchor</span>
<select id="lineAnchorMode">
<option value="auto-nearest">Auto nearest</option>
<option value="top-left">Top left</option>
<option value="bottom-center">Bottom center</option>
<option value="top-center">Top center</option>
<option value="top-right">Top right</option>
<option value="middle-left">Middle left</option>
<option value="middle-right">Middle right</option>
<option value="bottom-left">Bottom left</option>
<option value="bottom-right">Bottom right</option>
</select>
</label>
<label class="setting-row toggle-row">
<span class="setting-name">Merge same-name loot</span>
<input type="checkbox" id="mergeSameLootLabels" checked>
</label>
<button class="btn-sm" id="labelSettingsReset">Reset defaults</button>
</div>
<div class="tab-section">
<div class="section-label">Default text size</div>
<div class="range-with-value">
<input type="range" id="textSize" min="10" max="24" step="1" value="14">
<span id="textSizeValue" class="range-val">14 px</span>
</div>
</div>
<div class="tab-section">
<div class="section-label">Grid</div>
<label class="setting-row">
<span class="setting-name">Line weight</span>
<span id="gridLineWeightValue" class="setting-val">2.5 px</span>
<input type="range" id="gridLineWeight" min="0.5" max="6" step="0.5" value="2.5">
</label>
<label class="setting-row">
<span class="setting-name">Label size</span>
<span id="gridLabelSizeValue" class="setting-val">13 px</span>
<input type="range" id="gridLabelSize" min="8" max="24" step="1" value="13">
</label>
</div>
<div class="tab-section">
<div class="section-label">Theme</div>
<div class="theme-bar">
<button class="theme-btn active" data-theme="dark">Dark</button>
<button class="theme-btn" data-theme="darker">Darker</button>
<button class="theme-btn" data-theme="solarized">Solarized</button>
</div>
</div>
<div class="tab-section shortcuts-section">
<div class="section-label">Keyboard shortcuts</div>
<div class="shortcut-grid">
<kbd>P</kbd><span>Players</span>
<kbd>Z</kbd><span>Zombies</span>
<kbd>A</kbd><span>Animals</span>
<kbd>V</kbd><span>Vehicles</span>
<kbd>L</kbd><span>Loot</span>
<kbd>B</kbd><span>Bullets</span>
<kbd>C</kbd><span>Combat mode</span>
<kbd>F</kbd><span>Follow player</span>
<kbd>G</kbd><span>Grid overlay</span>
<kbd>M</kbd><span>Measure tool</span>
<kbd>Space</kbd><span>Re-center</span>
<kbd>Esc</kbd><span>Close / cancel</span>
<kbd>14</kbd><span>Load preset</span>
</div>
</div>
</section>
</div><!-- /sidebar-content -->
</aside>
<!-- ── Map viewport ───────────────────────────────────────────────── -->
<main class="viewport" id="viewport">
<!-- 3D canvas — hidden until 3D mode is activated -->
<canvas id="canvas3d"></canvas>
<div class="canvas" id="canvas">
<div id="tiles"></div>
<div id="sat-tiles"></div>
<div id="topo-tiles"></div>
<svg id="paths"></svg>
<div id="itemLabels"></div>
<div id="markers"></div>
</div>
<!-- Minimap (bottom-right corner of viewport) -->
<div class="minimap" id="minimapEl" style="display:none">
<img class="minimap-img" id="minimapImg" alt="">
<canvas class="minimap-canvas" id="minimapCanvas"></canvas>
</div>
<!-- Right-click context menu -->
<div class="ctx-menu" id="ctxMenu">
<button class="ctx-item" id="ctxAddWaypoint">Add waypoint (local)</button>
<button class="ctx-item ctx-item-shared" id="ctxAddSharedWaypoint">Add shared waypoint</button>
<button class="ctx-item" id="ctxCopyCoords">Copy coordinates</button>
</div>
<!-- Screen-space measurement overlay -->
<canvas class="measure-layer" id="measureLayer"></canvas>
</main>
<!-- ── Coord bar ──────────────────────────────────────────────────── -->
<footer class="coord-bar" id="coordBar">
<span id="coordDisplay"></span>
<span class="coord-sep">|</span>
<span id="gridDisplay"></span>
<span class="coord-sep">|</span>
<span id="zoomDisplay"></span>
<span class="coord-bar-spacer"></span>
<button class="measure-toggle-btn" id="measureToggle" title="Measure distance (M)">⟺ Measure</button>
</footer>
<!-- ── Toast notifications ────────────────────────────────────────── -->
<div class="toast-stack" id="toastStack"></div>
<script src="app.js?v=13"></script>
</body>
</html>