Vestingroute Woerden :root{ –moat-green: #1F3329; –moat-green-light: #2C4A3B; –water-teal: #3E7C82; –water-teal-light: #6AA6AA; –sand: #EFE7D2; –sand-deep: #DCCFA8; –brick: #9C4A2E; –brick-light: #C06B44; –ink: #1B241E; –paper: #FBF8F1; } *{ box-sizing: border-box; } html, body{ margin:0; padding:0; background: var(–paper); color: var(–ink); font-family: ‘Inter’, -apple-system, BlinkMacSystemFont, sans-serif; } .wvr-wrap{ max-width: 1180px; margin: 0 auto; padding: 0 0 48px 0; } /* HEADER */ .wvr-header{ background: var(–moat-green); color: var(–sand); padding: 36px 28px 30px; position: relative; overflow: hidden; } .wvr-header::after{ content:””; position:absolute; right:-40px; top:-40px; width:220px; height:220px; border-radius:50%; background: radial-gradient(circle, rgba(62,124,130,0.35) 0%, rgba(62,124,130,0) 70%); } .wvr-eyebrow{ display:flex; align-items:center; gap:10px; font-family:’Inter’, sans-serif; font-size:12.5px; letter-spacing:0.14em; text-transform:uppercase; color: var(–water-teal-light); margin-bottom:10px; font-weight:600; } .wvr-star{ width:16px; height:16px; flex:none; } .wvr-title{ font-family:’Fraunces’, serif; font-weight:600; font-size: clamp(28px, 4vw, 42px); margin:0 0 8px 0; letter-spacing: -0.01em; position:relative; } .wvr-sub{ font-family:’Inter’, sans-serif; font-size:15px; line-height:1.55; max-width:640px; color: rgba(239,231,210,0.82); margin:0; position:relative; } /* CONTROLS */ .wvr-controls{ display:flex; flex-wrap:wrap; gap:10px; align-items:center; padding:18px 28px; background: var(–sand); border-bottom: 1px solid var(–sand-deep); } .wvr-btn{ font-family:’Inter’, sans-serif; font-size:13.5px; font-weight:600; border:none; border-radius:7px; padding:10px 16px; cursor:pointer; background: var(–brick); color: var(–paper); transition: background .15s ease, transform .1s ease; } .wvr-btn:hover{ background: var(–brick-light); } .wvr-btn:active{ transform: translateY(1px); } .wvr-btn.secondary{ background: transparent; color: var(–moat-green); border: 1.5px solid var(–moat-green-light); } .wvr-btn.secondary:hover{ background: rgba(31,51,41,0.06); } .wvr-status{ font-size:13px; color: var(–moat-green-light); font-weight:500; flex:1; min-width:200px; } .wvr-status.error{ color: var(–brick); } /* LAYOUT */ .wvr-body{ display:grid; grid-template-columns: 300px 1fr; gap:0; background: var(–paper); } @media (max-width: 820px){ .wvr-body{ grid-template-columns: 1fr; } .wvr-list{ order:2; max-height:none; } .wvr-map{ order:1; } } .wvr-list{ border-right: 1px solid var(–sand-deep); max-height: 620px; overflow-y:auto; background: var(–paper); } .wvr-stop{ display:flex; gap:14px; padding:16px 20px; border-bottom: 1px solid #ECE4D0; cursor:pointer; transition: background .15s ease; } .wvr-stop:hover{ background: #F3EEE0; } .wvr-stop.active{ background: #EFE3CC; } .wvr-num{ flex:none; width:28px; height:28px; border-radius:50%; background: var(–moat-green); color: var(–sand); display:flex; align-items:center; justify-content:center; font-family:’Fraunces’, serif; font-weight:600; font-size:14px; } .wvr-stop-text h3{ margin:0 0 3px 0; font-family:’Inter’, sans-serif; font-size:14.5px; font-weight:700; color: var(–ink); } .wvr-stop-text p{ margin:0; font-size:12.5px; line-height:1.45; color:#5C5647; } .wvr-map{ height: 620px; width:100%; } #wvr-leaflet-map{ height:100%; width:100%; } /* leaflet marker labels */ .wvr-marker-icon{ background: var(–brick); color: var(–paper); border-radius:50%; width:30px; height:30px; display:flex; align-items:center; justify-content:center; font-family:’Fraunces’, serif; font-weight:700; font-size:14px; border: 2px solid var(–paper); box-shadow: 0 1px 4px rgba(0,0,0,0.35); } .wvr-you-icon{ width:18px; height:18px; border-radius:50%; background: var(–water-teal); border: 3px solid var(–paper); box-shadow: 0 0 0 3px rgba(62,124,130,0.35), 0 1px 4px rgba(0,0,0,0.3); } .leaflet-popup-content-wrapper{ background: var(–paper); color: var(–ink); border-radius:8px; } .leaflet-popup-content{ font-family:’Inter’, sans-serif; font-size:13px; } .leaflet-popup-content b{ font-family:’Fraunces’, serif; font-size:14.5px; }
Zes stops langs de gracht
Een wandeling langs kasteel, koffie, watertoren en vestingwerken. Zet je locatie aan en de kaart wijst je lopend de weg naar de volgende stop.
https://unpkg.com/leaflet@1.9.4/dist/leaflet.js (function(){ var waypoints = [ { id:1, name:”Kasteel van Woerden”, desc:”Middeleeuws kasteel aan het water, het startpunt van de route.”, lat:52.0851611, lng:4.8877051 }, { id:2, name:”Barista’s 50|50 Coffee”, desc:”Kleine specialty-koffiebar, ideaal voor een pauze onderweg.”, lat:52.0858304, lng:4.884777 }, { id:3, name:”Watertoren Woerden”, desc:”Karakteristieke watertoren uit 1906 aan de Oostsingel.”, lat:52.0886371, lng:4.884574 }, { id:4, name:”Oostsingel”, desc:”Groene singel langs de oude vestinggracht.”, lat:52.0887628, lng:4.8876921 }, { id:5, name:”Vesting Woerden / Emmakade”, desc:”Vestingwerken langs de gracht; hier zit ook de Cheese Warehouse.”, lat:52.0866667, lng:4.8811111 }, { id:6, name:”City Museum Woerden”, desc:”Stadsmuseum in het voormalige stadhuis aan het Kerkplein.”, lat:52.0861758, lng:4.8845081 } ]; var center = [52.0866, 4.8858]; var map = L.map(‘wvr-leaflet-map’, { scrollWheelZoom:false }).setView(center, 15.3); L.tileLayer(‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png’, { maxZoom: 19, attribution: ‘© OpenStreetMap contributors’ }).addTo(map); var statusEl = document.getElementById(‘wvr-status’); var listEl = document.getElementById(‘wvr-list’); var routeLayer = null; var youMarker = null; var watchId = null; var markers = []; function setStatus(msg, isError){ statusEl.textContent = msg; statusEl.className = ‘wvr-status’ + (isError ? ‘ error’ : ”); } function numberedIcon(n){ return L.divIcon({ className:”, html:’
‘, iconSize:[30,30], iconAnchor:[15,15] }); } var youIcon = L.divIcon({ className:”, html:’
‘,
iconSize:[18,18],
iconAnchor:[9,9]
});
// Render stop list + markers
waypoints.forEach(function(wp){
var m = L.marker([wp.lat, wp.lng], { icon: numberedIcon(wp.id) }).addTo(map);
m.bindPopup(‘‘+wp.id+’. ‘+wp.name+’
‘+wp.desc);
markers.push(m);
var row = document.createElement(‘div’);
row.className = ‘wvr-stop’;
row.innerHTML = ‘
‘ + ‘
‘+wp.name+’
‘+wp.desc+’
‘; row.addEventListener(‘click’, function(){ map.setView([wp.lat, wp.lng], 17); m.openPopup(); }); listEl.appendChild(row); }); var fullBounds = L.latLngBounds(waypoints.map(function(w){ return [w.lat, w.lng]; })); map.fitBounds(fullBounds.pad(0.25)); // Build a walking route through an ordered list of [lat,lng] points using OSRM’s foot profile function drawWalkingRoute(points, label){ if (routeLayer){ map.removeLayer(routeLayer); routeLayer = null; } if (points.length < 2) return; var coordStr = points.map(function(p){ return p[1] + ‘,’ + p[0]; }).join(‘;’); var url = ‘https://routing.openstreetmap.de/routed-foot/route/v1/driving/’ + coordStr + ‘?overview=full&geometries=geojson’; setStatus(‘Route wordt berekend…’); fetch(url) .then(function(r){ return r.json(); }) .then(function(data){ if (!data.routes || !data.routes.length){ setStatus(‘Kon geen looproute vinden.’, true); return; } var route = data.routes[0]; routeLayer = L.geoJSON(route.geometry, { style: { color: ‘#3E7C82’, weight: 5, opacity: 0.85 } }).addTo(map); var mins = Math.round(route.duration / 60); var km = (route.distance / 1000).toFixed(1); setStatus(label + ‘ — ongeveer ‘ + km + ‘ km, ‘ + mins + ‘ min lopen.’); map.fitBounds(routeLayer.getBounds().pad(0.15)); }) .catch(function(){ setStatus(‘Route-service niet bereikbaar. De stops blijven wel op de kaart zichtbaar.’, true); }); } function showFullRoute(){ var pts = waypoints.map(function(w){ return [w.lat, w.lng]; }); drawWalkingRoute(pts, ‘Volledige route (stop 1 t/m 6)’); map.fitBounds(fullBounds.pad(0.25)); } function routeFromYou(lat, lng){ var pts = [[lat, lng]].concat(waypoints.map(function(w){ return [w.lat, w.lng]; })); drawWalkingRoute(pts, ‘Route vanaf jouw locatie langs alle stops’); } function placeYou(lat, lng){ if (youMarker){ youMarker.setLatLng([lat, lng]); } else { youMarker = L.marker([lat, lng], { icon: youIcon, zIndexOffset: 1000 }).addTo(map); youMarker.bindPopup(‘Jouw locatie’); } } document.getElementById(‘wvr-locate’).addEventListener(‘click’, function(){ if (!navigator.geolocation){ setStatus(‘Geolocatie wordt niet ondersteund door deze browser.’, true); return; } setStatus(‘Locatie opvragen…’); navigator.geolocation.getCurrentPosition(function(pos){ var lat = pos.coords.latitude, lng = pos.coords.longitude; placeYou(lat, lng); routeFromYou(lat, lng); if (watchId === null){ watchId = navigator.geolocation.watchPosition(function(p){ placeYou(p.coords.latitude, p.coords.longitude); }, function(){}, { enableHighAccuracy:true, maximumAge:5000 }); } }, function(err){ setStatus(‘Locatie kon niet worden bepaald (‘ + err.message + ‘). Sta locatietoegang toe in je browser.’, true); }, { enableHighAccuracy:true, timeout:10000 }); }); document.getElementById(‘wvr-reset’).addEventListener(‘click’, function(){ showFullRoute(); }); // initial state: draw the full route through the six stops showFullRoute(); })();