sync: 2026-08-21 15:18:36

This commit is contained in:
2026-08-21 15:18:36 +02:00
parent aa5b994d31
commit 099c4032de

View File

@@ -8,7 +8,7 @@
<link <link
rel="stylesheet" rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css"
> >
<style> <style>
@@ -612,30 +612,57 @@
/* ===================================================== /* =====================================================
LEAFLET MAPLIBRE CONTROLS
===================================================== */ ===================================================== */
.leaflet-control-zoom { .maplibregl-ctrl-group {
margin-right: 18px !important;
margin-bottom: 82px !important;
border: none !important; border: none !important;
box-shadow: box-shadow:
0 2px 7px rgba(0, 0, 0, 0.25) !important; 0 2px 7px rgba(0, 0, 0, 0.25) !important;
border-radius: 8px !important;
} }
.leaflet-control-zoom a { .maplibregl-ctrl-group button {
border: none !important; border: none !important;
} }
.leaflet-control-attribution { .maplibregl-ctrl-attrib {
font-size: 10px; font-size: 10px;
} }
/* Position nav controls away from the search UI */
.maplibregl-ctrl-topleft {
top: 10px;
left: 10px;
}
.maplibregl-ctrl-topright {
top: 10px;
right: 10px;
}
/* =====================================================
MARKER STYLES
===================================================== */
/* Wrapper that holds both the label and the pin circle */
.poi-pin-wrapper {
position: relative;
cursor: pointer;
width: 34px;
height: 34px;
}
/* Permanent name label shown above each pin */ /* Permanent name label shown above each pin */
.pin-label { .pin-label {
position: absolute;
bottom: 38px;
left: 50%;
transform: translateX(-50%);
background: rgba(255, 255, 255, 0.92); background: rgba(255, 255, 255, 0.92);
border: none; border: none;
border-radius: 4px; border-radius: 4px;
@@ -645,18 +672,10 @@
font-weight: 500; font-weight: 500;
padding: 2px 7px; padding: 2px 7px;
white-space: nowrap; white-space: nowrap;
} pointer-events: none;
.pin-label::before {
display: none;
} }
/* Custom circular pin that reflects the POI type */ /* Custom circular pin that reflects the POI type */
.poi-pin {
background: transparent;
border: none;
}
.poi-pin-inner { .poi-pin-inner {
width: 34px; width: 34px;
height: 34px; height: 34px;
@@ -681,8 +700,7 @@
/* User location marker (blue dot) */ /* User location marker (blue dot) */
.user-loc-marker { .user-loc-marker {
background: transparent; cursor: default;
border: none;
} }
.user-loc-dot { .user-loc-dot {
@@ -762,10 +780,6 @@
right: 12px; right: 12px;
bottom: 72px; bottom: 72px;
} }
.leaflet-control-zoom {
margin-bottom: 125px !important;
}
} }
</style> </style>
</head> </head>
@@ -929,7 +943,7 @@
</button> </button>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> <script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js"></script>
<script> <script>
@@ -949,30 +963,26 @@
*/ */
const CLICK_ZOOM = 15; const CLICK_ZOOM = 15;
const MAPTILER_KEY = "aUftDXS9UHdRVbSuaUWz";
/* ========================================================= /* =========================================================
MAP MAP
========================================================= */ ========================================================= */
const map = const map = new maplibregl.Map({
L.map("map").setView( container: "map",
[ style:
AMSTERDAM_LAT, "https://api.maptiler.com/maps/streets-v4/style.json?key=" +
AMSTERDAM_LON MAPTILER_KEY,
], center: [AMSTERDAM_LON, AMSTERDAM_LAT],
DEFAULT_ZOOM zoom: DEFAULT_ZOOM
); });
map.addControl(
L.tileLayer( new maplibregl.NavigationControl(),
"https://api.maptiler.com/maps/streets-v4/256/{z}/{x}/{y}.png?key=aUftDXS9UHdRVbSuaUWz", "top-right"
{ );
maxZoom: 19,
attribution:
"&copy; OpenStreetMap contributors"
}
).addTo(map);
/* ========================================================= /* =========================================================
@@ -1014,6 +1024,8 @@
let selectedMarker = null; let selectedMarker = null;
let selectedPopup = null;
let userLocationMarker = null; let userLocationMarker = null;
let zoomMessageTimer = null; let zoomMessageTimer = null;
@@ -1052,13 +1064,13 @@
// Build a viewbox from the currently visible map area so // Build a viewbox from the currently visible map area so
// results are restricted to what the user can see. // results are restricted to what the user can see.
const visibleBounds = map.getBounds(); const mb = map.getBounds();
const viewbox = [ const viewbox = [
visibleBounds.getWest(), mb.west,
visibleBounds.getNorth(), mb.north,
visibleBounds.getEast(), mb.east,
visibleBounds.getSouth() mb.south
].join(","); ].join(",");
@@ -1182,27 +1194,42 @@
); );
// Build the marker element with label + pin
const el =
document.createElement(
"div"
);
el.className =
"poi-pin-wrapper";
el.innerHTML = `
<div class="pin-label">
${escapeHtml(
getName(place)
)}
</div>
<div
class="poi-pin-inner"
style="background:${getPoiColor(place)};"
>
${getIcon(place)}
</div>
`;
const marker = const marker =
L.marker([ new maplibregl.Marker({
place.lat, element: el
place.lon })
], { .setLngLat([
icon: createPoiIcon(place) place.lon,
}).addTo(map); place.lat
])
.addTo(map);
marker.bindTooltip( marker.getElement().addEventListener(
escapeHtml(getName(place)),
{
permanent: true,
direction: "top",
offset: [0, -20],
className: "pin-label"
}
);
marker.on(
"click", "click",
() => { () => {
@@ -1231,26 +1258,36 @@
const zoom = getZoomForPlace(data[0]); const zoom = getZoomForPlace(data[0]);
map.flyTo( map.flyTo({
bounds[0], center: [
zoom, bounds[0][1],
{ bounds[0][0]
duration: 0.7 ],
} zoom: zoom,
); duration: 700
});
} }
else { else {
map.fitBounds( const lons =
bounds, bounds.map(b => b[1]);
{
padding: [ const lats =
80, bounds.map(b => b[0]);
80
] map.fitBounds([
} [
); Math.min(...lons),
Math.min(...lats)
],
[
Math.max(...lons),
Math.max(...lats)
]
], {
padding: 80
});
} }
} }
@@ -1361,47 +1398,66 @@
"none"; "none";
if (selectedMarker) { clearSelection();
map.removeLayer(
selectedMarker
);
}
selectedMarker = selectedMarker =
L.marker([ new maplibregl.Marker()
place.lat, .setLngLat([
place.lon place.lon,
]).addTo(map); place.lat
])
.addTo(map);
const zoom = getZoomForPlace(place); const zoom = getZoomForPlace(place);
map.flyTo( map.flyTo({
[ center: [
place.lat, place.lon,
place.lon place.lat
], ],
zoom, zoom: zoom,
{ duration: 700
duration: 0.7 });
}
);
renderPlace(place); renderPlace(place);
} }
/* =========================================================
CLEAR SELECTION
========================================================= */
function clearSelection() {
if (selectedMarker) {
selectedMarker.remove();
selectedMarker =
null;
}
if (selectedPopup) {
selectedPopup.remove();
selectedPopup =
null;
}
}
/* ========================================================= /* =========================================================
MAP CLICK MAP CLICK
========================================================= */ ========================================================= */
map.on( map.on(
"click", "click",
async event => { async e => {
/* /*
* Don't reverse-geocode at low zoom. * Don't reverse-geocode at low zoom.
@@ -1418,10 +1474,10 @@
const lat = const lat =
event.latlng.lat; e.lngLat.lat;
const lon = const lon =
event.latlng.lng; e.lngLat.lng;
resultsCard.style.display = resultsCard.style.display =
@@ -1441,19 +1497,16 @@
`; `;
if (selectedMarker) { clearSelection();
map.removeLayer(
selectedMarker
);
}
selectedMarker = selectedMarker =
L.marker([ new maplibregl.Marker()
lat, .setLngLat([
lon lon,
]).addTo(map); lat
])
.addTo(map);
try { try {
@@ -1496,11 +1549,20 @@
} }
selectedMarker.bindPopup( selectedPopup =
escapeHtml( new maplibregl.Popup({
getName(place) offset: 25
})
.setHTML(
escapeHtml(
getName(place)
)
) )
).openPopup(); .setLngLat([
lon,
lat
])
.addTo(map);
renderPlace(place); renderPlace(place);
@@ -1923,15 +1985,7 @@
"none"; "none";
if (selectedMarker) { clearSelection();
map.removeLayer(
selectedMarker
);
selectedMarker =
null;
}
} }
@@ -2185,30 +2239,41 @@
function showUserLocation(lat, lon) { function showUserLocation(lat, lon) {
const coords = [lat, lon]; const coords = [lon, lat];
if (!userLocationMarker) { if (!userLocationMarker) {
const el =
document.createElement(
"div"
);
el.className =
"user-loc-marker";
el.innerHTML =
'<div class="user-loc-dot"></div>';
userLocationMarker = userLocationMarker =
L.marker(coords, { new maplibregl.Marker({
icon: createUserLocationIcon(), element: el
zIndexOffset: 1000 })
}).addTo(map); .setLngLat(coords)
.addTo(map);
} else { } else {
userLocationMarker.setLatLng(coords); userLocationMarker.setLngLat(coords);
} }
map.flyTo( map.flyTo({
coords, center: coords,
16, zoom: 16,
{ duration: 800
duration: 0.8 });
}
);
} }
@@ -2340,24 +2405,14 @@
markers.forEach( markers.forEach(
marker => marker =>
map.removeLayer( marker.remove()
marker
)
); );
markers = []; markers = [];
if (selectedMarker) { clearSelection();
map.removeLayer(
selectedMarker
);
selectedMarker =
null;
}
} }
@@ -2481,7 +2536,7 @@
road += road +=
" " + " " +
address.house_number; address.house_number;
} }
@@ -2655,38 +2710,6 @@
} }
function createPoiIcon(place) {
const html = `
<div
class="poi-pin-inner"
style="background:${getPoiColor(place)};"
>
${getIcon(place)}
</div>
`;
return L.divIcon({
className: "poi-pin",
html: html,
iconSize: [34, 34],
iconAnchor: [17, 17]
});
}
function createUserLocationIcon() {
return L.divIcon({
className: "user-loc-marker",
html: `<div class="user-loc-dot"></div>`,
iconSize: [18, 18],
iconAnchor: [9, 9]
});
}
function safeUrl(url) { function safeUrl(url) {
if (!url) if (!url)