MikaFil commited on
Commit
21c14a7
·
verified ·
1 Parent(s): 768c848

Update viewer.js

Browse files
Files changed (1) hide show
  1. viewer.js +97 -92
viewer.js CHANGED
@@ -55,54 +55,24 @@ function traverse(entity, callback) {
55
  }
56
  }
57
 
58
- /**
59
- * Charge la source d'orbit-camera.js une seule fois (cache global),
60
- * puis l'évalue POUR CHAQUE APP afin que pc.createScript enregistre
61
- * les types dans le ScriptRegistry de l'application courante.
62
- */
63
  const ORBIT_URL = "https://mikafil-viewer-sgos.static.hf.space/orbit-camera.js";
64
- async function registerOrbitScriptsForApp(app) {
65
- // Si cette app possède déjà les scripts, on ne fait rien
66
- try {
67
- if (app?.scripts?.get && app.scripts.get("orbitCamera")) return;
68
- } catch (_) {}
69
-
70
- // Cache global de la source
71
- if (!window.__ORBIT_SOURCE_PROMISE__) {
72
- window.__ORBIT_SOURCE_PROMISE__ = fetch(ORBIT_URL, { cache: "no-store", credentials: "omit" })
73
- .then(r => {
74
- if (!r.ok) throw new Error("Failed to fetch orbit-camera.js");
75
- return r.text();
76
- });
77
- }
78
- const src = await window.__ORBIT_SOURCE_PROMISE__;
79
-
80
- // Binder l’“application courante” sur CETTE app pendant l’évaluation
81
- const prevGetApp = pc.Application.getApplication ? pc.Application.getApplication.bind(pc.Application) : null;
82
- const prevApp = pc.app;
83
-
84
- try {
85
- if (pc.Application.getApplication) {
86
- pc.Application.getApplication = () => app;
87
- }
88
- pc.app = app;
89
-
90
- // Évaluation globale : pc.createScript enregistre dans le registry de "app"
91
- (0, eval)(src);
92
-
93
- } catch (e) {
94
- console.error("[viewer.js] orbit-camera.js eval error:", e);
95
- } finally {
96
- if (prevGetApp) pc.Application.getApplication = prevGetApp;
97
- pc.app = prevApp;
98
- }
99
 
100
- // Sécurité : vérifier que le type est bien dispo
101
- try {
102
- if (!(app?.scripts?.get && app.scripts.get("orbitCamera"))) {
103
- console.warn("[viewer.js] orbitCamera script type not found on app after eval");
104
- }
105
- } catch (_) {}
 
 
 
106
  }
107
 
108
  let pc;
@@ -128,44 +98,59 @@ export async function initializeViewer(config, instanceId) {
128
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
129
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
130
 
131
- // Params
132
  sogsUrl = config.sogs_json_url;
133
- glbUrl = (config.glb_url !== undefined)
134
- ? config.glb_url
135
- : "https://huggingface.co/datasets/MikaFil/viewer_gs/resolve/main/ressources/espace_expo/sol_blanc_2.glb";
136
- presentoirUrl = (config.presentoir_url !== undefined)
137
- ? config.presentoir_url
138
- : "https://huggingface.co/datasets/MikaFil/viewer_gs/resolve/main/ressources/espace_expo/sol_blanc_2.glb";
 
 
139
  minZoom = parseFloat(config.minZoom || "1");
140
  maxZoom = parseFloat(config.maxZoom || "20");
141
  minAngle = parseFloat(config.minAngle || "-45");
142
  maxAngle = parseFloat(config.maxAngle || "90");
143
- minAzimuth = (config.minAzimuth !== undefined) ? parseFloat(config.minAzimuth) : -360;
144
- maxAzimuth = (config.maxAzimuth !== undefined) ? parseFloat(config.maxAzimuth) : 360;
 
 
145
  minPivotY = parseFloat(config.minPivotY || "0");
146
- minY = (config.minY !== undefined) ? parseFloat(config.minY) : 0;
147
-
148
- modelX = (config.modelX !== undefined) ? parseFloat(config.modelX) : 0;
149
- modelY = (config.modelY !== undefined) ? parseFloat(config.modelY) : 0;
150
- modelZ = (config.modelZ !== undefined) ? parseFloat(config.modelZ) : 0;
151
- modelScale = (config.modelScale !== undefined) ? parseFloat(config.modelScale) : 1;
152
- modelRotationX = (config.modelRotationX !== undefined) ? parseFloat(config.modelRotationX) : 0;
153
- modelRotationY = (config.modelRotationY !== undefined) ? parseFloat(config.modelRotationY) : 0;
154
- modelRotationZ = (config.modelRotationZ !== undefined) ? parseFloat(config.modelRotationZ) : 0;
155
-
156
- presentoirScaleX = (config.presentoirScaleX !== undefined) ? parseFloat(config.presentoirScaleX) : 0;
157
- presentoirScaleY = (config.presentoirScaleY !== undefined) ? parseFloat(config.presentoirScaleY) : 0;
158
- presentoirScaleZ = (config.presentoirScaleZ !== undefined) ? parseFloat(config.presentoirScaleZ) : 0;
159
-
160
- const cameraX = (config.cameraX !== undefined) ? parseFloat(config.cameraX) : 0;
161
- const cameraY = (config.cameraY !== undefined) ? parseFloat(config.cameraY) : 2;
162
- const cameraZ = (config.cameraZ !== undefined) ? parseFloat(config.cameraZ) : 5;
163
- const cameraXPhone = (config.cameraXPhone !== undefined) ? parseFloat(config.cameraXPhone) : cameraX;
164
- const cameraYPhone = (config.cameraYPhone !== undefined) ? parseFloat(config.cameraYPhone) : cameraY;
165
- const cameraZPhone = (config.cameraZPhone !== undefined) ? parseFloat(config.cameraZPhone) : (cameraZ * 1.5);
166
-
167
- color_bg_hex = (config.canvas_background !== undefined) ? config.canvas_background : "#FFFFFF";
168
- espace_expo_bool = (config.espace_expo_bool !== undefined) ? config.espace_expo_bool : false;
 
 
 
 
 
 
 
 
 
 
 
169
  color_bg = hexToRgbaArray(color_bg_hex);
170
 
171
  chosenCameraX = isMobile ? cameraXPhone : cameraX;
@@ -195,30 +180,50 @@ export async function initializeViewer(config, instanceId) {
195
  canvas.addEventListener("gesturechange", (e) => e.preventDefault());
196
  canvas.addEventListener("gestureend", (e) => e.preventDefault());
197
  canvas.addEventListener("dblclick", (e) => e.preventDefault());
198
- canvas.addEventListener("touchstart", (e) => {
199
- if (e.touches.length > 1) e.preventDefault();
200
- }, { passive: false });
201
- canvas.addEventListener("wheel", (e) => { e.preventDefault(); }, { passive: false });
 
 
 
 
 
 
 
 
 
 
202
 
203
- // --- Clavier : bloquer le scroll uniquement quand la souris est au-dessus ---
204
- const scrollKeys = new Set(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","PageUp","PageDown","Home","End"," ","Space","Spacebar"]);
 
 
 
205
  let isPointerOverCanvas = false;
206
  const focusCanvas = () => canvas.focus({ preventScroll: true });
207
 
208
  const onPointerEnter = () => { isPointerOverCanvas = true; focusCanvas(); };
209
- const onPointerLeave = () => { isPointerOverCanvas = false; if (document.activeElement === canvas) canvas.blur(); };
 
 
 
210
 
211
  canvas.addEventListener("pointerenter", onPointerEnter);
212
  canvas.addEventListener("pointerleave", onPointerLeave);
213
  canvas.addEventListener("mouseenter", onPointerEnter);
214
  canvas.addEventListener("mouseleave", onPointerLeave);
 
215
  canvas.addEventListener("mousedown", focusCanvas);
216
  canvas.addEventListener("touchstart", () => { focusCanvas(); }, { passive: false });
 
217
  canvas.addEventListener("blur", () => { isPointerOverCanvas = false; });
218
 
219
  const onKeyDownCapture = (e) => {
220
  if (!isPointerOverCanvas) return;
221
- if (scrollKeys.has(e.key) || scrollKeys.has(e.code)) e.preventDefault();
 
 
222
  };
223
  window.addEventListener("keydown", onKeyDownCapture, true);
224
 
@@ -242,7 +247,7 @@ export async function initializeViewer(config, instanceId) {
242
  opts.graphicsDevice = device;
243
  opts.mouse = new pc.Mouse(canvas);
244
  opts.touch = new pc.TouchDevice(canvas);
245
- opts.keyboard = new pc.Keyboard(canvas);
246
  opts.componentSystems = [
247
  pc.RenderComponentSystem,
248
  pc.CameraComponentSystem,
@@ -286,7 +291,7 @@ export async function initializeViewer(config, instanceId) {
286
  canvas.removeEventListener("touchstart", focusCanvas);
287
  });
288
 
289
- // Assets (on ne met PAS orbit-camera ici)
290
  const assets = {
291
  sogs: new pc.Asset("gsplat", "gsplat", { url: sogsUrl }),
292
  glb: new pc.Asset("glb", "container", { url: glbUrl }),
@@ -296,13 +301,13 @@ export async function initializeViewer(config, instanceId) {
296
 
297
  const loader = new pc.AssetListLoader(Object.values(assets), app.assets);
298
  loader.load(async () => {
299
- // Enregistrer les scripts orbit pour CETTE app
300
- await registerOrbitScriptsForApp(app);
301
 
302
  app.start();
303
  progressDialog.style.display = "none";
304
 
305
- // Modèle
306
  modelEntity = new pc.Entity("model");
307
  modelEntity.addComponent("gsplat", { asset: assets.sogs });
308
  modelEntity.setLocalPosition(modelX, modelY, modelZ);
@@ -337,7 +342,7 @@ export async function initializeViewer(config, instanceId) {
337
  });
338
  }
339
 
340
- // Caméra + scripts d’input
341
  cameraEntity = new pc.Entity("camera");
342
  cameraEntity.addComponent("camera", {
343
  clearColor: new pc.Color(color_bg),
 
55
  }
56
  }
57
 
58
+ // Charger orbit-camera.js **par application**
 
 
 
 
59
  const ORBIT_URL = "https://mikafil-viewer-sgos.static.hf.space/orbit-camera.js";
60
+ function loadOrbitScriptsForApp(app, instanceId) {
61
+ return new Promise((resolve, reject) => {
62
+ // Si déjà enregistré dans CETTE app, ne rien faire
63
+ try {
64
+ if (app?.scripts?.get && app.scripts.get("orbitCamera")) return resolve();
65
+ } catch (_) {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ const asset = new pc.Asset("orbit-" + instanceId, "script", { url: ORBIT_URL });
68
+ app.assets.add(asset);
69
+ asset.once("load", () => resolve());
70
+ asset.once("error", (e) => {
71
+ console.error("[viewer.js] orbit-camera.js load error:", e);
72
+ reject(e);
73
+ });
74
+ app.assets.load(asset);
75
+ });
76
  }
77
 
78
  let pc;
 
98
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
99
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
100
 
101
+ // Config
102
  sogsUrl = config.sogs_json_url;
103
+ glbUrl =
104
+ config.glb_url !== undefined
105
+ ? config.glb_url
106
+ : "https://huggingface.co/datasets/MikaFil/viewer_gs/resolve/main/ressources/espace_expo/sol_blanc_2.glb";
107
+ presentoirUrl =
108
+ config.presentoir_url !== undefined
109
+ ? config.presentoir_url
110
+ : "https://huggingface.co/datasets/MikaFil/viewer_gs/resolve/main/ressources/espace_expo/sol_blanc_2.glb";
111
  minZoom = parseFloat(config.minZoom || "1");
112
  maxZoom = parseFloat(config.maxZoom || "20");
113
  minAngle = parseFloat(config.minAngle || "-45");
114
  maxAngle = parseFloat(config.maxAngle || "90");
115
+ minAzimuth =
116
+ config.minAzimuth !== undefined ? parseFloat(config.minAzimuth) : -360;
117
+ maxAzimuth =
118
+ config.maxAzimuth !== undefined ? parseFloat(config.maxAzimuth) : 360;
119
  minPivotY = parseFloat(config.minPivotY || "0");
120
+ minY = config.minY !== undefined ? parseFloat(config.minY) : 0;
121
+
122
+ modelX = config.modelX !== undefined ? parseFloat(config.modelX) : 0;
123
+ modelY = config.modelY !== undefined ? parseFloat(config.modelY) : 0;
124
+ modelZ = config.modelZ !== undefined ? parseFloat(config.modelZ) : 0;
125
+ modelScale = config.modelScale !== undefined ? parseFloat(config.modelScale) : 1;
126
+ modelRotationX =
127
+ config.modelRotationX !== undefined ? parseFloat(config.modelRotationX) : 0;
128
+ modelRotationY =
129
+ config.modelRotationY !== undefined ? parseFloat(config.modelRotationY) : 0;
130
+ modelRotationZ =
131
+ config.modelRotationZ !== undefined ? parseFloat(config.modelRotationZ) : 0;
132
+
133
+ presentoirScaleX =
134
+ config.presentoirScaleX !== undefined ? parseFloat(config.presentoirScaleX) : 0;
135
+ presentoirScaleY =
136
+ config.presentoirScaleY !== undefined ? parseFloat(config.presentoirScaleY) : 0;
137
+ presentoirScaleZ =
138
+ config.presentoirScaleZ !== undefined ? parseFloat(config.presentoirScaleZ) : 0;
139
+
140
+ const cameraX = config.cameraX !== undefined ? parseFloat(config.cameraX) : 0;
141
+ const cameraY = config.cameraY !== undefined ? parseFloat(config.cameraY) : 2;
142
+ const cameraZ = config.cameraZ !== undefined ? parseFloat(config.cameraZ) : 5;
143
+ const cameraXPhone =
144
+ config.cameraXPhone !== undefined ? parseFloat(config.cameraXPhone) : cameraX;
145
+ const cameraYPhone =
146
+ config.cameraYPhone !== undefined ? parseFloat(config.cameraYPhone) : cameraY;
147
+ const cameraZPhone =
148
+ config.cameraZPhone !== undefined ? parseFloat(config.cameraZPhone) : cameraZ * 1.5;
149
+
150
+ color_bg_hex =
151
+ config.canvas_background !== undefined ? config.canvas_background : "#FFFFFF";
152
+ espace_expo_bool =
153
+ config.espace_expo_bool !== undefined ? config.espace_expo_bool : false;
154
  color_bg = hexToRgbaArray(color_bg_hex);
155
 
156
  chosenCameraX = isMobile ? cameraXPhone : cameraX;
 
180
  canvas.addEventListener("gesturechange", (e) => e.preventDefault());
181
  canvas.addEventListener("gestureend", (e) => e.preventDefault());
182
  canvas.addEventListener("dblclick", (e) => e.preventDefault());
183
+ canvas.addEventListener(
184
+ "touchstart",
185
+ (e) => {
186
+ if (e.touches.length > 1) e.preventDefault();
187
+ },
188
+ { passive: false }
189
+ );
190
+ canvas.addEventListener(
191
+ "wheel",
192
+ (e) => {
193
+ e.preventDefault();
194
+ },
195
+ { passive: false }
196
+ );
197
 
198
+ // --- Clavier : bloquer le scroll seulement quand le pointeur est au-dessus du canvas ---
199
+ const scrollKeys = new Set([
200
+ "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight",
201
+ "PageUp", "PageDown", "Home", "End", " ", "Space", "Spacebar"
202
+ ]);
203
  let isPointerOverCanvas = false;
204
  const focusCanvas = () => canvas.focus({ preventScroll: true });
205
 
206
  const onPointerEnter = () => { isPointerOverCanvas = true; focusCanvas(); };
207
+ const onPointerLeave = () => {
208
+ isPointerOverCanvas = false;
209
+ if (document.activeElement === canvas) canvas.blur();
210
+ };
211
 
212
  canvas.addEventListener("pointerenter", onPointerEnter);
213
  canvas.addEventListener("pointerleave", onPointerLeave);
214
  canvas.addEventListener("mouseenter", onPointerEnter);
215
  canvas.addEventListener("mouseleave", onPointerLeave);
216
+
217
  canvas.addEventListener("mousedown", focusCanvas);
218
  canvas.addEventListener("touchstart", () => { focusCanvas(); }, { passive: false });
219
+
220
  canvas.addEventListener("blur", () => { isPointerOverCanvas = false; });
221
 
222
  const onKeyDownCapture = (e) => {
223
  if (!isPointerOverCanvas) return;
224
+ if (scrollKeys.has(e.key) || scrollKeys.has(e.code)) {
225
+ e.preventDefault();
226
+ }
227
  };
228
  window.addEventListener("keydown", onKeyDownCapture, true);
229
 
 
247
  opts.graphicsDevice = device;
248
  opts.mouse = new pc.Mouse(canvas);
249
  opts.touch = new pc.TouchDevice(canvas);
250
+ opts.keyboard = new pc.Keyboard(canvas); // clavier par canvas
251
  opts.componentSystems = [
252
  pc.RenderComponentSystem,
253
  pc.CameraComponentSystem,
 
291
  canvas.removeEventListener("touchstart", focusCanvas);
292
  });
293
 
294
+ // Assets (sans orbit-camera ici)
295
  const assets = {
296
  sogs: new pc.Asset("gsplat", "gsplat", { url: sogsUrl }),
297
  glb: new pc.Asset("glb", "container", { url: glbUrl }),
 
301
 
302
  const loader = new pc.AssetListLoader(Object.values(assets), app.assets);
303
  loader.load(async () => {
304
+ // Charger et enregistrer orbit-camera.js pour CETTE app
305
+ await loadOrbitScriptsForApp(app, instanceId);
306
 
307
  app.start();
308
  progressDialog.style.display = "none";
309
 
310
+ // Entités
311
  modelEntity = new pc.Entity("model");
312
  modelEntity.addComponent("gsplat", { asset: assets.sogs });
313
  modelEntity.setLocalPosition(modelX, modelY, modelZ);
 
342
  });
343
  }
344
 
345
+ // Caméra + scripts orbit
346
  cameraEntity = new pc.Entity("camera");
347
  cameraEntity.addComponent("camera", {
348
  clearColor: new pc.Color(color_bg),