UNPKG

@google/model-viewer

Version:

Easily display interactive 3D models on the web and in AR!

1,214 lines (1,171 loc) 1.45 MB
/** * @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 */ /** * @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 */ /** * True if the custom elements polyfill is in use. */ const isCEPolyfill = window.customElements !== undefined && window.customElements.polyfillWrapFlushCallback !== undefined; /** * @license * Copyright (c) 2018 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 */ /** * @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. */ const marker = `{{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 */ /** * @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 */ /** * @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 */ try { const options = { get capture() { return false; } }; // tslint:disable-next-line:no-any window.addEventListener('test', options, options); // tslint:disable-next-line:no-any window.removeEventListener('test', options, options); } catch (_e) { } /** * @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 */ /** * @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 */ /** * @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 */ /** * @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 (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.1.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 */ /** * @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; /** * 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 microtaskPromise = Promise.resolve(true); 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; const STATE_HAS_CONNECTED = 1 << 5; /** * 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. */ class UpdatingElement extends HTMLElement { constructor() { super(); this._updateState = 0; this._instanceProperties = undefined; this._updatePromise = microtaskPromise; this._hasConnectedResolver = undefined; /** * Map with keys for any properties that have changed since the last * update cycle with previous values. */ this._changedProperties = new Map(); /** * Map with keys of properties that should be reflected when updated. */ this._reflectingProperties = undefined; 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. * 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. * @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}`; Object.defineProperty(this.prototype, name, { // tslint:disable-next-line:no-any no symbol in index get() { return this[key]; }, set(value) { const oldValue = this[name]; this[key] = value; this._requestUpdate(name, oldValue); }, configurable: true, enumerable: true }); } /** * 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._saveInstanceProperties(); // ensures first update will be caught by an early access of // `updateComplete` this._requestUpdate(); } /** * 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() { this._updateState = this._updateState | STATE_HAS_CONNECTED; // Ensure first connection completes an update. Updates cannot complete // before connection and if one is pending connection the // `_hasConnectionResolver` will exist. If so, resolve it to complete the // update, otherwise requestUpdate. if (this._hasConnectedResolver) { this._hasConnectedResolver(); this._hasConnectedResolver = 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; const propName = ctor._attributeToPropertyMap.get(name); if (propName !== undefined) { const options = ctor._classProperties.get(propName) || defaultPropertyDeclaration; // 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 private version of `requestUpdate` does not access or return the * `updateComplete` promise. This promise can be overridden and is therefore * not free to access. */ _requestUpdate(name, oldValue) { let shouldRequestUpdate = true; // If we have a property key, perform property update steps. if (name !== undefined) { const ctor = this.constructor; const options = ctor._classProperties.get(name) || defaultPropertyDeclaration; 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._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._requestUpdate(name, oldValue); return this.updateComplete; } /** * Sets up the element to asynchronously update. */ async _enqueueUpdate() { // Mark state updating... this._updateState = this._updateState | STATE_UPDATE_REQUESTED; let resolve; let reject; const previousUpdatePromise = this._updatePromise; this._updatePromise = new Promise((res, rej) => { resolve = res; reject = rej; }); try { // Ensure any previous update has resolved before updating. // This `await` also ensures that property changes are batched. await previousUpdatePromise; } 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. } // Make sure the element has connected before updating. if (!this._hasConnected) { await new Promise((res) => this._hasConnectedResolver = res); } try { 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; } } catch (e) { reject(e); } resolve(!this._hasRequestedUpdate); } get _hasConnected() { return (this._updateState & STATE_HAS_CONNECTED); } 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<unknown> { * await new Promise((resolve) => requestAnimationFrame(() => resolve())); * super.performUpdate(); * } * ``` */ performUpdate() { // 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); } } catch (e) { // Prevent `firstUpdated` and `updated` from running when there's an // update exception. shouldUpdate = false; throw e; } finally { // Ensure element can accept additional updates after an exception. this._markUpdated(); } 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; } } /** * 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 = finalized; /** * Marks class as having finished creating properties. */ UpdatingElement[_a] = 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({}, 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. * * @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 */ const supportsAdoptingStyleSheets = ('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.2.1'); const HAS_WEBXR_DEVICE_API = navigator.xr != null && self.XRSession != null && self.XRDevice != null && self.XRDevice.prototype.supportsSession != null; const HAS_WEBXR_HIT_TEST_API = HAS_WEBXR_DEVICE_API && self.XRSession.prototype.requestHitTest; const HAS_FULLSCREEN_API = document.documentElement != null && document.documentElement.requestFullscreen != null; const HAS_RESIZE_OBSERVER = self.ResizeObserver != null; const HAS_INTERSECTION_OBSERVER = self.IntersectionObserver != null; const IS_WEBXR_AR_CANDIDATE = HAS_WEBXR_HIT_TEST_API && HAS_FULLSCREEN_API; const IS_MOBILE = (() => { const userAgent = navigator.userAgent || navigator.vendor || self.opera; let check = false; 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; })(); const HAS_OFFSCREEN_CANVAS = Boolean(self.OffscreenCanvas); const OFFSCREEN_CANVAS_SUPPORT_BITMAP = Boolean(self.OffscreenCanvas) && Boolean(self.OffscreenCanvas.prototype.transferToImageBitmap); const IS_ANDROID = /android/i.test(navigator.userAgent); 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')); })(); const IS_IOS_CHROME = IS_IOS && /CriOS\//.test(navigator.userAgent); const IS_IOS_SAFARI = IS_IOS && /Safari\//.test(navigator.userAgent); const IS_IE11 = !(window.ActiveXObject) && 'ActiveXObject' in window; var CloseIcon = ` <svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#000000"> <!-- NOTE(cdata): This SVG filter is a stop-gap until we can implement support for dynamic re-coloring of UI components --> <defs> <filter id="drop-shadow" x="-100%" y="-100%" width="300%" height="300%"> <feGaussianBlur in="SourceAlpha" stdDeviation="1"/> <feOffset dx="0" dy="0" result="offsetblur"/> <feFlood flood-color="#000000"/> <feComposite in2="offsetblur" operator="in"/> <feMerge> <feMergeNode/> <feMergeNode in="SourceGraphic"/> </feMerge> </filter> </defs> <path filter="url(#drop-shadow)" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> <path d="M0 0h24v24H0z" fill="none"/> </svg>`; var ControlsPrompt = ` <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="250px" height="200px" viewBox="0 0 250 200" fill="transparent" focusable="false" aria-hidden="true"> <!-- Rotation arc --> <path id="orbit" d="M50,75 C55,50 195,50 200,75 C195,100 55,100 50,75" stroke-linecap="round" stroke-dasharray="180 180" stroke-dashoffset="-40" stroke="#a1a1a1" stroke-width="7" fill="transparent"> <animate attributeName="stroke-dashoffset" dur="1.75s" calcMode="linear" values="-40;-40.56;-42.08;-44.32;-47.04;-50;-52.96;-55.68;-57.92;-59.44;-60;-59.44;-57.92;-55.68;-52.96;-50;-47.04;-44.32;-42.08;-40.56;-40" keyTimes="0;0.05;0.1;0.15;0.2;0.25;0.3;0.35;0.4;0.45;0.5;0.55;0.6;0.65;0.7;0.75;0.8;0.85;0.9;0.95;1" repeatCount="indefinite" /> </path> <path d="M50,75 C55,50 195,50 200,75 C195,100 55,100 50,75" opacity="1" stroke-linecap="round" stroke-dasharray="140 220" stroke-dashoffset="-225" stroke="white" stroke-width="7" fill="transparent"> <animate attributeName="stroke-dashoffset" dur="1.75s" calcMode="linear" values="-225;-225.56;-227.07999999999998;-229.32;-232.04;-235;-237.96;-240.68;-242.92;-244.44;-245;-244.44;-242.92;-240.68;-237.96;-235;-232.04;-229.32;-227.07999999999998;-225.56;-225" keyTimes="0;0.05;0.1;0.15;0.2;0.25;0.3;0.35;0.4;0.45;0.5;0.55;0.6;0.65;0.7;0.75;0.8;0.85;0.9;0.95;1" repeatCount="indefinite" /> </path> <!-- Hand Icon --> <defs> <path id="a" d="M0 0h24v24H0V0z"/> </defs> <clipPath id="b"> <use xlink:href="#a" overflow="visible"/> </clipPath> <g transform="translate(100, 70) scale(3.5)"> <g transform="translate(0, 0)"> <animateTransform attributeName="transform" type="translate" repeatCount="indefinite" keyTimes="0;0.05;0.1;0.15;0.2;0.25;0.3;0.35;0.4;0.45;0.5;0.55;0.6;0.65;0.7;0.75;0.8;0.85;0.9;0.95;1" values="0,0;-0.16800000000000015,0;-0.6239999999999988,0;-1.2960000000000003,0;-2.111999999999999,0;-3,0;-3.8879999999999995,0;-4.704,0;-5.3759999999999994,0;-5.832,0;-6,0;-5.832,0;-5.3759999999999994,0;-4.704,0;-3.8879999999999995,0;-3,0;-2.111999999999999,0;-1.2960000000000003,0;-0.6239999999999988,0;-0.16800000000000015,0;0,0" dur="1.75s" /> <path clip-path="url(#b)" fill="white" d="M9 11.24V7.5C9 6.12 10.12 5 11.5 5S14 6.12 14 7.5v3.74c1.21-.81 2-2.18 2-3.74C16 5.01 13.99 3 11.5 3S7 5.01 7 7.5c0 1.56.79 2.93 2 3.74zm9.84 4.63l-4.54-2.26c-.17-.07-.35-.11-.54-.11H13v-6c0-.83-.67-1.5-1.5-1.5S10 6.67 10 7.5v10.74l-3.43-.72c-.08-.01-.15-.03-.24-.03-.31 0-.59.13-.79.33l-.79.8 4.94 4.94c.27.27.65.44 1.06.44h6.79c.75 0 1.33-.55 1.44-1.28l.75-5.27c.01-.07.02-.14.02-.2 0-.62-.38-1.16-.91-1.38z"/> </g> </g> <path id="orbit-hidden" d="M-30,15 C-35,-10 115,-10 120,15 C115,40 -35,40 -30,15" stroke-width="0" fill="transparent"></path> <!-- Arrow --> <g transform="translate(80, 60)"> <polyline id="Path-3" stroke="#a1a1a1" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" transform="translate(-33.952293, -4) rotate(-39.000000)" points="35.5366949 39.6822958 26.6550872 26.0761929 41.2494988 29.5432078"> <animateMotion calcMode="linear" keyPoints="0.095;0.09668;0.10124;0.10796;0.11612;0.125;0.13388;0.14204;0.14876;0.15332;0.155;0.15332;0.14876;0.14204;0.13388;0.125;0.11612;0.10796;0.10124;0.09668;0.095" keyTimes="0;0.05;0.1;0.15;0.2;0.25;0.3;0.35;0.4;0.45;0.5;0.55;0.6;0.65;0.7;0.75;0.8;0.85;0.9;0.95;1" dur="1.75s" repeatCount="indefinite"> <mpath xlink:href="#orbit-hidden"/> </animateMotion> </polyline> </g> </svg>`; var ARGlyph = ` <svg version="1.1" id="view_x5F_in_x5F_AR_x5F_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> <rect id="Bounding_Box" x="0" y="0" fill="none" width="24" height="24"/> <g id="Art_layer"> <path d="M3,4c0-0.55,0.45-1,1-1h2V1H4C2.35,1,1,2.35,1,4v2h2V4z"/> <path d="M20,3c0.55,0,1,0.45,1,1v2h2V4c0-1.65-1.35-3-3-3h-2v2H20z"/> <path d="M4,21c-0.55,0-1-0.45-1-1v-2H1v2c0,1.65,1.35,3,3,3h2v-2H4z"/> <path d="M20,21c0.55,0,1-0.45,1-1v-2h2v2c0,1.65-1.35,3-3,3h-2v-2H20z"/> <g> <path d="M18.25,7.6l-5.5-3.18c-0.46-0.27-1.04-0.27-1.5,0L5.75,7.6C5.29,7.87,5,8.36,5,8.9v6.35c0,0.54,0.29,1.03,0.75,1.3 l5.5,3.18c0.46,0.27,1.04,0.27,1.5,0l5.5-3.18c0.46-0.27,0.75-0.76,0.75-1.3V8.9C19,8.36,18.71,7.87,18.25,7.6z M7,14.96v-4.62 l4,2.32v4.61L7,14.96z M12,10.93L8,8.61l4-2.31l4,2.31L12,10.93z M13,17.27v-4.61l4-2.32v4.62L13,17.27z"/> </g> </g> </svg>`; const template = document.createElement('template'); template.innerHTML = ` <style> :host { display: block; position: relative; contain: strict; width: 300px; height: 150px; } /* NOTE: This ruleset is our integration surface area with the * :focus-visible polyfill. * * @see https://github.com/WICG/focus-visible/pull/196 */ :host([data-js-focus-visible]:focus:not(.focus-visible)), :host([data-js-focus-visible]) :focus:not(.focus-visible) { outline: none; } .container { position: relative; } canvas { width: 100%; height: 100%; display: none; } canvas.show { display: block; } .slot { position: absolute; pointer-events: none; top: 0; left: 0; width: 100%; height: 100%; } .slot > * { pointer-events: initial; } .slot.poster { opacity: 0; transition: opacity 0.3s 0.3s; } .slot.poster.show { opacity: 1; transition: none; } .slot.poster > * { pointer-events: initial; } .slot.poster:not(.show) > * { pointer-events: none; } #default-poster { width: 100%; height: 100%; position: absolute; background-size: cover; background-position: center; background-color: var(--poster-color, #fff); background-image: var(--poster-image, none); } #default-progress-bar { display: block; position: relative; width: 100%; height: 100%; pointer-events: none; overflow: hidden; } #default-progress-bar > .mask { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--progress-mask, #fff); transition: opacity 0.3s; opacity: 0.2; } #default-progress-bar > .bar { position: absolute; top: 0; left: 0; width: 100%; height: var(--progress-bar-height, 5px); transition: transform 0.09s; transform-origin: top left; transform: scaleX(0); overflow: hidden; } #default-progress-bar > .bar:before { content: ''; display: block; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--progress-bar-color, rgba(0, 0, 0, 0.4)); transition: none; transform-origin: top left; transform: translateY(