@file-viewer/renderer-3d 2.1.13 → 2.1.14
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/dist/model.js +83 -3
- package/package.json +3 -3
package/dist/model.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
3
|
-
import { createFileViewerTranslator, } from '@file-viewer/core';
|
|
3
|
+
import { createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerTranslator, registerFileViewerViewStateProvider, unregisterFileViewerViewStateProvider, } from '@file-viewer/core';
|
|
4
4
|
import { formatGeometryKernelNotice, inspectGeometryKernelFile, isGeometryKernelFormat, } from '@file-viewer/geometry-engine';
|
|
5
5
|
const modelStyle = `
|
|
6
6
|
.model-viewer{display:flex;height:100%;min-height:100%;flex-direction:column;background:#f8fafc;color:#162333}
|
|
@@ -106,6 +106,7 @@ export default async function renderModel(buffer, target, type = 'glb', context)
|
|
|
106
106
|
let activeVersion = 0;
|
|
107
107
|
let mixer = null;
|
|
108
108
|
const clock = new THREE.Clock();
|
|
109
|
+
const viewStateEmitter = createFileViewerViewStateChangeEmitter();
|
|
109
110
|
const root = createElement('div', 'model-viewer');
|
|
110
111
|
const toolbar = createElement('div', 'model-toolbar');
|
|
111
112
|
const actions = createElement('div', 'model-actions');
|
|
@@ -165,6 +166,68 @@ export default async function renderModel(buffer, target, type = 'glb', context)
|
|
|
165
166
|
}
|
|
166
167
|
updateUi();
|
|
167
168
|
};
|
|
169
|
+
const vectorToArray = (vector) => {
|
|
170
|
+
return vector ? [vector.x, vector.y, vector.z] : undefined;
|
|
171
|
+
};
|
|
172
|
+
const readVector = (value, fallback) => {
|
|
173
|
+
if (!Array.isArray(value)) {
|
|
174
|
+
return fallback.clone();
|
|
175
|
+
}
|
|
176
|
+
const [x, y, z] = value.map(Number);
|
|
177
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) {
|
|
178
|
+
return fallback.clone();
|
|
179
|
+
}
|
|
180
|
+
return new THREE.Vector3(x, y, z);
|
|
181
|
+
};
|
|
182
|
+
const getModelViewState = () => ({
|
|
183
|
+
renderer: 'model',
|
|
184
|
+
extra: {
|
|
185
|
+
status,
|
|
186
|
+
cameraPosition: vectorToArray(camera?.position),
|
|
187
|
+
cameraTarget: vectorToArray(controls?.target),
|
|
188
|
+
autoRotate,
|
|
189
|
+
wireframe,
|
|
190
|
+
showGrid,
|
|
191
|
+
showAxes,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
const emitViewStateChange = (action, source = 'viewer') => {
|
|
195
|
+
const state = getModelViewState();
|
|
196
|
+
viewStateEmitter.emit(createFileViewerViewStateChange(state, { action, source }));
|
|
197
|
+
return state;
|
|
198
|
+
};
|
|
199
|
+
const applyModelViewState = (state, applyOptions = {}) => {
|
|
200
|
+
const source = applyOptions.source || 'api';
|
|
201
|
+
const action = applyOptions.action || 'restore';
|
|
202
|
+
const notify = applyOptions.notify !== false;
|
|
203
|
+
if (camera) {
|
|
204
|
+
camera.position.copy(readVector(state.extra?.cameraPosition, camera.position));
|
|
205
|
+
camera.updateProjectionMatrix();
|
|
206
|
+
}
|
|
207
|
+
if (controls) {
|
|
208
|
+
controls.target.copy(readVector(state.extra?.cameraTarget, controls.target));
|
|
209
|
+
controls.update();
|
|
210
|
+
}
|
|
211
|
+
if (typeof state.extra?.autoRotate === 'boolean') {
|
|
212
|
+
autoRotate = state.extra.autoRotate;
|
|
213
|
+
}
|
|
214
|
+
if (typeof state.extra?.wireframe === 'boolean') {
|
|
215
|
+
wireframe = state.extra.wireframe;
|
|
216
|
+
updateWireframe();
|
|
217
|
+
}
|
|
218
|
+
if (typeof state.extra?.showGrid === 'boolean') {
|
|
219
|
+
showGrid = state.extra.showGrid;
|
|
220
|
+
}
|
|
221
|
+
if (typeof state.extra?.showAxes === 'boolean') {
|
|
222
|
+
showAxes = state.extra.showAxes;
|
|
223
|
+
}
|
|
224
|
+
updateHelperVisibility();
|
|
225
|
+
updateUi();
|
|
226
|
+
if (notify) {
|
|
227
|
+
return emitViewStateChange(action, source);
|
|
228
|
+
}
|
|
229
|
+
return getModelViewState();
|
|
230
|
+
};
|
|
168
231
|
const resize = () => {
|
|
169
232
|
if (!renderer || !camera) {
|
|
170
233
|
return;
|
|
@@ -296,7 +359,7 @@ export default async function renderModel(buffer, target, type = 'glb', context)
|
|
|
296
359
|
size,
|
|
297
360
|
};
|
|
298
361
|
};
|
|
299
|
-
const fitToView = () => {
|
|
362
|
+
const fitToView = (source = 'viewer') => {
|
|
300
363
|
if (!modelRoot || !camera || !controls) {
|
|
301
364
|
return;
|
|
302
365
|
}
|
|
@@ -311,6 +374,7 @@ export default async function renderModel(buffer, target, type = 'glb', context)
|
|
|
311
374
|
camera.updateProjectionMatrix();
|
|
312
375
|
controls.target.copy(center);
|
|
313
376
|
controls.update();
|
|
377
|
+
emitViewStateChange('fit', source);
|
|
314
378
|
};
|
|
315
379
|
const addModelToScene = async (object) => {
|
|
316
380
|
if (!scene) {
|
|
@@ -522,25 +586,39 @@ export default async function renderModel(buffer, target, type = 'glb', context)
|
|
|
522
586
|
}
|
|
523
587
|
updateUi();
|
|
524
588
|
};
|
|
525
|
-
|
|
589
|
+
const onControlsEnd = () => {
|
|
590
|
+
emitViewStateChange('camera-change', 'user');
|
|
591
|
+
};
|
|
592
|
+
fitButton.addEventListener('click', () => fitToView('user'));
|
|
526
593
|
rotateButton.addEventListener('click', () => {
|
|
527
594
|
autoRotate = !autoRotate;
|
|
528
595
|
updateUi();
|
|
596
|
+
emitViewStateChange('view-option-change', 'user');
|
|
529
597
|
});
|
|
530
598
|
wireframeButton.addEventListener('click', () => {
|
|
531
599
|
wireframe = !wireframe;
|
|
532
600
|
updateWireframe();
|
|
601
|
+
emitViewStateChange('view-option-change', 'user');
|
|
533
602
|
});
|
|
534
603
|
gridButton.addEventListener('click', () => {
|
|
535
604
|
showGrid = !showGrid;
|
|
536
605
|
updateHelperVisibility();
|
|
606
|
+
emitViewStateChange('view-option-change', 'user');
|
|
537
607
|
});
|
|
538
608
|
axesButton.addEventListener('click', () => {
|
|
539
609
|
showAxes = !showAxes;
|
|
540
610
|
updateHelperVisibility();
|
|
611
|
+
emitViewStateChange('view-option-change', 'user');
|
|
541
612
|
});
|
|
542
613
|
updateUi();
|
|
543
614
|
ensureScene();
|
|
615
|
+
const controlsWithEvents = controls;
|
|
616
|
+
controlsWithEvents?.addEventListener('end', onControlsEnd);
|
|
617
|
+
registerFileViewerViewStateProvider(root, {
|
|
618
|
+
getState: getModelViewState,
|
|
619
|
+
applyState: applyModelViewState,
|
|
620
|
+
subscribe: viewStateEmitter.subscribe,
|
|
621
|
+
});
|
|
544
622
|
resizeObserver = new ResizeObserver(resize);
|
|
545
623
|
resizeObserver.observe(canvas);
|
|
546
624
|
clock.start();
|
|
@@ -554,6 +632,8 @@ export default async function renderModel(buffer, target, type = 'glb', context)
|
|
|
554
632
|
resizeObserver?.disconnect();
|
|
555
633
|
resizeObserver = null;
|
|
556
634
|
clearModel();
|
|
635
|
+
controlsWithEvents?.removeEventListener('end', onControlsEnd);
|
|
636
|
+
unregisterFileViewerViewStateProvider(root);
|
|
557
637
|
controls?.dispose();
|
|
558
638
|
controls = null;
|
|
559
639
|
renderer?.dispose();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-3d",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone 3D model renderer plugin for Flyfish File Viewer powered by Three.js loaders and OrbitControls.",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"LICENSE"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@file-viewer/core": "^2.1.
|
|
61
|
-
"@file-viewer/geometry-engine": "^2.1.
|
|
60
|
+
"@file-viewer/core": "^2.1.14",
|
|
61
|
+
"@file-viewer/geometry-engine": "^2.1.14",
|
|
62
62
|
"three": "^0.184.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|