@sakuzu/maplibre-gl-draw 1.0.0 → 2.0.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 +1016 -2
- package/README.ja.md +39 -19
- package/README.md +41 -21
- package/dist/api/datasets.d.ts +258 -0
- package/dist/api/document.d.ts +66 -0
- package/dist/api/draw.d.ts +135 -0
- package/dist/api/draw.js +18 -0
- package/dist/api/drawing.d.ts +87 -0
- package/dist/api/errors.d.ts +35 -0
- package/dist/api/errors.js +35 -0
- package/dist/api/events.d.ts +306 -0
- package/dist/api/extension/context.d.ts +247 -0
- package/dist/api/extension/feature-type.d.ts +129 -0
- package/dist/api/extension/mode.d.ts +123 -0
- package/dist/api/extension/plugin.d.ts +51 -0
- package/dist/api/extension/plugin.js +3 -0
- package/dist/api/extension/provider.d.ts +119 -0
- package/dist/api/extension/provider.js +3 -0
- package/dist/api/extension/render.d.ts +176 -0
- package/dist/api/extension/render.js +3 -0
- package/dist/api/extension/store.d.ts +190 -0
- package/dist/api/extension/store.js +3 -0
- package/dist/api/extensions.d.ts +306 -0
- package/dist/api/extensions.js +3 -0
- package/dist/api/features.d.ts +188 -0
- package/dist/api/features.js +3 -0
- package/dist/api/groups.d.ts +111 -0
- package/dist/api/groups.js +3 -0
- package/dist/api/hidden.d.ts +45 -0
- package/dist/api/hidden.js +3 -0
- package/dist/api/impl/adapters.js +463 -0
- package/dist/api/impl/contexts.js +466 -0
- package/dist/api/impl/create-draw.js +124 -0
- package/dist/api/impl/datasets.js +404 -0
- package/dist/api/impl/destroy-guard.js +74 -0
- package/dist/api/impl/document.js +280 -0
- package/dist/api/impl/drawing.js +180 -0
- package/dist/api/impl/engine-context.d.ts +7 -0
- package/dist/api/{context.js → impl/engine-context.js} +49 -38
- package/dist/{maplibre-gl-draw.js → api/impl/engine.js} +145 -177
- package/dist/api/impl/events.js +422 -0
- package/dist/api/impl/extension-host.js +361 -0
- package/dist/api/impl/extensions.js +229 -0
- package/dist/api/impl/features.js +445 -0
- package/dist/api/impl/geometry/apply.d.ts +32 -0
- package/dist/api/{geometry → impl/geometry}/apply.js +10 -27
- package/dist/api/{geometry → impl/geometry}/buffer.d.ts +4 -3
- package/dist/api/{geometry → impl/geometry}/buffer.js +12 -23
- package/dist/api/{geometry → impl/geometry}/split.d.ts +4 -3
- package/dist/api/{geometry → impl/geometry}/split.js +10 -21
- package/dist/api/{geometry → impl/geometry}/targets.d.ts +2 -20
- package/dist/api/{geometry → impl/geometry}/targets.js +8 -35
- package/dist/api/impl/geometry/types.js +3 -0
- package/dist/api/impl/groups.d.ts +3 -0
- package/dist/api/impl/groups.js +268 -0
- package/dist/api/impl/hidden.js +60 -0
- package/dist/api/impl/import-export/constants.d.ts +22 -0
- package/dist/api/impl/import-export/constants.js +24 -0
- package/dist/api/{import-export → impl/import-export}/embedded-file.js +2 -2
- package/dist/api/{import-export → impl/import-export}/format-detection.d.ts +1 -1
- package/dist/api/{import-export → impl/import-export}/format-detection.js +2 -1
- package/dist/api/impl/import-export/geojson-export.d.ts +19 -0
- package/dist/api/{import-export → impl/import-export}/geojson-export.js +71 -104
- package/dist/api/{import-export → impl/import-export}/geojson-import.d.ts +11 -7
- package/dist/api/{import-export → impl/import-export}/geojson-import.js +139 -97
- package/dist/api/{import-export → impl/import-export}/geometry-validation.d.ts +14 -0
- package/dist/api/{import-export → impl/import-export}/geometry-validation.js +45 -0
- package/dist/api/impl/import-export/image-import.d.ts +16 -0
- package/dist/api/impl/import-export/image-import.js +73 -0
- package/dist/api/impl/import-export/legacy-image-style.d.ts +16 -0
- package/dist/api/impl/import-export/legacy-image-style.js +49 -0
- package/dist/api/impl/import-export/native-format.d.ts +14 -0
- package/dist/api/{import-export → impl/import-export}/native-format.js +32 -22
- package/dist/api/impl/import-export/native-upgrade.d.ts +8 -0
- package/dist/api/impl/import-export/native-upgrade.js +139 -0
- package/dist/api/{import-export → impl/import-export}/native-validation.d.ts +1 -1
- package/dist/api/{import-export → impl/import-export}/native-validation.js +15 -14
- package/dist/api/impl/import-export/style-validation.d.ts +24 -0
- package/dist/api/impl/import-export/style-validation.js +86 -0
- package/dist/api/impl/import-export/types.d.ts +52 -0
- package/dist/api/impl/import-export/types.js +3 -0
- package/dist/api/impl/input.js +180 -0
- package/dist/api/impl/layers.js +307 -0
- package/dist/api/impl/metadata.d.ts +1 -0
- package/dist/api/impl/metadata.js +22 -0
- package/dist/api/impl/options.d.ts +1 -0
- package/dist/api/impl/options.js +822 -0
- package/dist/api/impl/placement.d.ts +1 -0
- package/dist/api/impl/placement.js +138 -0
- package/dist/api/impl/render-context.d.ts +13 -0
- package/dist/api/impl/render-context.js +272 -0
- package/dist/api/impl/rows.d.ts +1 -0
- package/dist/api/impl/rows.js +46 -0
- package/dist/api/impl/selection.d.ts +1 -0
- package/dist/api/impl/selection.js +186 -0
- package/dist/api/impl/shared.d.ts +64 -0
- package/dist/api/impl/shared.js +178 -0
- package/dist/api/impl/validate-extension.d.ts +1 -0
- package/dist/api/impl/validate-extension.js +159 -0
- package/dist/api/layers.d.ts +130 -0
- package/dist/api/layers.js +3 -0
- package/dist/api/metadata.d.ts +18 -0
- package/dist/api/metadata.js +3 -0
- package/dist/api/model.d.ts +487 -0
- package/dist/api/model.js +47 -0
- package/dist/api/options.d.ts +466 -0
- package/dist/api/options.js +3 -0
- package/dist/api/selection.d.ts +94 -0
- package/dist/api/selection.js +3 -0
- package/dist/api/state.d.ts +155 -0
- package/dist/api/state.js +12 -0
- package/dist/{display → dataset}/chunk.d.ts +1 -1
- package/dist/{display → dataset}/chunk.js +4 -3
- package/dist/{display → dataset}/dataset.js +18 -21
- package/dist/dataset/interaction.d.ts +1 -0
- package/dist/{display → dataset}/interaction.js +18 -6
- package/dist/dataset/manager.d.ts +1 -0
- package/dist/dataset/provider.d.ts +1 -0
- package/dist/{display → dataset}/retained.d.ts +1 -1
- package/dist/{display → dataset}/retained.js +8 -7
- package/dist/dataset/source.d.ts +1 -0
- package/dist/{display → dataset}/source.js +17 -4
- package/dist/dataset/spatial.d.ts +1 -0
- package/dist/{display → dataset}/spatial.js +1 -1
- package/dist/dataset/style.d.ts +1 -0
- package/dist/{display → dataset}/style.js +1 -1
- package/dist/dataset/table-source.d.ts +1 -0
- package/dist/{display/columnar/source.js → dataset/table-source.js} +53 -25
- package/dist/{display → dataset}/thinning.d.ts +0 -10
- package/dist/{display → dataset}/thinning.js +3 -2
- package/dist/dataset/triangulation.d.ts +1 -0
- package/dist/{display → dataset}/triangulation.js +0 -0
- package/dist/{display → dataset}/types.d.ts +82 -121
- package/dist/dataset/types.js +61 -0
- package/dist/dispatcher/hit-test/box-strategies.js +13 -13
- package/dist/dispatcher/hit-test/box-strategy.d.ts +2 -15
- package/dist/dispatcher/hit-test/globe-shape.js +5 -4
- package/dist/dispatcher/hit-test/service.d.ts +17 -0
- package/dist/dispatcher/hit-test/service.js +80 -16
- package/dist/dispatcher/hit-test/strategies/base.d.ts +13 -19
- package/dist/dispatcher/hit-test/strategies/circle.js +3 -2
- package/dist/dispatcher/hit-test/strategies/image.js +6 -18
- package/dist/dispatcher/hit-test/strategies/line.d.ts +0 -6
- package/dist/dispatcher/hit-test/strategies/line.js +9 -2
- package/dist/dispatcher/hit-test/strategies/multi.d.ts +0 -8
- package/dist/dispatcher/hit-test/strategies/multi.js +17 -8
- package/dist/dispatcher/hit-test/strategies/point.d.ts +9 -7
- package/dist/dispatcher/hit-test/strategies/point.js +8 -4
- package/dist/dispatcher/hit-test/strategies/polygon.d.ts +0 -7
- package/dist/dispatcher/hit-test/strategies/polygon.js +11 -3
- package/dist/dispatcher/hit-test/topmost.d.ts +1 -1
- package/dist/dispatcher/input-router.js +152 -69
- package/dist/dispatcher/normalizer.js +6 -2
- package/dist/dispatcher/types.d.ts +6 -1
- package/dist/extension/feature-handler.d.ts +1 -182
- package/dist/extension/index.d.ts +4 -7
- package/dist/extension/renderers.d.ts +1 -208
- package/dist/geometry/angle.d.ts +0 -8
- package/dist/geometry/angle.js +0 -8
- package/dist/geometry/bbox.d.ts +4 -12
- package/dist/geometry/bbox.js +4 -12
- package/dist/geometry/boolean.d.ts +0 -51
- package/dist/geometry/boolean.js +0 -51
- package/dist/geometry/buffer.d.ts +0 -26
- package/dist/geometry/buffer.js +0 -26
- package/dist/geometry/circle.d.ts +0 -9
- package/dist/geometry/circle.js +0 -9
- package/dist/geometry/coords.d.ts +0 -16
- package/dist/geometry/coords.js +0 -16
- package/dist/geometry/distance.d.ts +0 -24
- package/dist/geometry/distance.js +0 -24
- package/dist/geometry/errors.d.ts +21 -36
- package/dist/geometry/errors.js +49 -29
- package/dist/geometry/geojson.d.ts +81 -0
- package/dist/geometry/geojson.js +164 -0
- package/dist/geometry/index.d.ts +38 -23
- package/dist/geometry/index.js +43 -31
- package/dist/geometry/measure.d.ts +0 -27
- package/dist/geometry/measure.js +0 -27
- package/dist/geometry/predicates.d.ts +0 -9
- package/dist/geometry/predicates.js +0 -9
- package/dist/geometry/public-bounds.d.ts +26 -0
- package/dist/geometry/public-bounds.js +30 -0
- package/dist/geometry/public-combine.d.ts +78 -0
- package/dist/geometry/public-combine.js +82 -0
- package/dist/geometry/public-create.d.ts +54 -0
- package/dist/geometry/public-create.js +70 -0
- package/dist/geometry/public-measure.d.ts +170 -0
- package/dist/geometry/public-measure.js +283 -0
- package/dist/geometry/public-predicates.d.ts +54 -0
- package/dist/geometry/public-predicates.js +144 -0
- package/dist/geometry/public-repair.d.ts +75 -0
- package/dist/geometry/public-repair.js +77 -0
- package/dist/geometry/simplify.d.ts +0 -7
- package/dist/geometry/simplify.js +0 -7
- package/dist/geometry/split.d.ts +0 -20
- package/dist/geometry/split.js +0 -20
- package/dist/geometry/units.d.ts +20 -12
- package/dist/geometry/units.js +20 -12
- package/dist/index.d.ts +52 -66
- package/dist/index.js +6 -18
- package/dist/messages.d.ts +7 -7
- package/dist/modes/draw/circle.js +83 -207
- package/dist/modes/draw/commit-layer.d.ts +5 -16
- package/dist/modes/draw/commit-layer.js +2 -13
- package/dist/modes/draw/freehand.js +108 -246
- package/dist/modes/draw/image.js +4 -2
- package/dist/modes/draw/index.d.ts +5 -5
- package/dist/modes/draw/index.js +5 -5
- package/dist/modes/draw/line.js +18 -354
- package/dist/modes/draw/point.js +29 -78
- package/dist/modes/draw/polygon.js +23 -368
- package/dist/modes/draw/trace-support.d.ts +43 -36
- package/dist/modes/draw/trace-support.js +95 -98
- package/dist/modes/draw/vertex-drawing.d.ts +1 -0
- package/dist/modes/draw/vertex-drawing.js +176 -0
- package/dist/modes/handler.d.ts +1 -285
- package/dist/modes/manager.d.ts +2 -2
- package/dist/modes/manager.js +3 -0
- package/dist/modes/select/box-selection.d.ts +3 -3
- package/dist/modes/select/box-selection.js +2 -1
- package/dist/modes/select/click-handler.d.ts +5 -5
- package/dist/modes/select/click-handler.js +22 -20
- package/dist/modes/select/cursor-handler.d.ts +2 -2
- package/dist/modes/select/drag/intermediate-writes.js +1 -1
- package/dist/modes/select/drag/move.js +3 -3
- package/dist/modes/select/drag/operation.d.ts +3 -3
- package/dist/modes/select/drag/radius.js +5 -4
- package/dist/modes/select/drag/transform.d.ts +2 -2
- package/dist/modes/select/drag/transform.js +11 -5
- package/dist/modes/select/drag/vertex.d.ts +2 -2
- package/dist/modes/select/drag/vertex.js +13 -8
- package/dist/modes/select/drag-handler.js +44 -25
- package/dist/modes/select/mode.js +17 -17
- package/dist/modes/select/shortcut-handler.d.ts +8 -8
- package/dist/modes/select/shortcut-handler.js +9 -7
- package/dist/operations/layer-operations.js +29 -168
- package/dist/operations/resize.d.ts +2 -2
- package/dist/operations/resize.js +5 -5
- package/dist/operations/rotate.js +5 -5
- package/dist/operations/selection-operations.d.ts +16 -1
- package/dist/operations/selection-operations.js +28 -13
- package/dist/operations/shared-vertex.js +4 -2
- package/dist/operations/trace-graph.d.ts +0 -18
- package/dist/operations/trace-graph.js +0 -18
- package/dist/operations/vertex.js +36 -35
- package/dist/shared/color.d.ts +1 -0
- package/dist/shared/color.js +245 -0
- package/dist/shared/config/constants.d.ts +1 -54
- package/dist/shared/config/constants.js +1 -58
- package/dist/shared/config/feature-style.d.ts +16 -13
- package/dist/shared/config/feature-style.js +9 -0
- package/dist/shared/config/rendering.d.ts +3 -3
- package/dist/shared/config/selection-highlight.d.ts +0 -15
- package/dist/shared/config/selection-highlight.js +4 -7
- package/dist/shared/config/selection.d.ts +2 -32
- package/dist/shared/config/selection.js +0 -18
- package/dist/shared/config/topology.d.ts +2 -2
- package/dist/shared/config/trace.d.ts +4 -4
- package/dist/shared/math/angle.d.ts +1 -1
- package/dist/shared/math/angle.js +1 -1
- package/dist/shared/math/circle.d.ts +1 -1
- package/dist/shared/math/circle.js +1 -1
- package/dist/shared/math/distance.d.ts +2 -1
- package/dist/shared/math/distance.js +3 -2
- package/dist/shared/math/index.d.ts +1 -1
- package/dist/shared/math/index.js +1 -1
- package/dist/shared/math/transform.d.ts +23 -0
- package/dist/shared/math/transform.js +47 -28
- package/dist/shared/properties.d.ts +18 -0
- package/dist/shared/properties.js +129 -0
- package/dist/shared/types/events.d.ts +15 -7
- package/dist/shared/types/model.d.ts +109 -159
- package/dist/shared/types/style.d.ts +1 -1
- package/dist/shared/utils/color.d.ts +2 -36
- package/dist/shared/utils/color.js +13 -70
- package/dist/shared/utils/coordinates.d.ts +30 -4
- package/dist/shared/utils/coordinates.js +56 -10
- package/dist/shared/utils/event-emitter.d.ts +1 -262
- package/dist/shared/utils/event-emitter.js +4 -3
- package/dist/shared/utils/feature-bbox.js +8 -7
- package/dist/shared/utils/feature-segments.js +5 -4
- package/dist/shared/utils/image.d.ts +0 -4
- package/dist/shared/utils/image.js +0 -6
- package/dist/shared/utils/name-generator.d.ts +14 -20
- package/dist/shared/utils/name-generator.js +20 -3
- package/dist/shared/utils/pixel-ratio.d.ts +9 -3
- package/dist/shared/utils/pixel-ratio.js +13 -4
- package/dist/shared/utils/property.d.ts +7 -50
- package/dist/shared/utils/property.js +22 -87
- package/dist/snapping/custom-targets.js +21 -4
- package/dist/snapping/indicator.js +20 -11
- package/dist/snapping/providers/display.d.ts +6 -1
- package/dist/snapping/providers/display.js +2 -1
- package/dist/snapping/providers/guide.d.ts +3 -43
- package/dist/snapping/providers/guide.js +1 -44
- package/dist/snapping/providers/intersection.js +1 -1
- package/dist/snapping/providers/store.js +3 -3
- package/dist/snapping/service.js +18 -7
- package/dist/snapping/types.d.ts +9 -35
- package/dist/store/draw-store.js +233 -142
- package/dist/store/local-visibility.d.ts +11 -6
- package/dist/store/local-visibility.js +38 -7
- package/dist/store/lock.d.ts +0 -6
- package/dist/store/lock.js +0 -6
- package/dist/store/memory/change-bus.d.ts +3 -3
- package/dist/store/memory/change-bus.js +12 -0
- package/dist/store/memory/file-store.d.ts +2 -2
- package/dist/store/memory/ui-state.d.ts +1 -51
- package/dist/store/memory/ui-state.js +122 -134
- package/dist/store/memory.d.ts +1 -8
- package/dist/store/memory.js +249 -45
- package/dist/store/ordering.d.ts +9 -0
- package/dist/store/ordering.js +17 -0
- package/dist/store/spatial/spatial-index.d.ts +1 -1
- package/dist/store/spatial/spatial-index.js +1 -1
- package/dist/store/spatial/store-spatial-index.d.ts +3 -1
- package/dist/store/spatial/store-spatial-index.js +9 -3
- package/dist/store/store.d.ts +66 -107
- package/dist/store/types.d.ts +1 -1
- package/dist/store/writable-layer.d.ts +1 -1
- package/dist/store/writable-layer.js +2 -2
- package/dist/table/builder.d.ts +83 -0
- package/dist/table/builder.js +381 -0
- package/dist/table/index.d.ts +37 -0
- package/dist/table/index.js +5 -0
- package/dist/table/packed-rtree.d.ts +1 -0
- package/dist/{display → table}/packed-rtree.js +1 -1
- package/dist/table/partition.d.ts +1 -0
- package/dist/{display → table}/partition.js +3 -3
- package/dist/table/prepare.d.ts +44 -0
- package/dist/table/prepare.js +136 -0
- package/dist/table/table.d.ts +1 -0
- package/dist/{display/columnar → table}/table.js +29 -25
- package/dist/{display/columnar → table}/types.d.ts +68 -72
- package/dist/table/types.js +3 -0
- package/dist/view/coordinator.js +4 -3
- package/dist/view/feature-companion.d.ts +13 -7
- package/dist/view/feature-companion.js +11 -3
- package/dist/view/globe-subdivision.js +3 -3
- package/dist/view/layer/attach.d.ts +1 -1
- package/dist/view/layer/attach.js +1 -1
- package/dist/view/layer/custom-layer.js +40 -11
- package/dist/view/layer/display-list.js +2 -1
- package/dist/view/layer/drape-planner.d.ts +2 -2
- package/dist/view/layer/frame-render.d.ts +3 -3
- package/dist/view/layer/frame-render.js +7 -2
- package/dist/view/layer/frame-state.d.ts +6 -6
- package/dist/view/layer/index.d.ts +2 -2
- package/dist/view/layer/index.js +1 -1
- package/dist/view/layer/render.d.ts +4 -4
- package/dist/view/layer/render.js +3 -8
- package/dist/view/layer/renderers.d.ts +2 -2
- package/dist/view/layer/renderers.js +1 -1
- package/dist/view/layer/slot-manager.d.ts +2 -2
- package/dist/view/layer/slot-manager.js +4 -4
- package/dist/view/layer/slots.d.ts +2 -2
- package/dist/view/layer/slots.js +1 -1
- package/dist/view/layer/store-retained-bbox.js +3 -2
- package/dist/view/layer/store-retained-classify.d.ts +5 -7
- package/dist/view/layer/store-retained-classify.js +19 -7
- package/dist/view/layer/store-retained-collect.js +8 -7
- package/dist/view/layer/store-retained-coord-patch.d.ts +0 -8
- package/dist/view/layer/store-retained-coord-patch.js +13 -4
- package/dist/view/layer/store-retained-immediate.d.ts +3 -3
- package/dist/view/layer/store-retained-immediate.js +3 -8
- package/dist/view/layer/store-retained-invalidation.d.ts +2 -2
- package/dist/view/layer/store-retained.d.ts +2 -2
- package/dist/view/layer/store-retained.js +1 -1
- package/dist/view/renderers/batch-manager.js +8 -7
- package/dist/view/renderers/drawer.js +21 -15
- package/dist/view/renderers/image.js +13 -39
- package/dist/view/renderers/line/line-types.d.ts +3 -3
- package/dist/view/renderers/line/sdf-line.js +3 -1
- package/dist/view/renderers/point/billboard-depth.js +1 -1
- package/dist/view/renderers/point/point-instance.js +1 -1
- package/dist/view/renderers/point/point-shape.js +2 -2
- package/dist/view/renderers/point/point-style.js +48 -4
- package/dist/view/renderers/polygon/batch.js +1 -2
- package/dist/view/renderers/polygon/fill.js +3 -1
- package/dist/view/renderers/polygon/sdf-polygon.js +2 -3
- package/dist/view/renderers/polygon/triangulator.d.ts +1 -1
- package/dist/view/renderers/stroke.js +3 -1
- package/dist/view/shaders/helpers.d.ts +2 -42
- package/dist/view/shaders/helpers.js +0 -6
- package/dist/view/shaders/projection.d.ts +15 -7
- package/dist/view/shaders/projection.js +23 -6
- package/dist/view/shaders/quad.d.ts +16 -12
- package/dist/view/shaders/quad.js +34 -13
- package/dist/view/style-rule.d.ts +5 -42
- package/dist/view/style-rule.js +20 -44
- package/dist/view/terrain/binding.d.ts +1 -0
- package/dist/view/terrain/binding.js +29 -0
- package/dist/view/terrain/context.d.ts +3 -4
- package/dist/view/terrain/context.js +4 -5
- package/dist/view/terrain/drape/geometry.js +1 -1
- package/dist/view/terrain/drape/pass.d.ts +1 -1
- package/dist/view/terrain/drape/pass.js +8 -7
- package/dist/view/terrain/polygon.d.ts +9 -5
- package/dist/view/terrain/polygon.js +16 -2
- package/dist/view/terrain/state.d.ts +1 -1
- package/dist/view/terrain/state.js +1 -1
- package/dist/view/terrain/tessellation.d.ts +2 -2
- package/dist/view/terrain/tessellation.js +1 -1
- package/dist/view/ui/auxiliary-handles.d.ts +6 -29
- package/dist/view/ui/bounds.js +8 -12
- package/dist/view/ui/handle-test.js +2 -2
- package/dist/view/ui/handle-thinning.js +17 -17
- package/dist/view/ui/handles.js +21 -13
- package/dist/view/ui/helper.d.ts +1 -1
- package/dist/view/ui/helper.js +1 -1
- package/dist/view/ui/index.d.ts +1 -1
- package/dist/view/ui/selection-scope.js +4 -2
- package/dist/view/ui/selection-ui/bounding-box.js +6 -6
- package/dist/view/ui/selection-ui/extension-registry.d.ts +31 -20
- package/dist/view/ui/selection-ui/extension-registry.js +70 -7
- package/dist/view/ui/selection-ui/index.d.ts +2 -2
- package/dist/view/ui/selection-ui/index.js +1 -1
- package/dist/view/ui/selection-ui/renderer.js +15 -38
- package/dist/view/ui/selection-ui/types.d.ts +17 -2
- package/dist/view/ui/selection-ui-drawer.d.ts +8 -0
- package/dist/view/ui/selection-ui-drawer.js +63 -2
- package/dist/view/ui/tentative.js +1 -1
- package/dist/webgl/index.d.ts +65 -0
- package/dist/webgl/index.js +62 -0
- package/package.json +20 -9
- package/dist/api/api.d.ts +0 -1259
- package/dist/api/api.js +0 -86
- package/dist/api/context.d.ts +0 -173
- package/dist/api/display-api.js +0 -23
- package/dist/api/event-api.d.ts +0 -13
- package/dist/api/event-api.js +0 -17
- package/dist/api/extension-api.d.ts +0 -46
- package/dist/api/extension-api.js +0 -85
- package/dist/api/feature-api.d.ts +0 -11
- package/dist/api/feature-api.js +0 -101
- package/dist/api/geometry/apply.d.ts +0 -51
- package/dist/api/geometry/boolean.d.ts +0 -28
- package/dist/api/geometry/boolean.js +0 -65
- package/dist/api/geometry/types.d.ts +0 -31
- package/dist/api/geometry-operations.d.ts +0 -162
- package/dist/api/geometry-operations.js +0 -94
- package/dist/api/group-api.d.ts +0 -10
- package/dist/api/group-api.js +0 -78
- package/dist/api/import-export/constants.d.ts +0 -29
- package/dist/api/import-export/constants.js +0 -40
- package/dist/api/import-export/file-name.d.ts +0 -10
- package/dist/api/import-export/file-name.js +0 -20
- package/dist/api/import-export/geojson-export.d.ts +0 -19
- package/dist/api/import-export/image-import.d.ts +0 -12
- package/dist/api/import-export/image-import.js +0 -53
- package/dist/api/import-export/index.d.ts +0 -9
- package/dist/api/import-export/index.js +0 -107
- package/dist/api/import-export/native-format.d.ts +0 -15
- package/dist/api/import-export/style-validation.d.ts +0 -27
- package/dist/api/import-export/style-validation.js +0 -49
- package/dist/api/import-export/types.d.ts +0 -26
- package/dist/api/index.d.ts +0 -15
- package/dist/api/index.js +0 -3
- package/dist/api/input-api.d.ts +0 -158
- package/dist/api/input-api.js +0 -144
- package/dist/api/instance-api.d.ts +0 -38
- package/dist/api/instance-api.js +0 -136
- package/dist/api/layer-api.d.ts +0 -12
- package/dist/api/layer-api.js +0 -62
- package/dist/api/selection-api.d.ts +0 -7
- package/dist/api/selection-api.js +0 -78
- package/dist/api/snapping-api.d.ts +0 -125
- package/dist/api/snapping-api.js +0 -50
- package/dist/api/topology-api.d.ts +0 -30
- package/dist/api/topology-api.js +0 -16
- package/dist/api/tracing-api.d.ts +0 -31
- package/dist/api/tracing-api.js +0 -16
- package/dist/dispatcher/hit-test/index.d.ts +0 -14
- package/dist/dispatcher/hit-test/index.js +0 -9
- package/dist/dispatcher/index.d.ts +0 -15
- package/dist/dispatcher/index.js +0 -3
- package/dist/display/columnar/index.d.ts +0 -12
- package/dist/display/columnar/index.js +0 -13
- package/dist/display/columnar/prepare.d.ts +0 -42
- package/dist/display/columnar/prepare.js +0 -116
- package/dist/display/index.d.ts +0 -13
- package/dist/display/types.js +0 -43
- package/dist/maplibre-gl-draw.d.ts +0 -47
- package/dist/modes/cursor.js +0 -72
- package/dist/modes/index.d.ts +0 -7
- package/dist/operations/index.d.ts +0 -9
- package/dist/operations/index.js +0 -3
- package/dist/plugins/index.d.ts +0 -10
- package/dist/plugins/mutation-hooks.d.ts +0 -28
- package/dist/plugins/mutation-hooks.js +0 -84
- package/dist/plugins/plugin-context.js +0 -367
- package/dist/plugins/plugin-manager.d.ts +0 -103
- package/dist/plugins/plugin-manager.js +0 -316
- package/dist/plugins/plugin.d.ts +0 -529
- package/dist/shared/config/index.d.ts +0 -17
- package/dist/shared/config/index.js +0 -8
- package/dist/shared/utils/index.d.ts +0 -15
- package/dist/shared/utils/index.js +0 -24
- package/dist/snapping/index.d.ts +0 -14
- package/dist/snapping/index.js +0 -4
- package/dist/store/change-merger.js +0 -102
- package/dist/store/event-bridge.js +0 -161
- package/dist/store/index.d.ts +0 -12
- package/dist/store/index.js +0 -4
- package/dist/view/index.d.ts +0 -47
- package/dist/view/index.js +0 -20
- /package/dist/api/{geometry/types.js → datasets.js} +0 -0
- /package/dist/api/{import-export/types.js → document.js} +0 -0
- /package/dist/{display/columnar/types.js → api/drawing.js} +0 -0
- /package/dist/{display/index.js → api/events.js} +0 -0
- /package/dist/{modes/index.js → api/extension/context.js} +0 -0
- /package/dist/{plugins/index.js → api/extension/feature-type.js} +0 -0
- /package/dist/{plugins/plugin.js → api/extension/mode.js} +0 -0
- /package/dist/api/{display-api.d.ts → impl/adapters.d.ts} +0 -0
- /package/dist/{display/columnar/source.d.ts → api/impl/contexts.d.ts} +0 -0
- /package/dist/{display/columnar/table.d.ts → api/impl/create-draw.d.ts} +0 -0
- /package/dist/{display/interaction.d.ts → api/impl/datasets.d.ts} +0 -0
- /package/dist/{display/manager.d.ts → api/impl/destroy-guard.d.ts} +0 -0
- /package/dist/{display/packed-rtree.d.ts → api/impl/document.d.ts} +0 -0
- /package/dist/{display/partition.d.ts → api/impl/drawing.d.ts} +0 -0
- /package/dist/{display/provider.d.ts → api/impl/engine.d.ts} +0 -0
- /package/dist/{display/source.d.ts → api/impl/events.d.ts} +0 -0
- /package/dist/{display/spatial.d.ts → api/impl/extension-host.d.ts} +0 -0
- /package/dist/{display/style.d.ts → api/impl/extensions.d.ts} +0 -0
- /package/dist/{display/triangulation.d.ts → api/impl/features.d.ts} +0 -0
- /package/dist/{modes/cursor.d.ts → api/impl/geometry/types.d.ts} +0 -0
- /package/dist/{plugins/plugin-context.d.ts → api/impl/hidden.d.ts} +0 -0
- /package/dist/api/{import-export → impl/import-export}/embedded-file.d.ts +0 -0
- /package/dist/api/{import-export → impl/import-export}/own-property.d.ts +0 -0
- /package/dist/api/{import-export → impl/import-export}/own-property.js +0 -0
- /package/dist/{store/change-merger.d.ts → api/impl/input.d.ts} +0 -0
- /package/dist/{store/event-bridge.d.ts → api/impl/layers.d.ts} +0 -0
- /package/dist/{display → dataset}/chunk-set.d.ts +0 -0
- /package/dist/{display → dataset}/chunk-set.js +0 -0
- /package/dist/{display → dataset}/dataset.d.ts +0 -0
- /package/dist/{display → dataset}/manager.js +0 -0
- /package/dist/{display → dataset}/provider.js +0 -0
- /package/dist/{display → dataset}/selection.d.ts +0 -0
- /package/dist/{display → dataset}/selection.js +0 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* `draw.features`: the features of the document
|
|
5
|
+
*/
|
|
6
|
+
import { differenceAll, intersectionAll, unionAll } from '../../geometry/boolean.js';
|
|
7
|
+
import { getBoundingBox } from '../../shared/utils/feature-bbox.js';
|
|
8
|
+
import { isFeatureLocked } from '../../store/lock.js';
|
|
9
|
+
import { listEveryFeatureInOrder } from '../../store/ordering.js';
|
|
10
|
+
import { getStyleRuleChannel, resolveFeatureStyle } from '../../view/style-rule.js';
|
|
11
|
+
import { DrawError } from '../errors.js';
|
|
12
|
+
import { applyResult } from './geometry/apply.js';
|
|
13
|
+
import { runBuffer } from './geometry/buffer.js';
|
|
14
|
+
import { runSplit } from './geometry/split.js';
|
|
15
|
+
import { isAreaFeature, isBufferableFeature, isSplitLineFeature, toAreaCoordinates, toResultGeometry, } from './geometry/targets.js';
|
|
16
|
+
import { describeGeometryProblem } from './import-export/geometry-validation.js';
|
|
17
|
+
import { setOwnProperty } from './import-export/own-property.js';
|
|
18
|
+
import { describeStyleProblem } from './import-export/style-validation.js';
|
|
19
|
+
import { toAppliedDefaults } from './options.js';
|
|
20
|
+
import { moveFeatures, resolveMoveTarget } from './placement.js';
|
|
21
|
+
import { featureLocked, filterEntries, invalidInput, isRecord, isTaken, matches, notFound, onlyKeys, onlyLockOrVisibility, optionalBoolean, requireId, requireIds, requireRecord, } from './shared.js';
|
|
22
|
+
const INPUT_KEYS = [
|
|
23
|
+
'type',
|
|
24
|
+
'geometry',
|
|
25
|
+
'id',
|
|
26
|
+
'layerId',
|
|
27
|
+
'groupId',
|
|
28
|
+
'properties',
|
|
29
|
+
'style',
|
|
30
|
+
'visible',
|
|
31
|
+
'locked',
|
|
32
|
+
];
|
|
33
|
+
const PATCH_KEYS = ['geometry', 'properties', 'style', 'visible', 'locked'];
|
|
34
|
+
const FILTER_KEYS = ['layerId', 'groupId', 'type', 'visible', 'shown', 'locked', 'bbox'];
|
|
35
|
+
/**
|
|
36
|
+
* Creates `draw.features`
|
|
37
|
+
*
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
export function createFeatures(deps) {
|
|
41
|
+
const { store } = deps;
|
|
42
|
+
const geometryDeps = {
|
|
43
|
+
store,
|
|
44
|
+
generateFeatureId: deps.generateId,
|
|
45
|
+
};
|
|
46
|
+
const require = (id) => {
|
|
47
|
+
const feature = typeof id === 'string' ? store.getFeature(id) : undefined;
|
|
48
|
+
if (!feature)
|
|
49
|
+
throw notFound('feature', id);
|
|
50
|
+
return feature;
|
|
51
|
+
};
|
|
52
|
+
const requireAll = (ids) => requireIds(ids).map(require);
|
|
53
|
+
/** The features in stacking order, from the back */
|
|
54
|
+
const inStackingOrder = (features) => {
|
|
55
|
+
const position = new Map(listEveryFeatureInOrder(store).map((f, index) => [f.id, index]));
|
|
56
|
+
return [...features].sort((a, b) => (position.get(a.id) ?? 0) - (position.get(b.id) ?? 0));
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The checks of a filter: the entries compared as they are, and the IDs within the extent
|
|
60
|
+
* when the filter has one
|
|
61
|
+
*/
|
|
62
|
+
const filterOf = (filter) => {
|
|
63
|
+
const all = filterEntries(filter, FILTER_KEYS);
|
|
64
|
+
const shown = all.find(([key]) => key === 'shown')?.[1];
|
|
65
|
+
if (shown !== undefined && typeof shown !== 'boolean') {
|
|
66
|
+
throw invalidInput('shown must be a boolean');
|
|
67
|
+
}
|
|
68
|
+
const entries = all.filter(([key]) => key !== 'shown');
|
|
69
|
+
const bbox = entries.find(([key]) => key === 'bbox')?.[1];
|
|
70
|
+
if (bbox === undefined)
|
|
71
|
+
return { entries, inside: null, shown };
|
|
72
|
+
if (!Array.isArray(bbox) ||
|
|
73
|
+
bbox.length !== 4 ||
|
|
74
|
+
bbox.some((value) => typeof value !== 'number' || !Number.isFinite(value))) {
|
|
75
|
+
throw invalidInput('bbox must be [west, south, east, north] in degrees');
|
|
76
|
+
}
|
|
77
|
+
const [minX, minY, maxX, maxY] = bbox;
|
|
78
|
+
const bounds = { minX, minY, maxX, maxY };
|
|
79
|
+
const inside = new Set(deps.spatialIndex
|
|
80
|
+
? deps.spatialIndex.findInBounds(bounds)
|
|
81
|
+
: store
|
|
82
|
+
.listFeatures()
|
|
83
|
+
.filter((feature) => {
|
|
84
|
+
const box = getBoundingBox(feature);
|
|
85
|
+
return box.minX <= maxX && box.maxX >= minX && box.minY <= maxY && box.maxY >= minY;
|
|
86
|
+
})
|
|
87
|
+
.map((feature) => feature.id));
|
|
88
|
+
return { entries: entries.filter(([key]) => key !== 'bbox'), inside, shown };
|
|
89
|
+
};
|
|
90
|
+
/** Whether the feature, its group and its layer are all visible in the document */
|
|
91
|
+
const isShown = (feature) => feature.visible &&
|
|
92
|
+
(feature.groupId === undefined || store.getGroup(feature.groupId)?.visible !== false) &&
|
|
93
|
+
store.getLayer(feature.layerId)?.visible !== false;
|
|
94
|
+
const keep = (feature, { entries, inside, shown }) => (inside === null || inside.has(feature.id)) &&
|
|
95
|
+
(shown === undefined || isShown(feature) === shown) &&
|
|
96
|
+
matches(feature, entries);
|
|
97
|
+
const list = (filter) => {
|
|
98
|
+
const checks = filterOf(filter);
|
|
99
|
+
return listEveryFeatureInOrder(store).filter((feature) => keep(feature, checks));
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
get: (id) => store.getFeature(id),
|
|
103
|
+
getMany(ids) {
|
|
104
|
+
if (!Array.isArray(ids))
|
|
105
|
+
throw invalidInput('The IDs must be an array');
|
|
106
|
+
return ids.map((id) => store.getFeature(id));
|
|
107
|
+
},
|
|
108
|
+
list,
|
|
109
|
+
count(filter) {
|
|
110
|
+
const checks = filterOf(filter);
|
|
111
|
+
if (checks.entries.length === 0 && checks.inside === null && checks.shown === undefined) {
|
|
112
|
+
return store.listFeatures().length;
|
|
113
|
+
}
|
|
114
|
+
return store.listFeatures().filter((feature) => keep(feature, checks)).length;
|
|
115
|
+
},
|
|
116
|
+
has: (id) => store.getFeature(id) !== undefined,
|
|
117
|
+
create(input) {
|
|
118
|
+
const feature = prepareFeature(deps, input, new Set());
|
|
119
|
+
if (store.isReadOnly())
|
|
120
|
+
return null;
|
|
121
|
+
store.createFeature(feature);
|
|
122
|
+
return store.getFeature(feature.id) ?? null;
|
|
123
|
+
},
|
|
124
|
+
createMany(inputs) {
|
|
125
|
+
if (!Array.isArray(inputs))
|
|
126
|
+
throw invalidInput('The inputs must be an array');
|
|
127
|
+
const pending = new Set();
|
|
128
|
+
const features = inputs.map((input) => {
|
|
129
|
+
const feature = prepareFeature(deps, input, pending);
|
|
130
|
+
pending.add(feature.id);
|
|
131
|
+
return feature;
|
|
132
|
+
});
|
|
133
|
+
if (store.isReadOnly())
|
|
134
|
+
return null;
|
|
135
|
+
store.transact(() => {
|
|
136
|
+
for (const feature of features)
|
|
137
|
+
store.createFeature(feature);
|
|
138
|
+
});
|
|
139
|
+
return features.map((feature) => store.getFeature(feature.id));
|
|
140
|
+
},
|
|
141
|
+
update(id, patch) {
|
|
142
|
+
const feature = require(id);
|
|
143
|
+
const updates = preparePatch(feature, patch);
|
|
144
|
+
if (store.isReadOnly())
|
|
145
|
+
return null;
|
|
146
|
+
if (featureLocked(store, feature) && !onlyLockOrVisibility(patch))
|
|
147
|
+
return null;
|
|
148
|
+
store.updateFeature(feature.id, updates);
|
|
149
|
+
return store.getFeature(feature.id) ?? null;
|
|
150
|
+
},
|
|
151
|
+
updateMany(patches) {
|
|
152
|
+
if (!Array.isArray(patches))
|
|
153
|
+
throw invalidInput('The patches must be an array');
|
|
154
|
+
const seen = new Set();
|
|
155
|
+
const prepared = patches.map((entry) => {
|
|
156
|
+
requireRecord(entry, 'Each entry');
|
|
157
|
+
const feature = require(entry.id);
|
|
158
|
+
if (seen.has(feature.id))
|
|
159
|
+
throw invalidInput(`The ID ${feature.id} is given twice`);
|
|
160
|
+
seen.add(feature.id);
|
|
161
|
+
return { feature, patch: entry.patch, updates: preparePatch(feature, entry.patch) };
|
|
162
|
+
});
|
|
163
|
+
if (store.isReadOnly())
|
|
164
|
+
return null;
|
|
165
|
+
const refused = prepared.some(({ feature, patch }) => featureLocked(store, feature) && !onlyLockOrVisibility(patch));
|
|
166
|
+
if (refused)
|
|
167
|
+
return null;
|
|
168
|
+
store.transact(() => {
|
|
169
|
+
for (const { feature, updates } of prepared)
|
|
170
|
+
store.updateFeature(feature.id, updates);
|
|
171
|
+
});
|
|
172
|
+
return prepared.map(({ feature }) => store.getFeature(feature.id));
|
|
173
|
+
},
|
|
174
|
+
delete(id) {
|
|
175
|
+
const feature = require(id);
|
|
176
|
+
if (store.isReadOnly() || featureLocked(store, feature))
|
|
177
|
+
return false;
|
|
178
|
+
return store.deleteFeature(feature.id);
|
|
179
|
+
},
|
|
180
|
+
deleteMany(ids) {
|
|
181
|
+
const features = requireAll(ids);
|
|
182
|
+
if (store.isReadOnly())
|
|
183
|
+
return false;
|
|
184
|
+
if (features.some((feature) => featureLocked(store, feature)))
|
|
185
|
+
return false;
|
|
186
|
+
store.transact(() => {
|
|
187
|
+
for (const feature of features) {
|
|
188
|
+
if (store.getFeature(feature.id))
|
|
189
|
+
store.deleteFeature(feature.id);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return true;
|
|
193
|
+
},
|
|
194
|
+
move(id, to) {
|
|
195
|
+
return moveMany([id], to);
|
|
196
|
+
},
|
|
197
|
+
moveMany,
|
|
198
|
+
isEditable(id) {
|
|
199
|
+
const feature = require(id);
|
|
200
|
+
return !store.isReadOnly() && !isFeatureLocked(feature, store);
|
|
201
|
+
},
|
|
202
|
+
getAppliedStyle(id) {
|
|
203
|
+
const feature = store.getFeature(id);
|
|
204
|
+
if (!feature)
|
|
205
|
+
return undefined;
|
|
206
|
+
return appliedStyle(store, feature, deps.getStyleOptions());
|
|
207
|
+
},
|
|
208
|
+
union(ids) {
|
|
209
|
+
const inputs = requireAreas(ids, 2);
|
|
210
|
+
if (refuseChange(inputs))
|
|
211
|
+
return null;
|
|
212
|
+
return runAreaOperation(inputs, inputs[inputs.length - 1], inputs, unionAll);
|
|
213
|
+
},
|
|
214
|
+
difference(id, subtractIds) {
|
|
215
|
+
const [subject] = requireAreas([id], 1);
|
|
216
|
+
const others = requireAreas(subtractIds, 1);
|
|
217
|
+
if (others.some((other) => other.id === subject.id)) {
|
|
218
|
+
throw invalidInput('An area cannot be subtracted from itself');
|
|
219
|
+
}
|
|
220
|
+
if (refuseChange([subject]))
|
|
221
|
+
return null;
|
|
222
|
+
const inputs = inStackingOrder([subject, ...others]);
|
|
223
|
+
return runAreaOperation(inputs, subject, [subject], (areas) => differenceAll(areas[inputs.indexOf(subject)], areas.filter((_, index) => inputs[index] !== subject)));
|
|
224
|
+
},
|
|
225
|
+
intersection(ids) {
|
|
226
|
+
const inputs = requireAreas(ids, 2);
|
|
227
|
+
if (refuseChange(inputs))
|
|
228
|
+
return null;
|
|
229
|
+
return runAreaOperation(inputs, inputs[inputs.length - 1], inputs, intersectionAll);
|
|
230
|
+
},
|
|
231
|
+
split(id, lineId) {
|
|
232
|
+
const area = require(id);
|
|
233
|
+
const line = require(lineId);
|
|
234
|
+
if (!isAreaFeature(area))
|
|
235
|
+
throw invalidInput(`The feature ${area.id} is not an area`);
|
|
236
|
+
if (!isSplitLineFeature(line))
|
|
237
|
+
throw invalidInput(`The feature ${line.id} is not a line`);
|
|
238
|
+
if (refuseChange([area]))
|
|
239
|
+
return null;
|
|
240
|
+
return runSplit(geometryDeps, area, line, false).map((resultId) => store.getFeature(resultId));
|
|
241
|
+
},
|
|
242
|
+
buffer(ids, options) {
|
|
243
|
+
const inputs = inStackingOrder(requireAll(ids));
|
|
244
|
+
requireRecord(options, 'The options');
|
|
245
|
+
const { distanceMeters, segments } = options;
|
|
246
|
+
if (typeof distanceMeters !== 'number' || !Number.isFinite(distanceMeters)) {
|
|
247
|
+
throw invalidInput('distanceMeters must be a finite number');
|
|
248
|
+
}
|
|
249
|
+
if (segments !== undefined && (typeof segments !== 'number' || !(segments > 0))) {
|
|
250
|
+
throw invalidInput('segments must be a positive number');
|
|
251
|
+
}
|
|
252
|
+
for (const input of inputs) {
|
|
253
|
+
if (!isBufferableFeature(input)) {
|
|
254
|
+
throw invalidInput(`The feature ${input.id} cannot be buffered`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (refuseChange(inputs))
|
|
258
|
+
return null;
|
|
259
|
+
if (distanceMeters === 0 || inputs.length === 0)
|
|
260
|
+
return [];
|
|
261
|
+
return runBuffer(geometryDeps, inputs, { distanceMeters, segments }, false).map((resultId) => store.getFeature(resultId));
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
function moveMany(ids, to) {
|
|
265
|
+
const features = inStackingOrder(requireAll(ids));
|
|
266
|
+
const target = resolveMoveTarget(store, to);
|
|
267
|
+
if (store.isReadOnly())
|
|
268
|
+
return false;
|
|
269
|
+
if (features.some((feature) => featureLocked(store, feature)))
|
|
270
|
+
return false;
|
|
271
|
+
if (target.locked)
|
|
272
|
+
return false;
|
|
273
|
+
moveFeatures(store, features, target);
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
/** The features as areas in stacking order, at least `min` of them */
|
|
277
|
+
function requireAreas(ids, min) {
|
|
278
|
+
const features = inStackingOrder(requireAll(ids));
|
|
279
|
+
if (features.length < min) {
|
|
280
|
+
throw invalidInput(`At least ${min} areas are needed`);
|
|
281
|
+
}
|
|
282
|
+
for (const feature of features) {
|
|
283
|
+
if (!isAreaFeature(feature))
|
|
284
|
+
throw invalidInput(`The feature ${feature.id} is not an area`);
|
|
285
|
+
}
|
|
286
|
+
return features;
|
|
287
|
+
}
|
|
288
|
+
/** Whether a change of these features is refused: read-only, or one of them is locked */
|
|
289
|
+
function refuseChange(features) {
|
|
290
|
+
return store.isReadOnly() || features.some((feature) => featureLocked(store, feature));
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Runs a boolean operation on areas and puts the result in the place of `anchor`
|
|
294
|
+
*
|
|
295
|
+
* @returns The result, or null when the result has no area (nothing changes then)
|
|
296
|
+
*/
|
|
297
|
+
function runAreaOperation(inputs, anchor, removed, compute) {
|
|
298
|
+
const areas = inputs.map((feature) => toAreaCoordinates(feature));
|
|
299
|
+
const geometry = toResultGeometry(compute(areas));
|
|
300
|
+
if (geometry === null)
|
|
301
|
+
return null;
|
|
302
|
+
const resultId = store.transact(() => applyResult(geometryDeps, {
|
|
303
|
+
anchor,
|
|
304
|
+
removedIds: removed.map((feature) => feature.id),
|
|
305
|
+
geometry,
|
|
306
|
+
}));
|
|
307
|
+
return store.getFeature(resultId) ?? null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// Inputs and patches
|
|
312
|
+
// ============================================================================
|
|
313
|
+
/** Checks an input and builds the feature to store; throws DrawError on a wrong input */
|
|
314
|
+
function prepareFeature(deps, input, pending) {
|
|
315
|
+
const { store } = deps;
|
|
316
|
+
requireRecord(input, 'The input');
|
|
317
|
+
const record = input;
|
|
318
|
+
onlyKeys(record, INPUT_KEYS, 'The input');
|
|
319
|
+
if (typeof input.type !== 'string' || input.type === '') {
|
|
320
|
+
throw invalidInput('type must be a non-empty string');
|
|
321
|
+
}
|
|
322
|
+
const geometryProblem = describeGeometryProblem(input.type, input.geometry);
|
|
323
|
+
if (geometryProblem)
|
|
324
|
+
throw invalidInput(`The input has ${geometryProblem}`);
|
|
325
|
+
if (input.properties !== undefined && !isRecord(input.properties)) {
|
|
326
|
+
throw invalidInput('properties must be an object');
|
|
327
|
+
}
|
|
328
|
+
if (input.style !== undefined) {
|
|
329
|
+
const styleProblem = describeStyleProblem(input.style);
|
|
330
|
+
if (styleProblem)
|
|
331
|
+
throw invalidInput(`The input has ${styleProblem}`);
|
|
332
|
+
}
|
|
333
|
+
optionalBoolean(record, 'visible');
|
|
334
|
+
optionalBoolean(record, 'locked');
|
|
335
|
+
let id;
|
|
336
|
+
if (input.id === undefined) {
|
|
337
|
+
id = deps.generateId();
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
id = requireId(input.id);
|
|
341
|
+
if (isTaken(store, id) || pending.has(id)) {
|
|
342
|
+
throw new DrawError('already-exists', `The ID ${JSON.stringify(id)} is already taken`, {
|
|
343
|
+
id,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const group = input.groupId === undefined ? undefined : store.getGroup(requireId(input.groupId));
|
|
348
|
+
if (input.groupId !== undefined && !group)
|
|
349
|
+
throw notFound('group', input.groupId);
|
|
350
|
+
let layerId;
|
|
351
|
+
if (input.layerId !== undefined) {
|
|
352
|
+
layerId = requireId(input.layerId);
|
|
353
|
+
if (!store.getLayer(layerId))
|
|
354
|
+
throw notFound('layer', layerId);
|
|
355
|
+
if (group && group.layerId !== layerId) {
|
|
356
|
+
throw invalidInput(`The group ${group.id} is not in the layer ${layerId}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
else if (group) {
|
|
360
|
+
layerId = group.layerId;
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
layerId = deps.getActiveLayerId();
|
|
364
|
+
if (!store.getLayer(layerId)) {
|
|
365
|
+
throw new DrawError('invalid-state', 'There is no layer to put the feature in');
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
id,
|
|
370
|
+
type: input.type,
|
|
371
|
+
geometry: input.geometry,
|
|
372
|
+
layerId,
|
|
373
|
+
groupId: group?.id,
|
|
374
|
+
properties: withoutUndefined(input.properties ?? {}),
|
|
375
|
+
style: withoutUndefined(input.style ?? {}),
|
|
376
|
+
visible: input.visible ?? true,
|
|
377
|
+
locked: input.locked ?? false,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Checks a patch and builds the updates of the Store; throws DrawError on a wrong patch
|
|
382
|
+
*
|
|
383
|
+
* @internal
|
|
384
|
+
*/
|
|
385
|
+
export function preparePatch(feature, patch) {
|
|
386
|
+
requireRecord(patch, 'The patch');
|
|
387
|
+
const record = patch;
|
|
388
|
+
onlyKeys(record, PATCH_KEYS, 'The patch');
|
|
389
|
+
optionalBoolean(record, 'visible');
|
|
390
|
+
optionalBoolean(record, 'locked');
|
|
391
|
+
const updates = {};
|
|
392
|
+
if (patch.geometry !== undefined) {
|
|
393
|
+
const problem = describeGeometryProblem(feature.type, patch.geometry);
|
|
394
|
+
if (problem)
|
|
395
|
+
throw invalidInput(`The patch has ${problem}`);
|
|
396
|
+
updates.geometry = patch.geometry;
|
|
397
|
+
}
|
|
398
|
+
if (patch.properties !== undefined) {
|
|
399
|
+
if (!isRecord(patch.properties))
|
|
400
|
+
throw invalidInput('properties must be an object');
|
|
401
|
+
updates.properties = merged(feature.properties, patch.properties);
|
|
402
|
+
}
|
|
403
|
+
if (patch.style !== undefined) {
|
|
404
|
+
const problem = describeStyleProblem(patch.style);
|
|
405
|
+
if (problem)
|
|
406
|
+
throw invalidInput(`The patch has ${problem}`);
|
|
407
|
+
updates.style = merged(feature.style, patch.style);
|
|
408
|
+
}
|
|
409
|
+
if (patch.visible !== undefined)
|
|
410
|
+
updates.visible = patch.visible;
|
|
411
|
+
if (patch.locked !== undefined)
|
|
412
|
+
updates.locked = patch.locked;
|
|
413
|
+
return updates;
|
|
414
|
+
}
|
|
415
|
+
/** The keys of `base` with the keys of `patch` set, and removed where they are undefined */
|
|
416
|
+
function merged(base, patch) {
|
|
417
|
+
const result = {};
|
|
418
|
+
for (const [key, value] of Object.entries(base))
|
|
419
|
+
setOwnProperty(result, key, value);
|
|
420
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
421
|
+
if (value === undefined)
|
|
422
|
+
delete result[key];
|
|
423
|
+
else
|
|
424
|
+
setOwnProperty(result, key, value);
|
|
425
|
+
}
|
|
426
|
+
return result;
|
|
427
|
+
}
|
|
428
|
+
/** A copy without the keys whose value is undefined */
|
|
429
|
+
function withoutUndefined(value) {
|
|
430
|
+
return merged({}, value);
|
|
431
|
+
}
|
|
432
|
+
// ============================================================================
|
|
433
|
+
// The applied style
|
|
434
|
+
// ============================================================================
|
|
435
|
+
/**
|
|
436
|
+
* The look a feature is drawn with: the defaults of the options, the color of the layer rule
|
|
437
|
+
* and the style of the feature, in that order. The colors of the options and of the feature
|
|
438
|
+
* are the strings given, never rounded
|
|
439
|
+
*/
|
|
440
|
+
function appliedStyle(store, feature, style) {
|
|
441
|
+
const defaults = toAppliedDefaults(style, feature.type);
|
|
442
|
+
const layer = store.getLayer(feature.layerId);
|
|
443
|
+
const own = resolveFeatureStyle(feature, layer?.styleRule, getStyleRuleChannel(feature.type)) ?? {};
|
|
444
|
+
return { ...defaults, ...withoutUndefined(own) };
|
|
445
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Feature, FeatureCoordinates, FeatureType } from '../../../store/types.js';
|
|
2
|
+
import type { GeometryDeps } from './types.js';
|
|
3
|
+
export interface CommitParams {
|
|
4
|
+
/**
|
|
5
|
+
* The input whose style, properties and placement are inherited (in a boolean operation, the
|
|
6
|
+
* frontmost in z order)
|
|
7
|
+
*/
|
|
8
|
+
anchor: Feature;
|
|
9
|
+
/**
|
|
10
|
+
* The IDs of the inputs to delete. Left empty in an operation that keeps the inputs, such as
|
|
11
|
+
* the buffer
|
|
12
|
+
*/
|
|
13
|
+
removedIds: string[];
|
|
14
|
+
geometry: {
|
|
15
|
+
type: FeatureType;
|
|
16
|
+
coordinates: FeatureCoordinates;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The properties of the result. When omitted, they are inherited from the anchor with the
|
|
20
|
+
* Circle-specific properties removed.
|
|
21
|
+
* It is given explicitly only when the result stays a Circle (the Circle special case of the
|
|
22
|
+
* buffer).
|
|
23
|
+
*/
|
|
24
|
+
properties?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates one result feature, deletes the inputs and places it.
|
|
28
|
+
*
|
|
29
|
+
* It does not open a transaction. Because the caller wraps it in store.transact, even a case
|
|
30
|
+
* with several results, such as the buffer, is gathered into one StoreChange.
|
|
31
|
+
*/
|
|
32
|
+
export declare function applyResult(deps: GeometryDeps, params: CommitParams): string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
|
|
2
2
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
import { setDrawProperty } from '../../../shared/properties.js';
|
|
4
|
+
import { geometryFromCoordinates } from '../../../shared/utils/coordinates.js';
|
|
3
5
|
/**
|
|
4
6
|
* The parametric properties of Circle. They are not inherited by a result that has been
|
|
5
7
|
* reduced to a polygon (because a Circle becomes a polygon of 64 segments and loses the
|
|
@@ -17,7 +19,7 @@ const CIRCLE_ONLY_PROPERTIES = ['radiusMeters', 'radiusHandleAngle'];
|
|
|
17
19
|
*/
|
|
18
20
|
function planPlacement(store, anchor, removedIds) {
|
|
19
21
|
const group = anchor.groupId ? store.getGroup(anchor.groupId) : undefined;
|
|
20
|
-
const container = group ? group.featureIds : (store.getLayer(anchor.layerId)?.
|
|
22
|
+
const container = group ? group.featureIds : (store.getLayer(anchor.layerId)?.items ?? []);
|
|
21
23
|
const anchorIndex = container.indexOf(anchor.id);
|
|
22
24
|
const precedingIds = anchorIndex < 0 ? container : container.slice(0, anchorIndex);
|
|
23
25
|
const precedingCount = precedingIds.filter((id) => !removedIds.has(id)).length;
|
|
@@ -46,17 +48,17 @@ function moveToPlacement(store, resultId, placement) {
|
|
|
46
48
|
const layer = store.getLayer(placement.layerId);
|
|
47
49
|
if (!layer)
|
|
48
50
|
return;
|
|
49
|
-
const order = layer.
|
|
51
|
+
const order = layer.items.filter((id) => id !== resultId);
|
|
50
52
|
order.splice(placement.index, 0, resultId);
|
|
51
|
-
store.updateLayer(placement.layerId, { order });
|
|
53
|
+
store.updateLayer(placement.layerId, { items: order });
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
56
|
* Inherits the style and the properties from the input it inherits from.
|
|
55
57
|
*/
|
|
56
58
|
function inheritProperties(anchor) {
|
|
57
59
|
const properties = { ...anchor.properties };
|
|
58
|
-
for (const
|
|
59
|
-
|
|
60
|
+
for (const name of CIRCLE_ONLY_PROPERTIES) {
|
|
61
|
+
setDrawProperty(properties, name, undefined);
|
|
60
62
|
}
|
|
61
63
|
return properties;
|
|
62
64
|
}
|
|
@@ -64,7 +66,7 @@ function inheritProperties(anchor) {
|
|
|
64
66
|
* Creates one result feature, deletes the inputs and places it.
|
|
65
67
|
*
|
|
66
68
|
* It does not open a transaction. Because the caller wraps it in store.transact, even a case
|
|
67
|
-
* with several results, such as the buffer, is gathered into one
|
|
69
|
+
* with several results, such as the buffer, is gathered into one StoreChange.
|
|
68
70
|
*/
|
|
69
71
|
export function applyResult(deps, params) {
|
|
70
72
|
const { store, generateFeatureId } = deps;
|
|
@@ -73,11 +75,11 @@ export function applyResult(deps, params) {
|
|
|
73
75
|
const result = {
|
|
74
76
|
id: generateFeatureId(),
|
|
75
77
|
type: geometry.type,
|
|
76
|
-
|
|
78
|
+
geometry: geometryFromCoordinates(geometry.type, geometry.coordinates),
|
|
77
79
|
layerId: placement.layerId,
|
|
78
80
|
groupId: placement.groupId,
|
|
79
81
|
properties: params.properties ?? inheritProperties(anchor),
|
|
80
|
-
style:
|
|
82
|
+
style: { ...anchor.style },
|
|
81
83
|
locked: false,
|
|
82
84
|
visible: true,
|
|
83
85
|
};
|
|
@@ -93,22 +95,3 @@ export function applyResult(deps, params) {
|
|
|
93
95
|
moveToPlacement(store, result.id, placement);
|
|
94
96
|
return result.id;
|
|
95
97
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Creates the result feature and deletes the inputs in one transaction, and moves the
|
|
98
|
-
* selection to the result.
|
|
99
|
-
*
|
|
100
|
-
* A subscriber receives it as one StateChanges, which is what makes it one step for anything
|
|
101
|
-
* that records changes.
|
|
102
|
-
*/
|
|
103
|
-
export function commitResult(deps, params) {
|
|
104
|
-
const { store } = deps;
|
|
105
|
-
return store.transact(() => {
|
|
106
|
-
const resultId = applyResult(deps, params);
|
|
107
|
-
store.setSelection('feature', [resultId]);
|
|
108
|
-
return resultId;
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
/** Emits draw.geometry.applied. */
|
|
112
|
-
export function emitApplied(eventEmitter, payload) {
|
|
113
|
-
eventEmitter.emit('geometry.applied', payload);
|
|
114
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Feature } from '
|
|
2
|
-
import type {
|
|
1
|
+
import type { Feature } from '../../../store/types.js';
|
|
2
|
+
import type { BufferOptions, GeometryDeps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Runs the buffer and creates the result features.
|
|
5
5
|
*
|
|
@@ -7,5 +7,6 @@ import type { GeometryApiDeps, GeometryBufferOptions } from './types.js';
|
|
|
7
7
|
* gathered into one store.transact, so a single undo removes all of them.
|
|
8
8
|
*
|
|
9
9
|
* @param inputs The targets ordered in z order (the tail is the frontmost)
|
|
10
|
+
* @param select Whether the results become the selection
|
|
10
11
|
*/
|
|
11
|
-
export declare function runBuffer(deps:
|
|
12
|
+
export declare function runBuffer(deps: GeometryDeps, inputs: Feature[], options: BufferOptions, select?: boolean): string[];
|
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
* creates one result per input, several applyResult calls are gathered into one
|
|
9
9
|
* store.transact, and all the results are selected at the end.
|
|
10
10
|
*/
|
|
11
|
+
import { buffer as computeBuffer } from '../../../geometry/buffer.js';
|
|
11
12
|
// buffer is imported under an alias so that the name reads as the geometry module's function.
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { drawProperties } from '../../../shared/properties.js';
|
|
14
|
+
import { coordinatesOf } from '../../../shared/utils/coordinates.js';
|
|
15
|
+
import { getCircleRadius } from '../../../shared/utils/property.js';
|
|
16
|
+
import { applyResult } from './apply.js';
|
|
15
17
|
import { toBufferGeometry, toResultGeometry } from './targets.js';
|
|
16
18
|
/**
|
|
17
19
|
* Plans the buffer of a Circle input.
|
|
@@ -29,10 +31,10 @@ function planCircleBuffer(input, distanceMeters) {
|
|
|
29
31
|
return null;
|
|
30
32
|
return {
|
|
31
33
|
input,
|
|
32
|
-
geometry: { type: 'Circle', coordinates: input
|
|
34
|
+
geometry: { type: 'Circle', coordinates: coordinatesOf(input) },
|
|
33
35
|
// It stays a Circle, so the properties including radiusHandleAngle are inherited and only
|
|
34
36
|
// the radius is replaced.
|
|
35
|
-
properties: { ...input.properties, radiusMeters: nextRadius },
|
|
37
|
+
properties: { ...input.properties, ...drawProperties({ radiusMeters: nextRadius }) },
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
@@ -63,8 +65,9 @@ function planBuffer(input, options) {
|
|
|
63
65
|
* gathered into one store.transact, so a single undo removes all of them.
|
|
64
66
|
*
|
|
65
67
|
* @param inputs The targets ordered in z order (the tail is the frontmost)
|
|
68
|
+
* @param select Whether the results become the selection
|
|
66
69
|
*/
|
|
67
|
-
export function runBuffer(deps, inputs, options) {
|
|
70
|
+
export function runBuffer(deps, inputs, options, select = true) {
|
|
68
71
|
const { store } = deps;
|
|
69
72
|
const plans = [];
|
|
70
73
|
for (const input of inputs) {
|
|
@@ -73,15 +76,7 @@ export function runBuffer(deps, inputs, options) {
|
|
|
73
76
|
plans.push(plan);
|
|
74
77
|
}
|
|
75
78
|
if (plans.length === 0) {
|
|
76
|
-
// Every input was skipped or had an empty result. The Store is not changed at all
|
|
77
|
-
// the notification is emitted.
|
|
78
|
-
emitApplied(deps.eventEmitter, {
|
|
79
|
-
operation: 'buffer',
|
|
80
|
-
inputIds: inputs.map((input) => input.id),
|
|
81
|
-
resultId: null,
|
|
82
|
-
resultIds: [],
|
|
83
|
-
status: 'empty',
|
|
84
|
-
});
|
|
79
|
+
// Every input was skipped or had an empty result. The Store is not changed at all.
|
|
85
80
|
return [];
|
|
86
81
|
}
|
|
87
82
|
const resultIds = store.transact(() => {
|
|
@@ -91,15 +86,9 @@ export function runBuffer(deps, inputs, options) {
|
|
|
91
86
|
geometry: plan.geometry,
|
|
92
87
|
properties: plan.properties,
|
|
93
88
|
}));
|
|
94
|
-
|
|
89
|
+
if (select)
|
|
90
|
+
store.setSelection('feature', ids);
|
|
95
91
|
return ids;
|
|
96
92
|
});
|
|
97
|
-
emitApplied(deps.eventEmitter, {
|
|
98
|
-
operation: 'buffer',
|
|
99
|
-
inputIds: plans.map((plan) => plan.input.id),
|
|
100
|
-
resultId: resultIds[0],
|
|
101
|
-
resultIds,
|
|
102
|
-
status: 'applied',
|
|
103
|
-
});
|
|
104
93
|
return resultIds;
|
|
105
94
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Feature } from '
|
|
2
|
-
import type {
|
|
1
|
+
import type { Feature } from '../../../store/types.js';
|
|
2
|
+
import type { GeometryDeps } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Runs the split and replaces the polygon with the group of features that result from the
|
|
5
5
|
* split.
|
|
@@ -12,5 +12,6 @@ import type { GeometryApiDeps } from './types.js';
|
|
|
12
12
|
*
|
|
13
13
|
* @param area The polygon to be cut
|
|
14
14
|
* @param line The cutting line (it is not deleted and remains)
|
|
15
|
+
* @param select Whether the results become the selection
|
|
15
16
|
*/
|
|
16
|
-
export declare function runSplit(deps:
|
|
17
|
+
export declare function runSplit(deps: GeometryDeps, area: Feature, line: Feature, select?: boolean): string[];
|