fix: marker layout, badge position, and clipping
This commit is contained in:
parent
3f0babcb97
commit
e6d6fbd278
1 changed files with 116 additions and 78 deletions
|
|
@ -13,67 +13,59 @@
|
||||||
|
|
||||||
.custom-marker-wrapper {
|
.custom-marker-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 48px;
|
width: var(--marker-size, 48px);
|
||||||
height: 62px; /* Increased to accommodate pointer shape */
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
justify-content: flex-start;
|
||||||
|
overflow: visible;
|
||||||
.custom-marker-position-circle {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-marker-profile-wrapper {
|
.custom-marker-profile-wrapper {
|
||||||
position: absolute;
|
position: relative;
|
||||||
top: 0;
|
width: var(--marker-size, 48px);
|
||||||
left: 0;
|
height: var(--marker-size, 48px);
|
||||||
width: 48px;
|
display: flex;
|
||||||
height: 54px;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: visible;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-marker-image-container {
|
.custom-marker-image-container {
|
||||||
width: 48px;
|
width: var(--marker-size, 48px);
|
||||||
height: 54px;
|
height: var(--marker-size, 48px);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-marker-image-container::after {
|
.custom-marker-image-container::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: -6px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%) rotate(45deg);
|
||||||
width: 0;
|
width: 12px;
|
||||||
height: 0;
|
height: 12px;
|
||||||
border-left: 6px solid transparent;
|
background: var(--border-color, #757575);
|
||||||
border-right: 6px solid transparent;
|
z-index: -1;
|
||||||
border-top: 8px solid var(--border-color, #757575);
|
pointer-events: none;
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-marker-image {
|
.custom-marker-image {
|
||||||
width: 48px;
|
width: var(--marker-size, 48px);
|
||||||
height: 48px;
|
height: var(--marker-size, 48px);
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
display: block;
|
display: block;
|
||||||
|
border-radius: var(--marker-radius, 50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-marker-badge {
|
.custom-marker-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -2px;
|
right: -4px;
|
||||||
bottom: -2px;
|
bottom: -4px;
|
||||||
width: 20px;
|
width: var(--badge-size, 20px);
|
||||||
height: 20px;
|
height: var(--badge-size, 20px);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -83,6 +75,17 @@
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-marker-position-circle {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 10px;
|
||||||
|
width: var(--position-circle-size, 16px);
|
||||||
|
height: var(--position-circle-size, 16px);
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
||||||
|
z-index: 1;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
#refresh-button {
|
#refresh-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
|
@ -247,33 +250,40 @@ const MARKER_SIZES = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get selected marker size with fallback to medium
|
// Get selected marker size with fallback to medium
|
||||||
let selectedMarkerSize = MARKER_SIZES[MARKER_SIZE_PARAM] || MARKER_SIZES.medium;
|
let selectedMarkerSize = { ...(MARKER_SIZES[MARKER_SIZE_PARAM] || MARKER_SIZES.medium) };
|
||||||
|
|
||||||
// Apply CSS custom properties for dynamic sizing
|
// Apply CSS custom properties for dynamic sizing
|
||||||
document.documentElement.style.setProperty('--marker-size', `${selectedMarkerSize.marker}px`);
|
applyMarkerSizeVariables(selectedMarkerSize);
|
||||||
document.documentElement.style.setProperty('--badge-size', `${selectedMarkerSize.badge}px`);
|
|
||||||
document.documentElement.style.setProperty('--popup-offset', `${selectedMarkerSize.popupOffset}px`);
|
|
||||||
document.documentElement.style.setProperty('--marker-height', `${selectedMarkerSize.marker + 14}px`); // +14 for pointer
|
|
||||||
|
|
||||||
// Apply CSS variables for border radius and sizing
|
// Apply CSS variables for border radius
|
||||||
const styleSheet = document.getElementById('dynamic-styles');
|
|
||||||
|
|
||||||
// Set CSS variables on document root
|
|
||||||
document.documentElement.style.setProperty('--marker-radius', MARKER_BORDER_RADIUS);
|
document.documentElement.style.setProperty('--marker-radius', MARKER_BORDER_RADIUS);
|
||||||
document.documentElement.style.setProperty('--badge-radius', BADGE_BORDER_RADIUS);
|
document.documentElement.style.setProperty('--badge-radius', BADGE_BORDER_RADIUS);
|
||||||
document.documentElement.style.setProperty('--marker-size', `${selectedMarkerSize.marker}px`);
|
|
||||||
document.documentElement.style.setProperty('--badge-size', `${selectedMarkerSize.badge}px`);
|
const POSITION_CIRCLE_SIZE = 16;
|
||||||
document.documentElement.style.setProperty('--popup-offset', `${selectedMarkerSize.popupOffset}px`);
|
const MARKER_LAYOUT_FALLBACK_OFFSET = 24;
|
||||||
document.documentElement.style.setProperty('--marker-height', `${selectedMarkerSize.marker + 14}px`);
|
let markerDimensions = {
|
||||||
|
size: selectedMarkerSize.marker,
|
||||||
|
totalHeight: selectedMarkerSize.marker + MARKER_LAYOUT_FALLBACK_OFFSET
|
||||||
|
};
|
||||||
|
|
||||||
|
const styleSheet = document.getElementById('dynamic-styles');
|
||||||
|
|
||||||
// Add static CSS rules that use CSS variables (only if stylesheet is available)
|
// Add static CSS rules that use CSS variables (only if stylesheet is available)
|
||||||
if (styleSheet && styleSheet.sheet) {
|
if (styleSheet && styleSheet.sheet) {
|
||||||
// Add static sizing and radius rules that use CSS variables
|
const rules = [
|
||||||
styleSheet.sheet.insertRule(`.custom-marker-wrapper { width: var(--marker-size); height: calc(var(--marker-size) + 14px); }`, styleSheet.sheet.cssRules.length);
|
`.custom-marker-wrapper { width: var(--marker-size); }`,
|
||||||
styleSheet.sheet.insertRule(`.custom-marker-profile-wrapper { width: var(--marker-size); height: var(--marker-height); }`, styleSheet.sheet.cssRules.length);
|
`.custom-marker-profile-wrapper { width: var(--marker-size); height: var(--marker-size); }`,
|
||||||
styleSheet.sheet.insertRule(`.custom-marker-image-container { width: var(--marker-size); height: var(--marker-height); }`, styleSheet.sheet.cssRules.length);
|
`.custom-marker-image-container { width: var(--marker-size); height: var(--marker-size); }`,
|
||||||
styleSheet.sheet.insertRule(`.custom-marker-image { width: var(--marker-size); height: var(--marker-size); border-radius: var(--marker-radius); }`, styleSheet.sheet.cssRules.length);
|
`.custom-marker-image { width: var(--marker-size); height: var(--marker-size); border-radius: var(--marker-radius); }`,
|
||||||
styleSheet.sheet.insertRule(`.custom-marker-badge { width: var(--badge-size); height: var(--badge-size); border-radius: var(--badge-radius); font-size: calc(var(--badge-size) * 0.6); }`, styleSheet.sheet.cssRules.length);
|
`.custom-marker-badge { width: var(--badge-size); height: var(--badge-size); border-radius: var(--badge-radius); font-size: calc(var(--badge-size) * 0.6); }`
|
||||||
|
];
|
||||||
|
rules.forEach(rule => styleSheet.sheet.insertRule(rule, styleSheet.sheet.cssRules.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMarkerSizeVariables(sizeConfig) {
|
||||||
|
document.documentElement.style.setProperty('--marker-size', `${sizeConfig.marker}px`);
|
||||||
|
document.documentElement.style.setProperty('--badge-size', `${sizeConfig.badge}px`);
|
||||||
|
document.documentElement.style.setProperty('--popup-offset', `${sizeConfig.popupOffset}px`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse entities configuration
|
// Parse entities configuration
|
||||||
|
|
@ -457,9 +467,39 @@ function createMarkerHTML(personState, activityState, pictureUrl) {
|
||||||
<div class="custom-marker-position-circle" style="background: #76D4C3; border: 2px solid ${zoneConfig.color};"></div>
|
<div class="custom-marker-position-circle" style="background: #76D4C3; border: 2px solid ${zoneConfig.color};"></div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure the rendered marker stack so anchors match pointer and circle placement
|
||||||
|
function recalculateMarkerDimensions() {
|
||||||
|
markerDimensions.size = selectedMarkerSize.marker;
|
||||||
|
const measuredHeight = measureMarkerHeight();
|
||||||
|
markerDimensions.totalHeight = measuredHeight || (selectedMarkerSize.marker + MARKER_LAYOUT_FALLBACK_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPopupHTML(friendlyName, personState, pictureUrl, zoneColor, speedData, activityState) {
|
function measureMarkerHeight() {
|
||||||
|
if (!document.body) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tempContainer = document.createElement('div');
|
||||||
|
tempContainer.style.position = 'absolute';
|
||||||
|
tempContainer.style.visibility = 'hidden';
|
||||||
|
tempContainer.style.pointerEvents = 'none';
|
||||||
|
tempContainer.innerHTML = createMarkerHTML('not_home', 'unknown', '');
|
||||||
|
|
||||||
|
document.body.appendChild(tempContainer);
|
||||||
|
const markerElement = tempContainer.querySelector('.custom-marker-wrapper');
|
||||||
|
const measuredHeight = markerElement ? Math.ceil(markerElement.getBoundingClientRect().height) : null;
|
||||||
|
tempContainer.remove();
|
||||||
|
|
||||||
|
return measuredHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
recalculateMarkerDimensions();
|
||||||
|
|
||||||
|
|
||||||
|
function createPopupHTML(friendlyName, personState, pictureUrl, zoneColor, speedData, activityState) {
|
||||||
|
|
||||||
const stateLabel = personState.charAt(0).toUpperCase() + personState.slice(1).replace(/_/g, ' ');
|
const stateLabel = personState.charAt(0).toUpperCase() + personState.slice(1).replace(/_/g, ' ');
|
||||||
|
|
||||||
// Get activity display info from ACTIVITIES config
|
// Get activity display info from ACTIVITIES config
|
||||||
|
|
@ -533,10 +573,11 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
const speedData = data.speed || null;
|
const speedData = data.speed || null;
|
||||||
|
|
||||||
// Get dynamic marker dimensions
|
// Get dynamic marker dimensions
|
||||||
const markerSize = selectedMarkerSize.marker;
|
const markerSize = markerDimensions.size;
|
||||||
const markerHeight = markerSize + 14;
|
const markerTotalHeight = markerDimensions.totalHeight;
|
||||||
const markerAnchor = Math.floor(markerSize / 2);
|
|
||||||
const popupOffset = selectedMarkerSize.popupOffset;
|
const popupOffset = selectedMarkerSize.popupOffset;
|
||||||
|
const markerAnchorX = Math.floor(markerSize / 2);
|
||||||
|
const markerAnchorY = markerTotalHeight - Math.floor(POSITION_CIRCLE_SIZE / 2);
|
||||||
|
|
||||||
let marker = markers[entityId];
|
let marker = markers[entityId];
|
||||||
const wasPopupOpen = marker && marker.isPopupOpen();
|
const wasPopupOpen = marker && marker.isPopupOpen();
|
||||||
|
|
@ -554,8 +595,8 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
marker.setIcon(L.divIcon({
|
marker.setIcon(L.divIcon({
|
||||||
className: 'custom-leaflet-marker',
|
className: 'custom-leaflet-marker',
|
||||||
html: iconHtml,
|
html: iconHtml,
|
||||||
iconSize: [markerSize, markerHeight],
|
iconSize: [markerSize, markerTotalHeight],
|
||||||
iconAnchor: [markerAnchor, markerHeight],
|
iconAnchor: [markerAnchorX, markerAnchorY],
|
||||||
popupAnchor: [0, popupOffset]
|
popupAnchor: [0, popupOffset]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -566,8 +607,8 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
const icon = L.divIcon({
|
const icon = L.divIcon({
|
||||||
className: 'custom-leaflet-marker',
|
className: 'custom-leaflet-marker',
|
||||||
html: iconHtml,
|
html: iconHtml,
|
||||||
iconSize: [markerSize, markerHeight],
|
iconSize: [markerSize, markerTotalHeight],
|
||||||
iconAnchor: [markerAnchor, markerHeight],
|
iconAnchor: [markerAnchorX, markerAnchorY],
|
||||||
popupAnchor: [0, popupOffset]
|
popupAnchor: [0, popupOffset]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -582,7 +623,7 @@ function updateMarkerOSM(entityId, data, lat, lon, personState, activityState, p
|
||||||
currentPopup.closePopup();
|
currentPopup.closePopup();
|
||||||
}
|
}
|
||||||
currentPopup = marker;
|
currentPopup = marker;
|
||||||
map.setView(marker.getLatLng(), 17, { animate: true });
|
map.setView(marker.getLatLng(), Math.max(map.getZoom(), 17), { animate: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
markers[entityId] = marker;
|
markers[entityId] = marker;
|
||||||
|
|
@ -615,6 +656,9 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState
|
||||||
if (marker.infoWindow) {
|
if (marker.infoWindow) {
|
||||||
marker.infoWindow.setContent(createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color, speedData, activityState));
|
marker.infoWindow.setContent(createPopupHTML(friendlyName, personState, pictureUrl, zoneConfig.color, speedData, activityState));
|
||||||
marker.infoWindow.setPosition(position);
|
marker.infoWindow.setPosition(position);
|
||||||
|
marker.infoWindow.setOptions({
|
||||||
|
pixelOffset: new google.maps.Size(0, selectedMarkerSize.popupOffset)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create custom HTML overlay
|
// Create custom HTML overlay
|
||||||
|
|
@ -644,7 +688,7 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState
|
||||||
|
|
||||||
if (this.infoWindow) {
|
if (this.infoWindow) {
|
||||||
map.setCenter(this.position);
|
map.setCenter(this.position);
|
||||||
map.setZoom(17);
|
map.setZoom(Math.max(map.getZoom(), 17));
|
||||||
this.infoWindow.open(this.getMap());
|
this.infoWindow.open(this.getMap());
|
||||||
currentPopup = this.infoWindow;
|
currentPopup = this.infoWindow;
|
||||||
}
|
}
|
||||||
|
|
@ -662,12 +706,13 @@ function updateMarkerGoogle(entityId, data, lat, lon, personState, activityState
|
||||||
);
|
);
|
||||||
|
|
||||||
const div = this.div;
|
const div = this.div;
|
||||||
const markerSize = selectedMarkerSize.marker;
|
const markerSize = markerDimensions.size;
|
||||||
const markerHeight = markerSize + 14;
|
const markerTotalHeight = markerDimensions.totalHeight;
|
||||||
const markerAnchor = Math.floor(markerSize / 2);
|
const markerAnchor = Math.floor(markerSize / 2);
|
||||||
|
const verticalAnchor = markerTotalHeight - Math.floor(POSITION_CIRCLE_SIZE / 2);
|
||||||
|
|
||||||
div.style.left = (pos.x - markerAnchor) + 'px'; // Center horizontally
|
div.style.left = (pos.x - markerAnchor) + 'px'; // Center horizontally
|
||||||
div.style.top = (pos.y - markerHeight) + 'px'; // Position above point
|
div.style.top = (pos.y - verticalAnchor) + 'px'; // Position above point
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove() {
|
onRemove() {
|
||||||
|
|
@ -849,16 +894,9 @@ window.addEventListener('message', (event) => {
|
||||||
|
|
||||||
if (event.data.marker_size && MARKER_SIZES[event.data.marker_size]) {
|
if (event.data.marker_size && MARKER_SIZES[event.data.marker_size]) {
|
||||||
// Update marker size dynamically
|
// Update marker size dynamically
|
||||||
const newSize = MARKER_SIZES[event.data.marker_size];
|
selectedMarkerSize = { ...MARKER_SIZES[event.data.marker_size] };
|
||||||
selectedMarkerSize.marker = newSize.marker;
|
applyMarkerSizeVariables(selectedMarkerSize);
|
||||||
selectedMarkerSize.badge = newSize.badge;
|
recalculateMarkerDimensions();
|
||||||
selectedMarkerSize.popupOffset = newSize.popupOffset;
|
|
||||||
|
|
||||||
// Update CSS custom properties
|
|
||||||
document.documentElement.style.setProperty('--marker-size', `${newSize.marker}px`);
|
|
||||||
document.documentElement.style.setProperty('--badge-size', `${newSize.badge}px`);
|
|
||||||
document.documentElement.style.setProperty('--popup-offset', `${newSize.popupOffset}px`);
|
|
||||||
document.documentElement.style.setProperty('--marker-height', `${newSize.marker + 14}px`);
|
|
||||||
|
|
||||||
console.log('Marker size updated to:', event.data.marker_size);
|
console.log('Marker size updated to:', event.data.marker_size);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue