Skip to content

Commit

Permalink
feat: create useSelectFeatures and usePropOrDefault hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
simonseyock committed Sep 6, 2023
1 parent 920f823 commit c0df0ed
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 14 deletions.
23 changes: 9 additions & 14 deletions src/hooks/useDraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import OlInteractionDraw, { createBox, DrawEvent as OlDrawEvent, Options as OlDr
import OlVectorLayer from 'ol/layer/Vector';
import OlVectorSource from 'ol/source/Vector';
import { StyleLike as OlStyleLike } from 'ol/style/Style';
import { useEffect, useState } from 'react';

import {useOlListener} from "./useOlListener";

Check warning on line 10 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Strings must use singlequote

Check warning on line 10 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Strings must use singlequote
import {useOlInteraction} from "./useOlInteraction";

Check warning on line 11 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Strings must use singlequote

Check warning on line 11 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Strings must use singlequote
import {usePropOrDefault} from "./usePropOrDefault";

Check warning on line 12 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Strings must use singlequote

Check warning on line 12 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Strings must use singlequote

export type UseDrawType = 'Point' | 'LineString' | 'Polygon' | 'Circle' | 'Rectangle';

export interface UseDrawProps {
/**
* Active state of interaction
*/
active: boolean;
/**
* Whether the line, point, polygon, circle, rectangle or text shape should
Expand Down Expand Up @@ -62,21 +65,13 @@ export const useDraw = ({
onDrawEnd,

Check warning on line 65 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (16.x)

Expected indentation of 2 spaces but found 4

Check warning on line 65 in src/hooks/useDraw.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Expected indentation of 2 spaces but found 4
onDrawStart
}: UseDrawProps) => {
const [layer, setLayer] = useState<OlVectorLayer<OlVectorSource<OlGeometry>> | null>(null);

const map = useMap();

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

if (digitizeLayer) {
setLayer(digitizeLayer);
} else {
setLayer(DigitizeUtil.getDigitizeLayer(map));
}
}, [map, digitizeLayer]);
const layer = usePropOrDefault(
digitizeLayer,
() => map ? DigitizeUtil.getDigitizeLayer(map) : undefined,
[map]
);

const drawInteraction = useOlInteraction(
() => {
Expand Down
14 changes: 14 additions & 0 deletions src/hooks/usePropOrDefault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {DependencyList, useEffect, useState} from "react";

export const usePropOrDefault = <T>(prop: T|undefined, defaultFunc: () => T, dependencies: DependencyList): T|undefined => {
const [value, setValue] = useState<T>(undefined);
useEffect(() => {
if (prop) {
setValue(prop);
} else {
setValue(defaultFunc());
}
}, [prop, ...dependencies]);

return value;
};
113 changes: 113 additions & 0 deletions src/hooks/useSelectFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {DigitizeUtil} from '../Util/DigitizeUtil';
import OlCollection from 'ol/Collection';
import * as OlEventConditions from 'ol/events/condition';
import OlFeature from 'ol/Feature';
import OlGeometry from 'ol/geom/Geometry';
import OlInteractionSelect, {Options as OlSelectOptions, SelectEvent as OlSelectEvent} from 'ol/interaction/Select';
import OlVectorLayer from 'ol/layer/Vector';
import OlVectorSource from 'ol/source/Vector';
import {StyleLike as OlStyleLike} from 'ol/style/Style';
import {useEffect} from 'react';

import {useOlInteraction} from "./useOlInteraction";
import {usePropOrDefault} from "./usePropOrDefault";
import {useOlListener} from "./useOlListener";

export interface UseSelectFeaturesProps {
/**
* Active state of interaction
*/
active: boolean;
/**
* Select style of the selected features.
*/
selectStyle?: OlStyleLike;
/**
* Additional configuration object to apply to the ol.interaction.Select.
* See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Select-Select.html
* for more information
*
* Note: The keys condition, hitTolerance and style are handled internally
* and shouldn't be overwritten without any specific cause.
*/
selectInteractionConfig?: Omit<OlSelectOptions, 'condition' | 'features' | 'hitTolerance' | 'style' | 'layers'>;
/**
* Listener function for the 'select' event of the ol.interaction.Select
* See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Select.html
* for more information.
*/
onFeatureSelect?: (event: OlSelectEvent) => void;
/**
* Array of layers the SelectFeaturesButton should operate on.
*/
layers: OlVectorLayer<OlVectorSource<OlGeometry>>[];
/**
* Hit tolerance of the select action. Default: 5
*/
hitTolerance?: number;
/**
* Clear the feature collection of the interaction after select. Default: false
*/
clearAfterSelect?: boolean;
/**
* A feature collection to use.
*/
featuresCollection?: OlCollection<OlFeature<OlGeometry>>;
}

export const useSelectFeatures = ({
active,
selectStyle,
selectInteractionConfig,
onFeatureSelect,
hitTolerance = 5,
layers,
clearAfterSelect = false,
featuresCollection,
}: UseSelectFeaturesProps) => {
const features = usePropOrDefault(
featuresCollection,
() => new OlCollection(),
[]
);

const selectInteraction = useOlInteraction(
() => {
if (!features) {
return undefined;
}

const newInteraction = new OlInteractionSelect({
condition: OlEventConditions.singleClick,
features,
hitTolerance: hitTolerance,
style: selectStyle ?? DigitizeUtil.DEFAULT_SELECT_STYLE,
layers: layers,
...(selectInteractionConfig ?? {})
});

newInteraction.set('name', 'react-geo-select-interaction');

return newInteraction;
},
[features, hitTolerance, selectStyle, layers, selectInteractionConfig],
active
);

useOlListener(
selectInteraction,
i => i.on('select', e => {
if (features && clearAfterSelect) {
features.clear();
}
onFeatureSelect?.(e);
}),
[features, clearAfterSelect, onFeatureSelect]
);

useEffect(() => {
if (!active && features) {
features.clear();
}
}, []);
};

0 comments on commit c0df0ed

Please sign in to comment.