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

Update viewer_ar_ios.js

Browse files
Files changed (1) hide show
  1. viewer_ar_ios.js +39 -80
viewer_ar_ios.js CHANGED
@@ -4,12 +4,12 @@
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
- - Bouton "Lancer l'AR" (Android & iOS)
8
  */
9
 
10
  (function () {
11
  // ============ Utils: script tag / config / platform ============
12
  function getCurrentScript() {
 
13
  return document.currentScript || (function () {
14
  var scripts = document.getElementsByTagName('script');
15
  return scripts[scripts.length - 1] || null;
@@ -118,12 +118,9 @@
118
  ".ar-ui input[type=\"range\"].rotY{position:absolute;opacity:0;pointer-events:none;width:0;height:0}",
119
  ".ar-ui .val{font-size:12px;opacity:.95}",
120
 
121
- /* Bouton Lancer l'AR (visible Android & iOS) */
122
- "#ar-launch-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:72px;z-index:10003;padding:12px 16px;border-radius:12px;border:none;background:#111;color:#fff;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;box-shadow:0 6px 18px rgba(0,0,0,.25);cursor:pointer;pointer-events:auto}",
123
- "#ar-launch-btn:active{transform:translateX(-50%) scale(0.98)}",
124
-
125
- /* Anchor QuickLook caché (déclenché par le bouton sur iOS) */
126
- "#ios-quicklook-anchor{position:absolute;left:-9999px;top:-9999px;height:1px;width:1px;overflow:hidden}"
127
  ].join("\n");
128
  var styleTag = document.createElement("style");
129
  styleTag.textContent = css;
@@ -164,20 +161,43 @@
164
  }
165
  }
166
 
167
- // Canvas monté dans un conteneur (Squarespace-friendly)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  function ensureCanvas() {
169
  var scriptEl = getCurrentScript();
170
  var mountSel = scriptEl && scriptEl.getAttribute('data-mount');
171
  var desiredHeight = (scriptEl && scriptEl.getAttribute('data-height')) || '70vh';
172
 
 
173
  var mountEl = null;
174
  if (mountSel) mountEl = document.querySelector(mountSel);
175
  if (!mountEl) {
 
176
  mountEl = document.createElement('div');
177
  mountEl.id = 'ar-mount-fallback';
178
  document.body.insertBefore(mountEl, document.body.firstChild);
179
  }
180
 
 
181
  var mountStyle = mountEl.style;
182
  if (!mountStyle.position) mountStyle.position = 'relative';
183
  mountStyle.width = mountStyle.width || '100%';
@@ -185,6 +205,7 @@
185
  mountStyle.touchAction = mountStyle.touchAction || 'manipulation';
186
  mountStyle.webkitTapHighlightColor = 'transparent';
187
 
 
188
  var canvas = mountEl.querySelector('#application-canvas');
189
  if (!canvas) {
190
  canvas = document.createElement('canvas');
@@ -192,6 +213,7 @@
192
  mountEl.appendChild(canvas);
193
  }
194
 
 
195
  var cs = canvas.style;
196
  cs.position = 'absolute';
197
  cs.left = '0';
@@ -200,6 +222,7 @@
200
  cs.height = '100%';
201
  cs.display = 'block';
202
 
 
203
  try {
204
  mountEl.scrollIntoView({ behavior: 'instant', block: 'start' });
205
  } catch (_) {}
@@ -224,36 +247,6 @@
224
  return p;
225
  }
226
 
227
- // Bouton "Lancer l'AR" + (iOS) ancre rel=ar cachée
228
- function ensureLaunchControls(USDZ_URL) {
229
- // bouton visible (toujours présent)
230
- var btn = document.getElementById('ar-launch-btn');
231
- if (!btn) {
232
- btn = document.createElement('button');
233
- btn.id = 'ar-launch-btn';
234
- btn.type = 'button';
235
- btn.textContent = 'Lancer l’AR';
236
- // pointer-events auto par défaut ; stopper la propagation pour éviter le drag de la scène
237
- btn.addEventListener('pointerdown', function (e) { e.stopPropagation(); }, { passive: true });
238
- btn.addEventListener('click', function (e) { e.stopPropagation(); }, false);
239
- document.body.appendChild(btn);
240
- }
241
-
242
- var anchor = document.getElementById('ios-quicklook-anchor');
243
- if (isIOS()) {
244
- if (!anchor) {
245
- anchor = document.createElement('a');
246
- anchor.id = 'ios-quicklook-anchor';
247
- anchor.setAttribute('rel', 'ar');
248
- document.body.appendChild(anchor);
249
- }
250
- if (USDZ_URL) {
251
- anchor.setAttribute('href', buildQuickLookHref(USDZ_URL));
252
- }
253
- }
254
- return { btn: btn, anchor: anchor || null };
255
- }
256
-
257
  // ============ Boot : charge config, route iOS vs Android/Desktop ============
258
  (async function () {
259
  var cfgUrl = findConfigUrl();
@@ -265,56 +258,28 @@
265
  cfg.usdz_url :
266
  null;
267
 
268
- // Toujours créer le bouton (même iOS)
269
- var { btn: launchBtn, anchor: iosAnchor } = ensureLaunchControls(USDZ_URL);
270
-
271
  if (isIOS()) {
272
  if (USDZ_URL) {
273
- // Texte explicite + bouton qui déclenche Quick Look
274
- message("iOS détecté : appuyez sur « Lancer l’AR » pour ouvrir Quick Look.");
275
- launchBtn.onclick = function (e) {
276
- e.preventDefault();
277
- e.stopPropagation();
278
- // délencher l’ancre rel=ar (meilleure compatibilité iOS)
279
- if (iosAnchor && iosAnchor.href) {
280
- iosAnchor.click();
281
- }
282
- };
283
  } else {
284
  message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
285
- launchBtn.disabled = true;
286
- launchBtn.style.opacity = '0.5';
287
  }
288
- // (Optionnel) tu peux ajouter un viewer 3D non-AR ici si besoin.
289
  return;
290
  }
291
 
292
- // Android / Desktop : charger PlayCanvas et initialiser l’app
293
  try {
294
  await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
295
  } catch (e) {
296
  console.error("Chargement PlayCanvas échoué ->", e);
297
  message("Impossible de charger PlayCanvas (réseau/CDN). Réessaie plus tard.");
298
- launchBtn.disabled = true;
299
- launchBtn.style.opacity = '0.5';
300
  return;
301
  }
302
-
303
- // init de l’app WebXR, puis bouton déclencheur
304
- var activateARRef = { fn: null }; // on branche le bouton une fois activateAR défini
305
- initARApp(GLB_URL, activateARRef);
306
-
307
- launchBtn.onclick = function (e) {
308
- e.preventDefault();
309
- e.stopPropagation();
310
- if (typeof activateARRef.fn === 'function') {
311
- activateARRef.fn();
312
- }
313
- };
314
  })();
315
 
316
  // ============ App Android/Desktop (WebXR) ============
317
- function initARApp(GLB_URL, activateARRef) {
318
  var pc = window.pc;
319
  var canvas = ensureCanvas();
320
  var ui = ensureSliderUI();
@@ -430,7 +395,7 @@
430
  return e;
431
  }
432
 
433
- // Euler de base
434
  var baseEulerX = 0, baseEulerZ = 0;
435
 
436
  // Rotation via slider (0..360, 360 en haut / 0 en bas)
@@ -483,7 +448,7 @@
483
  baseEulerX = initE.x; baseEulerZ = initE.z;
484
 
485
  modelLoaded = true;
486
- message("Modèle chargé. Appuyez sur « Lancer l’AR » pour démarrer.");
487
  });
488
 
489
  if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
@@ -537,7 +502,7 @@
537
  document.addEventListener("pointerup", endDrag, { capture: true, passive: false });
538
  document.addEventListener("pointercancel", endDrag, { capture: true, passive: false });
539
 
540
- // --- Démarrage AR (Android/Desktop) — exposé via activateARRef.fn et bouton
541
  function activateAR() {
542
  if (!app.xr.isAvailable(pc.XRTYPE_AR)) { message("AR immersive indisponible sur cet appareil."); return; }
543
  if (!app.xr.domOverlay) app.xr.domOverlay = {};
@@ -553,12 +518,6 @@
553
  }
554
  });
555
  }
556
- // on branche la référence pour le bouton "Lancer l'AR"
557
- if (activateARRef && typeof activateARRef === 'object') {
558
- activateARRef.fn = activateAR;
559
- }
560
-
561
- // On garde la possibilité de démarrer par tap écran si tu veux (désactivable)
562
  app.mouse.on("mousedown", function () { if (!app.xr.active && !uiInteracting) activateAR(); });
563
  if (app.touch) {
564
  app.touch.on("touchend", function (evt) {
@@ -681,7 +640,7 @@
681
  app.xr.on("available:" + pc.XRTYPE_AR, function (a) {
682
  if (!a) message("AR immersive indisponible.");
683
  else if (!app.xr.hitTest.supported) message("AR Hit Test non supporté.");
684
- else message(modelLoaded ? "Touchez l’écran ou « Lancer l’AR »." : "Chargement du modèle…");
685
  });
686
 
687
  if (!app.xr.isAvailable(pc.XRTYPE_AR)) message("AR immersive indisponible.");
 
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;
 
118
  ".ar-ui input[type=\"range\"].rotY{position:absolute;opacity:0;pointer-events:none;width:0;height:0}",
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");
126
  styleTag.textContent = css;
 
161
  }
162
  }
163
 
164
+ function ensureQuickLookButton(USDZ_URL) {
165
+ var btn = document.getElementById("ios-quicklook-btn");
166
+ if (btn) return btn;
167
+
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";
175
+ img.src =
176
+ "data:image/svg+xml;charset=utf-8," +
177
+ encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="160" height="44"><rect rx="8" ry="8" width="160" height="44" fill="black"/><text x="80" y="28" font-size="14" text-anchor="middle" fill="white" font-family="system-ui, -apple-system, Segoe UI, Roboto">Voir en AR</text></svg>');
178
+
179
+ anchor.appendChild(img);
180
+ document.body.appendChild(anchor);
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%';
 
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');
 
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';
 
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 (_) {}
 
247
  return p;
248
  }
249
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  // ============ Boot : charge config, route iOS vs Android/Desktop ============
251
  (async function () {
252
  var cfgUrl = findConfigUrl();
 
258
  cfg.usdz_url :
259
  null;
260
 
 
 
 
261
  if (isIOS()) {
262
  if (USDZ_URL) {
263
+ ensureQuickLookButton(USDZ_URL);
264
+ message("iOS détecté : utilisez le bouton « Voir en AR » (AR Quick Look).");
 
 
 
 
 
 
 
 
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) {
274
  console.error("Chargement PlayCanvas échoué ->", e);
275
  message("Impossible de charger PlayCanvas (réseau/CDN). Réessaie plus tard.");
 
 
276
  return;
277
  }
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();
285
  var ui = ensureSliderUI();
 
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)
 
448
  baseEulerX = initE.x; baseEulerZ = initE.z;
449
 
450
  modelLoaded = true;
451
+ message("Modèle chargé. Touchez l’écran pour démarrer l’AR.");
452
  });
453
 
454
  if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
 
502
  document.addEventListener("pointerup", endDrag, { capture: true, passive: false });
503
  document.addEventListener("pointercancel", endDrag, { capture: true, passive: false });
504
 
505
+ // --- Démarrage AR (Android/Desktop)
506
  function activateAR() {
507
  if (!app.xr.isAvailable(pc.XRTYPE_AR)) { message("AR immersive indisponible sur cet appareil."); return; }
508
  if (!app.xr.domOverlay) app.xr.domOverlay = {};
 
518
  }
519
  });
520
  }
 
 
 
 
 
 
521
  app.mouse.on("mousedown", function () { if (!app.xr.active && !uiInteracting) activateAR(); });
522
  if (app.touch) {
523
  app.touch.on("touchend", function (evt) {
 
640
  app.xr.on("available:" + pc.XRTYPE_AR, function (a) {
641
  if (!a) message("AR immersive indisponible.");
642
  else if (!app.xr.hitTest.supported) message("AR Hit Test non supporté.");
643
+ else message(modelLoaded ? "Touchez l’écran pour démarrer l’AR." : "Chargement du modèle…");
644
  });
645
 
646
  if (!app.xr.isAvailable(pc.XRTYPE_AR)) message("AR immersive indisponible.");