ShowLocation component.

This commit is contained in:
Eric van der Vlist 2022-11-23 18:25:23 +01:00
parent 1555c00fe8
commit 2fa6199979
5 changed files with 107 additions and 11 deletions

View File

@ -3,7 +3,5 @@
--ion-background-color: white; --ion-background-color: white;
margin-left: calc(50% - 20px); margin-left: calc(50% - 20px);
position: fixed; position: fixed;
bottom: 6px bottom: 6px;
;
} }

View File

@ -7,12 +7,15 @@ import { IonButton, IonIcon } from '@ionic/react';
import { locateOutline } from 'ionicons/icons'; import { locateOutline } from 'ionicons/icons';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { stateAtom } from '../map'; import { stateAtom } from '../map';
import { locationAtom } from '../show-location';
// import { locationAtom } from '../map/CurrentLocation'; // import { locationAtom } from '../map/CurrentLocation';
const GetLocation: React.FC<{}> = () => { const GetLocation: React.FC<{}> = () => {
const [state, setState] = useAtom(stateAtom); const [state, setState] = useAtom(stateAtom);
const [, setLocation] = useAtom(locationAtom);
const onClickHandler = (event: any) => { const onClickHandler = (event: any) => {
console.log('Click handler'); console.log('Click handler');
Geolocation.getCurrentPosition().then((position) => { Geolocation.getCurrentPosition().then((position) => {
@ -22,6 +25,7 @@ const GetLocation: React.FC<{}> = () => {
rotation: state.rotation, rotation: state.rotation,
center: [position.coords.longitude, position.coords.latitude], center: [position.coords.longitude, position.coords.latitude],
}); });
setLocation([position.coords.longitude, position.coords.latitude]);
}); });
}; };

View File

@ -6,6 +6,9 @@ import { atomWithHash } from 'jotai-location';
import OlMap from 'ol/Map'; import OlMap from 'ol/Map';
import View from 'ol/View'; import View from 'ol/View';
import TileLayer from 'ol/layer/Tile'; 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 Attribution from 'ol/control/Attribution';
import Rotate from 'ol/control/Rotate'; import Rotate from 'ol/control/Rotate';
import ScaleLine from 'ol/control/ScaleLine'; import ScaleLine from 'ol/control/ScaleLine';
@ -17,13 +20,17 @@ import { isEqual } from 'lodash';
import './Map.css'; import './Map.css';
import Collection from 'ol/Collection'; import Collection from 'ol/Collection';
import { Circle, Fill, Stroke, Style, Icon } from 'ol/style';
import GetLocation from '../get-location'; import GetLocation from '../get-location';
import ShowLocation, { locationAtom } from '../show-location';
import { Point } from 'ol/geom';
export interface MapProperties {} export interface MapProperties {}
olUseGeographic(); olUseGeographic();
const mapAtom = atom<OlMap | null>(null); const mapAtom = atom<OlMap | null>(null);
const sourceAtom = atom<VectorSource | null>(null);
export const stateAtom = atomWithHash<any>('map', null); export const stateAtom = atomWithHash<any>('map', null);
//atom( //atom(
@ -47,24 +54,69 @@ export const stateAtom = atomWithHash<any>('map', null);
export const Map: React.FC<MapProperties> = (props: MapProperties) => { export const Map: React.FC<MapProperties> = (props: MapProperties) => {
const [map, setMap] = useAtom(mapAtom); const [map, setMap] = useAtom(mapAtom);
const [source, setSource] = useAtom(sourceAtom);
const [state, setState] = useAtom(stateAtom); const [state, setState] = useAtom(stateAtom);
const [location] = useAtom(locationAtom);
const target = useRef<HTMLDivElement>(null); const target = useRef<HTMLDivElement>(null);
const getLocation = useRef<HTMLDivElement>(null); const getLocation = useRef<HTMLDivElement>(null);
const showLocation = useRef<SVGSVGElement>(null);
const previousState = useRef<any>(null); const previousState = useRef<any>(null);
if (state && map) { if (state && map) {
if (!isEqual(state, previousState.current)) { if (!isEqual(state, previousState.current)) {
console.log({ caller: 'Map / updateView', state }); console.log({ caller: 'Map / updateView', state, map });
previousState.current = state; previousState.current = state;
map.getView().animate(state); const view = map.getView();
// view.beginInteraction();
// const view = new View(state);
// map.setView(view);
// map.renderSync();
// view.setCenter(state.center);
// view.setZoom(state.zoom);
// view.setRotation(state.rotation);
// view.resolveConstraints();
// view.endInteraction();
// map.setView(view);
// map.getView().animate(state);
// view.endInteraction();
view.animate({ ...state, duration: 500 });
} }
// const view = map.getView(); }
// view.setCenter(state.center);
// view.setZoom(state.zoom); if (source && location && showLocation.current) {
// view.setRotation(state.rotation); console.log({ caller: 'Map / updateLocation', location, source, map });
// map.renderSync(); source.clear(true);
const point = new Point(location);
const style = new Style({
image: new Icon({
// size: [20, 20],
imgSize: [24, 24],
declutterMode: 'declutter',
src: `data:image/svg+xml;utf8,${encodeURI(
showLocation.current.outerHTML
)}`,
}),
});
const feature = new Feature({
geometry: point,
// labelPoint: point,
// name: 'current location',
style: style,
});
feature.setStyle(style);
source.addFeature(feature);
// source.changed();
console.log({
caller: 'Map / updateLocation',
location,
source,
map,
style,
feature,
showLocation: showLocation.current,
});
} }
useEffect(() => { useEffect(() => {
@ -93,6 +145,8 @@ export const Map: React.FC<MapProperties> = (props: MapProperties) => {
new ScaleLine({ bar: true }), new ScaleLine({ bar: true }),
new Control({ element: getLocation.current ?? undefined }), new Control({ element: getLocation.current ?? undefined }),
]); ]);
const newSource = new VectorSource();
setSource(newSource);
const olMap = new OlMap({ const olMap = new OlMap({
view: new View( view: new View(
state ?? { state ?? {
@ -104,11 +158,12 @@ export const Map: React.FC<MapProperties> = (props: MapProperties) => {
new TileLayer({ new TileLayer({
source: new OSM(), source: new OSM(),
}), }),
new VectorLayer({ source: newSource }),
], ],
target: target.current ?? undefined, target: target.current ?? undefined,
controls, controls,
}); });
olMap.on(['change', 'moveend'], changeListener); olMap.on(['moveend'], changeListener);
setMap(olMap); setMap(olMap);
}, []); }, []);
@ -117,6 +172,15 @@ export const Map: React.FC<MapProperties> = (props: MapProperties) => {
<div ref={getLocation}> <div ref={getLocation}>
<GetLocation /> <GetLocation />
</div> </div>
<svg
ref={showLocation}
xmlns='http://www.w3.org/2000/svg'
width={24}
height={24}
version='1.1'
>
<ShowLocation />
</svg>
<div ref={target} className='ol-map'></div> <div ref={target} className='ol-map'></div>
</> </>
); );

View File

@ -0,0 +1,29 @@
import { atom, useAtom } from 'jotai';
import react from 'react';
export interface ShowLocationProperties {}
const initialLocation: number[] | null = null;
export const locationAtom = atom<number[] | null>(initialLocation);
export const ShowLocation: react.FC<ShowLocationProperties> = (
props: ShowLocationProperties
) => {
const [location] = useAtom(locationAtom);
console.log({ caller: 'ShowLocation', location });
return location !== null ? (
<circle
cx={8}
cy={8}
r={8}
fill='blue'
opacity='90%'
stroke='white'
strokeWidth={3}
strokeOpacity='100%'
/>
) : null;
};
export default ShowLocation;

View File

@ -0,0 +1 @@
export { default, locationAtom } from './ShowLocation';