Skip to content

Commit 7f4db6c

Browse files
AminTaheri23claude
authored andcommitted
feat: add collapsible map legend and reduce info panel opacity
Adds a context-sensitive legend to the info panel showing vehicle type color swatches in realtime/lines mode and a density gradient bar in heatmap mode. Includes a collapse toggle arrow and reduces panel background opacity from 0.85 to 0.65. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 940f0a2 commit 7f4db6c

1 file changed

Lines changed: 109 additions & 1 deletion

File tree

src/where_the_plow/static/index.html

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
position: absolute;
2323
top: 12px;
2424
right: 12px;
25-
background: rgba(20, 20, 30, 0.85);
25+
background: rgba(20, 20, 30, 0.65);
2626
color: #e5e7eb;
2727
padding: 14px 18px;
2828
border-radius: 8px;
@@ -172,6 +172,79 @@
172172
#coverage-view-toggle button:hover:not(.active) {
173173
background: rgba(255,255,255,0.05);
174174
}
175+
#legend {
176+
margin-top: 12px;
177+
padding-top: 10px;
178+
border-top: 1px solid rgba(255,255,255,0.1);
179+
}
180+
#legend-header {
181+
display: flex;
182+
align-items: center;
183+
justify-content: space-between;
184+
margin-bottom: 6px;
185+
}
186+
#legend-header .legend-title {
187+
margin-bottom: 0;
188+
}
189+
#legend-toggle {
190+
background: none;
191+
border: none;
192+
color: #9ca3af;
193+
cursor: pointer;
194+
padding: 0;
195+
font-size: 0.75rem;
196+
line-height: 1;
197+
transition: color 0.15s, transform 0.2s;
198+
display: flex;
199+
align-items: center;
200+
}
201+
#legend-toggle:hover {
202+
color: #e5e7eb;
203+
}
204+
#legend-toggle.collapsed {
205+
transform: rotate(-180deg);
206+
}
207+
#legend-body {
208+
overflow: hidden;
209+
transition: opacity 0.2s;
210+
}
211+
#legend-body.collapsed {
212+
display: none;
213+
}
214+
.legend-title {
215+
font-size: 0.7rem;
216+
text-transform: uppercase;
217+
letter-spacing: 0.05em;
218+
color: #9ca3af;
219+
margin-bottom: 6px;
220+
}
221+
.legend-row {
222+
display: flex;
223+
align-items: center;
224+
gap: 7px;
225+
font-size: 0.78rem;
226+
color: #e5e7eb;
227+
margin-bottom: 4px;
228+
}
229+
.legend-swatch {
230+
width: 12px;
231+
height: 12px;
232+
border-radius: 50%;
233+
flex-shrink: 0;
234+
}
235+
.legend-gradient {
236+
height: 10px;
237+
border-radius: 4px;
238+
background: linear-gradient(to right,
239+
#2563eb, #60a5fa, #fbbf24, #f97316, #ef4444);
240+
margin-bottom: 3px;
241+
}
242+
.legend-gradient-labels {
243+
display: flex;
244+
justify-content: space-between;
245+
font-size: 0.72rem;
246+
color: #9ca3af;
247+
}
175248
</style>
176249
</head>
177250
<body>
@@ -203,6 +276,26 @@ <h3>Where the Plow</h3>
203276
<input type="range" id="time-slider" min="0" max="1000" value="1000" />
204277
<div id="coverage-loading">Loading coverage data...</div>
205278
</div>
279+
<div id="legend">
280+
<div id="legend-header">
281+
<div class="legend-title">Legend</div>
282+
<button id="legend-toggle" title="Collapse legend">&#9650;</button>
283+
</div>
284+
<div id="legend-body">
285+
<div id="legend-vehicles">
286+
<div class="legend-row"><span class="legend-swatch" style="background:#2563eb"></span>Plow truck</div>
287+
<div class="legend-row"><span class="legend-swatch" style="background:#ea580c"></span>Loader</div>
288+
<div class="legend-row"><span class="legend-swatch" style="background:#16a34a"></span>Grader</div>
289+
<div class="legend-row"><span class="legend-swatch" style="background:#6b7280"></span>Other</div>
290+
</div>
291+
<div id="legend-heatmap" style="display:none">
292+
<div class="legend-gradient"></div>
293+
<div class="legend-gradient-labels">
294+
<span>Low</span><span>High</span>
295+
</div>
296+
</div>
297+
</div>
298+
</div>
206299
<div id="panel-footer">
207300
Data from <a href="https://map.stjohns.ca/avl/" target="_blank" rel="noopener">City of St. John's AVL</a><br>
208301
<a href="https://github.com/jackharrhy/where-the-plow" target="_blank" rel="noopener">View on GitHub</a>
@@ -302,11 +395,24 @@ <h3>Where the Plow</h3>
302395
btnLines.addEventListener('click', () => switchCoverageView('lines'));
303396
btnHeatmap.addEventListener('click', () => switchCoverageView('heatmap'));
304397

398+
function showLegend(type) {
399+
document.getElementById('legend-vehicles').style.display = type === 'vehicles' ? '' : 'none';
400+
document.getElementById('legend-heatmap').style.display = type === 'heatmap' ? '' : 'none';
401+
}
402+
403+
const legendToggleBtn = document.getElementById('legend-toggle');
404+
const legendBody = document.getElementById('legend-body');
405+
legendToggleBtn.addEventListener('click', () => {
406+
const collapsed = legendBody.classList.toggle('collapsed');
407+
legendToggleBtn.classList.toggle('collapsed', collapsed);
408+
});
409+
305410
function switchCoverageView(view) {
306411
if (view === coverageView) return;
307412
coverageView = view;
308413
btnLines.classList.toggle('active', view === 'lines');
309414
btnHeatmap.classList.toggle('active', view === 'heatmap');
415+
showLegend(view === 'heatmap' ? 'heatmap' : 'vehicles');
310416
renderCoverage(parseInt(timeSlider.value));
311417
}
312418

@@ -511,6 +617,7 @@ <h3>Where the Plow</h3>
511617
}
512618
document.getElementById('vehicle-count').style.display = '';
513619
document.getElementById('db-size').style.display = '';
620+
showLegend('vehicles');
514621
startAutoRefresh();
515622
}
516623

@@ -520,6 +627,7 @@ <h3>Where the Plow</h3>
520627
coverageView = 'lines';
521628
btnLines.classList.add('active');
522629
btnHeatmap.classList.remove('active');
630+
showLegend('vehicles');
523631
if (map.getLayer('vehicle-circles')) {
524632
map.setLayoutProperty('vehicle-circles', 'visibility', 'none');
525633
}

0 commit comments

Comments
 (0)