@navaramap/three-plugins 0.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/LICENSE +8 -0
- package/README.md +58 -0
- package/dist/index.d.ts +504 -0
- package/dist/index.js +553 -0
- package/dist/index.umd.cjs +1 -0
- package/package.json +43 -0
- package/src/CesiumIonPlugin.test.ts +113 -0
- package/src/CesiumIonPlugin.ts +161 -0
- package/src/OverlayPlugin.ts +202 -0
- package/src/PersonViewPlugin.ts +1044 -0
- package/src/TileJsonPlugin.test.ts +371 -0
- package/src/TileJsonPlugin.ts +301 -0
- package/src/index.ts +35 -0
- package/src/vite-env.d.ts +6 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# @navaramap/three-plugins
|
|
2
|
+
|
|
3
|
+
Optional feature plugins for `@navaramap/three`. Each plugin packages a self-contained capability on top of the core view:
|
|
4
|
+
|
|
5
|
+
- **`PersonViewPlugin`** — first-person walk mode with a controllable character (GLTF model, animations, key bindings, teleport, view-mode switching).
|
|
6
|
+
- **`OverlayPlugin`** — anchors DOM elements to geographic positions and keeps them projected to screen space as the camera moves.
|
|
7
|
+
- **`CesiumIonPlugin`** — resolves a Cesium Ion asset endpoint and registers the asset as a quantized-mesh terrain layer via `addTerrain()`.
|
|
8
|
+
- **`TileJsonPlugin`** — fetches a TileJSON 3.0.0 document and registers it as a Navara source, surfacing its attribution through the view's built-in credit UI.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
Like all Navara plugins, add them before `view.init()`:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import ThreeView from "@navaramap/three";
|
|
16
|
+
import {
|
|
17
|
+
DefaultPlugin,
|
|
18
|
+
type DefaultDescriptions,
|
|
19
|
+
} from "@navaramap/three-default-plugin";
|
|
20
|
+
import { OverlayPlugin, moveOverlayElement } from "@navaramap/three-plugins";
|
|
21
|
+
|
|
22
|
+
const view = new ThreeView<DefaultDescriptions>();
|
|
23
|
+
view.addPlugin(new DefaultPlugin());
|
|
24
|
+
const overlay = new OverlayPlugin();
|
|
25
|
+
view.addPlugin(overlay); // must happen before init()
|
|
26
|
+
await view.init();
|
|
27
|
+
|
|
28
|
+
// Basemap, credited through the built-in attribution UI.
|
|
29
|
+
const source = view.addSource({
|
|
30
|
+
type: "raster-tile",
|
|
31
|
+
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
32
|
+
maxZoom: 18,
|
|
33
|
+
});
|
|
34
|
+
view.addLayer({ type: "raster", source });
|
|
35
|
+
view.attribution?.add([
|
|
36
|
+
{
|
|
37
|
+
attribution: "© OpenStreetMap contributors",
|
|
38
|
+
attributionUrl: "https://www.openstreetmap.org/copyright",
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
// Anchor a DOM element to a geographic position.
|
|
43
|
+
overlay.setPositions([{ id: "tokyo", lng: 139.77, lat: 35.68, alt: 0 }]);
|
|
44
|
+
overlay.onUpdate(({ projected }) => {
|
|
45
|
+
const pos = projected.get("tokyo");
|
|
46
|
+
if (pos) moveOverlayElement(markerElement, pos.x, pos.y);
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`@navaramap/three`, `@navaramap/three-default-plugin`, and `three` are peer dependencies.
|
|
51
|
+
|
|
52
|
+
## Documentation
|
|
53
|
+
|
|
54
|
+
Each plugin's options and events are documented at https://navara-docs.netlify.app/.
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT OR Apache-2.0
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
import { default as default_2 } from '@navaramap/three';
|
|
2
|
+
import { DefaultDescriptions } from '@navaramap/three-default-plugin';
|
|
3
|
+
import { Layer } from '@navaramap/three';
|
|
4
|
+
import { Plugin as Plugin_2 } from '@navaramap/three';
|
|
5
|
+
import { QuantizedMeshSource } from '@navaramap/three';
|
|
6
|
+
import { Source } from '@navaramap/three';
|
|
7
|
+
import { TerrainSourceLayer } from '@navaramap/three';
|
|
8
|
+
import { ViewContext } from '@navaramap/three';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Animation configuration for the model.
|
|
12
|
+
* Clip names are model-specific — check your GLTF file for available clips.
|
|
13
|
+
*/
|
|
14
|
+
export declare type AnimationConfig = {
|
|
15
|
+
/** Clip name played while the model is idle (no movement keys held). */
|
|
16
|
+
idleClip: string;
|
|
17
|
+
/**
|
|
18
|
+
* Clip name played while the model is moving without dashing.
|
|
19
|
+
* Omit to keep `idleClip` playing while walking — useful for models
|
|
20
|
+
* that only ship with idle + dash animations.
|
|
21
|
+
*/
|
|
22
|
+
walkClip?: string;
|
|
23
|
+
/** Clip name played while the model is dashing (dash key held). */
|
|
24
|
+
dashClip: string;
|
|
25
|
+
/** Playback speed multiplier. */
|
|
26
|
+
speed: number;
|
|
27
|
+
/** Duration in seconds for cross-fade transitions between clips. */
|
|
28
|
+
crossfadeDuration: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export declare type CesiumIonConfig = {
|
|
32
|
+
/** Cesium Ion asset id. */
|
|
33
|
+
assetId: number | string;
|
|
34
|
+
/** Cesium Ion access token used to resolve the asset endpoint. */
|
|
35
|
+
accessToken: string;
|
|
36
|
+
endpoint?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export declare class CesiumIonPlugin extends Plugin_2<View_3, ViewContext> {
|
|
40
|
+
private view?;
|
|
41
|
+
private readonly config;
|
|
42
|
+
private endpoint?;
|
|
43
|
+
constructor(config: CesiumIonConfig);
|
|
44
|
+
init(view: View_3, _ctx: ViewContext): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Register the resolved Cesium Ion asset as a quantized-mesh terrain layer.
|
|
47
|
+
* Must be called after `view.init()`.
|
|
48
|
+
*
|
|
49
|
+
* Internally this creates an implicit quantized-mesh source for the asset and
|
|
50
|
+
* a terrain layer that references it. The source is owned by the returned
|
|
51
|
+
* layer: deleting the layer reclaims the source too, so callers only manage
|
|
52
|
+
* the layer handle.
|
|
53
|
+
*/
|
|
54
|
+
addTerrain(options?: CesiumIonTerrainOptions): Layer;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Quantized-mesh fetch/decode options forwarded to the source.
|
|
59
|
+
* The `url` and `token` fields are provided by the plugin from the resolved
|
|
60
|
+
* Cesium Ion endpoint.
|
|
61
|
+
*/
|
|
62
|
+
declare type CesiumIonSourceOptions = Omit<QuantizedMeshSource, "type" | "url" | "token" | "id">;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Options for {@link CesiumIonPlugin.addTerrain}. A flat object combining the
|
|
66
|
+
* quantized-mesh source's fetch/decode options with the terrain layer's render
|
|
67
|
+
* options; the plugin routes each field to the source or the layer.
|
|
68
|
+
*/
|
|
69
|
+
export declare type CesiumIonTerrainOptions = CesiumIonSourceOptions & CesiumIonTerrainRenderOptions;
|
|
70
|
+
|
|
71
|
+
/** Terrain mesh rendering options forwarded to the terrain layer. */
|
|
72
|
+
declare type CesiumIonTerrainRenderOptions = NonNullable<TerrainSourceLayer["terrain"]>;
|
|
73
|
+
|
|
74
|
+
export declare type CharacterConfig = {
|
|
75
|
+
/** URL of the GLTF model to load. */
|
|
76
|
+
modelUrl: string;
|
|
77
|
+
/** Animation clip configuration. */
|
|
78
|
+
animation: AnimationConfig;
|
|
79
|
+
/** Rotation offset to correct the model's default orientation. */
|
|
80
|
+
modelRotationOffset?: ModelRotationOffset;
|
|
81
|
+
modelScale?: number;
|
|
82
|
+
/** Hide the model while the camera is in FPV. Defaults to true. */
|
|
83
|
+
hideModelInFpv?: boolean;
|
|
84
|
+
/** Whether the character casts shadows. Defaults to false. */
|
|
85
|
+
castShadow?: boolean;
|
|
86
|
+
/** Whether the character receives shadows. Defaults to false. */
|
|
87
|
+
receiveShadow?: boolean;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Keyboard bindings. Each entry takes an array of `KeyboardEvent.code`
|
|
92
|
+
* values (e.g. `["KeyW"]`, `["ArrowUp", "ControlLeft"]`) so multiple
|
|
93
|
+
* keys can trigger the same action.
|
|
94
|
+
*/
|
|
95
|
+
export declare type KeyBindings = {
|
|
96
|
+
forward?: string[];
|
|
97
|
+
backward?: string[];
|
|
98
|
+
turnLeft?: string[];
|
|
99
|
+
turnRight?: string[];
|
|
100
|
+
ascend?: string[];
|
|
101
|
+
descend?: string[];
|
|
102
|
+
dash?: string[];
|
|
103
|
+
/** Hold to enable free camera (orbit) while allowCameraControl is false. */
|
|
104
|
+
orbitCamera?: string[];
|
|
105
|
+
/** Toggle between TPV and FPV. */
|
|
106
|
+
toggleView?: string[];
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Model rotation offset applied to the loaded GLTF model.
|
|
111
|
+
* Different models face different directions by default, so this
|
|
112
|
+
* allows you to correct the orientation.
|
|
113
|
+
*/
|
|
114
|
+
export declare type ModelRotationOffset = {
|
|
115
|
+
x: number;
|
|
116
|
+
y: number;
|
|
117
|
+
z: number;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Position an absolutely-positioned HTML element using a GPU-accelerated
|
|
122
|
+
* CSS `translate()` transform.
|
|
123
|
+
*/
|
|
124
|
+
export declare function moveOverlayElement(el: HTMLElement, x: number, y: number): void;
|
|
125
|
+
|
|
126
|
+
export declare type OverlayConfig = {
|
|
127
|
+
/** Positions farther than this (in meters) are skipped. @defaultValue `100_000` (100 km) */
|
|
128
|
+
maxDistance?: number;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Projects geographic positions to screen coordinates on every render frame.
|
|
133
|
+
*
|
|
134
|
+
* Register via `view.addPlugin(overlayPlugin)` **before** `view.init()`.
|
|
135
|
+
* The `preRender` hook is attached automatically during initialization.
|
|
136
|
+
*/
|
|
137
|
+
export declare class OverlayPlugin extends Plugin_2<View_2, ViewContext> {
|
|
138
|
+
private view?;
|
|
139
|
+
private maxDistance;
|
|
140
|
+
private positions;
|
|
141
|
+
private projected;
|
|
142
|
+
private listeners;
|
|
143
|
+
private boundHandler;
|
|
144
|
+
constructor(config?: OverlayConfig);
|
|
145
|
+
init(view: View_2, _ctx: ViewContext): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Replace the set of world positions to track.
|
|
148
|
+
* Positions are re-projected on the next render frame automatically.
|
|
149
|
+
*/
|
|
150
|
+
setPositions(positions: WorldPosition[]): void;
|
|
151
|
+
onUpdate(fn: UpdateListener): () => void;
|
|
152
|
+
dispose(): void;
|
|
153
|
+
private worldToScreen;
|
|
154
|
+
private handlePreRender;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export declare type OverlayState = {
|
|
158
|
+
projected: Map<string, ProjectedPosition>;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export declare type PersonViewConfig = {
|
|
162
|
+
character?: CharacterConfig;
|
|
163
|
+
/** When true, the camera is always free (no Alt-hold required). */
|
|
164
|
+
allowCameraControl?: boolean;
|
|
165
|
+
/** Initial view mode. */
|
|
166
|
+
initialView?: ViewMode;
|
|
167
|
+
/** m/s */
|
|
168
|
+
moveSpeed?: number;
|
|
169
|
+
/** deg/frame */
|
|
170
|
+
rotationSpeed?: number;
|
|
171
|
+
/** m/s */
|
|
172
|
+
altSpeed?: number;
|
|
173
|
+
minAlt?: number;
|
|
174
|
+
maxAlt?: number;
|
|
175
|
+
cameraDistance?: number;
|
|
176
|
+
/**
|
|
177
|
+
* Downward camera pitch in radians for **TPV**. `0` keeps the camera
|
|
178
|
+
* behind the model at eye level; positive values orbit the camera up and
|
|
179
|
+
* over so it looks down at the model while keeping it centered. Has no
|
|
180
|
+
* effect while the free camera is active (Alt-hold or `allowCameraControl`),
|
|
181
|
+
* where mouse drag controls the pitch instead.
|
|
182
|
+
*/
|
|
183
|
+
cameraPitch?: number;
|
|
184
|
+
cameraLerpSpeed?: number;
|
|
185
|
+
/** Forward offset (meters) applied to the FPV eye position. */
|
|
186
|
+
fpvForwardOffset?: number;
|
|
187
|
+
/**
|
|
188
|
+
* Eye-line height offset (meters) added to the position. Used in FPV for the
|
|
189
|
+
* eye position and in TPV as the shared eye-line height the camera orbits
|
|
190
|
+
* around and aims at.
|
|
191
|
+
*/
|
|
192
|
+
fpvHeightOffset?: number;
|
|
193
|
+
/**
|
|
194
|
+
* Downward camera pitch in radians for **FPV**. `0` looks straight ahead
|
|
195
|
+
* (horizontal); positive values tilt the view down in place without moving
|
|
196
|
+
* the eye. Has no effect while the free camera is active.
|
|
197
|
+
*/
|
|
198
|
+
fpvPitch?: number;
|
|
199
|
+
startLat?: number;
|
|
200
|
+
startLng?: number;
|
|
201
|
+
startHeight?: number;
|
|
202
|
+
/** radians */
|
|
203
|
+
startHeading?: number;
|
|
204
|
+
keys?: KeyBindings;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Register via `view.addPlugin(plugin)` **before** `view.init()`,
|
|
209
|
+
* then call `start()` after initialization completes.
|
|
210
|
+
*
|
|
211
|
+
* ### Default controls
|
|
212
|
+
*
|
|
213
|
+
* | Key | Action |
|
|
214
|
+
* |-----|--------|
|
|
215
|
+
* | W / S | Forward / backward |
|
|
216
|
+
* | A / D | Turn left / right |
|
|
217
|
+
* | Arrow Up / Space | Climb |
|
|
218
|
+
* | Arrow Down / Ctrl | Descend |
|
|
219
|
+
* | Shift | Dash (2.5x speed) |
|
|
220
|
+
* | Alt | Free camera (when allowCameraControl is false) |
|
|
221
|
+
* | V | Toggle TPV / FPV |
|
|
222
|
+
*/
|
|
223
|
+
export declare class PersonViewPlugin extends Plugin_2<View, ViewContext> {
|
|
224
|
+
private view?;
|
|
225
|
+
private config;
|
|
226
|
+
private character;
|
|
227
|
+
private keys;
|
|
228
|
+
private keyToAction;
|
|
229
|
+
private handle;
|
|
230
|
+
private modelRef;
|
|
231
|
+
private animId;
|
|
232
|
+
private lastTime;
|
|
233
|
+
private state;
|
|
234
|
+
private listeners;
|
|
235
|
+
private heldActions;
|
|
236
|
+
private dashMultiplier;
|
|
237
|
+
private orbitKeyHeld;
|
|
238
|
+
private orbitLatched;
|
|
239
|
+
private currentAnimState;
|
|
240
|
+
private modelHeading;
|
|
241
|
+
private cameraHeading;
|
|
242
|
+
private viewMode;
|
|
243
|
+
/** Set to `true` to ignore all movement keys (e.g. while a modal is open). */
|
|
244
|
+
movementSuppressed: boolean;
|
|
245
|
+
private boundKeyDown;
|
|
246
|
+
private boundKeyUp;
|
|
247
|
+
private _curPos;
|
|
248
|
+
private _east;
|
|
249
|
+
private _north;
|
|
250
|
+
private _worldForward;
|
|
251
|
+
private _offset;
|
|
252
|
+
private _headingMatrix;
|
|
253
|
+
private _characterFrame;
|
|
254
|
+
constructor(config?: PersonViewConfig);
|
|
255
|
+
init(view: View, _ctx: ViewContext): Promise<void>;
|
|
256
|
+
start(): void;
|
|
257
|
+
/** Instantly move to a new geographic position. */
|
|
258
|
+
teleport(options: TeleportOptions): void;
|
|
259
|
+
getState(): PersonViewState;
|
|
260
|
+
onStateChange(fn: StateListener): () => void;
|
|
261
|
+
setViewMode(mode: ViewMode): void;
|
|
262
|
+
toggleViewMode(): void;
|
|
263
|
+
setAllowCameraControl(value: boolean): void;
|
|
264
|
+
/**
|
|
265
|
+
* Rotate the character to the given heading in radians (0 = north,
|
|
266
|
+
* increasing clockwise) without changing position. Snaps the chase camera to
|
|
267
|
+
* match; in free-camera mode only the model rotates.
|
|
268
|
+
*/
|
|
269
|
+
setHeading(radians: number): void;
|
|
270
|
+
/** Current character heading in radians. */
|
|
271
|
+
getHeading(): number;
|
|
272
|
+
/**
|
|
273
|
+
* Set the downward TPV camera pitch in radians (0 = behind at eye level,
|
|
274
|
+
* positive orbits up and over the model). Takes effect immediately for the
|
|
275
|
+
* chase / locked camera.
|
|
276
|
+
*/
|
|
277
|
+
setCameraPitch(radians: number): void;
|
|
278
|
+
/** Current downward TPV camera pitch in radians. */
|
|
279
|
+
getCameraPitch(): number;
|
|
280
|
+
/**
|
|
281
|
+
* Set the downward FPV camera pitch in radians (0 = horizontal, positive
|
|
282
|
+
* tilts the view down in place). Takes effect immediately for the chase /
|
|
283
|
+
* locked camera.
|
|
284
|
+
*/
|
|
285
|
+
setFpvPitch(radians: number): void;
|
|
286
|
+
/** Current downward FPV camera pitch in radians. */
|
|
287
|
+
getFpvPitch(): number;
|
|
288
|
+
/**
|
|
289
|
+
* Set the FPV eye height offset in meters (added to the position to get the
|
|
290
|
+
* eye height). Also used as the shared eye-line height in TPV. Takes effect
|
|
291
|
+
* immediately for the chase / locked camera.
|
|
292
|
+
*/
|
|
293
|
+
setFpvHeightOffset(meters: number): void;
|
|
294
|
+
/** Current FPV eye height offset in meters. */
|
|
295
|
+
getFpvHeightOffset(): number;
|
|
296
|
+
dispose(): void;
|
|
297
|
+
private resolveCharacter;
|
|
298
|
+
private buildKeyMap;
|
|
299
|
+
private isFreeCamera;
|
|
300
|
+
private isMovementAction;
|
|
301
|
+
private applyModelVisibility;
|
|
302
|
+
private applyInitialCamera;
|
|
303
|
+
/**
|
|
304
|
+
* Chase / locked camera placement. Caller supplies the heading (radians)
|
|
305
|
+
* to use — lerped during the per-frame loop, snapped on teleport / init.
|
|
306
|
+
*
|
|
307
|
+
* Pitch is per-mode: FPV uses `fpvPitch` and tilts the view down in place
|
|
308
|
+
* (the eye stays fixed); TPV uses `cameraPitch` and orbits the camera around
|
|
309
|
+
* the model, staying aimed at it so the model remains centered.
|
|
310
|
+
*/
|
|
311
|
+
private placeChaseCamera;
|
|
312
|
+
/**
|
|
313
|
+
* Compose the character's world matrix as `ENU * Rz(-heading)`.
|
|
314
|
+
*
|
|
315
|
+
* The ENU frame already places the model at the right spot on the
|
|
316
|
+
* globe with +Z pointing world-up. Multiplying by a Z-rotation of
|
|
317
|
+
* `-heading` (negated because three.js Rz is counter-clockwise when
|
|
318
|
+
* viewed from +Z, while our heading convention is clockwise from
|
|
319
|
+
* north) bakes the heading into the world matrix.
|
|
320
|
+
*
|
|
321
|
+
* The character's `rotation` field is therefore left as the static
|
|
322
|
+
* `modelRotationOffset` only — its job is to position the model in
|
|
323
|
+
* its "facing-north, upright" rest pose. Heading then rotates the
|
|
324
|
+
* already-upright model around world-up, regardless of which axis
|
|
325
|
+
* the GLTF treats as forward.
|
|
326
|
+
*/
|
|
327
|
+
private composeCharacterFrame;
|
|
328
|
+
/** Advance a (lat,lng) point by `meters` along the given ENU heading. */
|
|
329
|
+
private advanceLatLng;
|
|
330
|
+
private notify;
|
|
331
|
+
private onKeyDown;
|
|
332
|
+
private onKeyUp;
|
|
333
|
+
private tick;
|
|
334
|
+
private hasStateChanged;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export declare type PersonViewState = {
|
|
338
|
+
lng: number;
|
|
339
|
+
lat: number;
|
|
340
|
+
alt: number;
|
|
341
|
+
/** Heading in radians — 0 = north, increasing clockwise. */
|
|
342
|
+
heading: number;
|
|
343
|
+
speed: number;
|
|
344
|
+
/** Current animation clip name, or null when no character is configured. */
|
|
345
|
+
animationState: string | null;
|
|
346
|
+
mode: ViewMode;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export declare type ProjectedPosition = {
|
|
350
|
+
x: number;
|
|
351
|
+
y: number;
|
|
352
|
+
/** Distance from the camera in meters (ECEF euclidean). */
|
|
353
|
+
distance: number;
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
declare type StateListener = (s: PersonViewState) => void;
|
|
357
|
+
|
|
358
|
+
/** Options for {@link PersonViewPlugin.teleport}. */
|
|
359
|
+
export declare type TeleportOptions = {
|
|
360
|
+
/** Longitude in degrees. */
|
|
361
|
+
lng: number;
|
|
362
|
+
/** Latitude in degrees. */
|
|
363
|
+
lat: number;
|
|
364
|
+
/** Altitude in meters. */
|
|
365
|
+
alt: number;
|
|
366
|
+
/**
|
|
367
|
+
* Heading in radians (0 = north, increasing clockwise). If omitted, the
|
|
368
|
+
* current camera heading is kept. (Use `setHeading` to rotate in place
|
|
369
|
+
* without moving, and `setCameraPitch` / `setFpvPitch` for camera pitch.)
|
|
370
|
+
*/
|
|
371
|
+
heading?: number;
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* The subset of a TileJSON 3.0.0 document this plugin consumes. Other spec
|
|
376
|
+
* fields (`bounds`, `center`, `grids`, ...) are ignored.
|
|
377
|
+
*/
|
|
378
|
+
export declare type TileJson = {
|
|
379
|
+
/** Semver of the TileJSON spec the document conforms to, e.g. `"3.0.0"`. */
|
|
380
|
+
tilejson: string;
|
|
381
|
+
/** Tile URL templates (`{z}/{x}/{y}`). Required and non-empty per the spec. */
|
|
382
|
+
tiles: string[];
|
|
383
|
+
/** Attribution/credit HTML shown through the view's attribution UI. */
|
|
384
|
+
attribution?: string;
|
|
385
|
+
/** Minimum zoom level. Applied to raster sources only. @defaultValue 0 */
|
|
386
|
+
minzoom?: number;
|
|
387
|
+
/** Maximum zoom level. @defaultValue 30 */
|
|
388
|
+
maxzoom?: number;
|
|
389
|
+
/** Tiling scheme. `"tms"` flips the Y axis (raster sources only). @defaultValue "xyz" */
|
|
390
|
+
scheme?: "xyz" | "tms";
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
/** Detail passed to the {@link TileJsonPlugin} `loaded` event. */
|
|
394
|
+
export declare type TileJsonLoadedEvent = {
|
|
395
|
+
/** The Navara source created for the document. */
|
|
396
|
+
source: Source;
|
|
397
|
+
/** The fetched and validated TileJSON document. */
|
|
398
|
+
tilejson: TileJson;
|
|
399
|
+
/** The document's `attribution` HTML, when it declares one. */
|
|
400
|
+
attribution?: string;
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
export declare class TileJsonPlugin extends Plugin_2<View_4, ViewContext> {
|
|
404
|
+
private view?;
|
|
405
|
+
private readonly events;
|
|
406
|
+
/** Credits pushed into `view.attribution`, tracked so dispose() can drop them. */
|
|
407
|
+
private readonly credits;
|
|
408
|
+
init(view: View_4, _ctx: ViewContext): Promise<void>;
|
|
409
|
+
/**
|
|
410
|
+
* Subscribe to a plugin event. Use `loaded` to receive each document's
|
|
411
|
+
* attribution (and the created source) for a custom credit UI.
|
|
412
|
+
*/
|
|
413
|
+
on<E extends keyof TileJsonPluginEventMap>(event: E, listener: TileJsonPluginEventMap[E]): void;
|
|
414
|
+
/** Subscribe to a plugin event for a single emission, then auto-unsubscribe. */
|
|
415
|
+
once<E extends keyof TileJsonPluginEventMap>(event: E, listener: TileJsonPluginEventMap[E]): void;
|
|
416
|
+
/** Remove a previously registered listener. */
|
|
417
|
+
off<E extends keyof TileJsonPluginEventMap>(event: E, listener: TileJsonPluginEventMap[E]): void;
|
|
418
|
+
/**
|
|
419
|
+
* Fetch a TileJSON document and register it as a single Navara source.
|
|
420
|
+
*
|
|
421
|
+
* `desc.url` is the TileJSON document URL; the plugin fetches it, then creates
|
|
422
|
+
* one source of the requested `desc.type` using the document's first tile
|
|
423
|
+
* endpoint, `minzoom`/`maxzoom`, and `scheme`. The document's `attribution` is
|
|
424
|
+
* surfaced through the view's built-in attribution UI (`view.attribution`), and
|
|
425
|
+
* a `loaded` event is emitted carrying the source, document, and attribution.
|
|
426
|
+
*
|
|
427
|
+
* A TileJSON `tiles` array lists mirror endpoints for the same tileset (as in
|
|
428
|
+
* MapLibre, which shards requests across them). Navara sources take a single
|
|
429
|
+
* URL, so only the first endpoint is used; extra endpoints are ignored with a
|
|
430
|
+
* warning.
|
|
431
|
+
*
|
|
432
|
+
* Must be called after `view.init()`. Returns the created {@link Source}
|
|
433
|
+
* handle; layers can reference it by handle or by `desc.id`.
|
|
434
|
+
*/
|
|
435
|
+
addSource(desc: TileJsonSourceDescription): Promise<Source>;
|
|
436
|
+
dispose(): void;
|
|
437
|
+
private fetchTileJson;
|
|
438
|
+
/**
|
|
439
|
+
* Add a credit to the view's built-in attribution UI, deduped so repeated or
|
|
440
|
+
* shared credits render once. No-op when the built-in UI is disabled
|
|
441
|
+
* (`defaultAttribution: false`) — those callers use the `loaded` event instead.
|
|
442
|
+
*/
|
|
443
|
+
private addCredit;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Events emitted by {@link TileJsonPlugin}. Subscribe via
|
|
448
|
+
* {@link TileJsonPlugin.on} / {@link TileJsonPlugin.once}.
|
|
449
|
+
*/
|
|
450
|
+
export declare type TileJsonPluginEventMap = {
|
|
451
|
+
/**
|
|
452
|
+
* Fired once per successful {@link TileJsonPlugin.addSource}, after the source
|
|
453
|
+
* is registered. Carries the created source, the parsed document, and its
|
|
454
|
+
* attribution so callers can drive a custom credit UI.
|
|
455
|
+
*/
|
|
456
|
+
loaded: (event: TileJsonLoadedEvent) => void;
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Describes a TileJSON tile source to register via {@link TileJsonPlugin.addSource}.
|
|
461
|
+
* Mirrors the shape of {@link ThreeView.addSource}, except `url` is the TileJSON
|
|
462
|
+
* document URL (not a tile template) — the plugin fetches it and derives the tile
|
|
463
|
+
* URL, zoom range, and attribution from the document.
|
|
464
|
+
*/
|
|
465
|
+
export declare type TileJsonSourceDescription = {
|
|
466
|
+
/** Navara source type to create, as in `addSource`. */
|
|
467
|
+
type: TileJsonSourceType;
|
|
468
|
+
/** URL of the TileJSON 3.0.0 document to fetch and expand. */
|
|
469
|
+
url: string;
|
|
470
|
+
/**
|
|
471
|
+
* Optional caller-provided source id. Handy for referencing the source from
|
|
472
|
+
* layers by id (`addLayer({ source: "<id>" })`) without holding the returned
|
|
473
|
+
* handle. When omitted, the engine generates one.
|
|
474
|
+
*/
|
|
475
|
+
id?: string;
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Which Navara source type a TileJSON document is materialized into. Declared by
|
|
480
|
+
* the caller because TileJSON has no field that reliably distinguishes raster
|
|
481
|
+
* imagery from vector tiles.
|
|
482
|
+
*/
|
|
483
|
+
export declare type TileJsonSourceType = "raster-tile" | "vector-tile";
|
|
484
|
+
|
|
485
|
+
declare type UpdateListener = (state: OverlayState) => void;
|
|
486
|
+
|
|
487
|
+
declare type View = default_2<DefaultDescriptions>;
|
|
488
|
+
|
|
489
|
+
declare type View_2 = default_2<DefaultDescriptions>;
|
|
490
|
+
|
|
491
|
+
declare type View_3 = default_2<DefaultDescriptions>;
|
|
492
|
+
|
|
493
|
+
declare type View_4 = default_2<DefaultDescriptions>;
|
|
494
|
+
|
|
495
|
+
export declare type ViewMode = "tpv" | "fpv";
|
|
496
|
+
|
|
497
|
+
export declare type WorldPosition = {
|
|
498
|
+
id: string;
|
|
499
|
+
lng: number;
|
|
500
|
+
lat: number;
|
|
501
|
+
alt: number;
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
export { }
|