diff --git a/src/Button/DrawButton/DrawButton.tsx b/src/Button/DrawButton/DrawButton.tsx index 7ed9c4b7d..de0d36f79 100644 --- a/src/Button/DrawButton/DrawButton.tsx +++ b/src/Button/DrawButton/DrawButton.tsx @@ -1,45 +1,20 @@ -import useMap from '@terrestris/react-util/dist/Hooks/useMap/useMap'; -import { DigitizeUtil } from '@terrestris/react-util/dist/Util/DigitizeUtil'; -import { EventsKey } from 'ol/events'; -import * as OlEventConditions from 'ol/events/condition'; +import { useDraw, UseDrawProps } from '@terrestris/react-util/dist/Hooks/useDraw/useDraw'; import OlFeature from 'ol/Feature'; 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 { unByKey } from 'ol/Observable'; -import OlVectorSource from 'ol/source/Vector'; -import { StyleLike as OlStyleLike } from 'ol/style/Style'; +import { + DrawEvent +} from 'ol/interaction/Draw'; import * as React from 'react'; -import { ReactNode, useEffect, useState } from 'react'; +import {ReactNode, useCallback, useState} from 'react'; import { CSS_PREFIX } from '../../constants'; import { FeatureLabelModal } from '../../FeatureLabelModal/FeatureLabelModal'; import ToggleButton, { ToggleButtonProps } from '../ToggleButton/ToggleButton'; -type DrawType = 'Point' | 'LineString' | 'Polygon' | 'Circle' | 'Rectangle' | 'Text'; +type ButtonDrawType = 'Point' | 'LineString' | 'Polygon' | 'Circle' | 'Rectangle' | 'Text'; interface OwnProps { - /** - * Whether the line, point, polygon, circle, rectangle or text shape should - * be drawn. - */ - drawType: DrawType; - /** - * 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; + drawType: ButtonDrawType; /** * Callback function that will be called when the ok-button of the modal was clicked */ @@ -54,11 +29,6 @@ interface OwnProps { * If exceeded label will be divided into multiple lines. Optional. */ maxLabelLineLength?: number; - /** - * The vector layer which will be used for digitize features. - * The standard digitizeLayer can be retrieved via `DigitizeUtil.getDigitizeLayer(map)`. - */ - digitizeLayer?: OlVectorLayer; /** * Title for modal used for input of labels for digitize features. */ @@ -71,19 +41,9 @@ interface OwnProps { * Text string for `Cancel` button of the modal. */ modalPromptCancelButtonText?: string; - /** - * 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; } -export type DrawButtonProps = OwnProps & Partial; +export type DrawButtonProps = OwnProps & Omit & Partial; /** * The className added to this component. @@ -110,108 +70,28 @@ const DrawButton: React.FC = ({ pressed, ...passThroughProps }) => { - - const [drawInteraction, setDrawInteraction] = useState(); - const [layer, setLayer] = useState | null>(null); - /** * Currently drawn feature which should be represented as label or post-it. */ const [digitizeTextFeature, setDigitizeTextFeature] = useState | null>(null); - const map = useMap(); - - useEffect(() => { - if (!map) { - return; - } - - if (digitizeLayer) { - setLayer(digitizeLayer); - } else { - setLayer(DigitizeUtil.getDigitizeLayer(map)); - } - }, [map, digitizeLayer]); - - useEffect(() => { - if (!map || !layer) { - return undefined; - } - - let geometryFunction; - let type: 'Point' | 'Circle' | 'LineString' | 'Polygon'; - - if (drawType === 'Rectangle') { - geometryFunction = createBox(); - type = 'Circle'; - } else if (drawType === 'Text') { - type = 'Point'; - } 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}`); - - newInteraction.setActive(false); - - map.addInteraction(newInteraction); - - setDrawInteraction(newInteraction); - - let key: EventsKey; - + const onDrawEndInternal = useCallback((evt: DrawEvent) => { if (drawType === 'Text') { - key = newInteraction.on('drawend', evt => { - evt.feature.set('isLabel', true); - setDigitizeTextFeature(evt.feature); - }); - } - - return () => { - unByKey(key); - map.removeInteraction(newInteraction); - }; - }, [drawType, layer, drawInteractionConfig, drawStyle, map]); - - useEffect(() => { - if (!drawInteraction) { - return undefined; + evt.feature.set('isLabel', true); + setDigitizeTextFeature(evt.feature); } - - const endKey = drawInteraction.on('drawend', (evt) => { - onDrawEnd?.(evt); - }); - - const startKey = drawInteraction.on('drawstart', (evt) => { - onDrawStart?.(evt); - }); - - return () => { - unByKey(startKey); - unByKey(endKey); - }; - }, [drawInteraction, onDrawStart, onDrawEnd]); - - useEffect(() => { - if (!drawInteraction) { - return; - } - - drawInteraction.setActive(!!pressed); - }, [drawInteraction, pressed]); - - if (!drawInteraction || !layer) { - return null; - } + onDrawEnd?.(evt); + }, [drawType, onDrawEnd]); + + useDraw({ + onDrawEnd: onDrawEndInternal, + digitizeLayer, + drawInteractionConfig, + drawStyle, + drawType: drawType === 'Text' ? 'Point' : drawType, + onDrawStart, + active: !!pressed + }); const finalClassName = className ? `${defaultClassName} ${className}` @@ -228,19 +108,21 @@ const DrawButton: React.FC = ({ const onModalLabelCancelInternal = () => { onModalLabelCancel?.(); - layer.getSource()?.removeFeature(digitizeTextFeature); + digitizeLayer?.getSource()?.removeFeature(digitizeTextFeature); setDigitizeTextFeature(null); }; - modal = ; + modal = ( + + ); } return ( @@ -250,8 +132,11 @@ const DrawButton: React.FC = ({ pressed={pressed} {...passThroughProps} /> - {modal} - ); + { + modal + } + + ); }; export default DrawButton;