diff --git a/docs/api-reference/modes/overview.md b/docs/api-reference/modes/overview.md index ee9d2f1fd..79b5236a9 100644 --- a/docs/api-reference/modes/overview.md +++ b/docs/api-reference/modes/overview.md @@ -84,7 +84,14 @@ The following options can be provided in the `modeConfig` object: ## [ResizeCircleMode](https://github.com/uber/nebula.gl/blob/master/modules/edit-modes/src/lib/resize-circle-mode.js) -User can resize an existing circular Polygon feature by clicking and dragging along the ring. +User can resize an existing circular Polygon feature by clicking along the ring. + +### ModeConfig + +The following options can be provided in the `modeConfig` object: + +- `dragToDraw` (optional): `boolean` + - If `true`, user can click and drag instead of clicking twice. Note however, that the user will not be able to pan the map while drawing. ## [DrawPolygonMode](https://github.com/uber/nebula.gl/blob/master/modules/edit-modes/src/lib/draw-polygon-mode.js) diff --git a/examples/advanced/src/example.tsx b/examples/advanced/src/example.tsx index 4de377d7a..3f53b1c66 100644 --- a/examples/advanced/src/example.tsx +++ b/examples/advanced/src/example.tsx @@ -671,6 +671,9 @@ export default class Example extends React.Component< if (this.state.mode === MeasureDistanceMode) { controls.push(this._renderMeasureDistanceControls()); } + if (this.state.mode === ResizeCircleMode) { + controls.push(this._renderTwoClickPolygonControls()); + } if (this.state.mode === DrawPolygonMode) { controls.push(this._renderDrawPolygonModeControls()); } diff --git a/modules/edit-modes/src/lib/resize-circle-mode.ts b/modules/edit-modes/src/lib/resize-circle-mode.ts index 60a918f9c..07bb4e5b8 100644 --- a/modules/edit-modes/src/lib/resize-circle-mode.ts +++ b/modules/edit-modes/src/lib/resize-circle-mode.ts @@ -10,8 +10,9 @@ import { getPickedEditHandle, NearestPointType, } from '../utils'; -import { LineString, Point, FeatureCollection, FeatureOf } from '../geojson-types'; +import { LineString, Point, Position, FeatureCollection, FeatureOf } from '../geojson-types'; import { + ClickEvent, ModeProps, PointerMoveEvent, StartDraggingEvent, @@ -128,6 +129,10 @@ export class ResizeCircleMode extends GeoJsonEditMode { } handleDragging(event: DraggingEvent, props: ModeProps): void { + if (props.modeConfig && !props.modeConfig.dragToDraw) { + return; + } + const editHandle = getPickedEditHandle(event.pointerDownPicks); if (editHandle) { @@ -135,32 +140,35 @@ export class ResizeCircleMode extends GeoJsonEditMode { event.cancelPan(); const editHandleProperties = editHandle.properties; + const featureIndex = editHandleProperties.featureIndex; + const pointerPosition = event.mapCoords; + this.drawCircle(featureIndex, pointerPosition, props); + } + } + + handleClick(event: ClickEvent, props: ModeProps) { + if (props.modeConfig && props.modeConfig.dragToDraw) { + // handled in drag handlers + return; + } - const feature = this.getSelectedFeature(props); - const center = turfCenter(feature).geometry.coordinates; - const numberOfSteps = Object.entries(feature.geometry.coordinates[0]).length - 1; - const radius = Math.max(distance(center, event.mapCoords), 0.001); - - const { steps = numberOfSteps } = {}; - const options = { steps }; - const updatedFeature = circle(center, radius, options); - const geometry = updatedFeature.geometry; - - const updatedData = new ImmutableFeatureCollection(props.data) - .replaceGeometry(editHandleProperties.featureIndex, geometry) - .getObject(); - - props.onEdit({ - updatedData, - editType: 'unionGeometry', - editContext: { - featureIndexes: [editHandleProperties.featureIndex], - }, - }); + this.addClickSequence(event); + const clickSequence = this.getClickSequence(); + if (clickSequence.length > 1) { + this._isResizing = false; + this.resetClickSequence(); + } else { + this._isResizing = true; } } handlePointerMove(event: PointerMoveEvent, props: ModeProps): void { + if (props.modeConfig && !props.modeConfig.dragToDraw && this._isResizing) { + const featureIndex = props.selectedIndexes[0]; + const pointerPosition = event.mapCoords; + this.drawCircle(featureIndex, pointerPosition, props); + } + if (!this._isResizing) { const selectedEditHandle = getPickedEditHandle(event.picks); this._selectedEditHandle = @@ -169,30 +177,59 @@ export class ResizeCircleMode extends GeoJsonEditMode { : null; } - const cursor = this.getCursor(event); + const cursor = this.getCursor(event, props); props.onUpdateCursor(cursor); } handleStartDragging(event: StartDraggingEvent, props: ModeProps) { - if (this._selectedEditHandle) { + if (props.modeConfig && props.modeConfig.dragToDraw && this._selectedEditHandle) { this._isResizing = true; } } handleStopDragging(event: StopDraggingEvent, props: ModeProps) { - if (this._isResizing) { + if (props.modeConfig && props.modeConfig.dragToDraw && this._isResizing) { this._selectedEditHandle = null; this._isResizing = false; } } - getCursor(event: PointerMoveEvent): string | null | undefined { + getCursor( + event: PointerMoveEvent, + props: ModeProps + ): string | null | undefined { const picks = (event && event.picks) || []; const handlesPicked = getPickedEditHandles(picks); - if (handlesPicked.length) { + const isResizingByClickingTwice = + props.modeConfig && !props.modeConfig.dragToDraw && this._isResizing; + if (handlesPicked.length || isResizingByClickingTwice) { return 'cell'; } return null; } + + drawCircle(featureIndex: number, pointerPosition: Position, props: ModeProps) { + const feature = this.getSelectedFeature(props); + const center = turfCenter(feature).geometry.coordinates; + const numberOfSteps = Object.entries(feature.geometry.coordinates[0]).length - 1; + const radius = Math.max(distance(center, pointerPosition), 0.001); + + const { steps = numberOfSteps } = {}; + const options = { steps }; + const updatedFeature = circle(center, radius, options); + const geometry = updatedFeature.geometry; + + const updatedData = new ImmutableFeatureCollection(props.data) + .replaceGeometry(featureIndex, geometry) + .getObject(); + + props.onEdit({ + updatedData, + editType: 'unionGeometry', + editContext: { + featureIndexes: [featureIndex], + }, + }); + } }