@deck.gl-community/editable-layers 9.2.0-beta.4 → 9.2.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/edit-modes/draw-polygon-mode.d.ts +7 -3
- package/dist/edit-modes/draw-polygon-mode.d.ts.map +1 -1
- package/dist/edit-modes/draw-polygon-mode.js +226 -81
- package/dist/edit-modes/draw-polygon-mode.js.map +1 -1
- package/dist/index.cjs +184 -60
- package/dist/index.cjs.map +3 -3
- package/package.json +6 -2
- package/src/edit-modes/draw-polygon-mode.ts +303 -99
package/dist/index.cjs
CHANGED
|
@@ -2938,48 +2938,53 @@ var DrawLineStringMode = class extends GeoJsonEditMode {
|
|
|
2938
2938
|
// dist/edit-modes/draw-polygon-mode.js
|
|
2939
2939
|
var import_line_intersect2 = __toESM(require("@turf/line-intersect"), 1);
|
|
2940
2940
|
var import_helpers9 = require("@turf/helpers");
|
|
2941
|
+
var import_boolean_within = __toESM(require("@turf/boolean-within"), 1);
|
|
2941
2942
|
var DrawPolygonMode = class extends GeoJsonEditMode {
|
|
2943
|
+
holeSequence = [];
|
|
2944
|
+
isDrawingHole = false;
|
|
2942
2945
|
createTentativeFeature(props) {
|
|
2943
2946
|
const { lastPointerMoveEvent } = props;
|
|
2944
2947
|
const clickSequence = this.getClickSequence();
|
|
2948
|
+
const holeSequence = this.holeSequence;
|
|
2945
2949
|
const lastCoords = lastPointerMoveEvent ? [lastPointerMoveEvent.mapCoords] : [];
|
|
2946
|
-
let
|
|
2947
|
-
if (
|
|
2948
|
-
|
|
2949
|
-
type: "
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
type: "LineString",
|
|
2955
|
-
coordinates: [...clickSequence, ...lastCoords]
|
|
2956
|
-
}
|
|
2950
|
+
let geometry;
|
|
2951
|
+
if (this.isDrawingHole && holeSequence.length > 1) {
|
|
2952
|
+
geometry = {
|
|
2953
|
+
type: "Polygon",
|
|
2954
|
+
coordinates: [
|
|
2955
|
+
[...clickSequence, clickSequence[0]],
|
|
2956
|
+
[...holeSequence, ...lastCoords, holeSequence[0]]
|
|
2957
|
+
]
|
|
2957
2958
|
};
|
|
2958
2959
|
} else if (clickSequence.length > 2) {
|
|
2959
|
-
|
|
2960
|
-
type: "
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
}
|
|
2960
|
+
geometry = {
|
|
2961
|
+
type: "Polygon",
|
|
2962
|
+
coordinates: [[...clickSequence, ...lastCoords, clickSequence[0]]]
|
|
2963
|
+
};
|
|
2964
|
+
} else {
|
|
2965
|
+
geometry = {
|
|
2966
|
+
type: "LineString",
|
|
2967
|
+
coordinates: [...clickSequence, ...lastCoords]
|
|
2968
2968
|
};
|
|
2969
2969
|
}
|
|
2970
|
-
return
|
|
2970
|
+
return {
|
|
2971
|
+
type: "Feature",
|
|
2972
|
+
properties: {
|
|
2973
|
+
guideType: "tentative"
|
|
2974
|
+
},
|
|
2975
|
+
geometry
|
|
2976
|
+
};
|
|
2971
2977
|
}
|
|
2972
2978
|
getGuides(props) {
|
|
2973
|
-
const clickSequence = this.getClickSequence();
|
|
2974
2979
|
const guides = {
|
|
2975
2980
|
type: "FeatureCollection",
|
|
2976
2981
|
features: []
|
|
2977
2982
|
};
|
|
2978
|
-
const
|
|
2979
|
-
if (
|
|
2980
|
-
guides.features.push(
|
|
2981
|
-
|
|
2982
|
-
const
|
|
2983
|
+
const tentative = this.createTentativeFeature(props);
|
|
2984
|
+
if (tentative)
|
|
2985
|
+
guides.features.push(tentative);
|
|
2986
|
+
const sequence = this.isDrawingHole ? this.holeSequence : this.getClickSequence();
|
|
2987
|
+
const handles = sequence.map((coord, index) => ({
|
|
2983
2988
|
type: "Feature",
|
|
2984
2989
|
properties: {
|
|
2985
2990
|
guideType: "editHandle",
|
|
@@ -2989,51 +2994,55 @@ var DrawPolygonMode = class extends GeoJsonEditMode {
|
|
|
2989
2994
|
},
|
|
2990
2995
|
geometry: {
|
|
2991
2996
|
type: "Point",
|
|
2992
|
-
coordinates:
|
|
2997
|
+
coordinates: coord
|
|
2993
2998
|
}
|
|
2994
2999
|
}));
|
|
2995
|
-
guides.features.push(...
|
|
3000
|
+
guides.features.push(...handles);
|
|
2996
3001
|
return guides;
|
|
2997
3002
|
}
|
|
2998
|
-
|
|
2999
|
-
const clickSequence = this.getClickSequence();
|
|
3000
|
-
if (clickSequence.length > 2) {
|
|
3001
|
-
const polygonToAdd = {
|
|
3002
|
-
type: "Polygon",
|
|
3003
|
-
coordinates: [[...clickSequence, clickSequence[0]]]
|
|
3004
|
-
};
|
|
3005
|
-
this.resetClickSequence();
|
|
3006
|
-
const editAction = this.getAddFeatureOrBooleanPolygonAction(polygonToAdd, props);
|
|
3007
|
-
if (editAction) {
|
|
3008
|
-
props.onEdit(editAction);
|
|
3009
|
-
}
|
|
3010
|
-
}
|
|
3011
|
-
}
|
|
3012
|
-
// eslint-disable-next-line complexity
|
|
3003
|
+
// eslint-disable-next-line complexity, max-statements
|
|
3013
3004
|
handleClick(event, props) {
|
|
3014
3005
|
const { picks } = event;
|
|
3015
3006
|
const clickedEditHandle = getPickedEditHandle(picks);
|
|
3016
3007
|
const clickSequence = this.getClickSequence();
|
|
3017
|
-
|
|
3018
|
-
if (clickSequence.length > 2 &&
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3008
|
+
const coords = event.mapCoords;
|
|
3009
|
+
if (!this.isDrawingHole && clickSequence.length > 2 && clickedEditHandle && Array.isArray(clickedEditHandle.properties.positionIndexes) && (clickedEditHandle.properties.positionIndexes[0] === 0 || clickedEditHandle.properties.positionIndexes[0] === clickSequence.length - 1)) {
|
|
3010
|
+
this.finishDrawing(props);
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
if (!this.isDrawingHole && clickSequence.length > 2) {
|
|
3014
|
+
if (isNearFirstPoint(coords, clickSequence[0])) {
|
|
3015
|
+
this.finishDrawing(props);
|
|
3016
|
+
this.resetClickSequence();
|
|
3017
|
+
return;
|
|
3027
3018
|
}
|
|
3028
3019
|
}
|
|
3020
|
+
if (this.isDrawingHole) {
|
|
3021
|
+
const current = this.holeSequence;
|
|
3022
|
+
current.push(coords);
|
|
3023
|
+
if (current.length > 2) {
|
|
3024
|
+
const poly = {
|
|
3025
|
+
type: "Polygon",
|
|
3026
|
+
coordinates: [
|
|
3027
|
+
[...clickSequence, clickSequence[0]],
|
|
3028
|
+
[...current, current[0]]
|
|
3029
|
+
]
|
|
3030
|
+
};
|
|
3031
|
+
this.resetClickSequence();
|
|
3032
|
+
this.holeSequence = [];
|
|
3033
|
+
this.isDrawingHole = false;
|
|
3034
|
+
const editAction = this.getAddFeatureOrBooleanPolygonAction(poly, props);
|
|
3035
|
+
if (editAction)
|
|
3036
|
+
props.onEdit(editAction);
|
|
3037
|
+
}
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3029
3040
|
let positionAdded = false;
|
|
3030
|
-
if (!clickedEditHandle
|
|
3041
|
+
if (!clickedEditHandle) {
|
|
3031
3042
|
this.addClickSequence(event);
|
|
3032
3043
|
positionAdded = true;
|
|
3033
3044
|
}
|
|
3034
|
-
if (
|
|
3035
|
-
this.finishDrawing(props);
|
|
3036
|
-
} else if (positionAdded) {
|
|
3045
|
+
if (positionAdded) {
|
|
3037
3046
|
props.onEdit({
|
|
3038
3047
|
// data is the same
|
|
3039
3048
|
updatedData: props.data,
|
|
@@ -3044,16 +3053,19 @@ var DrawPolygonMode = class extends GeoJsonEditMode {
|
|
|
3044
3053
|
});
|
|
3045
3054
|
}
|
|
3046
3055
|
}
|
|
3047
|
-
handleDoubleClick(
|
|
3056
|
+
handleDoubleClick(_event, props) {
|
|
3048
3057
|
this.finishDrawing(props);
|
|
3058
|
+
this.resetClickSequence();
|
|
3049
3059
|
}
|
|
3050
3060
|
handleKeyUp(event, props) {
|
|
3051
3061
|
if (event.key === "Enter") {
|
|
3052
3062
|
this.finishDrawing(props);
|
|
3063
|
+
this.resetClickSequence();
|
|
3053
3064
|
} else if (event.key === "Escape") {
|
|
3054
3065
|
this.resetClickSequence();
|
|
3066
|
+
this.holeSequence = [];
|
|
3067
|
+
this.isDrawingHole = false;
|
|
3055
3068
|
props.onEdit({
|
|
3056
|
-
// Because the new drawing feature is dropped, so the data will keep as the same.
|
|
3057
3069
|
updatedData: props.data,
|
|
3058
3070
|
editType: "cancelFeature",
|
|
3059
3071
|
editContext: {}
|
|
@@ -3064,7 +3076,119 @@ var DrawPolygonMode = class extends GeoJsonEditMode {
|
|
|
3064
3076
|
props.onUpdateCursor("cell");
|
|
3065
3077
|
super.handlePointerMove(event, props);
|
|
3066
3078
|
}
|
|
3079
|
+
// eslint-disable-next-line max-statements, complexity
|
|
3080
|
+
finishDrawing(props) {
|
|
3081
|
+
const clickSequence = this.getClickSequence();
|
|
3082
|
+
const polygon3 = [...clickSequence, clickSequence[0]];
|
|
3083
|
+
const newPolygon = (0, import_helpers9.polygon)([polygon3]);
|
|
3084
|
+
const canAddHole = canAddHoleToPolygon(props);
|
|
3085
|
+
const canOverlap = canPolygonOverlap(props);
|
|
3086
|
+
if (!canOverlap) {
|
|
3087
|
+
const overlapping = (0, import_line_intersect2.default)(newPolygon, newPolygon).features.filter((intersection) => !newPolygon.geometry.coordinates[0].some((coord) => coord[0] === intersection.geometry.coordinates[0] && coord[1] === intersection.geometry.coordinates[1]));
|
|
3088
|
+
if (overlapping.length > 0) {
|
|
3089
|
+
props.onEdit({
|
|
3090
|
+
updatedData: props.data,
|
|
3091
|
+
editType: "invalidPolygon",
|
|
3092
|
+
editContext: { reason: "overlaps" }
|
|
3093
|
+
});
|
|
3094
|
+
this.resetClickSequence();
|
|
3095
|
+
return;
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
if (canAddHole) {
|
|
3099
|
+
const holeResult = this.tryAddHoleToExistingPolygon(newPolygon, polygon3, props);
|
|
3100
|
+
if (holeResult.handled) {
|
|
3101
|
+
this.resetClickSequence();
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
const editAction = this.getAddFeatureOrBooleanPolygonAction({
|
|
3106
|
+
type: "Polygon",
|
|
3107
|
+
coordinates: [[...this.getClickSequence(), this.getClickSequence()[0]]]
|
|
3108
|
+
}, props);
|
|
3109
|
+
if (editAction)
|
|
3110
|
+
props.onEdit(editAction);
|
|
3111
|
+
this.resetClickSequence();
|
|
3112
|
+
return;
|
|
3113
|
+
}
|
|
3114
|
+
tryAddHoleToExistingPolygon(newPolygon, polygon3, props) {
|
|
3115
|
+
for (const [featureIndex, feature] of props.data.features.entries()) {
|
|
3116
|
+
if (feature.geometry.type === "Polygon") {
|
|
3117
|
+
const result = this.validateAndCreateHole(feature, featureIndex, newPolygon, polygon3, props);
|
|
3118
|
+
if (result.handled) {
|
|
3119
|
+
return result;
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
return { handled: false };
|
|
3124
|
+
}
|
|
3125
|
+
validateAndCreateHole(feature, featureIndex, newPolygon, polygon3, props) {
|
|
3126
|
+
const outer = (0, import_helpers9.polygon)(feature.geometry.coordinates);
|
|
3127
|
+
for (let i = 1; i < feature.geometry.coordinates.length; i++) {
|
|
3128
|
+
const hole = (0, import_helpers9.polygon)([feature.geometry.coordinates[i]]);
|
|
3129
|
+
const intersection = (0, import_line_intersect2.default)(hole, newPolygon);
|
|
3130
|
+
if (intersection.features.length > 0) {
|
|
3131
|
+
props.onEdit({
|
|
3132
|
+
updatedData: props.data,
|
|
3133
|
+
editType: "invalidHole",
|
|
3134
|
+
editContext: { reason: "intersects-existing-hole" }
|
|
3135
|
+
});
|
|
3136
|
+
return { handled: true };
|
|
3137
|
+
}
|
|
3138
|
+
if ((0, import_boolean_within.default)(hole, newPolygon) || (0, import_boolean_within.default)(newPolygon, hole)) {
|
|
3139
|
+
props.onEdit({
|
|
3140
|
+
updatedData: props.data,
|
|
3141
|
+
editType: "invalidHole",
|
|
3142
|
+
editContext: { reason: "contains-or-contained-by-existing-hole" }
|
|
3143
|
+
});
|
|
3144
|
+
return { handled: true };
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
const intersectionWithOuter = (0, import_line_intersect2.default)(outer, newPolygon);
|
|
3148
|
+
if (intersectionWithOuter.features.length > 0) {
|
|
3149
|
+
props.onEdit({
|
|
3150
|
+
updatedData: props.data,
|
|
3151
|
+
editType: "invalidPolygon",
|
|
3152
|
+
editContext: { reason: "intersects-existing-polygon" }
|
|
3153
|
+
});
|
|
3154
|
+
return { handled: true };
|
|
3155
|
+
}
|
|
3156
|
+
if ((0, import_boolean_within.default)(outer, newPolygon)) {
|
|
3157
|
+
props.onEdit({
|
|
3158
|
+
updatedData: props.data,
|
|
3159
|
+
editType: "invalidPolygon",
|
|
3160
|
+
editContext: { reason: "contains-existing-polygon" }
|
|
3161
|
+
});
|
|
3162
|
+
return { handled: true };
|
|
3163
|
+
}
|
|
3164
|
+
if ((0, import_boolean_within.default)(newPolygon, outer)) {
|
|
3165
|
+
const updatedData = new ImmutableFeatureCollection(props.data).replaceGeometry(featureIndex, {
|
|
3166
|
+
...feature.geometry,
|
|
3167
|
+
coordinates: [...feature.geometry.coordinates, polygon3]
|
|
3168
|
+
}).getObject();
|
|
3169
|
+
props.onEdit({
|
|
3170
|
+
updatedData,
|
|
3171
|
+
editType: "addHole",
|
|
3172
|
+
editContext: { hole: newPolygon.geometry }
|
|
3173
|
+
});
|
|
3174
|
+
return { handled: true };
|
|
3175
|
+
}
|
|
3176
|
+
return { handled: false };
|
|
3177
|
+
}
|
|
3067
3178
|
};
|
|
3179
|
+
function isNearFirstPoint(click, first, threshold = 1e-4) {
|
|
3180
|
+
const dx = click[0] - first[0];
|
|
3181
|
+
const dy = click[1] - first[1];
|
|
3182
|
+
return dx * dx + dy * dy < threshold * threshold;
|
|
3183
|
+
}
|
|
3184
|
+
function canAddHoleToPolygon(props) {
|
|
3185
|
+
var _a;
|
|
3186
|
+
return ((_a = props.modeConfig) == null ? void 0 : _a.allowHoles) ?? false;
|
|
3187
|
+
}
|
|
3188
|
+
function canPolygonOverlap(props) {
|
|
3189
|
+
var _a;
|
|
3190
|
+
return ((_a = props.modeConfig) == null ? void 0 : _a.allowSelfIntersection) ?? false;
|
|
3191
|
+
}
|
|
3068
3192
|
|
|
3069
3193
|
// dist/edit-modes/draw-rectangle-mode.js
|
|
3070
3194
|
var import_bbox_polygon4 = __toESM(require("@turf/bbox-polygon"), 1);
|