Skip to content

Commit

Permalink
feat: make feature text modal an own component
Browse files Browse the repository at this point in the history
  • Loading branch information
simonseyock committed Jan 28, 2022
1 parent 0bac307 commit 9ce529d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 78 deletions.
122 changes: 44 additions & 78 deletions src/Button/DrawButton/DrawButton.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import * as React from 'react';
import { useEffect, useState } from 'react';

import { Modal, Input } from 'antd';

const TextArea = Input.TextArea;

import { StyleLike as OlStyleLike } from 'ol/style/Style';
import OlInteractionDraw, { createBox, DrawEvent as OlDrawEvent, Options as OlDrawOptions } from 'ol/interaction/Draw';
import OlFeature from 'ol/Feature';
Expand All @@ -14,45 +10,15 @@ import OlVectorSource from 'ol/source/Vector';
import OlGeometry from 'ol/geom/Geometry';
import OlVectorLayer from 'ol/layer/Vector';

import StringUtil from '@terrestris/base-util/dist/StringUtil/StringUtil';

import ToggleButton, { ToggleButtonProps } from '../ToggleButton/ToggleButton';
import { CSS_PREFIX } from '../../constants';
import { useMap } from '../../Hook/useMap';
import { DigitizeUtil } from '../../Util/DigitizeUtil';

interface DefaultProps {
/**
* Title for modal used for input of labels for digitize features.
*/
modalPromptTitle: string;
/**
* Text string for `OK` button of the modal.
*/
modalPromptOkButtonText: string;
/**
* 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: OlDrawOptions;
}
import { FeatureLabelModal } from '../../FeatureLabelModal/FeatureLabelModal';

type DrawType = 'Point' | 'LineString' | 'Polygon' | 'Circle' | 'Rectangle' | 'Text';

interface BaseProps {
/**
* The className which should be added.
*/
className?: string;
interface OwnProps {
/**
* Whether the line, point, polygon, circle, rectangle or text shape should
* be drawn.
Expand Down Expand Up @@ -82,7 +48,7 @@ interface BaseProps {
* Callback function that will be called
* when the cancel-button of the modal was clicked
*/
onModalLabelCancel?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
onModalLabelCancel?: () => void;
/**
* Maximal length of feature label.
* If exceeded label will be divided into multiple lines. Optional.
Expand All @@ -93,9 +59,31 @@ interface BaseProps {
* The standard digitizeLayer can be retrieved via `DigitizeUtil.getDigitizeLayer(map)`.
*/
digitizeLayer?: OlVectorLayer<OlVectorSource<OlGeometry>>;
/**
* Title for modal used for input of labels for digitize features.
*/
modalPromptTitle?: string;
/**
* Text string for `OK` button of the modal.
*/
modalPromptOkButtonText?: string;
/**
* 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<OlDrawOptions, 'source'|'type'|'geometryFunction'|'style'|'freehandCondition'>;
}

export type DrawButtonProps = BaseProps & Partial<DefaultProps> & ToggleButtonProps;
export type DrawButtonProps = OwnProps & ToggleButtonProps;

/**
* The className added to this component.
Expand Down Expand Up @@ -123,11 +111,14 @@ const DrawButton: React.FC<DrawButtonProps> = ({
...passThroughProps
}) => {

const [showLabelPrompt, setShowLabelPrompt] = useState<boolean>(false);
const [textLabel, setTextLabel] = useState<string>('');
const [drawInteraction, setDrawInteraction] = useState<OlInteractionDraw>();
const [layer, setLayer] = useState<OlVectorLayer<OlVectorSource<OlGeometry>>>(null);

/**
* Currently drawn feature which should be represent as label or postit.
*/
const [digitizeTextFeature, setDigitizeTextFeature] = useState<OlFeature<OlGeometry>>(null);

const map = useMap();

useEffect(() => {
Expand Down Expand Up @@ -178,7 +169,6 @@ const DrawButton: React.FC<DrawButtonProps> = ({

if (drawType === 'Text') {
key = newInteraction.on('drawend', evt => {
setShowLabelPrompt(true);
evt.feature.set('isLabel', true);
setDigitizeTextFeature(evt.feature);
});
Expand Down Expand Up @@ -212,11 +202,6 @@ const DrawButton: React.FC<DrawButtonProps> = ({
};
}, [drawInteraction, onDrawStart, onDrawEnd]);

/**
* Currently drawn feature which should be represent as label or postit.
*/
const [digitizeTextFeature, setDigitizeTextFeature] = useState<OlFeature<OlGeometry>>(null);

/**
* Called when the draw button is toggled. If the button state is pressed,
* the appropriate draw interaction will be activated.
Expand All @@ -234,29 +219,19 @@ const DrawButton: React.FC<DrawButtonProps> = ({
* Turns visibility of modal off and call `setTextOnFeature` method.
*/
const onModalLabelOkInternal = () => {
setShowLabelPrompt(false);

let label = textLabel;
if (maxLabelLineLength) {
label = StringUtil.stringDivider(
textLabel, maxLabelLineLength, '\n'
);
}
digitizeTextFeature.set('label', label);
setTextLabel('');
onModalLabelOk?.(digitizeTextFeature);
setDigitizeTextFeature(null);
};

/**
* Callback function after `Cancel` button of label input modal was clicked.
* Turns visibility of modal off and removes last drawn feature from the
* digitize layer.
*/
const onModalLabelCancelInternal = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
setShowLabelPrompt(false);
setTextLabel('');
const onModalLabelCancelInternal = () => {
onModalLabelCancel?.();
layer.getSource().removeFeature(digitizeTextFeature);
onModalLabelCancel?.(event);
setDigitizeTextFeature(null);
};

const finalClassName = className
Expand All @@ -272,24 +247,15 @@ const DrawButton: React.FC<DrawButtonProps> = ({
className={finalClassName}
{...passThroughProps}
/>
{
showLabelPrompt &&
<Modal
title={modalPromptTitle}
okText={modalPromptOkButtonText}
cancelText={modalPromptCancelButtonText}
visible={showLabelPrompt}
closable={false}
onOk={onModalLabelOkInternal}
onCancel={onModalLabelCancelInternal}
>
<TextArea
value={textLabel}
onChange={e => setTextLabel(e.target.value)}
autoSize
/>
</Modal>
}
<FeatureLabelModal
feature={digitizeTextFeature}
onOk={onModalLabelOkInternal}
onCancel={onModalLabelCancelInternal}
title={modalPromptTitle}
okText={modalPromptOkButtonText}
cancelText={modalPromptCancelButtonText}
maxLabelLineLength={maxLabelLineLength}
/>
</span>);
};

Expand Down
65 changes: 65 additions & 0 deletions src/FeatureLabelModal/FeatureLabelModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as React from 'react';
import { useEffect, useState } from 'react';

import { Modal, ModalProps } from 'antd';
import TextArea from 'antd/lib/input/TextArea';

import Feature from 'ol/Feature';
import Geometry from 'ol/geom/Geometry';

import StringUtil from '@terrestris/base-util/dist/StringUtil/StringUtil';

type OwnProps = {
feature: Feature<Geometry>|null;
onOk: () => void;
onCancel: () => void;
/**
* Maximal length of feature label.
* If exceeded label will be divided into multiple lines. Optional.
*/
maxLabelLineLength?: number;
}

export type FeatureLabelModalProps = OwnProps & Omit<ModalProps, 'closable'|'visible'|'onOk'|'onCancel'>;

export const FeatureLabelModal: React.FC<FeatureLabelModalProps> = ({
feature,
onOk,
onCancel,
maxLabelLineLength,
...passThroughProps
}) => {
const [label, setLabel] = useState<string>(null);
const [showPrompt, setShowPrompt] = useState<boolean>(false);

useEffect(() => {
if (feature) {
setLabel(feature.get('label') ?? '');
setShowPrompt(true);
} else {
setShowPrompt(false);
}
}, [feature])

const onOkInternal = () => {
feature.set('label', maxLabelLineLength !== undefined ?
StringUtil.stringDivider(label, maxLabelLineLength, '\n') :
label
);
onOk();
};

return (showPrompt && <Modal
visible={showPrompt}
closable={false}
onOk={onOkInternal}
onCancel={onCancel}
{...passThroughProps}
>
<TextArea
value={label}
onChange={e => setLabel(e.target.value)}
autoSize
/>
</Modal>);
}

0 comments on commit 9ce529d

Please sign in to comment.