cione-comp-lib
Version:
`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`
432 lines (431 loc) • 16.3 kB
JavaScript
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 };