3dtiles-inspector 0.1.7 → 0.1.8
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 +11 -0
- package/README.md +7 -0
- package/dist/inspector-assets/viewer/app.js +133 -3
- package/package.json +1 -1
- package/src/viewer/app.js +23 -1
- package/src/viewer/cameraController.js +129 -3
- package/src/viewer/session.js +91 -11
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@ The format is based on Keep a Changelog and this project follows Semantic Versio
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.8] - 2026-05-03
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added a camera pivot indicator for rotate, pan, and zoom interactions.
|
|
14
|
+
- Added bottom-right tile runtime stats for downloading, parsing, loaded, and visible tile counts.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Moved the `Canvas` toolbar section above `Transform`.
|
|
19
|
+
|
|
9
20
|
## [0.1.7] - 2026-04-27
|
|
10
21
|
|
|
11
22
|
### Changed
|
package/README.md
CHANGED
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
Requires Node.js 18 or newer.
|
|
16
16
|
|
|
17
|
+
## Built On
|
|
18
|
+
|
|
19
|
+
This project is based on and integrates work from:
|
|
20
|
+
|
|
21
|
+
- [WilliamLiu-1997/3D-Tiles-RendererJS-3DGS-Plugin](https://github.com/WilliamLiu-1997/3D-Tiles-RendererJS-3DGS-Plugin)
|
|
22
|
+
- [NASA-AMMOS/3DTilesRendererJS](https://github.com/NASA-AMMOS/3DTilesRendererJS)
|
|
23
|
+
|
|
17
24
|
## Install
|
|
18
25
|
|
|
19
26
|
```bash
|
|
@@ -64485,6 +64485,88 @@ var PointerTracker = class {
|
|
|
64485
64485
|
return Boolean(this.buttons & 4);
|
|
64486
64486
|
}
|
|
64487
64487
|
};
|
|
64488
|
+
var PivotPointMesh = class extends Mesh {
|
|
64489
|
+
constructor(size = 15, thickness = 3) {
|
|
64490
|
+
super(new PlaneGeometry(0, 0), new PivotMaterial(size, thickness));
|
|
64491
|
+
this.renderOrder = Infinity;
|
|
64492
|
+
}
|
|
64493
|
+
set focus(value) {
|
|
64494
|
+
this.material.uniforms.opacity.value = value ? 1 : 0.5;
|
|
64495
|
+
}
|
|
64496
|
+
onBeforeRender(renderer2) {
|
|
64497
|
+
renderer2.getSize(this.material.uniforms.resolution.value);
|
|
64498
|
+
}
|
|
64499
|
+
updateMatrixWorld() {
|
|
64500
|
+
this.matrixWorld.makeTranslation(this.position);
|
|
64501
|
+
}
|
|
64502
|
+
dispose() {
|
|
64503
|
+
this.geometry.dispose();
|
|
64504
|
+
this.material.dispose();
|
|
64505
|
+
}
|
|
64506
|
+
};
|
|
64507
|
+
var PivotMaterial = class extends ShaderMaterial {
|
|
64508
|
+
constructor(size, thickness) {
|
|
64509
|
+
const coreD = size + thickness;
|
|
64510
|
+
const planeD = coreD + 3 * thickness;
|
|
64511
|
+
const normThk = thickness / coreD;
|
|
64512
|
+
const ringR = (coreD - 0.4 * thickness - 4) / coreD;
|
|
64513
|
+
const hw = 0.4 * normThk;
|
|
64514
|
+
super({
|
|
64515
|
+
depthWrite: false,
|
|
64516
|
+
depthTest: false,
|
|
64517
|
+
transparent: true,
|
|
64518
|
+
uniforms: {
|
|
64519
|
+
resolution: { value: new Vector2() },
|
|
64520
|
+
opacity: { value: 1 },
|
|
64521
|
+
planeD: { value: planeD },
|
|
64522
|
+
hw: { value: hw },
|
|
64523
|
+
ringR: { value: ringR },
|
|
64524
|
+
shadowW: { value: hw * 5 },
|
|
64525
|
+
uvScale: { value: planeD / coreD }
|
|
64526
|
+
},
|
|
64527
|
+
vertexShader: `
|
|
64528
|
+
uniform float planeD;
|
|
64529
|
+
uniform vec2 resolution;
|
|
64530
|
+
varying vec2 vUv;
|
|
64531
|
+
|
|
64532
|
+
void main() {
|
|
64533
|
+
vUv = uv;
|
|
64534
|
+
float aspect = resolution.x / resolution.y;
|
|
64535
|
+
vec2 offset = uv * 2.0 - vec2(1.0);
|
|
64536
|
+
offset.y *= aspect;
|
|
64537
|
+
vec4 screenPoint = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
64538
|
+
screenPoint.xy += offset * planeD * screenPoint.w / resolution.x;
|
|
64539
|
+
gl_Position = screenPoint;
|
|
64540
|
+
}
|
|
64541
|
+
`,
|
|
64542
|
+
fragmentShader: `
|
|
64543
|
+
uniform float hw;
|
|
64544
|
+
uniform float ringR;
|
|
64545
|
+
uniform float shadowW;
|
|
64546
|
+
uniform float opacity;
|
|
64547
|
+
uniform float uvScale;
|
|
64548
|
+
varying vec2 vUv;
|
|
64549
|
+
|
|
64550
|
+
void main() {
|
|
64551
|
+
vec2 uv = (vUv * 2.0 - 1.0) * uvScale;
|
|
64552
|
+
float len = length(uv);
|
|
64553
|
+
float fw = fwidth(len) * 0.5;
|
|
64554
|
+
float d = abs(len - ringR);
|
|
64555
|
+
|
|
64556
|
+
float ring = 1.0 - smoothstep(hw - fw, hw + fw, d);
|
|
64557
|
+
|
|
64558
|
+
float shadow = (1.0 - smoothstep(hw, shadowW, d)) * (1.0 - smoothstep(ringR - fw, ringR + fw, len)) * 0.5;
|
|
64559
|
+
|
|
64560
|
+
float white = ring;
|
|
64561
|
+
float black = shadow * (1.0 - white);
|
|
64562
|
+
float alpha = (white + black) * opacity;
|
|
64563
|
+
if (alpha < 0.001) discard;
|
|
64564
|
+
gl_FragColor = vec4(vec3(white / max(alpha / opacity, 0.001)), alpha);
|
|
64565
|
+
}
|
|
64566
|
+
`
|
|
64567
|
+
});
|
|
64568
|
+
}
|
|
64569
|
+
};
|
|
64488
64570
|
var _matrix2 = new Matrix4();
|
|
64489
64571
|
function setRaycasterFromCamera(raycaster, coords, camera2) {
|
|
64490
64572
|
const ray = raycaster instanceof Ray ? raycaster : raycaster.ray;
|
|
@@ -64522,6 +64604,8 @@ var UPDATE_EVENT = { type: "update" };
|
|
|
64522
64604
|
var FINISH_EVENT = { type: "finish" };
|
|
64523
64605
|
var THRESHOLD = 1e-3;
|
|
64524
64606
|
var MAX = 1e8;
|
|
64607
|
+
var PIVOT_SIZE = 22;
|
|
64608
|
+
var PIVOT_THICKNESS = 2.5;
|
|
64525
64609
|
var VIRTUAL_HIT_DISTANCE = 50;
|
|
64526
64610
|
var ZOOM_OUT_TRANSITION_COS_THRESHOLD = Math.cos(105 * Math.PI / 180);
|
|
64527
64611
|
var ZOOM_OUT_TRANSITION_COS_MAX_THRESHOLD = Math.cos(95 * Math.PI / 180);
|
|
@@ -64550,7 +64634,7 @@ var _quaternion2 = new Quaternion();
|
|
|
64550
64634
|
var _plane = new Plane();
|
|
64551
64635
|
var _ray2 = new Ray();
|
|
64552
64636
|
var _zoomOutMetrics = { distanceScale: 1, transitionWeight: 0 };
|
|
64553
|
-
var _pointerTracker, _domElement, _camera3, _scene2, _raycaster2, _zoomDelta, _zoomInertia, _rotateInertia, _dragInertia, _dragAnchorPoint, _dragStartPosition, _dragStartQuaternion, _dragPlaneNormal, _inertiaValue, _enabled, _ellipsoid, _ellipsoidMaxRadius, _lastTime, _hit, _contextMenuEvent, _pointerDownEvent, _pointerMoveEvent, _pointerUpEvent, _wheelEvent, _pointerEnterEvent, _zoomTimeout, _CameraController_instances, setState_fn, setZooming_fn, resetState_fn, bindEvents_fn, _contextMenu, _pointerDown, _pointerMove, _pointerUp, _wheel, _pointerEnter, finalizeCamera_fn, alignCameraRightToXYPlane_fn, rotateNearAnchor_fn, clampVerticalRotateAngle_fn, rotate_fn, initializeDragAnchor_fn, restoreDragStartCamera_fn, intersectDragPlane_fn, modifiedDrag_fn, keepCameraUpAtFixedPoint_fn, getZoomOutMetrics_fn, getScaledZoomTarget_fn, getZoomOutTransitionTarget_fn, getZoomPosition_fn, applyZoom_fn, reachCameraMaxDistance_fn, isCameraCenterMode_fn, limitCameraDistance_fn, shouldDragModified_fn, keepCameraUp_fn, normalRaycastClosest_fn, raycast_fn;
|
|
64637
|
+
var _pointerTracker, _domElement, _camera3, _scene2, _raycaster2, _pivotMesh, _zoomDelta, _zoomInertia, _rotateInertia, _dragInertia, _dragAnchorPoint, _dragStartPosition, _dragStartQuaternion, _dragPlaneNormal, _inertiaValue, _enabled, _ellipsoid, _ellipsoidMaxRadius, _lastTime, _hit, _contextMenuEvent, _pointerDownEvent, _pointerMoveEvent, _pointerUpEvent, _wheelEvent, _pointerEnterEvent, _zoomTimeout, _CameraController_instances, setState_fn, setZooming_fn, resetState_fn, bindEvents_fn, _contextMenu, updateIndicatorFromHit_fn, _pointerDown, _pointerMove, _pointerUp, _wheel, _pointerEnter, finalizeCamera_fn, alignCameraRightToXYPlane_fn, rotateNearAnchor_fn, clampVerticalRotateAngle_fn, rotate_fn, initializeDragAnchor_fn, restoreDragStartCamera_fn, intersectDragPlane_fn, modifiedDrag_fn, keepCameraUpAtFixedPoint_fn, getZoomOutMetrics_fn, getScaledZoomTarget_fn, getZoomOutTransitionTarget_fn, getZoomPosition_fn, applyZoom_fn, reachCameraMaxDistance_fn, isCameraCenterMode_fn, limitCameraDistance_fn, shouldDragModified_fn, keepCameraUp_fn, normalRaycastClosest_fn, raycast_fn;
|
|
64554
64638
|
var CameraController = class extends EventDispatcher {
|
|
64555
64639
|
constructor(renderer2, scene2, camera2, options = {}) {
|
|
64556
64640
|
super();
|
|
@@ -64567,6 +64651,7 @@ var CameraController = class extends EventDispatcher {
|
|
|
64567
64651
|
__privateAdd(this, _camera3);
|
|
64568
64652
|
__privateAdd(this, _scene2);
|
|
64569
64653
|
__privateAdd(this, _raycaster2);
|
|
64654
|
+
__privateAdd(this, _pivotMesh);
|
|
64570
64655
|
__privateAdd(this, _zoomDelta);
|
|
64571
64656
|
__privateAdd(this, _zoomInertia);
|
|
64572
64657
|
__privateAdd(this, _rotateInertia);
|
|
@@ -64624,6 +64709,7 @@ var CameraController = class extends EventDispatcher {
|
|
|
64624
64709
|
mouseToCoords(_pointer1.x, _pointer1.y, __privateGet(this, _domElement), _pointer1);
|
|
64625
64710
|
setRaycasterFromCamera(__privateGet(this, _raycaster2), _pointer1, __privateGet(this, _camera3));
|
|
64626
64711
|
__privateSet(this, _hit, __privateMethod(this, _CameraController_instances, raycast_fn).call(this, __privateGet(this, _raycaster2)));
|
|
64712
|
+
__privateMethod(this, _CameraController_instances, updateIndicatorFromHit_fn).call(this);
|
|
64627
64713
|
if (this.state === DRAG && __privateGet(this, _hit).distance > 0) {
|
|
64628
64714
|
__privateMethod(this, _CameraController_instances, initializeDragAnchor_fn).call(this);
|
|
64629
64715
|
}
|
|
@@ -64660,7 +64746,7 @@ var CameraController = class extends EventDispatcher {
|
|
|
64660
64746
|
if (!__privateGet(this, _enabled)) {
|
|
64661
64747
|
return;
|
|
64662
64748
|
}
|
|
64663
|
-
const tooClose = __privateGet(this,
|
|
64749
|
+
const tooClose = __privateGet(this, _pivotMesh).position.distanceTo(__privateGet(this, _camera3).position) <= __privateGet(this, _camera3).near;
|
|
64664
64750
|
if (!this.zooming || tooClose) {
|
|
64665
64751
|
__privateGet(this, _rotateInertia).set(0, 0);
|
|
64666
64752
|
__privateGet(this, _dragInertia).set(0, 0, 0);
|
|
@@ -64674,6 +64760,7 @@ var CameraController = class extends EventDispatcher {
|
|
|
64674
64760
|
setRaycasterFromCamera(__privateGet(this, _raycaster2), _pointer1, __privateGet(this, _camera3));
|
|
64675
64761
|
if (!this.zooming && this.state === NONE || tooClose) {
|
|
64676
64762
|
__privateSet(this, _hit, __privateMethod(this, _CameraController_instances, raycast_fn).call(this, __privateGet(this, _raycaster2)));
|
|
64763
|
+
__privateMethod(this, _CameraController_instances, updateIndicatorFromHit_fn).call(this);
|
|
64677
64764
|
}
|
|
64678
64765
|
let delta = 0;
|
|
64679
64766
|
switch (e.deltaMode) {
|
|
@@ -64721,6 +64808,8 @@ var CameraController = class extends EventDispatcher {
|
|
|
64721
64808
|
__privateSet(this, _pointerTracker, new PointerTracker());
|
|
64722
64809
|
__privateSet(this, _raycaster2, new Raycaster());
|
|
64723
64810
|
__privateGet(this, _raycaster2).params.Points.threshold = 0.1;
|
|
64811
|
+
__privateSet(this, _pivotMesh, new PivotPointMesh(PIVOT_SIZE, PIVOT_THICKNESS));
|
|
64812
|
+
__privateGet(this, _pivotMesh).visible = false;
|
|
64724
64813
|
__privateSet(this, _zoomDelta, 0);
|
|
64725
64814
|
__privateSet(this, _zoomInertia, 0);
|
|
64726
64815
|
__privateSet(this, _rotateInertia, new Vector2());
|
|
@@ -64759,6 +64848,9 @@ var CameraController = class extends EventDispatcher {
|
|
|
64759
64848
|
get camera() {
|
|
64760
64849
|
return __privateGet(this, _camera3);
|
|
64761
64850
|
}
|
|
64851
|
+
get indicator() {
|
|
64852
|
+
return __privateGet(this, _pivotMesh);
|
|
64853
|
+
}
|
|
64762
64854
|
setCamera(camera2) {
|
|
64763
64855
|
__privateSet(this, _camera3, camera2);
|
|
64764
64856
|
__privateMethod(this, _CameraController_instances, resetState_fn).call(this);
|
|
@@ -64772,6 +64864,9 @@ var CameraController = class extends EventDispatcher {
|
|
|
64772
64864
|
}
|
|
64773
64865
|
init() {
|
|
64774
64866
|
__privateGet(this, _domElement).style.touchAction = "none";
|
|
64867
|
+
__privateGet(this, _pivotMesh).raycast = () => {
|
|
64868
|
+
};
|
|
64869
|
+
__privateGet(this, _scene2).add(__privateGet(this, _pivotMesh));
|
|
64775
64870
|
__privateSet(this, _contextMenuEvent, __privateGet(this, _contextMenu).bind(this));
|
|
64776
64871
|
__privateSet(this, _pointerDownEvent, __privateGet(this, _pointerDown).bind(this));
|
|
64777
64872
|
__privateSet(this, _pointerMoveEvent, __privateGet(this, _pointerMove).bind(this));
|
|
@@ -64945,6 +65040,8 @@ var CameraController = class extends EventDispatcher {
|
|
|
64945
65040
|
"pointerenter",
|
|
64946
65041
|
__privateGet(this, _pointerEnterEvent)
|
|
64947
65042
|
);
|
|
65043
|
+
__privateGet(this, _pivotMesh).removeFromParent();
|
|
65044
|
+
__privateGet(this, _pivotMesh).dispose();
|
|
64948
65045
|
__privateGet(this, _domElement).style.touchAction = "";
|
|
64949
65046
|
__privateSet(this, _enabled, false);
|
|
64950
65047
|
__privateSet(this, _ellipsoid, null);
|
|
@@ -64955,6 +65052,7 @@ _domElement = new WeakMap();
|
|
|
64955
65052
|
_camera3 = new WeakMap();
|
|
64956
65053
|
_scene2 = new WeakMap();
|
|
64957
65054
|
_raycaster2 = new WeakMap();
|
|
65055
|
+
_pivotMesh = new WeakMap();
|
|
64958
65056
|
_zoomDelta = new WeakMap();
|
|
64959
65057
|
_zoomInertia = new WeakMap();
|
|
64960
65058
|
_rotateInertia = new WeakMap();
|
|
@@ -64982,8 +65080,14 @@ setState_fn = function(state = this.state) {
|
|
|
64982
65080
|
return;
|
|
64983
65081
|
}
|
|
64984
65082
|
this.state = state;
|
|
65083
|
+
if (state !== NONE) {
|
|
65084
|
+
__privateGet(this, _pivotMesh).visible = true;
|
|
65085
|
+
}
|
|
64985
65086
|
};
|
|
64986
65087
|
setZooming_fn = function(zooming, touchZooming = false) {
|
|
65088
|
+
if (!this.zooming && this.state === NONE && zooming) {
|
|
65089
|
+
__privateGet(this, _pivotMesh).visible = true;
|
|
65090
|
+
}
|
|
64987
65091
|
this.zooming = zooming;
|
|
64988
65092
|
this.touchZooming = touchZooming;
|
|
64989
65093
|
};
|
|
@@ -65000,6 +65104,7 @@ resetState_fn = function() {
|
|
|
65000
65104
|
__privateGet(this, _dragPlaneNormal).set(0, 0, 0);
|
|
65001
65105
|
__privateSet(this, _zoomInertia, 0);
|
|
65002
65106
|
__privateSet(this, _hit, null);
|
|
65107
|
+
__privateGet(this, _pivotMesh).visible = false;
|
|
65003
65108
|
};
|
|
65004
65109
|
bindEvents_fn = function() {
|
|
65005
65110
|
__privateGet(this, _domElement).addEventListener("contextmenu", __privateGet(this, _contextMenuEvent));
|
|
@@ -65010,6 +65115,15 @@ bindEvents_fn = function() {
|
|
|
65010
65115
|
__privateGet(this, _domElement).addEventListener("pointerenter", __privateGet(this, _pointerEnterEvent));
|
|
65011
65116
|
};
|
|
65012
65117
|
_contextMenu = new WeakMap();
|
|
65118
|
+
updateIndicatorFromHit_fn = function() {
|
|
65119
|
+
if (__privateGet(this, _hit) && __privateGet(this, _hit).distance > 0) {
|
|
65120
|
+
__privateGet(this, _pivotMesh).visible = true;
|
|
65121
|
+
__privateGet(this, _pivotMesh).position.copy(__privateGet(this, _hit).point);
|
|
65122
|
+
__privateGet(this, _pivotMesh).focus = !__privateGet(this, _hit).onGlobe;
|
|
65123
|
+
} else {
|
|
65124
|
+
__privateGet(this, _pivotMesh).visible = false;
|
|
65125
|
+
}
|
|
65126
|
+
};
|
|
65013
65127
|
_pointerDown = new WeakMap();
|
|
65014
65128
|
_pointerMove = new WeakMap();
|
|
65015
65129
|
_pointerUp = new WeakMap();
|
|
@@ -65291,6 +65405,7 @@ applyZoom_fn = function(zoomAmount) {
|
|
|
65291
65405
|
_forward.subVectors(hit.point, __privateGet(this, _camera3).position).normalize();
|
|
65292
65406
|
hit.point.copy(__privateGet(this, _camera3).position).addScaledVector(_forward, VIRTUAL_HIT_DISTANCE);
|
|
65293
65407
|
hit.distance = VIRTUAL_HIT_DISTANCE;
|
|
65408
|
+
__privateGet(this, _pivotMesh).position.copy(hit.point);
|
|
65294
65409
|
}
|
|
65295
65410
|
let zoomFactor = Math.exp(-zoomAmount * 1e-3);
|
|
65296
65411
|
if (this.minDistance > 0 && zoomFactor < 1) {
|
|
@@ -65463,6 +65578,12 @@ var MOVE_TO_COORDINATE_RADIUS = 10;
|
|
|
65463
65578
|
var statusEl = document.getElementById("status");
|
|
65464
65579
|
var cacheBytesValueEl = document.getElementById("cache-bytes-value");
|
|
65465
65580
|
var splatsCountValueEl = document.getElementById("splats-count-value");
|
|
65581
|
+
var tilesDownloadingValueEl = document.getElementById(
|
|
65582
|
+
"tiles-downloading-value"
|
|
65583
|
+
);
|
|
65584
|
+
var tilesParsingValueEl = document.getElementById("tiles-parsing-value");
|
|
65585
|
+
var tilesLoadedValueEl = document.getElementById("tiles-loaded-value");
|
|
65586
|
+
var tilesVisibleValueEl = document.getElementById("tiles-visible-value");
|
|
65466
65587
|
var toolbarEl = document.getElementById("toolbar");
|
|
65467
65588
|
var toolbarDockEl = toolbarEl.parentElement;
|
|
65468
65589
|
var toolbarToggleButton = document.getElementById("toolbar-toggle");
|
|
@@ -65963,7 +66084,7 @@ function getActiveSparkSplatsCount() {
|
|
|
65963
66084
|
return count;
|
|
65964
66085
|
}
|
|
65965
66086
|
function updateRuntimeStats(force = false) {
|
|
65966
|
-
if (!cacheBytesValueEl || !splatsCountValueEl) {
|
|
66087
|
+
if (!cacheBytesValueEl || !splatsCountValueEl || !tilesDownloadingValueEl || !tilesParsingValueEl || !tilesLoadedValueEl || !tilesVisibleValueEl) {
|
|
65967
66088
|
return;
|
|
65968
66089
|
}
|
|
65969
66090
|
const now = performance.now();
|
|
@@ -65972,10 +66093,19 @@ function updateRuntimeStats(force = false) {
|
|
|
65972
66093
|
}
|
|
65973
66094
|
lastRuntimeStatsUpdateTime = now;
|
|
65974
66095
|
const cacheBytes = tiles?.lruCache?.cachedBytes ?? 0;
|
|
66096
|
+
const tilesStats = tiles?.stats;
|
|
66097
|
+
const downloadingTiles = tilesStats?.downloading ?? 0;
|
|
66098
|
+
const parsingTiles = tilesStats?.parsing ?? 0;
|
|
66099
|
+
const loadedTiles = tilesStats?.loaded ?? 0;
|
|
66100
|
+
const visibleTiles = tiles?.visibleTiles?.size ?? tilesStats?.visible ?? 0;
|
|
65975
66101
|
const activeSparkSplats = getActiveSparkSplatsCount();
|
|
65976
66102
|
const splatCount = activeSparkSplats !== null ? activeSparkSplats : getLoadedGaussianSplatCount();
|
|
65977
66103
|
cacheBytesValueEl.textContent = formatBytes(cacheBytes);
|
|
65978
66104
|
splatsCountValueEl.textContent = formatInteger(splatCount);
|
|
66105
|
+
tilesDownloadingValueEl.textContent = formatInteger(downloadingTiles);
|
|
66106
|
+
tilesParsingValueEl.textContent = formatInteger(parsingTiles);
|
|
66107
|
+
tilesLoadedValueEl.textContent = formatInteger(loadedTiles);
|
|
66108
|
+
tilesVisibleValueEl.textContent = formatInteger(visibleTiles);
|
|
65979
66109
|
}
|
|
65980
66110
|
function setGeometricErrorScaleExponent(exponent) {
|
|
65981
66111
|
geometricErrorScaleExponent = clamp2(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "3dtiles-inspector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
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
|
@@ -79,6 +79,12 @@ const MOVE_TO_COORDINATE_RADIUS = 10;
|
|
|
79
79
|
const statusEl = document.getElementById('status');
|
|
80
80
|
const cacheBytesValueEl = document.getElementById('cache-bytes-value');
|
|
81
81
|
const splatsCountValueEl = document.getElementById('splats-count-value');
|
|
82
|
+
const tilesDownloadingValueEl = document.getElementById(
|
|
83
|
+
'tiles-downloading-value',
|
|
84
|
+
);
|
|
85
|
+
const tilesParsingValueEl = document.getElementById('tiles-parsing-value');
|
|
86
|
+
const tilesLoadedValueEl = document.getElementById('tiles-loaded-value');
|
|
87
|
+
const tilesVisibleValueEl = document.getElementById('tiles-visible-value');
|
|
82
88
|
const toolbarEl = document.getElementById('toolbar');
|
|
83
89
|
const toolbarDockEl = toolbarEl.parentElement;
|
|
84
90
|
const toolbarToggleButton = document.getElementById('toolbar-toggle');
|
|
@@ -692,7 +698,14 @@ function getActiveSparkSplatsCount() {
|
|
|
692
698
|
}
|
|
693
699
|
|
|
694
700
|
function updateRuntimeStats(force = false) {
|
|
695
|
-
if (
|
|
701
|
+
if (
|
|
702
|
+
!cacheBytesValueEl ||
|
|
703
|
+
!splatsCountValueEl ||
|
|
704
|
+
!tilesDownloadingValueEl ||
|
|
705
|
+
!tilesParsingValueEl ||
|
|
706
|
+
!tilesLoadedValueEl ||
|
|
707
|
+
!tilesVisibleValueEl
|
|
708
|
+
) {
|
|
696
709
|
return;
|
|
697
710
|
}
|
|
698
711
|
|
|
@@ -707,6 +720,11 @@ function updateRuntimeStats(force = false) {
|
|
|
707
720
|
lastRuntimeStatsUpdateTime = now;
|
|
708
721
|
|
|
709
722
|
const cacheBytes = tiles?.lruCache?.cachedBytes ?? 0;
|
|
723
|
+
const tilesStats = tiles?.stats;
|
|
724
|
+
const downloadingTiles = tilesStats?.downloading ?? 0;
|
|
725
|
+
const parsingTiles = tilesStats?.parsing ?? 0;
|
|
726
|
+
const loadedTiles = tilesStats?.loaded ?? 0;
|
|
727
|
+
const visibleTiles = tiles?.visibleTiles?.size ?? tilesStats?.visible ?? 0;
|
|
710
728
|
const activeSparkSplats = getActiveSparkSplatsCount();
|
|
711
729
|
const splatCount =
|
|
712
730
|
activeSparkSplats !== null
|
|
@@ -715,6 +733,10 @@ function updateRuntimeStats(force = false) {
|
|
|
715
733
|
|
|
716
734
|
cacheBytesValueEl.textContent = formatBytes(cacheBytes);
|
|
717
735
|
splatsCountValueEl.textContent = formatInteger(splatCount);
|
|
736
|
+
tilesDownloadingValueEl.textContent = formatInteger(downloadingTiles);
|
|
737
|
+
tilesParsingValueEl.textContent = formatInteger(parsingTiles);
|
|
738
|
+
tilesLoadedValueEl.textContent = formatInteger(loadedTiles);
|
|
739
|
+
tilesVisibleValueEl.textContent = formatInteger(visibleTiles);
|
|
718
740
|
}
|
|
719
741
|
|
|
720
742
|
function setGeometricErrorScaleExponent(exponent) {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EventDispatcher,
|
|
3
3
|
Matrix4,
|
|
4
|
+
Mesh,
|
|
4
5
|
Plane,
|
|
6
|
+
PlaneGeometry,
|
|
5
7
|
Quaternion,
|
|
6
8
|
Ray,
|
|
7
9
|
Raycaster,
|
|
10
|
+
ShaderMaterial,
|
|
8
11
|
Vector2,
|
|
9
12
|
Vector3,
|
|
10
13
|
} from 'three';
|
|
@@ -191,6 +194,98 @@ class PointerTracker {
|
|
|
191
194
|
return Boolean(this.buttons & 4);
|
|
192
195
|
}
|
|
193
196
|
}
|
|
197
|
+
|
|
198
|
+
class PivotPointMesh extends Mesh {
|
|
199
|
+
constructor(size = 15, thickness = 3) {
|
|
200
|
+
super(new PlaneGeometry(0, 0), new PivotMaterial(size, thickness));
|
|
201
|
+
this.renderOrder = Infinity;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
set focus(value) {
|
|
205
|
+
this.material.uniforms.opacity.value = value ? 1 : 0.5;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
onBeforeRender(renderer) {
|
|
209
|
+
renderer.getSize(this.material.uniforms.resolution.value);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
updateMatrixWorld() {
|
|
213
|
+
this.matrixWorld.makeTranslation(this.position);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
dispose() {
|
|
217
|
+
this.geometry.dispose();
|
|
218
|
+
this.material.dispose();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
class PivotMaterial extends ShaderMaterial {
|
|
223
|
+
constructor(size, thickness) {
|
|
224
|
+
const coreD = size + thickness;
|
|
225
|
+
const planeD = coreD + 3 * thickness;
|
|
226
|
+
const normThk = thickness / coreD;
|
|
227
|
+
const ringR = (coreD - 0.4 * thickness - 4.0) / coreD;
|
|
228
|
+
const hw = 0.4 * normThk;
|
|
229
|
+
|
|
230
|
+
super({
|
|
231
|
+
depthWrite: false,
|
|
232
|
+
depthTest: false,
|
|
233
|
+
transparent: true,
|
|
234
|
+
|
|
235
|
+
uniforms: {
|
|
236
|
+
resolution: { value: new Vector2() },
|
|
237
|
+
opacity: { value: 1 },
|
|
238
|
+
planeD: { value: planeD },
|
|
239
|
+
hw: { value: hw },
|
|
240
|
+
ringR: { value: ringR },
|
|
241
|
+
shadowW: { value: hw * 5.0 },
|
|
242
|
+
uvScale: { value: planeD / coreD },
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
vertexShader: `
|
|
246
|
+
uniform float planeD;
|
|
247
|
+
uniform vec2 resolution;
|
|
248
|
+
varying vec2 vUv;
|
|
249
|
+
|
|
250
|
+
void main() {
|
|
251
|
+
vUv = uv;
|
|
252
|
+
float aspect = resolution.x / resolution.y;
|
|
253
|
+
vec2 offset = uv * 2.0 - vec2(1.0);
|
|
254
|
+
offset.y *= aspect;
|
|
255
|
+
vec4 screenPoint = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
256
|
+
screenPoint.xy += offset * planeD * screenPoint.w / resolution.x;
|
|
257
|
+
gl_Position = screenPoint;
|
|
258
|
+
}
|
|
259
|
+
`,
|
|
260
|
+
fragmentShader: `
|
|
261
|
+
uniform float hw;
|
|
262
|
+
uniform float ringR;
|
|
263
|
+
uniform float shadowW;
|
|
264
|
+
uniform float opacity;
|
|
265
|
+
uniform float uvScale;
|
|
266
|
+
varying vec2 vUv;
|
|
267
|
+
|
|
268
|
+
void main() {
|
|
269
|
+
vec2 uv = (vUv * 2.0 - 1.0) * uvScale;
|
|
270
|
+
float len = length(uv);
|
|
271
|
+
float fw = fwidth(len) * 0.5;
|
|
272
|
+
float d = abs(len - ringR);
|
|
273
|
+
|
|
274
|
+
float ring = 1.0 - smoothstep(hw - fw, hw + fw, d);
|
|
275
|
+
|
|
276
|
+
float shadow = (1.0 - smoothstep(hw, shadowW, d)) * (1.0 - smoothstep(ringR - fw, ringR + fw, len)) * 0.5;
|
|
277
|
+
|
|
278
|
+
float white = ring;
|
|
279
|
+
float black = shadow * (1.0 - white);
|
|
280
|
+
float alpha = (white + black) * opacity;
|
|
281
|
+
if (alpha < 0.001) discard;
|
|
282
|
+
gl_FragColor = vec4(vec3(white / max(alpha / opacity, 0.001)), alpha);
|
|
283
|
+
}
|
|
284
|
+
`,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
194
289
|
const _matrix = new Matrix4();
|
|
195
290
|
// custom version of set raycaster from camera that relies on the underlying matrices
|
|
196
291
|
// so the ray origin is position at the camera near clip.
|
|
@@ -240,6 +335,8 @@ const UPDATE_EVENT = { type: 'update' };
|
|
|
240
335
|
const FINISH_EVENT = { type: 'finish' };
|
|
241
336
|
const THRESHOLD = 1e-3;
|
|
242
337
|
const MAX = 1e8;
|
|
338
|
+
const PIVOT_SIZE = 22;
|
|
339
|
+
const PIVOT_THICKNESS = 2.5;
|
|
243
340
|
const VIRTUAL_HIT_DISTANCE = 50;
|
|
244
341
|
const ZOOM_OUT_TRANSITION_COS_THRESHOLD = Math.cos((105 * Math.PI) / 180);
|
|
245
342
|
const ZOOM_OUT_TRANSITION_COS_MAX_THRESHOLD = Math.cos((95 * Math.PI) / 180);
|
|
@@ -281,6 +378,7 @@ class CameraController extends EventDispatcher {
|
|
|
281
378
|
#camera;
|
|
282
379
|
#scene;
|
|
283
380
|
#raycaster;
|
|
381
|
+
#pivotMesh;
|
|
284
382
|
#zoomDelta;
|
|
285
383
|
#zoomInertia;
|
|
286
384
|
#rotateInertia;
|
|
@@ -330,6 +428,8 @@ class CameraController extends EventDispatcher {
|
|
|
330
428
|
this.#pointerTracker = new PointerTracker();
|
|
331
429
|
this.#raycaster = new Raycaster();
|
|
332
430
|
this.#raycaster.params.Points.threshold = 0.1;
|
|
431
|
+
this.#pivotMesh = new PivotPointMesh(PIVOT_SIZE, PIVOT_THICKNESS);
|
|
432
|
+
this.#pivotMesh.visible = false;
|
|
333
433
|
this.#zoomDelta = 0;
|
|
334
434
|
this.#zoomInertia = 0;
|
|
335
435
|
this.#rotateInertia = new Vector2();
|
|
@@ -368,13 +468,22 @@ class CameraController extends EventDispatcher {
|
|
|
368
468
|
get camera() {
|
|
369
469
|
return this.#camera;
|
|
370
470
|
}
|
|
471
|
+
get indicator() {
|
|
472
|
+
return this.#pivotMesh;
|
|
473
|
+
}
|
|
371
474
|
#setState(state = this.state) {
|
|
372
475
|
if (this.state === state) {
|
|
373
476
|
return;
|
|
374
477
|
}
|
|
375
478
|
this.state = state;
|
|
479
|
+
if (state !== NONE) {
|
|
480
|
+
this.#pivotMesh.visible = true;
|
|
481
|
+
}
|
|
376
482
|
}
|
|
377
483
|
#setZooming(zooming, touchZooming = false) {
|
|
484
|
+
if (!this.zooming && this.state === NONE && zooming) {
|
|
485
|
+
this.#pivotMesh.visible = true;
|
|
486
|
+
}
|
|
378
487
|
this.zooming = zooming;
|
|
379
488
|
this.touchZooming = touchZooming;
|
|
380
489
|
}
|
|
@@ -391,6 +500,7 @@ class CameraController extends EventDispatcher {
|
|
|
391
500
|
this.#dragPlaneNormal.set(0, 0, 0);
|
|
392
501
|
this.#zoomInertia = 0;
|
|
393
502
|
this.#hit = null;
|
|
503
|
+
this.#pivotMesh.visible = false;
|
|
394
504
|
}
|
|
395
505
|
setCamera(camera) {
|
|
396
506
|
this.#camera = camera;
|
|
@@ -405,6 +515,8 @@ class CameraController extends EventDispatcher {
|
|
|
405
515
|
}
|
|
406
516
|
init() {
|
|
407
517
|
this.#domElement.style.touchAction = 'none';
|
|
518
|
+
this.#pivotMesh.raycast = () => {};
|
|
519
|
+
this.#scene.add(this.#pivotMesh);
|
|
408
520
|
this.#contextMenuEvent = this.#contextMenu.bind(this);
|
|
409
521
|
this.#pointerDownEvent = this.#pointerDown.bind(this);
|
|
410
522
|
this.#pointerMoveEvent = this.#pointerMove.bind(this);
|
|
@@ -600,6 +712,8 @@ class CameraController extends EventDispatcher {
|
|
|
600
712
|
'pointerenter',
|
|
601
713
|
this.#pointerEnterEvent,
|
|
602
714
|
);
|
|
715
|
+
this.#pivotMesh.removeFromParent();
|
|
716
|
+
this.#pivotMesh.dispose();
|
|
603
717
|
this.#domElement.style.touchAction = '';
|
|
604
718
|
this.#enabled = false;
|
|
605
719
|
this.#ellipsoid = null;
|
|
@@ -615,6 +729,15 @@ class CameraController extends EventDispatcher {
|
|
|
615
729
|
#contextMenu = (e) => {
|
|
616
730
|
e.preventDefault();
|
|
617
731
|
};
|
|
732
|
+
#updateIndicatorFromHit() {
|
|
733
|
+
if (this.#hit && this.#hit.distance > 0) {
|
|
734
|
+
this.#pivotMesh.visible = true;
|
|
735
|
+
this.#pivotMesh.position.copy(this.#hit.point);
|
|
736
|
+
this.#pivotMesh.focus = !this.#hit.onGlobe;
|
|
737
|
+
} else {
|
|
738
|
+
this.#pivotMesh.visible = false;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
618
741
|
#pointerDown = (e) => {
|
|
619
742
|
if (!this.#enabled) {
|
|
620
743
|
return;
|
|
@@ -653,6 +776,7 @@ class CameraController extends EventDispatcher {
|
|
|
653
776
|
mouseToCoords(_pointer1.x, _pointer1.y, this.#domElement, _pointer1);
|
|
654
777
|
setRaycasterFromCamera(this.#raycaster, _pointer1, this.#camera);
|
|
655
778
|
this.#hit = this.#raycast(this.#raycaster);
|
|
779
|
+
this.#updateIndicatorFromHit();
|
|
656
780
|
if (this.state === DRAG && this.#hit.distance > 0) {
|
|
657
781
|
this.#initializeDragAnchor();
|
|
658
782
|
}
|
|
@@ -689,9 +813,9 @@ class CameraController extends EventDispatcher {
|
|
|
689
813
|
if (!this.#enabled) {
|
|
690
814
|
return;
|
|
691
815
|
}
|
|
692
|
-
const tooClose =
|
|
693
|
-
|
|
694
|
-
|
|
816
|
+
const tooClose =
|
|
817
|
+
this.#pivotMesh.position.distanceTo(this.#camera.position) <=
|
|
818
|
+
this.#camera.near;
|
|
695
819
|
if (!this.zooming || tooClose) {
|
|
696
820
|
this.#rotateInertia.set(0, 0);
|
|
697
821
|
this.#dragInertia.set(0, 0, 0);
|
|
@@ -705,6 +829,7 @@ class CameraController extends EventDispatcher {
|
|
|
705
829
|
setRaycasterFromCamera(this.#raycaster, _pointer1, this.#camera);
|
|
706
830
|
if ((!this.zooming && this.state === NONE) || tooClose) {
|
|
707
831
|
this.#hit = this.#raycast(this.#raycaster);
|
|
832
|
+
this.#updateIndicatorFromHit();
|
|
708
833
|
}
|
|
709
834
|
let delta = 0;
|
|
710
835
|
switch (e.deltaMode) {
|
|
@@ -1056,6 +1181,7 @@ class CameraController extends EventDispatcher {
|
|
|
1056
1181
|
.copy(this.#camera.position)
|
|
1057
1182
|
.addScaledVector(_forward, VIRTUAL_HIT_DISTANCE);
|
|
1058
1183
|
hit.distance = VIRTUAL_HIT_DISTANCE;
|
|
1184
|
+
this.#pivotMesh.position.copy(hit.point);
|
|
1059
1185
|
}
|
|
1060
1186
|
let zoomFactor = Math.exp(-zoomAmount * 0.001);
|
|
1061
1187
|
if (this.minDistance > 0 && zoomFactor < 1) {
|
package/src/viewer/session.js
CHANGED
|
@@ -900,6 +900,24 @@ function buildViewerHtml(viewerConfig) {
|
|
|
900
900
|
pointer-events: none;
|
|
901
901
|
}
|
|
902
902
|
|
|
903
|
+
.tile-runtime-stats {
|
|
904
|
+
position: fixed;
|
|
905
|
+
right: 16px;
|
|
906
|
+
bottom: 16px;
|
|
907
|
+
display: flex;
|
|
908
|
+
flex-wrap: nowrap;
|
|
909
|
+
justify-content: flex-end;
|
|
910
|
+
gap: 14px;
|
|
911
|
+
box-sizing: border-box;
|
|
912
|
+
max-width: calc(100vw - 32px);
|
|
913
|
+
padding: 4px 8px;
|
|
914
|
+
border-radius: 6px;
|
|
915
|
+
background: rgba(255, 255, 255, 0.15);
|
|
916
|
+
backdrop-filter: blur(6px);
|
|
917
|
+
z-index: 12;
|
|
918
|
+
pointer-events: none;
|
|
919
|
+
}
|
|
920
|
+
|
|
903
921
|
.runtime-stat {
|
|
904
922
|
display: grid;
|
|
905
923
|
gap: 4px;
|
|
@@ -912,6 +930,19 @@ function buildViewerHtml(viewerConfig) {
|
|
|
912
930
|
backdrop-filter: blur(14px);
|
|
913
931
|
}
|
|
914
932
|
|
|
933
|
+
.tile-runtime-stats .runtime-stat {
|
|
934
|
+
display: inline-flex;
|
|
935
|
+
align-items: center;
|
|
936
|
+
gap: 0;
|
|
937
|
+
min-width: 0;
|
|
938
|
+
padding: 0;
|
|
939
|
+
border: 0;
|
|
940
|
+
border-radius: 0;
|
|
941
|
+
background: transparent;
|
|
942
|
+
box-shadow: none;
|
|
943
|
+
backdrop-filter: none;
|
|
944
|
+
}
|
|
945
|
+
|
|
915
946
|
.runtime-stat-label {
|
|
916
947
|
margin: 0;
|
|
917
948
|
font-size: 10px;
|
|
@@ -921,6 +952,18 @@ function buildViewerHtml(viewerConfig) {
|
|
|
921
952
|
color: #5d738b;
|
|
922
953
|
}
|
|
923
954
|
|
|
955
|
+
.tile-runtime-stats .runtime-stat-label,
|
|
956
|
+
.tile-runtime-stats .runtime-stat-value {
|
|
957
|
+
display: inline-flex;
|
|
958
|
+
align-items: center;
|
|
959
|
+
font-size: 12px;
|
|
960
|
+
font-weight: 400;
|
|
961
|
+
letter-spacing: 0;
|
|
962
|
+
line-height: 14px;
|
|
963
|
+
text-transform: none;
|
|
964
|
+
color: #24292f;
|
|
965
|
+
}
|
|
966
|
+
|
|
924
967
|
.runtime-stat-value {
|
|
925
968
|
margin: 0;
|
|
926
969
|
font-size: 15px;
|
|
@@ -929,6 +972,10 @@ function buildViewerHtml(viewerConfig) {
|
|
|
929
972
|
color: #16324f;
|
|
930
973
|
}
|
|
931
974
|
|
|
975
|
+
.tile-runtime-stats .runtime-stat-value {
|
|
976
|
+
font-variant-numeric: tabular-nums;
|
|
977
|
+
}
|
|
978
|
+
|
|
932
979
|
canvas {
|
|
933
980
|
display: block;
|
|
934
981
|
}
|
|
@@ -1216,6 +1263,16 @@ function buildViewerHtml(viewerConfig) {
|
|
|
1216
1263
|
top: 16px;
|
|
1217
1264
|
right: 16px;
|
|
1218
1265
|
left: 16px;
|
|
1266
|
+
flex-wrap: wrap;
|
|
1267
|
+
justify-content: stretch;
|
|
1268
|
+
max-width: none;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
.tile-runtime-stats {
|
|
1272
|
+
right: 16px;
|
|
1273
|
+
bottom: 16px;
|
|
1274
|
+
left: 16px;
|
|
1275
|
+
flex-wrap: wrap;
|
|
1219
1276
|
justify-content: stretch;
|
|
1220
1277
|
max-width: none;
|
|
1221
1278
|
}
|
|
@@ -1225,6 +1282,11 @@ function buildViewerHtml(viewerConfig) {
|
|
|
1225
1282
|
min-width: 0;
|
|
1226
1283
|
}
|
|
1227
1284
|
|
|
1285
|
+
.tile-runtime-stats .runtime-stat {
|
|
1286
|
+
flex: 0 0 auto;
|
|
1287
|
+
min-width: 0;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1228
1290
|
.toolbar-dock {
|
|
1229
1291
|
top: auto;
|
|
1230
1292
|
bottom: 16px;
|
|
@@ -1257,6 +1319,24 @@ function buildViewerHtml(viewerConfig) {
|
|
|
1257
1319
|
<p id="splats-count-value" class="runtime-stat-value">0</p>
|
|
1258
1320
|
</div>
|
|
1259
1321
|
</div>
|
|
1322
|
+
<div class="tile-runtime-stats" aria-live="polite">
|
|
1323
|
+
<div class="runtime-stat">
|
|
1324
|
+
<p class="runtime-stat-label">Downloading: </p>
|
|
1325
|
+
<p id="tiles-downloading-value" class="runtime-stat-value">0</p>
|
|
1326
|
+
</div>
|
|
1327
|
+
<div class="runtime-stat">
|
|
1328
|
+
<p class="runtime-stat-label">Parsing: </p>
|
|
1329
|
+
<p id="tiles-parsing-value" class="runtime-stat-value">0</p>
|
|
1330
|
+
</div>
|
|
1331
|
+
<div class="runtime-stat">
|
|
1332
|
+
<p class="runtime-stat-label">Loaded: </p>
|
|
1333
|
+
<p id="tiles-loaded-value" class="runtime-stat-value">0</p>
|
|
1334
|
+
</div>
|
|
1335
|
+
<div class="runtime-stat">
|
|
1336
|
+
<p class="runtime-stat-label">Visible: </p>
|
|
1337
|
+
<p id="tiles-visible-value" class="runtime-stat-value">0</p>
|
|
1338
|
+
</div>
|
|
1339
|
+
</div>
|
|
1260
1340
|
<div class="toolbar-dock expanded">
|
|
1261
1341
|
<button
|
|
1262
1342
|
id="toolbar-toggle"
|
|
@@ -1269,16 +1349,6 @@ function buildViewerHtml(viewerConfig) {
|
|
|
1269
1349
|
Hide Sidebar
|
|
1270
1350
|
</button>
|
|
1271
1351
|
<div id="toolbar" class="toolbar">
|
|
1272
|
-
<div class="toolbar-section">
|
|
1273
|
-
<div class="toolbar-section-header">
|
|
1274
|
-
<p class="toolbar-section-title">Transform</p>
|
|
1275
|
-
</div>
|
|
1276
|
-
<div class="transform-actions">
|
|
1277
|
-
<button id="translate" type="button">Translate</button>
|
|
1278
|
-
<button id="rotate" type="button">Rotate</button>
|
|
1279
|
-
<button id="set-position" class="full-span" type="button">Set Position</button>
|
|
1280
|
-
</div>
|
|
1281
|
-
</div>
|
|
1282
1352
|
<div class="toolbar-section">
|
|
1283
1353
|
<div class="toolbar-section-header">
|
|
1284
1354
|
<p class="toolbar-section-title">Canvas</p>
|
|
@@ -1289,6 +1359,16 @@ function buildViewerHtml(viewerConfig) {
|
|
|
1289
1359
|
<button id="move-to-tiles" type="button">Move To Tiles</button>
|
|
1290
1360
|
</div>
|
|
1291
1361
|
</div>
|
|
1362
|
+
<div class="toolbar-section">
|
|
1363
|
+
<div class="toolbar-section-header">
|
|
1364
|
+
<p class="toolbar-section-title">Transform</p>
|
|
1365
|
+
</div>
|
|
1366
|
+
<div class="transform-actions">
|
|
1367
|
+
<button id="translate" type="button">Translate</button>
|
|
1368
|
+
<button id="rotate" type="button">Rotate</button>
|
|
1369
|
+
<button id="set-position" class="full-span" type="button">Set Position</button>
|
|
1370
|
+
</div>
|
|
1371
|
+
</div>
|
|
1292
1372
|
<div class="toolbar-section">
|
|
1293
1373
|
<div class="toolbar-section-header">
|
|
1294
1374
|
<p class="toolbar-section-title">Coordinate</p>
|
|
@@ -1299,8 +1379,8 @@ function buildViewerHtml(viewerConfig) {
|
|
|
1299
1379
|
<label><span>Height</span><input id="height" type="number" step="any" value="0" /></label>
|
|
1300
1380
|
</div>
|
|
1301
1381
|
<div class="coordinate-actions">
|
|
1302
|
-
<button id="move-tiles-to-coordinate" class="wide" type="button">Move Tiles</button>
|
|
1303
1382
|
<button id="move-camera-to-coordinate" class="wide" type="button">Move Camera</button>
|
|
1383
|
+
<button id="move-tiles-to-coordinate" class="wide" type="button">Move Tiles</button>
|
|
1304
1384
|
</div>
|
|
1305
1385
|
</div>
|
|
1306
1386
|
<div class="toolbar-section">
|