@accelint/map-toolkit 1.3.0 → 1.5.0
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/CHANGELOG.md +31 -0
- package/catalog-info.yaml +3 -3
- package/dist/camera/store.js +1 -1
- package/dist/camera/store.js.map +1 -1
- package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
- package/dist/deckgl/base-map/index.d.ts +2 -2
- package/dist/deckgl/base-map/index.js +24 -7
- package/dist/deckgl/base-map/index.js.map +1 -1
- package/dist/deckgl/base-map/provider.d.ts +2 -2
- package/dist/deckgl/base-map/provider.js +2 -4
- package/dist/deckgl/base-map/provider.js.map +1 -1
- package/dist/deckgl/index.js +3 -3
- package/dist/deckgl/shapes/display-shape-layer/index.js +1 -1
- package/dist/deckgl/shapes/display-shape-layer/store.js +7 -1
- package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/index.js +3 -3
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +7 -7
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/store.js +37 -3
- package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/constants.js +2 -1
- package/dist/deckgl/shapes/edit-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +2 -2
- package/dist/deckgl/shapes/edit-shape-layer/index.js +30 -12
- package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +6 -6
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js +10 -4
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js +129 -0
- package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js.map +1 -0
- package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/store.js +19 -4
- package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +4 -3
- package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +1 -1
- package/dist/deckgl/shapes/index.js +4 -4
- package/dist/deckgl/shapes/shared/constants.js +5 -5
- package/dist/deckgl/shapes/shared/constants.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/layer-config.js +1 -1
- package/dist/hotkey-manager/dist/react/use-hotkey.js +39 -0
- package/dist/hotkey-manager/dist/react/use-hotkey.js.map +1 -0
- package/dist/shared/cleanup.d.ts +58 -0
- package/dist/shared/cleanup.js +93 -0
- package/dist/shared/cleanup.js.map +1 -0
- package/dist/shared/create-map-store.d.ts +12 -0
- package/dist/shared/create-map-store.js +8 -3
- package/dist/shared/create-map-store.js.map +1 -1
- package/dist/viewport/viewport-size.d.ts +2 -2
- package/package.json +10 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/index.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { TranslateMode, ViewMode } from '@deck.gl-community/editable-layers';\nimport { BoundingTransformMode } from './bounding-transform-mode';\nimport { CircleTransformMode } from './circle-transform-mode';\nimport { VertexTransformMode } from './vertex-transform-mode';\nimport type { EditMode } from '../types';\n\n/**\n * Cached edit mode instances.\n *\n * CRITICAL: Mode instances must be cached at module level to prevent\n * deck.gl assertion failures. Creating new mode instances on each render\n * causes the EditableGeoJsonLayer to fail with assertion errors.\n *\n * BoundingTransformMode combines ScaleModeWithFreeTransform, RotateMode, and\n * TranslateMode for shapes without vertex editing (ellipses, rectangles),\n * allowing non-uniform scaling plus rotate/translate via bounding box handles.\n * Shows live dimension tooltips during scaling.\n *\n * VertexTransformMode combines ModifyMode with ScaleModeWithFreeTransform,\n * RotateMode, and TranslateMode for shapes that support vertex editing\n * (polygons, lines), allowing vertex manipulation plus scale/rotate/translate.\n *\n * CircleTransformMode combines ResizeCircleMode with TranslateMode\n * for circles, allowing resize from edge plus drag to translate.\n * Shows live
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/index.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport { TranslateMode, ViewMode } from '@deck.gl-community/editable-layers';\nimport { BoundingTransformMode } from './bounding-transform-mode';\nimport { CircleTransformMode } from './circle-transform-mode';\nimport { PointTranslateMode } from './point-translate-mode';\nimport { VertexTransformMode } from './vertex-transform-mode';\nimport type { EditMode } from '../types';\n\n/**\n * Cached edit mode instances.\n *\n * CRITICAL: Mode instances must be cached at module level to prevent\n * deck.gl assertion failures. Creating new mode instances on each render\n * causes the EditableGeoJsonLayer to fail with assertion errors.\n *\n * BoundingTransformMode combines ScaleModeWithFreeTransform, RotateMode, and\n * TranslateMode for shapes without vertex editing (ellipses, rectangles),\n * allowing non-uniform scaling plus rotate/translate via bounding box handles.\n * Shows live dimension tooltips during scaling.\n *\n * VertexTransformMode combines ModifyMode with ScaleModeWithFreeTransform,\n * RotateMode, and TranslateMode for shapes that support vertex editing\n * (polygons, lines), allowing vertex manipulation plus scale/rotate/translate.\n *\n * CircleTransformMode combines ResizeCircleMode with TranslateMode\n * for circles, allowing resize from edge plus drag to translate.\n * Shows live radius/area tooltips during resize.\n *\n * PointTranslateMode allows clicking anywhere on the map to reposition\n * a point, or dragging the point for traditional translation behavior.\n *\n * TranslateMode allows dragging to move the shape (generic translation).\n */\nconst EDIT_MODE_INSTANCES = {\n view: new ViewMode(),\n 'bounding-transform': new BoundingTransformMode(),\n 'vertex-transform': new VertexTransformMode(),\n 'circle-transform': new CircleTransformMode(),\n translate: new TranslateMode(),\n 'point-translate': new PointTranslateMode(),\n} as const;\n\n/**\n * Get the cached mode instance for an edit mode.\n *\n * Returns the pre-instantiated edit mode for the specified mode type.\n * Modes are cached at module level to prevent deck.gl assertion failures\n * that occur when creating new mode instances on each render.\n *\n * ## Available Edit Modes\n * - `'bounding-transform'`: For shapes without vertex editing (rectangles, ellipses)\n * - `'vertex-transform'`: For shapes with vertex editing (polygons, lines)\n * - `'circle-transform'`: For circles (resize from edge + translate)\n * - `'point-translate'`: For points (click to place + drag to move)\n * - `'translate'`: Generic translation (drag to move)\n *\n * @param mode - The edit mode to get the instance for\n * @returns The cached mode instance\n *\n * @example\n * ```typescript\n * import { getEditModeInstance } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes';\n *\n * // Get the bounding transform mode for editing rectangles/ellipses\n * const boundingMode = getEditModeInstance('bounding-transform');\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: boundingMode,\n * // ... other props\n * });\n * ```\n */\nexport function getEditModeInstance(\n mode: EditMode,\n): (typeof EDIT_MODE_INSTANCES)[EditMode] {\n return EDIT_MODE_INSTANCES[mode];\n}\n\n/**\n * Get the ViewMode instance (for when not editing).\n *\n * Returns the pre-instantiated ViewMode which is the default mode when\n * no editing operation is active. This mode allows viewing and interacting\n * with the map without editing shapes.\n *\n * @returns The cached ViewMode instance\n *\n * @example\n * ```typescript\n * import { getViewModeInstance } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes';\n *\n * // Get the view mode (default when not editing)\n * const viewMode = getViewModeInstance();\n *\n * // Use with EditableGeoJsonLayer\n * const layer = new EditableGeoJsonLayer({\n * mode: viewMode,\n * // ... other props\n * });\n * ```\n */\nexport function getViewModeInstance(): ViewMode {\n return EDIT_MODE_INSTANCES.view;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,MAAM,sBAAsB;CAC1B,MAAM,IAAI,UAAU;CACpB,sBAAsB,IAAI,uBAAuB;CACjD,oBAAoB,IAAI,qBAAqB;CAC7C,oBAAoB,IAAI,qBAAqB;CAC7C,WAAW,IAAI,eAAe;CAC9B,mBAAmB,IAAI,oBAAoB;CAC5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCD,SAAgB,oBACd,MACwC;AACxC,QAAO,oBAAoB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { GeoJsonEditMode, TranslateMode } from "@deck.gl-community/editable-layers";
|
|
15
|
+
|
|
16
|
+
//#region src/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.ts
|
|
17
|
+
/**
|
|
18
|
+
* Edit mode for Point shapes that supports both click-to-place and drag behaviors.
|
|
19
|
+
*
|
|
20
|
+
* ## Capabilities
|
|
21
|
+
* This mode provides two ways to reposition a point:
|
|
22
|
+
* - **Click on empty space**: Instantly moves the point to the clicked location
|
|
23
|
+
* - **Drag the point**: Traditional click-and-drag behavior (via TranslateMode)
|
|
24
|
+
*
|
|
25
|
+
* ## Behavior Details
|
|
26
|
+
* - Clicking anywhere on the map (that isn't the point itself) repositions the point
|
|
27
|
+
* - Clicking directly on the point and dragging works as traditional translation
|
|
28
|
+
* - Both behaviors emit the 'translated' edit type for consistency with existing event handling
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { PointTranslateMode } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes/point-translate-mode';
|
|
33
|
+
* import { EditableGeoJsonLayer } from '@deck.gl-community/editable-layers';
|
|
34
|
+
*
|
|
35
|
+
* // Used internally by EditShapeLayer for points
|
|
36
|
+
* const mode = new PointTranslateMode();
|
|
37
|
+
*
|
|
38
|
+
* const layer = new EditableGeoJsonLayer({
|
|
39
|
+
* mode,
|
|
40
|
+
* data: pointFeatureCollection,
|
|
41
|
+
* selectedFeatureIndexes: [0],
|
|
42
|
+
* onEdit: handleEdit,
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
var PointTranslateMode = class extends GeoJsonEditMode {
|
|
47
|
+
translateMode = new TranslateMode();
|
|
48
|
+
/**
|
|
49
|
+
* Handle click events to reposition the point.
|
|
50
|
+
*
|
|
51
|
+
* If the click is on empty map space (not on the point itself),
|
|
52
|
+
* moves the point to the clicked location immediately.
|
|
53
|
+
*
|
|
54
|
+
* @param event - Click event containing map coordinates and pick information
|
|
55
|
+
* @param props - Mode props containing data, selected indexes, and edit callback
|
|
56
|
+
*/
|
|
57
|
+
handleClick(event, props) {
|
|
58
|
+
if (event.picks?.some((pick) => pick.isGuide || pick.featureIndex !== void 0)) return;
|
|
59
|
+
const { mapCoords } = event;
|
|
60
|
+
const selectedIndex = props.selectedIndexes?.[0];
|
|
61
|
+
if (selectedIndex === void 0) return;
|
|
62
|
+
const feature = props.data.features[selectedIndex];
|
|
63
|
+
if (!feature) return;
|
|
64
|
+
const updatedFeature = {
|
|
65
|
+
...feature,
|
|
66
|
+
geometry: {
|
|
67
|
+
type: "Point",
|
|
68
|
+
coordinates: mapCoords
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
props.onEdit({
|
|
72
|
+
updatedData: {
|
|
73
|
+
...props.data,
|
|
74
|
+
features: [updatedFeature]
|
|
75
|
+
},
|
|
76
|
+
editType: "translated",
|
|
77
|
+
editContext: { featureIndexes: [selectedIndex] }
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Delegate pointer move events to TranslateMode for cursor updates.
|
|
82
|
+
*
|
|
83
|
+
* @param event - Pointer move event with current cursor position
|
|
84
|
+
* @param props - Mode props containing state and configuration
|
|
85
|
+
*/
|
|
86
|
+
handlePointerMove(event, props) {
|
|
87
|
+
this.translateMode.handlePointerMove(event, props);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Delegate start dragging to TranslateMode for traditional drag behavior.
|
|
91
|
+
*
|
|
92
|
+
* @param event - Drag start event with pointer down coordinates
|
|
93
|
+
* @param props - Mode props containing data and edit callback
|
|
94
|
+
*/
|
|
95
|
+
handleStartDragging(event, props) {
|
|
96
|
+
this.translateMode.handleStartDragging(event, props);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Delegate dragging to TranslateMode for traditional drag behavior.
|
|
100
|
+
*
|
|
101
|
+
* @param event - Dragging event with current and previous pointer positions
|
|
102
|
+
* @param props - Mode props containing data and edit callback
|
|
103
|
+
*/
|
|
104
|
+
handleDragging(event, props) {
|
|
105
|
+
this.translateMode.handleDragging(event, props);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Delegate stop dragging to TranslateMode for traditional drag behavior.
|
|
109
|
+
*
|
|
110
|
+
* @param event - Drag stop event with final pointer position
|
|
111
|
+
* @param props - Mode props containing data and edit callback
|
|
112
|
+
*/
|
|
113
|
+
handleStopDragging(event, props) {
|
|
114
|
+
this.translateMode.handleStopDragging(event, props);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Delegate guide rendering to TranslateMode.
|
|
118
|
+
*
|
|
119
|
+
* @param props - Mode props containing data and selected indexes
|
|
120
|
+
* @returns Guide feature collection for rendering edit handles
|
|
121
|
+
*/
|
|
122
|
+
getGuides(props) {
|
|
123
|
+
return this.translateMode.getGuides(props);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
//#endregion
|
|
128
|
+
export { PointTranslateMode };
|
|
129
|
+
//# sourceMappingURL=point-translate-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-translate-mode.js","names":[],"sources":["../../../../../src/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n type ClickEvent,\n type DraggingEvent,\n type FeatureCollection,\n GeoJsonEditMode,\n type GuideFeatureCollection,\n type ModeProps,\n type PointerMoveEvent,\n type StartDraggingEvent,\n type StopDraggingEvent,\n TranslateMode,\n} from '@deck.gl-community/editable-layers';\n\n/**\n * Edit mode for Point shapes that supports both click-to-place and drag behaviors.\n *\n * ## Capabilities\n * This mode provides two ways to reposition a point:\n * - **Click on empty space**: Instantly moves the point to the clicked location\n * - **Drag the point**: Traditional click-and-drag behavior (via TranslateMode)\n *\n * ## Behavior Details\n * - Clicking anywhere on the map (that isn't the point itself) repositions the point\n * - Clicking directly on the point and dragging works as traditional translation\n * - Both behaviors emit the 'translated' edit type for consistency with existing event handling\n *\n * @example\n * ```typescript\n * import { PointTranslateMode } from '@accelint/map-toolkit/deckgl/shapes/edit-shape-layer/modes/point-translate-mode';\n * import { EditableGeoJsonLayer } from '@deck.gl-community/editable-layers';\n *\n * // Used internally by EditShapeLayer for points\n * const mode = new PointTranslateMode();\n *\n * const layer = new EditableGeoJsonLayer({\n * mode,\n * data: pointFeatureCollection,\n * selectedFeatureIndexes: [0],\n * onEdit: handleEdit,\n * });\n * ```\n */\nexport class PointTranslateMode extends GeoJsonEditMode {\n private translateMode = new TranslateMode();\n\n /**\n * Handle click events to reposition the point.\n *\n * If the click is on empty map space (not on the point itself),\n * moves the point to the clicked location immediately.\n *\n * @param event - Click event containing map coordinates and pick information\n * @param props - Mode props containing data, selected indexes, and edit callback\n */\n override handleClick(\n event: ClickEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n // If clicked on the point itself or a guide, let drag handle it\n const clickedOnFeature = event.picks?.some(\n (pick) => pick.isGuide || pick.featureIndex !== undefined,\n );\n\n if (clickedOnFeature) {\n return;\n }\n\n const { mapCoords } = event;\n const selectedIndex = props.selectedIndexes?.[0];\n\n if (selectedIndex === undefined) {\n return;\n }\n\n const feature = props.data.features[selectedIndex];\n\n if (!feature) {\n return;\n }\n\n // Create updated feature with new coordinates\n const updatedFeature = {\n ...feature,\n geometry: {\n type: 'Point' as const,\n coordinates: mapCoords,\n },\n };\n\n // Emit edit action with 'translated' type to work with existing completion handlers\n props.onEdit({\n updatedData: {\n ...props.data,\n features: [updatedFeature],\n },\n editType: 'translated',\n editContext: {\n featureIndexes: [selectedIndex],\n },\n });\n }\n\n /**\n * Delegate pointer move events to TranslateMode for cursor updates.\n *\n * @param event - Pointer move event with current cursor position\n * @param props - Mode props containing state and configuration\n */\n override handlePointerMove(\n event: PointerMoveEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handlePointerMove(event, props);\n }\n\n /**\n * Delegate start dragging to TranslateMode for traditional drag behavior.\n *\n * @param event - Drag start event with pointer down coordinates\n * @param props - Mode props containing data and edit callback\n */\n override handleStartDragging(\n event: StartDraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handleStartDragging(event, props);\n }\n\n /**\n * Delegate dragging to TranslateMode for traditional drag behavior.\n *\n * @param event - Dragging event with current and previous pointer positions\n * @param props - Mode props containing data and edit callback\n */\n override handleDragging(\n event: DraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handleDragging(event, props);\n }\n\n /**\n * Delegate stop dragging to TranslateMode for traditional drag behavior.\n *\n * @param event - Drag stop event with final pointer position\n * @param props - Mode props containing data and edit callback\n */\n override handleStopDragging(\n event: StopDraggingEvent,\n props: ModeProps<FeatureCollection>,\n ): void {\n this.translateMode.handleStopDragging(event, props);\n }\n\n /**\n * Delegate guide rendering to TranslateMode.\n *\n * @param props - Mode props containing data and selected indexes\n * @returns Guide feature collection for rendering edit handles\n */\n override getGuides(\n props: ModeProps<FeatureCollection>,\n ): GuideFeatureCollection {\n return this.translateMode.getGuides(props);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,IAAa,qBAAb,cAAwC,gBAAgB;CACtD,AAAQ,gBAAgB,IAAI,eAAe;;;;;;;;;;CAW3C,AAAS,YACP,OACA,OACM;AAMN,MAJyB,MAAM,OAAO,MACnC,SAAS,KAAK,WAAW,KAAK,iBAAiB,OACjD,CAGC;EAGF,MAAM,EAAE,cAAc;EACtB,MAAM,gBAAgB,MAAM,kBAAkB;AAE9C,MAAI,kBAAkB,OACpB;EAGF,MAAM,UAAU,MAAM,KAAK,SAAS;AAEpC,MAAI,CAAC,QACH;EAIF,MAAM,iBAAiB;GACrB,GAAG;GACH,UAAU;IACR,MAAM;IACN,aAAa;IACd;GACF;AAGD,QAAM,OAAO;GACX,aAAa;IACX,GAAG,MAAM;IACT,UAAU,CAAC,eAAe;IAC3B;GACD,UAAU;GACV,aAAa,EACX,gBAAgB,CAAC,cAAc,EAChC;GACF,CAAC;;;;;;;;CASJ,AAAS,kBACP,OACA,OACM;AACN,OAAK,cAAc,kBAAkB,OAAO,MAAM;;;;;;;;CASpD,AAAS,oBACP,OACA,OACM;AACN,OAAK,cAAc,oBAAoB,OAAO,MAAM;;;;;;;;CAStD,AAAS,eACP,OACA,OACM;AACN,OAAK,cAAc,eAAe,OAAO,MAAM;;;;;;;;CASjD,AAAS,mBACP,OACA,OACM;AACN,OAAK,cAAc,mBAAmB,OAAO,MAAM;;;;;;;;CASrD,AAAS,UACP,OACwB;AACxB,SAAO,KAAK,cAAc,UAAU,MAAM"}
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import { ImmutableFeatureCollection, RotateMode } from "@deck.gl-community/editable-layers";
|
|
15
14
|
import { bearing, centroid, transformRotate } from "@turf/turf";
|
|
15
|
+
import { ImmutableFeatureCollection, RotateMode } from "@deck.gl-community/editable-layers";
|
|
16
16
|
|
|
17
17
|
//#region src/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.ts
|
|
18
18
|
/** Snap interval in degrees (45° = 8 positions around the circle) */
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
import { createMapStore } from "../../../shared/create-map-store.js";
|
|
17
17
|
import { MapEvents } from "../../base-map/events.js";
|
|
18
|
-
import { isCircleShape, isEllipseShape, isPointShape, isRectangleShape } from "../shared/types.js";
|
|
19
18
|
import { releaseModeAndCursor, requestCursorChange, requestModeChange } from "../shared/utils/mode-utils.js";
|
|
20
|
-
import {
|
|
19
|
+
import { isCircleShape, isEllipseShape, isPointShape, isRectangleShape } from "../shared/types.js";
|
|
21
20
|
import { EDIT_CURSOR_MAP, EDIT_SHAPE_LAYER_ID, EDIT_SHAPE_MODE } from "./constants.js";
|
|
21
|
+
import { EditShapeEvents } from "./events.js";
|
|
22
22
|
import { Broadcast } from "@accelint/bus";
|
|
23
23
|
import { getLogger } from "@accelint/logger";
|
|
24
24
|
|
|
@@ -66,9 +66,12 @@ const DEFAULT_EDITING_STATE = {
|
|
|
66
66
|
};
|
|
67
67
|
/**
|
|
68
68
|
* Determine the appropriate edit mode for a shape type
|
|
69
|
+
*
|
|
70
|
+
* @param shape - The shape to determine the edit mode for
|
|
71
|
+
* @returns The edit mode to use for this shape type
|
|
69
72
|
*/
|
|
70
73
|
function getEditModeForShape(shape) {
|
|
71
|
-
if (isPointShape(shape)) return "translate";
|
|
74
|
+
if (isPointShape(shape)) return "point-translate";
|
|
72
75
|
if (isCircleShape(shape)) return "circle-transform";
|
|
73
76
|
if (isEllipseShape(shape) || isRectangleShape(shape)) return "bounding-transform";
|
|
74
77
|
return "vertex-transform";
|
|
@@ -177,6 +180,12 @@ const editStore = createMapStore({
|
|
|
177
180
|
}
|
|
178
181
|
});
|
|
179
182
|
/**
|
|
183
|
+
* Manually clear editing state for a specific mapId.
|
|
184
|
+
*/
|
|
185
|
+
function clearEditingState(mapId) {
|
|
186
|
+
editStore.clear(mapId);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
180
189
|
* Update feature from the layer component (called during drag operations)
|
|
181
190
|
*/
|
|
182
191
|
function updateFeatureFromLayer(mapId, feature) {
|
|
@@ -188,7 +197,13 @@ function updateFeatureFromLayer(mapId, feature) {
|
|
|
188
197
|
function cancelEditingFromLayer(mapId) {
|
|
189
198
|
editStore.actions(mapId).cancel();
|
|
190
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Save editing (called by the layer component on Enter)
|
|
202
|
+
*/
|
|
203
|
+
function saveEditingFromLayer(mapId) {
|
|
204
|
+
editStore.actions(mapId).save();
|
|
205
|
+
}
|
|
191
206
|
|
|
192
207
|
//#endregion
|
|
193
|
-
export { cancelEditingFromLayer, editStore, updateFeatureFromLayer };
|
|
208
|
+
export { cancelEditingFromLayer, clearEditingState, editStore, saveEditingFromLayer, updateFeatureFromLayer };
|
|
194
209
|
//# sourceMappingURL=store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":["DEFAULT_EDITING_STATE: EditingState"],"sources":["../../../../src/deckgl/shapes/edit-shape-layer/store.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\n/**\n * Edit Shape Store\n *\n * Manages editing state for shape modification.\n *\n * @example\n * ```typescript\n * import { editStore } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * function EditControls({ mapId }) {\n * const { state, edit, save, cancel } = editStore.use(mapId);\n *\n * return (\n * <div>\n * <p>Editing: {state.editingShape?.name ?? 'none'}</p>\n * <button onClick={save}>Save</button>\n * <button onClick={cancel}>Cancel</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { getLogger } from '@accelint/logger';\nimport { createMapStore } from '@/shared/create-map-store';\nimport { MapEvents } from '../../base-map/events';\nimport {\n isCircleShape,\n isEllipseShape,\n isPointShape,\n isRectangleShape,\n} from '../shared/types';\nimport {\n releaseModeAndCursor,\n requestCursorChange,\n requestModeChange,\n} from '../shared/utils/mode-utils';\nimport {\n EDIT_CURSOR_MAP,\n EDIT_SHAPE_LAYER_ID,\n EDIT_SHAPE_MODE,\n} from './constants';\nimport { EditShapeEvents } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { Feature } from 'geojson';\nimport type { MapEventType } from '../../base-map/types';\nimport type { Shape } from '../shared/types';\nimport type {\n EditShapeEvent,\n ShapeEditCanceledEvent,\n ShapeEditingEvent,\n ShapeUpdatedEvent,\n} from './events';\nimport type {\n EditFunction,\n EditingState,\n EditMode,\n EditShapeOptions,\n} from './types';\n\nconst logger = getLogger({\n enabled:\n process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test',\n level: 'warn',\n prefix: '[EditShapeLayer]',\n pretty: true,\n});\n\n/**\n * Typed event bus instances\n */\nconst editShapeBus = Broadcast.getInstance<EditShapeEvent>();\nconst mapEventBus = Broadcast.getInstance<MapEventType>();\n\n/**\n * Default editing state\n */\nconst DEFAULT_EDITING_STATE: EditingState = {\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n};\n\n/**\n * Actions for edit shape store\n */\ntype EditShapeActions = {\n /** Start editing a shape */\n edit: EditFunction;\n /** Save the current edits */\n save: () => void;\n /** Cancel editing */\n cancel: () => void;\n};\n\n/**\n * Determine the appropriate edit mode for a shape type\n */\nfunction getEditModeForShape(shape: Shape): EditMode {\n if (isPointShape(shape)) {\n return 'translate';\n }\n if (isCircleShape(shape)) {\n return 'circle-transform';\n }\n if (isEllipseShape(shape) || isRectangleShape(shape)) {\n return 'bounding-transform';\n }\n return 'vertex-transform';\n}\n\n/**\n * Start editing a shape\n */\nfunction startEditing(\n mapId: UniqueId,\n state: EditingState,\n shape: Shape,\n options: EditShapeOptions | undefined,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n // Prevent editing locked shapes\n if (shape.locked) {\n logger.warn(`Cannot edit locked shape: \"${shape.name}\"`);\n return;\n }\n\n // Already editing - cancel first\n if (state.editingShape) {\n cancelEditingInternal(mapId, state, notify, setState);\n }\n\n // Determine edit mode (can be overridden via options)\n const editMode = options?.mode ?? getEditModeForShape(shape);\n\n // Update state with new object reference\n setState({\n editingShape: shape,\n editMode,\n featureBeingEdited: shape.feature,\n });\n\n // Request map mode and cursor\n requestModeChange(mapId, EDIT_SHAPE_MODE, EDIT_SHAPE_LAYER_ID);\n const cursor = EDIT_CURSOR_MAP[editMode];\n requestCursorChange(mapId, cursor, EDIT_SHAPE_LAYER_ID);\n\n // Disable map panning during editing\n mapEventBus.emit(MapEvents.disablePan, { id: mapId });\n\n // Emit editing started event\n editShapeBus.emit(EditShapeEvents.editing, {\n shape,\n mapId,\n } as unknown as ShapeEditingEvent['payload']);\n\n notify();\n}\n\n/**\n * Save editing and create updated shape\n */\nfunction saveEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): Shape | null {\n if (!(state.editingShape && state.featureBeingEdited)) {\n return null;\n }\n\n const originalShape = state.editingShape;\n const updatedFeature = state.featureBeingEdited;\n\n // Create updated shape with new geometry\n const updatedShape = {\n ...originalShape,\n feature: {\n ...updatedFeature,\n properties: {\n ...originalShape.feature.properties,\n ...updatedFeature.properties,\n },\n },\n lastUpdated: Date.now(),\n } as Shape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit shape updated event\n editShapeBus.emit(EditShapeEvents.updated, {\n shape: updatedShape,\n mapId,\n } as unknown as ShapeUpdatedEvent['payload']);\n\n notify();\n\n return updatedShape;\n}\n\n/**\n * Cancel the current editing operation\n */\nfunction cancelEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n if (!state.editingShape) {\n return; // Nothing to cancel\n }\n\n const originalShape = state.editingShape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: originalShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n\n notify();\n}\n\n/**\n * Edit shape store\n */\nexport const editStore = createMapStore<EditingState, EditShapeActions>({\n defaultState: { ...DEFAULT_EDITING_STATE },\n\n actions: (mapId, { get, set, notify }) => ({\n edit: (shape: Shape, options?: EditShapeOptions) => {\n startEditing(mapId, get(), shape, options, notify, set);\n },\n\n save: () => {\n saveEditingInternal(mapId, get(), notify, set);\n },\n\n cancel: () => {\n cancelEditingInternal(mapId, get(), notify, set);\n },\n }),\n\n // Note: EditShapeLayer is \"neutral\" regarding mode change authorization.\n // It doesn't auto-cancel or reject mode changes - those decisions are\n // left to UI components that can prompt the user.\n\n onCleanup: (mapId, state) => {\n // Cancel any active editing before cleanup\n if (state.editingShape) {\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: state.editingShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n }\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get the current editing state for a mapId\n * Returns null if no store instance exists\n */\nexport function getEditingState(mapId: UniqueId): EditingState | null {\n if (!editStore.exists(mapId)) {\n return null;\n }\n return editStore.get(mapId);\n}\n\n/**\n * Hook for editing state\n */\nexport function useEditingState(\n mapId: UniqueId,\n): { state: EditingState } & EditShapeActions {\n return editStore.use(mapId);\n}\n\n/**\n * Manually clear editing state for a specific mapId.\n */\nexport function clearEditingState(mapId: UniqueId): void {\n editStore.clear(mapId);\n}\n\n/**\n * Update feature from the layer component (called during drag operations)\n */\nexport function updateFeatureFromLayer(\n mapId: UniqueId,\n feature: Feature,\n): void {\n editStore.set(mapId, { featureBeingEdited: feature });\n}\n\n/**\n * Cancel editing (called by the layer component on ESC)\n */\nexport function cancelEditingFromLayer(mapId: UniqueId): void {\n editStore.actions(mapId).cancel();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","names":["DEFAULT_EDITING_STATE: EditingState"],"sources":["../../../../src/deckgl/shapes/edit-shape-layer/store.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\n/**\n * Edit Shape Store\n *\n * Manages editing state for shape modification.\n *\n * @example\n * ```typescript\n * import { editStore } from '@accelint/map-toolkit/deckgl/shapes';\n *\n * function EditControls({ mapId }) {\n * const { state, edit, save, cancel } = editStore.use(mapId);\n *\n * return (\n * <div>\n * <p>Editing: {state.editingShape?.name ?? 'none'}</p>\n * <button onClick={save}>Save</button>\n * <button onClick={cancel}>Cancel</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { Broadcast } from '@accelint/bus';\nimport { getLogger } from '@accelint/logger';\nimport { createMapStore } from '@/shared/create-map-store';\nimport { MapEvents } from '../../base-map/events';\nimport {\n isCircleShape,\n isEllipseShape,\n isPointShape,\n isRectangleShape,\n} from '../shared/types';\nimport {\n releaseModeAndCursor,\n requestCursorChange,\n requestModeChange,\n} from '../shared/utils/mode-utils';\nimport {\n EDIT_CURSOR_MAP,\n EDIT_SHAPE_LAYER_ID,\n EDIT_SHAPE_MODE,\n} from './constants';\nimport { EditShapeEvents } from './events';\nimport type { UniqueId } from '@accelint/core';\nimport type { Feature } from 'geojson';\nimport type { MapEventType } from '../../base-map/types';\nimport type { Shape } from '../shared/types';\nimport type {\n EditShapeEvent,\n ShapeEditCanceledEvent,\n ShapeEditingEvent,\n ShapeUpdatedEvent,\n} from './events';\nimport type {\n EditFunction,\n EditingState,\n EditMode,\n EditShapeOptions,\n} from './types';\n\nconst logger = getLogger({\n enabled:\n process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test',\n level: 'warn',\n prefix: '[EditShapeLayer]',\n pretty: true,\n});\n\n/**\n * Typed event bus instances\n */\nconst editShapeBus = Broadcast.getInstance<EditShapeEvent>();\nconst mapEventBus = Broadcast.getInstance<MapEventType>();\n\n/**\n * Default editing state\n */\nconst DEFAULT_EDITING_STATE: EditingState = {\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n};\n\n/**\n * Actions for edit shape store\n */\ntype EditShapeActions = {\n /** Start editing a shape */\n edit: EditFunction;\n /** Save the current edits */\n save: () => void;\n /** Cancel editing */\n cancel: () => void;\n};\n\n/**\n * Determine the appropriate edit mode for a shape type\n *\n * @param shape - The shape to determine the edit mode for\n * @returns The edit mode to use for this shape type\n */\nfunction getEditModeForShape(shape: Shape): EditMode {\n if (isPointShape(shape)) {\n return 'point-translate';\n }\n if (isCircleShape(shape)) {\n return 'circle-transform';\n }\n if (isEllipseShape(shape) || isRectangleShape(shape)) {\n return 'bounding-transform';\n }\n return 'vertex-transform';\n}\n\n/**\n * Start editing a shape\n */\nfunction startEditing(\n mapId: UniqueId,\n state: EditingState,\n shape: Shape,\n options: EditShapeOptions | undefined,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n // Prevent editing locked shapes\n if (shape.locked) {\n logger.warn(`Cannot edit locked shape: \"${shape.name}\"`);\n return;\n }\n\n // Already editing - cancel first\n if (state.editingShape) {\n cancelEditingInternal(mapId, state, notify, setState);\n }\n\n // Determine edit mode (can be overridden via options)\n const editMode = options?.mode ?? getEditModeForShape(shape);\n\n // Update state with new object reference\n setState({\n editingShape: shape,\n editMode,\n featureBeingEdited: shape.feature,\n });\n\n // Request map mode and cursor\n requestModeChange(mapId, EDIT_SHAPE_MODE, EDIT_SHAPE_LAYER_ID);\n const cursor = EDIT_CURSOR_MAP[editMode];\n requestCursorChange(mapId, cursor, EDIT_SHAPE_LAYER_ID);\n\n // Disable map panning during editing\n mapEventBus.emit(MapEvents.disablePan, { id: mapId });\n\n // Emit editing started event\n editShapeBus.emit(EditShapeEvents.editing, {\n shape,\n mapId,\n } as unknown as ShapeEditingEvent['payload']);\n\n notify();\n}\n\n/**\n * Save editing and create updated shape\n */\nfunction saveEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): Shape | null {\n if (!(state.editingShape && state.featureBeingEdited)) {\n return null;\n }\n\n const originalShape = state.editingShape;\n const updatedFeature = state.featureBeingEdited;\n\n // Create updated shape with new geometry\n const updatedShape = {\n ...originalShape,\n feature: {\n ...updatedFeature,\n properties: {\n ...originalShape.feature.properties,\n ...updatedFeature.properties,\n },\n },\n lastUpdated: Date.now(),\n } as Shape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit shape updated event\n editShapeBus.emit(EditShapeEvents.updated, {\n shape: updatedShape,\n mapId,\n } as unknown as ShapeUpdatedEvent['payload']);\n\n notify();\n\n return updatedShape;\n}\n\n/**\n * Cancel the current editing operation\n */\nfunction cancelEditingInternal(\n mapId: UniqueId,\n state: EditingState,\n notify: () => void,\n setState: (updates: Partial<EditingState>) => void,\n): void {\n if (!state.editingShape) {\n return; // Nothing to cancel\n }\n\n const originalShape = state.editingShape;\n\n // Reset state\n setState({\n editingShape: null,\n editMode: 'view',\n featureBeingEdited: null,\n });\n\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: originalShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n\n notify();\n}\n\n/**\n * Edit shape store\n */\nexport const editStore = createMapStore<EditingState, EditShapeActions>({\n defaultState: { ...DEFAULT_EDITING_STATE },\n\n actions: (mapId, { get, set, notify }) => ({\n edit: (shape: Shape, options?: EditShapeOptions) => {\n startEditing(mapId, get(), shape, options, notify, set);\n },\n\n save: () => {\n saveEditingInternal(mapId, get(), notify, set);\n },\n\n cancel: () => {\n cancelEditingInternal(mapId, get(), notify, set);\n },\n }),\n\n // Note: EditShapeLayer is \"neutral\" regarding mode change authorization.\n // It doesn't auto-cancel or reject mode changes - those decisions are\n // left to UI components that can prompt the user.\n\n onCleanup: (mapId, state) => {\n // Cancel any active editing before cleanup\n if (state.editingShape) {\n // Return to default mode and cursor\n releaseModeAndCursor(mapId, EDIT_SHAPE_LAYER_ID);\n\n // Re-enable map panning\n mapEventBus.emit(MapEvents.enablePan, { id: mapId });\n\n // Emit canceled event\n editShapeBus.emit(EditShapeEvents.canceled, {\n shape: state.editingShape,\n mapId,\n } as unknown as ShapeEditCanceledEvent['payload']);\n }\n },\n});\n\n// =============================================================================\n// Convenience exports\n// =============================================================================\n\n/**\n * Get the current editing state for a mapId\n * Returns null if no store instance exists\n */\nexport function getEditingState(mapId: UniqueId): EditingState | null {\n if (!editStore.exists(mapId)) {\n return null;\n }\n return editStore.get(mapId);\n}\n\n/**\n * Hook for editing state\n */\nexport function useEditingState(\n mapId: UniqueId,\n): { state: EditingState } & EditShapeActions {\n return editStore.use(mapId);\n}\n\n/**\n * Manually clear editing state for a specific mapId.\n */\nexport function clearEditingState(mapId: UniqueId): void {\n editStore.clear(mapId);\n}\n\n/**\n * Update feature from the layer component (called during drag operations)\n */\nexport function updateFeatureFromLayer(\n mapId: UniqueId,\n feature: Feature,\n): void {\n editStore.set(mapId, { featureBeingEdited: feature });\n}\n\n/**\n * Cancel editing (called by the layer component on ESC)\n */\nexport function cancelEditingFromLayer(mapId: UniqueId): void {\n editStore.actions(mapId).cancel();\n}\n\n/**\n * Save editing (called by the layer component on Enter)\n */\nexport function saveEditingFromLayer(mapId: UniqueId): void {\n editStore.actions(mapId).save();\n}\n"],"mappings":"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"}
|
|
@@ -22,9 +22,10 @@ import { Feature } from "geojson";
|
|
|
22
22
|
* - 'bounding-transform': Scale/rotate/translate via bounding box handles (ellipses, rectangles)
|
|
23
23
|
* - 'vertex-transform': Drag vertices OR scale/rotate/translate (polygons, lines)
|
|
24
24
|
* - 'circle-transform': Drag edge to resize, drag body to translate (circles)
|
|
25
|
-
* - 'translate': Drag to move the shape (
|
|
25
|
+
* - 'translate': Drag to move the shape (generic translation)
|
|
26
|
+
* - 'point-translate': Click to place OR drag to move (points)
|
|
26
27
|
*/
|
|
27
|
-
type EditMode = 'view' | 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate';
|
|
28
|
+
type EditMode = 'view' | 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate' | 'point-translate';
|
|
28
29
|
/**
|
|
29
30
|
* State for the editing store
|
|
30
31
|
*/
|
|
@@ -41,7 +42,7 @@ type EditingState = {
|
|
|
41
42
|
*/
|
|
42
43
|
type EditShapeOptions = {
|
|
43
44
|
/** Override the default edit mode (auto-detected from shape type by default) */
|
|
44
|
-
mode?: 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate';
|
|
45
|
+
mode?: 'bounding-transform' | 'vertex-transform' | 'circle-transform' | 'translate' | 'point-translate';
|
|
45
46
|
};
|
|
46
47
|
/**
|
|
47
48
|
* Options for the useEditShape hook
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
'use client';
|
|
15
15
|
|
|
16
|
-
import { MapContext } from "../../base-map/provider.js";
|
|
17
16
|
import { EditShapeEvents } from "./events.js";
|
|
18
17
|
import { editStore } from "./store.js";
|
|
18
|
+
import { MapContext } from "../../base-map/provider.js";
|
|
19
19
|
import { useContext, useMemo } from "react";
|
|
20
20
|
import { useBus } from "@accelint/bus/react";
|
|
21
21
|
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
import { BASE_FILL_OPACITY, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_EDIT_HANDLE_COLOR, DEFAULT_EDIT_HANDLE_OUTLINE_COLOR, DEFAULT_STYLE_PROPERTIES, LINE_PATTERNS, LINE_WIDTHS, SHAPE_LAYER_IDS } from "./shared/constants.js";
|
|
15
14
|
import { ShapeEvents } from "./shared/events.js";
|
|
16
|
-
import { getDashArray, getFillColor, getLineColor, getLineWidth, normalizeColor } from "./shared/utils/style-utils.js";
|
|
17
15
|
import { ShapeFeatureType, isCircleShape, isEllipseShape, isLineStringShape, isPointShape, isPolygonShape, isRectangleShape } from "./shared/types.js";
|
|
16
|
+
import { DrawShapeEvents } from "./draw-shape-layer/events.js";
|
|
17
|
+
import { BASE_FILL_OPACITY, DASH_ARRAYS, DEFAULT_COLORS, DEFAULT_EDIT_HANDLE_COLOR, DEFAULT_EDIT_HANDLE_OUTLINE_COLOR, DEFAULT_STYLE_PROPERTIES, LINE_PATTERNS, LINE_WIDTHS, SHAPE_LAYER_IDS } from "./shared/constants.js";
|
|
18
|
+
import { EditShapeEvents } from "./edit-shape-layer/events.js";
|
|
19
|
+
import { getDashArray, getFillColor, getLineColor, getLineWidth, normalizeColor } from "./shared/utils/style-utils.js";
|
|
18
20
|
import { DisplayShapeLayer } from "./display-shape-layer/index.js";
|
|
19
21
|
import { useSelectShape } from "./display-shape-layer/use-select-shape.js";
|
|
20
|
-
import { DrawShapeEvents } from "./draw-shape-layer/events.js";
|
|
21
22
|
import { DrawShapeLayer } from "./draw-shape-layer/index.js";
|
|
22
23
|
import { useDrawShape } from "./draw-shape-layer/use-draw-shape.js";
|
|
23
|
-
import { EditShapeEvents } from "./edit-shape-layer/events.js";
|
|
24
24
|
import { EditShapeLayer } from "./edit-shape-layer/index.js";
|
|
25
25
|
import { useEditShape } from "./edit-shape-layer/use-edit-shape.js";
|
|
26
26
|
|
|
@@ -200,15 +200,15 @@ function formatDistance(value) {
|
|
|
200
200
|
return value.toFixed(2);
|
|
201
201
|
}
|
|
202
202
|
/**
|
|
203
|
-
* Format circle tooltip text showing
|
|
203
|
+
* Format circle tooltip text showing radius and area.
|
|
204
204
|
*
|
|
205
|
-
* @param
|
|
205
|
+
* @param radius - Circle radius in the specified units
|
|
206
206
|
* @param area - Circle area in the specified units squared
|
|
207
207
|
* @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')
|
|
208
|
-
* @returns Formatted tooltip text: "
|
|
208
|
+
* @returns Formatted tooltip text: "r: {radius} {unit}\n{area} {unit}²"
|
|
209
209
|
*/
|
|
210
|
-
function formatCircleTooltip(
|
|
211
|
-
return `
|
|
210
|
+
function formatCircleTooltip(radius, area, unitAbbrev) {
|
|
211
|
+
return `r: ${formatDistance(radius)} ${unitAbbrev}\n${formatDistance(area)} ${unitAbbrev}²`;
|
|
212
212
|
}
|
|
213
213
|
/**
|
|
214
214
|
* Format rectangle tooltip text showing dimensions and area.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":["DEFAULT_STYLE_PROPERTIES: StyleProperties","DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n>","DEFAULT_EDIT_HANDLE_COLOR: Color","DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color","EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection","TOOLTIP_CHARACTER_SET: string[]"],"sources":["../../../../src/deckgl/shapes/shared/constants.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport { DEFAULT_TEXT_STYLE } from '../../text-settings';\nimport type { Color } from '@deck.gl/core';\nimport type { StyleProperties } from './types';\n\n/**\n * Layer IDs for shape layers\n */\nexport const SHAPE_LAYER_IDS = {\n DISPLAY: 'DISPLAY_SHAPES',\n DISPLAY_HIGHLIGHT: 'DISPLAY_SHAPES::Highlight',\n DISPLAY_LABELS: 'DISPLAY_SHAPES::Labels',\n} as const;\n\n/**\n * Base fill opacity multiplier for standard semi-transparent look.\n * Multiplies alpha by 0.2 (reduces to 20% of original opacity).\n */\nexport const BASE_FILL_OPACITY = 0.2;\n\n/**\n * Default border/outline width in pixels when not specified in styleProperties\n */\nexport const DEFAULT_LINE_WIDTH = 2;\n\n/**\n * Additional pixels added to border/outline width on hover\n */\nexport const HOVER_WIDTH_INCREASE = 2;\n\n/**\n * Additional pixels added to border/outline width for selection highlight\n */\nexport const HIGHLIGHT_WIDTH_INCREASE = 5;\n\n/**\n * Fixed opacity for label background (0-255)\n */\nexport const LABEL_BACKGROUND_OPACITY = 200;\n\n/**\n * Fixed opacity for label border (0-255)\n */\nexport const LABEL_BORDER_OPACITY = 255;\n\n/**\n * Default colors as RGBA arrays for DeckGL layers.\n *\n * These are the canonical color values used throughout the shapes system.\n * All other color constants should derive from these to maintain consistency.\n */\nexport const DEFAULT_COLORS = {\n /** Default fill color (white at full alpha) */\n fill: [255, 255, 255, 255] as Color,\n /** Default border/outline color (outline-interactive-hover: #888a8f) */\n line: [136, 138, 143, 255] as Color,\n /** Highlight/selection color (turquoise at ~39% alpha) */\n highlight: [40, 245, 190, 100] as Color,\n} as const;\n\n/**\n * Tentative (during-drawing) colors.\n *\n * These colors are used for the shape preview while drawing.\n * Fill is semi-transparent (8% opacity) to not obscure underlying features.\n * Border/outline uses the same color as saved shapes for consistency.\n */\nexport const DEFAULT_TENTATIVE_COLORS = {\n /** Tentative fill color (white at 8% opacity: 0.08 * 255 ≈ 20) */\n fill: [255, 255, 255, 20] as Color,\n /** Tentative border/outline color (same as saved shapes for consistency) */\n line: DEFAULT_COLORS.line,\n} as const;\n\n/**\n * Default style properties for saved shapes.\n *\n * These are applied when a shape is completed/saved.\n * Can be overridden via styleDefaults in draw options.\n */\nexport const DEFAULT_STYLE_PROPERTIES: StyleProperties = {\n fillColor: DEFAULT_COLORS.fill,\n lineColor: DEFAULT_COLORS.line,\n lineWidth: 2,\n linePattern: 'solid',\n};\n\n/**\n * Border/outline width options (in pixels)\n */\nexport const LINE_WIDTHS = [1, 2, 4, 8] as const;\n\n/**\n * Border/outline pattern options\n */\nexport const LINE_PATTERNS = ['solid', 'dashed', 'dotted'] as const;\n\n/**\n * Dash array patterns for border/outline rendering\n */\nexport const DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n> = {\n solid: null,\n dashed: [8, 4],\n dotted: [2, 4],\n};\n\n/**\n * Default tentative fill color (white at 8% opacity - rgba(255, 255, 255, 0.08))\n * Used when drawing new shapes before they're completed.\n * 0.08 * 255 ≈ 20\n */\nexport const DEFAULT_TENTATIVE_FILL_COLOR: Color = [255, 255, 255, 20];\n\n/**\n * Default tentative border/outline color (outline-interactive-hover: #888a8f)\n * Used when drawing new shapes before they're completed.\n */\nexport const DEFAULT_TENTATIVE_LINE_COLOR: Color = [136, 138, 143, 255];\n\n/**\n * Default edit handle color (white) - used by both draw and edit layers\n */\nexport const DEFAULT_EDIT_HANDLE_COLOR: Color = [255, 255, 255, 255];\n\n/**\n * Edit handle outline color (dark for contrast)\n */\nexport const DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color = [0, 0, 0, 200];\n\n/**\n * Empty feature collection for initializing editable layers\n */\nexport const EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection = {\n type: 'FeatureCollection',\n features: [],\n};\n\n/**\n * Custom character set for deck.gl TextLayer used by tooltip rendering.\n *\n * deck.gl's TextLayer uses SDF (Signed Distance Field) font rendering which\n * by default only supports basic ASCII characters (32-128). Special characters\n * like degree symbol (°) and superscript 2 (²) must be explicitly included\n * for tooltip text like \"100.5 km²\" to render correctly.\n */\nexport const TOOLTIP_CHARACTER_SET: string[] = ['°', '²'];\n\n// Add standard ASCII characters (space through tilde + DEL)\nfor (let i = 32; i <= 128; i++) {\n TOOLTIP_CHARACTER_SET.push(String.fromCharCode(i));\n}\n\n/**\n * Sublayer props for tooltip text rendering.\n * Used by both draw-shape-layer and edit-shape-layer for area/distance tooltips.\n */\nexport const TOOLTIP_SUBLAYER_PROPS = {\n tooltips: {\n ...DEFAULT_TEXT_STYLE,\n fontFamily: 'Roboto MonoVariable, monospace',\n characterSet: TOOLTIP_CHARACTER_SET,\n getTextAnchor: 'start',\n getAlignmentBaseline: 'bottom',\n getPixelOffset: [8, 0],\n },\n};\n\n/**\n * Shared edit handle sublayer props for EditableGeoJsonLayer.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDIT_HANDLE_SUBLAYER_PROPS = {\n editHandlePointOutline: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 6,\n },\n editHandlePoint: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 4,\n },\n};\n\n/**\n * Combined sublayer props for EditableGeoJsonLayer with tooltips and edit handles.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDITABLE_LAYER_SUBLAYER_PROPS = {\n ...TOOLTIP_SUBLAYER_PROPS,\n ...EDIT_HANDLE_SUBLAYER_PROPS,\n};\n\n/**\n * Format a distance value for tooltip display.\n * Used by draw and edit mode tooltips for consistent formatting.\n *\n * @param value - The distance value to format\n * @returns The formatted string with 2 decimal places\n */\nexport function formatDistance(value: number): string {\n return value.toFixed(2);\n}\n\n// =============================================================================\n// Tooltip Text Formatters\n// =============================================================================\n// These functions generate consistent tooltip text for both draw and edit modes.\n\n/**\n * Format circle tooltip text showing diameter and area.\n *\n * @param diameter - Circle diameter in the specified units\n * @param area - Circle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"d: {diameter} {unit}\\n{area} {unit}²\"\n */\nexport function formatCircleTooltip(\n diameter: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `d: ${formatDistance(diameter)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format rectangle tooltip text showing dimensions and area.\n *\n * @param width - Rectangle width in the specified units\n * @param height - Rectangle height in the specified units\n * @param area - Rectangle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{width} {unit} x {height} {unit}\\n{area} {unit}²\"\n */\nexport function formatRectangleTooltip(\n width: number,\n height: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(width)} ${unitAbbrev} x ${formatDistance(height)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format ellipse tooltip text showing axes and area.\n *\n * @param majorAxis - Ellipse major axis (full length) in the specified units\n * @param minorAxis - Ellipse minor axis (full length) in the specified units\n * @param area - Ellipse area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{major} {unit} x {minor} {unit}\\n{area} {unit}²\"\n */\nexport function formatEllipseTooltip(\n majorAxis: number,\n minorAxis: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(majorAxis)} ${unitAbbrev} x ${formatDistance(minorAxis)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format simple distance tooltip text.\n *\n * @param distance - Distance value in the specified units\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{distance} {unit}\"\n */\nexport function formatDistanceTooltip(\n distance: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(distance)} ${unitAbbrev}`;\n}\n\n// =============================================================================\n// Edit Event Type Classification\n// =============================================================================\n\n/**\n * Continuous edit event types that fire during dragging.\n * These are emitted repeatedly while the user drags during an edit operation.\n */\nexport const CONTINUOUS_EDIT_TYPES = new Set([\n 'movePosition',\n 'unionGeometry',\n 'scaling',\n 'rotating',\n 'translating',\n]);\n\n/**\n * Completion edit event types that fire when dragging ends.\n * These are emitted once when the user finishes an edit action.\n */\nexport const COMPLETION_EDIT_TYPES = new Set([\n 'finishMovePosition',\n 'addPosition',\n 'removePosition',\n 'scaled',\n 'rotated',\n 'translated',\n]);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB;CAC7B,SAAS;CACT,mBAAmB;CACnB,gBAAgB;CACjB;;;;;AAMD,MAAa,oBAAoB;;;;AAKjC,MAAa,qBAAqB;;;;AAKlC,MAAa,uBAAuB;;;;AAKpC,MAAa,2BAA2B;;;;;;;AAkBxC,MAAa,iBAAiB;CAE5B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,WAAW;EAAC;EAAI;EAAK;EAAK;EAAI;CAC/B;;;;;;;;AASD,MAAa,2BAA2B;CAEtC,MAAM;EAAC;EAAK;EAAK;EAAK;EAAG;CAEzB,MAAM,eAAe;CACtB;;;;;;;AAQD,MAAaA,2BAA4C;CACvD,WAAW,eAAe;CAC1B,WAAW,eAAe;CAC1B,WAAW;CACX,aAAa;CACd;;;;AAKD,MAAa,cAAc;CAAC;CAAG;CAAG;CAAG;CAAE;;;;AAKvC,MAAa,gBAAgB;CAAC;CAAS;CAAU;CAAS;;;;AAK1D,MAAaC,cAGT;CACF,OAAO;CACP,QAAQ,CAAC,GAAG,EAAE;CACd,QAAQ,CAAC,GAAG,EAAE;CACf;;;;AAkBD,MAAaC,4BAAmC;CAAC;CAAK;CAAK;CAAK;CAAI;;;;AAKpE,MAAaC,oCAA2C;CAAC;CAAG;CAAG;CAAG;CAAI;;;;AAKtE,MAAaC,2BAAgE;CAC3E,MAAM;CACN,UAAU,EAAE;CACb;;;;;;;;;AAUD,MAAaC,wBAAkC,CAAC,KAAK,IAAI;AAGzD,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IACzB,uBAAsB,KAAK,OAAO,aAAa,EAAE,CAAC;;;;;AAOpD,MAAa,yBAAyB,EACpC,UAAU;CACR,GAAG;CACH,YAAY;CACZ,cAAc;CACd,eAAe;CACf,sBAAsB;CACtB,gBAAgB,CAAC,GAAG,EAAE;CACvB,EACF;;;;;AAMD,MAAa,6BAA6B;CACxC,wBAAwB;EACtB,cAAc;EACd,WAAW;EACZ;CACD,iBAAiB;EACf,cAAc;EACd,WAAW;EACZ;CACF;;;;;AAMD,MAAa,gCAAgC;CAC3C,GAAG;CACH,GAAG;CACJ;;;;;;;;AASD,SAAgB,eAAe,OAAuB;AACpD,QAAO,MAAM,QAAQ,EAAE;;;;;;;;;;AAgBzB,SAAgB,oBACd,UACA,MACA,YACQ;AACR,QAAO,MAAM,eAAe,SAAS,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAY7F,SAAgB,uBACd,OACA,QACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,MAAM,CAAC,GAAG,WAAW,KAAK,eAAe,OAAO,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAYjI,SAAgB,qBACd,WACA,WACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,UAAU,CAAC,GAAG,WAAW,KAAK,eAAe,UAAU,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;AAUxI,SAAgB,sBACd,UACA,YACQ;AACR,QAAO,GAAG,eAAe,SAAS,CAAC,GAAG;;;;;;AAWxC,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;AAMF,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACA;CACD,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","names":["DEFAULT_STYLE_PROPERTIES: StyleProperties","DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n>","DEFAULT_EDIT_HANDLE_COLOR: Color","DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color","EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection","TOOLTIP_CHARACTER_SET: string[]"],"sources":["../../../../src/deckgl/shapes/shared/constants.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\n\nimport { DEFAULT_TEXT_STYLE } from '../../text-settings';\nimport type { Color } from '@deck.gl/core';\nimport type { StyleProperties } from './types';\n\n/**\n * Layer IDs for shape layers\n */\nexport const SHAPE_LAYER_IDS = {\n DISPLAY: 'DISPLAY_SHAPES',\n DISPLAY_HIGHLIGHT: 'DISPLAY_SHAPES::Highlight',\n DISPLAY_LABELS: 'DISPLAY_SHAPES::Labels',\n} as const;\n\n/**\n * Base fill opacity multiplier for standard semi-transparent look.\n * Multiplies alpha by 0.2 (reduces to 20% of original opacity).\n */\nexport const BASE_FILL_OPACITY = 0.2;\n\n/**\n * Default border/outline width in pixels when not specified in styleProperties\n */\nexport const DEFAULT_LINE_WIDTH = 2;\n\n/**\n * Additional pixels added to border/outline width on hover\n */\nexport const HOVER_WIDTH_INCREASE = 2;\n\n/**\n * Additional pixels added to border/outline width for selection highlight\n */\nexport const HIGHLIGHT_WIDTH_INCREASE = 5;\n\n/**\n * Fixed opacity for label background (0-255)\n */\nexport const LABEL_BACKGROUND_OPACITY = 200;\n\n/**\n * Fixed opacity for label border (0-255)\n */\nexport const LABEL_BORDER_OPACITY = 255;\n\n/**\n * Default colors as RGBA arrays for DeckGL layers.\n *\n * These are the canonical color values used throughout the shapes system.\n * All other color constants should derive from these to maintain consistency.\n */\nexport const DEFAULT_COLORS = {\n /** Default fill color (white at full alpha) */\n fill: [255, 255, 255, 255] as Color,\n /** Default border/outline color (outline-interactive-hover: #888a8f) */\n line: [136, 138, 143, 255] as Color,\n /** Highlight/selection color (turquoise at ~39% alpha) */\n highlight: [40, 245, 190, 100] as Color,\n} as const;\n\n/**\n * Tentative (during-drawing) colors.\n *\n * These colors are used for the shape preview while drawing.\n * Fill is semi-transparent (8% opacity) to not obscure underlying features.\n * Border/outline uses the same color as saved shapes for consistency.\n */\nexport const DEFAULT_TENTATIVE_COLORS = {\n /** Tentative fill color (white at 8% opacity: 0.08 * 255 ≈ 20) */\n fill: [255, 255, 255, 20] as Color,\n /** Tentative border/outline color (same as saved shapes for consistency) */\n line: DEFAULT_COLORS.line,\n} as const;\n\n/**\n * Default style properties for saved shapes.\n *\n * These are applied when a shape is completed/saved.\n * Can be overridden via styleDefaults in draw options.\n */\nexport const DEFAULT_STYLE_PROPERTIES: StyleProperties = {\n fillColor: DEFAULT_COLORS.fill,\n lineColor: DEFAULT_COLORS.line,\n lineWidth: 2,\n linePattern: 'solid',\n};\n\n/**\n * Border/outline width options (in pixels)\n */\nexport const LINE_WIDTHS = [1, 2, 4, 8] as const;\n\n/**\n * Border/outline pattern options\n */\nexport const LINE_PATTERNS = ['solid', 'dashed', 'dotted'] as const;\n\n/**\n * Dash array patterns for border/outline rendering\n */\nexport const DASH_ARRAYS: Record<\n 'solid' | 'dashed' | 'dotted',\n [number, number] | null\n> = {\n solid: null,\n dashed: [8, 4],\n dotted: [2, 4],\n};\n\n/**\n * Default tentative fill color (white at 8% opacity - rgba(255, 255, 255, 0.08))\n * Used when drawing new shapes before they're completed.\n * 0.08 * 255 ≈ 20\n */\nexport const DEFAULT_TENTATIVE_FILL_COLOR: Color = [255, 255, 255, 20];\n\n/**\n * Default tentative border/outline color (outline-interactive-hover: #888a8f)\n * Used when drawing new shapes before they're completed.\n */\nexport const DEFAULT_TENTATIVE_LINE_COLOR: Color = [136, 138, 143, 255];\n\n/**\n * Default edit handle color (white) - used by both draw and edit layers\n */\nexport const DEFAULT_EDIT_HANDLE_COLOR: Color = [255, 255, 255, 255];\n\n/**\n * Edit handle outline color (dark for contrast)\n */\nexport const DEFAULT_EDIT_HANDLE_OUTLINE_COLOR: Color = [0, 0, 0, 200];\n\n/**\n * Empty feature collection for initializing editable layers\n */\nexport const EMPTY_FEATURE_COLLECTION: import('geojson').FeatureCollection = {\n type: 'FeatureCollection',\n features: [],\n};\n\n/**\n * Custom character set for deck.gl TextLayer used by tooltip rendering.\n *\n * deck.gl's TextLayer uses SDF (Signed Distance Field) font rendering which\n * by default only supports basic ASCII characters (32-128). Special characters\n * like degree symbol (°) and superscript 2 (²) must be explicitly included\n * for tooltip text like \"100.5 km²\" to render correctly.\n */\nexport const TOOLTIP_CHARACTER_SET: string[] = ['°', '²'];\n\n// Add standard ASCII characters (space through tilde + DEL)\nfor (let i = 32; i <= 128; i++) {\n TOOLTIP_CHARACTER_SET.push(String.fromCharCode(i));\n}\n\n/**\n * Sublayer props for tooltip text rendering.\n * Used by both draw-shape-layer and edit-shape-layer for area/distance tooltips.\n */\nexport const TOOLTIP_SUBLAYER_PROPS = {\n tooltips: {\n ...DEFAULT_TEXT_STYLE,\n fontFamily: 'Roboto MonoVariable, monospace',\n characterSet: TOOLTIP_CHARACTER_SET,\n getTextAnchor: 'start',\n getAlignmentBaseline: 'bottom',\n getPixelOffset: [8, 0],\n },\n};\n\n/**\n * Shared edit handle sublayer props for EditableGeoJsonLayer.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDIT_HANDLE_SUBLAYER_PROPS = {\n editHandlePointOutline: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 6,\n },\n editHandlePoint: {\n getFillColor: DEFAULT_EDIT_HANDLE_COLOR,\n getRadius: 4,\n },\n};\n\n/**\n * Combined sublayer props for EditableGeoJsonLayer with tooltips and edit handles.\n * Used by both draw-shape-layer and edit-shape-layer.\n */\nexport const EDITABLE_LAYER_SUBLAYER_PROPS = {\n ...TOOLTIP_SUBLAYER_PROPS,\n ...EDIT_HANDLE_SUBLAYER_PROPS,\n};\n\n/**\n * Format a distance value for tooltip display.\n * Used by draw and edit mode tooltips for consistent formatting.\n *\n * @param value - The distance value to format\n * @returns The formatted string with 2 decimal places\n */\nexport function formatDistance(value: number): string {\n return value.toFixed(2);\n}\n\n// =============================================================================\n// Tooltip Text Formatters\n// =============================================================================\n// These functions generate consistent tooltip text for both draw and edit modes.\n\n/**\n * Format circle tooltip text showing radius and area.\n *\n * @param radius - Circle radius in the specified units\n * @param area - Circle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"r: {radius} {unit}\\n{area} {unit}²\"\n */\nexport function formatCircleTooltip(\n radius: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `r: ${formatDistance(radius)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format rectangle tooltip text showing dimensions and area.\n *\n * @param width - Rectangle width in the specified units\n * @param height - Rectangle height in the specified units\n * @param area - Rectangle area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{width} {unit} x {height} {unit}\\n{area} {unit}²\"\n */\nexport function formatRectangleTooltip(\n width: number,\n height: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(width)} ${unitAbbrev} x ${formatDistance(height)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format ellipse tooltip text showing axes and area.\n *\n * @param majorAxis - Ellipse major axis (full length) in the specified units\n * @param minorAxis - Ellipse minor axis (full length) in the specified units\n * @param area - Ellipse area in the specified units squared\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{major} {unit} x {minor} {unit}\\n{area} {unit}²\"\n */\nexport function formatEllipseTooltip(\n majorAxis: number,\n minorAxis: number,\n area: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(majorAxis)} ${unitAbbrev} x ${formatDistance(minorAxis)} ${unitAbbrev}\\n${formatDistance(area)} ${unitAbbrev}²`;\n}\n\n/**\n * Format simple distance tooltip text.\n *\n * @param distance - Distance value in the specified units\n * @param unitAbbrev - Unit abbreviation (e.g., 'km', 'mi')\n * @returns Formatted tooltip text: \"{distance} {unit}\"\n */\nexport function formatDistanceTooltip(\n distance: number,\n unitAbbrev: string,\n): string {\n return `${formatDistance(distance)} ${unitAbbrev}`;\n}\n\n// =============================================================================\n// Edit Event Type Classification\n// =============================================================================\n\n/**\n * Continuous edit event types that fire during dragging.\n * These are emitted repeatedly while the user drags during an edit operation.\n */\nexport const CONTINUOUS_EDIT_TYPES = new Set([\n 'movePosition',\n 'unionGeometry',\n 'scaling',\n 'rotating',\n 'translating',\n]);\n\n/**\n * Completion edit event types that fire when dragging ends.\n * These are emitted once when the user finishes an edit action.\n */\nexport const COMPLETION_EDIT_TYPES = new Set([\n 'finishMovePosition',\n 'addPosition',\n 'removePosition',\n 'scaled',\n 'rotated',\n 'translated',\n]);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB;CAC7B,SAAS;CACT,mBAAmB;CACnB,gBAAgB;CACjB;;;;;AAMD,MAAa,oBAAoB;;;;AAKjC,MAAa,qBAAqB;;;;AAKlC,MAAa,uBAAuB;;;;AAKpC,MAAa,2BAA2B;;;;;;;AAkBxC,MAAa,iBAAiB;CAE5B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,MAAM;EAAC;EAAK;EAAK;EAAK;EAAI;CAE1B,WAAW;EAAC;EAAI;EAAK;EAAK;EAAI;CAC/B;;;;;;;;AASD,MAAa,2BAA2B;CAEtC,MAAM;EAAC;EAAK;EAAK;EAAK;EAAG;CAEzB,MAAM,eAAe;CACtB;;;;;;;AAQD,MAAaA,2BAA4C;CACvD,WAAW,eAAe;CAC1B,WAAW,eAAe;CAC1B,WAAW;CACX,aAAa;CACd;;;;AAKD,MAAa,cAAc;CAAC;CAAG;CAAG;CAAG;CAAE;;;;AAKvC,MAAa,gBAAgB;CAAC;CAAS;CAAU;CAAS;;;;AAK1D,MAAaC,cAGT;CACF,OAAO;CACP,QAAQ,CAAC,GAAG,EAAE;CACd,QAAQ,CAAC,GAAG,EAAE;CACf;;;;AAkBD,MAAaC,4BAAmC;CAAC;CAAK;CAAK;CAAK;CAAI;;;;AAKpE,MAAaC,oCAA2C;CAAC;CAAG;CAAG;CAAG;CAAI;;;;AAKtE,MAAaC,2BAAgE;CAC3E,MAAM;CACN,UAAU,EAAE;CACb;;;;;;;;;AAUD,MAAaC,wBAAkC,CAAC,KAAK,IAAI;AAGzD,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IACzB,uBAAsB,KAAK,OAAO,aAAa,EAAE,CAAC;;;;;AAOpD,MAAa,yBAAyB,EACpC,UAAU;CACR,GAAG;CACH,YAAY;CACZ,cAAc;CACd,eAAe;CACf,sBAAsB;CACtB,gBAAgB,CAAC,GAAG,EAAE;CACvB,EACF;;;;;AAMD,MAAa,6BAA6B;CACxC,wBAAwB;EACtB,cAAc;EACd,WAAW;EACZ;CACD,iBAAiB;EACf,cAAc;EACd,WAAW;EACZ;CACF;;;;;AAMD,MAAa,gCAAgC;CAC3C,GAAG;CACH,GAAG;CACJ;;;;;;;;AASD,SAAgB,eAAe,OAAuB;AACpD,QAAO,MAAM,QAAQ,EAAE;;;;;;;;;;AAgBzB,SAAgB,oBACd,QACA,MACA,YACQ;AACR,QAAO,MAAM,eAAe,OAAO,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAY3F,SAAgB,uBACd,OACA,QACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,MAAM,CAAC,GAAG,WAAW,KAAK,eAAe,OAAO,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;;;AAYjI,SAAgB,qBACd,WACA,WACA,MACA,YACQ;AACR,QAAO,GAAG,eAAe,UAAU,CAAC,GAAG,WAAW,KAAK,eAAe,UAAU,CAAC,GAAG,WAAW,IAAI,eAAe,KAAK,CAAC,GAAG,WAAW;;;;;;;;;AAUxI,SAAgB,sBACd,UACA,YACQ;AACR,QAAO,GAAG,eAAe,SAAS,CAAC,GAAG;;;;;;AAWxC,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;AAMF,MAAa,wBAAwB,IAAI,IAAI;CAC3C;CACA;CACA;CACA;CACA;CACA;CACD,CAAC"}
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
'use client';
|
|
15
15
|
|
|
16
|
-
import { DEFAULT_EDIT_HANDLE_COLOR, EDITABLE_LAYER_SUBLAYER_PROPS } from "../constants.js";
|
|
17
16
|
import { DEFAULT_DISTANCE_UNITS, getDistanceUnitFromAbbreviation } from "../../../../shared/units.js";
|
|
17
|
+
import { DEFAULT_EDIT_HANDLE_COLOR, EDITABLE_LAYER_SUBLAYER_PROPS } from "../constants.js";
|
|
18
18
|
|
|
19
19
|
//#region src/deckgl/shapes/shared/utils/layer-config.ts
|
|
20
20
|
/**
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import { useEffect } from "react";
|
|
15
|
+
|
|
16
|
+
//#region ../hotkey-manager/dist/react/use-hotkey.js
|
|
17
|
+
/**
|
|
18
|
+
* A React hook that binds a HotkeyManager on mount and unbinds on unmount.
|
|
19
|
+
*
|
|
20
|
+
* @param manager - The hotkey manager to bind.
|
|
21
|
+
* @returns void
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* const myHotkey = registerHotkey({ key: { code: Keycode.KeyA }, onKeyUp: handler });
|
|
26
|
+
*
|
|
27
|
+
* function MyComponent() {
|
|
28
|
+
* useHotkey(myHotkey);
|
|
29
|
+
* return <div />;
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function useHotkey(manager) {
|
|
34
|
+
useEffect(() => manager.bind(), [manager]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { useHotkey };
|
|
39
|
+
//# sourceMappingURL=use-hotkey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-hotkey.js","names":[],"sources":["../../../../../hotkey-manager/dist/react/use-hotkey.js"],"sourcesContent":["/*\n * Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n\nimport { useEffect } from \"react\";\n\n//#region src/react/use-hotkey.ts\n/**\n* A React hook that binds a HotkeyManager on mount and unbinds on unmount.\n*\n* @param manager - The hotkey manager to bind.\n* @returns void\n*\n* @example\n* ```tsx\n* const myHotkey = registerHotkey({ key: { code: Keycode.KeyA }, onKeyUp: handler });\n*\n* function MyComponent() {\n* useHotkey(myHotkey);\n* return <div />;\n* }\n* ```\n*/\nfunction useHotkey(manager) {\n\tuseEffect(() => manager.bind(), [manager]);\n}\n/**\n* Creates a React hook from a HotkeyManager for module-level usage.\n* This is useful when you want to define the hotkey at module scope and use it as a hook.\n*\n* @param manager - The hotkey manager to wrap.\n* @returns A React hook that binds the hotkey on mount.\n*\n* @example\n* ```tsx\n* const myHotkey = registerHotkey({ key: { code: Keycode.KeyA }, onKeyUp: handler });\n* const useMyHotkey = createUseHotkey(myHotkey);\n*\n* function MyComponent() {\n* useMyHotkey();\n* return <div />;\n* }\n* ```\n*/\nfunction createUseHotkey(manager) {\n\treturn function useHotkeyHook() {\n\t\tuseEffect(() => manager.bind(), []);\n\t};\n}\n\n//#endregion\nexport { createUseHotkey, useHotkey };\n//# sourceMappingURL=use-hotkey.js.map"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAS,UAAU,SAAS;AAC3B,iBAAgB,QAAQ,MAAM,EAAE,CAAC,QAAQ,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { UniqueId } from "@accelint/core";
|
|
14
|
+
|
|
15
|
+
//#region src/shared/cleanup.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* Returns the current generation counter for a map instance.
|
|
18
|
+
*
|
|
19
|
+
* Use as a `key` prop on `<MapLibre>` to force a clean remount whenever the map's
|
|
20
|
+
* stores are cleared (e.g., on Activity deactivation).
|
|
21
|
+
*
|
|
22
|
+
* @param mapId - The map instance ID
|
|
23
|
+
* @returns The current generation (0 on first render, increments with each cleanup)
|
|
24
|
+
*/
|
|
25
|
+
declare function getMapGeneration(mapId: UniqueId): number;
|
|
26
|
+
/**
|
|
27
|
+
* Clears ALL map store state for a given map instance.
|
|
28
|
+
*
|
|
29
|
+
* This function calls cleanup for every store in the map-toolkit. It's called
|
|
30
|
+
* automatically by MapProvider when a map instance unmounts.
|
|
31
|
+
*
|
|
32
|
+
* **⚠️ IMPORTANT: When creating a new store with createMapStore():**
|
|
33
|
+
* 1. Export a `clear*State(mapId)` function from your store
|
|
34
|
+
* 2. Import and add it to this `clearAllMapStores()` function
|
|
35
|
+
* 3. The cleanup function should call your store's internal cleanup mechanism
|
|
36
|
+
*
|
|
37
|
+
* @param mapId - The map instance ID to clean up
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // In your store file (e.g., my-feature/store.ts)
|
|
42
|
+
* export function clearMyFeatureState(mapId: UniqueId): void {
|
|
43
|
+
* myFeatureStore.cleanup(mapId);
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* // Then add to this file:
|
|
47
|
+
* import { clearMyFeatureState } from '../my-feature/store';
|
|
48
|
+
*
|
|
49
|
+
* export function clearAllMapStores(mapId: UniqueId): void {
|
|
50
|
+
* // ... existing cleanups
|
|
51
|
+
* clearMyFeatureState(mapId);
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare function clearAllMapStores(mapId: UniqueId): void;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { clearAllMapStores, getMapGeneration };
|
|
58
|
+
//# sourceMappingURL=cleanup.d.ts.map
|