UNPKG

cione-comp-lib

Version:

`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`

432 lines (431 loc) 16.3 kB
import { ReactiveElement as d } from "../../../_@lit_reactive-element@1.6.1@@lit/reactive-element/reactive-element.mjs"; import "../../../_lit-html@2.7.0@lit-html/lit-html.mjs"; import "../../../_lit-element@3.3.0@lit-element/lit-element.mjs"; import { property as e } from "../../../_@lit_reactive-element@1.6.1@@lit/reactive-element/decorators/property.mjs"; import "../../../_@lit_reactive-element@1.6.1@@lit/reactive-element/decorators/query-assigned-elements.mjs"; import { HAS_RESIZE_OBSERVER, HAS_INTERSECTION_OBSERVER } from "./constants.mjs"; import { $updateEnvironment } from "./features/environment.mjs"; import { makeTemplate } from "./template.mjs"; import { CachingGLTFLoader, $evictionPolicy } from "./three-components/CachingGLTFLoader.mjs"; import { ModelScene } from "./three-components/ModelScene.mjs"; import { Renderer } from "./three-components/Renderer.mjs"; import { debounce, clamp } from "./utilities.mjs"; import { dataUrlToBlob } from "./utilities/data-conversion.mjs"; import { ProgressTracker } from "./utilities/progress-tracker.mjs"; /* @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 __decorate = globalThis && globalThis.__decorate || function(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d2; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d2 = decorators[i]) r = (c < 3 ? d2(r) : c > 3 ? d2(target, key, r) : d2(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; const CLEAR_MODEL_TIMEOUT_MS = 10; const FALLBACK_SIZE_UPDATE_THRESHOLD_MS = 50; const ANNOUNCE_MODEL_VISIBILITY_DEBOUNCE_THRESHOLD = 0; const UNSIZED_MEDIA_WIDTH = 300; const UNSIZED_MEDIA_HEIGHT = 150; const blobCanvas = document.createElement("canvas"); const $fallbackResizeHandler = Symbol("fallbackResizeHandler"); const $defaultAriaLabel = Symbol("defaultAriaLabel"); const $resizeObserver = Symbol("resizeObserver"); const $clearModelTimeout = Symbol("clearModelTimeout"); const $onContextLost = Symbol("onContextLost"); const $loaded = Symbol("loaded"); const $status = Symbol("status"); const $onFocus = Symbol("onFocus"); const $onBlur = Symbol("onBlur"); const $updateSize = Symbol("updateSize"); const $intersectionObserver = Symbol("intersectionObserver"); const $isElementInViewport = Symbol("isElementInViewport"); const $announceModelVisibility = Symbol("announceModelVisibility"); const $ariaLabel = Symbol("ariaLabel"); const $altDefaulted = Symbol("altDefaulted"); const $statusElement = Symbol("statusElement"); const $updateStatus = Symbol("updateStatus"); const $loadedTime = Symbol("loadedTime"); const $updateSource = Symbol("updateSource"); const $markLoaded = Symbol("markLoaded"); const $container = Symbol("container"); const $userInputElement = Symbol("input"); const $canvas = Symbol("canvas"); const $scene = Symbol("scene"); const $needsRender = Symbol("needsRender"); const $tick = Symbol("tick"); const $onModelLoad = Symbol("onModelLoad"); const $onResize = Symbol("onResize"); const $renderer = Symbol("renderer"); const $progressTracker = Symbol("progressTracker"); const $getLoaded = Symbol("getLoaded"); const $getModelIsVisible = Symbol("getModelIsVisible"); const $shouldAttemptPreload = Symbol("shouldAttemptPreload"); const toVector3D = (v) => { return { x: v.x, y: v.y, z: v.z, toString() { return `${this.x}m ${this.y}m ${this.z}m`; } }; }; const toVector2D = (v) => { return { u: v.x, v: v.y, toString() { return `${this.u} ${this.v}`; } }; }; class ModelViewerElementBase extends d { constructor() { super(); this.alt = null; this.src = null; this.withCredentials = false; this.generateSchema = false; this[_a] = false; this[_b] = false; this[_c] = 0; this[_d] = ""; this[_e] = null; this[_f] = debounce(() => { const boundingRect = this.getBoundingClientRect(); this[$updateSize](boundingRect); }, FALLBACK_SIZE_UPDATE_THRESHOLD_MS); this[_g] = debounce((oldVisibility) => { const newVisibility = this.modelIsVisible; if (newVisibility !== oldVisibility) { this.dispatchEvent(new CustomEvent("model-visibility", { detail: { visible: newVisibility } })); } }, ANNOUNCE_MODEL_VISIBILITY_DEBOUNCE_THRESHOLD); this[_h] = null; this[_j] = null; this[_k] = new ProgressTracker(); this[_l] = () => { this[$statusElement].textContent = this[$status]; }; this[_m] = () => { this[$statusElement].textContent = ""; }; this[_o] = (event) => { this.dispatchEvent(new CustomEvent("error", { detail: { type: "webglcontextlost", sourceError: event.sourceEvent } })); }; this.attachShadow({ mode: "open" }); const shadowRoot = this.shadowRoot; makeTemplate(shadowRoot); this[$container] = shadowRoot.querySelector(".container"); this[$userInputElement] = shadowRoot.querySelector(".userInput"); this[$canvas] = shadowRoot.querySelector("canvas"); this[$statusElement] = shadowRoot.querySelector("#status"); this[$defaultAriaLabel] = this[$userInputElement].getAttribute("aria-label"); let width, height; if (this.isConnected) { const rect = this.getBoundingClientRect(); width = rect.width; height = rect.height; } else { width = UNSIZED_MEDIA_WIDTH; height = UNSIZED_MEDIA_HEIGHT; } this[$scene] = new ModelScene({ canvas: this[$canvas], element: this, width, height }); Promise.resolve().then(() => { this[$updateSize](this.getBoundingClientRect()); }); if (HAS_RESIZE_OBSERVER) { this[$resizeObserver] = new ResizeObserver((entries) => { if (this[$renderer].isPresenting) { return; } for (let entry of entries) { if (entry.target === this) { this[$updateSize](entry.contentRect); } } }); } if (HAS_INTERSECTION_OBSERVER) { this[$intersectionObserver] = new IntersectionObserver((entries) => { for (let entry of entries) { if (entry.target === this) { const oldVisibility = this.modelIsVisible; this[$isElementInViewport] = entry.isIntersecting; this[$announceModelVisibility](oldVisibility); if (this[$isElementInViewport] && !this.loaded) { this[$updateSource](); } } } }, { root: null, rootMargin: "0px", threshold: 1e-5 }); } else { this[$isElementInViewport] = true; } } static get is() { return "model-viewer"; } static set modelCacheSize(value) { CachingGLTFLoader[$evictionPolicy].evictionThreshold = value; } static get modelCacheSize() { return CachingGLTFLoader[$evictionPolicy].evictionThreshold; } static set minimumRenderScale(value) { if (value > 1) { console.warn("<model-viewer> minimumRenderScale has been clamped to a maximum value of 1."); } if (value <= 0) { console.warn("<model-viewer> minimumRenderScale has been clamped to a minimum value of 0.25."); } Renderer.singleton.minScale = value; } static get minimumRenderScale() { return Renderer.singleton.minScale; } get loaded() { return this[$getLoaded](); } get [(_a = $isElementInViewport, _b = $loaded, _c = $loadedTime, _d = $status, _e = $clearModelTimeout, _f = $fallbackResizeHandler, _g = $announceModelVisibility, _h = $resizeObserver, _j = $intersectionObserver, _k = $progressTracker, $renderer)]() { return Renderer.singleton; } get modelIsVisible() { return this[$getModelIsVisible](); } connectedCallback() { super.connectedCallback && super.connectedCallback(); if (HAS_RESIZE_OBSERVER) { this[$resizeObserver].observe(this); } else { self.addEventListener("resize", this[$fallbackResizeHandler]); } if (HAS_INTERSECTION_OBSERVER) { this[$intersectionObserver].observe(this); } this.addEventListener("focus", this[$onFocus]); this.addEventListener("blur", this[$onBlur]); const renderer = this[$renderer]; renderer.addEventListener("contextlost", this[$onContextLost]); renderer.registerScene(this[$scene]); if (this[$clearModelTimeout] != null) { self.clearTimeout(this[$clearModelTimeout]); this[$clearModelTimeout] = null; this.requestUpdate("src", null); } } disconnectedCallback() { super.disconnectedCallback && super.disconnectedCallback(); if (HAS_RESIZE_OBSERVER) { this[$resizeObserver].unobserve(this); } else { self.removeEventListener("resize", this[$fallbackResizeHandler]); } if (HAS_INTERSECTION_OBSERVER) { this[$intersectionObserver].unobserve(this); } this.removeEventListener("focus", this[$onFocus]); this.removeEventListener("blur", this[$onBlur]); const renderer = this[$renderer]; renderer.removeEventListener("contextlost", this[$onContextLost]); renderer.unregisterScene(this[$scene]); this[$clearModelTimeout] = self.setTimeout(() => { this[$scene].dispose(); this[$clearModelTimeout] = null; }, CLEAR_MODEL_TIMEOUT_MS); } updated(changedProperties) { super.updated(changedProperties); if (changedProperties.has("src")) { if (this.src == null) { this[$loaded] = false; this[$loadedTime] = 0; this[$scene].reset(); } else if (this.src !== this[$scene].url) { this[$loaded] = false; this[$loadedTime] = 0; this[$updateSource](); } } if (changedProperties.has("alt")) { this[$userInputElement].setAttribute("aria-label", this[$ariaLabel]); } if (changedProperties.has("withCredentials")) { CachingGLTFLoader.withCredentials = this.withCredentials; this[$renderer].textureUtils.withCredentials = this.withCredentials; } if (changedProperties.has("generateSchema")) { if (this.generateSchema) { this[$scene].updateSchema(this.src); } else { this[$scene].updateSchema(null); } } } toDataURL(type, encoderOptions) { return this[$renderer].displayCanvas(this[$scene]).toDataURL(type, encoderOptions); } async toBlob(options) { const mimeType = options ? options.mimeType : void 0; const qualityArgument = options ? options.qualityArgument : void 0; const useIdealAspect = options ? options.idealAspect : void 0; const { width, height, idealAspect, aspect } = this[$scene]; const { dpr, scaleFactor } = this[$renderer]; let outputWidth = width * scaleFactor * dpr; let outputHeight = height * scaleFactor * dpr; let offsetX = 0; let offsetY = 0; if (useIdealAspect === true) { if (idealAspect > aspect) { const oldHeight = outputHeight; outputHeight = Math.round(outputWidth / idealAspect); offsetY = (oldHeight - outputHeight) / 2; } else { const oldWidth = outputWidth; outputWidth = Math.round(outputHeight * idealAspect); offsetX = (oldWidth - outputWidth) / 2; } } blobCanvas.width = outputWidth; blobCanvas.height = outputHeight; try { return new Promise(async (resolve, reject) => { blobCanvas.getContext("2d").drawImage(this[$renderer].displayCanvas(this[$scene]), offsetX, offsetY, outputWidth, outputHeight, 0, 0, outputWidth, outputHeight); if (blobCanvas.msToBlob) { if (!mimeType || mimeType === "image/png") { return resolve(blobCanvas.msToBlob()); } } if (!blobCanvas.toBlob) { return resolve(await dataUrlToBlob(blobCanvas.toDataURL(mimeType, qualityArgument))); } blobCanvas.toBlob((blob) => { if (!blob) { return reject(new Error("Unable to retrieve canvas blob")); } resolve(blob); }, mimeType, qualityArgument); }); } finally { this[$updateSize]({ width, height }); } } registerRenderer(renderer) { this[$scene].externalRenderer = renderer; } unregisterRenderer() { this[$scene].externalRenderer = null; } get [$ariaLabel]() { return this[$altDefaulted]; } get [$altDefaulted]() { return this.alt == null || this.alt === "null" ? this[$defaultAriaLabel] : this.alt; } [$getLoaded]() { return this[$loaded]; } [$getModelIsVisible]() { return this.loaded && this[$isElementInViewport]; } [$shouldAttemptPreload]() { return !!this.src && this[$isElementInViewport]; } [$updateSize]({ width, height }) { if (width === 0 || height === 0) { return; } this[$container].style.width = `${width}px`; this[$container].style.height = `${height}px`; this[$onResize]({ width, height }); } [$tick](_time, _delta) { } [$markLoaded]() { if (this[$loaded]) { return; } this[$loaded] = true; this[$loadedTime] = performance.now(); } [$needsRender]() { this[$scene].queueRender(); } [$onModelLoad]() { } [$updateStatus](status) { this[$status] = status; const rootNode = this.getRootNode(); if (rootNode != null && rootNode.activeElement === this && this[$statusElement].textContent != status) { this[$statusElement].textContent = status; } } [(_l = $onFocus, _m = $onBlur, $onResize)](e2) { this[$scene].setSize(e2.width, e2.height); } async [(_o = $onContextLost, $updateSource)]() { const scene = this[$scene]; if (this.loaded || !this[$shouldAttemptPreload]() || this.src === scene.url) { return; } if (this.generateSchema) { scene.updateSchema(this.src); } this[$updateStatus]("Loading"); scene.stopAnimation(); const updateSourceProgress = this[$progressTracker].beginActivity(); const source = this.src; try { const srcUpdated = scene.setSource(source, (progress) => updateSourceProgress(clamp(progress, 0, 1) * 0.95)); const envUpdated = this[$updateEnvironment](); await Promise.all([srcUpdated, envUpdated]); this[$markLoaded](); this[$onModelLoad](); await new Promise((resolve) => { requestAnimationFrame(() => { requestAnimationFrame(() => { this.dispatchEvent(new CustomEvent("load", { detail: { url: source } })); resolve(); }); }); }); } catch (error) { this.dispatchEvent(new CustomEvent("error", { detail: { type: "loadfailure", sourceError: error } })); } finally { updateSourceProgress(1); } } } __decorate([ e({ type: String }) ], ModelViewerElementBase.prototype, "alt", void 0); __decorate([ e({ type: String }) ], ModelViewerElementBase.prototype, "src", void 0); __decorate([ e({ type: Boolean, attribute: "with-credentials" }) ], ModelViewerElementBase.prototype, "withCredentials", void 0); __decorate([ e({ type: Boolean, attribute: "generate-schema" }) ], ModelViewerElementBase.prototype, "generateSchema", void 0); export { $altDefaulted, $announceModelVisibility, $ariaLabel, $canvas, $container, $getLoaded, $getModelIsVisible, $intersectionObserver, $isElementInViewport, $loadedTime, $markLoaded, $needsRender, $onModelLoad, $onResize, $progressTracker, $renderer, $scene, $shouldAttemptPreload, $statusElement, $tick, $updateSize, $updateSource, $updateStatus, $userInputElement, blobCanvas, ModelViewerElementBase as default, toVector2D, toVector3D };