Skip to content

Commit

Permalink
Add rectangle mode
Browse files Browse the repository at this point in the history
New draw mode that extends polygon but behaves
like rectangle.

On First click, coordinate is set. On Second click the rectangle
is created as bounding box. This will be used for
drawing bounding box.

Signed-off-by: Vijayan Balasubramanian <balasvij@amazon.com>
  • Loading branch information
VijayanB committed Mar 8, 2023
1 parent d2cf87f commit 1583f81
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 0 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"@types/mapbox__mapbox-gl-draw": "^1.3.3",
"@types/wellknown": "^0.5.4",
"cypress-file-upload": "^5.0.8",
"geojson": "^0.5.0",
"install": "^0.13.0",
"maplibre-gl": "^2.4.0",
"prettier": "^2.1.1",
"uuid": "3.3.2",
Expand Down
149 changes: 149 additions & 0 deletions public/components/draw/modes/rectangle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { Feature, GeoJSON, Position } from 'geojson';
import { DrawCustomMode, DrawFeature, DrawPolygon, MapMouseEvent } from '@mapbox/mapbox-gl-draw';

// converted to typescript from
// https://github.com/mapbox/geojson.io/blob/main/src/ui/draw/rectangle.js
const doubleClickZoom = {
enable: (ctx: any) => {
setTimeout(() => {
// First check we've got a map and some context.
if (
!ctx.map ||
!ctx.map.doubleClickZoom ||
!ctx._ctx ||
!ctx._ctx.store ||
!ctx._ctx.store.getInitialConfigValue
)
return;
// Now check initial state wasn't false (we leave it disabled if so)
if (!ctx._ctx.store.getInitialConfigValue('doubleClickZoom')) return;
ctx.map.doubleClickZoom.enable();
}, 0);
},
disable(ctx: { map: { doubleClickZoom: { disable: () => void } } }) {
setTimeout(() => {
if (!ctx.map || !ctx.map.doubleClickZoom) return;
// Always disable here, as it's necessary in some cases.
ctx.map.doubleClickZoom.disable();
}, 0);
},
};

interface DrawRectangleState extends DrawPolygon {
startPoint: Position;
endPoint: Position;
}

// TODO Convert this to class
export const DrawRectangle: DrawCustomMode<DrawRectangleState, {}> = {
onSetup(): any {
const rectangleGeoJSON: GeoJSON = {
type: 'Feature',
properties: {},
geometry: {
type: 'Polygon',
coordinates: [[]],
},
};
const rectangle: DrawFeature = this.newFeature(rectangleGeoJSON);
// @ts-ignore
this.addFeature(rectangle);
// @ts-ignore
this.clearSelectedFeatures();
doubleClickZoom.disable(this);
// @ts-ignore
this.updateUIClasses({ mouse: 'add' });
// @ts-ignore
this.setActionableState({
trash: true,
});
return rectangle;
},
// Whenever a user clicks on the map, Draw will call `onClick`
onClick(state: DrawRectangleState, e: MapMouseEvent) {
// if state.startPoint exist, means its second click
// change to simple_select mode
if (
state.startPoint &&
state.startPoint[0] !== e.lngLat.lng &&
state.startPoint[1] !== e.lngLat.lat
) {
// @ts-ignore
this.updateUIClasses({ mouse: 'pointer' });
state.endPoint = [e.lngLat.lng, e.lngLat.lat];
// @ts-ignore
this.changeMode('simple_select', { featuresId: state.id });
}
// on first click, save clicked point coords as starting for rectangle
const startPoint = [e.lngLat.lng, e.lngLat.lat];
state.startPoint = startPoint;
},
onMouseMove(state: DrawRectangleState, e: MapMouseEvent) {
// if startPoint, update the feature coordinates, using the bounding box concept
// we are simply using the startingPoint coordinates and the current Mouse Position
// coordinates to calculate the bounding box on the fly, which will be our rectangle
if (state.startPoint) {
state.updateCoordinate('0.0', state.startPoint[0], state.startPoint[1]); // minX, minY - the starting point
state.updateCoordinate('0.1', e.lngLat.lng, state.startPoint[1]); // maxX, minY
state.updateCoordinate('0.2', e.lngLat.lng, e.lngLat.lat); // maxX, maxY
state.updateCoordinate('0.3', state.startPoint[0], e.lngLat.lat); // minX,maxY
state.updateCoordinate('0.4', state.startPoint[0], state.startPoint[1]); // minX,minY - ending point (equals to starting point)
}
},
onKeyUp(state: DrawRectangleState, e: KeyboardEvent) {
if (e.code === 'Escape') {
// change mode to simple select if escape is pressed
// @ts-ignore
this.changeMode('simple_select');
}
},
onStop(state: DrawRectangleState) {
doubleClickZoom.enable(this);
// @ts-ignore
this.updateUIClasses({ mouse: 'none' });
// @ts-ignore
this.activateUIButton();

// check to see if we've deleted this feature
// @ts-ignore
if (this.getFeature(state.id) === undefined) return;

// remove last added coordinate
state.removeCoordinate('0.4');
if (state.isValid()) {
// @ts-ignore
this.map.fire('draw.create', {
features: [state.toGeoJSON()],
});
} else {
// @ts-ignore
this.deleteFeature([state.id], { silent: true });
// @ts-ignore
this.changeMode('simple_select', {}, { silent: true });
}
},
toDisplayFeatures(
state: DrawRectangleState,
geojson: Feature,
display: (geojson: Feature) => void
) {
const isActivePolygon = geojson?.properties?.id === state.id;
geojson.properties!.active = isActivePolygon ? 'true' : 'false';
if (!isActivePolygon) return display(geojson);

// Only render the rectangular polygon if it has the starting point
if (!state.startPoint) return;
return display(geojson);
},
onTrash(state: DrawRectangleState) {
// @ts-ignore
this.deleteFeature([state.id], { silent: true });
// @ts-ignore
this.changeMode('simple_select');
},
};
108 changes: 108 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,41 @@
debug "^3.1.0"
lodash.once "^4.1.1"

"@mapbox/extent@0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@mapbox/extent/-/extent-0.4.0.tgz#3e591f32e1f0c3981c864239f7b0ac06e610f8a9"
integrity sha512-MSoKw3qPceGuupn04sdaJrFeLKvcSETVLZCGS8JA9x6zXQL3FWiKaIXYIZEDXd5jpXpWlRxinCZIN49yRy0C9A==

"@mapbox/geojson-area@^0.2.2":
version "0.2.2"
resolved "https://registry.yarnpkg.com/@mapbox/geojson-area/-/geojson-area-0.2.2.tgz#18d7814aa36bf23fbbcc379f8e26a22927debf10"
integrity sha512-bBqqFn1kIbLBfn7Yq1PzzwVkPYQr9lVUeT8Dhd0NL5n76PBuXzOcuLV7GOSbEB1ia8qWxH4COCvFpziEu/yReA==
dependencies:
wgs84 "0.0.0"

"@mapbox/geojson-coords@0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@mapbox/geojson-coords/-/geojson-coords-0.0.2.tgz#f73d5744c832de0f05c48899f16a4288cefb2606"
integrity sha512-YuVzpseee/P1T5BWyeVVPppyfmuXYHFwZHmybkqaMfu4BWlOf2cmMGKj2Rr92MwfSTOCSUA0PAsVGRG8akY0rg==
dependencies:
"@mapbox/geojson-normalize" "0.0.1"
geojson-flatten "^1.0.4"

"@mapbox/geojson-extent@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@mapbox/geojson-extent/-/geojson-extent-1.0.1.tgz#bd99a6b66ba98e63a29511c9cd1bbd1df4c1e203"
integrity sha512-hh8LEO3djT4fqfr8sSC6wKt+p0TMiu+KOLMBUiFOyj+zGq7+IXwQGl0ppCVDkyzCewyd9LoGe9zAvDxXrLfhLw==
dependencies:
"@mapbox/extent" "0.4.0"
"@mapbox/geojson-coords" "0.0.2"
rw "~0.1.4"
traverse "~0.6.6"

"@mapbox/geojson-normalize@0.0.1", "@mapbox/geojson-normalize@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@mapbox/geojson-normalize/-/geojson-normalize-0.0.1.tgz#1da1e6b3a7add3ad29909b30f438f60581b7cd80"
integrity sha512-82V7YHcle8lhgIGqEWwtXYN5cy0QM/OHq3ypGhQTbvHR57DF0vMHMjjVSQKFfVXBe/yWCBZTyOuzvK7DFFnx5Q==

"@mapbox/geojson-rewind@^0.5.2":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz#591a5d71a9cd1da1a0bf3420b3bea31b0fc7946a"
Expand All @@ -57,6 +92,19 @@
resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234"
integrity sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==

"@mapbox/mapbox-gl-draw@^1.4.0":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-draw/-/mapbox-gl-draw-1.4.1.tgz#96dcec4d3957150de854423ac15856fde43d1452"
integrity sha512-g6F49KZagF9269/IoF6vZJeail6qtoc5mVF3eVRikNT7UFnY0QASfe2y53mgE99s6GrHdpV+PZuFxaL71hkMhg==
dependencies:
"@mapbox/geojson-area" "^0.2.2"
"@mapbox/geojson-extent" "^1.0.1"
"@mapbox/geojson-normalize" "^0.0.1"
"@mapbox/point-geometry" "^0.1.0"
hat "0.0.3"
lodash.isequal "^4.5.0"
xtend "^4.0.2"

"@mapbox/mapbox-gl-supported@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz#c15367178d8bfe4765e6b47b542fe821ce259c7b"
Expand Down Expand Up @@ -98,6 +146,21 @@
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249"
integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==

"@types/mapbox-gl@*":
version "2.7.10"
resolved "https://registry.yarnpkg.com/@types/mapbox-gl/-/mapbox-gl-2.7.10.tgz#a3a32a366bad8966c0a40b78209ed430ba018ce1"
integrity sha512-nMVEcu9bAcenvx6oPWubQSPevsekByjOfKjlkr+8P91vawtkxTnopDoXXq1Qn/f4cg3zt0Z2W9DVsVsKRNXJTw==
dependencies:
"@types/geojson" "*"

"@types/mapbox__mapbox-gl-draw@^1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@types/mapbox__mapbox-gl-draw/-/mapbox__mapbox-gl-draw-1.3.3.tgz#b96cce3e3bcd3ed2c4243a848725c66328737797"
integrity sha512-VJYdbxPxLNd0rUmgD3h7lm743A5J0uVj03Wd7P3Z+plLhUmPYIipAS8F3DhiP1x5dhIo9r27spFp3oASovd1sg==
dependencies:
"@types/geojson" "*"
"@types/mapbox-gl" "*"

"@types/mapbox__point-geometry@*", "@types/mapbox__point-geometry@^0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.2.tgz#488a9b76e8457d6792ea2504cdd4ecdd9860a27e"
Expand Down Expand Up @@ -674,11 +737,21 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==

geojson-flatten@^1.0.4:
version "1.1.1"
resolved "https://registry.yarnpkg.com/geojson-flatten/-/geojson-flatten-1.1.1.tgz#601aae07ba6406281ebca683573dcda69eba04c7"
integrity sha512-k/6BCd0qAt7vdqdM1LkLfAy72EsLDy0laNwX0x2h49vfYCiQkRc4PSra8DNEdJ10EKRpwEvDXMb0dBknTJuWpQ==

geojson-vt@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/geojson-vt/-/geojson-vt-3.2.1.tgz#f8adb614d2c1d3f6ee7c4265cad4bbf3ad60c8b7"
integrity sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==

geojson@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0"
integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==

get-intrinsic@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
Expand Down Expand Up @@ -769,6 +842,11 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"

hat@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/hat/-/hat-0.0.3.tgz#bb014a9e64b3788aed8005917413d4ff3d502d8a"
integrity sha512-zpImx2GoKXy42fVDSEad2BPKuSQdLcqsCYa48K3zHSzM/ugWuYjLDr8IXxpVuL7uCLHw56eaiLxCRthhOzf5ug==

http-signature@~1.3.6:
version "1.3.6"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9"
Expand Down Expand Up @@ -816,6 +894,11 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==

install@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/install/-/install-0.13.0.tgz#6af6e9da9dd0987de2ab420f78e60d9c17260776"
integrity sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==

is-ci@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867"
Expand Down Expand Up @@ -934,6 +1017,11 @@ listr2@^3.8.3:
through "^2.3.8"
wrap-ansi "^7.0.0"

lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==

lodash.once@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
Expand Down Expand Up @@ -1225,6 +1313,11 @@ rimraf@^3.0.0:
dependencies:
glob "^7.1.3"

rw@~0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/rw/-/rw-0.1.4.tgz#4903cbd80248ae0ede685bf58fd236a7a9b29a3e"
integrity sha512-vSj3D96kMcjNyqPcp65wBRIDImGSrUuMxngNNxvw8MQaO+aQ6llzRPH7XcJy5zrpb3wU++045+Uz/IDIM684iw==

rxjs@^7.5.1:
version "7.8.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4"
Expand Down Expand Up @@ -1385,6 +1478,11 @@ tough-cookie@~2.5.0:
psl "^1.1.28"
punycode "^2.1.1"

traverse@~0.6.6:
version "0.6.7"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe"
integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==

tslib@^2.1.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
Expand Down Expand Up @@ -1463,6 +1561,11 @@ wellknown@^0.5.0:
concat-stream "~1.5.0"
minimist "~1.2.0"

wgs84@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/wgs84/-/wgs84-0.0.0.tgz#34fdc555917b6e57cf2a282ed043710c049cdc76"
integrity sha512-ANHlY4Rb5kHw40D0NJ6moaVfOCMrp9Gpd1R/AIQYg2ko4/jzcJ+TVXYYF6kXJqQwITvEZP4yEthjM7U6rYlljQ==

which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
Expand Down Expand Up @@ -1500,6 +1603,11 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==

xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==

yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
Expand Down

0 comments on commit 1583f81

Please sign in to comment.