Compare commits

...

2 commits

Author SHA1 Message Date
david kiania
b678f1ecaa Merge: exempt specialist vehicles from clustering 2026-06-08 15:59:49 +03:00
david kiania
4f25fae6c8 feat(map): exempt specialist vehicles from clustering
Crane/motorbike/pick-up are held out of the supercluster index and always
rendered as individual markers at every zoom, so they never fold into a
cluster bubble and always stand out. The rest of the fleet clusters as before.
KPIs and legend are unaffected (still computed from the full filtered set).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 15:59:47 +03:00

View file

@ -539,6 +539,7 @@ const liveMarkers = new Map(); // imei → maplibregl.Marker (individual vehicl
const clusterMarkers = new Map(); // cluster_id → maplibregl.Marker (count bubbles) const clusterMarkers = new Map(); // cluster_id → maplibregl.Marker (count bubbles)
let liveFeatures = []; // deduped (one device per vehicle) — see dedupeLiveFeatures let liveFeatures = []; // deduped (one device per vehicle) — see dedupeLiveFeatures
let cluster = null; // Supercluster index of the currently-filtered fleet let cluster = null; // Supercluster index of the currently-filtered fleet
let liveSpecialists = []; // crane/motorbike/pick-up — drawn individually, never clustered
const CLUSTER_RADIUS = 60; // px cluster radius const CLUSTER_RADIUS = 60; // px cluster radius
const CLUSTER_MAXZOOM = 11; // above this, clusters disband into individual pins (~city zoom) const CLUSTER_MAXZOOM = 11; // above this, clusters disband into individual pins (~city zoom)
const VEHICLE_META = new Map(); // plate → {cost_centre, assigned_city} const VEHICLE_META = new Map(); // plate → {cost_centre, assigned_city}
@ -735,12 +736,22 @@ function filteredLiveFeatures() {
}); });
} }
// A vehicle is exempt from clustering exactly when it carries a specialist icon
// (crane / motorbike / pick-up) — keyed off the feed's vehicle_type / fleet_segment.
function isSpecialist(p) {
return !!(p && (SPECIALIST_ICONS[p.vehicle_type] || p.fleet_segment === 'specialist'));
}
// Load the filtered fleet into supercluster, redraw bubbles+pins, recompute KPIs. // Load the filtered fleet into supercluster, redraw bubbles+pins, recompute KPIs.
function applyLiveFilters() { function applyLiveFilters() {
if (mode !== 'live') return; if (mode !== 'live') return;
const filtered = filteredLiveFeatures(); const filtered = filteredLiveFeatures();
// Specialists are never clustered — they always render as individual icons so
// they stand out. Only the rest of the fleet feeds supercluster.
liveSpecialists = filtered.filter(f => isSpecialist(f.properties));
const clusterable = filtered.filter(f => !isSpecialist(f.properties));
cluster = new Supercluster({ radius: CLUSTER_RADIUS, maxZoom: CLUSTER_MAXZOOM }); cluster = new Supercluster({ radius: CLUSTER_RADIUS, maxZoom: CLUSTER_MAXZOOM });
cluster.load(filtered.map(f => ({ cluster.load(clusterable.map(f => ({
type: 'Feature', type: 'Feature',
properties: { ...f.properties }, properties: { ...f.properties },
geometry: { type: 'Point', coordinates: f.geometry.coordinates }, geometry: { type: 'Point', coordinates: f.geometry.coordinates },
@ -799,6 +810,12 @@ function renderClusters() {
upsertLiveMarker(it.properties, c, it); upsertLiveMarker(it.properties, c, it);
} }
}); });
// Specialists: always drawn individually, at every zoom (never clustered).
liveSpecialists.forEach(f => {
if (!Array.isArray(f.geometry && f.geometry.coordinates)) return;
seenVeh.add(f.properties.imei);
upsertLiveMarker(f.properties, f.geometry.coordinates, f);
});
for (const [imei, m] of liveMarkers) { if (!seenVeh.has(imei)) { m.remove(); liveMarkers.delete(imei); } } for (const [imei, m] of liveMarkers) { if (!seenVeh.has(imei)) { m.remove(); liveMarkers.delete(imei); } }
for (const [id, m] of clusterMarkers) { if (!seenClu.has(id)) { m.remove(); clusterMarkers.delete(id); } } for (const [id, m] of clusterMarkers) { if (!seenClu.has(id)) { m.remove(); clusterMarkers.delete(id); } }
// If the popped-open vehicle got absorbed into a cluster, close its popup. // If the popped-open vehicle got absorbed into a cluster, close its popup.