diff --git a/resources/js/maps/station-map.js b/resources/js/maps/station-map.js new file mode 100644 index 0000000..f737393 --- /dev/null +++ b/resources/js/maps/station-map.js @@ -0,0 +1,92 @@ +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, +}); + +const CLASSIFICATION_COLOURS = { + current: '#22c55e', + recent: '#64748b', + stale: '#f59e0b', + outdated: '#ef4444', +}; + +const UK_CENTRE = [54.0, -2.0]; +const UK_ZOOM = 6; + +export function stationMap(results, meta) { + return { + results, + meta, + _map: null, + _markers: [], + + init() { + 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()); + }, + + _clearMarkers() { + this._markers.forEach((m) => m.remove()); + this._markers = []; + }, + + _plotMarkers() { + this._clearMarkers(); + + if (!this.results || this.results.length === 0) { + return; + } + + const bounds = []; + + this.results.forEach((station) => { + const colour = CLASSIFICATION_COLOURS[station.price_classification] ?? '#64748b'; + const miles = (station.distance_km * 0.621371).toFixed(1); + const supermarketTag = station.is_supermarket + ? 'Supermarket' + : ''; + + const popup = ` +