diff --git a/src/components/map/MapView.svelte b/src/components/map/MapView.svelte index 9b78105..d16df62 100644 --- a/src/components/map/MapView.svelte +++ b/src/components/map/MapView.svelte @@ -2,30 +2,25 @@ import { browser } from '$app/environment'; import { createEventDispatcher, onMount, onDestroy } from 'svelte'; import { - PUBLIC_OBA_GOOGLE_MAPS_API_KEY as apiKey, PUBLIC_OBA_REGION_CENTER_LAT as initialLat, - PUBLIC_OBA_REGION_CENTER_LNG as initialLng, - PUBLIC_OBA_MAP_PROVIDER as mapProvider + PUBLIC_OBA_REGION_CENTER_LNG as initialLng } from '$env/static/public'; import { debounce } from '$lib/utils'; import LocationButton from '$lib/LocationButton/LocationButton.svelte'; - import StopMarker from './StopMarker.svelte'; import RouteMap from './RouteMap.svelte'; import MapTypeButton from '$lib/MapTypeButton/MapTypeButton.svelte'; import { faBus } from '@fortawesome/free-solid-svg-icons'; import { RouteType, routePriorities, prioritizedRouteTypeForDisplay } from '$config/routeConfig'; - import GoogleMapProvider from '$lib/Provider/GoogleMapProvider'; - import OpenStreetMapProvider from '$lib/Provider/OpenStreetMapProvider'; - export let selectedTrip = null; export let selectedRoute = null; export let showRoute = false; export let showRouteMap = false; export let showAllStops = true; export let stop = null; + export let mapProvider = null; let selectedStopID = null; @@ -39,17 +34,6 @@ let allStops = []; let routeReference = []; - const createMapProvider = () => { - switch (mapProvider) { - case 'google': - return new GoogleMapProvider(apiKey); - case 'osm': - return new OpenStreetMapProvider(); - default: - throw new Error(`Unsupported map provider: ${mapProvider}`); - } - }; - async function loadStopsForLocation(lat, lng) { const response = await fetch(`/api/oba/stops-for-location?lat=${lat}&lng=${lng}`); if (!response.ok) { @@ -59,14 +43,14 @@ } async function initMap() { - mapInstance = createMapProvider(); - try { - await mapInstance.initMap(mapElement, { + await mapProvider.initMap(mapElement, { lat: Number(initialLat), lng: Number(initialLng) }); + mapInstance = mapProvider; + await loadStopsAndAddMarkers(initialLat, initialLng); const debouncedLoadMarkers = debounce(async () => { @@ -140,8 +124,10 @@ } function addMarker(s, routeReference) { - const container = document.createElement('div'); - document.body.appendChild(container); + if (!mapInstance) { + console.error('Map not initialized yet'); + return; + } let icon = faBus; @@ -155,26 +141,17 @@ icon = prioritizedRouteTypeForDisplay(prioritizedType); } - // TODO: move this into GoogleMapProvider - new StopMarker({ - target: container, - props: { - stop: s, - icon, - onClick: () => { - selectedStopID = s.id; - dispatch('stopSelected', { stop: s }); - } - } - }); - - const marker = mapInstance.addMarker({ + const markerObj = mapInstance.addMarker({ position: { lat: s.lat, lng: s.lon }, icon: icon, - element: container + stop: s, + onClick: () => { + selectedStopID = s.id; + dispatch('stopSelected', { stop: s }); + } }); - markers.push({ s, marker, element: container }); + markers.push(markerObj); } function handleThemeChange(event) { @@ -206,8 +183,8 @@ if (browser) { window.removeEventListener('themeChange', handleThemeChange); } - markers.forEach(({ marker, element }) => { - mapInstance.removeMarker(marker); + markers.forEach(({ markerObj, element }) => { + mapProvider.removeMarker(markerObj); if (element && element.parentNode) { element.parentNode.removeChild(element); } diff --git a/src/lib/Provider/GoogleMapProvider.js b/src/lib/Provider/GoogleMapProvider.js index 37045e8..c51f856 100644 --- a/src/lib/Provider/GoogleMapProvider.js +++ b/src/lib/Provider/GoogleMapProvider.js @@ -1,4 +1,6 @@ import { loadGoogleMapsLibrary, createMap, nightModeStyles } from '$lib/googleMaps'; +import StopMarker from '$components/map/StopMarker.svelte'; +import { faBus } from '@fortawesome/free-solid-svg-icons'; /* global google */ export default class GoogleMapProvider { constructor(apiKey) { @@ -31,42 +33,68 @@ export default class GoogleMapProvider { } addMarker(options) { - const marker = new google.maps.Marker({ - map: this.map, - position: options.position, - icon: { - url: - 'data:image/svg+xml;charset=UTF-8,' + - encodeURIComponent(''), - anchor: new google.maps.Point(0, 0), - scaledSize: new google.maps.Size(1, 1) - }, - label: { - text: ' ', - fontSize: '0px' - }, - optimized: false - }); + try { + const container = document.createElement('div'); + document.body.appendChild(container); + + new StopMarker({ + target: container, + props: { + stop: options.stop, + icon: options.icon || faBus, + onClick: options.onClick || (() => {}) + } + }); + + const marker = new google.maps.Marker({ + map: this.map, + position: options.position, + icon: { + url: + 'data:image/svg+xml;charset=UTF-8,' + + encodeURIComponent( + '' + ), + anchor: new google.maps.Point(0, 0), + scaledSize: new google.maps.Size(1, 1) + }, + label: { + text: ' ', + fontSize: '0px' + }, + optimized: false + }); + + const overlay = new google.maps.OverlayView(); + overlay.setMap(this.map); + overlay.draw = function () { + const projection = this.getProjection(); + const position = projection.fromLatLngToDivPixel(marker.getPosition()); + container.style.left = position.x - 20 + 'px'; + container.style.top = position.y - 20 + 'px'; + container.style.position = 'absolute'; + this.getPanes().overlayMouseTarget.appendChild(container); + }; - const overlay = new google.maps.OverlayView(); - overlay.setMap(this.map); - overlay.draw = function () { - const projection = this.getProjection(); - const position = projection.fromLatLngToDivPixel(marker.getPosition()); - options.element.style.left = position.x - 20 + 'px'; - options.element.style.top = position.y - 20 + 'px'; - options.element.style.position = 'absolute'; - this.getPanes().overlayMouseTarget.appendChild(options.element); - }; - - return { marker, overlay }; + return { marker, overlay, element: container }; + } catch (error) { + console.error('Error adding marker:', error); + return null; + } } removeMarker(markerObj) { - markerObj.marker.setMap(null); + if (!markerObj) return; - // TODO: I'm hitting an error here when zooming in. - markerObj.overlay.setMap(null); + if (markerObj.marker) { + markerObj.marker.setMap(null); + } + if (markerObj.overlay) { + markerObj.overlay.setMap(null); + } + if (markerObj.element && markerObj.element.parentNode) { + markerObj.element.parentNode.removeChild(markerObj.element); + } } setCenter(latLng) { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 1dcec6b..71aa291 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -5,6 +5,12 @@ import ModalPane from '../components/navigation/ModalPane.svelte'; import StopPane from '../components/oba/StopPane.svelte'; import SearchResults from '../components/search/SearchResults.svelte'; + import { + PUBLIC_OBA_GOOGLE_MAPS_API_KEY as apiKey, + } from '$env/static/public'; + import GoogleMapProvider from '$lib/Provider/GoogleMapProvider'; + + const mapProvider = new GoogleMapProvider(apiKey); let stop; let selectedTrip = null; @@ -13,6 +19,7 @@ let showRouteMap = false; let showAllStops = false; let searchResults = null; + function stopSelected(event) { stop = event.detail.stop; @@ -66,7 +73,7 @@ } -
+
@@ -91,7 +98,7 @@ on:stopSelected={stopSelected} /> {:else} -

No results found.

+

No results found.

{/if} {/if} @@ -103,4 +110,5 @@ {showRoute} {showRouteMap} {stop} + mapProvider={mapProvider} />