From ff244641e8cd7d82c28d19184e04044321b85a07 Mon Sep 17 00:00:00 2001 From: Nicole Date: Sun, 16 Nov 2025 00:02:42 +0100 Subject: [PATCH] Visual improvements to marker popup --- src/map-badge-v2.html | 142 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 11 deletions(-) diff --git a/src/map-badge-v2.html b/src/map-badge-v2.html index dd0a882..dae9a1e 100644 --- a/src/map-badge-v2.html +++ b/src/map-badge-v2.html @@ -109,6 +109,84 @@ background: transparent !important; border: none !important; } + + /* Modern popup styling */ + .custom-popup { + background: white; + border-radius: 12px; + padding: 16px; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + min-width: 200px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + } + + .custom-popup-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 12px; + } + + .custom-popup-avatar { + width: 48px; + height: 48px; + border-radius: 50%; + object-fit: cover; + border: 2px solid #e0e0e0; + } + + .custom-popup-info { + flex: 1; + } + + .custom-popup-name { + font-size: 16px; + font-weight: 600; + color: #333; + margin: 0 0 4px 0; + } + + .custom-popup-state { + font-size: 13px; + color: #666; + display: flex; + align-items: center; + gap: 4px; + } + + .custom-popup-state-icon { + width: 12px; + height: 12px; + border-radius: 50%; + display: inline-block; + } + + /* Leaflet popup customization */ + .leaflet-popup-content-wrapper { + padding: 0; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + } + + .leaflet-popup-content { + margin: 0; + min-width: 200px; + } + + .leaflet-popup-tip { + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + + /* Google Maps InfoWindow styling */ + .gm-style .gm-style-iw-c { + padding: 0 !important; + border-radius: 12px !important; + box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; + } + + .gm-style .gm-style-iw-d { + overflow: hidden !important; + } @@ -192,6 +270,7 @@ let lastUpdate = null; let updateCount = 0; let initialViewSet = false; let isOSM = MAP_PROVIDER === 'osm'; +let currentPopup = null; // Track currently open popup // OpenStreetMap initialization function initOSM() { @@ -317,6 +396,28 @@ function createMarkerHTML(personState, activityState, pictureUrl) { `; } +function createPopupHTML(friendlyName, personState, pictureUrl, zoneColor) { + const stateLabel = personState.charAt(0).toUpperCase() + personState.slice(1).replace(/_/g, ' '); + + return ` +
+
+ +
+

${friendlyName}

+
+ + ${stateLabel} +
+
+
+
+ `; +} + function updateMarker(entityId, data) { const lat = data.attributes.latitude; const lon = data.attributes.longitude; @@ -344,14 +445,14 @@ function updateMarker(entityId, data) { // OpenStreetMap marker update function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, pictureUrl) { const friendlyName = data.attributes.friendly_name || entityId; - const activityLabel = activityState.replace(/_/g, ' '); + const zoneConfig = ZONES[personState] || ZONES.not_home || { color: '#757575' }; if (markers[entityId]) { // Update existing marker markers[entityId].setLatLng([lat, lon]); // Update popup content - const popupContent = `
${friendlyName}
📍 ${personState}
🏃 ${activityLabel}
`; + const popupContent = createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color); markers[entityId].setPopupContent(popupContent); // Update icon HTML @@ -361,7 +462,7 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p html: iconHtml, iconSize: [48, 62], iconAnchor: [24, 62], - popupAnchor: [0, -62] + popupAnchor: [0, -68] })); } else { // Create new marker @@ -371,14 +472,22 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p html: iconHtml, iconSize: [48, 62], iconAnchor: [24, 62], - popupAnchor: [0, -62] + popupAnchor: [0, -68] }); const marker = L.marker([lat, lon], { icon: icon }).addTo(map); - const popupContent = `
${friendlyName}
📍 ${personState}
🏃 ${activityLabel}
`; + const popupContent = createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color); marker.bindPopup(popupContent); + // Close other popups when this one opens + marker.on('popupopen', function() { + if (currentPopup && currentPopup !== marker) { + currentPopup.closePopup(); + } + currentPopup = marker; + }); + markers[entityId] = marker; } @@ -388,6 +497,8 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p // Google Maps marker update function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState, pictureUrl) { const position = { lat: lat, lng: lon }; + const friendlyName = data.attributes.friendly_name || entityId; + const zoneConfig = ZONES[personState] || ZONES.not_home || { color: '#757575' }; if (markers[entityId]) { // Update existing marker @@ -398,6 +509,11 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState if (overlayDiv) { overlayDiv.innerHTML = createMarkerHTML(personState, activityState, pictureUrl); } + + // Update info window content + if (markers[entityId].infoWindow) { + markers[entityId].infoWindow.setContent(createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color)); + } } else { // Create custom HTML overlay class CustomMarker extends google.maps.OverlayView { @@ -418,8 +534,14 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState // Add click event for info window div.addEventListener('click', () => { + // Close currently open popup + if (currentPopup && currentPopup !== this.infoWindow) { + currentPopup.close(); + } + if (this.infoWindow) { this.infoWindow.open(this.getMap()); + currentPopup = this.infoWindow; } }); @@ -458,9 +580,6 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState } } - const friendlyName = data.attributes.friendly_name || entityId; - const activityLabel = activityState.replace(/_/g, ' '); - const marker = new CustomMarker( position, createMarkerHTML(personState, activityState, pictureUrl), @@ -469,10 +588,11 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState marker.setMap(map); - // Create info window + // Create info window with modern popup const infoWindow = new google.maps.InfoWindow({ - content: `
${friendlyName}
📍 ${personState}
🏃 ${activityLabel}
`, - position: position + content: createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color), + position: position, + pixelOffset: new google.maps.Size(0, -68) }); marker.infoWindow = infoWindow;