Skip to content

Commit

Permalink
Add option to prevent overlapping lines when drawing a polygon (uber#549
Browse files Browse the repository at this point in the history
)
  • Loading branch information
StijnAmeloot authored Feb 11, 2022
1 parent 0f2682a commit 1ba44f2
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 10 deletions.
7 changes: 7 additions & 0 deletions docs/api-reference/modes/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ User can resize an existing circular Polygon feature by clicking and dragging al

User can draw a new `Polygon` feature by clicking positions to add then closing the polygon (or double-clicking).

### ModeConfig

The following options can be provided in the `modeConfig` object:

- `preventOverlappingLines` (optional): `boolean`
- If `true`, it will not be possible to add a polygon point if the current line overlaps any other lines on the same polygon.

### Edit Context

`editContext` argument to the `onEdit` callback contains the following properties:
Expand Down
64 changes: 56 additions & 8 deletions examples/advanced/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,9 @@ export default class Example extends React.Component<
};

_download = () => {
const blob = new Blob([JSON.stringify(this.state.testFeatures)], { type: 'octet/stream' });
const blob = new Blob([JSON.stringify(this.state.testFeatures)], {
type: 'octet/stream',
});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'nebula.geojson';
Expand Down Expand Up @@ -469,11 +471,17 @@ export default class Example extends React.Component<
onClick={() => {
if (this.state.modeConfig && this.state.modeConfig.booleanOperation === operation) {
this.setState({
modeConfig: { ...(this.state.modeConfig || {}), booleanOperation: null },
modeConfig: {
...(this.state.modeConfig || {}),
booleanOperation: null,
},
});
} else {
this.setState({
modeConfig: { ...(this.state.modeConfig || {}), booleanOperation: operation },
modeConfig: {
...(this.state.modeConfig || {}),
booleanOperation: operation,
},
});
}
}}
Expand Down Expand Up @@ -532,7 +540,9 @@ export default class Example extends React.Component<
type="checkbox"
checked={Boolean(this.state.modeConfig && this.state.modeConfig.lock90Degree)}
onChange={(event) =>
this.setState({ modeConfig: { lock90Degree: Boolean(event.target.checked) } })
this.setState({
modeConfig: { lock90Degree: Boolean(event.target.checked) },
})
}
/>
</ToolboxControl>
Expand Down Expand Up @@ -593,6 +603,30 @@ export default class Example extends React.Component<
);
}

_renderDrawPolygonModeControls() {
return (
<ToolboxRow key="draw-polygon">
<ToolboxTitle>Prevent overlapping lines</ToolboxTitle>
<ToolboxControl>
<input
type="checkbox"
checked={Boolean(
this.state.modeConfig && this.state.modeConfig.preventOverlappingLines
)}
onChange={(event) =>
this.setState({
modeConfig: {
...(this.state.modeConfig || {}),
preventOverlappingLines: Boolean(event.target.checked),
},
})
}
/>
</ToolboxControl>
</ToolboxRow>
);
}

_renderModeConfigControls() {
const controls = [];

Expand All @@ -615,6 +649,9 @@ export default class Example extends React.Component<
if (this.state.mode === MeasureDistanceMode) {
controls.push(this._renderMeasureDistanceControls());
}
if (this.state.mode === DrawPolygonMode) {
controls.push(this._renderDrawPolygonModeControls());
}

return controls;
}
Expand Down Expand Up @@ -731,21 +768,30 @@ export default class Example extends React.Component<
<ToolboxControl>
<ToolboxButton
onClick={() =>
this.setState({ selectedFeatureIndexes: [], selectionTool: SELECTION_TYPE.NONE })
this.setState({
selectedFeatureIndexes: [],
selectionTool: SELECTION_TYPE.NONE,
})
}
>
Clear Selection
</ToolboxButton>
<ToolboxButton
onClick={() =>
this.setState({ mode: ViewMode, selectionTool: SELECTION_TYPE.RECTANGLE })
this.setState({
mode: ViewMode,
selectionTool: SELECTION_TYPE.RECTANGLE,
})
}
>
Rect Select
</ToolboxButton>
<ToolboxButton
onClick={() =>
this.setState({ mode: ViewMode, selectionTool: SELECTION_TYPE.POLYGON })
this.setState({
mode: ViewMode,
selectionTool: SELECTION_TYPE.POLYGON,
})
}
>
Lasso Select
Expand Down Expand Up @@ -1026,7 +1072,9 @@ export default class Example extends React.Component<
// @ts-ignore
selectionType: this.state.selectionTool,
onSelect: ({ pickingInfos }) => {
this.setState({ selectedFeatureIndexes: pickingInfos.map((pi) => pi.index) });
this.setState({
selectedFeatureIndexes: pickingInfos.map((pi) => pi.index),
});
},
layerIds: ['geojson'],

Expand Down
21 changes: 19 additions & 2 deletions modules/edit-modes/src/lib/draw-polygon-mode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import lineIntersect from '@turf/line-intersect';
import { lineString as turfLineString } from '@turf/helpers';
import {
ClickEvent,
PointerMoveEvent,
Expand Down Expand Up @@ -79,14 +81,27 @@ export class DrawPolygonMode extends GeoJsonEditMode {
handleClick(event: ClickEvent, props: ModeProps<FeatureCollection>) {
const { picks } = event;
const clickedEditHandle = getPickedEditHandle(picks);
const clickSequence = this.getClickSequence();

let overlappingLines = false;
if (clickSequence.length > 2 && props.modeConfig && props.modeConfig.preventOverlappingLines) {
const currentLine = turfLineString([
clickSequence[clickSequence.length - 1],
event.mapCoords,
]);
const otherLines = turfLineString([...clickSequence.slice(0, clickSequence.length - 1)]);
const intersectingPoints = lineIntersect(currentLine, otherLines);
if (intersectingPoints.features.length > 0) {
overlappingLines = true;
}
}

let positionAdded = false;
if (!clickedEditHandle) {
if (!clickedEditHandle && !overlappingLines) {
// Don't add another point right next to an existing one
this.addClickSequence(event);
positionAdded = true;
}
const clickSequence = this.getClickSequence();

if (
clickSequence.length > 2 &&
Expand Down Expand Up @@ -121,6 +136,7 @@ export class DrawPolygonMode extends GeoJsonEditMode {
});
}
}

handleKeyUp(event: KeyboardEvent, props: ModeProps<FeatureCollection>) {
if (event.key === 'Enter') {
const clickSequence = this.getClickSequence();
Expand All @@ -138,6 +154,7 @@ export class DrawPolygonMode extends GeoJsonEditMode {
}
}
}

handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>) {
props.onUpdateCursor('cell');
super.handlePointerMove(event, props);
Expand Down

0 comments on commit 1ba44f2

Please sign in to comment.