@accelint/map-toolkit 0.5.0 → 0.6.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 +14 -0
- package/catalog-info.yaml +5 -3
- package/dist/camera/use-camera-state.js +1 -2
- package/dist/camera/use-camera-state.js.map +1 -1
- package/dist/deckgl/base-map/constants.d.ts +9 -2
- package/dist/deckgl/base-map/constants.js +9 -2
- package/dist/deckgl/base-map/constants.js.map +1 -1
- package/dist/deckgl/base-map/index.d.ts +4 -2
- package/dist/deckgl/base-map/index.js +5 -6
- package/dist/deckgl/base-map/index.js.map +1 -1
- package/dist/deckgl/base-map/types.d.ts +6 -1
- package/dist/deckgl/index.d.ts +8 -2
- package/dist/deckgl/index.js +6 -2
- package/dist/deckgl/saved-viewports/index.d.ts +1 -1
- package/dist/deckgl/saved-viewports/index.js +1 -2
- package/dist/deckgl/saved-viewports/index.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/constants.d.ts +44 -0
- package/dist/deckgl/shapes/display-shape-layer/constants.js +61 -0
- package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -0
- package/dist/{node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/assert.js → deckgl/shapes/display-shape-layer/fiber.d.ts} +11 -7
- package/dist/{packages/hotkey-manager/dist/lib/is-client/index.js → deckgl/shapes/display-shape-layer/fiber.js} +6 -7
- package/dist/deckgl/shapes/display-shape-layer/fiber.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/index.d.ts +206 -0
- package/dist/deckgl/shapes/display-shape-layer/index.js +416 -0
- package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.d.ts +66 -0
- package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js +116 -0
- package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/store.d.ts +87 -0
- package/dist/deckgl/shapes/display-shape-layer/store.js +316 -0
- package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/types.d.ts +115 -0
- package/dist/{node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/fly-to-viewport.js → deckgl/shapes/display-shape-layer/types.js} +0 -2
- package/dist/deckgl/shapes/display-shape-layer/use-shape-selection.d.ts +89 -0
- package/dist/deckgl/shapes/display-shape-layer/use-shape-selection.js +88 -0
- package/dist/deckgl/shapes/display-shape-layer/use-shape-selection.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.d.ts +61 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js +111 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.d.ts +196 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js +368 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js.map +1 -0
- package/dist/deckgl/shapes/index.d.ts +20 -0
- package/dist/{node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/math-utils.js → deckgl/shapes/index.js} +6 -11
- package/dist/deckgl/shapes/shared/constants.d.ts +78 -0
- package/dist/deckgl/shapes/shared/constants.js +109 -0
- package/dist/deckgl/shapes/shared/constants.js.map +1 -0
- package/dist/deckgl/shapes/shared/events.d.ts +73 -0
- package/dist/deckgl/shapes/shared/events.js +58 -0
- package/dist/deckgl/shapes/shared/events.js.map +1 -0
- package/dist/deckgl/shapes/shared/types.d.ts +158 -0
- package/dist/{node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/get-bounds.js → deckgl/shapes/shared/types.js} +13 -4
- package/dist/deckgl/shapes/shared/types.js.map +1 -0
- package/dist/deckgl/symbol-layer/index.d.ts +1 -1
- package/dist/viewport/viewport-size.d.ts +2 -2
- package/package.json +36 -20
- package/dist/_virtual/rolldown_runtime.js +0 -22
- package/dist/decorators/deckgl.d.ts +0 -19
- package/dist/decorators/deckgl.js +0 -32
- package/dist/decorators/deckgl.js.map +0 -1
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/assert.js.map +0 -1
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/fit-bounds.js +0 -63
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/fit-bounds.js.map +0 -1
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/get-bounds.js.map +0 -1
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/index.js +0 -19
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/math-utils.js.map +0 -1
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/normalize-viewport-props.js +0 -14
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/web-mercator-utils.js +0 -59
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/web-mercator-utils.js.map +0 -1
- package/dist/node_modules/.pnpm/@math.gl_web-mercator@4.1.0/node_modules/@math.gl/web-mercator/dist/web-mercator-viewport.js +0 -16
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/attribution-control.js +0 -29
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/attribution-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/fullscreen-control.js +0 -29
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/fullscreen-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/geolocate-control.js +0 -54
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/geolocate-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/layer.js +0 -15
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/logo-control.js +0 -29
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/logo-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/map.js +0 -91
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/map.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/marker.js +0 -88
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/marker.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/navigation-control.js +0 -29
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/navigation-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/popup.js +0 -69
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/popup.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/scale-control.js +0 -35
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/scale-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/source.js +0 -15
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/terrain-control.js +0 -29
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/terrain-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/use-control.js +0 -40
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/use-control.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/use-map.js +0 -23
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/components/use-map.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/index.js +0 -27
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/maplibre/create-ref.js +0 -57
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/maplibre/create-ref.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/maplibre/maplibre.js +0 -343
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/maplibre/maplibre.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/apply-react-style.js +0 -28
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/apply-react-style.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/compare-class-names.js +0 -31
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/compare-class-names.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/deep-equal.js +0 -57
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/deep-equal.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/set-globals.js +0 -30
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/set-globals.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/style-utils.js +0 -53
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/style-utils.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/transform.js +0 -52
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/transform.js.map +0 -1
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/use-isomorphic-layout-effect.js +0 -22
- package/dist/node_modules/.pnpm/@vis.gl_react-maplibre@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@vis.gl/react-maplibre/dist/utils/use-isomorphic-layout-effect.js.map +0 -1
- package/dist/node_modules/.pnpm/immer@10.2.0/node_modules/immer/dist/immer.js +0 -812
- package/dist/node_modules/.pnpm/immer@10.2.0/node_modules/immer/dist/immer.js.map +0 -1
- package/dist/node_modules/.pnpm/radashi@12.7.1/node_modules/radashi/dist/radashi.js +0 -35
- package/dist/node_modules/.pnpm/radashi@12.7.1/node_modules/radashi/dist/radashi.js.map +0 -1
- package/dist/node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/cjs/react-dom.development.js +0 -195
- package/dist/node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/cjs/react-dom.development.js.map +0 -1
- package/dist/node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/cjs/react-dom.production.js +0 -76
- package/dist/node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/cjs/react-dom.production.js.map +0 -1
- package/dist/node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/index.js +0 -39
- package/dist/node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/index.js.map +0 -1
- package/dist/node_modules/.pnpm/react-map-gl@8.1.0_maplibre-gl@5.15.0_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/react-map-gl/dist/maplibre.js +0 -16
- package/dist/node_modules/.pnpm/zustand@5.0.9_@types_react@19.2.7_immer@10.2.0_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/middleware/immer.js +0 -27
- package/dist/node_modules/.pnpm/zustand@5.0.9_@types_react@19.2.7_immer@10.2.0_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/middleware/immer.js.map +0 -1
- package/dist/node_modules/.pnpm/zustand@5.0.9_@types_react@19.2.7_immer@10.2.0_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/vanilla.js +0 -45
- package/dist/node_modules/.pnpm/zustand@5.0.9_@types_react@19.2.7_immer@10.2.0_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/vanilla.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/actions/register-hotkey/index.js +0 -78
- package/dist/packages/hotkey-manager/dist/actions/register-hotkey/index.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/constants.js +0 -47
- package/dist/packages/hotkey-manager/dist/constants.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/enums/keycode.js +0 -130
- package/dist/packages/hotkey-manager/dist/enums/keycode.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/lib/is-client/index.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/lib/is-mac/index.js +0 -24
- package/dist/packages/hotkey-manager/dist/lib/is-mac/index.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/lib/key-to-id/index.js +0 -39
- package/dist/packages/hotkey-manager/dist/lib/key-to-id/index.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/lib/key-to-string/index.js +0 -27
- package/dist/packages/hotkey-manager/dist/lib/key-to-string/index.js.map +0 -1
- package/dist/packages/hotkey-manager/dist/stores/hotkey-store/index.js +0 -95
- package/dist/packages/hotkey-manager/dist/stores/hotkey-store/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/deckgl/shapes/display-shape-layer/index.ts"],"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'use client';\n\nimport { Broadcast } from '@accelint/bus';\nimport { CompositeLayer } from '@deck.gl/core';\nimport { PathStyleExtension } from '@deck.gl/extensions';\nimport { GeoJsonLayer, IconLayer } from '@deck.gl/layers';\nimport { DASH_ARRAYS, SHAPE_LAYER_IDS } from '../shared/constants';\nimport { type ShapeEvent, ShapeEvents } from '../shared/events';\nimport {\n COFFIN_CORNERS,\n DEFAULT_DISPLAY_PROPS,\n MAP_INTERACTION,\n} from './constants';\nimport { createShapeLabelLayer } from './shape-label-layer';\nimport {\n getDashArray,\n getFillColor,\n getHighlightColor,\n getHighlightLineWidth,\n getHoverLineWidth,\n getStrokeColor,\n} from './utils/display-style';\nimport type { Layer, PickingInfo } from '@deck.gl/core';\nimport type { EditableShape, ShapeId } from '../shared/types';\nimport type { DisplayShapeLayerProps } from './types';\n\n/**\n * Typed event bus instance for shape events.\n * Provides type-safe event emission for shape interactions.\n */\nconst shapeBus = Broadcast.getInstance<ShapeEvent>();\n\n/**\n * State interface for DisplayShapeLayer\n */\ninterface DisplayShapeLayerState {\n /** Index of currently hovered shape, undefined when not hovering */\n hoverIndex?: number;\n /** ID of the last hovered shape for event deduplication */\n lastHoveredId?: ShapeId | null;\n /** Allow additional properties from base layer state */\n [key: string]: unknown;\n}\n\n/**\n * Cache for transformed features to avoid recreating objects on every render.\n */\ninterface FeaturesCache {\n /** Reference to the original data array for identity comparison */\n data: EditableShape[];\n /** Transformed features with shapeId added to properties */\n features: EditableShape['feature'][];\n}\n\n/**\n * DisplayShapeLayer - Read-only shapes visualization layer\n *\n * A composite deck.gl layer for displaying geographic shapes with interactive features.\n * Ideal for rendering shapes from external APIs or displaying read-only geographic data.\n *\n * ## Features\n * - **Multiple geometry types**: Point, LineString, Polygon, and Circle\n * - **Icon support**: Custom icons for Point geometries via icon atlases\n * - **Interactive selection**: Click handling with dotted border and optional highlight\n * - **Hover effects**: Line width increases on hover for better UX\n * - **Customizable labels**: Flexible label positioning with per-shape or global options\n * - **Style properties**: Full control over colors, stroke patterns, and opacity\n * - **Event bus integration**: Automatically emits shape events via @accelint/bus\n * - **Multi-map support**: Events include map instance ID for isolation\n *\n * ## Selection Visual Feedback\n * When a shape is selected via `selectedShapeId`:\n * - The shape's stroke pattern changes to dotted\n * - An optional highlight renders underneath (controlled by `showHighlight` prop)\n *\n * ## Layer Structure\n * Renders up to four sublayers (in order, bottom to top):\n * 1. **Highlight layer**: Selection highlight effect for non-icon-Point shapes (if showHighlight=true)\n * 2. **Coffin corners layer**: Selection/hover feedback for Point shapes with icons\n * 3. **Main GeoJsonLayer**: Shape geometries with styling and interaction\n * 4. **Label layer**: Text labels (if showLabels enabled)\n *\n * ## Icon Atlas Constraint\n * When using icons for Point geometries, all shapes in a single layer must share the\n * same icon atlas. The layer uses the first atlas found across all features. If you\n * need icons from different atlases, use separate DisplayShapeLayer instances.\n *\n * ## Event Bus Integration\n * Automatically emits shape events that can be consumed anywhere in your app:\n * - `shapes:selected` - Emitted when a shape is clicked (includes mapId)\n * - `shapes:hovered` - Emitted when the hovered shape changes (deduplicated, includes mapId)\n *\n * For selection with auto-deselection, use the companion `useShapeSelection` hook which handles\n * all the event wiring automatically. See the example below.\n *\n * @example Basic usage with useShapeSelection hook (recommended)\n * ```tsx\n * import '@accelint/map-toolkit/deckgl/shapes/display-shape-layer/fiber';\n * import { useShapeSelection } from '@accelint/map-toolkit/deckgl/shapes';\n * import { uuid } from '@accelint/core';\n *\n * const MAP_ID = uuid();\n *\n * function MapWithShapes() {\n * const { selectedId } = useShapeSelection(MAP_ID);\n *\n * return (\n * <BaseMap id={MAP_ID}>\n * <displayShapeLayer\n * id=\"my-shapes\"\n * mapId={MAP_ID}\n * data={shapes}\n * selectedShapeId={selectedId}\n * showLabels={true}\n * pickable={true}\n * />\n * </BaseMap>\n * );\n * }\n * ```\n *\n * @example With custom label positioning\n * ```tsx\n * <displayShapeLayer\n * id=\"my-shapes\"\n * data={shapes}\n * showLabels={true}\n * labelOptions={{\n * // Position circle labels at the top\n * circleLabelCoordinateAnchor: 'top',\n * circleLabelVerticalAnchor: 'bottom',\n * circleLabelOffset: [0, -10],\n * // Position line labels at the middle\n * lineStringLabelCoordinateAnchor: 'middle',\n * }}\n * />\n * ```\n */\nexport class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {\n // State is typed via DisplayShapeLayerState but deck.gl doesn't support generic state\n declare state: DisplayShapeLayerState;\n\n /** Cache for transformed features to avoid recreating objects on every render */\n private featuresCache: FeaturesCache | null = null;\n\n static override layerName = 'DisplayShapeLayer';\n\n static override defaultProps = {\n ...DEFAULT_DISPLAY_PROPS,\n };\n\n /**\n * Clean up state and caches when layer is destroyed\n */\n override finalizeState(): void {\n // Clear hover state to prevent stale references\n if (this.state?.hoverIndex !== undefined) {\n this.setState({ hoverIndex: undefined, lastHoveredId: undefined });\n }\n // Clear features cache\n this.featuresCache = null;\n }\n\n /**\n * Override getPickingInfo to handle events from sublayers\n * This is the correct pattern for CompositeLayer event handling\n */\n override getPickingInfo({\n info,\n mode,\n sourceLayer,\n }: {\n info: PickingInfo;\n mode?: string;\n // biome-ignore lint/suspicious/noExplicitAny: sourceLayer type from deck.gl is not well-typed\n sourceLayer?: any;\n }) {\n // Check if this picking event came from our main shapes layer\n if (sourceLayer?.id === `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}`) {\n // Handle click events (deck.gl uses 'query' mode for clicks)\n if (mode === 'query') {\n this.handleShapeClick(info);\n }\n\n // Handle hover events (including when mode is undefined, which is hover)\n if (mode === 'hover' || !mode) {\n // Update hover state\n if (info.index !== undefined && info.index !== this.state?.hoverIndex) {\n this.setState({ hoverIndex: info.index });\n } else if (\n info.index === undefined &&\n this.state?.hoverIndex !== undefined\n ) {\n this.setState({ hoverIndex: undefined });\n }\n\n // Call hover callback\n this.handleShapeHover(info);\n }\n }\n\n return info;\n }\n\n /**\n * Convert shapes to GeoJSON features with shapeId in properties.\n * Uses caching to avoid recreating objects on every render cycle.\n */\n private getFeaturesWithId(): EditableShape['feature'][] {\n const { data } = this.props;\n\n // Return cached features if data hasn't changed (identity check)\n if (this.featuresCache?.data === data) {\n return this.featuresCache.features;\n }\n\n // Transform features and cache the result\n const features = data.map((shape) => ({\n ...shape.feature,\n properties: {\n ...shape.feature.properties,\n shapeId: shape.id,\n },\n }));\n\n this.featuresCache = { data, features };\n return features;\n }\n\n /**\n * Look up a shape by ID from the data prop.\n * Used by event handlers to get full shape without storing in feature properties.\n */\n private getShapeById(shapeId: ShapeId): EditableShape | undefined {\n return this.props.data.find((shape) => shape.id === shapeId);\n }\n\n /**\n * Handle shape click\n */\n private handleShapeClick = (info: PickingInfo): void => {\n const { onShapeClick, mapId } = this.props;\n\n if (!info.object) {\n return;\n }\n\n // Look up shape from data prop using shapeId stored in feature properties\n const shapeId = info.object.properties?.shapeId as ShapeId | undefined;\n if (!shapeId) {\n return;\n }\n\n const shape = this.getShapeById(shapeId);\n if (!shape) {\n return;\n }\n\n // Emit shape selected event via bus (include mapId for multi-map isolation)\n shapeBus.emit(ShapeEvents.selected, { shapeId: shape.id, mapId });\n\n // Call callback if provided\n if (onShapeClick) {\n onShapeClick(shape);\n }\n };\n\n /**\n * Handle shape hover\n */\n private handleShapeHover = (info: PickingInfo): void => {\n const { onShapeHover, mapId } = this.props;\n\n // Look up shape from data prop using shapeId stored in feature properties\n const shapeId =\n (info.object?.properties?.shapeId as ShapeId | undefined) ?? null;\n const shape = shapeId ? (this.getShapeById(shapeId) ?? null) : null;\n\n // Dedupe hover events - only emit if hovered shape changed\n if (shapeId !== this.state?.lastHoveredId) {\n this.setState({ lastHoveredId: shapeId });\n\n // Emit shape hovered event via bus (include mapId for multi-map isolation)\n shapeBus.emit(ShapeEvents.hovered, {\n shapeId,\n mapId,\n });\n }\n\n // Always call callback if provided (for local state updates)\n if (onShapeHover) {\n onShapeHover(shape);\n }\n };\n\n /**\n * Render highlight sublayer (underneath main layer)\n * Note: Points with icons use coffin corners instead of highlight layer\n */\n private renderHighlightLayer(\n features: EditableShape['feature'][],\n ): GeoJsonLayer | null {\n const { selectedShapeId, showHighlight, highlightColor } = this.props;\n\n if (!selectedShapeId || showHighlight === false) {\n return null;\n }\n\n const selectedFeature = features.find(\n (f) => f.properties?.shapeId === selectedShapeId,\n );\n\n if (!selectedFeature) {\n return null;\n }\n\n // Skip highlight layer for Point geometries with icons - they use coffin corners instead\n // Points without icons should still show the highlight layer\n if (selectedFeature.geometry.type === 'Point') {\n const hasIcon = !!selectedFeature.properties?.styleProperties?.icon;\n if (hasIcon) {\n return null;\n }\n }\n\n return new GeoJsonLayer({\n id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY_HIGHLIGHT}`,\n // biome-ignore lint/suspicious/noExplicitAny: GeoJsonLayer accepts various feature formats\n data: [selectedFeature] as any,\n\n // Styling\n filled: true,\n stroked: true,\n lineWidthUnits: 'pixels',\n lineWidthMinPixels: MAP_INTERACTION.LINE_WIDTH_MIN_PIXELS,\n getFillColor: () => [0, 0, 0, 0], // Transparent fill\n getLineColor: () => highlightColor || getHighlightColor(),\n getLineWidth: getHighlightLineWidth,\n\n // Behavior\n pickable: false,\n updateTriggers: {\n getLineColor: [highlightColor],\n getLineWidth: [selectedShapeId, features],\n },\n });\n }\n\n /**\n * Render coffin corners layer for Point geometries that have icons on hover/select\n * Coffin corners provide visual feedback for points instead of highlight layer\n */\n private renderCoffinCornersLayer(\n features: EditableShape['feature'][],\n ): IconLayer | null {\n const { selectedShapeId } = this.props;\n\n // Find point features that need coffin corners (hovered or selected)\n const pointFeatures = features.filter((f) => {\n if (f.geometry.type !== 'Point') {\n return false;\n }\n const hasIcon = !!f.properties?.styleProperties?.icon;\n if (!hasIcon) {\n return false;\n }\n\n const shapeId = f.properties?.shapeId;\n const isSelected = shapeId === selectedShapeId;\n const isHovered =\n this.state?.hoverIndex !== undefined &&\n features.indexOf(f) === this.state.hoverIndex;\n\n return isSelected || isHovered;\n });\n\n if (pointFeatures.length === 0) {\n return null;\n }\n\n // Get icon atlas from first point feature (all should share the same atlas)\n const firstPointIcon = pointFeatures[0]?.properties?.styleProperties?.icon;\n const iconAtlas = firstPointIcon?.atlas;\n const iconMapping = firstPointIcon?.mapping;\n\n if (!iconAtlas) {\n return null;\n }\n\n if (!iconMapping) {\n return null;\n }\n\n // Add coffin corners icons to the mapping\n const extendedMapping = {\n ...iconMapping,\n [COFFIN_CORNERS.HOVER_ICON]: {\n x: 0,\n y: 0,\n width: 76,\n height: 76,\n mask: false,\n },\n [COFFIN_CORNERS.SELECTED_ICON]: {\n x: 76,\n y: 0,\n width: 76,\n height: 76,\n mask: false,\n },\n [COFFIN_CORNERS.SELECTED_HOVER_ICON]: {\n x: 152,\n y: 0,\n width: 76,\n height: 76,\n mask: false,\n },\n };\n\n return new IconLayer({\n id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-coffin-corners`,\n data: pointFeatures,\n iconAtlas,\n iconMapping: extendedMapping,\n getIcon: (d: EditableShape['feature']) => {\n const shapeId = d.properties?.shapeId;\n const isSelected = shapeId === selectedShapeId;\n const isHovered =\n this.state?.hoverIndex !== undefined &&\n features.indexOf(d) === this.state.hoverIndex;\n\n if (isSelected && isHovered) {\n return COFFIN_CORNERS.SELECTED_HOVER_ICON;\n }\n if (isSelected) {\n return COFFIN_CORNERS.SELECTED_ICON;\n }\n return COFFIN_CORNERS.HOVER_ICON;\n },\n getSize: COFFIN_CORNERS.SIZE,\n getPosition: (d: EditableShape['feature']) => {\n const coords =\n d.geometry.type === 'Point' ? d.geometry.coordinates : [0, 0];\n return coords as [number, number];\n },\n getPixelOffset: (d: EditableShape['feature']) => {\n const iconSize =\n d.properties?.styleProperties?.icon?.size ??\n MAP_INTERACTION.ICON_SIZE;\n // Center the coffin corners on the point icon\n return [-1, -iconSize / 2];\n },\n billboard: false,\n pickable: false,\n updateTriggers: {\n getIcon: [selectedShapeId, this.state?.hoverIndex],\n data: [features, selectedShapeId, this.state?.hoverIndex],\n },\n });\n }\n\n /**\n * Extract icon configuration from features in a single pass.\n * Returns the first icon's atlas and mapping (all shapes share the same atlas).\n * Uses early return for O(1) best case when first feature has icons.\n */\n private getIconConfig(features: EditableShape['feature'][]): {\n hasIcons: boolean;\n atlas?: string;\n mapping?: Record<\n string,\n { x: number; y: number; width: number; height: number; mask?: boolean }\n >;\n } {\n for (const f of features) {\n const icon = f.properties?.styleProperties?.icon;\n if (icon) {\n return {\n hasIcons: true,\n atlas: icon.atlas,\n mapping: icon.mapping,\n };\n }\n }\n return { hasIcons: false };\n }\n\n /**\n * Render main shapes layer\n */\n private renderMainLayer(features: EditableShape['feature'][]): GeoJsonLayer {\n const { pickable, applyBaseOpacity, selectedShapeId } = this.props;\n\n // Single-pass icon config extraction (O(1) best case with early return)\n const {\n hasIcons,\n atlas: iconAtlas,\n mapping: iconMapping,\n } = this.getIconConfig(features);\n\n return new GeoJsonLayer({\n id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}`,\n // biome-ignore lint/suspicious/noExplicitAny: GeoJsonLayer accepts various feature formats\n data: features as any,\n\n // Styling\n filled: true,\n stroked: true,\n getFillColor: (d: EditableShape['feature']) =>\n getFillColor(d, applyBaseOpacity),\n getLineColor: getStrokeColor,\n getLineWidth: (d, info) => {\n const isHovered = info?.index === this.state?.hoverIndex;\n return getHoverLineWidth(d, isHovered);\n },\n lineWidthUnits: 'pixels',\n lineWidthMinPixels: MAP_INTERACTION.LINE_WIDTH_MIN_PIXELS,\n lineWidthMaxPixels: 20,\n\n // Points - use icons if any feature has icon config, otherwise circles\n pointType: hasIcons ? 'icon' : 'circle',\n getPointRadius: (d) => {\n const iconSize = d.properties?.styleProperties?.icon?.size;\n return iconSize ?? 2;\n },\n pointRadiusUnits: 'pixels',\n\n // Icon configuration (only used if pointType includes 'icon')\n ...(hasIcons && iconAtlas ? { iconAtlas } : {}),\n ...(hasIcons && iconMapping ? { iconMapping } : {}),\n ...(hasIcons\n ? {\n getIcon: (d: EditableShape['feature']) =>\n d.properties?.styleProperties?.icon?.name ?? 'marker',\n getIconSize: (d: EditableShape['feature']) => {\n return (\n d.properties?.styleProperties?.icon?.size ??\n MAP_INTERACTION.ICON_SIZE\n );\n },\n getIconColor: getStrokeColor,\n getIconPixelOffset: (d: EditableShape['feature']) => {\n const iconSize =\n d.properties?.styleProperties?.icon?.size ??\n MAP_INTERACTION.ICON_SIZE;\n return [-1, -iconSize / 2];\n },\n iconBillboard: false,\n }\n : {}),\n\n // Dash pattern support - selected shapes get dotted border\n extensions: [new PathStyleExtension({ dash: true })],\n getDashArray: (d: EditableShape['feature']) => {\n const isSelected = d.properties?.shapeId === selectedShapeId;\n if (isSelected) {\n return DASH_ARRAYS.dotted;\n }\n return getDashArray(d);\n },\n\n // Behavior\n pickable,\n autoHighlight: false, // We handle highlighting manually\n // Note: onClick and onHover are handled via getPickingInfo() override\n\n // Update triggers\n updateTriggers: {\n getFillColor: [features, applyBaseOpacity],\n getLineColor: [features],\n getLineWidth: [features, this.state?.hoverIndex],\n getDashArray: [features, selectedShapeId],\n getPointRadius: [features],\n ...(hasIcons\n ? {\n getIcon: [features],\n getIconSize: [features],\n getIconColor: [features],\n getIconPixelOffset: [features],\n }\n : {}),\n },\n });\n }\n\n /**\n * Render labels layer\n */\n private renderLabelsLayer(): ReturnType<typeof createShapeLabelLayer> | null {\n const { showLabels, data, labelOptions } = this.props;\n\n if (!showLabels) {\n return null;\n }\n\n return createShapeLabelLayer({\n id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY_LABELS}`,\n data,\n labelOptions,\n });\n }\n\n /**\n * Render all sublayers\n */\n renderLayers(): Layer[] {\n // Compute features once per render cycle for performance\n const features = this.getFeaturesWithId();\n\n return [\n this.renderHighlightLayer(features),\n this.renderCoffinCornersLayer(features),\n this.renderMainLayer(features),\n this.renderLabelsLayer(),\n ].filter(Boolean) as Layer[];\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
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 { EditableShape } from "../shared/types.js";
|
|
14
|
+
import { LabelPositionOptions } from "./utils/labels.js";
|
|
15
|
+
import { TextLayer } from "@deck.gl/layers";
|
|
16
|
+
|
|
17
|
+
//#region src/deckgl/shapes/display-shape-layer/shape-label-layer.d.ts
|
|
18
|
+
/**
|
|
19
|
+
* Props for creating a shape label layer
|
|
20
|
+
*/
|
|
21
|
+
interface ShapeLabelLayerProps {
|
|
22
|
+
/** Layer ID (defaults to DISPLAY_LABELS constant) */
|
|
23
|
+
id?: string;
|
|
24
|
+
/** Array of shapes to label */
|
|
25
|
+
data: EditableShape[];
|
|
26
|
+
/**
|
|
27
|
+
* Global label positioning options
|
|
28
|
+
* Per-shape properties in styleProperties take precedence
|
|
29
|
+
*/
|
|
30
|
+
labelOptions?: LabelPositionOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a TextLayer for rendering shape labels with intelligent positioning
|
|
34
|
+
*
|
|
35
|
+
* ## Features
|
|
36
|
+
* - **Geometry-aware positioning**: Different defaults for Point, LineString, Polygon, and Circle
|
|
37
|
+
* - **Three-tier priority system**: Per-shape properties > labelOptions > defaults
|
|
38
|
+
* - **Coordinate anchoring**: Position labels at start/middle/end (or edge positions for circles)
|
|
39
|
+
* - **Pixel-based offsets**: Consistent label placement at all zoom levels
|
|
40
|
+
* - **Text-only styling**: White uppercase text with black outline for legibility
|
|
41
|
+
* - **Position caching**: Label positions are computed once per shape using a WeakMap cache
|
|
42
|
+
*
|
|
43
|
+
* ## Label Positioning Priority
|
|
44
|
+
* 1. Per-shape `styleProperties` (highest priority)
|
|
45
|
+
* 2. Global `labelOptions` parameter
|
|
46
|
+
* 3. Geometry-specific defaults (fallback)
|
|
47
|
+
*
|
|
48
|
+
* @param props - Shape label layer configuration
|
|
49
|
+
* @returns Configured TextLayer instance
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const labelLayer = createShapeLabelLayer({
|
|
54
|
+
* id: 'my-labels',
|
|
55
|
+
* data: shapes,
|
|
56
|
+
* labelOptions: {
|
|
57
|
+
* circleLabelCoordinateAnchor: 'top',
|
|
58
|
+
* pointLabelOffset: [0, -20],
|
|
59
|
+
* },
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function createShapeLabelLayer(props: ShapeLabelLayerProps): TextLayer<EditableShape>;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { ShapeLabelLayerProps, createShapeLabelLayer };
|
|
66
|
+
//# sourceMappingURL=shape-label-layer.d.ts.map
|
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
'use client';
|
|
15
|
+
|
|
16
|
+
import { SHAPE_LAYER_IDS } from "../shared/constants.js";
|
|
17
|
+
import { getLabelPosition2d, getLabelText } from "./utils/labels.js";
|
|
18
|
+
import { TextLayer } from "@deck.gl/layers";
|
|
19
|
+
|
|
20
|
+
//#region src/deckgl/shapes/display-shape-layer/shape-label-layer.ts
|
|
21
|
+
/**
|
|
22
|
+
* Creates a cached label position getter to avoid computing position multiple times per shape.
|
|
23
|
+
* Uses WeakMap so positions are garbage collected when shapes are removed.
|
|
24
|
+
*/
|
|
25
|
+
function createCachedPositionGetter(labelOptions) {
|
|
26
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
27
|
+
const getNullable = (shape) => {
|
|
28
|
+
if (cache.has(shape)) return cache.get(shape) ?? null;
|
|
29
|
+
const position = getLabelPosition2d(shape, labelOptions);
|
|
30
|
+
cache.set(shape, position);
|
|
31
|
+
return position;
|
|
32
|
+
};
|
|
33
|
+
const getRequired = (shape) => {
|
|
34
|
+
const position = getNullable(shape);
|
|
35
|
+
if (!position) throw new Error("Shape has no valid position - should have been filtered");
|
|
36
|
+
return position;
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
getRequired,
|
|
40
|
+
getNullable
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a TextLayer for rendering shape labels with intelligent positioning
|
|
45
|
+
*
|
|
46
|
+
* ## Features
|
|
47
|
+
* - **Geometry-aware positioning**: Different defaults for Point, LineString, Polygon, and Circle
|
|
48
|
+
* - **Three-tier priority system**: Per-shape properties > labelOptions > defaults
|
|
49
|
+
* - **Coordinate anchoring**: Position labels at start/middle/end (or edge positions for circles)
|
|
50
|
+
* - **Pixel-based offsets**: Consistent label placement at all zoom levels
|
|
51
|
+
* - **Text-only styling**: White uppercase text with black outline for legibility
|
|
52
|
+
* - **Position caching**: Label positions are computed once per shape using a WeakMap cache
|
|
53
|
+
*
|
|
54
|
+
* ## Label Positioning Priority
|
|
55
|
+
* 1. Per-shape `styleProperties` (highest priority)
|
|
56
|
+
* 2. Global `labelOptions` parameter
|
|
57
|
+
* 3. Geometry-specific defaults (fallback)
|
|
58
|
+
*
|
|
59
|
+
* @param props - Shape label layer configuration
|
|
60
|
+
* @returns Configured TextLayer instance
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const labelLayer = createShapeLabelLayer({
|
|
65
|
+
* id: 'my-labels',
|
|
66
|
+
* data: shapes,
|
|
67
|
+
* labelOptions: {
|
|
68
|
+
* circleLabelCoordinateAnchor: 'top',
|
|
69
|
+
* pointLabelOffset: [0, -20],
|
|
70
|
+
* },
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function createShapeLabelLayer(props) {
|
|
75
|
+
const { id = SHAPE_LAYER_IDS.DISPLAY_LABELS, data, labelOptions } = props;
|
|
76
|
+
const { getRequired, getNullable } = createCachedPositionGetter(labelOptions);
|
|
77
|
+
return new TextLayer({
|
|
78
|
+
id,
|
|
79
|
+
data: data.filter((shape) => getNullable(shape) !== null),
|
|
80
|
+
getText: getLabelText,
|
|
81
|
+
getPosition: (d) => getRequired(d).coordinates,
|
|
82
|
+
getPixelOffset: (d) => getRequired(d).pixelOffset,
|
|
83
|
+
getTextAnchor: (d) => getRequired(d).textAnchor,
|
|
84
|
+
getAlignmentBaseline: (d) => getRequired(d).alignmentBaseline,
|
|
85
|
+
getColor: [
|
|
86
|
+
255,
|
|
87
|
+
255,
|
|
88
|
+
255,
|
|
89
|
+
255
|
|
90
|
+
],
|
|
91
|
+
getSize: 10,
|
|
92
|
+
getAngle: 0,
|
|
93
|
+
outlineWidth: 2,
|
|
94
|
+
outlineColor: [
|
|
95
|
+
0,
|
|
96
|
+
0,
|
|
97
|
+
0,
|
|
98
|
+
255
|
|
99
|
+
],
|
|
100
|
+
background: false,
|
|
101
|
+
fontFamily: "Roboto MonoVariable, monospace",
|
|
102
|
+
fontWeight: "bold",
|
|
103
|
+
fontSettings: { sdf: true },
|
|
104
|
+
updateTriggers: {
|
|
105
|
+
getPosition: [labelOptions],
|
|
106
|
+
getPixelOffset: [labelOptions],
|
|
107
|
+
getTextAnchor: [labelOptions],
|
|
108
|
+
getAlignmentBaseline: [labelOptions]
|
|
109
|
+
},
|
|
110
|
+
pickable: false
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
export { createShapeLabelLayer };
|
|
116
|
+
//# sourceMappingURL=shape-label-layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape-label-layer.js","names":[],"sources":["../../../../src/deckgl/shapes/display-shape-layer/shape-label-layer.ts"],"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'use client';\n\nimport { TextLayer } from '@deck.gl/layers';\nimport { SHAPE_LAYER_IDS } from '../shared/constants';\nimport {\n getLabelPosition2d,\n getLabelText,\n type LabelPosition2d,\n type LabelPositionOptions,\n} from './utils/labels';\nimport type { EditableShape } from '../shared/types';\n\n/**\n * Creates a cached label position getter to avoid computing position multiple times per shape.\n * Uses WeakMap so positions are garbage collected when shapes are removed.\n */\nfunction createCachedPositionGetter(\n labelOptions: LabelPositionOptions | undefined,\n) {\n const cache = new WeakMap<EditableShape, LabelPosition2d | null>();\n\n // Returns nullable position for filtering\n const getNullable = (shape: EditableShape): LabelPosition2d | null => {\n if (cache.has(shape)) {\n return cache.get(shape) ?? null;\n }\n const position = getLabelPosition2d(shape, labelOptions);\n cache.set(shape, position);\n return position;\n };\n\n // Returns position, throwing if null (use only after filtering)\n const getRequired = (shape: EditableShape): LabelPosition2d => {\n const position = getNullable(shape);\n if (!position) {\n throw new Error(\n 'Shape has no valid position - should have been filtered',\n );\n }\n return position;\n };\n\n return { getRequired, getNullable };\n}\n\n/**\n * Props for creating a shape label layer\n */\nexport interface ShapeLabelLayerProps {\n /** Layer ID (defaults to DISPLAY_LABELS constant) */\n id?: string;\n /** Array of shapes to label */\n data: EditableShape[];\n /**\n * Global label positioning options\n * Per-shape properties in styleProperties take precedence\n */\n labelOptions?: LabelPositionOptions;\n}\n\n/**\n * Creates a TextLayer for rendering shape labels with intelligent positioning\n *\n * ## Features\n * - **Geometry-aware positioning**: Different defaults for Point, LineString, Polygon, and Circle\n * - **Three-tier priority system**: Per-shape properties > labelOptions > defaults\n * - **Coordinate anchoring**: Position labels at start/middle/end (or edge positions for circles)\n * - **Pixel-based offsets**: Consistent label placement at all zoom levels\n * - **Text-only styling**: White uppercase text with black outline for legibility\n * - **Position caching**: Label positions are computed once per shape using a WeakMap cache\n *\n * ## Label Positioning Priority\n * 1. Per-shape `styleProperties` (highest priority)\n * 2. Global `labelOptions` parameter\n * 3. Geometry-specific defaults (fallback)\n *\n * @param props - Shape label layer configuration\n * @returns Configured TextLayer instance\n *\n * @example\n * ```tsx\n * const labelLayer = createShapeLabelLayer({\n * id: 'my-labels',\n * data: shapes,\n * labelOptions: {\n * circleLabelCoordinateAnchor: 'top',\n * pointLabelOffset: [0, -20],\n * },\n * });\n * ```\n */\nexport function createShapeLabelLayer(\n props: ShapeLabelLayerProps,\n): TextLayer<EditableShape> {\n const { id = SHAPE_LAYER_IDS.DISPLAY_LABELS, data, labelOptions } = props;\n\n // Create cached position getter to avoid computing position 4x per shape\n const { getRequired, getNullable } = createCachedPositionGetter(labelOptions);\n\n // Filter out shapes with invalid positions (null coordinates)\n const validData = data.filter((shape) => getNullable(shape) !== null);\n\n return new TextLayer<EditableShape>({\n id,\n data: validData,\n\n // Text content - uppercase\n getText: getLabelText,\n\n // Position - use cached getter for all position-related properties\n // getRequired is safe because we filtered out null positions above\n getPosition: (d: EditableShape) => getRequired(d).coordinates,\n getPixelOffset: (d: EditableShape) => getRequired(d).pixelOffset,\n getTextAnchor: (d: EditableShape) => getRequired(d).textAnchor,\n getAlignmentBaseline: (d: EditableShape) =>\n getRequired(d).alignmentBaseline,\n\n // Styling - white text with black outline, no background\n getColor: [255, 255, 255, 255], // White text\n getSize: 10,\n getAngle: 0,\n\n // Text outline for legibility (black stroke around white text)\n outlineWidth: 2,\n outlineColor: [0, 0, 0, 255], // Black outline\n\n // No background or border\n background: false,\n\n // Font\n fontFamily: 'Roboto MonoVariable, monospace',\n fontWeight: 'bold',\n fontSettings: {\n sdf: true,\n },\n\n // Update triggers - tell deck.gl to recalculate when labelOptions change\n updateTriggers: {\n getPosition: [labelOptions],\n getPixelOffset: [labelOptions],\n getTextAnchor: [labelOptions],\n getAlignmentBaseline: [labelOptions],\n },\n\n // Behavior\n pickable: false,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA4BA,SAAS,2BACP,cACA;CACA,MAAM,wBAAQ,IAAI,SAAgD;CAGlE,MAAM,eAAe,UAAiD;AACpE,MAAI,MAAM,IAAI,MAAM,CAClB,QAAO,MAAM,IAAI,MAAM,IAAI;EAE7B,MAAM,WAAW,mBAAmB,OAAO,aAAa;AACxD,QAAM,IAAI,OAAO,SAAS;AAC1B,SAAO;;CAIT,MAAM,eAAe,UAA0C;EAC7D,MAAM,WAAW,YAAY,MAAM;AACnC,MAAI,CAAC,SACH,OAAM,IAAI,MACR,0DACD;AAEH,SAAO;;AAGT,QAAO;EAAE;EAAa;EAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDrC,SAAgB,sBACd,OAC0B;CAC1B,MAAM,EAAE,KAAK,gBAAgB,gBAAgB,MAAM,iBAAiB;CAGpE,MAAM,EAAE,aAAa,gBAAgB,2BAA2B,aAAa;AAK7E,QAAO,IAAI,UAAyB;EAClC;EACA,MAJgB,KAAK,QAAQ,UAAU,YAAY,MAAM,KAAK,KAAK;EAOnE,SAAS;EAIT,cAAc,MAAqB,YAAY,EAAE,CAAC;EAClD,iBAAiB,MAAqB,YAAY,EAAE,CAAC;EACrD,gBAAgB,MAAqB,YAAY,EAAE,CAAC;EACpD,uBAAuB,MACrB,YAAY,EAAE,CAAC;EAGjB,UAAU;GAAC;GAAK;GAAK;GAAK;GAAI;EAC9B,SAAS;EACT,UAAU;EAGV,cAAc;EACd,cAAc;GAAC;GAAG;GAAG;GAAG;GAAI;EAG5B,YAAY;EAGZ,YAAY;EACZ,YAAY;EACZ,cAAc,EACZ,KAAK,MACN;EAGD,gBAAgB;GACd,aAAa,CAAC,aAAa;GAC3B,gBAAgB,CAAC,aAAa;GAC9B,eAAe,CAAC,aAAa;GAC7B,sBAAsB,CAAC,aAAa;GACrC;EAGD,UAAU;EACX,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
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 { ShapeId } from "../shared/types.js";
|
|
14
|
+
import { UniqueId } from "@accelint/core";
|
|
15
|
+
|
|
16
|
+
//#region src/deckgl/shapes/display-shape-layer/store.d.ts
|
|
17
|
+
/**
|
|
18
|
+
* Creates or retrieves a cached subscription function for a given mapId.
|
|
19
|
+
* Uses a fan-out pattern: 1 bus listener -> N React subscribers.
|
|
20
|
+
* Automatically cleans up selection state when the last subscriber unsubscribes.
|
|
21
|
+
*
|
|
22
|
+
* @param mapId - The unique identifier for the map instance
|
|
23
|
+
* @returns A subscription function for useSyncExternalStore
|
|
24
|
+
*/
|
|
25
|
+
declare function getOrCreateSubscription(mapId: UniqueId): (onStoreChange: () => void) => () => void;
|
|
26
|
+
/**
|
|
27
|
+
* Creates or retrieves a cached snapshot function for a given mapId.
|
|
28
|
+
* The selection ID returned gets equality checked, so it needs to be stable or React re-renders unnecessarily.
|
|
29
|
+
*
|
|
30
|
+
* @param mapId - The unique identifier for the map instance
|
|
31
|
+
* @returns A snapshot function for useSyncExternalStore
|
|
32
|
+
*/
|
|
33
|
+
declare function getOrCreateSnapshot(mapId: UniqueId): () => ShapeId | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Creates or retrieves a cached server snapshot function for a given mapId.
|
|
36
|
+
* Server snapshots always return undefined since selection state is client-only.
|
|
37
|
+
* Required for SSR/RSC compatibility with useSyncExternalStore.
|
|
38
|
+
*
|
|
39
|
+
* @param mapId - The unique identifier for the map instance
|
|
40
|
+
* @returns A server snapshot function for useSyncExternalStore
|
|
41
|
+
*/
|
|
42
|
+
declare function getOrCreateServerSnapshot(mapId: UniqueId): () => ShapeId | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Creates or retrieves a cached setSelectedId function for a given mapId.
|
|
45
|
+
* This maintains referential stability for the function reference.
|
|
46
|
+
*
|
|
47
|
+
* @param mapId - The unique identifier for the map instance
|
|
48
|
+
* @returns A setSelectedId function for this instance
|
|
49
|
+
*/
|
|
50
|
+
declare function getOrCreateSetSelectedId(mapId: UniqueId): (id: ShapeId | undefined) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Creates or retrieves a cached clearSelection function for a given mapId.
|
|
53
|
+
* This maintains referential stability for the function reference.
|
|
54
|
+
*
|
|
55
|
+
* Note: This always emits a deselected event, even if nothing is currently selected.
|
|
56
|
+
* This matches the original behavior and allows consumers to use clearSelection
|
|
57
|
+
* as a "force deselect" without needing to check selection state first.
|
|
58
|
+
*
|
|
59
|
+
* @param mapId - The unique identifier for the map instance
|
|
60
|
+
* @returns A clearSelection function for this instance
|
|
61
|
+
*/
|
|
62
|
+
declare function getOrCreateClearSelection(mapId: UniqueId): () => void;
|
|
63
|
+
/**
|
|
64
|
+
* Get the current selected shape ID for a given map instance (direct access, not reactive).
|
|
65
|
+
* @internal - For internal map-toolkit use only
|
|
66
|
+
*
|
|
67
|
+
* @param mapId - The unique identifier for the map instance
|
|
68
|
+
* @returns The currently selected shape ID, or undefined
|
|
69
|
+
*/
|
|
70
|
+
declare function getSelectedShapeId(mapId: UniqueId): ShapeId | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Manually clear all selection state for a specific mapId.
|
|
73
|
+
* This is typically not needed as cleanup happens automatically when all subscribers unmount.
|
|
74
|
+
* Use this only in advanced scenarios where manual cleanup is required.
|
|
75
|
+
*
|
|
76
|
+
* @param mapId - The unique identifier for the map instance to clear
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* // Manual cleanup (rarely needed)
|
|
81
|
+
* clearSelectionState('my-map-instance');
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare function clearSelectionState(mapId: UniqueId): void;
|
|
85
|
+
//#endregion
|
|
86
|
+
export { clearSelectionState, getOrCreateClearSelection, getOrCreateServerSnapshot, getOrCreateSetSelectedId, getOrCreateSnapshot, getOrCreateSubscription, getSelectedShapeId };
|
|
87
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,316 @@
|
|
|
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 { MapEvents } from "../../base-map/events.js";
|
|
15
|
+
import { ShapeEvents } from "../shared/events.js";
|
|
16
|
+
import { Broadcast } from "@accelint/bus";
|
|
17
|
+
|
|
18
|
+
//#region src/deckgl/shapes/display-shape-layer/store.ts
|
|
19
|
+
/**
|
|
20
|
+
* Shape Selection Store
|
|
21
|
+
*
|
|
22
|
+
* This module provides a store pattern for managing shape selection state,
|
|
23
|
+
* designed to work with React's `useSyncExternalStore` hook.
|
|
24
|
+
*
|
|
25
|
+
* ## Architecture
|
|
26
|
+
*
|
|
27
|
+
* The store uses a fan-out pattern similar to `map-cursor/store.ts` and `map-mode/store.ts`:
|
|
28
|
+
* - **1 bus listener per mapId** - Regardless of how many React components subscribe
|
|
29
|
+
* - **N React subscribers** - Each component gets notified via `useSyncExternalStore`
|
|
30
|
+
* - **Automatic cleanup** - Bus listeners are removed when the last subscriber unmounts
|
|
31
|
+
*
|
|
32
|
+
* ## Why This Pattern?
|
|
33
|
+
*
|
|
34
|
+
* Without this pattern, using `useOn` directly in each React component would
|
|
35
|
+
* create N bus listeners for N components subscribing to the same events.
|
|
36
|
+
* The fan-out pattern ensures exactly 1 bus listener per mapId, regardless
|
|
37
|
+
* of how many React components need the state. This also provides proper
|
|
38
|
+
* cleanup semantics that prevent listener accumulation during HMR.
|
|
39
|
+
*
|
|
40
|
+
* ## Usage
|
|
41
|
+
*
|
|
42
|
+
* This module is internal to `useShapeSelection`. Use the hook instead:
|
|
43
|
+
*
|
|
44
|
+
* ```tsx
|
|
45
|
+
* import { useShapeSelection } from '@accelint/map-toolkit/deckgl/shapes';
|
|
46
|
+
*
|
|
47
|
+
* const { selectedId, setSelectedId, clearSelection } = useShapeSelection(mapId);
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @module
|
|
51
|
+
*/
|
|
52
|
+
/**
|
|
53
|
+
* Typed event bus instances for shape and map events
|
|
54
|
+
*/
|
|
55
|
+
const shapeBus = Broadcast.getInstance();
|
|
56
|
+
const mapBus = Broadcast.getInstance();
|
|
57
|
+
/**
|
|
58
|
+
* Store for shape selection state keyed by mapId
|
|
59
|
+
*/
|
|
60
|
+
const selectionStore = /* @__PURE__ */ new Map();
|
|
61
|
+
/**
|
|
62
|
+
* Track React component subscribers per mapId (for fan-out notifications).
|
|
63
|
+
* Each Set contains onStoreChange callbacks from useSyncExternalStore.
|
|
64
|
+
*/
|
|
65
|
+
const componentSubscribers = /* @__PURE__ */ new Map();
|
|
66
|
+
/**
|
|
67
|
+
* Cache of bus unsubscribe functions (1 per mapId).
|
|
68
|
+
* This ensures we only have one bus listener per map instance, regardless of
|
|
69
|
+
* how many React components subscribe to it.
|
|
70
|
+
*/
|
|
71
|
+
const busUnsubscribers = /* @__PURE__ */ new Map();
|
|
72
|
+
/**
|
|
73
|
+
* Cache of subscription functions per mapId to avoid recreating on every render
|
|
74
|
+
*/
|
|
75
|
+
const subscriptionCache = /* @__PURE__ */ new Map();
|
|
76
|
+
/**
|
|
77
|
+
* Cache of snapshot functions per mapId to maintain referential stability
|
|
78
|
+
*/
|
|
79
|
+
const snapshotCache = /* @__PURE__ */ new Map();
|
|
80
|
+
/**
|
|
81
|
+
* Cache of server snapshot functions per mapId to maintain referential stability.
|
|
82
|
+
* Server snapshots always return undefined since selection state is client-only.
|
|
83
|
+
*/
|
|
84
|
+
const serverSnapshotCache = /* @__PURE__ */ new Map();
|
|
85
|
+
/**
|
|
86
|
+
* Cache of setSelectedId functions per mapId to maintain referential stability
|
|
87
|
+
*/
|
|
88
|
+
const setSelectedIdCache = /* @__PURE__ */ new Map();
|
|
89
|
+
/**
|
|
90
|
+
* Cache of clearSelection functions per mapId to maintain referential stability
|
|
91
|
+
*/
|
|
92
|
+
const clearSelectionCache = /* @__PURE__ */ new Map();
|
|
93
|
+
/**
|
|
94
|
+
* All state caches that need cleanup when an instance is removed
|
|
95
|
+
*/
|
|
96
|
+
const stateCaches = [
|
|
97
|
+
selectionStore,
|
|
98
|
+
componentSubscribers,
|
|
99
|
+
subscriptionCache,
|
|
100
|
+
snapshotCache,
|
|
101
|
+
serverSnapshotCache,
|
|
102
|
+
setSelectedIdCache,
|
|
103
|
+
clearSelectionCache
|
|
104
|
+
];
|
|
105
|
+
/**
|
|
106
|
+
* Clear all cached state for a given mapId
|
|
107
|
+
*/
|
|
108
|
+
function clearAllCaches(mapId) {
|
|
109
|
+
for (const cache of stateCaches) cache.delete(mapId);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get or create selection state for a given mapId
|
|
113
|
+
*/
|
|
114
|
+
function getOrCreateState(mapId) {
|
|
115
|
+
if (!selectionStore.has(mapId)) selectionStore.set(mapId, { selectedId: void 0 });
|
|
116
|
+
return selectionStore.get(mapId);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get current selection snapshot for a given map instance (for useSyncExternalStore)
|
|
120
|
+
*/
|
|
121
|
+
function getSnapshot(mapId) {
|
|
122
|
+
return selectionStore.get(mapId)?.selectedId;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Notify all React subscribers for a given mapId
|
|
126
|
+
*/
|
|
127
|
+
function notifySubscribers(mapId) {
|
|
128
|
+
const subscribers = componentSubscribers.get(mapId);
|
|
129
|
+
if (subscribers) for (const onStoreChange of subscribers) onStoreChange();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Ensures a single bus listener exists for the given mapId.
|
|
133
|
+
* All React subscribers will be notified via fan-out when the bus events fire.
|
|
134
|
+
* This prevents creating N bus listeners for N React components.
|
|
135
|
+
*
|
|
136
|
+
* @param mapId - The unique identifier for the map instance
|
|
137
|
+
*/
|
|
138
|
+
function ensureBusListener(mapId) {
|
|
139
|
+
if (busUnsubscribers.has(mapId)) return;
|
|
140
|
+
const state = getOrCreateState(mapId);
|
|
141
|
+
const unsubSelected = shapeBus.on(ShapeEvents.selected, (event) => {
|
|
142
|
+
if (event.payload.mapId !== mapId) return;
|
|
143
|
+
const previousId = state.selectedId;
|
|
144
|
+
state.selectedId = event.payload.shapeId;
|
|
145
|
+
if (previousId !== state.selectedId) notifySubscribers(mapId);
|
|
146
|
+
});
|
|
147
|
+
const unsubDeselected = shapeBus.on(ShapeEvents.deselected, (event) => {
|
|
148
|
+
if (event.payload.mapId !== mapId) return;
|
|
149
|
+
const previousId = state.selectedId;
|
|
150
|
+
state.selectedId = void 0;
|
|
151
|
+
if (previousId !== state.selectedId) notifySubscribers(mapId);
|
|
152
|
+
});
|
|
153
|
+
const unsubClick = mapBus.on(MapEvents.click, (event) => {
|
|
154
|
+
if (state.selectedId && event.payload.id === mapId && event.payload.info.index === -1) shapeBus.emit(ShapeEvents.deselected, { mapId });
|
|
155
|
+
});
|
|
156
|
+
busUnsubscribers.set(mapId, () => {
|
|
157
|
+
unsubSelected();
|
|
158
|
+
unsubDeselected();
|
|
159
|
+
unsubClick();
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Cleans up the bus listener if no React subscribers remain.
|
|
164
|
+
*
|
|
165
|
+
* @param mapId - The unique identifier for the map instance
|
|
166
|
+
*/
|
|
167
|
+
function cleanupBusListenerIfNeeded(mapId) {
|
|
168
|
+
const subscribers = componentSubscribers.get(mapId);
|
|
169
|
+
if (!subscribers || subscribers.size === 0) {
|
|
170
|
+
const unsub = busUnsubscribers.get(mapId);
|
|
171
|
+
if (unsub) {
|
|
172
|
+
unsub();
|
|
173
|
+
busUnsubscribers.delete(mapId);
|
|
174
|
+
}
|
|
175
|
+
clearAllCaches(mapId);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Creates or retrieves a cached subscription function for a given mapId.
|
|
180
|
+
* Uses a fan-out pattern: 1 bus listener -> N React subscribers.
|
|
181
|
+
* Automatically cleans up selection state when the last subscriber unsubscribes.
|
|
182
|
+
*
|
|
183
|
+
* @param mapId - The unique identifier for the map instance
|
|
184
|
+
* @returns A subscription function for useSyncExternalStore
|
|
185
|
+
*/
|
|
186
|
+
function getOrCreateSubscription(mapId) {
|
|
187
|
+
let subscription = subscriptionCache.get(mapId);
|
|
188
|
+
if (!subscription) {
|
|
189
|
+
subscription = (onStoreChange) => {
|
|
190
|
+
getOrCreateState(mapId);
|
|
191
|
+
ensureBusListener(mapId);
|
|
192
|
+
let subscriberSet = componentSubscribers.get(mapId);
|
|
193
|
+
if (!subscriberSet) {
|
|
194
|
+
subscriberSet = /* @__PURE__ */ new Set();
|
|
195
|
+
componentSubscribers.set(mapId, subscriberSet);
|
|
196
|
+
}
|
|
197
|
+
subscriberSet.add(onStoreChange);
|
|
198
|
+
return () => {
|
|
199
|
+
const currentSubscriberSet = componentSubscribers.get(mapId);
|
|
200
|
+
if (currentSubscriberSet) currentSubscriberSet.delete(onStoreChange);
|
|
201
|
+
cleanupBusListenerIfNeeded(mapId);
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
subscriptionCache.set(mapId, subscription);
|
|
205
|
+
}
|
|
206
|
+
return subscription;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Creates or retrieves a cached snapshot function for a given mapId.
|
|
210
|
+
* The selection ID returned gets equality checked, so it needs to be stable or React re-renders unnecessarily.
|
|
211
|
+
*
|
|
212
|
+
* @param mapId - The unique identifier for the map instance
|
|
213
|
+
* @returns A snapshot function for useSyncExternalStore
|
|
214
|
+
*/
|
|
215
|
+
function getOrCreateSnapshot(mapId) {
|
|
216
|
+
let snapshot = snapshotCache.get(mapId);
|
|
217
|
+
if (!snapshot) {
|
|
218
|
+
snapshot = () => getSnapshot(mapId);
|
|
219
|
+
snapshotCache.set(mapId, snapshot);
|
|
220
|
+
}
|
|
221
|
+
return snapshot;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Creates or retrieves a cached server snapshot function for a given mapId.
|
|
225
|
+
* Server snapshots always return undefined since selection state is client-only.
|
|
226
|
+
* Required for SSR/RSC compatibility with useSyncExternalStore.
|
|
227
|
+
*
|
|
228
|
+
* @param mapId - The unique identifier for the map instance
|
|
229
|
+
* @returns A server snapshot function for useSyncExternalStore
|
|
230
|
+
*/
|
|
231
|
+
function getOrCreateServerSnapshot(mapId) {
|
|
232
|
+
let serverSnapshot = serverSnapshotCache.get(mapId);
|
|
233
|
+
if (!serverSnapshot) {
|
|
234
|
+
serverSnapshot = () => void 0;
|
|
235
|
+
serverSnapshotCache.set(mapId, serverSnapshot);
|
|
236
|
+
}
|
|
237
|
+
return serverSnapshot;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Creates or retrieves a cached setSelectedId function for a given mapId.
|
|
241
|
+
* This maintains referential stability for the function reference.
|
|
242
|
+
*
|
|
243
|
+
* @param mapId - The unique identifier for the map instance
|
|
244
|
+
* @returns A setSelectedId function for this instance
|
|
245
|
+
*/
|
|
246
|
+
function getOrCreateSetSelectedId(mapId) {
|
|
247
|
+
let setSelectedId = setSelectedIdCache.get(mapId);
|
|
248
|
+
if (!setSelectedId) {
|
|
249
|
+
setSelectedId = (id) => {
|
|
250
|
+
const previousId = getOrCreateState(mapId).selectedId;
|
|
251
|
+
if (id === void 0 && previousId !== void 0) shapeBus.emit(ShapeEvents.deselected, { mapId });
|
|
252
|
+
else if (id !== void 0 && previousId !== id) shapeBus.emit(ShapeEvents.selected, {
|
|
253
|
+
shapeId: id,
|
|
254
|
+
mapId
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
setSelectedIdCache.set(mapId, setSelectedId);
|
|
258
|
+
}
|
|
259
|
+
return setSelectedId;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Creates or retrieves a cached clearSelection function for a given mapId.
|
|
263
|
+
* This maintains referential stability for the function reference.
|
|
264
|
+
*
|
|
265
|
+
* Note: This always emits a deselected event, even if nothing is currently selected.
|
|
266
|
+
* This matches the original behavior and allows consumers to use clearSelection
|
|
267
|
+
* as a "force deselect" without needing to check selection state first.
|
|
268
|
+
*
|
|
269
|
+
* @param mapId - The unique identifier for the map instance
|
|
270
|
+
* @returns A clearSelection function for this instance
|
|
271
|
+
*/
|
|
272
|
+
function getOrCreateClearSelection(mapId) {
|
|
273
|
+
let clearSelection = clearSelectionCache.get(mapId);
|
|
274
|
+
if (!clearSelection) {
|
|
275
|
+
clearSelection = () => {
|
|
276
|
+
shapeBus.emit(ShapeEvents.deselected, { mapId });
|
|
277
|
+
};
|
|
278
|
+
clearSelectionCache.set(mapId, clearSelection);
|
|
279
|
+
}
|
|
280
|
+
return clearSelection;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get the current selected shape ID for a given map instance (direct access, not reactive).
|
|
284
|
+
* @internal - For internal map-toolkit use only
|
|
285
|
+
*
|
|
286
|
+
* @param mapId - The unique identifier for the map instance
|
|
287
|
+
* @returns The currently selected shape ID, or undefined
|
|
288
|
+
*/
|
|
289
|
+
function getSelectedShapeId(mapId) {
|
|
290
|
+
return getSnapshot(mapId);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Manually clear all selection state for a specific mapId.
|
|
294
|
+
* This is typically not needed as cleanup happens automatically when all subscribers unmount.
|
|
295
|
+
* Use this only in advanced scenarios where manual cleanup is required.
|
|
296
|
+
*
|
|
297
|
+
* @param mapId - The unique identifier for the map instance to clear
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```tsx
|
|
301
|
+
* // Manual cleanup (rarely needed)
|
|
302
|
+
* clearSelectionState('my-map-instance');
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
function clearSelectionState(mapId) {
|
|
306
|
+
const unsub = busUnsubscribers.get(mapId);
|
|
307
|
+
if (unsub) {
|
|
308
|
+
unsub();
|
|
309
|
+
busUnsubscribers.delete(mapId);
|
|
310
|
+
}
|
|
311
|
+
clearAllCaches(mapId);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
//#endregion
|
|
315
|
+
export { clearSelectionState, getOrCreateClearSelection, getOrCreateServerSnapshot, getOrCreateSetSelectedId, getOrCreateSnapshot, getOrCreateSubscription, getSelectedShapeId };
|
|
316
|
+
//# sourceMappingURL=store.js.map
|