UNPKG

@plattar/plattar-ar-adapter

Version:

Plattar AR Adapter for interfacing with Google & Apple WebAR

324 lines (323 loc) 12.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PlattarController = exports.ControllerState = void 0; const plattar_api_1 = require("@plattar/plattar-api"); const configurator_state_1 = require("../../util/configurator-state"); var ControllerState; (function (ControllerState) { ControllerState[ControllerState["None"] = 0] = "None"; ControllerState[ControllerState["Renderer"] = 1] = "Renderer"; ControllerState[ControllerState["QRCode"] = 2] = "QRCode"; })(ControllerState || (exports.ControllerState = ControllerState = {})); /** * All Plattar Controllers are derived from the same interface */ class PlattarController { /** * Default QR Code rendering options */ _GetDefaultQROptions(opt = null) { const options = opt ?? {}; return { color: options.color ?? (this.getAttribute("qr-color") || "#101721"), qrType: options.qrType ?? (this.getAttribute("qr-style") || "default"), shorten: options.shorten ?? (this.getBooleanAttribute("qr-shorten") || true), margin: options.margin ?? 0, detached: options.detached ?? (this.getBooleanAttribute("qr-detached") || false), url: options.url ?? null }; } ; constructor(parent) { this._state = ControllerState.None; this._element = null; this._prevQROpt = null; this._selectVariationObserver = null; this._selectVariationIDObserver = null; this._selectVariationSKUObserver = null; this._parent = parent; } /** * Generates a brand new Configurator State from the provided SceneID or inputted Configurator State */ async createConfiguratorState() { // get our Scene ID const sceneID = this.getAttribute("scene-id"); if (!sceneID) { throw new Error("PlattarController.createConfiguratorState() - cannot create as required attribute scene-id is not defined"); } const configState = this.getAttribute("config-state"); // get a list of variation ID's to use for initialising const variationIDs = this.getAttribute("variation-id"); // get a list of variation SKU's to use for initialising const variationSKUs = this.getAttribute("variation-sku"); // generate the decoded configurator state const decodedState = configState ? await configurator_state_1.ConfiguratorState.decodeState(sceneID, configState) : await configurator_state_1.ConfiguratorState.decodeScene(sceneID); // change the ID's and SKU's (if any) of the default configuration state const variationIDList = variationIDs ? variationIDs.split(",") : []; const variationSKUList = variationSKUs ? variationSKUs.split(",") : []; variationIDList.forEach((variationID) => { decodedState.state.setVariationID(variationID); }); variationSKUList.forEach((variationSKU) => { decodedState.state.setVariationSKU(variationSKU); }); // return fully modified configuration state return decodedState; } /** * Setup messenger observers to detect variation changes and apply to the internal * configuration state */ setupMessengerObservers(viewer, configState) { this._selectVariationObserver = viewer.messengerInstance.observer.subscribe("selectVariation", (cd) => { if (cd.type === "call") { const args = cd.data[0]; const variations = args ? (Array.isArray(args) ? args : [args]) : []; variations.forEach((variationID) => { configState.state.setVariationID(variationID); }); } }); this._selectVariationIDObserver = viewer.messengerInstance.observer.subscribe("selectVariationID", (cd) => { if (cd.type === "call") { const args = cd.data[0]; const variations = args ? (Array.isArray(args) ? args : [args]) : []; variations.forEach((variationID) => { configState.state.setVariationID(variationID); }); } }); this._selectVariationSKUObserver = viewer.messengerInstance.observer.subscribe("selectVariationSKU", (cd) => { if (cd.type === "call") { const args = cd.data[0]; const variations = args ? (Array.isArray(args) ? args : [args]) : []; variations.forEach((variationSKU) => { configState.state.setVariationSKU(variationSKU); }); } }); } /** * Remove all pre-existing observers */ removeMessengerObservers() { if (this._selectVariationObserver) { this._selectVariationObserver(); this._selectVariationObserver = null; } if (this._selectVariationIDObserver) { this._selectVariationIDObserver(); this._selectVariationIDObserver = null; } if (this._selectVariationSKUObserver) { this._selectVariationSKUObserver(); this._selectVariationSKUObserver = null; } } /** * Initialise and start AR mode if available */ async startAR() { const launcher = await this.initAR(); return launcher.start(); } /** * Decide which QR Code to render according to the qr-type attribute * @param options * @returns */ async startQRCode(options) { const qrType = this.getAttribute("qr-type") || "viewer"; switch (qrType.toLowerCase()) { case "ar": return this.startARQRCode(options); case "viewer": default: return this.startViewerQRCode(options); } } /** * Displays a QR Code that sends the user direct to AR * @param options * @returns */ async startARQRCode(options) { const opt = this._GetDefaultQROptions(options); const viewer = document.createElement("plattar-qrcode"); // remove the old renderer instance if any if (!opt.detached) { this.removeRenderer(); this._element = viewer; } // required attributes with defaults for plattar-viewer node const width = this.getAttribute("width") || "500px"; const height = this.getAttribute("height") || "500px"; viewer.setAttribute("width", width); viewer.setAttribute("height", height); if (opt.color) { viewer.setAttribute("color", opt.color); } if (opt.margin) { viewer.setAttribute("margin", `${opt.margin}`); } if (opt.qrType) { viewer.setAttribute("qr-type", opt.qrType); } viewer.setAttribute("shorten", (opt.shorten && (opt.shorten === true || opt.shorten === "true")) ? "true" : "false"); const qrOptions = btoa(JSON.stringify(opt)); let dst = plattar_api_1.Server.location().base + "renderer/launcher.html?qr_options=" + qrOptions; //let configState: string | null = null; const sceneID = this.getAttribute("scene-id"); const embedType = this.getAttribute("embed-type"); const productID = this.getAttribute("product-id"); const sceneProductID = this.getAttribute("scene-product-id"); const variationID = this.getAttribute("variation-id"); const variationSKU = this.getAttribute("variation-sku"); const arMode = this.getAttribute("ar-mode"); const showBanner = this.getAttribute("show-ar-banner"); const sceneGraphID = this.getAttribute("scene-graph-id"); if (embedType) { dst += "&embed_type=" + embedType; } if (productID) { dst += "&product_id=" + productID; } if (sceneProductID) { dst += "&scene_product_id=" + sceneProductID; } if (variationID) { dst += "&variation_id=" + variationID; } if (variationSKU) { dst += "&variation_sku=" + variationSKU; } if (arMode) { dst += "&ar_mode=" + arMode; } if (sceneID) { dst += "&scene_id=" + sceneID; } if (showBanner) { dst += "&show_ar_banner=" + showBanner; } if (sceneGraphID) { dst += "&scene_graph_id=" + sceneGraphID; } else { try { const sceneGraphID = await (await this.getConfiguratorState()).state.encodeSceneGraphID(); dst += "&scene_graph_id=" + sceneGraphID; } catch (_err) { // scene graph ID not available for some reason // we will generate a new one console.error(_err); } } viewer.setAttribute("url", opt.url || dst); this._prevQROpt = opt; if (!opt.detached) { this._state = ControllerState.QRCode; return new Promise((accept, reject) => { this.append(viewer); viewer.onload = () => { return accept(viewer); }; }); } return new Promise((accept, reject) => { return accept(viewer); }); } /** * Removes the currently active renderer view from the DOM */ removeRenderer() { // remove all other children const shadow = this.parent.shadowRoot; if (shadow) { let child = shadow.lastElementChild; while (child) { shadow.removeChild(child); child = shadow.lastElementChild; } } this._element = null; this.removeMessengerObservers(); return true; } /** * Returns the Parent Instance */ get parent() { return this._parent; } /** * Returns the specified attribute from the parent * @param attribute - The name of the attribute * @returns - The attribute value or null */ getAttribute(attribute) { return this.parent ? (this.parent.hasAttribute(attribute) ? this.parent.getAttribute(attribute) : null) : null; } /** * Returns the specified attribute from the parent as a boolean * @param attribute - The name of the attribute * @returns - The attribute value */ getBooleanAttribute(attribute) { return this.parent ? (this.parent.hasAttribute(attribute) ? (this.parent.getAttribute(attribute)?.toLowerCase() === "true" ? true : false) : false) : false; } /** * Sets a particular attribute into the HTML DOM * * @param attribute - The name of the attribute * @param value - The value of the attribute */ setAttribute(attribute, value) { if (this.parent) { this.parent.setAttribute(attribute, value); } } /** * Removes a particular attribute from HTML DOM * * @param attribute - The name of the attribute */ removeAttribute(attribute) { if (this.parent) { this.parent.removeAttribute(attribute); } } /** * Appends the provided element into the shadow-root of the parent element * @param element - The element to append */ append(element) { if (this._element !== element) { return; } // ensure append only allows a single element in the shadow DOM const shadow = this.parent.shadowRoot || this.parent.attachShadow({ mode: 'open' }); if (shadow) { let child = shadow.lastElementChild; while (child) { shadow.removeChild(child); child = shadow.lastElementChild; } } shadow.append(element); } /** * * @param element */ removeChild(element) { const shadow = this.parent.shadowRoot; if (shadow) { shadow.removeChild(element); } } } exports.PlattarController = PlattarController;