style(markers): parked = clean pastel department square, no arrow
Per feedback: recently-parked vehicles now render as a pastel tint of their cost-centre colour (blended toward white) as a plain square — arrow removed. Moving-now keeps the full-colour circle + arrow; offline stays grey. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
74f1ef268f
commit
d73755af35
2 changed files with 27 additions and 14 deletions
|
|
@ -7,8 +7,8 @@ trips** into one view for the Fireside Communications / Tracksolid fleet.
|
||||||
a heading arrow, the plate tail, and a hover popup (status, driver, reverse-geocoded
|
a heading arrow, the plate tail, and a hover popup (status, driver, reverse-geocoded
|
||||||
address, heading, odometer, last fix, source). Markers **scale with the zoom level**.
|
address, heading, odometer, last fix, source). Markers **scale with the zoom level**.
|
||||||
Shape encodes recency so stakeholders read activity at a glance:
|
Shape encodes recency so stakeholders read activity at a glance:
|
||||||
- **● circle** — moving right now
|
- **● circle** (full colour + heading arrow) — moving right now
|
||||||
- **■ square** — active within the last 24h, now stopped (with last-heading arrow)
|
- **■ square** (pastel colour, no arrow) — active within the last 24h, now stopped
|
||||||
- **grey ●** — offline (no fix in 24h)
|
- **grey ●** — offline (no fix in 24h)
|
||||||
- **Filters** (bottom-right card) apply to the live map *instantly*:
|
- **Filters** (bottom-right card) apply to the live map *instantly*:
|
||||||
- **Number plate** — multi-select, sorted A→Z; picking a vehicle auto-fills its
|
- **Number plate** — multi-select, sorted A→Z; picking a vehicle auto-fills its
|
||||||
|
|
|
||||||
37
index.html
37
index.html
|
|
@ -202,10 +202,10 @@
|
||||||
filter: drop-shadow(0 0 1px rgba(0,0,0,.65));
|
filter: drop-shadow(0 0 1px rgba(0,0,0,.65));
|
||||||
}
|
}
|
||||||
.veh-pin .idle-dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,.92); }
|
.veh-pin .idle-dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,.92); }
|
||||||
/* Parked = reported within 24h ("moved within 24h"): department-coloured
|
/* Parked = reported within 24h ("active within 24h"): a clean PASTEL
|
||||||
SQUARE (same 32px) with the heading arrow, so high-level viewers can scan
|
department-coloured SQUARE (same 32px, no arrow/dot), so high-level viewers
|
||||||
recent fleet activity by department. Moving-now stays a circle. */
|
can scan recent fleet activity by department. Moving-now stays a circle. */
|
||||||
.veh-marker.parked .veh-pin { border-radius: 6px; opacity: .95; }
|
.veh-marker.parked .veh-pin { border-radius: 6px; opacity: 1; }
|
||||||
.veh-marker.offline .veh-pin { opacity: .5; border-color: rgba(255,255,255,.4); }
|
.veh-marker.offline .veh-pin { opacity: .5; border-color: rgba(255,255,255,.4); }
|
||||||
.veh-plate {
|
.veh-plate {
|
||||||
position: absolute; top: 33px; left: 50%; transform: translateX(-50%);
|
position: absolute; top: 33px; left: 50%; transform: translateX(-50%);
|
||||||
|
|
@ -359,6 +359,14 @@ function colorForCostCentre(cc) {
|
||||||
for (let i = 0; i < cc.length; i++) h = (h * 31 + cc.charCodeAt(i)) | 0;
|
for (let i = 0; i < cc.length; i++) h = (h * 31 + cc.charCodeAt(i)) | 0;
|
||||||
return COST_CENTRE_PALETTE[Math.abs(h) % COST_CENTRE_PALETTE.length];
|
return COST_CENTRE_PALETTE[Math.abs(h) % COST_CENTRE_PALETTE.length];
|
||||||
}
|
}
|
||||||
|
// Pastel tint of a #rrggbb colour — blended toward white. Used for recently-
|
||||||
|
// parked vehicles so they read as a softer version of their department colour.
|
||||||
|
function pastelColor(hex, mix = 0.58) {
|
||||||
|
const h = hex.replace('#', '');
|
||||||
|
const r = parseInt(h.slice(0, 2), 16), g = parseInt(h.slice(2, 4), 16), b = parseInt(h.slice(4, 6), 16);
|
||||||
|
const t = c => Math.round(c + (255 - c) * mix);
|
||||||
|
return `rgb(${t(r)}, ${t(g)}, ${t(b)})`;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// State
|
// State
|
||||||
|
|
@ -520,10 +528,13 @@ function renderLive() {
|
||||||
|
|
||||||
function upsertLiveMarker(p, coords, feature) {
|
function upsertLiveMarker(p, coords, feature) {
|
||||||
const state = vehicleState(p);
|
const state = vehicleState(p);
|
||||||
// Active (moving now) and parked (reported within 24h = "moved within 24h")
|
// Active (moving now) = full department colour. Parked (reported within 24h)
|
||||||
// both take the department/cost-centre colour so stakeholders read fleet
|
// = a PASTEL of that department colour. Offline (>24h silent) = grey. Lets
|
||||||
// activity at a glance. Only offline (>24h silent) stays grey.
|
// high-level viewers read fleet activity by department at a glance.
|
||||||
const color = state === 'offline' ? OFFLINE_COLOR : colorForCostCentre(p.cost_centre);
|
const ccColor = colorForCostCentre(p.cost_centre);
|
||||||
|
const color = state === 'offline' ? OFFLINE_COLOR
|
||||||
|
: state === 'parked' ? pastelColor(ccColor)
|
||||||
|
: ccColor;
|
||||||
const speed = Number(p.speed || 0);
|
const speed = Number(p.speed || 0);
|
||||||
const dir = Number(p.direction || 0);
|
const dir = Number(p.direction || 0);
|
||||||
let m = liveMarkers.get(p.imei);
|
let m = liveMarkers.get(p.imei);
|
||||||
|
|
@ -552,13 +563,15 @@ function upsertLiveMarker(p, coords, feature) {
|
||||||
el.classList.add(state);
|
el.classList.add(state);
|
||||||
const pin = el.querySelector('.veh-pin');
|
const pin = el.querySelector('.veh-pin');
|
||||||
pin.style.setProperty('--c', color);
|
pin.style.setProperty('--c', color);
|
||||||
// Direction arrow for vehicles moving now AND for parked vehicles (last
|
// Direction arrow only for vehicles moving now. Parked = a clean pastel
|
||||||
// heading) — the square + arrow says "active in the last 24h, now stopped".
|
// square (no arrow, no dot). Idling/offline keep the neutral dot.
|
||||||
// Idling (engine on, speed 0) and offline keep the neutral dot.
|
|
||||||
const glyph = el.querySelector('.glyph');
|
const glyph = el.querySelector('.glyph');
|
||||||
if ((state === 'active' && speed > 0) || state === 'parked') {
|
if (state === 'active' && speed > 0) {
|
||||||
glyph.className = 'glyph veh-arrow';
|
glyph.className = 'glyph veh-arrow';
|
||||||
glyph.style.setProperty('--dir', dir + 'deg');
|
glyph.style.setProperty('--dir', dir + 'deg');
|
||||||
|
} else if (state === 'parked') {
|
||||||
|
glyph.className = 'glyph'; // empty — just the pastel square
|
||||||
|
glyph.style.removeProperty('--dir');
|
||||||
} else {
|
} else {
|
||||||
glyph.className = 'glyph idle-dot';
|
glyph.className = 'glyph idle-dot';
|
||||||
glyph.style.removeProperty('--dir');
|
glyph.style.removeProperty('--dir');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue