@accelint/map-toolkit 1.4.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/catalog-info.yaml +4 -4
- package/dist/camera/events.js +1 -1
- package/dist/camera/index.d.ts +1 -1
- package/dist/camera/index.js +1 -1
- package/dist/camera/store.d.ts +1 -1
- package/dist/camera/store.js +4 -6
- package/dist/camera/store.js.map +1 -1
- package/dist/camera/types.d.ts +1 -1
- package/dist/camera/types.js +1 -1
- package/dist/cursor-coordinates/constants.js +1 -1
- package/dist/cursor-coordinates/index.d.ts +1 -1
- package/dist/cursor-coordinates/index.js +1 -1
- package/dist/cursor-coordinates/store.d.ts +1 -1
- package/dist/cursor-coordinates/store.js +1 -1
- package/dist/cursor-coordinates/types.d.ts +1 -1
- package/dist/cursor-coordinates/types.js +1 -1
- package/dist/cursor-coordinates/use-cursor-coordinates.d.ts +1 -1
- package/dist/cursor-coordinates/use-cursor-coordinates.js +4 -9
- package/dist/cursor-coordinates/use-cursor-coordinates.js.map +1 -1
- package/dist/deckgl/base-map/constants.js +1 -1
- package/dist/deckgl/base-map/controls.d.ts +1 -1
- package/dist/deckgl/base-map/controls.js +1 -1
- package/dist/deckgl/base-map/events.js +1 -1
- package/dist/deckgl/base-map/index.d.ts +3 -3
- package/dist/deckgl/base-map/index.js +15 -7
- package/dist/deckgl/base-map/index.js.map +1 -1
- package/dist/deckgl/base-map/provider.d.ts +3 -3
- package/dist/deckgl/base-map/provider.js +3 -5
- package/dist/deckgl/base-map/provider.js.map +1 -1
- package/dist/deckgl/base-map/types.d.ts +1 -1
- package/dist/deckgl/base-map/types.js +1 -1
- package/dist/deckgl/index.d.ts +4 -4
- package/dist/deckgl/index.js +4 -4
- package/dist/deckgl/saved-viewports/index.d.ts +1 -1
- package/dist/deckgl/saved-viewports/index.js +1 -1
- package/dist/deckgl/saved-viewports/storage.d.ts +1 -1
- package/dist/deckgl/saved-viewports/storage.js +5 -10
- package/dist/deckgl/saved-viewports/storage.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/constants.js +66 -13
- package/dist/deckgl/shapes/display-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/fiber.d.ts +1 -1
- package/dist/deckgl/shapes/display-shape-layer/fiber.js +1 -1
- package/dist/deckgl/shapes/display-shape-layer/index.d.ts +74 -35
- package/dist/deckgl/shapes/display-shape-layer/index.js +381 -154
- package/dist/deckgl/shapes/display-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/shape-label-layer.js +1 -1
- package/dist/deckgl/shapes/display-shape-layer/store.js +8 -2
- package/dist/deckgl/shapes/display-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/types.d.ts +108 -19
- package/dist/deckgl/shapes/display-shape-layer/types.js +1 -1
- package/dist/deckgl/shapes/display-shape-layer/use-select-shape.d.ts +1 -1
- package/dist/deckgl/shapes/display-shape-layer/use-select-shape.js +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js +66 -36
- package/dist/deckgl/shapes/display-shape-layer/utils/display-style.js.map +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/elevation.js +407 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/elevation.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js +151 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/icon-config.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js +50 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/interaction.js.map +1 -0
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.d.ts +1 -1
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js +28 -39
- package/dist/deckgl/shapes/display-shape-layer/utils/labels.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/constants.js +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/events.d.ts +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/events.js +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/fiber.js +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/index.d.ts +3 -3
- package/dist/deckgl/shapes/draw-shape-layer/index.js +7 -17
- package/dist/deckgl/shapes/draw-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js +8 -9
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-circle-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-ellipse-mode-with-tooltip.js +3 -3
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js +4 -21
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-line-string-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js +4 -34
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-polygon-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js +11 -12
- package/dist/deckgl/shapes/draw-shape-layer/modes/draw-rectangle-mode-with-tooltip.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/modes/index.js +2 -32
- package/dist/deckgl/shapes/draw-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/store.js +38 -4
- package/dist/deckgl/shapes/draw-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/types.d.ts +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/types.js +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.d.ts +1 -1
- package/dist/deckgl/shapes/draw-shape-layer/use-draw-shape.js +2 -2
- package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js +4 -9
- package/dist/deckgl/shapes/draw-shape-layer/utils/feature-conversion.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/constants.js +17 -2
- package/dist/deckgl/shapes/edit-shape-layer/constants.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/events.d.ts +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/events.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/fiber.d.ts +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/fiber.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/index.d.ts +7 -4
- package/dist/deckgl/shapes/edit-shape-layer/index.js +52 -21
- package/dist/deckgl/shapes/edit-shape-layer/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js +4 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/base-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js +2 -2
- package/dist/deckgl/shapes/edit-shape-layer/modes/bounding-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js +7 -7
- package/dist/deckgl/shapes/edit-shape-layer/modes/circle-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js +2 -2
- package/dist/deckgl/shapes/edit-shape-layer/modes/index.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/point-translate-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js +2 -2
- package/dist/deckgl/shapes/edit-shape-layer/modes/rotate-mode-with-snap.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/scale-mode-with-free-transform.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/modes/vertex-transform-mode.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/store.js +78 -14
- package/dist/deckgl/shapes/edit-shape-layer/store.js.map +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/types.d.ts +14 -2
- package/dist/deckgl/shapes/edit-shape-layer/types.js +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.d.ts +1 -1
- package/dist/deckgl/shapes/edit-shape-layer/use-edit-shape.js +2 -2
- package/dist/deckgl/shapes/index.d.ts +4 -4
- package/dist/deckgl/shapes/index.js +5 -5
- package/dist/deckgl/shapes/shared/constants.d.ts +4 -3
- package/dist/deckgl/shapes/shared/constants.js +55 -15
- package/dist/deckgl/shapes/shared/constants.js.map +1 -1
- package/dist/deckgl/shapes/shared/events.d.ts +5 -1
- package/dist/deckgl/shapes/shared/events.js +1 -1
- package/dist/deckgl/shapes/shared/events.js.map +1 -1
- package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js +19 -16
- package/dist/deckgl/shapes/shared/hooks/use-shift-zoom-disable.js.map +1 -1
- package/dist/deckgl/shapes/shared/types.d.ts +174 -53
- package/dist/deckgl/shapes/shared/types.js +155 -2
- package/dist/deckgl/shapes/shared/types.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/geometry-measurements.js +29 -24
- package/dist/deckgl/shapes/shared/utils/geometry-measurements.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/layer-config.js +9 -6
- package/dist/deckgl/shapes/shared/utils/layer-config.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/mode-utils.js +50 -20
- package/dist/deckgl/shapes/shared/utils/mode-utils.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/pick-filtering.js +22 -15
- package/dist/deckgl/shapes/shared/utils/pick-filtering.js.map +1 -1
- package/dist/deckgl/shapes/shared/utils/style-utils.d.ts +38 -14
- package/dist/deckgl/shapes/shared/utils/style-utils.js +43 -32
- package/dist/deckgl/shapes/shared/utils/style-utils.js.map +1 -1
- package/dist/deckgl/symbol-layer/fiber.d.ts +1 -1
- package/dist/deckgl/symbol-layer/fiber.js +1 -1
- package/dist/deckgl/symbol-layer/index.d.ts +1 -1
- package/dist/deckgl/symbol-layer/index.js +1 -1
- package/dist/deckgl/text-layer/character-sets.js +1 -1
- package/dist/deckgl/text-layer/default-settings.d.ts +1 -1
- package/dist/deckgl/text-layer/default-settings.js +1 -1
- package/dist/deckgl/text-layer/fiber.d.ts +1 -1
- package/dist/deckgl/text-layer/fiber.js +1 -1
- package/dist/deckgl/text-layer/index.d.ts +1 -1
- package/dist/deckgl/text-layer/index.js +1 -1
- package/dist/deckgl/text-settings.d.ts +3 -3
- package/dist/deckgl/text-settings.js +1 -1
- package/dist/map-cursor/events.js +1 -1
- package/dist/map-cursor/index.d.ts +1 -1
- package/dist/map-cursor/index.js +1 -1
- package/dist/map-cursor/store.d.ts +1 -1
- package/dist/map-cursor/store.js +1 -1
- package/dist/map-cursor/types.d.ts +1 -1
- package/dist/map-cursor/types.js +1 -1
- package/dist/map-cursor/use-map-cursor.d.ts +1 -1
- package/dist/map-cursor/use-map-cursor.js +1 -1
- package/dist/map-mode/events.js +1 -1
- package/dist/map-mode/index.d.ts +1 -1
- package/dist/map-mode/index.js +1 -1
- package/dist/map-mode/store.d.ts +1 -1
- package/dist/map-mode/store.js +3 -8
- package/dist/map-mode/store.js.map +1 -1
- package/dist/map-mode/types.d.ts +1 -1
- package/dist/map-mode/types.js +1 -1
- package/dist/map-mode/use-map-mode.d.ts +1 -1
- package/dist/map-mode/use-map-mode.js +1 -1
- package/dist/maplibre/hooks/use-maplibre.d.ts +1 -1
- package/dist/maplibre/hooks/use-maplibre.js +1 -1
- package/dist/maplibre/index.d.ts +1 -1
- package/dist/maplibre/index.js +1 -1
- package/dist/shared/cleanup.d.ts +58 -0
- package/dist/shared/cleanup.js +93 -0
- package/dist/shared/cleanup.js.map +1 -0
- package/dist/shared/constants.js +1 -1
- package/dist/shared/create-map-store.d.ts +13 -1
- package/dist/shared/create-map-store.js +9 -4
- package/dist/shared/create-map-store.js.map +1 -1
- package/dist/shared/logger.js +31 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/units.js +1 -1
- package/dist/viewport/index.d.ts +1 -1
- package/dist/viewport/index.js +1 -1
- package/dist/viewport/store.d.ts +1 -1
- package/dist/viewport/store.js +1 -1
- package/dist/viewport/types.d.ts +1 -1
- package/dist/viewport/types.js +1 -1
- package/dist/viewport/utils.d.ts +1 -1
- package/dist/viewport/utils.js +1 -1
- package/dist/viewport/viewport-size.d.ts +3 -3
- package/dist/viewport/viewport-size.js +1 -1
- package/package.json +22 -19
- package/dist/hotkey-manager/dist/react/use-hotkey.js +0 -39
- package/dist/hotkey-manager/dist/react/use-hotkey.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2026 Hypergiant Galactic Systems Inc. All rights reserved.
|
|
3
3
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
5
|
* of the License at https://www.apache.org/licenses/LICENSE-2.0
|
|
@@ -13,25 +13,23 @@
|
|
|
13
13
|
|
|
14
14
|
'use client';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { createLoggerDomain } from "../../../shared/logger.js";
|
|
17
17
|
import { ShapeEvents } from "../shared/events.js";
|
|
18
|
+
import { isLineGeometry, isPointType, isPolygonGeometry } from "../shared/types.js";
|
|
19
|
+
import { SHAPE_LAYER_IDS } from "../shared/constants.js";
|
|
18
20
|
import { getDashArray, getFillColor, getLineColor } from "../shared/utils/style-utils.js";
|
|
19
|
-
import { COFFIN_CORNERS, DEFAULT_DISPLAY_PROPS, MAP_INTERACTION } from "./constants.js";
|
|
21
|
+
import { BRIGHTNESS_FACTOR, COFFIN_CORNERS, DASH_EXTENSION, DEFAULT_DISPLAY_PROPS, HIGHLIGHT_COLOR_TUPLE, MAP_INTERACTION, MATERIAL_SETTINGS } from "./constants.js";
|
|
20
22
|
import { createShapeLabelLayer } from "./shape-label-layer.js";
|
|
21
|
-
import {
|
|
23
|
+
import { applyOverlayOpacity, brightenColor, getHighlightLineWidth, getHoverLineWidth, getOverlayFillColor } from "./utils/display-style.js";
|
|
24
|
+
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";
|
|
22
27
|
import { Broadcast } from "@accelint/bus";
|
|
23
|
-
import { getLogger } from "@accelint/logger";
|
|
24
28
|
import { CompositeLayer } from "@deck.gl/core";
|
|
25
|
-
import {
|
|
26
|
-
import { GeoJsonLayer, IconLayer } from "@deck.gl/layers";
|
|
29
|
+
import { GeoJsonLayer, IconLayer, LineLayer } from "@deck.gl/layers";
|
|
27
30
|
|
|
28
31
|
//#region src/deckgl/shapes/display-shape-layer/index.ts
|
|
29
|
-
const logger =
|
|
30
|
-
enabled: process.env.NODE_ENV !== "production",
|
|
31
|
-
level: "warn",
|
|
32
|
-
prefix: "[DisplayShapeLayer]",
|
|
33
|
-
pretty: true
|
|
34
|
-
});
|
|
32
|
+
const logger = createLoggerDomain("[DisplayShapeLayer]");
|
|
35
33
|
/**
|
|
36
34
|
* Typed event bus instance for shape events.
|
|
37
35
|
* Provides type-safe event emission for shape interactions.
|
|
@@ -46,24 +44,27 @@ const shapeBus = Broadcast.getInstance();
|
|
|
46
44
|
* ## Features
|
|
47
45
|
* - **Multiple geometry types**: Point, LineString, Polygon, and Circle
|
|
48
46
|
* - **Icon support**: Custom icons for Point geometries via icon atlases
|
|
49
|
-
* - **Interactive selection**: Click handling with
|
|
50
|
-
* - **Hover effects**:
|
|
47
|
+
* - **Interactive selection**: Click handling with brightness overlay on polygon select, optional highlight effect for non-icon-Point shapes (if showHighlight=true)
|
|
48
|
+
* - **Hover effects**: Polygon fills brighten via material lighting; outline width increases by 2px on hover
|
|
51
49
|
* - **Customizable labels**: Flexible label positioning with per-shape or global options
|
|
52
50
|
* - **Style properties**: Full control over colors, border/outline patterns, and opacity
|
|
53
51
|
* - **Event bus integration**: Automatically emits shape events via @accelint/bus
|
|
54
52
|
* - **Multi-map support**: Events include map instance ID for isolation
|
|
55
53
|
*
|
|
56
|
-
* ##
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* -
|
|
54
|
+
* ## Interaction Philosophy
|
|
55
|
+
* Interactions never modify a shape's innate styling. Hover and selection are always
|
|
56
|
+
* additive overlays rendered apart from the main layer using opacity-scaled fill colors
|
|
57
|
+
* and material-based brightness — the base shape is never altered.
|
|
60
58
|
*
|
|
61
59
|
* ## Layer Structure
|
|
62
|
-
* Renders up to
|
|
63
|
-
* 1. **
|
|
64
|
-
* 2. **
|
|
65
|
-
* 3. **
|
|
66
|
-
* 4. **
|
|
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
|
|
64
|
+
* 4. **Elevation visualization**: Curtains (LineStrings) or wireframes (polygons) — elevation only
|
|
65
|
+
* 5. **Elevation indicators**: Vertical strut lines for elevated non-polygon shapes — elevation only
|
|
66
|
+
* 6. **Main GeoJsonLayer**: Shape geometries with styling and interaction
|
|
67
|
+
* 7. **Label layer**: Text labels (if showLabels enabled)
|
|
67
68
|
*
|
|
68
69
|
* ## Icon Atlas Constraint
|
|
69
70
|
* When using icons for Point geometries, all shapes in a single layer must share the
|
|
@@ -124,6 +125,10 @@ const shapeBus = Broadcast.getInstance();
|
|
|
124
125
|
var DisplayShapeLayer = class extends CompositeLayer {
|
|
125
126
|
/** Cache for transformed features to avoid recreating objects on every render */
|
|
126
127
|
featuresCache = null;
|
|
128
|
+
/** Cache for elevation classification and curtain features */
|
|
129
|
+
elevationCache = null;
|
|
130
|
+
/** Cache for elevation indicator line segments */
|
|
131
|
+
indicatorCache = null;
|
|
127
132
|
static layerName = "DisplayShapeLayer";
|
|
128
133
|
static defaultProps = { ...DEFAULT_DISPLAY_PROPS };
|
|
129
134
|
/**
|
|
@@ -135,19 +140,64 @@ var DisplayShapeLayer = class extends CompositeLayer {
|
|
|
135
140
|
lastHoveredId: void 0
|
|
136
141
|
});
|
|
137
142
|
this.featuresCache = null;
|
|
143
|
+
this.elevationCache = null;
|
|
144
|
+
this.indicatorCache = null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolved highlight color — uses prop if provided, falls back to default.
|
|
148
|
+
*/
|
|
149
|
+
get resolvedHighlight() {
|
|
150
|
+
return this.props.highlightColor ?? HIGHLIGHT_COLOR_TUPLE;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Handle picking events from the main shapes layer
|
|
154
|
+
*/
|
|
155
|
+
handleMainLayerPick(info, mode) {
|
|
156
|
+
if (mode === "query") this.handleShapeClick(info);
|
|
157
|
+
if (mode === "hover" || !mode) {
|
|
158
|
+
if (info.index !== void 0 && info.index !== this.state?.hoverIndex) this.setState({ hoverIndex: info.index });
|
|
159
|
+
this.handleShapeHover(info);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Handle picking events from curtain layers and map back to original LineString
|
|
164
|
+
*/
|
|
165
|
+
handleCurtainPick(info, mode) {
|
|
166
|
+
if (!info.object) return;
|
|
167
|
+
const curtainShapeId = info.object.properties?.shapeId;
|
|
168
|
+
if (!curtainShapeId) return;
|
|
169
|
+
const features = this.getFeaturesWithId();
|
|
170
|
+
const featureIndex = this.featuresCache?.shapeIdToIndex.get(curtainShapeId);
|
|
171
|
+
if (featureIndex === void 0) return;
|
|
172
|
+
const modifiedInfo = {
|
|
173
|
+
...info,
|
|
174
|
+
index: featureIndex,
|
|
175
|
+
object: features[featureIndex]
|
|
176
|
+
};
|
|
177
|
+
if (mode === "query") this.handleShapeClick(modifiedInfo);
|
|
178
|
+
if (mode === "hover" || !mode) {
|
|
179
|
+
if (featureIndex !== this.state?.hoverIndex) this.setState({ hoverIndex: featureIndex });
|
|
180
|
+
this.handleShapeHover(modifiedInfo);
|
|
181
|
+
}
|
|
182
|
+
return modifiedInfo;
|
|
138
183
|
}
|
|
139
184
|
/**
|
|
140
185
|
* Override getPickingInfo to handle events from sublayers
|
|
141
186
|
* This is the correct pattern for CompositeLayer event handling
|
|
142
187
|
*/
|
|
143
188
|
getPickingInfo({ info, mode, sourceLayer }) {
|
|
189
|
+
if ((mode === "hover" || !mode) && (info.index === void 0 || info.index < 0)) {
|
|
190
|
+
if (this.state?.hoverIndex !== void 0) this.setState({ hoverIndex: void 0 });
|
|
191
|
+
this.handleShapeHover(info);
|
|
192
|
+
return info;
|
|
193
|
+
}
|
|
144
194
|
if (sourceLayer?.id === `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}`) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
195
|
+
this.handleMainLayerPick(info, mode);
|
|
196
|
+
return info;
|
|
197
|
+
}
|
|
198
|
+
if (sourceLayer?.id?.includes("-elevation-curtain")) {
|
|
199
|
+
const curtainInfo = this.handleCurtainPick(info, mode);
|
|
200
|
+
if (curtainInfo) return curtainInfo;
|
|
151
201
|
}
|
|
152
202
|
return info;
|
|
153
203
|
}
|
|
@@ -160,20 +210,25 @@ var DisplayShapeLayer = class extends CompositeLayer {
|
|
|
160
210
|
if (this.featuresCache?.data === data) return this.featuresCache.features;
|
|
161
211
|
const features = [];
|
|
162
212
|
const shapeIdToIndex = /* @__PURE__ */ new Map();
|
|
213
|
+
const normalizedLineColors = [];
|
|
163
214
|
for (const [i, shape] of data.entries()) {
|
|
164
|
-
|
|
215
|
+
let feature = {
|
|
165
216
|
...shape.feature,
|
|
166
217
|
properties: {
|
|
167
218
|
...shape.feature.properties,
|
|
168
219
|
shapeId: shape.id
|
|
169
220
|
}
|
|
170
|
-
}
|
|
221
|
+
};
|
|
222
|
+
if (isPolygonGeometry(feature.geometry) && getFeatureElevation(feature) > 0) feature = flattenFeatureTo2D(feature);
|
|
223
|
+
features.push(feature);
|
|
171
224
|
shapeIdToIndex.set(shape.id, i);
|
|
225
|
+
normalizedLineColors.push(getLineColor(shape.feature));
|
|
172
226
|
}
|
|
173
227
|
this.featuresCache = {
|
|
174
228
|
data,
|
|
175
229
|
features,
|
|
176
|
-
shapeIdToIndex
|
|
230
|
+
shapeIdToIndex,
|
|
231
|
+
normalizedLineColors
|
|
177
232
|
};
|
|
178
233
|
return features;
|
|
179
234
|
}
|
|
@@ -182,7 +237,8 @@ var DisplayShapeLayer = class extends CompositeLayer {
|
|
|
182
237
|
* Used by event handlers to get full shape without storing in feature properties.
|
|
183
238
|
*/
|
|
184
239
|
getShapeById(shapeId) {
|
|
185
|
-
|
|
240
|
+
const index = this.featuresCache?.shapeIdToIndex.get(shapeId);
|
|
241
|
+
return index !== void 0 ? this.props.data[index] : void 0;
|
|
186
242
|
}
|
|
187
243
|
/**
|
|
188
244
|
* Handle shape click
|
|
@@ -205,116 +261,166 @@ var DisplayShapeLayer = class extends CompositeLayer {
|
|
|
205
261
|
*/
|
|
206
262
|
handleShapeHover = (info) => {
|
|
207
263
|
const { onShapeHover, mapId } = this.props;
|
|
208
|
-
const shapeId = info.object?.properties?.shapeId
|
|
209
|
-
const shape = shapeId ? this.getShapeById(shapeId)
|
|
264
|
+
const shapeId = info.object?.properties?.shapeId;
|
|
265
|
+
const shape = shapeId ? this.getShapeById(shapeId) : void 0;
|
|
210
266
|
if (shapeId !== this.state?.lastHoveredId) {
|
|
211
267
|
this.setState({ lastHoveredId: shapeId });
|
|
212
268
|
shapeBus.emit(ShapeEvents.hovered, {
|
|
213
|
-
shapeId,
|
|
269
|
+
shapeId: shapeId ?? null,
|
|
214
270
|
mapId
|
|
215
271
|
});
|
|
216
272
|
}
|
|
217
273
|
if (onShapeHover) onShapeHover(shape);
|
|
218
274
|
};
|
|
219
275
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
276
|
+
* Get or compute elevation-derived data (feature classification + curtain features).
|
|
277
|
+
* Cached on features identity and applyBaseOpacity to avoid per-frame recomputation.
|
|
278
|
+
*/
|
|
279
|
+
getElevationData(features, applyBaseOpacity) {
|
|
280
|
+
if (this.elevationCache !== null && this.elevationCache.features === features && this.elevationCache.applyBaseOpacity === applyBaseOpacity) return this.elevationCache;
|
|
281
|
+
const classification = classifyElevatedFeatures(features, getFeatureElevation);
|
|
282
|
+
const curtainFeatures = createCurtainPolygonFeatures(classification.lines, applyBaseOpacity);
|
|
283
|
+
this.elevationCache = {
|
|
284
|
+
features,
|
|
285
|
+
applyBaseOpacity,
|
|
286
|
+
classification,
|
|
287
|
+
curtainFeatures
|
|
288
|
+
};
|
|
289
|
+
return {
|
|
290
|
+
classification,
|
|
291
|
+
curtainFeatures
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Render highlight sublayer (underneath main layer).
|
|
296
|
+
* Note: Points with icons use coffin corners instead of highlight layer.
|
|
222
297
|
*/
|
|
223
298
|
renderHighlightLayer(features) {
|
|
224
|
-
const { selectedShapeId, showHighlight
|
|
225
|
-
if (!selectedShapeId || showHighlight === false) return
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
if (selectedFeature
|
|
229
|
-
|
|
299
|
+
const { selectedShapeId, showHighlight } = this.props;
|
|
300
|
+
if (!selectedShapeId || showHighlight === false) return [];
|
|
301
|
+
const featureIndex = this.featuresCache?.shapeIdToIndex.get(selectedShapeId);
|
|
302
|
+
const selectedFeature = featureIndex !== void 0 ? features[featureIndex] : void 0;
|
|
303
|
+
if (!selectedFeature) return [];
|
|
304
|
+
if (isPointType(selectedFeature.geometry)) {
|
|
305
|
+
if (!!selectedFeature.properties?.styleProperties?.icon) return [];
|
|
230
306
|
}
|
|
231
|
-
|
|
307
|
+
const highlightFeature = flattenFeatureTo2D(selectedFeature);
|
|
308
|
+
const lineColor = this.resolvedHighlight;
|
|
309
|
+
return [new GeoJsonLayer({
|
|
232
310
|
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY_HIGHLIGHT}`,
|
|
233
|
-
data: [
|
|
234
|
-
filled:
|
|
311
|
+
data: [highlightFeature],
|
|
312
|
+
filled: false,
|
|
235
313
|
stroked: true,
|
|
236
314
|
lineWidthUnits: "pixels",
|
|
237
315
|
lineWidthMinPixels: MAP_INTERACTION.LINE_WIDTH_MIN_PIXELS,
|
|
238
|
-
|
|
239
|
-
0,
|
|
240
|
-
0,
|
|
241
|
-
0,
|
|
242
|
-
0
|
|
243
|
-
],
|
|
244
|
-
getLineColor: () => highlightColor || getHighlightColor(),
|
|
316
|
+
getLineColor: lineColor,
|
|
245
317
|
getLineWidth: getHighlightLineWidth,
|
|
246
318
|
pickable: false,
|
|
247
319
|
updateTriggers: {
|
|
248
|
-
getLineColor: [highlightColor],
|
|
320
|
+
getLineColor: [this.props.highlightColor],
|
|
249
321
|
getLineWidth: [selectedShapeId, features]
|
|
250
322
|
}
|
|
251
|
-
});
|
|
323
|
+
})];
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Render selection overlay layer for polygon shapes.
|
|
327
|
+
* Mirrors renderHoverLayer but triggers on selectedShapeId instead of hover.
|
|
328
|
+
* When a shape is both selected and hovered, both layers stack for a brighter combined effect.
|
|
329
|
+
*/
|
|
330
|
+
renderSelectLayer(features) {
|
|
331
|
+
const { selectedShapeId, enableElevation } = this.props;
|
|
332
|
+
if (!selectedShapeId) return [];
|
|
333
|
+
const featureIndex = this.featuresCache?.shapeIdToIndex.get(selectedShapeId);
|
|
334
|
+
const selectedFeature = featureIndex !== void 0 ? features[featureIndex] : void 0;
|
|
335
|
+
if (!selectedFeature) return [];
|
|
336
|
+
if (!isPolygonGeometry(selectedFeature.geometry)) return [];
|
|
337
|
+
return [new GeoJsonLayer({
|
|
338
|
+
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY_SELECTION}`,
|
|
339
|
+
data: [selectedFeature],
|
|
340
|
+
filled: true,
|
|
341
|
+
stroked: false,
|
|
342
|
+
getFillColor: getOverlayFillColor,
|
|
343
|
+
extruded: enableElevation,
|
|
344
|
+
getElevation: getFeatureElevation,
|
|
345
|
+
material: MATERIAL_SETTINGS.HOVER_OR_SELECT,
|
|
346
|
+
pickable: false,
|
|
347
|
+
updateTriggers: {
|
|
348
|
+
data: [features, selectedShapeId],
|
|
349
|
+
getFillColor: [features],
|
|
350
|
+
getElevation: [features]
|
|
351
|
+
}
|
|
352
|
+
})];
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Render hover layer for all polygon shapes (2D and 3D).
|
|
356
|
+
* Overlays the shape's base fill with brighter material lighting.
|
|
357
|
+
* Stacks with other interaction layers (e.g. selection highlight underneath).
|
|
358
|
+
*/
|
|
359
|
+
renderHoverLayer(features) {
|
|
360
|
+
const { enableElevation, selectedShapeId } = this.props;
|
|
361
|
+
const hoverIndex = this.state?.hoverIndex;
|
|
362
|
+
if (hoverIndex === void 0) return [];
|
|
363
|
+
const hoveredFeature = features[hoverIndex];
|
|
364
|
+
if (!hoveredFeature) return [];
|
|
365
|
+
if (!isPolygonGeometry(hoveredFeature.geometry)) return [];
|
|
366
|
+
const material = hoveredFeature.properties?.shapeId === selectedShapeId ? MATERIAL_SETTINGS.HOVER_AND_SELECT : MATERIAL_SETTINGS.HOVER_OR_SELECT;
|
|
367
|
+
return [new GeoJsonLayer({
|
|
368
|
+
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-hover`,
|
|
369
|
+
data: [hoveredFeature],
|
|
370
|
+
filled: true,
|
|
371
|
+
stroked: false,
|
|
372
|
+
getFillColor: getOverlayFillColor,
|
|
373
|
+
extruded: enableElevation,
|
|
374
|
+
getElevation: getFeatureElevation,
|
|
375
|
+
material,
|
|
376
|
+
pickable: false,
|
|
377
|
+
updateTriggers: {
|
|
378
|
+
data: [features, hoverIndex],
|
|
379
|
+
getFillColor: [features],
|
|
380
|
+
getElevation: [features],
|
|
381
|
+
material: [selectedShapeId, hoverIndex]
|
|
382
|
+
}
|
|
383
|
+
})];
|
|
252
384
|
}
|
|
253
385
|
/**
|
|
254
386
|
* Render coffin corners layer for Point geometries that have icons on hover/select
|
|
255
|
-
* Coffin corners provide visual feedback for points instead of
|
|
387
|
+
* Coffin corners provide visual feedback for points instead of select layer
|
|
256
388
|
*/
|
|
257
389
|
renderCoffinCornersLayer(features) {
|
|
258
390
|
const { selectedShapeId } = this.props;
|
|
259
391
|
const hoverIndex = this.state?.hoverIndex;
|
|
260
392
|
const shapeIdToIndex = this.featuresCache?.shapeIdToIndex;
|
|
261
|
-
if (!shapeIdToIndex) return
|
|
262
|
-
const pointFeatures =
|
|
263
|
-
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
const isSelected =
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (pointFeatures.length === 0) return null;
|
|
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 [];
|
|
271
402
|
const firstPointIcon = pointFeatures[0]?.properties?.styleProperties?.icon;
|
|
272
403
|
const iconAtlas = firstPointIcon?.atlas;
|
|
273
404
|
const iconMapping = firstPointIcon?.mapping;
|
|
274
405
|
if (!(iconAtlas && iconMapping)) {
|
|
275
406
|
logger.warn("Point shape has icon style but missing iconAtlas or iconMapping - coffin corners will not render");
|
|
276
|
-
return
|
|
407
|
+
return [];
|
|
277
408
|
}
|
|
278
|
-
const extendedMapping =
|
|
279
|
-
|
|
280
|
-
[COFFIN_CORNERS.HOVER_ICON]: {
|
|
281
|
-
x: 0,
|
|
282
|
-
y: 0,
|
|
283
|
-
width: 76,
|
|
284
|
-
height: 76,
|
|
285
|
-
mask: false
|
|
286
|
-
},
|
|
287
|
-
[COFFIN_CORNERS.SELECTED_ICON]: {
|
|
288
|
-
x: 76,
|
|
289
|
-
y: 0,
|
|
290
|
-
width: 76,
|
|
291
|
-
height: 76,
|
|
292
|
-
mask: false
|
|
293
|
-
},
|
|
294
|
-
[COFFIN_CORNERS.SELECTED_HOVER_ICON]: {
|
|
295
|
-
x: 152,
|
|
296
|
-
y: 0,
|
|
297
|
-
width: 76,
|
|
298
|
-
height: 76,
|
|
299
|
-
mask: false
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
return new IconLayer({
|
|
409
|
+
const extendedMapping = extendMappingWithCoffinCorners(iconMapping);
|
|
410
|
+
return [new IconLayer({
|
|
303
411
|
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-coffin-corners`,
|
|
304
412
|
data: pointFeatures,
|
|
305
413
|
iconAtlas,
|
|
306
414
|
iconMapping: extendedMapping,
|
|
307
415
|
getIcon: (d) => {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
const featureIndex = shapeId ? shapeIdToIndex.get(shapeId) : void 0;
|
|
311
|
-
if (isSelected && hoverIndex !== void 0 && featureIndex === hoverIndex) return COFFIN_CORNERS.SELECTED_HOVER_ICON;
|
|
416
|
+
const { isSelected, isHovered } = getPointInteractionState(d, selectedShapeId, hoverIndex, shapeIdToIndex);
|
|
417
|
+
if (isSelected && isHovered) return COFFIN_CORNERS.SELECTED_HOVER_ICON;
|
|
312
418
|
if (isSelected) return COFFIN_CORNERS.SELECTED_ICON;
|
|
313
419
|
return COFFIN_CORNERS.HOVER_ICON;
|
|
314
420
|
},
|
|
315
421
|
getSize: COFFIN_CORNERS.SIZE,
|
|
316
422
|
getPosition: (d) => {
|
|
317
|
-
return d.geometry
|
|
423
|
+
return isPointType(d.geometry) ? d.geometry.coordinates : [0, 0];
|
|
318
424
|
},
|
|
319
425
|
getPixelOffset: (d) => {
|
|
320
426
|
return [-1, -(d.properties?.styleProperties?.icon?.size ?? MAP_INTERACTION.ICON_SIZE) / 2];
|
|
@@ -329,80 +435,63 @@ var DisplayShapeLayer = class extends CompositeLayer {
|
|
|
329
435
|
this.state?.hoverIndex
|
|
330
436
|
]
|
|
331
437
|
}
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* Extract icon configuration from features in a single pass.
|
|
336
|
-
* Returns the first icon's atlas and mapping (all shapes share the same atlas).
|
|
337
|
-
* Uses early return for O(1) best case when first feature has icons.
|
|
338
|
-
*/
|
|
339
|
-
getIconConfig(features) {
|
|
340
|
-
for (const f of features) {
|
|
341
|
-
const icon = f.properties?.styleProperties?.icon;
|
|
342
|
-
if (icon) return {
|
|
343
|
-
hasIcons: true,
|
|
344
|
-
atlas: icon.atlas,
|
|
345
|
-
mapping: icon.mapping
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
return { hasIcons: false };
|
|
438
|
+
})];
|
|
349
439
|
}
|
|
350
440
|
/**
|
|
351
441
|
* Render main shapes layer
|
|
352
442
|
*/
|
|
353
443
|
renderMainLayer(features) {
|
|
354
444
|
const { pickable, applyBaseOpacity, selectedShapeId } = this.props;
|
|
355
|
-
const { hasIcons, atlas: iconAtlas, mapping: iconMapping } =
|
|
445
|
+
const { hasIcons, atlas: iconAtlas, mapping: iconMapping } = getIconConfig(features);
|
|
356
446
|
return new GeoJsonLayer({
|
|
357
447
|
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}`,
|
|
358
448
|
data: features,
|
|
359
449
|
filled: true,
|
|
360
450
|
stroked: true,
|
|
361
451
|
getFillColor: (d) => getFillColor(d, applyBaseOpacity),
|
|
362
|
-
getLineColor,
|
|
452
|
+
getLineColor: (d, info) => {
|
|
453
|
+
const baseColor = this.featuresCache?.normalizedLineColors[info?.index ?? -1] ?? getLineColor(d);
|
|
454
|
+
const isHovered = info?.index === this.state?.hoverIndex;
|
|
455
|
+
const isSelected = d.properties?.shapeId === selectedShapeId;
|
|
456
|
+
if (isHovered && isSelected) return brightenColor(baseColor, BRIGHTNESS_FACTOR.HOVER_AND_SELECT);
|
|
457
|
+
if (isHovered || isSelected) return brightenColor(baseColor, BRIGHTNESS_FACTOR.HOVER_OR_SELECT);
|
|
458
|
+
return baseColor;
|
|
459
|
+
},
|
|
363
460
|
getLineWidth: (d, info) => {
|
|
461
|
+
if (this.props.enableElevation && isLineGeometry(d.geometry) && getFeatureElevation(d) > 0) return d.properties?.styleProperties?.lineWidth ?? 2;
|
|
364
462
|
return getHoverLineWidth(d, info?.index === this.state?.hoverIndex);
|
|
365
463
|
},
|
|
366
464
|
lineWidthUnits: "pixels",
|
|
367
465
|
lineWidthMinPixels: MAP_INTERACTION.LINE_WIDTH_MIN_PIXELS,
|
|
368
466
|
lineWidthMaxPixels: 20,
|
|
467
|
+
extruded: this.props.enableElevation ?? false,
|
|
468
|
+
getElevation: getFeatureElevation,
|
|
469
|
+
...this.props.enableElevation ? { material: MATERIAL_SETTINGS.NORMAL } : {},
|
|
369
470
|
pointType: hasIcons ? "icon" : "circle",
|
|
370
471
|
getPointRadius: (d) => {
|
|
371
472
|
return d.properties?.styleProperties?.icon?.size ?? 2;
|
|
372
473
|
},
|
|
373
474
|
pointRadiusUnits: "pixels",
|
|
374
|
-
...hasIcons
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
getIcon: (d) => d.properties?.styleProperties?.icon?.name ?? "marker",
|
|
378
|
-
getIconSize: (d) => {
|
|
379
|
-
return d.properties?.styleProperties?.icon?.size ?? MAP_INTERACTION.ICON_SIZE;
|
|
380
|
-
},
|
|
381
|
-
getIconColor: getLineColor,
|
|
382
|
-
getIconPixelOffset: (d) => {
|
|
383
|
-
return [-1, -(d.properties?.styleProperties?.icon?.size ?? MAP_INTERACTION.ICON_SIZE) / 2];
|
|
384
|
-
},
|
|
385
|
-
iconBillboard: false
|
|
386
|
-
} : {},
|
|
387
|
-
extensions: [new PathStyleExtension({ dash: true })],
|
|
388
|
-
getDashArray: (d) => {
|
|
389
|
-
if (d.properties?.shapeId === selectedShapeId) return DASH_ARRAYS.dotted;
|
|
390
|
-
return getDashArray(d);
|
|
391
|
-
},
|
|
475
|
+
...getIconLayerProps(hasIcons, iconAtlas, iconMapping),
|
|
476
|
+
extensions: DASH_EXTENSION,
|
|
477
|
+
getDashArray,
|
|
392
478
|
pickable,
|
|
393
479
|
autoHighlight: false,
|
|
480
|
+
...this.props.enableElevation ? { parameters: {
|
|
481
|
+
depthTest: true,
|
|
482
|
+
depthCompare: "less-equal"
|
|
483
|
+
} } : {},
|
|
394
484
|
updateTriggers: {
|
|
395
485
|
getFillColor: [features, applyBaseOpacity],
|
|
396
|
-
getLineColor: [
|
|
486
|
+
getLineColor: [
|
|
487
|
+
features,
|
|
488
|
+
this.state?.hoverIndex,
|
|
489
|
+
selectedShapeId
|
|
490
|
+
],
|
|
397
491
|
getLineWidth: [features, this.state?.hoverIndex],
|
|
398
|
-
getDashArray: [features
|
|
492
|
+
getDashArray: [features],
|
|
399
493
|
getPointRadius: [features],
|
|
400
|
-
...hasIcons
|
|
401
|
-
getIcon: [features],
|
|
402
|
-
getIconSize: [features],
|
|
403
|
-
getIconColor: [features],
|
|
404
|
-
getIconPixelOffset: [features]
|
|
405
|
-
} : {}
|
|
494
|
+
...getIconUpdateTriggers(hasIcons, features)
|
|
406
495
|
}
|
|
407
496
|
});
|
|
408
497
|
}
|
|
@@ -415,32 +504,170 @@ var DisplayShapeLayer = class extends CompositeLayer {
|
|
|
415
504
|
*/
|
|
416
505
|
renderLabelsLayer() {
|
|
417
506
|
const { showLabels, data, labelOptions } = this.props;
|
|
418
|
-
if (showLabels === "never") return
|
|
507
|
+
if (showLabels === "never") return [];
|
|
419
508
|
let labelData = data;
|
|
420
509
|
if (showLabels === "hover") {
|
|
421
510
|
const hoverIndex = this.state?.hoverIndex;
|
|
422
|
-
if (hoverIndex === void 0) return
|
|
511
|
+
if (hoverIndex === void 0) return [];
|
|
423
512
|
const hoveredShape = data[hoverIndex];
|
|
424
513
|
labelData = hoveredShape ? [hoveredShape] : [];
|
|
425
514
|
}
|
|
426
|
-
if (labelData.length === 0) return
|
|
427
|
-
return createShapeLabelLayer({
|
|
515
|
+
if (labelData.length === 0) return [];
|
|
516
|
+
return [createShapeLabelLayer({
|
|
428
517
|
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY_LABELS}`,
|
|
429
518
|
data: labelData,
|
|
430
519
|
labelOptions
|
|
520
|
+
})];
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Render vertical elevation indicator lines for non-polygon shapes.
|
|
524
|
+
* Creates vertical "strut" lines from ground level to elevated features.
|
|
525
|
+
* For LineStrings, creates a "curtain" effect with vertical lines at each coordinate.
|
|
526
|
+
* Polygons use wireframe extrusion instead.
|
|
527
|
+
*/
|
|
528
|
+
renderElevationIndicatorLayer(features, elevatedNonPolygons) {
|
|
529
|
+
if (elevatedNonPolygons.length === 0) return [];
|
|
530
|
+
const { selectedShapeId } = this.props;
|
|
531
|
+
const hoverIndex = this.state?.hoverIndex;
|
|
532
|
+
const cache = this.indicatorCache;
|
|
533
|
+
let lineData;
|
|
534
|
+
if (cache !== null && cache.features === features && cache.selectedShapeId === selectedShapeId && cache.hoverIndex === hoverIndex) lineData = cache.lineData;
|
|
535
|
+
else {
|
|
536
|
+
lineData = buildIndicatorLineData(elevatedNonPolygons, features, selectedShapeId, hoverIndex);
|
|
537
|
+
this.indicatorCache = {
|
|
538
|
+
features,
|
|
539
|
+
selectedShapeId,
|
|
540
|
+
hoverIndex,
|
|
541
|
+
lineData
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
if (lineData.length === 0) return [];
|
|
545
|
+
return [new LineLayer({
|
|
546
|
+
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-elevation-indicators`,
|
|
547
|
+
data: lineData,
|
|
548
|
+
getSourcePosition: (d) => d.source,
|
|
549
|
+
getTargetPosition: (d) => d.target,
|
|
550
|
+
getColor: (d) => d.color,
|
|
551
|
+
getWidth: 2,
|
|
552
|
+
widthUnits: "pixels",
|
|
553
|
+
pickable: false,
|
|
554
|
+
updateTriggers: {
|
|
555
|
+
data: [
|
|
556
|
+
features,
|
|
557
|
+
selectedShapeId,
|
|
558
|
+
hoverIndex
|
|
559
|
+
],
|
|
560
|
+
getColor: [
|
|
561
|
+
features,
|
|
562
|
+
selectedShapeId,
|
|
563
|
+
hoverIndex
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
})];
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Create a single curtain GeoJsonLayer with shared configuration.
|
|
570
|
+
*/
|
|
571
|
+
createCurtainGeoJsonLayer(idSuffix, data, getFillColor$1, dataTriggers, fillColorTriggers) {
|
|
572
|
+
return new GeoJsonLayer({
|
|
573
|
+
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-${idSuffix}`,
|
|
574
|
+
data,
|
|
575
|
+
filled: true,
|
|
576
|
+
stroked: false,
|
|
577
|
+
_full3d: true,
|
|
578
|
+
getFillColor: getFillColor$1,
|
|
579
|
+
pickable: this.props.pickable ?? true,
|
|
580
|
+
parameters: {
|
|
581
|
+
depthTest: true,
|
|
582
|
+
depthCompare: "less-equal"
|
|
583
|
+
},
|
|
584
|
+
updateTriggers: {
|
|
585
|
+
data: dataTriggers,
|
|
586
|
+
getFillColor: fillColorTriggers
|
|
587
|
+
}
|
|
431
588
|
});
|
|
432
589
|
}
|
|
433
590
|
/**
|
|
591
|
+
* Render curtain layers for elevated LineStrings.
|
|
592
|
+
* Creates three separate layers for main, hovered, and selected states.
|
|
593
|
+
*/
|
|
594
|
+
renderCurtainLayers(features, allCurtainFeatures) {
|
|
595
|
+
const layers = [];
|
|
596
|
+
const { selectedShapeId } = this.props;
|
|
597
|
+
const hoverIndex = this.state?.hoverIndex;
|
|
598
|
+
const hoveredShapeId = hoverIndex !== void 0 && features[hoverIndex] ? features[hoverIndex].properties?.shapeId : void 0;
|
|
599
|
+
const { main, hovered, selected } = partitionCurtains(allCurtainFeatures, hoveredShapeId, selectedShapeId);
|
|
600
|
+
const isSelectedHovered = selectedShapeId === hoveredShapeId;
|
|
601
|
+
const dataTriggers = [
|
|
602
|
+
features,
|
|
603
|
+
hoveredShapeId,
|
|
604
|
+
selectedShapeId
|
|
605
|
+
];
|
|
606
|
+
if (main.length > 0) layers.push(this.createCurtainGeoJsonLayer("elevation-curtain", main, (d) => d.properties.fillColor, dataTriggers, [features, this.props.applyBaseOpacity]));
|
|
607
|
+
if (hovered.length > 0) {
|
|
608
|
+
const hoveredColor = applyOverlayOpacity(brightenColor(hovered[0].properties.lineColor, BRIGHTNESS_FACTOR.HOVER_OR_SELECT));
|
|
609
|
+
layers.push(this.createCurtainGeoJsonLayer("elevation-curtain-hover", hovered, () => hoveredColor, dataTriggers, [features]));
|
|
610
|
+
}
|
|
611
|
+
if (selected.length > 0) {
|
|
612
|
+
const factor = isSelectedHovered ? BRIGHTNESS_FACTOR.HOVER_AND_SELECT : BRIGHTNESS_FACTOR.HOVER_OR_SELECT;
|
|
613
|
+
const selectedColor = applyOverlayOpacity(brightenColor(selected[0].properties.lineColor, factor));
|
|
614
|
+
layers.push(this.createCurtainGeoJsonLayer("elevation-curtain-selected", selected, () => selectedColor, dataTriggers, [features, isSelectedHovered]));
|
|
615
|
+
}
|
|
616
|
+
return layers;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Render elevation visualization layers (curtains for lines, wireframes for polygons).
|
|
620
|
+
*/
|
|
621
|
+
renderElevationVisualizationLayer(features, allCurtainFeatures, elevatedPolygons) {
|
|
622
|
+
const layers = [];
|
|
623
|
+
if (allCurtainFeatures.length > 0) layers.push(...this.renderCurtainLayers(features, allCurtainFeatures));
|
|
624
|
+
if (elevatedPolygons.length > 0) {
|
|
625
|
+
const { applyBaseOpacity } = this.props;
|
|
626
|
+
layers.push(new GeoJsonLayer({
|
|
627
|
+
id: `${this.props.id}-${SHAPE_LAYER_IDS.DISPLAY}-elevation-wireframe`,
|
|
628
|
+
data: elevatedPolygons,
|
|
629
|
+
filled: false,
|
|
630
|
+
stroked: false,
|
|
631
|
+
extruded: true,
|
|
632
|
+
wireframe: true,
|
|
633
|
+
getElevation: getFeatureElevation,
|
|
634
|
+
getFillColor: (d) => getFillColor(d, applyBaseOpacity),
|
|
635
|
+
getLineColor,
|
|
636
|
+
pickable: false,
|
|
637
|
+
parameters: {
|
|
638
|
+
depthTest: true,
|
|
639
|
+
depthCompare: "less-equal"
|
|
640
|
+
},
|
|
641
|
+
updateTriggers: {
|
|
642
|
+
getElevation: [features],
|
|
643
|
+
getFillColor: [features, applyBaseOpacity],
|
|
644
|
+
getLineColor: [features]
|
|
645
|
+
}
|
|
646
|
+
}));
|
|
647
|
+
}
|
|
648
|
+
return layers;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
434
651
|
* Render all sublayers
|
|
435
652
|
*/
|
|
436
653
|
renderLayers() {
|
|
437
654
|
const features = this.getFeaturesWithId();
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
this.
|
|
441
|
-
this.
|
|
442
|
-
this.
|
|
443
|
-
|
|
655
|
+
const enableElevation = this.props.enableElevation ?? false;
|
|
656
|
+
const layers = [
|
|
657
|
+
...this.renderHighlightLayer(features),
|
|
658
|
+
...this.renderSelectLayer(features),
|
|
659
|
+
...this.renderHoverLayer(features),
|
|
660
|
+
...this.renderCoffinCornersLayer(features)
|
|
661
|
+
];
|
|
662
|
+
if (enableElevation) {
|
|
663
|
+
const { classification, curtainFeatures } = this.getElevationData(features, this.props.applyBaseOpacity);
|
|
664
|
+
const { polygons, nonPolygons } = classification;
|
|
665
|
+
layers.push(...this.renderElevationVisualizationLayer(features, curtainFeatures, polygons));
|
|
666
|
+
layers.push(...this.renderElevationIndicatorLayer(features, nonPolygons));
|
|
667
|
+
}
|
|
668
|
+
layers.push(this.renderMainLayer(features));
|
|
669
|
+
layers.push(...this.renderLabelsLayer());
|
|
670
|
+
return layers;
|
|
444
671
|
}
|
|
445
672
|
};
|
|
446
673
|
|