Update viewer_ar_ios.js
Browse files- viewer_ar_ios.js +67 -45
viewer_ar_ios.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
| 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 (plans 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 |
*/
|
|
@@ -106,28 +107,31 @@
|
|
| 106 |
}
|
| 107 |
|
| 108 |
// ============ UI / Overlay commun ============
|
| 109 |
-
// Style minimal intégré : toasts
|
| 110 |
-
// (Si tu utilises un CSS externe, tu peux déplacer ces règles dans ce fichier.)
|
| 111 |
var css = [
|
| 112 |
/* Toast (bas) */
|
| 113 |
".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}",
|
| 114 |
/* Variante centrée + plus grande pour le message “Modèle chargé …” */
|
| 115 |
".pc-ar-msg.pc-ar-msg--centerBig{top:50%;bottom:auto;transform:translate(-50%,-50%);font-size:18px;padding:14px 18px;max-width:min(90vw,720px)}",
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
"#xr-overlay-root{position:fixed;inset:0;z-index:10001;pointer-events:none}",
|
| 118 |
|
| 119 |
-
/* --- NE PAS MODIFIER : panneau Rotation --- */
|
| 120 |
".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}",
|
| 121 |
".ar-ui .label{font-size:12px;text-align:center;opacity:.95}",
|
| 122 |
".rotY-wrap{position:relative;width:48px;height:200px;display:flex;align-items:center;justify-content:center;touch-action:none;overflow:visible;pointer-events:auto}",
|
| 123 |
".rotY-rail{position:absolute;left:50%;transform:translateX(-50%);width:4px;height:100%;background:rgba(255,255,255,.35);border-radius:2px;pointer-events:none}",
|
| 124 |
".rotY-knob{position:absolute;left:50%;width:22px;height:22px;border-radius:50%;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,.35);transform:translate(-50%,-50%);top:50%;will-change:top;touch-action:none;pointer-events:none}",
|
| 125 |
".ar-ui input[type=\"range\"].rotY{position:absolute;opacity:0;pointer-events:none;width:0;height:0}",
|
| 126 |
-
".ar-ui .val{font-size:12px;opacity:.95}"
|
| 127 |
-
|
| 128 |
-
/* iOS Quick Look button */
|
| 129 |
-
"#ios-quicklook-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10003;display:inline-block;pointer-events:auto}",
|
| 130 |
-
"#ios-quicklook-btn img{display:block;height:44px;width:auto}"
|
| 131 |
].join("\n");
|
| 132 |
var styleTag = document.createElement("style");
|
| 133 |
styleTag.textContent = css;
|
|
@@ -179,24 +183,39 @@
|
|
| 179 |
}
|
| 180 |
}
|
| 181 |
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
|
|
|
| 196 |
|
| 197 |
-
anchor
|
| 198 |
-
document.body.appendChild(anchor);
|
| 199 |
-
return anchor;
|
| 200 |
}
|
| 201 |
|
| 202 |
// ============ Canvas monté dans un conteneur contrôlé (Squarespace) ============
|
|
@@ -248,7 +267,7 @@
|
|
| 248 |
return canvas;
|
| 249 |
}
|
| 250 |
|
| 251 |
-
// ---------- Panneau “Rotation” (inchangé) ----------
|
| 252 |
function ensureSliderUI() {
|
| 253 |
var p = overlayRoot.querySelector(".ar-ui");
|
| 254 |
if (p) return p;
|
|
@@ -266,27 +285,31 @@
|
|
| 266 |
return p;
|
| 267 |
}
|
| 268 |
|
| 269 |
-
// ============ Boot : charge config,
|
| 270 |
(async function () {
|
| 271 |
var cfgUrl = findConfigUrl();
|
| 272 |
var cfg = await loadConfigJson(cfgUrl);
|
| 273 |
-
var GLB_URL = (cfg && typeof cfg.glb_url === "string" && cfg.glb_url)
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
var USDZ_URL = (cfg && typeof cfg.usdz_url === "string" && cfg.usdz_url)
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
|
|
|
| 280 |
if (isIOS()) {
|
| 281 |
if (USDZ_URL) {
|
| 282 |
-
|
| 283 |
-
|
|
|
|
|
|
|
| 284 |
} else {
|
| 285 |
messageToast("iOS détecté, mais aucun 'usdz_url' dans config.json.");
|
| 286 |
}
|
| 287 |
return;
|
| 288 |
}
|
| 289 |
|
|
|
|
| 290 |
try {
|
| 291 |
await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
|
| 292 |
} catch (e) {
|
|
@@ -303,11 +326,11 @@
|
|
| 303 |
|
| 304 |
// Canvas + UI
|
| 305 |
var canvas = ensureCanvas();
|
| 306 |
-
var sliderPanel = ensureSliderUI();
|
| 307 |
-
var rotTrack = sliderPanel.querySelector("#ar-rotY-wrap");
|
| 308 |
-
var rotThumb = sliderPanel.querySelector("#ar-rotY-knob");
|
| 309 |
-
var rotRangeInput = sliderPanel.querySelector("#ar-rotY");
|
| 310 |
-
var rotValueLabel = sliderPanel.querySelector("#ar-rotY-val");
|
| 311 |
|
| 312 |
window.focus();
|
| 313 |
|
|
@@ -473,8 +496,7 @@
|
|
| 473 |
baseEulerX = initE.x; baseEulerZ = initE.z;
|
| 474 |
|
| 475 |
modelLoaded = true;
|
| 476 |
-
|
| 477 |
-
// >>> Message centré & un peu plus grand pour l’invite initiale
|
| 478 |
messageCenterBig("Modèle chargé. Touchez l’écran pour démarrer l’AR.");
|
| 479 |
});
|
| 480 |
|
|
@@ -529,7 +551,7 @@
|
|
| 529 |
document.addEventListener("pointerup", endDrag, { capture: true, passive: false });
|
| 530 |
document.addEventListener("pointercancel", endDrag, { capture: true, passive: false });
|
| 531 |
|
| 532 |
-
// --- Démarrage AR (
|
| 533 |
function activateAR() {
|
| 534 |
if (!app.xr.isAvailable(pc.XRTYPE_AR)) { messageToast("AR immersive indisponible sur cet appareil."); return; }
|
| 535 |
if (!app.xr.domOverlay) app.xr.domOverlay = {};
|
|
@@ -593,7 +615,7 @@
|
|
| 593 |
placedOnce = true;
|
| 594 |
rotRangeInput.disabled = false;
|
| 595 |
|
| 596 |
-
// Après placement,
|
| 597 |
messageToast("Objet placé. Glissez pour déplacer, tournez-le avec le slider →");
|
| 598 |
}
|
| 599 |
});
|
|
|
|
| 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) + bouton “Lancer l’AR”
|
| 4 |
- Android/Desktop : WebXR AR (plans HORIZONTAUX uniquement) + slider yaw + blob shadow
|
| 5 |
+
- Message de démarrage centré & plus grand sur iOS ET Android
|
| 6 |
- Éclairage PBR par défaut (sans WebXR light estimation)
|
| 7 |
- Monté dans un conteneur choisi (data-mount="#ar-mount") pour Squarespace
|
| 8 |
*/
|
|
|
|
| 107 |
}
|
| 108 |
|
| 109 |
// ============ UI / Overlay commun ============
|
| 110 |
+
// Style minimal intégré : toasts, message centré, bouton “Lancer l’AR” (iOS & Android).
|
|
|
|
| 111 |
var css = [
|
| 112 |
/* Toast (bas) */
|
| 113 |
".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}",
|
| 114 |
/* Variante centrée + plus grande pour le message “Modèle chargé …” */
|
| 115 |
".pc-ar-msg.pc-ar-msg--centerBig{top:50%;bottom:auto;transform:translate(-50%,-50%);font-size:18px;padding:14px 18px;max-width:min(90vw,720px)}",
|
| 116 |
|
| 117 |
+
/* Bouton “Lancer l’AR” */
|
| 118 |
+
"#ar-launch-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:72px;z-index:10003;pointer-events:auto;appearance:none;border:none;border-radius:14px;padding:12px 18px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:15px;font-weight:600;color:#fff;background:rgba(0,0,0,0.85);box-shadow:0 6px 18px rgba(0,0,0,.25);backdrop-filter:blur(6px);cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent}",
|
| 119 |
+
"#ar-launch-btn:active{transform:translateX(-50%) scale(0.98)}",
|
| 120 |
+
"#ar-launch-btn:disabled{opacity:.5;cursor:not-allowed}",
|
| 121 |
+
|
| 122 |
+
/* Ancre Quick Look cachée (iOS) */
|
| 123 |
+
"#ios-quicklook-anchor{position:absolute!important;width:1px!important;height:1px!important;overflow:hidden!important;clip-path:inset(50%)!important;pointer-events:none!important}",
|
| 124 |
+
|
| 125 |
"#xr-overlay-root{position:fixed;inset:0;z-index:10001;pointer-events:none}",
|
| 126 |
|
| 127 |
+
/* --- NE PAS MODIFIER : panneau Rotation (WebXR) --- */
|
| 128 |
".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}",
|
| 129 |
".ar-ui .label{font-size:12px;text-align:center;opacity:.95}",
|
| 130 |
".rotY-wrap{position:relative;width:48px;height:200px;display:flex;align-items:center;justify-content:center;touch-action:none;overflow:visible;pointer-events:auto}",
|
| 131 |
".rotY-rail{position:absolute;left:50%;transform:translateX(-50%);width:4px;height:100%;background:rgba(255,255,255,.35);border-radius:2px;pointer-events:none}",
|
| 132 |
".rotY-knob{position:absolute;left:50%;width:22px;height:22px;border-radius:50%;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,.35);transform:translate(-50%,-50%);top:50%;will-change:top;touch-action:none;pointer-events:none}",
|
| 133 |
".ar-ui input[type=\"range\"].rotY{position:absolute;opacity:0;pointer-events:none;width:0;height:0}",
|
| 134 |
+
".ar-ui .val{font-size:12px;opacity:.95}"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
].join("\n");
|
| 136 |
var styleTag = document.createElement("style");
|
| 137 |
styleTag.textContent = css;
|
|
|
|
| 183 |
}
|
| 184 |
}
|
| 185 |
|
| 186 |
+
// Bouton “Lancer l’AR” (visible) + ancre Quick Look (cachée) pour iOS
|
| 187 |
+
function ensureIOSLaunchUI(usdzUrl) {
|
| 188 |
+
// Ancre cachée qui déclenche Quick Look
|
| 189 |
+
var anchor = document.getElementById("ios-quicklook-anchor");
|
| 190 |
+
if (!anchor) {
|
| 191 |
+
anchor = document.createElement("a");
|
| 192 |
+
anchor.id = "ios-quicklook-anchor";
|
| 193 |
+
anchor.setAttribute("rel", "ar");
|
| 194 |
+
document.body.appendChild(anchor);
|
| 195 |
+
}
|
| 196 |
+
if (usdzUrl) anchor.setAttribute("href", buildQuickLookHref(usdzUrl));
|
| 197 |
+
|
| 198 |
+
// Bouton visible “Lancer l’AR”
|
| 199 |
+
var btn = document.getElementById("ar-launch-btn");
|
| 200 |
+
if (!btn) {
|
| 201 |
+
btn = document.createElement("button");
|
| 202 |
+
btn.id = "ar-launch-btn";
|
| 203 |
+
btn.type = "button";
|
| 204 |
+
btn.textContent = "Lancer l’AR";
|
| 205 |
+
// Évite la propagation d’events vers la scène
|
| 206 |
+
btn.addEventListener("pointerdown", function (e) { e.stopPropagation(); }, { passive: true });
|
| 207 |
+
btn.addEventListener("click", function (e) { e.stopPropagation(); }, false);
|
| 208 |
+
document.body.appendChild(btn);
|
| 209 |
+
}
|
| 210 |
|
| 211 |
+
// Clic => simulateur de clic sur l’ancre rel="ar"
|
| 212 |
+
btn.onclick = function (e) {
|
| 213 |
+
e.preventDefault();
|
| 214 |
+
e.stopPropagation();
|
| 215 |
+
if (anchor && anchor.href) anchor.click();
|
| 216 |
+
};
|
| 217 |
|
| 218 |
+
return { btn: btn, anchor: anchor };
|
|
|
|
|
|
|
| 219 |
}
|
| 220 |
|
| 221 |
// ============ Canvas monté dans un conteneur contrôlé (Squarespace) ============
|
|
|
|
| 267 |
return canvas;
|
| 268 |
}
|
| 269 |
|
| 270 |
+
// ---------- Panneau “Rotation” (inchangé pour WebXR) ----------
|
| 271 |
function ensureSliderUI() {
|
| 272 |
var p = overlayRoot.querySelector(".ar-ui");
|
| 273 |
if (p) return p;
|
|
|
|
| 285 |
return p;
|
| 286 |
}
|
| 287 |
|
| 288 |
+
// ============ Boot : charge config, branche iOS vs Android/Desktop ============
|
| 289 |
(async function () {
|
| 290 |
var cfgUrl = findConfigUrl();
|
| 291 |
var cfg = await loadConfigJson(cfgUrl);
|
| 292 |
+
var GLB_URL = (cfg && typeof cfg.glb_url === "string" && cfg.glb_url)
|
| 293 |
+
? cfg.glb_url
|
| 294 |
+
: "https://huggingface.co/datasets/MikaFil/viewer_gs/resolve/main/AR/tests/danae_no_metallic.glb";
|
| 295 |
+
var USDZ_URL = (cfg && typeof cfg.usdz_url === "string" && cfg.usdz_url)
|
| 296 |
+
? cfg.usdz_url
|
| 297 |
+
: null;
|
| 298 |
+
|
| 299 |
+
// --------- iOS : Quick Look + message centré + bouton “Lancer l’AR” ---------
|
| 300 |
if (isIOS()) {
|
| 301 |
if (USDZ_URL) {
|
| 302 |
+
// UI iOS (ancre rel=ar + bouton visible)
|
| 303 |
+
ensureIOSLaunchUI(USDZ_URL);
|
| 304 |
+
// Message de démarrage centré et plus grand (même UX que WebXR)
|
| 305 |
+
messageCenterBig("Modèle chargé. Appuyez sur « Lancer l’AR » pour démarrer.");
|
| 306 |
} else {
|
| 307 |
messageToast("iOS détecté, mais aucun 'usdz_url' dans config.json.");
|
| 308 |
}
|
| 309 |
return;
|
| 310 |
}
|
| 311 |
|
| 312 |
+
// --------- Android / Desktop : WebXR ---------
|
| 313 |
try {
|
| 314 |
await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
|
| 315 |
} catch (e) {
|
|
|
|
| 326 |
|
| 327 |
// Canvas + UI
|
| 328 |
var canvas = ensureCanvas();
|
| 329 |
+
var sliderPanel = ensureSliderUI();
|
| 330 |
+
var rotTrack = sliderPanel.querySelector("#ar-rotY-wrap");
|
| 331 |
+
var rotThumb = sliderPanel.querySelector("#ar-rotY-knob");
|
| 332 |
+
var rotRangeInput = sliderPanel.querySelector("#ar-rotY");
|
| 333 |
+
var rotValueLabel = sliderPanel.querySelector("#ar-rotY-val");
|
| 334 |
|
| 335 |
window.focus();
|
| 336 |
|
|
|
|
| 496 |
baseEulerX = initE.x; baseEulerZ = initE.z;
|
| 497 |
|
| 498 |
modelLoaded = true;
|
| 499 |
+
// Message de démarrage centré & plus grand (même UX que iOS)
|
|
|
|
| 500 |
messageCenterBig("Modèle chargé. Touchez l’écran pour démarrer l’AR.");
|
| 501 |
});
|
| 502 |
|
|
|
|
| 551 |
document.addEventListener("pointerup", endDrag, { capture: true, passive: false });
|
| 552 |
document.addEventListener("pointercancel", endDrag, { capture: true, passive: false });
|
| 553 |
|
| 554 |
+
// --- Démarrage AR (tap écran)
|
| 555 |
function activateAR() {
|
| 556 |
if (!app.xr.isAvailable(pc.XRTYPE_AR)) { messageToast("AR immersive indisponible sur cet appareil."); return; }
|
| 557 |
if (!app.xr.domOverlay) app.xr.domOverlay = {};
|
|
|
|
| 615 |
placedOnce = true;
|
| 616 |
rotRangeInput.disabled = false;
|
| 617 |
|
| 618 |
+
// Après placement, toasts bas classiques
|
| 619 |
messageToast("Objet placé. Glissez pour déplacer, tournez-le avec le slider →");
|
| 620 |
}
|
| 621 |
});
|