@anov/gis-skills-cli 0.0.0-stage → 0.3.3
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 +637 -0
- package/INSTALL.md +481 -0
- package/LICENSE +15 -0
- package/README.md +148 -2
- package/RELEASING.md +162 -0
- package/bin/anov-gis-skills.mjs +470 -0
- package/lib/mcp-config.mjs +273 -0
- package/package.json +43 -4
- package/skills/anovgis-analysis/SKILL.md +585 -0
- package/skills/anovgis-effects/SKILL.md +260 -0
- package/skills/anovgis-imagery-terrain/SKILL.md +505 -0
- package/skills/anovgis-layers/SKILL.md +627 -0
- package/skills/anovgis-materials/SKILL.md +635 -0
- package/skills/anovgis-models-3dtiles/SKILL.md +448 -0
- package/skills/anovgis-pitfalls/SKILL.md +561 -0
- package/skills/anovgis-popup-widget/SKILL.md +474 -0
- package/skills/anovgis-primitives/SKILL.md +482 -0
- package/skills/anovgis-vector-graphics/SKILL.md +602 -0
- package/skills/anovgis-viewer/SKILL.md +618 -0
- package/skills/using-anovgis/DEMO-MAP.md +64 -0
- package/skills/using-anovgis/DEMO-SKILL-MAP.md +248 -0
- package/skills/using-anovgis/DOMAINS.md +183 -0
- package/skills/using-anovgis/REFERENCE.md +114 -0
- package/skills/using-anovgis/SKILL.md +392 -0
- package/skills/using-anovgis/templates/README.md +154 -0
- package/skills/using-anovgis/templates/combo1-vue3-vite.md +295 -0
- package/skills/using-anovgis/templates/combo2-vue2-cli.md +119 -0
- package/skills/using-anovgis/templates/combo3-html-cdn.md +107 -0
- package/skills/using-anovgis/templates/combo4-vanilla-webpack.md +91 -0
- package/skills/using-anovgis/templates/wizard-profiles.md +105 -0
- package/vendor/cesiumjs-skills/LICENSE +201 -0
- package/vendor/cesiumjs-skills/NOTICE +18 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-3d-tiles/SKILL.md +465 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-camera/SKILL.md +500 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-core-utilities/SKILL.md +403 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/REFERENCE.md +397 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/SKILL.md +351 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/01-diffuse-tint.js +38 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/02-texture-swap.js +42 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/03-feature-id-tileset.js +29 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/04-translucent-override.js +37 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/05-vertex-displacement.js +49 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/06-metadata-ramp.js +34 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/07-voxel-shader.js +27 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/README.md +19 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/_sandcastle-template.html +9 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-entities/SKILL.md +389 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-imagery/SKILL.md +471 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-interaction/SKILL.md +423 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-materials-shaders/SKILL.md +292 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-models-particles/SKILL.md +423 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-primitives/SKILL.md +537 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-spatial-math/SKILL.md +358 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-terrain-environment/SKILL.md +401 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-time-properties/SKILL.md +353 -0
- package/vendor/cesiumjs-skills/skills/cesiumjs-viewer-setup/SKILL.md +434 -0
- package/vendor/cesiumjs-skills/skills/using-cesiumjs-skills/SKILL.md +35 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cesiumjs-interaction
|
|
3
|
+
description: "CesiumJS interaction and picking - ScreenSpaceEventHandler, multi-key KeyboardEventModifier input actions, Scene.pick, Scene.drillPick, Scene.pickPosition, mouse and touch events. Use when handling user clicks on the globe, selecting entities or 3D Tiles features, registering modifier-key shortcuts, implementing hover effects, or building drag-based interactions."
|
|
4
|
+
---
|
|
5
|
+
# CesiumJS Interaction & Picking
|
|
6
|
+
|
|
7
|
+
Version baseline: CesiumJS v1.142 (ES module imports, Ion token required).
|
|
8
|
+
|
|
9
|
+
## ScreenSpaceEventHandler
|
|
10
|
+
|
|
11
|
+
Central class for mouse, touch, and pointer events on the Cesium canvas.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { ScreenSpaceEventHandler, ScreenSpaceEventType,
|
|
15
|
+
KeyboardEventModifier, defined } from "cesium";
|
|
16
|
+
|
|
17
|
+
let handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
|
|
18
|
+
|
|
19
|
+
// Register a click handler
|
|
20
|
+
handler.setInputAction((event) => {
|
|
21
|
+
console.log("Clicked at", event.position.x, event.position.y);
|
|
22
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
23
|
+
|
|
24
|
+
// With keyboard modifier (Shift+Click)
|
|
25
|
+
handler.setInputAction((event) => {
|
|
26
|
+
console.log("Shift+Click at", event.position);
|
|
27
|
+
}, ScreenSpaceEventType.LEFT_CLICK, KeyboardEventModifier.SHIFT);
|
|
28
|
+
|
|
29
|
+
// With multiple modifiers (Ctrl+Shift+Click, 1.142+)
|
|
30
|
+
handler.setInputAction((event) => {
|
|
31
|
+
console.log("Ctrl+Shift+Click at", event.position);
|
|
32
|
+
}, ScreenSpaceEventType.LEFT_CLICK, [
|
|
33
|
+
KeyboardEventModifier.CTRL,
|
|
34
|
+
KeyboardEventModifier.SHIFT,
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
// Query or remove actions
|
|
38
|
+
const clickAction = handler.getInputAction(ScreenSpaceEventType.LEFT_CLICK);
|
|
39
|
+
const ctrlShiftClickAction = handler.getInputAction(ScreenSpaceEventType.LEFT_CLICK, [
|
|
40
|
+
KeyboardEventModifier.SHIFT,
|
|
41
|
+
KeyboardEventModifier.CTRL, // order does not matter
|
|
42
|
+
]);
|
|
43
|
+
if (defined(clickAction) && defined(ctrlShiftClickAction)) {
|
|
44
|
+
console.log("Click handlers registered");
|
|
45
|
+
}
|
|
46
|
+
handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
|
|
47
|
+
handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK, [
|
|
48
|
+
KeyboardEventModifier.CTRL,
|
|
49
|
+
KeyboardEventModifier.SHIFT,
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
// Always destroy when done to avoid memory leaks
|
|
53
|
+
handler = handler && handler.destroy();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The Viewer also has a built-in handler at `viewer.screenSpaceEventHandler` -- use it to avoid creating a second handler for simple cases.
|
|
57
|
+
|
|
58
|
+
## ScreenSpaceEventType Reference
|
|
59
|
+
|
|
60
|
+
| Event | Callback shape | Notes |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `LEFT_DOWN` / `LEFT_UP` / `LEFT_CLICK` | `({ position })` | Cartesian2 screen coords |
|
|
63
|
+
| `LEFT_DOUBLE_CLICK` | `({ position })` | Left only |
|
|
64
|
+
| `RIGHT_DOWN` / `RIGHT_UP` / `RIGHT_CLICK` | `({ position })` | |
|
|
65
|
+
| `MIDDLE_DOWN` / `MIDDLE_UP` / `MIDDLE_CLICK` | `({ position })` | |
|
|
66
|
+
| `MOUSE_MOVE` | `({ startPosition, endPosition })` | Fires on every pointer move |
|
|
67
|
+
| `WHEEL` | `(delta)` | Positive = scroll up |
|
|
68
|
+
| `PINCH_START` | `({ position1, position2 })` | Two-finger touch begins |
|
|
69
|
+
| `PINCH_END` | `()` | Two-finger touch ends |
|
|
70
|
+
| `PINCH_MOVE` | `({ distance, angleAndHeight })` | Two-finger move |
|
|
71
|
+
|
|
72
|
+
`KeyboardEventModifier`: `SHIFT`, `CTRL`, `ALT` -- optional third argument to
|
|
73
|
+
`setInputAction`, `getInputAction`, and `removeInputAction`. In 1.142+, pass a
|
|
74
|
+
single modifier or an array of modifiers. Modifier arrays are order-independent
|
|
75
|
+
but exact: a handler registered for `[CTRL, SHIFT]` does not fire when `ALT` is
|
|
76
|
+
also held.
|
|
77
|
+
|
|
78
|
+
## Scene Picking Methods
|
|
79
|
+
|
|
80
|
+
### pick / pickAsync / drillPick / pickPosition
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
import { Cartographic, Math as CesiumMath, defined } from "cesium";
|
|
84
|
+
|
|
85
|
+
// pick -- synchronous, returns top-most object or undefined
|
|
86
|
+
const picked = viewer.scene.pick(event.position);
|
|
87
|
+
|
|
88
|
+
// pickAsync -- non-blocking (WebGL2, v1.136+), falls back to sync on WebGL1
|
|
89
|
+
const picked2 = await viewer.scene.pickAsync(movement.endPosition);
|
|
90
|
+
|
|
91
|
+
// drillPick -- all objects at position, front-to-back; use limit to cap cost
|
|
92
|
+
const allPicked = viewer.scene.drillPick(event.position, 5);
|
|
93
|
+
|
|
94
|
+
// pickPosition -- world Cartesian3 from depth buffer
|
|
95
|
+
if (viewer.scene.pickPositionSupported) {
|
|
96
|
+
const cartesian = viewer.scene.pickPosition(event.position);
|
|
97
|
+
if (defined(cartesian)) {
|
|
98
|
+
const c = Cartographic.fromCartesian(cartesian);
|
|
99
|
+
console.log(CesiumMath.toDegrees(c.longitude), CesiumMath.toDegrees(c.latitude), c.height);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Set `scene.pickTranslucentDepth = true` to include translucent primitives in `pickPosition`.
|
|
105
|
+
|
|
106
|
+
### pickVoxel (experimental)
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
// Pick a voxel cell and read its properties
|
|
110
|
+
const voxelCell = viewer.scene.pickVoxel(event.position);
|
|
111
|
+
if (defined(voxelCell)) {
|
|
112
|
+
console.log(voxelCell.getProperty("temperature"));
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Picking Return Values
|
|
117
|
+
|
|
118
|
+
| Picked object | Return shape | Key properties |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| Entity | `{ primitive, id }` | `id` is the `Entity` instance |
|
|
121
|
+
| Cesium3DTileFeature | `Cesium3DTileFeature` | `.getProperty(name)`, `.getPropertyIds()`, `.color` |
|
|
122
|
+
| Billboard/Label (collection) | `{ primitive, id }` | `id` is the user-set id |
|
|
123
|
+
| Primitive (geometry) | `{ primitive, id }` | `id` is the `GeometryInstance` id |
|
|
124
|
+
| Globe surface | `undefined` | Use `camera.pickEllipsoid()` or `pickPosition()` |
|
|
125
|
+
|
|
126
|
+
## Recipes
|
|
127
|
+
|
|
128
|
+
### 1. Entity Selection with Click
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
handler.setInputAction((event) => {
|
|
132
|
+
const picked = viewer.scene.pick(event.position);
|
|
133
|
+
if (defined(picked) && defined(picked.id)) {
|
|
134
|
+
viewer.selectedEntity = picked.id; // shows InfoBox
|
|
135
|
+
} else {
|
|
136
|
+
viewer.selectedEntity = undefined;
|
|
137
|
+
}
|
|
138
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 2. 3D Tiles Feature Picking and Property Inspection
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
import { Cesium3DTileFeature, Color } from "cesium";
|
|
145
|
+
|
|
146
|
+
handler.setInputAction((event) => {
|
|
147
|
+
const picked = viewer.scene.pick(event.position);
|
|
148
|
+
if (picked instanceof Cesium3DTileFeature) {
|
|
149
|
+
// Read properties
|
|
150
|
+
const ids = picked.getPropertyIds();
|
|
151
|
+
ids.forEach((id) => console.log(`${id}: ${picked.getProperty(id)}`));
|
|
152
|
+
picked.color = Color.YELLOW; // highlight
|
|
153
|
+
}
|
|
154
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 3. Terrain Position Picking (Lon/Lat from Click)
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
handler.setInputAction((event) => {
|
|
161
|
+
const cartesian = viewer.camera.pickEllipsoid(
|
|
162
|
+
event.position, viewer.scene.globe.ellipsoid);
|
|
163
|
+
if (defined(cartesian)) {
|
|
164
|
+
const c = Cartographic.fromCartesian(cartesian);
|
|
165
|
+
console.log(`Lon: ${CesiumMath.toDegrees(c.longitude).toFixed(6)}`);
|
|
166
|
+
console.log(`Lat: ${CesiumMath.toDegrees(c.latitude).toFixed(6)}`);
|
|
167
|
+
}
|
|
168
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
For height on 3D content, use `scene.pickPosition` instead (see above).
|
|
172
|
+
|
|
173
|
+
### 4. Multi-Pick with drillPick
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
import { EntityCollection, CallbackProperty, ColorMaterialProperty, Color } from "cesium";
|
|
177
|
+
|
|
178
|
+
const pickedEntities = new EntityCollection();
|
|
179
|
+
const highlightColor = Color.YELLOW.withAlpha(0.5);
|
|
180
|
+
|
|
181
|
+
// Make entity material react to selection state
|
|
182
|
+
function makePickable(entity, baseColor) {
|
|
183
|
+
entity.polygon.material = new ColorMaterialProperty(
|
|
184
|
+
new CallbackProperty((time, result) => {
|
|
185
|
+
return pickedEntities.contains(entity)
|
|
186
|
+
? highlightColor.clone(result) : baseColor.clone(result);
|
|
187
|
+
}, false));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
handler.setInputAction((movement) => {
|
|
191
|
+
const all = viewer.scene.drillPick(movement.endPosition);
|
|
192
|
+
pickedEntities.removeAll();
|
|
193
|
+
for (const p of all) {
|
|
194
|
+
if (defined(p.id)) pickedEntities.add(p.id);
|
|
195
|
+
}
|
|
196
|
+
}, ScreenSpaceEventType.MOUSE_MOVE);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 5. Hover Highlighting with MOUSE_MOVE
|
|
200
|
+
|
|
201
|
+
```js
|
|
202
|
+
import { Color } from "cesium";
|
|
203
|
+
|
|
204
|
+
const highlighted = { feature: undefined, originalColor: new Color() };
|
|
205
|
+
|
|
206
|
+
handler.setInputAction((movement) => {
|
|
207
|
+
if (defined(highlighted.feature)) {
|
|
208
|
+
highlighted.feature.color = highlighted.originalColor;
|
|
209
|
+
highlighted.feature = undefined;
|
|
210
|
+
}
|
|
211
|
+
const picked = viewer.scene.pick(movement.endPosition);
|
|
212
|
+
if (defined(picked) && defined(picked.color)) {
|
|
213
|
+
highlighted.feature = picked;
|
|
214
|
+
Color.clone(picked.color, highlighted.originalColor);
|
|
215
|
+
picked.color = Color.YELLOW;
|
|
216
|
+
}
|
|
217
|
+
}, ScreenSpaceEventType.MOUSE_MOVE);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 6. Drag-Based Drawing and Measurement
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
import { Cartographic, EllipsoidGeodesic, Ellipsoid, Color } from "cesium";
|
|
224
|
+
|
|
225
|
+
const positions = [];
|
|
226
|
+
|
|
227
|
+
handler.setInputAction((event) => {
|
|
228
|
+
const cartesian = viewer.camera.pickEllipsoid(
|
|
229
|
+
event.position, viewer.scene.globe.ellipsoid);
|
|
230
|
+
if (!defined(cartesian)) return;
|
|
231
|
+
positions.push(cartesian);
|
|
232
|
+
|
|
233
|
+
if (positions.length === 2) {
|
|
234
|
+
viewer.entities.add({
|
|
235
|
+
polyline: { positions: positions.slice(), width: 3,
|
|
236
|
+
material: Color.RED, clampToGround: true },
|
|
237
|
+
});
|
|
238
|
+
const start = Cartographic.fromCartesian(positions[0]);
|
|
239
|
+
const end = Cartographic.fromCartesian(positions[1]);
|
|
240
|
+
const geodesic = new EllipsoidGeodesic(start, end, Ellipsoid.WGS84);
|
|
241
|
+
console.log(`Distance: ${(geodesic.surfaceDistance / 1000).toFixed(2)} km`);
|
|
242
|
+
positions.length = 0;
|
|
243
|
+
}
|
|
244
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 7. Coordinate Readout on Mouse Move
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
import { HorizontalOrigin, VerticalOrigin, Cartesian2 } from "cesium";
|
|
251
|
+
|
|
252
|
+
const coordLabel = viewer.entities.add({
|
|
253
|
+
label: { show: false, showBackground: true, font: "14px monospace",
|
|
254
|
+
horizontalOrigin: HorizontalOrigin.LEFT, verticalOrigin: VerticalOrigin.TOP,
|
|
255
|
+
pixelOffset: new Cartesian2(15, 0) },
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
handler.setInputAction((movement) => {
|
|
259
|
+
const cartesian = viewer.camera.pickEllipsoid(
|
|
260
|
+
movement.endPosition, viewer.scene.globe.ellipsoid);
|
|
261
|
+
if (defined(cartesian)) {
|
|
262
|
+
const c = Cartographic.fromCartesian(cartesian);
|
|
263
|
+
coordLabel.position = cartesian;
|
|
264
|
+
coordLabel.label.show = true;
|
|
265
|
+
coordLabel.label.text =
|
|
266
|
+
`Lon: ${CesiumMath.toDegrees(c.longitude).toFixed(4)}\n` +
|
|
267
|
+
`Lat: ${CesiumMath.toDegrees(c.latitude).toFixed(4)}`;
|
|
268
|
+
} else {
|
|
269
|
+
coordLabel.label.show = false;
|
|
270
|
+
}
|
|
271
|
+
}, ScreenSpaceEventType.MOUSE_MOVE);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 8. Conditional Behavior Based on Picked Object Type
|
|
275
|
+
|
|
276
|
+
```js
|
|
277
|
+
import { Cesium3DTileFeature } from "cesium";
|
|
278
|
+
|
|
279
|
+
handler.setInputAction((event) => {
|
|
280
|
+
const picked = viewer.scene.pick(event.position);
|
|
281
|
+
if (!defined(picked)) {
|
|
282
|
+
console.log("No object picked");
|
|
283
|
+
} else if (picked instanceof Cesium3DTileFeature) {
|
|
284
|
+
console.log("3D Tile feature:", picked.getProperty("name"));
|
|
285
|
+
} else if (defined(picked.id) && defined(picked.id.position)) {
|
|
286
|
+
viewer.selectedEntity = picked.id; // Entity
|
|
287
|
+
} else if (defined(picked.primitive)) {
|
|
288
|
+
console.log("Primitive:", picked.primitive.constructor.name);
|
|
289
|
+
}
|
|
290
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 9. pickAsync for Non-Blocking Hover (v1.136+)
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
const highlighted = { feature: undefined, originalColor: new Color() };
|
|
297
|
+
|
|
298
|
+
handler.setInputAction(async (movement) => {
|
|
299
|
+
if (defined(highlighted.feature)) {
|
|
300
|
+
highlighted.feature.color = highlighted.originalColor;
|
|
301
|
+
highlighted.feature = undefined;
|
|
302
|
+
}
|
|
303
|
+
const picked = await viewer.scene.pickAsync(movement.endPosition);
|
|
304
|
+
if (defined(picked) && defined(picked.color)) {
|
|
305
|
+
highlighted.feature = picked;
|
|
306
|
+
Color.clone(picked.color, highlighted.originalColor);
|
|
307
|
+
picked.color = Color.YELLOW;
|
|
308
|
+
}
|
|
309
|
+
}, ScreenSpaceEventType.MOUSE_MOVE);
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 10. Hover + Selection with Silhouettes (Full Pattern)
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
import { PostProcessStageLibrary, Color } from "cesium";
|
|
316
|
+
|
|
317
|
+
const scene = viewer.scene;
|
|
318
|
+
const silhouetteHover = PostProcessStageLibrary.createEdgeDetectionStage();
|
|
319
|
+
silhouetteHover.uniforms.color = Color.BLUE;
|
|
320
|
+
silhouetteHover.uniforms.length = 0.01;
|
|
321
|
+
silhouetteHover.selected = [];
|
|
322
|
+
|
|
323
|
+
const silhouetteSelect = PostProcessStageLibrary.createEdgeDetectionStage();
|
|
324
|
+
silhouetteSelect.uniforms.color = Color.LIME;
|
|
325
|
+
silhouetteSelect.uniforms.length = 0.01;
|
|
326
|
+
silhouetteSelect.selected = [];
|
|
327
|
+
|
|
328
|
+
scene.postProcessStages.add(
|
|
329
|
+
PostProcessStageLibrary.createSilhouetteStage([silhouetteHover, silhouetteSelect]));
|
|
330
|
+
|
|
331
|
+
let selectedFeature;
|
|
332
|
+
|
|
333
|
+
viewer.screenSpaceEventHandler.setInputAction((movement) => {
|
|
334
|
+
silhouetteHover.selected = [];
|
|
335
|
+
const picked = scene.pick(movement.endPosition);
|
|
336
|
+
if (defined(picked) && picked !== selectedFeature) {
|
|
337
|
+
silhouetteHover.selected = [picked];
|
|
338
|
+
}
|
|
339
|
+
}, ScreenSpaceEventType.MOUSE_MOVE);
|
|
340
|
+
|
|
341
|
+
viewer.screenSpaceEventHandler.setInputAction((event) => {
|
|
342
|
+
silhouetteSelect.selected = [];
|
|
343
|
+
const picked = scene.pick(event.position);
|
|
344
|
+
if (defined(picked)) {
|
|
345
|
+
selectedFeature = picked;
|
|
346
|
+
silhouetteSelect.selected = [picked];
|
|
347
|
+
silhouetteHover.selected = [];
|
|
348
|
+
} else {
|
|
349
|
+
selectedFeature = undefined;
|
|
350
|
+
}
|
|
351
|
+
}, ScreenSpaceEventType.LEFT_CLICK);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### 11. Wheel Zoom with Custom Logic
|
|
355
|
+
|
|
356
|
+
```js
|
|
357
|
+
handler.setInputAction((delta) => {
|
|
358
|
+
// delta > 0 = scroll up (zoom in), delta < 0 = scroll out
|
|
359
|
+
const zoomAmount = delta > 0 ? 0.9 : 1.1;
|
|
360
|
+
viewer.camera.zoomIn(viewer.camera.positionCartographic.height * (1 - zoomAmount));
|
|
361
|
+
}, ScreenSpaceEventType.WHEEL);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### 12. Right-Click Context Menu
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
viewer.scene.canvas.addEventListener("contextmenu", (e) => e.preventDefault());
|
|
368
|
+
|
|
369
|
+
handler.setInputAction((event) => {
|
|
370
|
+
const picked = viewer.scene.pick(event.position);
|
|
371
|
+
if (defined(picked) && defined(picked.id)) {
|
|
372
|
+
showContextMenu(event.position, picked.id); // your app logic
|
|
373
|
+
}
|
|
374
|
+
}, ScreenSpaceEventType.RIGHT_CLICK);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### 13. Drag Interaction (Move an Entity)
|
|
378
|
+
|
|
379
|
+
```js
|
|
380
|
+
let draggedEntity = null;
|
|
381
|
+
const sscc = viewer.scene.screenSpaceCameraController;
|
|
382
|
+
|
|
383
|
+
handler.setInputAction((event) => {
|
|
384
|
+
const picked = viewer.scene.pick(event.position);
|
|
385
|
+
if (defined(picked) && defined(picked.id)) {
|
|
386
|
+
draggedEntity = picked.id;
|
|
387
|
+
sscc.enableRotate = false;
|
|
388
|
+
sscc.enableTranslate = false;
|
|
389
|
+
}
|
|
390
|
+
}, ScreenSpaceEventType.LEFT_DOWN);
|
|
391
|
+
|
|
392
|
+
handler.setInputAction((movement) => {
|
|
393
|
+
if (!defined(draggedEntity)) return;
|
|
394
|
+
const cartesian = viewer.camera.pickEllipsoid(
|
|
395
|
+
movement.endPosition, viewer.scene.globe.ellipsoid);
|
|
396
|
+
if (defined(cartesian)) draggedEntity.position = cartesian;
|
|
397
|
+
}, ScreenSpaceEventType.MOUSE_MOVE);
|
|
398
|
+
|
|
399
|
+
handler.setInputAction(() => {
|
|
400
|
+
draggedEntity = null;
|
|
401
|
+
sscc.enableRotate = true;
|
|
402
|
+
sscc.enableTranslate = true;
|
|
403
|
+
}, ScreenSpaceEventType.LEFT_UP);
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Performance Tips
|
|
407
|
+
|
|
408
|
+
1. **Prefer `pickAsync` over `pick` on MOUSE_MOVE** -- synchronous pick stalls the GPU pipeline; `pickAsync` yields to the GPU and resolves next frame (WebGL2, v1.136+).
|
|
409
|
+
2. **Use `drillPick` with a `limit`** -- without one, it re-renders the scene for every overlapping object.
|
|
410
|
+
3. **Avoid `pick` in MOUSE_MOVE when only click picking is needed** -- MOUSE_MOVE fires on every pointer move and triggers a pick render pass each time.
|
|
411
|
+
4. **Enable `depthTestAgainstTerrain`** for accurate `pickPosition` results over terrain.
|
|
412
|
+
5. **Destroy unused handlers** -- each one registers DOM listeners that leak memory if not cleaned up.
|
|
413
|
+
6. **Throttle expensive hover logic** -- debounce to 50-100ms for operations beyond simple highlighting.
|
|
414
|
+
7. **Check `scene.pickPositionSupported`** before using `pickPosition` -- falls back to `camera.pickEllipsoid` on unsupported GPUs.
|
|
415
|
+
8. **Set `scene.pickTranslucentDepth = true` only when needed** -- adds an extra render pass.
|
|
416
|
+
9. **Reuse result objects** -- pass a scratch `Cartesian3` to `pickPosition` to avoid GC pressure in MOUSE_MOVE.
|
|
417
|
+
10. **Use `scene.requestRenderMode = true`** with picking to avoid unnecessary renders; call `scene.requestRender()` only on state changes.
|
|
418
|
+
|
|
419
|
+
## See Also
|
|
420
|
+
|
|
421
|
+
- **cesiumjs-entities** -- Entity API, graphics types, DataSources
|
|
422
|
+
- **cesiumjs-3d-tiles** -- Cesium3DTileset, Cesium3DTileFeature, styling, metadata
|
|
423
|
+
- **cesiumjs-camera** -- Camera.pickEllipsoid, ScreenSpaceCameraController, flyTo
|