Visual improvements to marker popup
This commit is contained in:
parent
4f41f4d2c5
commit
ff244641e8
1 changed files with 131 additions and 11 deletions
|
|
@ -109,6 +109,84 @@
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
border: none !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;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -192,6 +270,7 @@ let lastUpdate = null;
|
||||||
let updateCount = 0;
|
let updateCount = 0;
|
||||||
let initialViewSet = false;
|
let initialViewSet = false;
|
||||||
let isOSM = MAP_PROVIDER === 'osm';
|
let isOSM = MAP_PROVIDER === 'osm';
|
||||||
|
let currentPopup = null; // Track currently open popup
|
||||||
|
|
||||||
// OpenStreetMap initialization
|
// OpenStreetMap initialization
|
||||||
function initOSM() {
|
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 `
|
||||||
|
<div class="custom-popup">
|
||||||
|
<div class="custom-popup-header">
|
||||||
|
<img
|
||||||
|
src="${pictureUrl}"
|
||||||
|
class="custom-popup-avatar"
|
||||||
|
onerror="this.src='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2248%22 height=%2248%22><circle cx=%2224%22 cy=%2224%22 r=%2220%22 fill=%22%23cccccc%22/></svg>'">
|
||||||
|
<div class="custom-popup-info">
|
||||||
|
<h3 class="custom-popup-name">${friendlyName}</h3>
|
||||||
|
<div class="custom-popup-state">
|
||||||
|
<span class="custom-popup-state-icon" style="background: ${zoneColor}"></span>
|
||||||
|
${stateLabel}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
function updateMarker(entityId, data) {
|
function updateMarker(entityId, data) {
|
||||||
const lat = data.attributes.latitude;
|
const lat = data.attributes.latitude;
|
||||||
const lon = data.attributes.longitude;
|
const lon = data.attributes.longitude;
|
||||||
|
|
@ -344,14 +445,14 @@ function updateMarker(entityId, data) {
|
||||||
// OpenStreetMap marker update
|
// OpenStreetMap marker update
|
||||||
function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, pictureUrl) {
|
function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, pictureUrl) {
|
||||||
const friendlyName = data.attributes.friendly_name || entityId;
|
const friendlyName = data.attributes.friendly_name || entityId;
|
||||||
const activityLabel = activityState.replace(/_/g, ' ');
|
const zoneConfig = ZONES[personState] || ZONES.not_home || { color: '#757575' };
|
||||||
|
|
||||||
if (markers[entityId]) {
|
if (markers[entityId]) {
|
||||||
// Update existing marker
|
// Update existing marker
|
||||||
markers[entityId].setLatLng([lat, lon]);
|
markers[entityId].setLatLng([lat, lon]);
|
||||||
|
|
||||||
// Update popup content
|
// Update popup content
|
||||||
const popupContent = `<div style="padding: 8px;"><b>${friendlyName}</b><br>📍 ${personState}<br>🏃 ${activityLabel}</div>`;
|
const popupContent = createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color);
|
||||||
markers[entityId].setPopupContent(popupContent);
|
markers[entityId].setPopupContent(popupContent);
|
||||||
|
|
||||||
// Update icon HTML
|
// Update icon HTML
|
||||||
|
|
@ -361,7 +462,7 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
html: iconHtml,
|
html: iconHtml,
|
||||||
iconSize: [48, 62],
|
iconSize: [48, 62],
|
||||||
iconAnchor: [24, 62],
|
iconAnchor: [24, 62],
|
||||||
popupAnchor: [0, -62]
|
popupAnchor: [0, -68]
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
// Create new marker
|
// Create new marker
|
||||||
|
|
@ -371,14 +472,22 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
html: iconHtml,
|
html: iconHtml,
|
||||||
iconSize: [48, 62],
|
iconSize: [48, 62],
|
||||||
iconAnchor: [24, 62],
|
iconAnchor: [24, 62],
|
||||||
popupAnchor: [0, -62]
|
popupAnchor: [0, -68]
|
||||||
});
|
});
|
||||||
|
|
||||||
const marker = L.marker([lat, lon], { icon: icon }).addTo(map);
|
const marker = L.marker([lat, lon], { icon: icon }).addTo(map);
|
||||||
|
|
||||||
const popupContent = `<div style="padding: 8px;"><b>${friendlyName}</b><br>📍 ${personState}<br>🏃 ${activityLabel}</div>`;
|
const popupContent = createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color);
|
||||||
marker.bindPopup(popupContent);
|
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;
|
markers[entityId] = marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,6 +497,8 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
// Google Maps marker update
|
// Google Maps marker update
|
||||||
function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState, pictureUrl) {
|
function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState, pictureUrl) {
|
||||||
const position = { lat: lat, lng: lon };
|
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]) {
|
if (markers[entityId]) {
|
||||||
// Update existing marker
|
// Update existing marker
|
||||||
|
|
@ -398,6 +509,11 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState
|
||||||
if (overlayDiv) {
|
if (overlayDiv) {
|
||||||
overlayDiv.innerHTML = createMarkerHTML(personState, activityState, pictureUrl);
|
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 {
|
} else {
|
||||||
// Create custom HTML overlay
|
// Create custom HTML overlay
|
||||||
class CustomMarker extends google.maps.OverlayView {
|
class CustomMarker extends google.maps.OverlayView {
|
||||||
|
|
@ -418,8 +534,14 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState
|
||||||
|
|
||||||
// Add click event for info window
|
// Add click event for info window
|
||||||
div.addEventListener('click', () => {
|
div.addEventListener('click', () => {
|
||||||
|
// Close currently open popup
|
||||||
|
if (currentPopup && currentPopup !== this.infoWindow) {
|
||||||
|
currentPopup.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.infoWindow) {
|
if (this.infoWindow) {
|
||||||
this.infoWindow.open(this.getMap());
|
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(
|
const marker = new CustomMarker(
|
||||||
position,
|
position,
|
||||||
createMarkerHTML(personState, activityState, pictureUrl),
|
createMarkerHTML(personState, activityState, pictureUrl),
|
||||||
|
|
@ -469,10 +588,11 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState
|
||||||
|
|
||||||
marker.setMap(map);
|
marker.setMap(map);
|
||||||
|
|
||||||
// Create info window
|
// Create info window with modern popup
|
||||||
const infoWindow = new google.maps.InfoWindow({
|
const infoWindow = new google.maps.InfoWindow({
|
||||||
content: `<div style="padding: 8px;"><b>${friendlyName}</b><br>📍 ${personState}<br>🏃 ${activityLabel}</div>`,
|
content: createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color),
|
||||||
position: position
|
position: position,
|
||||||
|
pixelOffset: new google.maps.Size(0, -68)
|
||||||
});
|
});
|
||||||
|
|
||||||
marker.infoWindow = infoWindow;
|
marker.infoWindow = infoWindow;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue