diff --git a/public/index.html b/public/index.html
index 2dbba6bf..5d0ecc05 100644
--- a/public/index.html
+++ b/public/index.html
@@ -83,7 +83,7 @@
-
+
diff --git a/public/map.js b/public/map.js
index b7b2bee5..5c2c31c0 100644
--- a/public/map.js
+++ b/public/map.js
@@ -377,39 +377,41 @@
var _renderingMarkers = false;
var _lastDeconflictZoom = null;
- function deconflictLabels(labelMarkers, mapRef) {
+ function deconflictLabels(markers, mapRef) {
const placed = [];
- const LABEL_W = 38;
- const LABEL_H = 24;
- const PAD = 6;
+ const PAD = 4;
- const overlaps = function(b) {
- return placed.some(function(p) {
- return b.x < p.x + p.w + PAD && b.x + b.w + PAD > p.x &&
- b.y < p.y + p.h + PAD && b.y + b.h + PAD > p.y;
- });
+ var overlaps = function(b) {
+ for (var k = 0; k < placed.length; k++) {
+ var p = placed[k];
+ if (b.x < p.x + p.w + PAD && b.x + b.w + PAD > p.x &&
+ b.y < p.y + p.h + PAD && b.y + b.h + PAD > p.y) return true;
+ }
+ return false;
};
- // Generate spiral offsets — 5 rings, 8 directions each, up to 120px out
+ // Spiral offsets — 6 rings, 8 directions, up to ~132px
var offsets = [];
for (var ring = 1; ring <= 6; ring++) {
- var dist = ring * 28;
+ var dist = ring * 22;
for (var angle = 0; angle < 360; angle += 45) {
var rad = angle * Math.PI / 180;
offsets.push([Math.round(Math.cos(rad) * dist), Math.round(Math.sin(rad) * dist)]);
}
}
- for (var i = 0; i < labelMarkers.length; i++) {
- var m = labelMarkers[i];
+ for (var i = 0; i < markers.length; i++) {
+ var m = markers[i];
+ var w = m.isLabel ? 38 : 20;
+ var h = m.isLabel ? 24 : 20;
var pt = mapRef.latLngToLayerPoint(m.latLng);
var bestPt = pt;
- var box = { x: pt.x - LABEL_W / 2, y: pt.y - LABEL_H / 2, w: LABEL_W, h: LABEL_H };
+ var box = { x: pt.x - w / 2, y: pt.y - h / 2, w: w, h: h };
if (overlaps(box)) {
for (var j = 0; j < offsets.length; j++) {
var tryPt = L.point(pt.x + offsets[j][0], pt.y + offsets[j][1]);
- var tryBox = { x: tryPt.x - LABEL_W / 2, y: tryPt.y - LABEL_H / 2, w: LABEL_W, h: LABEL_H };
+ var tryBox = { x: tryPt.x - w / 2, y: tryPt.y - h / 2, w: w, h: h };
if (!overlaps(tryBox)) {
bestPt = tryPt;
box = tryBox;
@@ -439,43 +441,13 @@
return true;
});
- const labelMarkers = [];
+ const allMarkers = [];
for (const node of filtered) {
const useLabel = node.role === 'repeater' && filters.hashLabels;
const icon = useLabel ? makeRepeaterLabelIcon(node) : makeMarkerIcon(node.role || 'companion');
const latLng = L.latLng(node.lat, node.lon);
-
- if (useLabel) {
- labelMarkers.push({ latLng, node, icon });
- } else {
- const marker = L.marker(latLng, {
- icon,
- alt: `${node.name || 'Unknown'} (${node.role || 'node'})`,
- });
- marker.bindPopup(buildPopup(node), { maxWidth: 280 });
- markerLayer.addLayer(marker);
- }
- }
-
- if (labelMarkers.length > 0) {
- deconflictLabels(labelMarkers, map);
- for (const m of labelMarkers) {
- const pos = m.adjustedLatLng || m.latLng;
- const marker = L.marker(pos, {
- icon: m.icon,
- alt: `${m.node.name || 'Unknown'} (${m.node.role || 'node'})`,
- });
- marker.bindPopup(buildPopup(m.node), { maxWidth: 280 });
- markerLayer.addLayer(marker);
-
- if (m.offset > 15) {
- const line = L.polyline([m.latLng, pos], {
- color: '#999', weight: 1, dashArray: '3,3', opacity: 0.6
- });
- markerLayer.addLayer(line);
- }
- }
+ allMarkers.push({ latLng, node, icon, isLabel: useLabel, popupFn: function() { return buildPopup(node); }, alt: (node.name || 'Unknown') + ' (' + (node.role || 'node') + ')' });
}
// Add observer markers
@@ -483,12 +455,27 @@
for (const obs of observers) {
if (!obs.lat || !obs.lon) continue;
const icon = makeMarkerIcon('observer');
- const marker = L.marker([obs.lat, obs.lon], {
- icon,
- alt: `${obs.name || obs.id} (observer)`,
+ const latLng = L.latLng(obs.lat, obs.lon);
+ allMarkers.push({ latLng, node: obs, icon, isLabel: false, popupFn: function() { return buildObserverPopup(obs); }, alt: (obs.name || obs.id || 'Unknown') + ' (observer)' });
+ }
+ }
+
+ // Deconflict ALL markers
+ if (allMarkers.length > 0) {
+ deconflictLabels(allMarkers, map);
+ }
+
+ for (const m of allMarkers) {
+ const pos = m.adjustedLatLng || m.latLng;
+ const marker = L.marker(pos, { icon: m.icon, alt: m.alt });
+ marker.bindPopup(m.popupFn(), { maxWidth: 280 });
+ markerLayer.addLayer(marker);
+
+ if (m.offset > 15 && m.isLabel) {
+ const line = L.polyline([m.latLng, pos], {
+ color: '#999', weight: 1, dashArray: '3,3', opacity: 0.6
});
- marker.bindPopup(buildObserverPopup(obs), { maxWidth: 280 });
- markerLayer.addLayer(marker);
+ markerLayer.addLayer(line);
}
}
}