Skip to content

Commit

Permalink
Merge pull request #465 from terrestris/ol-hooks
Browse files Browse the repository at this point in the history
feat: add some ol related hooks
  • Loading branch information
hwbllmnn authored Sep 5, 2023
2 parents 20e8dd3 + f7636c7 commit b55a052
Show file tree
Hide file tree
Showing 8 changed files with 457 additions and 4 deletions.
245 changes: 244 additions & 1 deletion package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
},
"dependencies": {
"@terrestris/base-util": "^1.0.1",
"lodash": "^4.17.21"
"lodash": "^4.17.21",
"ol": "^8.0.0"
},
"devDependencies": {
"@babel/core": "^7.14.0",
Expand All @@ -66,10 +67,10 @@
"jest-fetch-mock": "^3.0.3",
"less": "^4.1.1",
"np": "^7.5.0",
"regenerator-runtime": "^0.13.7",
"rimraf": "^3.0.2",
"react": "^18.0.0",
"react-dom": "^18.1.0",
"regenerator-runtime": "^0.13.7",
"rimraf": "^3.0.2",
"ts-jest": "^26.5.6",
"typescript": "^4.2.4"
}
Expand Down
5 changes: 5 additions & 0 deletions src/contexts/MapContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import OlMap from 'ol/Map';
import React from 'react';

const MapContext = React.createContext<OlMap|null>(null);
export default MapContext;
13 changes: 13 additions & 0 deletions src/hooks/useMap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
useContext
} from 'react';

import OlMap from 'ol/Map';

import MapContext from '../contexts/MapContext';

export const useMap = (): (OlMap | undefined) => {
return useContext(MapContext);
};

export default useMap;
60 changes: 60 additions & 0 deletions src/hooks/useOlInteraction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
DependencyList,
useEffect,
useState
} from 'react';

import {
isNil
} from 'lodash';

import {
Interaction
} from 'ol/interaction';

import useMap from './useMap';

/**
* This hook adds an interaction to the map and removes/updates it if the dependency array changes.
* It accepts an optional active parameter that toggles the active state of the interaction. If it is undefined the
* active state will not get changed.
* @param constructor returns an interaction to be added to the map, will be called again, if the interaction needs
* to be updated
* @param dependencies
* @param active
*/
export const useOlInteraction = <InteractionType extends Interaction> (
constructor: () => InteractionType|undefined,
dependencies: DependencyList,
active?: undefined|boolean
): InteractionType|undefined => {
const map = useMap();
const [interaction, setInteraction] = useState<InteractionType>();
useEffect(() => {
if (!map) {
return undefined;
}

const newInteraction = constructor();
if (!newInteraction) {
return undefined;
}

setInteraction(newInteraction);
map.addInteraction(newInteraction);

return () => {
map.removeInteraction(newInteraction);
setInteraction(undefined);
};
}, [...dependencies, map]);

useEffect(() => {
if (!interaction || isNil(active)) {
return;
}
interaction.setActive(active);
}, [interaction, active]);

return interaction;
};
58 changes: 58 additions & 0 deletions src/hooks/useOlLayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
DependencyList,
useEffect,
useState
} from 'react';

import {
isNil
} from 'lodash';
import BaseLayer from 'ol/layer/Base';

import useMap from './useMap';

/**
* This hook adds a layer to the map and removes/updates it if the dependency array changes.
* It accepts an optional visible parameter that toggles the visible state of the layer. If it is undefined the
* visible state will not get changed.
* @param constructor returns a layer to be added to the map, will be called again, if the layer needs
* to be updated
* @param dependencies
* @param visible
*/
export const useOlLayer = <LayerType extends BaseLayer>(
constructor: () => LayerType|undefined,
dependencies: DependencyList,
visible?: undefined|boolean
): LayerType|undefined => {
const map = useMap();
const [layer, setLayer] = useState<LayerType>();
useEffect(() => {
if (!map) {
return undefined;
}

const newLayer = constructor();

if (!newLayer) {
return undefined;
}

map.addLayer(newLayer);
setLayer(newLayer);
return () => {
map.removeLayer(newLayer);
setLayer(undefined);
};
}, [map, ...dependencies]);

useEffect(() => {
if (!layer || isNil(visible)) {
return;
}

layer.setVisible(visible);
}, [layer, visible]);

return layer;
};
40 changes: 40 additions & 0 deletions src/hooks/useOlListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
DependencyList,
useEffect
} from 'react';

import {
Observable
} from 'ol';
import {
EventsKey
} from 'ol/events';
import {
unByKey
} from 'ol/Observable';

/**
* This hook unregisters listeners if the dependency array changes
*/
export const useOlListener = <ObservableType extends Observable>(
observable: ObservableType|ObservableType[]|undefined,
observe: (o: ObservableType) => EventsKey|EventsKey[],
dependencies: DependencyList,
active?: boolean
): void => {
useEffect(() => {
if (!observable || active === false) {
return undefined;
}
const observables = Array.isArray(observable) ? observable : [observable];
const keys: EventsKey[] = observables.flatMap(o => {
const k = observe(o);
return Array.isArray(k) ? k : [k];
});
return () => {
for (const key of keys) {
unByKey(key);
}
};
}, [observable, active, ...dependencies]);
};
33 changes: 33 additions & 0 deletions src/hooks/usePermalink/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
useEffect,
useRef
} from 'react';

import OlInteractionLink from 'ol/interaction/Link';

import OlMap from 'ol/Map';

export const usePermalink = (map: OlMap|undefined) => {
const linkInteractionRef = useRef<OlInteractionLink>();

useEffect(() => {
if (!map) {
return undefined;
}

if (!linkInteractionRef.current) {
linkInteractionRef.current = new OlInteractionLink({
params: ['x', 'y', 'z', 'r']
});
map.addInteraction(linkInteractionRef.current);
}

return () => {
if (linkInteractionRef.current) {
map.removeInteraction(linkInteractionRef.current);
}
};
}, [map]);
};

export default usePermalink;

0 comments on commit b55a052

Please sign in to comment.