3dtiles-inspector 0.2.5 → 0.2.6
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
CHANGED
|
@@ -6,6 +6,12 @@ The format is based on Keep a Changelog and this project follows Semantic Versio
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.6] - 2026-05-05
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added realtime `camerapose` URL synchronization so shared viewer URLs can restore the current camera pose.
|
|
14
|
+
|
|
9
15
|
## [0.2.5] - 2026-05-05
|
|
10
16
|
|
|
11
17
|
### Fixed
|
|
@@ -68245,6 +68245,10 @@ function createFlyToController({
|
|
|
68245
68245
|
}
|
|
68246
68246
|
return true;
|
|
68247
68247
|
}
|
|
68248
|
+
function cancelCameraFlight() {
|
|
68249
|
+
activeCameraFlight = null;
|
|
68250
|
+
activeCameraFlightStatus = "";
|
|
68251
|
+
}
|
|
68248
68252
|
async function applyTilesSetPositionFromPointerEvent(event) {
|
|
68249
68253
|
const coordinate = pickCoordinateFromPointerEvent(event);
|
|
68250
68254
|
if (!coordinate) {
|
|
@@ -68309,6 +68313,7 @@ function createFlyToController({
|
|
|
68309
68313
|
}
|
|
68310
68314
|
return {
|
|
68311
68315
|
applyTilesSetPositionFromPointerEvent,
|
|
68316
|
+
cancelCameraFlight,
|
|
68312
68317
|
frameTileset,
|
|
68313
68318
|
getActiveEllipsoid,
|
|
68314
68319
|
moveCameraToCoordinate,
|
|
@@ -68325,6 +68330,148 @@ var init_flyTo = __esm({
|
|
|
68325
68330
|
}
|
|
68326
68331
|
});
|
|
68327
68332
|
|
|
68333
|
+
// src/viewer/navigation/cameraUrlPose.js
|
|
68334
|
+
function formatPoseNumber(value) {
|
|
68335
|
+
const fixed = value.toFixed(9);
|
|
68336
|
+
const trimmed = fixed.replace(/(\.\d*?[1-9])0+$/, "$1").replace(/\.0+$/, "");
|
|
68337
|
+
return trimmed === "-0" ? "0" : trimmed;
|
|
68338
|
+
}
|
|
68339
|
+
function serializeCameraPose(camera) {
|
|
68340
|
+
camera.updateMatrixWorld(true);
|
|
68341
|
+
const values = [
|
|
68342
|
+
camera.position.x,
|
|
68343
|
+
camera.position.y,
|
|
68344
|
+
camera.position.z,
|
|
68345
|
+
camera.quaternion.x,
|
|
68346
|
+
camera.quaternion.y,
|
|
68347
|
+
camera.quaternion.z,
|
|
68348
|
+
camera.quaternion.w
|
|
68349
|
+
];
|
|
68350
|
+
if (camera.isOrthographicCamera) {
|
|
68351
|
+
values.push(camera.zoom);
|
|
68352
|
+
}
|
|
68353
|
+
if (!values.every(Number.isFinite)) {
|
|
68354
|
+
return null;
|
|
68355
|
+
}
|
|
68356
|
+
return values.map(formatPoseNumber).join(CAMERA_POSE_VALUE_SEPARATOR);
|
|
68357
|
+
}
|
|
68358
|
+
function getCameraPoseParam(url) {
|
|
68359
|
+
return url.searchParams.get(CAMERA_POSE_PARAM) ?? url.searchParams.get(CAMERA_POSE_ALIAS_PARAM);
|
|
68360
|
+
}
|
|
68361
|
+
function parseCameraPose(value) {
|
|
68362
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
68363
|
+
return null;
|
|
68364
|
+
}
|
|
68365
|
+
const parts = value.trim().split(/[,_\s]+/).filter(Boolean);
|
|
68366
|
+
if (parts.length !== CAMERA_POSE_COMPONENT_COUNT && parts.length !== CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM) {
|
|
68367
|
+
return null;
|
|
68368
|
+
}
|
|
68369
|
+
const values = parts.map(Number);
|
|
68370
|
+
if (!values.every(Number.isFinite)) {
|
|
68371
|
+
return null;
|
|
68372
|
+
}
|
|
68373
|
+
const quaternionLength = Math.hypot(
|
|
68374
|
+
values[3],
|
|
68375
|
+
values[4],
|
|
68376
|
+
values[5],
|
|
68377
|
+
values[6]
|
|
68378
|
+
);
|
|
68379
|
+
if (quaternionLength <= 1e-12) {
|
|
68380
|
+
return null;
|
|
68381
|
+
}
|
|
68382
|
+
const zoom = values.length === CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM ? values[7] : null;
|
|
68383
|
+
if (zoom !== null && zoom <= 0) {
|
|
68384
|
+
return null;
|
|
68385
|
+
}
|
|
68386
|
+
return {
|
|
68387
|
+
position: values.slice(0, 3),
|
|
68388
|
+
quaternion: values.slice(3, 7),
|
|
68389
|
+
zoom
|
|
68390
|
+
};
|
|
68391
|
+
}
|
|
68392
|
+
function replaceCameraPoseUrl(serializedPose) {
|
|
68393
|
+
const url = new URL(window.location.href);
|
|
68394
|
+
url.searchParams.delete(CAMERA_POSE_ALIAS_PARAM);
|
|
68395
|
+
url.searchParams.set(CAMERA_POSE_PARAM, serializedPose);
|
|
68396
|
+
window.history.replaceState(window.history.state, "", url.href);
|
|
68397
|
+
}
|
|
68398
|
+
function getInvalidCameraPoseMessage() {
|
|
68399
|
+
return "Invalid camerapose URL parameter ignored. Expected x_y_z_qx_qy_qz_qw.";
|
|
68400
|
+
}
|
|
68401
|
+
function createCameraUrlPoseController({
|
|
68402
|
+
camera,
|
|
68403
|
+
cameraController,
|
|
68404
|
+
setStatus
|
|
68405
|
+
}) {
|
|
68406
|
+
let lastSerializedPose = null;
|
|
68407
|
+
let lastUrlWriteTime = 0;
|
|
68408
|
+
function applyPose(pose) {
|
|
68409
|
+
camera.position.fromArray(pose.position);
|
|
68410
|
+
camera.quaternion.fromArray(pose.quaternion).normalize();
|
|
68411
|
+
if (pose.zoom !== null && camera.isOrthographicCamera) {
|
|
68412
|
+
camera.zoom = Math.max(pose.zoom, 1e-6);
|
|
68413
|
+
camera.updateProjectionMatrix();
|
|
68414
|
+
}
|
|
68415
|
+
camera.updateMatrixWorld(true);
|
|
68416
|
+
cameraController.setCamera(camera);
|
|
68417
|
+
}
|
|
68418
|
+
function applyFromUrl({ showStatus = false } = {}) {
|
|
68419
|
+
const url = new URL(window.location.href);
|
|
68420
|
+
const value = getCameraPoseParam(url);
|
|
68421
|
+
if (value === null) {
|
|
68422
|
+
return false;
|
|
68423
|
+
}
|
|
68424
|
+
const pose = parseCameraPose(value);
|
|
68425
|
+
if (!pose) {
|
|
68426
|
+
if (showStatus && setStatus) {
|
|
68427
|
+
setStatus(getInvalidCameraPoseMessage(), true);
|
|
68428
|
+
}
|
|
68429
|
+
return false;
|
|
68430
|
+
}
|
|
68431
|
+
applyPose(pose);
|
|
68432
|
+
lastSerializedPose = serializeCameraPose(camera);
|
|
68433
|
+
lastUrlWriteTime = performance.now();
|
|
68434
|
+
if (lastSerializedPose) {
|
|
68435
|
+
replaceCameraPoseUrl(lastSerializedPose);
|
|
68436
|
+
}
|
|
68437
|
+
if (showStatus && setStatus) {
|
|
68438
|
+
setStatus("Applied camera pose from URL.");
|
|
68439
|
+
}
|
|
68440
|
+
return true;
|
|
68441
|
+
}
|
|
68442
|
+
function flush() {
|
|
68443
|
+
const serializedPose = serializeCameraPose(camera);
|
|
68444
|
+
if (!serializedPose || serializedPose === lastSerializedPose) {
|
|
68445
|
+
return;
|
|
68446
|
+
}
|
|
68447
|
+
replaceCameraPoseUrl(serializedPose);
|
|
68448
|
+
lastSerializedPose = serializedPose;
|
|
68449
|
+
lastUrlWriteTime = performance.now();
|
|
68450
|
+
}
|
|
68451
|
+
function update(time = performance.now()) {
|
|
68452
|
+
if (time - lastUrlWriteTime < CAMERA_POSE_UPDATE_INTERVAL_MS) {
|
|
68453
|
+
return;
|
|
68454
|
+
}
|
|
68455
|
+
flush();
|
|
68456
|
+
}
|
|
68457
|
+
return {
|
|
68458
|
+
applyFromUrl,
|
|
68459
|
+
flush,
|
|
68460
|
+
update
|
|
68461
|
+
};
|
|
68462
|
+
}
|
|
68463
|
+
var CAMERA_POSE_PARAM, CAMERA_POSE_ALIAS_PARAM, CAMERA_POSE_COMPONENT_COUNT, CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM, CAMERA_POSE_UPDATE_INTERVAL_MS, CAMERA_POSE_VALUE_SEPARATOR;
|
|
68464
|
+
var init_cameraUrlPose = __esm({
|
|
68465
|
+
"src/viewer/navigation/cameraUrlPose.js"() {
|
|
68466
|
+
CAMERA_POSE_PARAM = "camerapose";
|
|
68467
|
+
CAMERA_POSE_ALIAS_PARAM = "cameraPose";
|
|
68468
|
+
CAMERA_POSE_COMPONENT_COUNT = 7;
|
|
68469
|
+
CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM = 8;
|
|
68470
|
+
CAMERA_POSE_UPDATE_INTERVAL_MS = 100;
|
|
68471
|
+
CAMERA_POSE_VALUE_SEPARATOR = "_";
|
|
68472
|
+
}
|
|
68473
|
+
});
|
|
68474
|
+
|
|
68328
68475
|
// src/viewer/screenSelection/state.js
|
|
68329
68476
|
function clamp3(value, min, max) {
|
|
68330
68477
|
return Math.min(max, Math.max(min, value));
|
|
@@ -71052,6 +71199,7 @@ var require_app = __commonJS({
|
|
|
71052
71199
|
init_shutdown();
|
|
71053
71200
|
init_setPositionController();
|
|
71054
71201
|
init_flyTo();
|
|
71202
|
+
init_cameraUrlPose();
|
|
71055
71203
|
init_cropController();
|
|
71056
71204
|
init_rootTransformController();
|
|
71057
71205
|
init_transformModeController();
|
|
@@ -71256,6 +71404,14 @@ var require_app = __commonJS({
|
|
|
71256
71404
|
getTiles: () => tiles,
|
|
71257
71405
|
getTilesetBoundingSphere
|
|
71258
71406
|
});
|
|
71407
|
+
var cameraUrlPose = createCameraUrlPoseController({
|
|
71408
|
+
camera,
|
|
71409
|
+
cameraController,
|
|
71410
|
+
setStatus
|
|
71411
|
+
});
|
|
71412
|
+
var appliedInitialCameraPose = cameraUrlPose.applyFromUrl({
|
|
71413
|
+
showStatus: true
|
|
71414
|
+
});
|
|
71259
71415
|
setPositionController = createSetPositionController({
|
|
71260
71416
|
cameraController,
|
|
71261
71417
|
maxClickDistanceSq: SET_POSITION_CLICK_MAX_DISTANCE_SQ,
|
|
@@ -71559,10 +71715,19 @@ var require_app = __commonJS({
|
|
|
71559
71715
|
renderer,
|
|
71560
71716
|
setStatus
|
|
71561
71717
|
});
|
|
71562
|
-
|
|
71718
|
+
window.addEventListener("popstate", () => {
|
|
71719
|
+
if (cameraUrlPose.applyFromUrl({ showStatus: true })) {
|
|
71720
|
+
flyTo2.cancelCameraFlight();
|
|
71721
|
+
cancelPositionPickModes();
|
|
71722
|
+
}
|
|
71723
|
+
});
|
|
71724
|
+
window.addEventListener("pagehide", cameraUrlPose.flush);
|
|
71725
|
+
cameraController.addEventListener("finish", cameraUrlPose.flush);
|
|
71726
|
+
loadTileset(TILESET_URL, { frameOnLoad: !appliedInitialCameraPose });
|
|
71563
71727
|
function frame() {
|
|
71564
71728
|
cameraController.update();
|
|
71565
71729
|
flyTo2.update();
|
|
71730
|
+
cameraUrlPose.update();
|
|
71566
71731
|
rootTransform.flush();
|
|
71567
71732
|
globeController.update();
|
|
71568
71733
|
tiles?.update();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "3dtiles-inspector",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Inspect, align, and save local 3D Tiles root transforms in an interactive browser session.",
|
|
5
5
|
"author": "William Liu <lyz15972107087@gmail.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
package/src/viewer/app.js
CHANGED
|
@@ -17,6 +17,7 @@ import { bindViewerEvents } from './dom/events.js';
|
|
|
17
17
|
import { createViewerShutdownRequester } from './io/shutdown.js';
|
|
18
18
|
import { createSetPositionController } from './io/setPositionController.js';
|
|
19
19
|
import { createFlyToController } from './navigation/flyTo.js';
|
|
20
|
+
import { createCameraUrlPoseController } from './navigation/cameraUrlPose.js';
|
|
20
21
|
import { createCropController } from './screenSelection/cropController.js';
|
|
21
22
|
import { createRootTransformController } from './transform/rootTransformController.js';
|
|
22
23
|
import { createTransformModeController } from './transform/transformModeController.js';
|
|
@@ -269,6 +270,15 @@ const flyTo = createFlyToController({
|
|
|
269
270
|
getTilesetBoundingSphere,
|
|
270
271
|
});
|
|
271
272
|
|
|
273
|
+
const cameraUrlPose = createCameraUrlPoseController({
|
|
274
|
+
camera,
|
|
275
|
+
cameraController,
|
|
276
|
+
setStatus,
|
|
277
|
+
});
|
|
278
|
+
const appliedInitialCameraPose = cameraUrlPose.applyFromUrl({
|
|
279
|
+
showStatus: true,
|
|
280
|
+
});
|
|
281
|
+
|
|
272
282
|
setPositionController = createSetPositionController({
|
|
273
283
|
cameraController,
|
|
274
284
|
maxClickDistanceSq: SET_POSITION_CLICK_MAX_DISTANCE_SQ,
|
|
@@ -605,11 +615,21 @@ bindViewerEvents({
|
|
|
605
615
|
setStatus,
|
|
606
616
|
});
|
|
607
617
|
|
|
608
|
-
|
|
618
|
+
window.addEventListener('popstate', () => {
|
|
619
|
+
if (cameraUrlPose.applyFromUrl({ showStatus: true })) {
|
|
620
|
+
flyTo.cancelCameraFlight();
|
|
621
|
+
cancelPositionPickModes();
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
window.addEventListener('pagehide', cameraUrlPose.flush);
|
|
625
|
+
cameraController.addEventListener('finish', cameraUrlPose.flush);
|
|
626
|
+
|
|
627
|
+
loadTileset(TILESET_URL, { frameOnLoad: !appliedInitialCameraPose });
|
|
609
628
|
|
|
610
629
|
function frame() {
|
|
611
630
|
cameraController.update();
|
|
612
631
|
flyTo.update();
|
|
632
|
+
cameraUrlPose.update();
|
|
613
633
|
rootTransform.flush();
|
|
614
634
|
globeController.update();
|
|
615
635
|
tiles?.update();
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const CAMERA_POSE_PARAM = 'camerapose';
|
|
2
|
+
const CAMERA_POSE_ALIAS_PARAM = 'cameraPose';
|
|
3
|
+
const CAMERA_POSE_COMPONENT_COUNT = 7;
|
|
4
|
+
const CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM = 8;
|
|
5
|
+
const CAMERA_POSE_UPDATE_INTERVAL_MS = 100;
|
|
6
|
+
const CAMERA_POSE_VALUE_SEPARATOR = '_';
|
|
7
|
+
|
|
8
|
+
function formatPoseNumber(value) {
|
|
9
|
+
const fixed = value.toFixed(9);
|
|
10
|
+
const trimmed = fixed
|
|
11
|
+
.replace(/(\.\d*?[1-9])0+$/, '$1')
|
|
12
|
+
.replace(/\.0+$/, '');
|
|
13
|
+
|
|
14
|
+
return trimmed === '-0' ? '0' : trimmed;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function serializeCameraPose(camera) {
|
|
18
|
+
camera.updateMatrixWorld(true);
|
|
19
|
+
|
|
20
|
+
const values = [
|
|
21
|
+
camera.position.x,
|
|
22
|
+
camera.position.y,
|
|
23
|
+
camera.position.z,
|
|
24
|
+
camera.quaternion.x,
|
|
25
|
+
camera.quaternion.y,
|
|
26
|
+
camera.quaternion.z,
|
|
27
|
+
camera.quaternion.w,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
if (camera.isOrthographicCamera) {
|
|
31
|
+
values.push(camera.zoom);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!values.every(Number.isFinite)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return values.map(formatPoseNumber).join(CAMERA_POSE_VALUE_SEPARATOR);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getCameraPoseParam(url) {
|
|
42
|
+
return (
|
|
43
|
+
url.searchParams.get(CAMERA_POSE_PARAM) ??
|
|
44
|
+
url.searchParams.get(CAMERA_POSE_ALIAS_PARAM)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseCameraPose(value) {
|
|
49
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const parts = value.trim().split(/[,_\s]+/).filter(Boolean);
|
|
54
|
+
if (
|
|
55
|
+
parts.length !== CAMERA_POSE_COMPONENT_COUNT &&
|
|
56
|
+
parts.length !== CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM
|
|
57
|
+
) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const values = parts.map(Number);
|
|
62
|
+
if (!values.every(Number.isFinite)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const quaternionLength = Math.hypot(
|
|
67
|
+
values[3],
|
|
68
|
+
values[4],
|
|
69
|
+
values[5],
|
|
70
|
+
values[6],
|
|
71
|
+
);
|
|
72
|
+
if (quaternionLength <= 1e-12) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const zoom = values.length === CAMERA_POSE_COMPONENT_COUNT_WITH_ZOOM
|
|
77
|
+
? values[7]
|
|
78
|
+
: null;
|
|
79
|
+
if (zoom !== null && zoom <= 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
position: values.slice(0, 3),
|
|
85
|
+
quaternion: values.slice(3, 7),
|
|
86
|
+
zoom,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function replaceCameraPoseUrl(serializedPose) {
|
|
91
|
+
const url = new URL(window.location.href);
|
|
92
|
+
url.searchParams.delete(CAMERA_POSE_ALIAS_PARAM);
|
|
93
|
+
url.searchParams.set(CAMERA_POSE_PARAM, serializedPose);
|
|
94
|
+
window.history.replaceState(window.history.state, '', url.href);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getInvalidCameraPoseMessage() {
|
|
98
|
+
return 'Invalid camerapose URL parameter ignored. Expected x_y_z_qx_qy_qz_qw.';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function createCameraUrlPoseController({
|
|
102
|
+
camera,
|
|
103
|
+
cameraController,
|
|
104
|
+
setStatus,
|
|
105
|
+
}) {
|
|
106
|
+
let lastSerializedPose = null;
|
|
107
|
+
let lastUrlWriteTime = 0;
|
|
108
|
+
|
|
109
|
+
function applyPose(pose) {
|
|
110
|
+
camera.position.fromArray(pose.position);
|
|
111
|
+
camera.quaternion.fromArray(pose.quaternion).normalize();
|
|
112
|
+
|
|
113
|
+
if (pose.zoom !== null && camera.isOrthographicCamera) {
|
|
114
|
+
camera.zoom = Math.max(pose.zoom, 1e-6);
|
|
115
|
+
camera.updateProjectionMatrix();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
camera.updateMatrixWorld(true);
|
|
119
|
+
cameraController.setCamera(camera);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function applyFromUrl({ showStatus = false } = {}) {
|
|
123
|
+
const url = new URL(window.location.href);
|
|
124
|
+
const value = getCameraPoseParam(url);
|
|
125
|
+
if (value === null) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const pose = parseCameraPose(value);
|
|
130
|
+
if (!pose) {
|
|
131
|
+
if (showStatus && setStatus) {
|
|
132
|
+
setStatus(getInvalidCameraPoseMessage(), true);
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
applyPose(pose);
|
|
138
|
+
lastSerializedPose = serializeCameraPose(camera);
|
|
139
|
+
lastUrlWriteTime = performance.now();
|
|
140
|
+
if (lastSerializedPose) {
|
|
141
|
+
replaceCameraPoseUrl(lastSerializedPose);
|
|
142
|
+
}
|
|
143
|
+
if (showStatus && setStatus) {
|
|
144
|
+
setStatus('Applied camera pose from URL.');
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function flush() {
|
|
150
|
+
const serializedPose = serializeCameraPose(camera);
|
|
151
|
+
if (!serializedPose || serializedPose === lastSerializedPose) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
replaceCameraPoseUrl(serializedPose);
|
|
156
|
+
lastSerializedPose = serializedPose;
|
|
157
|
+
lastUrlWriteTime = performance.now();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function update(time = performance.now()) {
|
|
161
|
+
if (time - lastUrlWriteTime < CAMERA_POSE_UPDATE_INTERVAL_MS) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
flush();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
applyFromUrl,
|
|
169
|
+
flush,
|
|
170
|
+
update,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -133,6 +133,11 @@ export function createFlyToController({
|
|
|
133
133
|
return true;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
function cancelCameraFlight() {
|
|
137
|
+
activeCameraFlight = null;
|
|
138
|
+
activeCameraFlightStatus = '';
|
|
139
|
+
}
|
|
140
|
+
|
|
136
141
|
async function applyTilesSetPositionFromPointerEvent(event) {
|
|
137
142
|
const coordinate = pickCoordinateFromPointerEvent(event);
|
|
138
143
|
if (!coordinate) {
|
|
@@ -204,6 +209,7 @@ export function createFlyToController({
|
|
|
204
209
|
|
|
205
210
|
return {
|
|
206
211
|
applyTilesSetPositionFromPointerEvent,
|
|
212
|
+
cancelCameraFlight,
|
|
207
213
|
frameTileset,
|
|
208
214
|
getActiveEllipsoid,
|
|
209
215
|
moveCameraToCoordinate,
|