MikaFil commited on
Commit
1a0748c
·
verified ·
1 Parent(s): e6632ca

Update viewer_ar_ios.js

Browse files
Files changed (1) hide show
  1. viewer_ar_ios.js +75 -41
viewer_ar_ios.js CHANGED
@@ -1,23 +1,23 @@
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,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: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,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: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,7 +147,7 @@
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,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)); // << blocage du scaling
172
 
173
  var img = document.createElement("img");
174
  img.alt = "Voir en AR";
@@ -181,16 +181,53 @@
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,9 +247,8 @@
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,7 +258,6 @@
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,11 +265,9 @@
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,7 +278,7 @@
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,12 +299,13 @@
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,10 +395,10 @@
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,14 +421,14 @@
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,7 +453,7 @@
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,7 +528,7 @@
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;
 
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
  }
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: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
  ".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
  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
  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
  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
  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
  cfg.usdz_url :
259
  null;
260
 
 
261
  if (isIOS()) {
262
  if (USDZ_URL) {
263
  ensureQuickLookButton(USDZ_URL);
 
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
  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
  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
  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
  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
 
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
  }
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;