saltylab-firmware/ui/gps_map_panel.html
sl-webui f384cc4810 feat: Robot GPS live map panel (Issue #709 companion)
Adds gps_map_panel.html/css/js — standalone dashboard panel:

- Leaflet.js + OpenStreetMap with dark CSS filter (matches dashboard theme)
- Heading-aware SVG robot marker (orange arrow shows direction of travel)
- Orange breadcrumb trail polyline (up to 2000 pts, CLEAR button)
- FOLLOW mode auto-pan; drag map to switch to FREE mode
- Sidebar: speed (km/h, color-coded), altitude, heading compass rose,
  fix status (0=NO FIX…4=RTK), fix count, lat/lon, trail log
- Exponential backoff auto-reconnect (2s→30s cap)
- Stale detection at 5s for fix + velocity badges

Subscribes via rosbridge to:
  saltybot/gps/fix  std_msgs/String JSON — {lat, lon, alt, stat, t}
  saltybot/gps/vel  std_msgs/String JSON — {spd, hdg, t}

index.html: new GPS MAP card (🛰️, #709) before CAN MONITOR
dashboard.js: gpsWatch subscription + 'gps' panel entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:28:44 -04:00

115 lines
3.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>Saltybot — GPS Map</title>
<link rel="stylesheet" href="gps_map_panel.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/roslib@1.3.0/build/roslib.min.js"></script>
</head>
<body>
<!-- ── Header ── -->
<div id="header">
<div class="logo"><a href="index.html">SALTYBOT</a> — GPS MAP</div>
<div id="conn-bar">
<div id="conn-dot"></div>
<input id="ws-input" type="text" value="ws://localhost:9090" placeholder="ws://robot-ip:9090" />
<button class="hdr-btn" id="btn-connect">CONNECT</button>
<span id="conn-label">Not connected</span>
</div>
</div>
<!-- ── Status bar ── -->
<div id="status-bar">
<span style="color:var(--text-dim);font-size:10px">GPS FIX</span>
<span class="sys-badge badge-stale" id="badge-fix">STALE</span>
<span style="color:var(--text-dim)"></span>
<span style="color:var(--text-dim);font-size:10px">VELOCITY</span>
<span class="sys-badge badge-stale" id="badge-vel">STALE</span>
<span id="last-update">Awaiting data…</span>
</div>
<!-- ── Main ── -->
<div id="main">
<!-- Map -->
<div id="map-wrap">
<div id="map"></div>
<div id="map-controls">
<button class="map-btn active" id="btn-follow">⊙ FOLLOW</button>
<button class="map-btn" id="btn-clear">✕ CLEAR</button>
</div>
</div>
<!-- Sidebar -->
<div id="sidebar">
<!-- Speed -->
<div class="stat-section">
<div class="section-title">Speed</div>
<div class="big-stat">
<div class="big-val" id="val-speed" style="color:#f97316"></div>
<div class="big-unit">km/h</div>
<div class="big-lbl">GROUND SPEED</div>
</div>
</div>
<!-- Altitude + heading -->
<div class="stat-section">
<div class="section-title">Altitude &amp; Heading</div>
<div class="kv-grid">
<div class="kv-cell">
<div class="kv-lbl">ALT m</div>
<div class="kv-val" id="val-alt"></div>
</div>
<div class="kv-cell">
<div class="kv-lbl">HDG °</div>
<div class="kv-val" id="val-hdg"></div>
</div>
</div>
<div id="compass-wrap">
<canvas id="compass-canvas" width="110" height="110"></canvas>
</div>
</div>
<!-- Fix quality -->
<div class="stat-section">
<div class="section-title">Fix Quality</div>
<div class="kv-grid">
<div class="kv-cell">
<div class="kv-lbl">STATUS</div>
<div class="kv-val" id="val-stat"></div>
</div>
<div class="kv-cell">
<div class="kv-lbl">FIXES</div>
<div class="kv-val" id="val-fixes">0</div>
</div>
</div>
<div style="margin-top:8px">
<div class="coord-row">LAT <span class="coord-val" id="val-lat"></span></div>
<div class="coord-row">LON <span class="coord-val" id="val-lon"></span></div>
</div>
</div>
<!-- Trail log -->
<div class="section-title" style="padding:8px 12px 2px">Trail log</div>
<div id="trail-log"></div>
</div>
</div>
<!-- ── Bottom bar ── -->
<div id="bottombar">
<span class="bb-lbl">FIXES</span><span id="bb-fixes">0</span>
<span class="bb-lbl">TRAIL PTS</span><span id="bb-trail">0</span>
<span class="bb-lbl">MSGS</span><span id="bb-msgs">0</span>
<span id="last-msg">No data</span>
</div>
<script src="gps_map_panel.js"></script>
</body>
</html>