@plattar/plattar-ar-adapter
Version:
Plattar AR Adapter for interfacing with Google & Apple WebAR
324 lines (323 loc) • 12.2 kB
JavaScript
"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;