import L from 'leaflet'; import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png'; import markerIcon from 'leaflet/dist/images/marker-icon.png'; import markerShadow from 'leaflet/dist/images/marker-shadow.png'; delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconUrl: markerIcon, iconRetinaUrl: markerIcon2x, shadowUrl: markerShadow, }); function escHtml(str) { return String(str ?? '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } const CLASSIFICATION_COLOURS = { current: '#22c55e', recent: '#64748b', stale: '#f59e0b', outdated: '#ef4444', }; const UK_CENTRE = [54.0, -2.0]; const UK_ZOOM = 7; const USER_MARKER_CSS = ` @keyframes fuelalert-pulse { 0% { transform: scale(1); opacity: 0.6; } 70% { transform: scale(2.8); opacity: 0; } 100% { transform: scale(1); opacity: 0; } } .fuelalert-user-marker { position: relative; width: 16px; height: 16px; } .fuelalert-user-dot { position: absolute; inset: 0; border-radius: 50%; background: #3b82f6; border: 2px solid #fff; box-shadow: 0 0 0 2px #3b82f6; } .fuelalert-user-ring { position: absolute; inset: 0; border-radius: 50%; background: #3b82f6; animation: fuelalert-pulse 2s ease-out infinite; } `; function injectUserMarkerStyles() { if (document.getElementById('fuelalert-user-marker-styles')) return; const style = document.createElement('style'); style.id = 'fuelalert-user-marker-styles'; style.textContent = USER_MARKER_CSS; document.head.appendChild(style); } export function stationMap(results, meta, radius) { return { results, meta, radius, _map: null, _markers: [], _userMarker: null, init() { injectUserMarkerStyles(); this._map = L.map(this.$el, { zoomControl: true }).setView(UK_CENTRE, UK_ZOOM); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', maxZoom: 19, }).addTo(this._map); if (this.results && this.results.length > 0) { this._plotMarkers(); } this.$watch('results', () => this._plotMarkers()); this.locateUser(); }, getZoomForRadius(radiusMiles) { if (radiusMiles <= 1) return 15; if (radiusMiles <= 2) return 14; if (radiusMiles <= 5) return 12; if (radiusMiles <= 10) return 11; if (radiusMiles <= 15) return 10; if (radiusMiles <= 25) return 9; if (radiusMiles <= 50) return 8; return 7; }, _clearMarkers() { this._markers.forEach((m) => m.remove()); this._markers = []; }, addUserMarker(lat, lng) { if (this._userMarker) { this._userMarker.remove(); } const icon = L.divIcon({ className: '', html: '