From 5664810aa19e6d06c491bcd46fcb9cf2b46679eb Mon Sep 17 00:00:00 2001 From: Simon Seyock Date: Wed, 6 Sep 2023 19:45:06 +0200 Subject: [PATCH] refactor: modify button uses `useModify` hook --- src/Button/ModifyButton/ModifyButton.tsx | 232 ++++------------------- 1 file changed, 40 insertions(+), 192 deletions(-) diff --git a/src/Button/ModifyButton/ModifyButton.tsx b/src/Button/ModifyButton/ModifyButton.tsx index 86d0b61257..1dabc4833b 100644 --- a/src/Button/ModifyButton/ModifyButton.tsx +++ b/src/Button/ModifyButton/ModifyButton.tsx @@ -1,76 +1,19 @@ -import useMap from '@terrestris/react-util/dist/Hooks/useMap/useMap'; -import { DigitizeUtil } from '@terrestris/react-util/dist/Util/DigitizeUtil'; -import OlCollection from 'ol/Collection'; -import { singleClick } from 'ol/events/condition'; +import { useModify, UseModifyProps } from '@terrestris/react-util/dist/Hooks/useModify/useModify'; import OlFeature from 'ol/Feature'; import OlGeometry from 'ol/geom/Geometry'; -import Modify, { ModifyEvent, Options as ModifyOptions } from 'ol/interaction/Modify'; import { SelectEvent as OlSelectEvent } from 'ol/interaction/Select'; -import Translate, { Options as TranslateOptions, TranslateEvent } from 'ol/interaction/Translate'; -import OlVectorLayer from 'ol/layer/Vector'; -import { unByKey } from 'ol/Observable'; -import OlVectorSource from 'ol/source/Vector'; 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 SelectFeaturesButton, { SelectFeaturesButtonProps } from '../SelectFeaturesButton/SelectFeaturesButton'; +import ToggleButton, {ToggleButtonProps} from '../ToggleButton/ToggleButton'; interface OwnProps { /** - * Additional configuration object to apply to the ol.interaction.Modify. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Modify-Modify.html - * for more information - * - * Note: The keys features, deleteCondition and style are handled internally - * and shouldn't be overwritten without any specific cause. + * The className which should be added. */ - modifyInteractionConfig?: Omit; - /** - * Additional configuration object to apply to the ol.interaction.Translate. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Translate-Translate.html - * for more information - * - * Note: The key feature is handled internally and shouldn't be overwritten - * without any specific cause. - */ - translateInteractionConfig?: Omit; - /** - * The vector layer which will be used for digitize features. - * The standard digitizeLayer can be retrieved via `DigitizeUtil.getDigitizeLayer(map)`. - */ - digitizeLayer?: OlVectorLayer>; - /** - * Listener function for the 'modifystart' event of an ol.interaction.Modify. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Modify-ModifyEvent.html - * for more information. - */ - onModifyStart?: (event: ModifyEvent) => void; - /** - * Listener function for the 'modifyend' event of an ol.interaction.Modify. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Modify-ModifyEvent.html - * for more information. - */ - onModifyEnd?: (event: ModifyEvent) => void; - /** - * Listener function for the 'translatestart' event of an ol.interaction.Translate. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Translate-TranslateEvent.html - * for more information. - */ - onTranslateStart?: (event: TranslateEvent) => void; - /** - * Listener function for the 'translateend' event of an ol.interaction.Translate. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Translate-TranslateEvent.html - * for more information. - */ - onTranslateEnd?: (event: TranslateEvent) => void; - /** - * Listener function for the 'translating' event of an ol.interaction.Translate. - * See https://openlayers.org/en/latest/apidoc/module-ol_interaction_Translate-TranslateEvent.html - * for more information. - */ - onTranslating?: (event: TranslateEvent) => void; + className?: string; /** * Callback function that will be called when the ok-button of the modal was clicked */ @@ -103,8 +46,7 @@ interface OwnProps { editLabel?: boolean; } -export type ModifyButtonProps = OwnProps & Omit; +export type ModifyButtonProps = OwnProps & Omit & Partial; /** * The className added to this component. @@ -113,6 +55,7 @@ const defaultClassName = `${CSS_PREFIX}modifybutton`; export const ModifyButton: React.FC = ({ className, + hitTolerance = 5, onModifyStart, onModifyEnd, onTranslateStart, @@ -120,6 +63,7 @@ export const ModifyButton: React.FC = ({ onTranslating, digitizeLayer, selectStyle, + selectInteractionConfig, modifyInteractionConfig, translateInteractionConfig, onModalLabelOk, @@ -132,136 +76,36 @@ export const ModifyButton: React.FC = ({ pressed, ...passThroughProps }) => { - const [layers, setLayers] = useState<[OlVectorLayer>]|null>(null); - const [modifyInteraction, setModifyInteraction] = useState(null); - const [translateInteraction, setTranslateInteraction] = useState(null); - const [features, setFeatures] = useState>|null>(null); - - const map = useMap(); - const [editLabelFeature, setEditLabelFeature] = useState|null>(null); - useEffect(() => { - if (!map) { - return; - } - - setLayers([digitizeLayer ?? DigitizeUtil.getDigitizeLayer(map)]); - setFeatures(new OlCollection()); - }, [map, digitizeLayer]); - - useEffect(() => { - if (!map || !features) { - return undefined; - } - - const newTranslateInteraction = new Translate({ - features, - ...translateInteractionConfig - }); - newTranslateInteraction.set('name', 'react-geo-translate-interaction'); - newTranslateInteraction.setActive(false); - - map.addInteraction(newTranslateInteraction); - setTranslateInteraction(newTranslateInteraction); - - const newModifyInteraction = new Modify({ - features, - deleteCondition: singleClick, - style: selectStyle ?? DigitizeUtil.DEFAULT_SELECT_STYLE, - ...modifyInteractionConfig - }); - newModifyInteraction.set('name', 'react-geo-modify-interaction'); - newModifyInteraction.setActive(false); - - map.addInteraction(newModifyInteraction); - setModifyInteraction(newModifyInteraction); - - return () => { - map.removeInteraction(newModifyInteraction); - map.removeInteraction(newTranslateInteraction); - }; - }, [selectStyle, modifyInteractionConfig, translateInteractionConfig, features, map]); - - useEffect(() => { - if (!modifyInteraction) { - return undefined; - } - - const startKey = modifyInteraction.on('modifystart', e => { - onModifyStart?.(e); - }); - - const endKey = modifyInteraction.on('modifyend', e => { - onModifyEnd?.(e); - }); - - return () => { - unByKey(startKey); - unByKey(endKey); - }; - }, [modifyInteraction, onModifyStart, onModifyEnd]); - - useEffect(() => { - if (!translateInteraction) { - return undefined; - } - - const startKey = translateInteraction.on('translatestart', e => { - onTranslateStart?.(e); - }); - - const endKey = translateInteraction.on('translateend', e => { - onTranslateEnd?.(e); - }); - - const translatingKey = translateInteraction.on('translating', e => { - onTranslating?.(e); - }); - - return () => { - unByKey(startKey); - unByKey(endKey); - unByKey(translatingKey); - }; - }, [translateInteraction, onTranslateStart, onTranslateEnd, onTranslating]); - - useEffect(() => { - if (!modifyInteraction || !translateInteraction) { - return; - } - - modifyInteraction.setActive(!!pressed); - translateInteraction.setActive(!!pressed); - }, [modifyInteraction, translateInteraction, pressed]); - - if (!layers || !features || !modifyInteraction || !translateInteraction) { - return null; - } - - const onFeatureSelect = (event: OlSelectEvent) => { + const onFeatureSelect = useCallback((event: OlSelectEvent) => { if (editLabel) { const labeled = event.selected.find(f => f.get('isLabel')); setEditLabelFeature(labeled || null); } - }; + }, [editLabel]); + + useModify({ + selectStyle, + selectInteractionConfig, + digitizeLayer, + onModifyStart, + onModifyEnd, + onTranslateStart, + onTranslateEnd, + onTranslating, + active: !!pressed, + modifyInteractionConfig, + translateInteractionConfig, + onFeatureSelect, + hitTolerance + }); const finalClassName = className ? `${defaultClassName} ${className}` : defaultClassName; - const button = ( - - ); + const btnWrapperClass = `${CSS_PREFIX}digitize-button-wrapper`; let modal: ReactNode = null; if (editLabelFeature) { @@ -277,25 +121,29 @@ export const ModifyButton: React.FC = ({ modal = ( ); } - if (!editLabel) { - return button; - } else { - return <> - {button} - {modal} - ; - } + return ( + + + { + modal + } + + ); }; export default ModifyButton;