@accelint/map-toolkit 2.0.0 → 3.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +8 -1
  3. package/catalog-info.yaml +9 -6
  4. package/dist/deckgl/base-map/index.d.ts +2 -2
  5. package/dist/deckgl/base-map/provider.d.ts +2 -2
  6. package/dist/deckgl/extensions/coffin-corner/coffin-corner-extension.d.ts +144 -0
  7. package/dist/deckgl/extensions/coffin-corner/coffin-corner-extension.js +535 -0
  8. package/dist/deckgl/extensions/coffin-corner/coffin-corner-extension.js.map +1 -0
  9. package/dist/deckgl/extensions/coffin-corner/index.d.ts +17 -0
  10. package/dist/deckgl/extensions/coffin-corner/index.js +19 -0
  11. package/dist/deckgl/extensions/coffin-corner/store.d.ts +96 -0
  12. package/dist/deckgl/extensions/coffin-corner/store.js +173 -0
  13. package/dist/deckgl/extensions/coffin-corner/store.js.map +1 -0
  14. package/dist/deckgl/extensions/coffin-corner/types.d.ts +76 -0
  15. package/dist/deckgl/extensions/coffin-corner/types.js +27 -0
  16. package/dist/deckgl/extensions/coffin-corner/types.js.map +1 -0
  17. package/dist/deckgl/extensions/coffin-corner/use-coffin-corner.d.ts +81 -0
  18. package/dist/deckgl/extensions/coffin-corner/use-coffin-corner.js +75 -0
  19. package/dist/deckgl/extensions/coffin-corner/use-coffin-corner.js.map +1 -0
  20. package/dist/deckgl/extensions/index.d.ts +15 -0
  21. package/dist/deckgl/extensions/index.js +16 -0
  22. package/dist/deckgl/index.d.ts +6 -1
  23. package/dist/deckgl/index.js +5 -1
  24. package/dist/deckgl/shapes/display-shape-layer/constants.js +6 -15
  25. package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
  26. package/dist/deckgl/shapes/display-shape-layer/index.d.ts +31 -15
  27. package/dist/deckgl/shapes/display-shape-layer/index.js +97 -78
  28. package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -1
  29. package/dist/deckgl/shapes/display-shape-layer/types.d.ts +8 -0
  30. package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js +3 -48
  31. package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js.map +1 -1
  32. package/dist/deckgl/shapes/display-shape-layer/utils/radius-label.js +53 -0
  33. package/dist/deckgl/shapes/display-shape-layer/utils/radius-label.js.map +1 -0
  34. package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +7 -3
  35. package/dist/deckgl/shapes/draw-shape-layer/index.js +7 -3
  36. package/dist/deckgl/shapes/draw-shape-layer/index.js.map +1 -1
  37. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +4 -2
  38. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
  39. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +3 -2
  40. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js.map +1 -1
  41. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +5 -2
  42. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js.map +1 -1
  43. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +5 -2
  44. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js.map +1 -1
  45. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +7 -2
  46. package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js.map +1 -1
  47. package/dist/deckgl/shapes/draw-shape-layer/types.d.ts +2 -2
  48. package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +7 -4
  49. package/dist/deckgl/shapes/edit-shape-layer/index.js +22 -8
  50. package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
  51. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +3 -2
  52. package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -1
  53. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +4 -2
  54. package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
  55. package/dist/deckgl/shapes/edit-shape-layer/store.js +15 -4
  56. package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
  57. package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +4 -2
  58. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.d.ts +1 -1
  59. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +7 -3
  60. package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js.map +1 -1
  61. package/dist/deckgl/shapes/index.d.ts +3 -2
  62. package/dist/deckgl/shapes/index.js +2 -1
  63. package/dist/deckgl/shapes/shared/constants.js +1 -1
  64. package/dist/deckgl/shapes/shared/types.d.ts +11 -4
  65. package/dist/deckgl/shapes/shared/types.js.map +1 -1
  66. package/dist/deckgl/shapes/shared/utils/duplicate-shape.d.ts +56 -0
  67. package/dist/deckgl/shapes/shared/utils/duplicate-shape.js +131 -0
  68. package/dist/deckgl/shapes/shared/utils/duplicate-shape.js.map +1 -0
  69. package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -1
  70. package/dist/deckgl/shapes/shared/utils/layer-config.js +10 -7
  71. package/dist/deckgl/shapes/shared/utils/layer-config.js.map +1 -1
  72. package/dist/deckgl/symbol-layer/fiber.d.ts +3 -1
  73. package/dist/deckgl/symbol-layer/fiber.js.map +1 -1
  74. package/dist/shared/units.d.ts +15 -56
  75. package/dist/shared/units.js +1 -52
  76. package/dist/shared/units.js.map +1 -1
  77. package/dist/viewport/index.d.ts +2 -3
  78. package/dist/viewport/index.js +1 -2
  79. package/dist/viewport/types.d.ts +8 -4
  80. package/dist/viewport/utils.d.ts +3 -3
  81. package/dist/viewport/utils.js +16 -8
  82. package/dist/viewport/utils.js.map +1 -1
  83. package/dist/viewport/viewport-size.d.ts +4 -3
  84. package/dist/viewport/viewport-size.js +2 -2
  85. package/dist/viewport/viewport-size.js.map +1 -1
  86. package/package.json +13 -6
  87. package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js +0 -50
  88. package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js.map +0 -1
@@ -14,6 +14,7 @@
14
14
  'use client';
15
15
 
16
16
  import { DEFAULT_COLORS } from "../shared/constants.js";
17
+ import { CoffinCornerExtension } from "../../extensions/coffin-corner/coffin-corner-extension.js";
17
18
  import { PathStyleExtension } from "@deck.gl/extensions";
18
19
 
19
20
  //#region src/deckgl/shapes/display-shape-layer/constants.ts
@@ -29,19 +30,6 @@ const MAP_INTERACTION = {
29
30
  ICON_HOVER_SIZE_INCREASE: 5
30
31
  };
31
32
  /**
32
- * Coffin corners configuration for Point selection/hover feedback.
33
- *
34
- * Coffin corners are bracket-like corners that appear around Point shapes
35
- * with icons to indicate hover and selection states. They provide visual
36
- * feedback without obscuring the icon itself.
37
- */
38
- const COFFIN_CORNERS = {
39
- HOVER_ICON: "coffin-corners-hover",
40
- SELECTED_ICON: "coffin-corners-selected",
41
- SELECTED_HOVER_ICON: "coffin-corners-selected-hover",
42
- SIZE: 38
43
- };
44
- /**
45
33
  * Default props for DisplayShapeLayer.
46
34
  *
47
35
  * Provides sensible defaults for interactive shape display with labels,
@@ -109,7 +97,10 @@ const BRIGHTNESS_FACTOR = {
109
97
  */
110
98
  const OVERLAY_FILL_OPACITY = .25;
111
99
  /** Reusable deck.gl PathStyleExtension enabling dash patterns on GeoJsonLayer lines. */
112
- const DASH_EXTENSION = [new PathStyleExtension({ dash: true })];
100
+ const DASH_EXTENSION = new PathStyleExtension({ dash: true });
101
+ const COFFIN_CORNER_EXTENSION = new CoffinCornerExtension();
102
+ /** Stable extensions array for GeoJsonLayer — avoids new reference per render triggering getShaders() re-evaluation. */
103
+ const DISPLAY_EXTENSIONS = [DASH_EXTENSION, COFFIN_CORNER_EXTENSION];
113
104
  /** Readonly [r, g, b, a] tuple of DEFAULT_COLORS.highlight, pre-spread at module load for hot-path usage. */
114
105
  const HIGHLIGHT_COLOR_TUPLE = [
115
106
  DEFAULT_COLORS.highlight[0],
@@ -119,5 +110,5 @@ const HIGHLIGHT_COLOR_TUPLE = [
119
110
  ];
120
111
 
121
112
  //#endregion
122
- export { BRIGHTNESS_FACTOR, COFFIN_CORNERS, DASH_EXTENSION, DEFAULT_DISPLAY_PROPS, HIGHLIGHT_COLOR_TUPLE, MAP_INTERACTION, MATERIAL_SETTINGS, OVERLAY_FILL_OPACITY };
113
+ export { BRIGHTNESS_FACTOR, DEFAULT_DISPLAY_PROPS, DISPLAY_EXTENSIONS, HIGHLIGHT_COLOR_TUPLE, MAP_INTERACTION, MATERIAL_SETTINGS, OVERLAY_FILL_OPACITY };
123
114
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","names":["HIGHLIGHT_COLOR_TUPLE: Rgba255Tuple"],"sources":["../../../../src/deckgl/shapes/display-shape-layer/constants.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\nimport { PathStyleExtension } from '@deck.gl/extensions';\nimport { DEFAULT_COLORS } from '../shared/constants';\nimport type { Rgba255Tuple } from '@accelint/predicates';\n\n/**\n * Map interaction constants.\n *\n * Values derived from ngc2 for consistency with existing UI patterns.\n * Controls sizing and interaction feedback for shape rendering.\n */\nexport const MAP_INTERACTION = {\n LINE_WIDTH_MIN_PIXELS: 1, // Minimum line width in pixels\n ICON_SIZE: 38, // Size of shape icons\n ICON_HOVER_SIZE_INCREASE: 5, // Additional pixels added on hover\n} as const;\n\n/**\n * Coffin corners configuration for Point selection/hover feedback.\n *\n * Coffin corners are bracket-like corners that appear around Point shapes\n * with icons to indicate hover and selection states. They provide visual\n * feedback without obscuring the icon itself.\n */\nexport const COFFIN_CORNERS = {\n /** Icon name for hover state (white corners with background fill) */\n HOVER_ICON: 'coffin-corners-hover',\n /** Icon name for selected state (blue corners, no fill) */\n SELECTED_ICON: 'coffin-corners-selected',\n /** Icon name for selected+hover state (blue corners with background fill) */\n SELECTED_HOVER_ICON: 'coffin-corners-selected-hover',\n /** Size of the coffin corners icon */\n SIZE: 38,\n} as const;\n\n/**\n * Default props for DisplayShapeLayer.\n *\n * Provides sensible defaults for interactive shape display with labels,\n * standard opacity handling, and minimal visual feedback. These can be\n * overridden via layer props.\n */\nexport const DEFAULT_DISPLAY_PROPS = {\n pickable: true,\n showLabels: 'always' as const,\n showHighlight: false,\n applyBaseOpacity: true,\n highlightColor: DEFAULT_COLORS.highlight,\n};\n\n/**\n * Material settings for lighting effects on polygon shapes.\n * Controls fill brightness for hover and selection overlay layers.\n * Keys mirror BRIGHTNESS_FACTOR for consistency.\n */\nexport const MATERIAL_SETTINGS = {\n // Normal state - standard lighting\n NORMAL: {\n ambient: 0.35,\n diffuse: 0.6,\n shininess: 32,\n specularColor: [255, 255, 255] as [number, number, number],\n },\n // Hovered or selected (single active state)\n HOVER_OR_SELECT: {\n ambient: 0.6,\n diffuse: 0.8,\n shininess: 64,\n specularColor: [255, 255, 255] as [number, number, number],\n },\n // Hovered and selected simultaneously - brighter\n HOVER_AND_SELECT: {\n ambient: 0.75,\n diffuse: 0.95,\n shininess: 80,\n specularColor: [255, 255, 255] as [number, number, number],\n },\n} as const;\n\n/**\n * Brightness multipliers for interaction state feedback.\n * Applied via brightenColor() to line colors, curtains, and elevation indicators.\n * - HOVER_OR_SELECT: shape is hovered or selected (single active state)\n * - HOVER_AND_SELECT: shape is both hovered and selected simultaneously\n */\nexport const BRIGHTNESS_FACTOR = {\n HOVER_OR_SELECT: 1.4,\n HOVER_AND_SELECT: 1.7,\n} as const;\n\n/**\n * Opacity multiplier for interaction overlay layers (hover, select).\n * Applied to the shape's fill alpha — sits between the base opacity (0.2)\n * and full opacity (1.0) so the overlay reads clearly without being too solid.\n */\nexport const OVERLAY_FILL_OPACITY = 0.25;\n\n/** Reusable deck.gl PathStyleExtension enabling dash patterns on GeoJsonLayer lines. */\nexport const DASH_EXTENSION = [new PathStyleExtension({ dash: true })];\n\n/** Readonly [r, g, b, a] tuple of DEFAULT_COLORS.highlight, pre-spread at module load for hot-path usage. */\nexport const HIGHLIGHT_COLOR_TUPLE: Rgba255Tuple = [\n DEFAULT_COLORS.highlight[0],\n DEFAULT_COLORS.highlight[1],\n DEFAULT_COLORS.highlight[2],\n DEFAULT_COLORS.highlight[3] ?? 255,\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,kBAAkB;CAC7B,uBAAuB;CACvB,WAAW;CACX,0BAA0B;CAC3B;;;;;;;;AASD,MAAa,iBAAiB;CAE5B,YAAY;CAEZ,eAAe;CAEf,qBAAqB;CAErB,MAAM;CACP;;;;;;;;AASD,MAAa,wBAAwB;CACnC,UAAU;CACV,YAAY;CACZ,eAAe;CACf,kBAAkB;CAClB,gBAAgB,eAAe;CAChC;;;;;;AAOD,MAAa,oBAAoB;CAE/B,QAAQ;EACN,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;GAAC;GAAK;GAAK;GAAI;EAC/B;CAED,iBAAiB;EACf,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;GAAC;GAAK;GAAK;GAAI;EAC/B;CAED,kBAAkB;EAChB,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;GAAC;GAAK;GAAK;GAAI;EAC/B;CACF;;;;;;;AAQD,MAAa,oBAAoB;CAC/B,iBAAiB;CACjB,kBAAkB;CACnB;;;;;;AAOD,MAAa,uBAAuB;;AAGpC,MAAa,iBAAiB,CAAC,IAAI,mBAAmB,EAAE,MAAM,MAAM,CAAC,CAAC;;AAGtE,MAAaA,wBAAsC;CACjD,eAAe,UAAU;CACzB,eAAe,UAAU;CACzB,eAAe,UAAU;CACzB,eAAe,UAAU,MAAM;CAChC"}
1
+ {"version":3,"file":"constants.js","names":["HIGHLIGHT_COLOR_TUPLE: Rgba255Tuple"],"sources":["../../../../src/deckgl/shapes/display-shape-layer/constants.ts"],"sourcesContent":["/*\n * Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n'use client';\nimport { PathStyleExtension } from '@deck.gl/extensions';\nimport { CoffinCornerExtension } from '../../extensions/coffin-corner/coffin-corner-extension';\nimport { DEFAULT_COLORS } from '../shared/constants';\nimport type { Rgba255Tuple } from '@accelint/predicates';\n\n/**\n * Map interaction constants.\n *\n * Values derived from ngc2 for consistency with existing UI patterns.\n * Controls sizing and interaction feedback for shape rendering.\n */\nexport const MAP_INTERACTION = {\n LINE_WIDTH_MIN_PIXELS: 1,\n ICON_SIZE: 38,\n ICON_HOVER_SIZE_INCREASE: 5,\n} as const;\n\n/**\n * Default props for DisplayShapeLayer.\n *\n * Provides sensible defaults for interactive shape display with labels,\n * standard opacity handling, and minimal visual feedback. These can be\n * overridden via layer props.\n */\nexport const DEFAULT_DISPLAY_PROPS = {\n pickable: true,\n showLabels: 'always' as const,\n showHighlight: false,\n applyBaseOpacity: true,\n highlightColor: DEFAULT_COLORS.highlight,\n};\n\n/**\n * Material settings for lighting effects on polygon shapes.\n * Controls fill brightness for hover and selection overlay layers.\n * Keys mirror BRIGHTNESS_FACTOR for consistency.\n */\nexport const MATERIAL_SETTINGS = {\n // Normal state - standard lighting\n NORMAL: {\n ambient: 0.35,\n diffuse: 0.6,\n shininess: 32,\n specularColor: [255, 255, 255] as [number, number, number],\n },\n // Hovered or selected (single active state)\n HOVER_OR_SELECT: {\n ambient: 0.6,\n diffuse: 0.8,\n shininess: 64,\n specularColor: [255, 255, 255] as [number, number, number],\n },\n // Hovered and selected simultaneously - brighter\n HOVER_AND_SELECT: {\n ambient: 0.75,\n diffuse: 0.95,\n shininess: 80,\n specularColor: [255, 255, 255] as [number, number, number],\n },\n} as const;\n\n/**\n * Brightness multipliers for interaction state feedback.\n * Applied via brightenColor() to line colors, curtains, and elevation indicators.\n * - HOVER_OR_SELECT: shape is hovered or selected (single active state)\n * - HOVER_AND_SELECT: shape is both hovered and selected simultaneously\n */\nexport const BRIGHTNESS_FACTOR = {\n HOVER_OR_SELECT: 1.4,\n HOVER_AND_SELECT: 1.7,\n} as const;\n\n/**\n * Opacity multiplier for interaction overlay layers (hover, select).\n * Applied to the shape's fill alpha — sits between the base opacity (0.2)\n * and full opacity (1.0) so the overlay reads clearly without being too solid.\n */\nexport const OVERLAY_FILL_OPACITY = 0.25;\n\n/** Reusable deck.gl PathStyleExtension enabling dash patterns on GeoJsonLayer lines. */\nexport const DASH_EXTENSION = new PathStyleExtension({ dash: true });\n\nexport const COFFIN_CORNER_EXTENSION = new CoffinCornerExtension();\n\n/** Stable extensions array for GeoJsonLayer — avoids new reference per render triggering getShaders() re-evaluation. */\nexport const DISPLAY_EXTENSIONS = [DASH_EXTENSION, COFFIN_CORNER_EXTENSION];\n\n/** Readonly [r, g, b, a] tuple of DEFAULT_COLORS.highlight, pre-spread at module load for hot-path usage. */\nexport const HIGHLIGHT_COLOR_TUPLE: Rgba255Tuple = [\n DEFAULT_COLORS.highlight[0],\n DEFAULT_COLORS.highlight[1],\n DEFAULT_COLORS.highlight[2],\n DEFAULT_COLORS.highlight[3] ?? 255,\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,kBAAkB;CAC7B,uBAAuB;CACvB,WAAW;CACX,0BAA0B;CAC3B;;;;;;;;AASD,MAAa,wBAAwB;CACnC,UAAU;CACV,YAAY;CACZ,eAAe;CACf,kBAAkB;CAClB,gBAAgB,eAAe;CAChC;;;;;;AAOD,MAAa,oBAAoB;CAE/B,QAAQ;EACN,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;GAAC;GAAK;GAAK;GAAI;EAC/B;CAED,iBAAiB;EACf,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;GAAC;GAAK;GAAK;GAAI;EAC/B;CAED,kBAAkB;EAChB,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;GAAC;GAAK;GAAK;GAAI;EAC/B;CACF;;;;;;;AAQD,MAAa,oBAAoB;CAC/B,iBAAiB;CACjB,kBAAkB;CACnB;;;;;;AAOD,MAAa,uBAAuB;;AAGpC,MAAa,iBAAiB,IAAI,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAEpE,MAAa,0BAA0B,IAAI,uBAAuB;;AAGlE,MAAa,qBAAqB,CAAC,gBAAgB,wBAAwB;;AAG3E,MAAaA,wBAAsC;CACjD,eAAe,UAAU;CACzB,eAAe,UAAU;CACzB,eAAe,UAAU;CACzB,eAAe,UAAU,MAAM;CAChC"}
@@ -25,7 +25,7 @@ import { CompositeLayer, Layer, PickingInfo } from "@deck.gl/core";
25
25
  * ## Features
26
26
  * - **Multiple geometry types**: Point, LineString, Polygon, and Circle
27
27
  * - **Icon support**: Custom icons for Point geometries via icon atlases
28
- * - **Interactive selection**: Click handling with brightness overlay on polygon select, optional highlight effect for non-icon-Point shapes (if showHighlight=true)
28
+ * - **Interactive selection**: Click handling with brightness overlay on polygon select, optional highlight outline for non-Point shapes (if showHighlight=true). Point geometries use coffin corner brackets instead.
29
29
  * - **Hover effects**: Polygon fills brighten via material lighting; outline width increases by 2px on hover
30
30
  * - **Customizable labels**: Flexible label positioning with per-shape or global options
31
31
  * - **Style properties**: Full control over colors, border/outline patterns, and opacity
@@ -38,13 +38,14 @@ import { CompositeLayer, Layer, PickingInfo } from "@deck.gl/core";
38
38
  * and material-based brightness — the base shape is never altered.
39
39
  *
40
40
  * ## Layer Structure
41
- * Renders up to seven sublayers (in order, bottom to top):
42
- * 1. **Select layer**: Selection brightness overlay for polygon shapes
43
- * 2. **Hover layer**: Hover brightness overlay for polygon shapes
44
- * 3. **Coffin corners layer**: Selection/hover feedback for Point shapes with icons
41
+ * Renders sublayers in this order (bottom to top):
42
+ * 1. **Highlight layer**: Selection outline for non-polygon, non-Point shapes (when showHighlight enabled)
43
+ * 2. **Select layer**: Selection brightness overlay for polygon shapes
44
+ * 3. **Hover layer**: Hover brightness overlay for polygon shapes
45
45
  * 4. **Elevation visualization**: Curtains (LineStrings) or wireframes (polygons) — elevation only
46
46
  * 5. **Elevation indicators**: Vertical strut lines for elevated non-polygon shapes — elevation only
47
- * 6. **Main GeoJsonLayer**: Shape geometries with styling and interaction
47
+ * 6. **Main GeoJsonLayer**: Shape geometries with styling and interaction; includes CoffinCornerExtension
48
+ * which propagates to the icon/scatterplot sublayer for Point hover/select bracket feedback
48
49
  * 7. **Label layer**: Text labels (if showLabels enabled)
49
50
  *
50
51
  * ## Icon Atlas Constraint
@@ -111,6 +112,8 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
111
112
  private elevationCache;
112
113
  /** Cache for elevation indicator line segments */
113
114
  private indicatorCache;
115
+ /** Cached coffin corner color tuple — avoids new array reference per render when highlight hasn't changed. */
116
+ private coffinCornerColorCache;
114
117
  static layerName: string;
115
118
  static defaultProps: {
116
119
  pickable: boolean;
@@ -127,6 +130,11 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
127
130
  * Resolved highlight color — uses prop if provided, falls back to default.
128
131
  */
129
132
  private get resolvedHighlight();
133
+ /**
134
+ * Coffin corner bracket color derived from resolvedHighlight with forced full opacity.
135
+ * Cached to avoid a new array reference per render triggering deck.gl prop-change detection.
136
+ */
137
+ private get coffinCornerColor();
130
138
  /**
131
139
  * Handle picking events from the main shapes layer
132
140
  */
@@ -173,11 +181,13 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
173
181
  */
174
182
  private getShapeById;
175
183
  /**
176
- * Handle shape click
184
+ * Handle shape click — emits `shapes:selected` via bus and calls `onShapeClick` callback.
185
+ * @param info - deck.gl picking info from the clicked sublayer.
177
186
  */
178
187
  private handleShapeClick;
179
188
  /**
180
- * Handle shape hover
189
+ * Handle shape hover — emits `shapes:hovered` via bus (deduplicated by shapeId) and calls `onShapeHover` callback.
190
+ * @param info - deck.gl picking info from the hovered sublayer.
181
191
  */
182
192
  private handleShapeHover;
183
193
  /**
@@ -187,7 +197,8 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
187
197
  private getElevationData;
188
198
  /**
189
199
  * Render highlight sublayer (underneath main layer).
190
- * Note: Points with icons use coffin corners instead of highlight layer.
200
+ * Point geometries skip this layer they use coffin corner brackets
201
+ * via CoffinCornerExtension on the main layer's icon/scatterplot sublayer instead.
191
202
  */
192
203
  private renderHighlightLayer;
193
204
  /**
@@ -202,11 +213,6 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
202
213
  * Stacks with other interaction layers (e.g. selection highlight underneath).
203
214
  */
204
215
  private renderHoverLayer;
205
- /**
206
- * Render coffin corners layer for Point geometries that have icons on hover/select
207
- * Coffin corners provide visual feedback for points instead of select layer
208
- */
209
- private renderCoffinCornersLayer;
210
216
  /**
211
217
  * Render main shapes layer
212
218
  */
@@ -219,6 +225,15 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
219
225
  * - 'never': No labels
220
226
  */
221
227
  private renderLabelsLayer;
228
+ /**
229
+ * Render radius label layer for hovered circle shapes.
230
+ * Shows the circle's radius value converted to the configured display unit.
231
+ *
232
+ * Positioning relative to the shape's label:
233
+ * - When showLabels is 'always' or 'hover': appears below the label
234
+ * - When showLabels is 'never': appears in the label's position
235
+ */
236
+ private renderRadiusLabelLayer;
222
237
  /**
223
238
  * Render vertical elevation indicator lines for non-polygon shapes.
224
239
  * Creates vertical "strut" lines from ground level to elevated features.
@@ -240,7 +255,8 @@ declare class DisplayShapeLayer extends CompositeLayer<DisplayShapeLayerProps> {
240
255
  */
241
256
  private renderElevationVisualizationLayer;
242
257
  /**
243
- * Render all sublayers
258
+ * Render all sublayers.
259
+ * @returns Ordered array of sublayers (highlight, select, hover, elevation, main, labels) from bottom to top.
244
260
  */
245
261
  renderLayers(): Layer[];
246
262
  }
@@ -13,23 +13,23 @@
13
13
 
14
14
  'use client';
15
15
 
16
- import { createLoggerDomain } from "../../../shared/logger.js";
17
16
  import { ShapeEvents } from "../shared/events.js";
18
- import { isLineGeometry, isPointType, isPolygonGeometry } from "../shared/types.js";
17
+ import { isCircleShape, isLineGeometry, isPointType, isPolygonGeometry } from "../shared/types.js";
18
+ import { DEFAULT_TEXT_SIZE, DEFAULT_TEXT_STYLE } from "../../text-settings.js";
19
19
  import { SHAPE_LAYER_IDS } from "../shared/constants.js";
20
20
  import { getDashArray, getFillColor, getLineColor } from "../shared/utils/style-utils.js";
21
- import { BRIGHTNESS_FACTOR, COFFIN_CORNERS, DASH_EXTENSION, DEFAULT_DISPLAY_PROPS, HIGHLIGHT_COLOR_TUPLE, MAP_INTERACTION, MATERIAL_SETTINGS } from "./constants.js";
21
+ import { BRIGHTNESS_FACTOR, DEFAULT_DISPLAY_PROPS, DISPLAY_EXTENSIONS, HIGHLIGHT_COLOR_TUPLE, MAP_INTERACTION, MATERIAL_SETTINGS } from "./constants.js";
22
+ import { getLabelPosition2d } from "./utils/labels.js";
22
23
  import { createShapeLabelLayer } from "./shape-label-layer.js";
23
24
  import { applyOverlayOpacity, brightenColor, getHighlightLineWidth, getHoverLineWidth, getOverlayFillColor } from "./utils/display-style.js";
24
25
  import { buildIndicatorLineData, classifyElevatedFeatures, createCurtainPolygonFeatures, flattenFeatureTo2D, getFeatureElevation, partitionCurtains } from "./utils/elevation.js";
25
- import { extendMappingWithCoffinCorners, getIconConfig, getIconLayerProps, getIconUpdateTriggers } from "./utils/icon-config.js";
26
- import { getPointInteractionState } from "./utils/interaction.js";
26
+ import { getIconConfig, getIconLayerProps, getIconUpdateTriggers } from "./utils/icon-config.js";
27
+ import { getRadiusLabelText } from "./utils/radius-label.js";
27
28
  import { Broadcast } from "@accelint/bus";
28
29
  import { CompositeLayer } from "@deck.gl/core";
29
- import { GeoJsonLayer, IconLayer, LineLayer } from "@deck.gl/layers";
30
+ import { GeoJsonLayer, LineLayer, TextLayer } from "@deck.gl/layers";
30
31
 
31
32
  //#region src/deckgl/shapes/display-shape-layer/index.ts
32
- const logger = createLoggerDomain("[DisplayShapeLayer]");
33
33
  /**
34
34
  * Typed event bus instance for shape events.
35
35
  * Provides type-safe event emission for shape interactions.
@@ -44,7 +44,7 @@ const shapeBus = Broadcast.getInstance();
44
44
  * ## Features
45
45
  * - **Multiple geometry types**: Point, LineString, Polygon, and Circle
46
46
  * - **Icon support**: Custom icons for Point geometries via icon atlases
47
- * - **Interactive selection**: Click handling with brightness overlay on polygon select, optional highlight effect for non-icon-Point shapes (if showHighlight=true)
47
+ * - **Interactive selection**: Click handling with brightness overlay on polygon select, optional highlight outline for non-Point shapes (if showHighlight=true). Point geometries use coffin corner brackets instead.
48
48
  * - **Hover effects**: Polygon fills brighten via material lighting; outline width increases by 2px on hover
49
49
  * - **Customizable labels**: Flexible label positioning with per-shape or global options
50
50
  * - **Style properties**: Full control over colors, border/outline patterns, and opacity
@@ -57,13 +57,14 @@ const shapeBus = Broadcast.getInstance();
57
57
  * and material-based brightness — the base shape is never altered.
58
58
  *
59
59
  * ## Layer Structure
60
- * Renders up to seven sublayers (in order, bottom to top):
61
- * 1. **Select layer**: Selection brightness overlay for polygon shapes
62
- * 2. **Hover layer**: Hover brightness overlay for polygon shapes
63
- * 3. **Coffin corners layer**: Selection/hover feedback for Point shapes with icons
60
+ * Renders sublayers in this order (bottom to top):
61
+ * 1. **Highlight layer**: Selection outline for non-polygon, non-Point shapes (when showHighlight enabled)
62
+ * 2. **Select layer**: Selection brightness overlay for polygon shapes
63
+ * 3. **Hover layer**: Hover brightness overlay for polygon shapes
64
64
  * 4. **Elevation visualization**: Curtains (LineStrings) or wireframes (polygons) — elevation only
65
65
  * 5. **Elevation indicators**: Vertical strut lines for elevated non-polygon shapes — elevation only
66
- * 6. **Main GeoJsonLayer**: Shape geometries with styling and interaction
66
+ * 6. **Main GeoJsonLayer**: Shape geometries with styling and interaction; includes CoffinCornerExtension
67
+ * which propagates to the icon/scatterplot sublayer for Point hover/select bracket feedback
67
68
  * 7. **Label layer**: Text labels (if showLabels enabled)
68
69
  *
69
70
  * ## Icon Atlas Constraint
@@ -129,6 +130,8 @@ var DisplayShapeLayer = class extends CompositeLayer {
129
130
  elevationCache = null;
130
131
  /** Cache for elevation indicator line segments */
131
132
  indicatorCache = null;
133
+ /** Cached coffin corner color tuple — avoids new array reference per render when highlight hasn't changed. */
134
+ coffinCornerColorCache = null;
132
135
  static layerName = "DisplayShapeLayer";
133
136
  static defaultProps = { ...DEFAULT_DISPLAY_PROPS };
134
137
  /**
@@ -142,6 +145,7 @@ var DisplayShapeLayer = class extends CompositeLayer {
142
145
  this.featuresCache = null;
143
146
  this.elevationCache = null;
144
147
  this.indicatorCache = null;
148
+ this.coffinCornerColorCache = null;
145
149
  }
146
150
  /**
147
151
  * Resolved highlight color — uses prop if provided, falls back to default.
@@ -150,6 +154,23 @@ var DisplayShapeLayer = class extends CompositeLayer {
150
154
  return this.props.highlightColor ?? HIGHLIGHT_COLOR_TUPLE;
151
155
  }
152
156
  /**
157
+ * Coffin corner bracket color derived from resolvedHighlight with forced full opacity.
158
+ * Cached to avoid a new array reference per render triggering deck.gl prop-change detection.
159
+ */
160
+ get coffinCornerColor() {
161
+ const highlight = this.resolvedHighlight;
162
+ if (this.coffinCornerColorCache?.source !== highlight) this.coffinCornerColorCache = {
163
+ source: highlight,
164
+ color: [
165
+ highlight[0],
166
+ highlight[1],
167
+ highlight[2],
168
+ 255
169
+ ]
170
+ };
171
+ return this.coffinCornerColorCache.color;
172
+ }
173
+ /**
153
174
  * Handle picking events from the main shapes layer
154
175
  */
155
176
  handleMainLayerPick(info, mode) {
@@ -241,7 +262,8 @@ var DisplayShapeLayer = class extends CompositeLayer {
241
262
  return index !== void 0 ? this.props.data[index] : void 0;
242
263
  }
243
264
  /**
244
- * Handle shape click
265
+ * Handle shape click — emits `shapes:selected` via bus and calls `onShapeClick` callback.
266
+ * @param info - deck.gl picking info from the clicked sublayer.
245
267
  */
246
268
  handleShapeClick = (info) => {
247
269
  const { onShapeClick, mapId } = this.props;
@@ -257,7 +279,8 @@ var DisplayShapeLayer = class extends CompositeLayer {
257
279
  if (onShapeClick) onShapeClick(shape);
258
280
  };
259
281
  /**
260
- * Handle shape hover
282
+ * Handle shape hover — emits `shapes:hovered` via bus (deduplicated by shapeId) and calls `onShapeHover` callback.
283
+ * @param info - deck.gl picking info from the hovered sublayer.
261
284
  */
262
285
  handleShapeHover = (info) => {
263
286
  const { onShapeHover, mapId } = this.props;
@@ -293,7 +316,8 @@ var DisplayShapeLayer = class extends CompositeLayer {
293
316
  }
294
317
  /**
295
318
  * Render highlight sublayer (underneath main layer).
296
- * Note: Points with icons use coffin corners instead of highlight layer.
319
+ * Point geometries skip this layer they use coffin corner brackets
320
+ * via CoffinCornerExtension on the main layer's icon/scatterplot sublayer instead.
297
321
  */
298
322
  renderHighlightLayer(features) {
299
323
  const { selectedShapeId, showHighlight } = this.props;
@@ -301,9 +325,7 @@ var DisplayShapeLayer = class extends CompositeLayer {
301
325
  const featureIndex = this.featuresCache?.shapeIdToIndex.get(selectedShapeId);
302
326
  const selectedFeature = featureIndex !== void 0 ? features[featureIndex] : void 0;
303
327
  if (!selectedFeature) return [];
304
- if (isPointType(selectedFeature.geometry)) {
305
- if (!!selectedFeature.properties?.styleProperties?.icon) return [];
306
- }
328
+ if (isPointType(selectedFeature.geometry)) return [];
307
329
  const highlightFeature = flattenFeatureTo2D(selectedFeature);
308
330
  const lineColor = this.resolvedHighlight;
309
331
  return [new GeoJsonLayer({
@@ -383,66 +405,13 @@ var DisplayShapeLayer = class extends CompositeLayer {
383
405
  })];
384
406
  }
385
407
  /**
386
- * Render coffin corners layer for Point geometries that have icons on hover/select
387
- * Coffin corners provide visual feedback for points instead of select layer
388
- */
389
- renderCoffinCornersLayer(features) {
390
- const { selectedShapeId } = this.props;
391
- const hoverIndex = this.state?.hoverIndex;
392
- const shapeIdToIndex = this.featuresCache?.shapeIdToIndex;
393
- if (!shapeIdToIndex) return [];
394
- const pointFeatures = [];
395
- for (const f of features) {
396
- if (f.geometry.type !== "Point") continue;
397
- if (!f.properties?.styleProperties?.icon) continue;
398
- const { isSelected, isHovered } = getPointInteractionState(f, selectedShapeId, hoverIndex, shapeIdToIndex);
399
- if (isSelected || isHovered) pointFeatures.push(f);
400
- }
401
- if (pointFeatures.length === 0) return [];
402
- const firstPointIcon = pointFeatures[0]?.properties?.styleProperties?.icon;
403
- const iconAtlas = firstPointIcon?.atlas;
404
- const iconMapping = firstPointIcon?.mapping;
405
- if (!(iconAtlas && iconMapping)) {
406
- logger.warn("Point shape has icon style but missing iconAtlas or iconMapping - coffin corners will not render");
407
- return [];
408
- }
409
- const extendedMapping = extendMappingWithCoffinCorners(iconMapping);
410
- return [new IconLayer({
411
- id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-coffin-corners`,
412
- data: pointFeatures,
413
- iconAtlas,
414
- iconMapping: extendedMapping,
415
- getIcon: (d) => {
416
- const { isSelected, isHovered } = getPointInteractionState(d, selectedShapeId, hoverIndex, shapeIdToIndex);
417
- if (isSelected && isHovered) return COFFIN_CORNERS.SELECTED_HOVER_ICON;
418
- if (isSelected) return COFFIN_CORNERS.SELECTED_ICON;
419
- return COFFIN_CORNERS.HOVER_ICON;
420
- },
421
- getSize: COFFIN_CORNERS.SIZE,
422
- getPosition: (d) => {
423
- return isPointType(d.geometry) ? d.geometry.coordinates : [0, 0];
424
- },
425
- getPixelOffset: (d) => {
426
- return [-1, -(d.properties?.styleProperties?.icon?.size ?? MAP_INTERACTION.ICON_SIZE) / 2];
427
- },
428
- billboard: false,
429
- pickable: false,
430
- updateTriggers: {
431
- getIcon: [selectedShapeId, this.state?.hoverIndex],
432
- data: [
433
- features,
434
- selectedShapeId,
435
- this.state?.hoverIndex
436
- ]
437
- }
438
- })];
439
- }
440
- /**
441
408
  * Render main shapes layer
442
409
  */
443
410
  renderMainLayer(features) {
444
411
  const { pickable, applyBaseOpacity, selectedShapeId } = this.props;
445
412
  const { hasIcons, atlas: iconAtlas, mapping: iconMapping } = getIconConfig(features);
413
+ const hoveredFeature = this.state?.hoverIndex !== void 0 ? features[this.state.hoverIndex] : void 0;
414
+ const hoveredEntityId = hoveredFeature?.geometry.type === "Point" ? hoveredFeature.properties?.shapeId : void 0;
446
415
  return new GeoJsonLayer({
447
416
  id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}`,
448
417
  data: features,
@@ -473,7 +442,11 @@ var DisplayShapeLayer = class extends CompositeLayer {
473
442
  },
474
443
  pointRadiusUnits: "pixels",
475
444
  ...getIconLayerProps(hasIcons, iconAtlas, iconMapping),
476
- extensions: DASH_EXTENSION,
445
+ selectedEntityId: selectedShapeId,
446
+ hoveredEntityId,
447
+ getEntityId: (d) => d.properties?.shapeId,
448
+ selectedCoffinCornerColor: this.coffinCornerColor,
449
+ extensions: DISPLAY_EXTENSIONS,
477
450
  getDashArray,
478
451
  pickable,
479
452
  autoHighlight: false,
@@ -520,6 +493,51 @@ var DisplayShapeLayer = class extends CompositeLayer {
520
493
  })];
521
494
  }
522
495
  /**
496
+ * Render radius label layer for hovered circle shapes.
497
+ * Shows the circle's radius value converted to the configured display unit.
498
+ *
499
+ * Positioning relative to the shape's label:
500
+ * - When showLabels is 'always' or 'hover': appears below the label
501
+ * - When showLabels is 'never': appears in the label's position
502
+ */
503
+ renderRadiusLabelLayer() {
504
+ const { data, unit, showLabels, labelOptions } = this.props;
505
+ const hoverIndex = this.state?.hoverIndex;
506
+ const hoveredShape = hoverIndex !== void 0 ? data[hoverIndex] : void 0;
507
+ const radiusText = hoveredShape && isCircleShape(hoveredShape) ? getRadiusLabelText(hoveredShape, unit) : void 0;
508
+ const labelPosition = radiusText && hoveredShape ? getLabelPosition2d(hoveredShape, labelOptions) : void 0;
509
+ if (!labelPosition) return [];
510
+ const pixelOffset = showLabels !== "never" ? [labelPosition.pixelOffset[0], labelPosition.pixelOffset[1] + DEFAULT_TEXT_SIZE + 2] : labelPosition.pixelOffset;
511
+ return [new TextLayer({
512
+ id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-radius-label`,
513
+ data: [{
514
+ text: radiusText,
515
+ position: labelPosition.coordinates
516
+ }],
517
+ getText: (d) => d.text,
518
+ getPosition: (d) => d.position,
519
+ getPixelOffset: pixelOffset,
520
+ getTextAnchor: labelPosition.textAnchor,
521
+ getAlignmentBaseline: labelPosition.alignmentBaseline,
522
+ ...DEFAULT_TEXT_STYLE,
523
+ getAngle: 0,
524
+ background: false,
525
+ fontFamily: "Roboto MonoVariable, monospace",
526
+ pickable: false,
527
+ updateTriggers: {
528
+ getText: [hoverIndex, unit],
529
+ getPosition: [hoverIndex, labelOptions],
530
+ getPixelOffset: [
531
+ hoverIndex,
532
+ labelOptions,
533
+ showLabels
534
+ ],
535
+ getTextAnchor: [hoverIndex, labelOptions],
536
+ getAlignmentBaseline: [hoverIndex, labelOptions]
537
+ }
538
+ })];
539
+ }
540
+ /**
523
541
  * Render vertical elevation indicator lines for non-polygon shapes.
524
542
  * Creates vertical "strut" lines from ground level to elevated features.
525
543
  * For LineStrings, creates a "curtain" effect with vertical lines at each coordinate.
@@ -648,7 +666,8 @@ var DisplayShapeLayer = class extends CompositeLayer {
648
666
  return layers;
649
667
  }
650
668
  /**
651
- * Render all sublayers
669
+ * Render all sublayers.
670
+ * @returns Ordered array of sublayers (highlight, select, hover, elevation, main, labels) from bottom to top.
652
671
  */
653
672
  renderLayers() {
654
673
  const features = this.getFeaturesWithId();
@@ -656,8 +675,7 @@ var DisplayShapeLayer = class extends CompositeLayer {
656
675
  const layers = [
657
676
  ...this.renderHighlightLayer(features),
658
677
  ...this.renderSelectLayer(features),
659
- ...this.renderHoverLayer(features),
660
- ...this.renderCoffinCornersLayer(features)
678
+ ...this.renderHoverLayer(features)
661
679
  ];
662
680
  if (enableElevation) {
663
681
  const { classification, curtainFeatures } = this.getElevationData(features, this.props.applyBaseOpacity);
@@ -667,6 +685,7 @@ var DisplayShapeLayer = class extends CompositeLayer {
667
685
  }
668
686
  layers.push(this.renderMainLayer(features));
669
687
  layers.push(...this.renderLabelsLayer());
688
+ layers.push(...this.renderRadiusLabelLayer());
670
689
  return layers;
671
690
  }
672
691
  };