diff options
Diffstat (limited to 'modern/src/map/Map.js')
-rw-r--r-- | modern/src/map/Map.js | 103 |
1 files changed, 68 insertions, 35 deletions
diff --git a/modern/src/map/Map.js b/modern/src/map/Map.js index fec8d501..8a43e97b 100644 --- a/modern/src/map/Map.js +++ b/modern/src/map/Map.js @@ -1,8 +1,13 @@ import 'mapbox-gl/dist/mapbox-gl.css'; +import './switcher/switcher.css'; import mapboxgl from 'mapbox-gl'; +import { SwitcherControl } from './switcher/switcher'; import React, { useRef, useLayoutEffect, useEffect, useState } from 'react'; import { deviceCategories } from '../common/deviceCategories'; import { loadIcon, loadImage } from './mapUtil'; +import { styleCarto, styleMapbox, styleOsm } from './mapStyles'; +import t from '../common/localization'; +import { useAttributePreference } from '../common/preferences'; const element = document.createElement('div'); element.style.width = '100%'; @@ -10,55 +15,83 @@ element.style.height = '100%'; export const map = new mapboxgl.Map({ container: element, - style: { - version: 8, - sources: { - osm: { - type: 'raster', - tiles: ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"], - tileSize: 256, - attribution: '© <a target="_top" rel="noopener" href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', - }, - }, - glyphs: 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf', - layers: [{ - id: 'osm', - type: 'raster', - source: 'osm', - }], - }, + style: styleOsm(), }); -map.addControl(new mapboxgl.NavigationControl()); +let ready = false; +const readyListeners = new Set(); -let readyListeners = []; +const addReadyListener = listener => { + readyListeners.add(listener); + listener(ready); +}; -const onMapReady = listener => { - if (!readyListeners) { - listener(); - } else { - readyListeners.push(listener); - } +const removeReadyListener = listener => { + readyListeners.delete(listener); }; -map.on('load', async () => { +const updateReadyValue = value => { + ready = value; + readyListeners.forEach(listener => listener(value)); +}; + +const initMap = async () => { const background = await loadImage('images/background.svg'); await Promise.all(deviceCategories.map(async category => { - const imageData = await loadIcon(category, background, `images/icon/${category}.svg`); - map.addImage(category, imageData, { pixelRatio: window.devicePixelRatio }); + if (!map.hasImage(category)) { + const imageData = await loadIcon(category, background, `images/icon/${category}.svg`); + map.addImage(category, imageData, { pixelRatio: window.devicePixelRatio }); + } })); - if (readyListeners) { - readyListeners.forEach(listener => listener()); - readyListeners = null; - } -}); + updateReadyValue(true); +}; + +map.on('load', initMap); + +map.addControl(new mapboxgl.NavigationControl({ + showCompass: false, +})); + +map.addControl(new SwitcherControl( + [ + { title: t('mapOsm'), uri: styleOsm() }, + { title: t('mapCarto'), uri: styleCarto() }, + { title: t('mapMapboxStreets'), uri: styleMapbox('streets-v11') }, + { title: t('mapMapboxOutdoors'), uri: styleMapbox('outdoors-v11') }, + { title: t('mapMapboxSatellite'), uri: styleMapbox('satellite-v9') }, + ], + t('mapOsm'), + () => updateReadyValue(false), + () => { + const waiting = () => { + if (!map.loaded()) { + setTimeout(waiting, 100); + } else { + initMap(); + } + }; + waiting(); + }, +)); const Map = ({ children }) => { const containerEl = useRef(null); const [mapReady, setMapReady] = useState(false); - - useEffect(() => onMapReady(() => setMapReady(true)), []); + + const mapboxAccessToken = useAttributePreference('mapboxAccessToken'); + + useEffect(() => { + mapboxgl.accessToken = mapboxAccessToken; + }, [mapboxAccessToken]); + + useEffect(() => { + const listener = ready => setMapReady(ready); + addReadyListener(listener); + return () => { + removeReadyListener(listener); + }; + }, []); useLayoutEffect(() => { const currentEl = containerEl.current; |