import { Component, createEffect, createSignal, onMount } from 'solid-js'; import { useParams, useNavigate } from '@solidjs/router'; import OlMap from 'ol/Map'; import View from 'ol/View'; import TileLayer from 'ol/layer/Tile'; import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; import Feature from 'ol/Feature'; import Attribution from 'ol/control/Attribution'; import Rotate from 'ol/control/Rotate'; import ScaleLine from 'ol/control/ScaleLine'; import Control from 'ol/control/Control'; import { useGeographic as olUseGeographic } from 'ol/proj'; import DragRotate from 'ol/interaction/DragRotate'; import 'ol/ol.css'; import './Map.css'; import { Collection } from 'ol'; import { Point } from 'ol/geom'; import { Style, Icon } from 'ol/style'; import GetLocation, { getCurrentLocation } from '../get-location'; import ShowLocationIcon from '../get-location/ShowLocationIcon.svg'; import { Back, Forward } from '../back-forward'; import GpxImport from '../gpx-import'; import AllGpxes from '../all-gpxes'; import MapTileProvider, { mapTileProviders } from '../map-tile-provider'; import Interaction from 'ol/interaction/Interaction'; import DoubleClickZoom from 'ol/interaction/DoubleClickZoom'; import DragPan from 'ol/interaction/DragPan'; import PinchRotate from 'ol/interaction/PinchRotate'; import PinchZoom from 'ol/interaction/PinchZoom'; import KeyboardPan from 'ol/interaction/KeyboardPan'; import KeyboardZoom from 'ol/interaction/KeyboardZoom'; import MouseWheelZoom from 'ol/interaction/MouseWheelZoom'; import DragZoom from 'ol/interaction/DragZoom'; import Infos, { clickHandler } from '../infos'; import GpxDialog from '../gpx-dialog'; import GpxRecord from '../gpx-record'; const [getState, setState] = createSignal({ lon: 0, lat: 0, rotation: 0, zoom: 0, provider: 'osm', }); export { getState }; const [getMap, setMap] = createSignal(null); export { getMap }; const Map: Component = () => { const params = useParams(); const navigate = useNavigate(); let target: HTMLDivElement; createEffect(() => { console.log({ caller: 'Map / setState', params: { ...params, }, }); setState({ provider: params.provider, lon: +params.lon, lat: +params.lat, rotation: +params.rotation, zoom: +params.zoom, }); const map = getMap(); const layers = map?.getLayers(); const tileLayer = layers?.item(0) as TileLayer | undefined; if (tileLayer?.get('provider') !== params.provider) { tileLayer?.set('provider', params.provider, true); tileLayer?.setSource(mapTileProviders[params.provider].source); } const view = map?.getView(); view?.animate({ center: [getState().lon, getState().lat], rotation: getState().rotation, zoom: getState().zoom, duration: 1000, }); }); createEffect(() => { const location = getCurrentLocation(); if (location) { console.log({ caller: 'Map / updateLocation', location, }); const source = getMap() ?.getAllLayers() .at(1) ?.getSource() as VectorSource; source!.clear(true); const point = new Point([location.lon, location.lat]); const style = new Style({ image: new Icon({ // size: [20, 20], imgSize: [24, 24], declutterMode: 'obstacle', // @ts-ignore src: ShowLocationIcon, }), }); const feature = new Feature({ geometry: point, // labelPoint: point, // name: 'current location', style: style, }); feature.set('type', 'current-location'); feature.setStyle(style); source.addFeature(feature); // source.changed(); console.log({ caller: 'Map / updateLocation', location, source, style, feature, }); } }); onMount(() => { olUseGeographic(); const changeListener = (event: any) => { const map = getMap(); const view = map?.getView(); const center = view?.getCenter(); if (center) { navigate( `/map/${getState().provider}/${center[0]}/${ center[1] }/${view?.getZoom()}/${view?.getRotation()}` ); } console.log({ caller: 'Map / changeListener', event, params: { ...params, }, map, }); }; const tileLayer = new TileLayer({ source: mapTileProviders[params.provider].source, }); tileLayer.set('provider', params.provider, true); const vectorLayer = new VectorLayer({ source: new VectorSource(), zIndex: Infinity, }); const olMap = new OlMap({ view: new View({ center: [+getState().lon, +getState().lat], zoom: +getState().zoom, rotation: +getState().rotation, }), layers: [tileLayer, vectorLayer], target: target, controls: new Collection([ new Attribution({ collapsible: true }), new Rotate(), new ScaleLine({ bar: true }), ]), moveTolerance: 10, interactions: new Collection([ new DragRotate(), new DoubleClickZoom(), new DragPan(), new PinchRotate(), new PinchZoom(), new KeyboardPan(), new KeyboardZoom(), new MouseWheelZoom(), new DragZoom(), ]), }); olMap.on(['moveend'], changeListener); olMap.on(['singleclick'], clickHandler); setMap(olMap); }); return ( // @ts-ignore
); }; export default Map;