MikaFil commited on
Commit
d1ac7d9
·
verified ·
1 Parent(s): eff4893

Update viewer_ar_ios.js

Browse files
Files changed (1) hide show
  1. viewer_ar_ios.js +42 -75
viewer_ar_ios.js CHANGED
@@ -1,23 +1,23 @@
1
- /* viewer_ar_ios.js — AR PlayCanvas + GLB/USDZ via config.json
2
  - Lit config.json (data-config) => { "glb_url": "...", "usdz_url": "..." }
3
- - iOS : AR Quick Look (USDZ) avec #allowsContentScaling=0 (pas de zoom)
4
  - Android/Desktop : WebXR AR (horizontaux uniquement) + slider yaw + blob shadow
5
  - Éclairage PBR par défaut (sans WebXR light estimation)
6
- - Monté dans un conteneur choisi (data-mount="#ar-mount") pour Squarespace
7
  */
8
 
9
  (function () {
10
- // ============ Utils: script tag / config / platform ============
11
- function getCurrentScript() {
12
- // robuste même si currentScript n'est pas dispo
13
- return document.currentScript || (function () {
14
- var scripts = document.getElementsByTagName('script');
15
- return scripts[scripts.length - 1] || null;
16
- })();
17
- }
18
-
19
  function findConfigUrl() {
20
- var el = getCurrentScript();
 
 
 
 
 
 
 
 
 
21
  if (!el) return null;
22
  var url = el.getAttribute('data-config');
23
  return url || null;
@@ -46,7 +46,7 @@
46
  }
47
  }
48
 
49
- // ============ PlayCanvas version fixée (Android/Desktop) ============
50
  var PC_VERSION = "2.11.7";
51
  var PC_URLS = {
52
  esm: ["https://cdn.jsdelivr.net/npm/playcanvas@" + PC_VERSION + "/build/playcanvas.min.mjs"],
@@ -105,10 +105,10 @@
105
  }
106
  }
107
 
108
- // ============ UI / Overlay commun ============
109
  var css = [
110
- ".pc-ar-msg{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10002;padding:10px 14px;background:rgba(0,0,0,.65);color:#fff;border-radius:12px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.3;text-align:center;max-width:min(90vw,640px);box-shadow:0 6px 20px rgba(0,0,0,.25);backdrop-filter:blur(4px);pointer-events:none}",
111
- "#xr-overlay-root{position:fixed;inset:0;z-index:10001;pointer-events:none}",
112
 
113
  ".ar-ui{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:rgba(0,0,0,0.55);color:#fff;padding:12px 10px;border-radius:16px;width:56px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:8px;box-shadow:0 6px 18px rgba(0,0,0,.25);backdrop-filter:blur(6px);touch-action:none}",
114
  ".ar-ui .label{font-size:12px;text-align:center;opacity:.95}",
@@ -119,7 +119,7 @@
119
  ".ar-ui .val{font-size:12px;opacity:.95}",
120
 
121
  /* iOS Quick Look button */
122
- "#ios-quicklook-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10003;display:inline-block;pointer-events:auto}",
123
  "#ios-quicklook-btn img{display:block;height:44px;width:auto}"
124
  ].join("\n");
125
  var styleTag = document.createElement("style");
@@ -147,7 +147,7 @@
147
  el.textContent = msg;
148
  }
149
 
150
- // iOS Quick Look URL (empêche le pinch to scale)
151
  function buildQuickLookHref(usdzUrl) {
152
  try {
153
  var u = new URL(usdzUrl, window.location.href);
@@ -168,7 +168,7 @@
168
  var anchor = document.createElement("a");
169
  anchor.id = "ios-quicklook-btn";
170
  anchor.setAttribute("rel", "ar");
171
- anchor.setAttribute("href", buildQuickLookHref(USDZ_URL));
172
 
173
  var img = document.createElement("img");
174
  img.alt = "Voir en AR";
@@ -181,53 +181,16 @@
181
  return anchor;
182
  }
183
 
184
- // ============ Canvas monté dans un conteneur contrôlé (Squarespace) ============
185
  function ensureCanvas() {
186
- var scriptEl = getCurrentScript();
187
- var mountSel = scriptEl && scriptEl.getAttribute('data-mount');
188
- var desiredHeight = (scriptEl && scriptEl.getAttribute('data-height')) || '70vh';
189
-
190
- // Trouve le conteneur cible
191
- var mountEl = null;
192
- if (mountSel) mountEl = document.querySelector(mountSel);
193
- if (!mountEl) {
194
- // fallback : tout en haut du body (pour éviter "sous le footer")
195
- mountEl = document.createElement('div');
196
- mountEl.id = 'ar-mount-fallback';
197
- document.body.insertBefore(mountEl, document.body.firstChild);
198
  }
199
-
200
- // Style du conteneur
201
- var mountStyle = mountEl.style;
202
- if (!mountStyle.position) mountStyle.position = 'relative';
203
- mountStyle.width = mountStyle.width || '100%';
204
- mountStyle.minHeight = mountStyle.minHeight || desiredHeight;
205
- mountStyle.touchAction = mountStyle.touchAction || 'manipulation';
206
- mountStyle.webkitTapHighlightColor = 'transparent';
207
-
208
- // Réutilise ou crée le canvas
209
- var canvas = mountEl.querySelector('#application-canvas');
210
- if (!canvas) {
211
- canvas = document.createElement('canvas');
212
- canvas.id = 'application-canvas';
213
- mountEl.appendChild(canvas);
214
- }
215
-
216
- // Le canvas remplit le conteneur
217
- var cs = canvas.style;
218
- cs.position = 'absolute';
219
- cs.left = '0';
220
- cs.top = '0';
221
- cs.width = '100%';
222
- cs.height = '100%';
223
- cs.display = 'block';
224
-
225
- // Optionnel : ramener le viewport sur le viewer
226
- try {
227
- mountEl.scrollIntoView({ behavior: 'instant', block: 'start' });
228
- } catch (_) {}
229
-
230
- return canvas;
231
  }
232
 
233
  function ensureSliderUI() {
@@ -247,8 +210,9 @@
247
  return p;
248
  }
249
 
250
- // ============ Boot : charge config, route iOS vs Android/Desktop ============
251
  (async function () {
 
252
  var cfgUrl = findConfigUrl();
253
  var cfg = await loadConfigJson(cfgUrl);
254
  var GLB_URL = (cfg && typeof cfg.glb_url === "string" && cfg.glb_url) ?
@@ -258,6 +222,7 @@
258
  cfg.usdz_url :
259
  null;
260
 
 
261
  if (isIOS()) {
262
  if (USDZ_URL) {
263
  ensureQuickLookButton(USDZ_URL);
@@ -265,9 +230,11 @@
265
  } else {
266
  message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
267
  }
 
268
  return;
269
  }
270
 
 
271
  try {
272
  await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
273
  } catch (e) {
@@ -278,7 +245,7 @@
278
  initARApp(GLB_URL);
279
  })();
280
 
281
- // ============ App Android/Desktop (WebXR) ============
282
  function initARApp(GLB_URL) {
283
  var pc = window.pc;
284
  var canvas = ensureCanvas();
@@ -299,13 +266,12 @@
299
  app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
300
  app.setCanvasResolution(pc.RESOLUTION_AUTO);
301
  app.graphicsDevice.maxPixelRatio = window.devicePixelRatio || 1;
302
-
303
  var onResize = function () { app.resizeCanvas(); };
304
  window.addEventListener("resize", onResize);
305
  app.on("destroy", function () { window.removeEventListener("resize", onResize); });
306
  app.start();
307
 
308
- // Rendu / PBR defaults
309
  app.scene.gammaCorrection = pc.GAMMA_SRGB;
310
  app.scene.toneMapping = pc.TONEMAP_ACES;
311
  app.scene.exposure = 1;
@@ -395,10 +361,10 @@
395
  return e;
396
  }
397
 
398
- // Euler de base (évite inversions)
399
  var baseEulerX = 0, baseEulerZ = 0;
400
 
401
- // Rotation via slider (0..360, 360 en haut / 0 en bas)
402
  var rotationYDeg = 0;
403
  function clamp360(d) { return Math.max(0, Math.min(360, d)); }
404
 
@@ -421,14 +387,14 @@
421
  if (rotLikePlane) blob.setRotation(rotLikePlane);
422
  }
423
 
424
- // Chargement GLB (depuis config.json)
425
  app.assets.loadFromUrl(GLB_URL, "container", function (err, asset) {
426
  if (err) { console.error(err); message("Échec du chargement du modèle GLB."); return; }
427
  var instance = asset.resource.instantiateRenderEntity({ castShadows: true, receiveShadows: false });
428
  modelRoot.addChild(instance);
429
  modelRoot.setLocalScale(1, 1, 1);
430
 
431
- // Fix matériaux simples
432
  var renders = instance.findComponents('render');
433
  for (var ri = 0; ri < renders.length; ri++) {
434
  var r = renders[ri];
@@ -453,7 +419,7 @@
453
 
454
  if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
455
 
456
- // Slider fiable (pointer events en capture)
457
  var uiInteracting = false;
458
  var draggingWrap = false;
459
  var activePointerId = null;
@@ -528,7 +494,7 @@
528
  }
529
  app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
530
 
531
- // Hit-test HORIZONTAL uniquement
532
  var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
533
  function isHorizontalUpFacing(rot, minDot) {
534
  minDot = (typeof minDot === "number") ? minDot : 0.75;
@@ -648,3 +614,4 @@
648
  else message("Chargement du modèle…");
649
  }
650
  })();
 
 
1
+ /* script_ar.js — AR PlayCanvas + GLB/USDZ via config.json
2
  - Lit config.json (data-config) => { "glb_url": "...", "usdz_url": "..." }
3
+ - iOS : fallback AR Quick Look (USDZ) avec #allowsContentScaling=0 (pas de zoom)
4
  - Android/Desktop : WebXR AR (horizontaux uniquement) + slider yaw + blob shadow
5
  - Éclairage PBR par défaut (sans WebXR light estimation)
 
6
  */
7
 
8
  (function () {
9
+ // ===== Utils: config + platform =====
 
 
 
 
 
 
 
 
10
  function findConfigUrl() {
11
+ var el = document.currentScript || null;
12
+ if (!el) {
13
+ var scripts = document.getElementsByTagName('script');
14
+ for (var i = scripts.length - 1; i >= 0; i--) {
15
+ if (scripts[i].getAttribute && scripts[i].getAttribute('data-config')) {
16
+ el = scripts[i];
17
+ break;
18
+ }
19
+ }
20
+ }
21
  if (!el) return null;
22
  var url = el.getAttribute('data-config');
23
  return url || null;
 
46
  }
47
  }
48
 
49
+ // ===== PlayCanvas version fixée (Android/Desktop) =====
50
  var PC_VERSION = "2.11.7";
51
  var PC_URLS = {
52
  esm: ["https://cdn.jsdelivr.net/npm/playcanvas@" + PC_VERSION + "/build/playcanvas.min.mjs"],
 
105
  }
106
  }
107
 
108
+ // ===== UI / Overlay commun =====
109
  var css = [
110
+ ".pc-ar-msg{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:2;padding:10px 14px;background:rgba(0,0,0,.65);color:#fff;border-radius:12px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.3;text-align:center;max-width:min(90vw,640px);box-shadow:0 6px 20px rgba(0,0,0,.25);backdrop-filter:blur(4px);pointer-events:none}",
111
+ "#xr-overlay-root{position:fixed;inset:0;z-index:9999;pointer-events:none}",
112
 
113
  ".ar-ui{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:rgba(0,0,0,0.55);color:#fff;padding:12px 10px;border-radius:16px;width:56px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:8px;box-shadow:0 6px 18px rgba(0,0,0,.25);backdrop-filter:blur(6px);touch-action:none}",
114
  ".ar-ui .label{font-size:12px;text-align:center;opacity:.95}",
 
119
  ".ar-ui .val{font-size:12px;opacity:.95}",
120
 
121
  /* iOS Quick Look button */
122
+ "#ios-quicklook-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10001;display:inline-block;pointer-events:auto}",
123
  "#ios-quicklook-btn img{display:block;height:44px;width:auto}"
124
  ].join("\n");
125
  var styleTag = document.createElement("style");
 
147
  el.textContent = msg;
148
  }
149
 
150
+ // Construit l'URL Quick Look avec allowsContentScaling=0
151
  function buildQuickLookHref(usdzUrl) {
152
  try {
153
  var u = new URL(usdzUrl, window.location.href);
 
168
  var anchor = document.createElement("a");
169
  anchor.id = "ios-quicklook-btn";
170
  anchor.setAttribute("rel", "ar");
171
+ anchor.setAttribute("href", buildQuickLookHref(USDZ_URL)); // << blocage du scaling
172
 
173
  var img = document.createElement("img");
174
  img.alt = "Voir en AR";
 
181
  return anchor;
182
  }
183
 
 
184
  function ensureCanvas() {
185
+ var c = document.getElementById("application-canvas");
186
+ if (!c) {
187
+ c = document.createElement("canvas");
188
+ c.id = "application-canvas";
189
+ c.style.width = "100%";
190
+ c.style.height = "100%";
191
+ document.body.appendChild(c);
 
 
 
 
 
192
  }
193
+ return c;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  }
195
 
196
  function ensureSliderUI() {
 
210
  return p;
211
  }
212
 
213
+ // ===== Boot : charge config, route iOS vs Android/Desktop =====
214
  (async function () {
215
+ // 1) Lire config.json
216
  var cfgUrl = findConfigUrl();
217
  var cfg = await loadConfigJson(cfgUrl);
218
  var GLB_URL = (cfg && typeof cfg.glb_url === "string" && cfg.glb_url) ?
 
222
  cfg.usdz_url :
223
  null;
224
 
225
+ // 2) iOS → AR Quick Look (fallback)
226
  if (isIOS()) {
227
  if (USDZ_URL) {
228
  ensureQuickLookButton(USDZ_URL);
 
230
  } else {
231
  message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
232
  }
233
+ // Option : lancer un viewer 3D non-AR ici si désiré.
234
  return;
235
  }
236
 
237
+ // 3) Android/Desktop → charger PlayCanvas et lancer l'app WebXR
238
  try {
239
  await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
240
  } catch (e) {
 
245
  initARApp(GLB_URL);
246
  })();
247
 
248
+ // ===== App Android/Desktop (WebXR) =====
249
  function initARApp(GLB_URL) {
250
  var pc = window.pc;
251
  var canvas = ensureCanvas();
 
266
  app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
267
  app.setCanvasResolution(pc.RESOLUTION_AUTO);
268
  app.graphicsDevice.maxPixelRatio = window.devicePixelRatio || 1;
 
269
  var onResize = function () { app.resizeCanvas(); };
270
  window.addEventListener("resize", onResize);
271
  app.on("destroy", function () { window.removeEventListener("resize", onResize); });
272
  app.start();
273
 
274
+ // ===== Rendu / PBR defaults =====
275
  app.scene.gammaCorrection = pc.GAMMA_SRGB;
276
  app.scene.toneMapping = pc.TONEMAP_ACES;
277
  app.scene.exposure = 1;
 
361
  return e;
362
  }
363
 
364
+ // Euler base
365
  var baseEulerX = 0, baseEulerZ = 0;
366
 
367
+ // Rotation via slider
368
  var rotationYDeg = 0;
369
  function clamp360(d) { return Math.max(0, Math.min(360, d)); }
370
 
 
387
  if (rotLikePlane) blob.setRotation(rotLikePlane);
388
  }
389
 
390
+ // Chargement GLB (config.json)
391
  app.assets.loadFromUrl(GLB_URL, "container", function (err, asset) {
392
  if (err) { console.error(err); message("Échec du chargement du modèle GLB."); return; }
393
  var instance = asset.resource.instantiateRenderEntity({ castShadows: true, receiveShadows: false });
394
  modelRoot.addChild(instance);
395
  modelRoot.setLocalScale(1, 1, 1);
396
 
397
+ // Fix matériaux
398
  var renders = instance.findComponents('render');
399
  for (var ri = 0; ri < renders.length; ri++) {
400
  var r = renders[ri];
 
419
 
420
  if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
421
 
422
+ // ===== Slider fiable : Pointer Events en CAPTURE =====
423
  var uiInteracting = false;
424
  var draggingWrap = false;
425
  var activePointerId = null;
 
494
  }
495
  app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
496
 
497
+ // ====== Hit-test HORIZONTAL uniquement ======
498
  var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
499
  function isHorizontalUpFacing(rot, minDot) {
500
  minDot = (typeof minDot === "number") ? minDot : 0.75;
 
614
  else message("Chargement du modèle…");
615
  }
616
  })();
617
+