diff --git a/Module.php b/Module.php
index d2911cf..d94a574 100644
--- a/Module.php
+++ b/Module.php
@@ -11,6 +11,7 @@ class Module extends AbstractModule
const MODEL_TYPES = [
'gltf' => 'gLTF',
+ /*
'obj' => 'OBJ',
'obj+mtl' => 'OBJ + MTL',
'json' => 'JSON',
@@ -18,6 +19,7 @@ class Module extends AbstractModule
'stl' => 'STL',
'dae' => 'Collada .dae',
'ply' => 'PLY',
+ */
];
public function getConfig()
diff --git a/asset/css/render3d.css b/asset/css/render3d.css
index 657decd..92380e5 100644
--- a/asset/css/render3d.css
+++ b/asset/css/render3d.css
@@ -1,7 +1,34 @@
-/* Panaorama viewer custom */
-@media screen {
- .render-3d {
- /* width: 600px; */
- /* height: 400px; */
- }
+
+.model-3d-wrap {
+ width: 100%
+}
+#lazy-load-poster {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ background-image: url("/modules/Render3D/asset/img/pre-load-image.jpg");
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+#button-load {
+ background-image: url("/modules/Render3D/asset/img/ic_get_app_white_24dp.svg");
+ background-repeat: no-repeat;
+ background-size: 24px 24px;
+ background-position: 6% 50%;
+ background-color: #000;
+ color: white;
+ cursor: pointer;
+ border-radius: 6px;
+ display: inline-block;
+ padding: 10px 18px 9px 40px;
+ font-weight: 500;
+ box-shadow: 0 0 8px rgba(0,0,0,.2), 0 0 4px rgba(0,0,0,.25);
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate3d(-50%, -50%, 0);
+ z-index: 100;
}
diff --git a/asset/img/ic_get_app_white_24dp.svg b/asset/img/ic_get_app_white_24dp.svg
new file mode 100644
index 0000000..defd2e1
--- /dev/null
+++ b/asset/img/ic_get_app_white_24dp.svg
@@ -0,0 +1,4 @@
+
diff --git a/asset/img/pre-load-image.jpg b/asset/img/pre-load-image.jpg
new file mode 100644
index 0000000..f36ee6e
Binary files /dev/null and b/asset/img/pre-load-image.jpg differ
diff --git a/asset/vendor/google/model-viewer.js b/asset/vendor/google/model-viewer.js
new file mode 100644
index 0000000..316b5cf
--- /dev/null
+++ b/asset/vendor/google/model-viewer.js
@@ -0,0 +1,56628 @@
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+/**
+ * An expression marker with embedded unique key to avoid collision with
+ * possible text in templates.
+ */
+`{{lit-${String(Math.random()).slice(2)}}}`;
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+/**
+ * Our TrustedTypePolicy for HTML which is declared using the html template
+ * tag function.
+ *
+ * That HTML is a developer-authored constant, and is parsed with innerHTML
+ * before any untrusted expressions have been mixed in. Therefor it is
+ * considered safe by construction.
+ */
+window.trustedTypes &&
+ trustedTypes.createPolicy('lit-html', { createHTML: (s) => s });
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+// Detect event listener options support. If the `capture` property is read
+// from the options object, then options are supported. If not, then the third
+// argument to add/removeEventListener is interpreted as the boolean capture
+// value so we should only pass the `capture` property.
+let eventOptionsSupported = false;
+// Wrap into an IIFE because MS Edge <= v41 does not support having try/catch
+// blocks right into the body of a module
+(() => {
+ try {
+ const options = {
+ get capture() {
+ eventOptionsSupported = true;
+ return false;
+ }
+ };
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ window.addEventListener('test', options, options);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ window.removeEventListener('test', options, options);
+ }
+ catch (_e) {
+ // event options not supported
+ }
+})();
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+// IMPORTANT: do not change the property name or the assignment expression.
+// This line will be used in regexes to search for lit-html usage.
+// TODO(justinfagnani): inject version number at build time
+if (typeof window !== 'undefined') {
+ (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.3.0');
+}
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+if (typeof window.ShadyCSS === 'undefined') ;
+else if (typeof window.ShadyCSS.prepareTemplateDom === 'undefined') {
+ console.warn(`Incompatible ShadyCSS version detected. ` +
+ `Please update to at least @webcomponents/webcomponentsjs@2.0.2 and ` +
+ `@webcomponents/shadycss@1.3.1.`);
+}
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+var _a$d;
+/**
+ * Use this module if you want to create your own base class extending
+ * [[UpdatingElement]].
+ * @packageDocumentation
+ */
+/*
+ * When using Closure Compiler, JSCompiler_renameProperty(property, object) is
+ * replaced at compile time by the munged name for object[property]. We cannot
+ * alias this function, so we have to use a small shim that has the same
+ * behavior when not compiling.
+ */
+window.JSCompiler_renameProperty =
+ (prop, _obj) => prop;
+const defaultConverter = {
+ toAttribute(value, type) {
+ switch (type) {
+ case Boolean:
+ return value ? '' : null;
+ case Object:
+ case Array:
+ // if the value is `null` or `undefined` pass this through
+ // to allow removing/no change behavior.
+ return value == null ? value : JSON.stringify(value);
+ }
+ return value;
+ },
+ fromAttribute(value, type) {
+ switch (type) {
+ case Boolean:
+ return value !== null;
+ case Number:
+ return value === null ? null : Number(value);
+ case Object:
+ case Array:
+ return JSON.parse(value);
+ }
+ return value;
+ }
+};
+/**
+ * Change function that returns true if `value` is different from `oldValue`.
+ * This method is used as the default for a property's `hasChanged` function.
+ */
+const notEqual = (value, old) => {
+ // This ensures (old==NaN, value==NaN) always returns false
+ return old !== value && (old === old || value === value);
+};
+const defaultPropertyDeclaration = {
+ attribute: true,
+ type: String,
+ converter: defaultConverter,
+ reflect: false,
+ hasChanged: notEqual
+};
+const STATE_HAS_UPDATED = 1;
+const STATE_UPDATE_REQUESTED = 1 << 2;
+const STATE_IS_REFLECTING_TO_ATTRIBUTE = 1 << 3;
+const STATE_IS_REFLECTING_TO_PROPERTY = 1 << 4;
+/**
+ * The Closure JS Compiler doesn't currently have good support for static
+ * property semantics where "this" is dynamic (e.g.
+ * https://github.com/google/closure-compiler/issues/3177 and others) so we use
+ * this hack to bypass any rewriting by the compiler.
+ */
+const finalized = 'finalized';
+/**
+ * Base element class which manages element properties and attributes. When
+ * properties change, the `update` method is asynchronously called. This method
+ * should be supplied by subclassers to render updates as desired.
+ * @noInheritDoc
+ */
+class UpdatingElement extends HTMLElement {
+ constructor() {
+ super();
+ this.initialize();
+ }
+ /**
+ * Returns a list of attributes corresponding to the registered properties.
+ * @nocollapse
+ */
+ static get observedAttributes() {
+ // note: piggy backing on this to ensure we're finalized.
+ this.finalize();
+ const attributes = [];
+ // Use forEach so this works even if for/of loops are compiled to for loops
+ // expecting arrays
+ this._classProperties.forEach((v, p) => {
+ const attr = this._attributeNameForProperty(p, v);
+ if (attr !== undefined) {
+ this._attributeToPropertyMap.set(attr, p);
+ attributes.push(attr);
+ }
+ });
+ return attributes;
+ }
+ /**
+ * Ensures the private `_classProperties` property metadata is created.
+ * In addition to `finalize` this is also called in `createProperty` to
+ * ensure the `@property` decorator can add property metadata.
+ */
+ /** @nocollapse */
+ static _ensureClassProperties() {
+ // ensure private storage for property declarations.
+ if (!this.hasOwnProperty(JSCompiler_renameProperty('_classProperties', this))) {
+ this._classProperties = new Map();
+ // NOTE: Workaround IE11 not supporting Map constructor argument.
+ const superProperties = Object.getPrototypeOf(this)._classProperties;
+ if (superProperties !== undefined) {
+ superProperties.forEach((v, k) => this._classProperties.set(k, v));
+ }
+ }
+ }
+ /**
+ * Creates a property accessor on the element prototype if one does not exist
+ * and stores a PropertyDeclaration for the property with the given options.
+ * The property setter calls the property's `hasChanged` property option
+ * or uses a strict identity check to determine whether or not to request
+ * an update.
+ *
+ * This method may be overridden to customize properties; however,
+ * when doing so, it's important to call `super.createProperty` to ensure
+ * the property is setup correctly. This method calls
+ * `getPropertyDescriptor` internally to get a descriptor to install.
+ * To customize what properties do when they are get or set, override
+ * `getPropertyDescriptor`. To customize the options for a property,
+ * implement `createProperty` like this:
+ *
+ * static createProperty(name, options) {
+ * options = Object.assign(options, {myOption: true});
+ * super.createProperty(name, options);
+ * }
+ *
+ * @nocollapse
+ */
+ static createProperty(name, options = defaultPropertyDeclaration) {
+ // Note, since this can be called by the `@property` decorator which
+ // is called before `finalize`, we ensure storage exists for property
+ // metadata.
+ this._ensureClassProperties();
+ this._classProperties.set(name, options);
+ // Do not generate an accessor if the prototype already has one, since
+ // it would be lost otherwise and that would never be the user's intention;
+ // Instead, we expect users to call `requestUpdate` themselves from
+ // user-defined accessors. Note that if the super has an accessor we will
+ // still overwrite it
+ if (options.noAccessor || this.prototype.hasOwnProperty(name)) {
+ return;
+ }
+ const key = typeof name === 'symbol' ? Symbol() : `__${name}`;
+ const descriptor = this.getPropertyDescriptor(name, key, options);
+ if (descriptor !== undefined) {
+ Object.defineProperty(this.prototype, name, descriptor);
+ }
+ }
+ /**
+ * Returns a property descriptor to be defined on the given named property.
+ * If no descriptor is returned, the property will not become an accessor.
+ * For example,
+ *
+ * class MyElement extends LitElement {
+ * static getPropertyDescriptor(name, key, options) {
+ * const defaultDescriptor =
+ * super.getPropertyDescriptor(name, key, options);
+ * const setter = defaultDescriptor.set;
+ * return {
+ * get: defaultDescriptor.get,
+ * set(value) {
+ * setter.call(this, value);
+ * // custom action.
+ * },
+ * configurable: true,
+ * enumerable: true
+ * }
+ * }
+ * }
+ *
+ * @nocollapse
+ */
+ static getPropertyDescriptor(name, key, options) {
+ return {
+ // tslint:disable-next-line:no-any no symbol in index
+ get() {
+ return this[key];
+ },
+ set(value) {
+ const oldValue = this[name];
+ this[key] = value;
+ this
+ .requestUpdateInternal(name, oldValue, options);
+ },
+ configurable: true,
+ enumerable: true
+ };
+ }
+ /**
+ * Returns the property options associated with the given property.
+ * These options are defined with a PropertyDeclaration via the `properties`
+ * object or the `@property` decorator and are registered in
+ * `createProperty(...)`.
+ *
+ * Note, this method should be considered "final" and not overridden. To
+ * customize the options for a given property, override `createProperty`.
+ *
+ * @nocollapse
+ * @final
+ */
+ static getPropertyOptions(name) {
+ return this._classProperties && this._classProperties.get(name) ||
+ defaultPropertyDeclaration;
+ }
+ /**
+ * Creates property accessors for registered properties and ensures
+ * any superclasses are also finalized.
+ * @nocollapse
+ */
+ static finalize() {
+ // finalize any superclasses
+ const superCtor = Object.getPrototypeOf(this);
+ if (!superCtor.hasOwnProperty(finalized)) {
+ superCtor.finalize();
+ }
+ this[finalized] = true;
+ this._ensureClassProperties();
+ // initialize Map populated in observedAttributes
+ this._attributeToPropertyMap = new Map();
+ // make any properties
+ // Note, only process "own" properties since this element will inherit
+ // any properties defined on the superClass, and finalization ensures
+ // the entire prototype chain is finalized.
+ if (this.hasOwnProperty(JSCompiler_renameProperty('properties', this))) {
+ const props = this.properties;
+ // support symbols in properties (IE11 does not support this)
+ const propKeys = [
+ ...Object.getOwnPropertyNames(props),
+ ...(typeof Object.getOwnPropertySymbols === 'function') ?
+ Object.getOwnPropertySymbols(props) :
+ []
+ ];
+ // This for/of is ok because propKeys is an array
+ for (const p of propKeys) {
+ // note, use of `any` is due to TypeSript lack of support for symbol in
+ // index types
+ // tslint:disable-next-line:no-any no symbol in index
+ this.createProperty(p, props[p]);
+ }
+ }
+ }
+ /**
+ * Returns the property name for the given attribute `name`.
+ * @nocollapse
+ */
+ static _attributeNameForProperty(name, options) {
+ const attribute = options.attribute;
+ return attribute === false ?
+ undefined :
+ (typeof attribute === 'string' ?
+ attribute :
+ (typeof name === 'string' ? name.toLowerCase() : undefined));
+ }
+ /**
+ * Returns true if a property should request an update.
+ * Called when a property value is set and uses the `hasChanged`
+ * option for the property if present or a strict identity check.
+ * @nocollapse
+ */
+ static _valueHasChanged(value, old, hasChanged = notEqual) {
+ return hasChanged(value, old);
+ }
+ /**
+ * Returns the property value for the given attribute value.
+ * Called via the `attributeChangedCallback` and uses the property's
+ * `converter` or `converter.fromAttribute` property option.
+ * @nocollapse
+ */
+ static _propertyValueFromAttribute(value, options) {
+ const type = options.type;
+ const converter = options.converter || defaultConverter;
+ const fromAttribute = (typeof converter === 'function' ? converter : converter.fromAttribute);
+ return fromAttribute ? fromAttribute(value, type) : value;
+ }
+ /**
+ * Returns the attribute value for the given property value. If this
+ * returns undefined, the property will *not* be reflected to an attribute.
+ * If this returns null, the attribute will be removed, otherwise the
+ * attribute will be set to the value.
+ * This uses the property's `reflect` and `type.toAttribute` property options.
+ * @nocollapse
+ */
+ static _propertyValueToAttribute(value, options) {
+ if (options.reflect === undefined) {
+ return;
+ }
+ const type = options.type;
+ const converter = options.converter;
+ const toAttribute = converter && converter.toAttribute ||
+ defaultConverter.toAttribute;
+ return toAttribute(value, type);
+ }
+ /**
+ * Performs element initialization. By default captures any pre-set values for
+ * registered properties.
+ */
+ initialize() {
+ this._updateState = 0;
+ this._updatePromise =
+ new Promise((res) => this._enableUpdatingResolver = res);
+ this._changedProperties = new Map();
+ this._saveInstanceProperties();
+ // ensures first update will be caught by an early access of
+ // `updateComplete`
+ this.requestUpdateInternal();
+ }
+ /**
+ * Fixes any properties set on the instance before upgrade time.
+ * Otherwise these would shadow the accessor and break these properties.
+ * The properties are stored in a Map which is played back after the
+ * constructor runs. Note, on very old versions of Safari (<=9) or Chrome
+ * (<=41), properties created for native platform properties like (`id` or
+ * `name`) may not have default values set in the element constructor. On
+ * these browsers native properties appear on instances and therefore their
+ * default value will overwrite any element default (e.g. if the element sets
+ * this.id = 'id' in the constructor, the 'id' will become '' since this is
+ * the native platform default).
+ */
+ _saveInstanceProperties() {
+ // Use forEach so this works even if for/of loops are compiled to for loops
+ // expecting arrays
+ this.constructor
+ ._classProperties.forEach((_v, p) => {
+ if (this.hasOwnProperty(p)) {
+ const value = this[p];
+ delete this[p];
+ if (!this._instanceProperties) {
+ this._instanceProperties = new Map();
+ }
+ this._instanceProperties.set(p, value);
+ }
+ });
+ }
+ /**
+ * Applies previously saved instance properties.
+ */
+ _applyInstanceProperties() {
+ // Use forEach so this works even if for/of loops are compiled to for loops
+ // expecting arrays
+ // tslint:disable-next-line:no-any
+ this._instanceProperties.forEach((v, p) => this[p] = v);
+ this._instanceProperties = undefined;
+ }
+ connectedCallback() {
+ // Ensure first connection completes an update. Updates cannot complete
+ // before connection.
+ this.enableUpdating();
+ }
+ enableUpdating() {
+ if (this._enableUpdatingResolver !== undefined) {
+ this._enableUpdatingResolver();
+ this._enableUpdatingResolver = undefined;
+ }
+ }
+ /**
+ * Allows for `super.disconnectedCallback()` in extensions while
+ * reserving the possibility of making non-breaking feature additions
+ * when disconnecting at some point in the future.
+ */
+ disconnectedCallback() {
+ }
+ /**
+ * Synchronizes property values when attributes change.
+ */
+ attributeChangedCallback(name, old, value) {
+ if (old !== value) {
+ this._attributeToProperty(name, value);
+ }
+ }
+ _propertyToAttribute(name, value, options = defaultPropertyDeclaration) {
+ const ctor = this.constructor;
+ const attr = ctor._attributeNameForProperty(name, options);
+ if (attr !== undefined) {
+ const attrValue = ctor._propertyValueToAttribute(value, options);
+ // an undefined value does not change the attribute.
+ if (attrValue === undefined) {
+ return;
+ }
+ // Track if the property is being reflected to avoid
+ // setting the property again via `attributeChangedCallback`. Note:
+ // 1. this takes advantage of the fact that the callback is synchronous.
+ // 2. will behave incorrectly if multiple attributes are in the reaction
+ // stack at time of calling. However, since we process attributes
+ // in `update` this should not be possible (or an extreme corner case
+ // that we'd like to discover).
+ // mark state reflecting
+ this._updateState = this._updateState | STATE_IS_REFLECTING_TO_ATTRIBUTE;
+ if (attrValue == null) {
+ this.removeAttribute(attr);
+ }
+ else {
+ this.setAttribute(attr, attrValue);
+ }
+ // mark state not reflecting
+ this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_ATTRIBUTE;
+ }
+ }
+ _attributeToProperty(name, value) {
+ // Use tracking info to avoid deserializing attribute value if it was
+ // just set from a property setter.
+ if (this._updateState & STATE_IS_REFLECTING_TO_ATTRIBUTE) {
+ return;
+ }
+ const ctor = this.constructor;
+ // Note, hint this as an `AttributeMap` so closure clearly understands
+ // the type; it has issues with tracking types through statics
+ // tslint:disable-next-line:no-unnecessary-type-assertion
+ const propName = ctor._attributeToPropertyMap.get(name);
+ if (propName !== undefined) {
+ const options = ctor.getPropertyOptions(propName);
+ // mark state reflecting
+ this._updateState = this._updateState | STATE_IS_REFLECTING_TO_PROPERTY;
+ this[propName] =
+ // tslint:disable-next-line:no-any
+ ctor._propertyValueFromAttribute(value, options);
+ // mark state not reflecting
+ this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_PROPERTY;
+ }
+ }
+ /**
+ * This protected version of `requestUpdate` does not access or return the
+ * `updateComplete` promise. This promise can be overridden and is therefore
+ * not free to access.
+ */
+ requestUpdateInternal(name, oldValue, options) {
+ let shouldRequestUpdate = true;
+ // If we have a property key, perform property update steps.
+ if (name !== undefined) {
+ const ctor = this.constructor;
+ options = options || ctor.getPropertyOptions(name);
+ if (ctor._valueHasChanged(this[name], oldValue, options.hasChanged)) {
+ if (!this._changedProperties.has(name)) {
+ this._changedProperties.set(name, oldValue);
+ }
+ // Add to reflecting properties set.
+ // Note, it's important that every change has a chance to add the
+ // property to `_reflectingProperties`. This ensures setting
+ // attribute + property reflects correctly.
+ if (options.reflect === true &&
+ !(this._updateState & STATE_IS_REFLECTING_TO_PROPERTY)) {
+ if (this._reflectingProperties === undefined) {
+ this._reflectingProperties = new Map();
+ }
+ this._reflectingProperties.set(name, options);
+ }
+ }
+ else {
+ // Abort the request if the property should not be considered changed.
+ shouldRequestUpdate = false;
+ }
+ }
+ if (!this._hasRequestedUpdate && shouldRequestUpdate) {
+ this._updatePromise = this._enqueueUpdate();
+ }
+ }
+ /**
+ * Requests an update which is processed asynchronously. This should
+ * be called when an element should update based on some state not triggered
+ * by setting a property. In this case, pass no arguments. It should also be
+ * called when manually implementing a property setter. In this case, pass the
+ * property `name` and `oldValue` to ensure that any configured property
+ * options are honored. Returns the `updateComplete` Promise which is resolved
+ * when the update completes.
+ *
+ * @param name {PropertyKey} (optional) name of requesting property
+ * @param oldValue {any} (optional) old value of requesting property
+ * @returns {Promise} A Promise that is resolved when the update completes.
+ */
+ requestUpdate(name, oldValue) {
+ this.requestUpdateInternal(name, oldValue);
+ return this.updateComplete;
+ }
+ /**
+ * Sets up the element to asynchronously update.
+ */
+ async _enqueueUpdate() {
+ this._updateState = this._updateState | STATE_UPDATE_REQUESTED;
+ try {
+ // Ensure any previous update has resolved before updating.
+ // This `await` also ensures that property changes are batched.
+ await this._updatePromise;
+ }
+ catch (e) {
+ // Ignore any previous errors. We only care that the previous cycle is
+ // done. Any error should have been handled in the previous update.
+ }
+ const result = this.performUpdate();
+ // If `performUpdate` returns a Promise, we await it. This is done to
+ // enable coordinating updates with a scheduler. Note, the result is
+ // checked to avoid delaying an additional microtask unless we need to.
+ if (result != null) {
+ await result;
+ }
+ return !this._hasRequestedUpdate;
+ }
+ get _hasRequestedUpdate() {
+ return (this._updateState & STATE_UPDATE_REQUESTED);
+ }
+ get hasUpdated() {
+ return (this._updateState & STATE_HAS_UPDATED);
+ }
+ /**
+ * Performs an element update. Note, if an exception is thrown during the
+ * update, `firstUpdated` and `updated` will not be called.
+ *
+ * You can override this method to change the timing of updates. If this
+ * method is overridden, `super.performUpdate()` must be called.
+ *
+ * For instance, to schedule updates to occur just before the next frame:
+ *
+ * ```
+ * protected async performUpdate(): Promise {
+ * await new Promise((resolve) => requestAnimationFrame(() => resolve()));
+ * super.performUpdate();
+ * }
+ * ```
+ */
+ performUpdate() {
+ // Abort any update if one is not pending when this is called.
+ // This can happen if `performUpdate` is called early to "flush"
+ // the update.
+ if (!this._hasRequestedUpdate) {
+ return;
+ }
+ // Mixin instance properties once, if they exist.
+ if (this._instanceProperties) {
+ this._applyInstanceProperties();
+ }
+ let shouldUpdate = false;
+ const changedProperties = this._changedProperties;
+ try {
+ shouldUpdate = this.shouldUpdate(changedProperties);
+ if (shouldUpdate) {
+ this.update(changedProperties);
+ }
+ else {
+ this._markUpdated();
+ }
+ }
+ catch (e) {
+ // Prevent `firstUpdated` and `updated` from running when there's an
+ // update exception.
+ shouldUpdate = false;
+ // Ensure element can accept additional updates after an exception.
+ this._markUpdated();
+ throw e;
+ }
+ if (shouldUpdate) {
+ if (!(this._updateState & STATE_HAS_UPDATED)) {
+ this._updateState = this._updateState | STATE_HAS_UPDATED;
+ this.firstUpdated(changedProperties);
+ }
+ this.updated(changedProperties);
+ }
+ }
+ _markUpdated() {
+ this._changedProperties = new Map();
+ this._updateState = this._updateState & ~STATE_UPDATE_REQUESTED;
+ }
+ /**
+ * Returns a Promise that resolves when the element has completed updating.
+ * The Promise value is a boolean that is `true` if the element completed the
+ * update without triggering another update. The Promise result is `false` if
+ * a property was set inside `updated()`. If the Promise is rejected, an
+ * exception was thrown during the update.
+ *
+ * To await additional asynchronous work, override the `_getUpdateComplete`
+ * method. For example, it is sometimes useful to await a rendered element
+ * before fulfilling this Promise. To do this, first await
+ * `super._getUpdateComplete()`, then any subsequent state.
+ *
+ * @returns {Promise} The Promise returns a boolean that indicates if the
+ * update resolved without triggering another update.
+ */
+ get updateComplete() {
+ return this._getUpdateComplete();
+ }
+ /**
+ * Override point for the `updateComplete` promise.
+ *
+ * It is not safe to override the `updateComplete` getter directly due to a
+ * limitation in TypeScript which means it is not possible to call a
+ * superclass getter (e.g. `super.updateComplete.then(...)`) when the target
+ * language is ES5 (https://github.com/microsoft/TypeScript/issues/338).
+ * This method should be overridden instead. For example:
+ *
+ * class MyElement extends LitElement {
+ * async _getUpdateComplete() {
+ * await super._getUpdateComplete();
+ * await this._myChild.updateComplete;
+ * }
+ * }
+ */
+ _getUpdateComplete() {
+ return this._updatePromise;
+ }
+ /**
+ * Controls whether or not `update` should be called when the element requests
+ * an update. By default, this method always returns `true`, but this can be
+ * customized to control when to update.
+ *
+ * @param _changedProperties Map of changed properties with old values
+ */
+ shouldUpdate(_changedProperties) {
+ return true;
+ }
+ /**
+ * Updates the element. This method reflects property values to attributes.
+ * It can be overridden to render and keep updated element DOM.
+ * Setting properties inside this method will *not* trigger
+ * another update.
+ *
+ * @param _changedProperties Map of changed properties with old values
+ */
+ update(_changedProperties) {
+ if (this._reflectingProperties !== undefined &&
+ this._reflectingProperties.size > 0) {
+ // Use forEach so this works even if for/of loops are compiled to for
+ // loops expecting arrays
+ this._reflectingProperties.forEach((v, k) => this._propertyToAttribute(k, this[k], v));
+ this._reflectingProperties = undefined;
+ }
+ this._markUpdated();
+ }
+ /**
+ * Invoked whenever the element is updated. Implement to perform
+ * post-updating tasks via DOM APIs, for example, focusing an element.
+ *
+ * Setting properties inside this method will trigger the element to update
+ * again after this update cycle completes.
+ *
+ * @param _changedProperties Map of changed properties with old values
+ */
+ updated(_changedProperties) {
+ }
+ /**
+ * Invoked when the element is first updated. Implement to perform one time
+ * work on the element after update.
+ *
+ * Setting properties inside this method will trigger the element to update
+ * again after this update cycle completes.
+ *
+ * @param _changedProperties Map of changed properties with old values
+ */
+ firstUpdated(_changedProperties) {
+ }
+}
+_a$d = finalized;
+/**
+ * Marks class as having finished creating properties.
+ */
+UpdatingElement[_a$d] = true;
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+const standardProperty = (options, element) => {
+ // When decorating an accessor, pass it through and add property metadata.
+ // Note, the `hasOwnProperty` check in `createProperty` ensures we don't
+ // stomp over the user's accessor.
+ if (element.kind === 'method' && element.descriptor &&
+ !('value' in element.descriptor)) {
+ return Object.assign(Object.assign({}, element), { finisher(clazz) {
+ clazz.createProperty(element.key, options);
+ } });
+ }
+ else {
+ // createProperty() takes care of defining the property, but we still
+ // must return some kind of descriptor, so return a descriptor for an
+ // unused prototype field. The finisher calls createProperty().
+ return {
+ kind: 'field',
+ key: Symbol(),
+ placement: 'own',
+ descriptor: {},
+ // When @babel/plugin-proposal-decorators implements initializers,
+ // do this instead of the initializer below. See:
+ // https://github.com/babel/babel/issues/9260 extras: [
+ // {
+ // kind: 'initializer',
+ // placement: 'own',
+ // initializer: descriptor.initializer,
+ // }
+ // ],
+ initializer() {
+ if (typeof element.initializer === 'function') {
+ this[element.key] = element.initializer.call(this);
+ }
+ },
+ finisher(clazz) {
+ clazz.createProperty(element.key, options);
+ }
+ };
+ }
+};
+const legacyProperty = (options, proto, name) => {
+ proto.constructor
+ .createProperty(name, options);
+};
+/**
+ * A property decorator which creates a LitElement property which reflects a
+ * corresponding attribute value. A [[`PropertyDeclaration`]] may optionally be
+ * supplied to configure property features.
+ *
+ * This decorator should only be used for public fields. Private or protected
+ * fields should use the [[`internalProperty`]] decorator.
+ *
+ * @example
+ * ```ts
+ * class MyElement {
+ * @property({ type: Boolean })
+ * clicked = false;
+ * }
+ * ```
+ * @category Decorator
+ * @ExportDecoratedItems
+ */
+function property(options) {
+ // tslint:disable-next-line:no-any decorator
+ return (protoOrDescriptor, name) => (name !== undefined) ?
+ legacyProperty(options, protoOrDescriptor, name) :
+ standardProperty(options, protoOrDescriptor);
+}
+
+/**
+@license
+Copyright (c) 2019 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+*/
+/**
+ * Whether the current browser supports `adoptedStyleSheets`.
+ */
+(window.ShadowRoot) &&
+ (window.ShadyCSS === undefined || window.ShadyCSS.nativeShadow) &&
+ ('adoptedStyleSheets' in Document.prototype) &&
+ ('replace' in CSSStyleSheet.prototype);
+
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * http://polymer.github.io/PATENTS.txt
+ */
+// IMPORTANT: do not change the property name or the assignment expression.
+// This line will be used in regexes to search for LitElement usage.
+// TODO(justinfagnani): inject version number at build time
+(window['litElementVersions'] || (window['litElementVersions'] = []))
+ .push('2.4.0');
+
+/* @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// NOTE(cdata): The HAS_WEBXR_* constants can be enabled in Chrome by turning on
+// the appropriate flags. However, just because we have the API does not
+// guarantee that AR will work.
+const HAS_WEBXR_DEVICE_API = navigator.xr != null &&
+ self.XRSession != null && navigator.xr.isSessionSupported != null;
+const HAS_WEBXR_HIT_TEST_API = HAS_WEBXR_DEVICE_API && self.XRSession.prototype.requestHitTestSource;
+const HAS_RESIZE_OBSERVER = self.ResizeObserver != null;
+const HAS_INTERSECTION_OBSERVER = self.IntersectionObserver != null;
+const IS_WEBXR_AR_CANDIDATE = HAS_WEBXR_HIT_TEST_API;
+(() => {
+ const userAgent = navigator.userAgent || navigator.vendor || self.opera;
+ let check = false;
+ // eslint-disable-next-line
+ if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i
+ .test(userAgent) ||
+ /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i
+ .test(userAgent.substr(0, 4))) {
+ check = true;
+ }
+ return check;
+})();
+/\bCrOS\b/.test(navigator.userAgent);
+// Disabling offscreen canvas for now because it is slower and has bugs relating
+// to janky updates and out of sync frames.
+const USE_OFFSCREEN_CANVAS = false;
+// Boolean((self as any).OffscreenCanvas) &&
+// Boolean((self as any).OffscreenCanvas.prototype.transferToImageBitmap) &&
+// !IS_CHROMEOS; // TODO(elalish): file a bug on inverted renders
+const IS_ANDROID = /android/i.test(navigator.userAgent);
+// Prior to iOS 13, detecting iOS Safari was relatively straight-forward.
+// As of iOS 13, Safari on iPad (in its default configuration) reports the same
+// user-agent string as Safari on desktop MacOS. Strictly speaking, we only care
+// about iOS for the purposes if selecting for cases where Quick Look is known
+// to be supported. However, for API correctness purposes, we must rely on
+// known, detectable signals to distinguish iOS Safari from MacOS Safari. At the
+// time of this writing, there are no non-iOS/iPadOS Apple devices with
+// multi-touch displays.
+// @see https://stackoverflow.com/questions/57765958/how-to-detect-ipad-and-ipad-os-version-in-ios-13-and-up
+// @see https://forums.developer.apple.com/thread/119186
+// @see https://github.com/google/model-viewer/issues/758
+const IS_IOS = (/iPad|iPhone|iPod/.test(navigator.userAgent) && !self.MSStream) ||
+ (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
+const IS_AR_QUICKLOOK_CANDIDATE = (() => {
+ const tempAnchor = document.createElement('a');
+ return Boolean(tempAnchor.relList && tempAnchor.relList.supports &&
+ tempAnchor.relList.supports('ar'));
+})();
+// @see https://developer.chrome.com/multidevice/user-agent
+/Safari\//.test(navigator.userAgent);
+const IS_FIREFOX = /firefox/i.test(navigator.userAgent);
+const IS_OCULUS = /OculusBrowser/.test(navigator.userAgent);
+IS_IOS && /CriOS\//.test(navigator.userAgent);
+const IS_SCENEVIEWER_CANDIDATE = IS_ANDROID && !IS_FIREFOX && !IS_OCULUS;
+
+/* @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var CloseIcon = `
+`;
+
+/* @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var ControlsPrompt = `
+`;
+
+/* @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var ARGlyph = `
+`;
+
+/* @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+const template = document.createElement('template');
+template.innerHTML = `
+
+