@file-viewer/renderer-3d 2.1.12 → 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.
Files changed (2) hide show
  1. package/dist/model.js +83 -3
  2. 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
- fitButton.addEventListener('click', fitToView);
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.12",
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.12",
61
- "@file-viewer/geometry-engine": "^2.1.12",
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": {