Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

several digitize related hooks #472

Merged
merged 3 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions src/hooks/useDraw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import * as OlEventConditions from 'ol/events/condition';
import OlGeometry from 'ol/geom/Geometry';
import OlInteractionDraw, { createBox, DrawEvent as OlDrawEvent, Options as OlDrawOptions } from 'ol/interaction/Draw';
import OlVectorLayer from 'ol/layer/Vector';
import OlVectorSource from 'ol/source/Vector';
import { StyleLike as OlStyleLike } from 'ol/style/Style';

import { DigitizeUtil } from '../Util/DigitizeUtil';
import useMap from './useMap';
import {useOlInteraction} from './useOlInteraction';
import {useOlListener} from './useOlListener';
import {usePropOrDefault} from './usePropOrDefault';

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
* be drawn.
*/
drawType: UseDrawType;
/**
* Style object / style function for drawn feature.
*/
drawStyle?: OlStyleLike;
/**
* Listener function for the 'drawend' event of an ol.interaction.Draw.
* See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Draw-DrawEvent.html
* for more information.
*/
onDrawEnd?: (event: OlDrawEvent) => void;
/**
* Listener function for the 'drawstart' event of an ol.interaction.Draw.
* See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Draw-DrawEvent.html
* for more information.
*/
onDrawStart?: (event: OlDrawEvent) => void;
/**
* The vector layer which will be used for digitize features.
* The standard digitizeLayer can be retrieved via `DigitizeUtil.getDigitizeLayer(map)`.
*/
digitizeLayer?: OlVectorLayer<OlVectorSource<OlGeometry>>;
/**
* Additional configuration object to apply to the ol.interaction.Draw.
* See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Draw-Draw.html
* for more information
*
* Note: The keys source, type, geometryFunction, style and freehandCondition
* are handled internally and shouldn't be overwritten without any
* specific cause.
*/
drawInteractionConfig?: Omit<OlDrawOptions, 'source'|'type'|'geometryFunction'|'style'|'freehandCondition'>;
}

export const useDraw = ({
active,
digitizeLayer,
drawInteractionConfig,
drawStyle,
drawType,
onDrawEnd,
onDrawStart
}: UseDrawProps) => {
const map = useMap();

const layer = usePropOrDefault(
digitizeLayer,
() => map ? DigitizeUtil.getDigitizeLayer(map) : undefined,
[map]
);

const drawInteraction = useOlInteraction(
() => {
if (!map || !layer) {
return undefined;
}

let geometryFunction;
let type: 'Point' | 'Circle' | 'LineString' | 'Polygon';

if (drawType === 'Rectangle') {
geometryFunction = createBox();
type = 'Circle';
} else {
type = drawType;
}

const newInteraction = new OlInteractionDraw({
source: layer.getSource() || undefined,
type: type,
geometryFunction: geometryFunction,
style: drawStyle ?? DigitizeUtil.defaultDigitizeStyleFunction,
freehandCondition: OlEventConditions.never,
...(drawInteractionConfig ?? {})
});

newInteraction.set('name', `react-geo-draw-interaction-${drawType}`);
return newInteraction;
},
[map, layer, drawType, drawStyle, drawInteractionConfig],
active
);

useOlListener(
drawInteraction,
i => i.on('drawend', (evt) => {
onDrawEnd?.(evt);
}),
[drawInteraction, onDrawEnd]
);

useOlListener(
drawInteraction,
i => i.on('drawstart', (evt) => {
onDrawStart?.(evt);
}),
[drawInteraction, onDrawStart]
);
};
18 changes: 18 additions & 0 deletions src/hooks/usePropOrDefault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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 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 {DigitizeUtil} from '../Util/DigitizeUtil';
import {useOlInteraction} from './useOlInteraction';
import {useOlListener} from './useOlListener';
import {usePropOrDefault} from './usePropOrDefault';

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();
}
}, []);
};
Loading