Reiseblog mit CMS
This commit is contained in:
commit
7f820a6478
19 changed files with 600 additions and 0 deletions
114
src/components/RouteMap.astro
Normal file
114
src/components/RouteMap.astro
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
import { loadRoute } from '../lib/gpx.js';
|
||||
import { loadPhotoMarkers } from '../lib/photos.js';
|
||||
|
||||
// Beides läuft beim BAUEN (nicht im Browser): GPX -> Linie, Fotos -> Marker.
|
||||
const route = await loadRoute();
|
||||
const markers = await loadPhotoMarkers();
|
||||
const data = JSON.stringify({ route, markers });
|
||||
---
|
||||
|
||||
<div id="routemap-wrap" class="routemap collapsed">
|
||||
<button id="routemap-toggle" type="button" aria-label="Karte vergrößern" title="Karte vergrößern / verkleinern">⤢</button>
|
||||
<div id="routemap"></div>
|
||||
</div>
|
||||
|
||||
<script type="application/json" id="routemap-data" set:html={data}></script>
|
||||
|
||||
<script>
|
||||
import L from 'leaflet';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
// Behebt die "kaputten Marker-Icons", wenn Leaflet per npm gebündelt wird.
|
||||
import iconUrl from 'leaflet/dist/images/marker-icon.png';
|
||||
import iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png';
|
||||
import shadowUrl from 'leaflet/dist/images/marker-shadow.png';
|
||||
|
||||
L.Marker.prototype.options.icon = L.icon({
|
||||
iconUrl,
|
||||
iconRetinaUrl,
|
||||
shadowUrl,
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
shadowSize: [41, 41],
|
||||
});
|
||||
|
||||
const { route, markers } = JSON.parse(document.getElementById('routemap-data').textContent);
|
||||
|
||||
const map = L.map('routemap', { scrollWheelZoom: false });
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© OpenStreetMap-Mitwirkende',
|
||||
maxZoom: 19,
|
||||
}).addTo(map);
|
||||
|
||||
const bounds = L.latLngBounds([]);
|
||||
|
||||
if (route.features?.length) {
|
||||
const routeLayer = L.geoJSON(route, { style: { color: '#e63946', weight: 4 } }).addTo(map);
|
||||
bounds.extend(routeLayer.getBounds());
|
||||
}
|
||||
|
||||
for (const m of markers) {
|
||||
const marker = L.marker([m.lat, m.lng]).addTo(map);
|
||||
marker.bindPopup(
|
||||
`<a href="${m.url}" target="_blank" rel="noopener">` +
|
||||
`<img src="${m.url}" alt="" style="max-width:220px;display:block;border-radius:6px" />` +
|
||||
`</a>`
|
||||
);
|
||||
bounds.extend(marker.getLatLng());
|
||||
}
|
||||
|
||||
if (bounds.isValid()) {
|
||||
map.fitBounds(bounds, { padding: [20, 20] });
|
||||
} else {
|
||||
map.setView([20, 0], 2); // Weltansicht, solange noch keine Daten da sind
|
||||
}
|
||||
|
||||
const wrap = document.getElementById('routemap-wrap');
|
||||
document.getElementById('routemap-toggle').addEventListener('click', () => {
|
||||
const expanded = wrap.classList.toggle('expanded');
|
||||
wrap.classList.toggle('collapsed', !expanded);
|
||||
map.scrollWheelZoom[expanded ? 'enable' : 'disable']();
|
||||
// Leaflet muss nach Größenänderung neu zeichnen.
|
||||
setTimeout(() => map.invalidateSize(), 260);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.routemap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.routemap.collapsed #routemap {
|
||||
height: 180px;
|
||||
}
|
||||
.routemap.expanded {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
border-radius: 0;
|
||||
}
|
||||
.routemap.expanded #routemap {
|
||||
height: 100vh;
|
||||
}
|
||||
#routemap {
|
||||
width: 100%;
|
||||
}
|
||||
#routemap-toggle {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
z-index: 1001;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue