Improve warning in AssetManager, Create MaterialManager.copyMaterialProps, fix camera aspect when canvas has height 0, add undo for some buttons, changes/fixes for ui, handle InteractionPromptPlugin in CameraViewPlugin, support async onStop and onComplete in PopmotionPlugin, allow resetting geometry in BaseGroundPlugin, add pluginListeners, forPlugin in ThreeViewer, add SwitchNodeBasePlugin.snapIcons, fixes in InteractionPromptPlugin, add isEditor, LS_DEFAULT_LOGO in LoadingScreenPlugin, add isEditor in FrameFadePlugin.
1 rok temu Improve warning in AssetManager, Create MaterialManager.copyMaterialProps, fix camera aspect when canvas has height 0, add undo for some buttons, changes/fixes for ui, handle InteractionPromptPlugin in CameraViewPlugin, support async onStop and onComplete in PopmotionPlugin, allow resetting geometry in BaseGroundPlugin, add pluginListeners, forPlugin in ThreeViewer, add SwitchNodeBasePlugin.snapIcons, fixes in InteractionPromptPlugin, add isEditor, LS_DEFAULT_LOGO in LoadingScreenPlugin, add isEditor in FrameFadePlugin.
1 rok temu Improve warning in AssetManager, Create MaterialManager.copyMaterialProps, fix camera aspect when canvas has height 0, add undo for some buttons, changes/fixes for ui, handle InteractionPromptPlugin in CameraViewPlugin, support async onStop and onComplete in PopmotionPlugin, allow resetting geometry in BaseGroundPlugin, add pluginListeners, forPlugin in ThreeViewer, add SwitchNodeBasePlugin.snapIcons, fixes in InteractionPromptPlugin, add isEditor, LS_DEFAULT_LOGO in LoadingScreenPlugin, add isEditor in FrameFadePlugin.
1 rok temu Improve warning in AssetManager, Create MaterialManager.copyMaterialProps, fix camera aspect when canvas has height 0, add undo for some buttons, changes/fixes for ui, handle InteractionPromptPlugin in CameraViewPlugin, support async onStop and onComplete in PopmotionPlugin, allow resetting geometry in BaseGroundPlugin, add pluginListeners, forPlugin in ThreeViewer, add SwitchNodeBasePlugin.snapIcons, fixes in InteractionPromptPlugin, add isEditor, LS_DEFAULT_LOGO in LoadingScreenPlugin, add isEditor in FrameFadePlugin.
1 rok temu Improve warning in AssetManager, Create MaterialManager.copyMaterialProps, fix camera aspect when canvas has height 0, add undo for some buttons, changes/fixes for ui, handle InteractionPromptPlugin in CameraViewPlugin, support async onStop and onComplete in PopmotionPlugin, allow resetting geometry in BaseGroundPlugin, add pluginListeners, forPlugin in ThreeViewer, add SwitchNodeBasePlugin.snapIcons, fixes in InteractionPromptPlugin, add isEditor, LS_DEFAULT_LOGO in LoadingScreenPlugin, add isEditor in FrameFadePlugin.
1 rok temu |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- import {createDiv, createStyles, onChange, serialize, timeout} from 'ts-browser-helpers'
- import styles from './LoadingScreenPlugin.css?inline'
- import spinner1 from './loaders/spinner1.css?inline'
- import {uiButton, uiDropdown, uiFolderContainer, uiInput, uiSlider, uiToggle} from 'uiconfig.js'
- import {AAssetManagerProcessStatePlugin} from '../base/AAssetManagerProcessStatePlugin'
- import {ThreeViewer} from '../../viewer'
-
- /**
- * Loading Screen Plugin
- *
- * Shows a configurable loading screen overlay over the canvas.
- *
- * @category Plugins
- */
- @uiFolderContainer('Loading Screen')
- export class LoadingScreenPlugin extends AAssetManagerProcessStatePlugin {
- public static readonly PluginType = 'LoadingScreenPlugin'
-
- styles = styles
-
- spinners = [{
- styles: spinner1,
- html: '<span class="loader"></span>',
- }]
- refresh() {
- if (!this._viewer) return
- this._updateMainDiv(this._isPreviewing ? this._previewState : this._viewer.assetManager.processState, false)
- }
-
- @uiDropdown('Loader', ['Spinner 1'].map((v, i) => ({value: i, label: v})))
- @serialize() loader = 0
-
- @uiInput('Loading text header')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() loadingTextHeader = 'Loading Files'
- @uiInput('Error text header')
- @serialize() errorTextHeader = 'Error Loading Files'
-
- @uiToggle('Show file names')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() showFileNames = true
-
- @uiToggle('Show process states')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() showProcessStates = true
-
- @uiToggle('Show progress')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() showProgress = true
-
- @uiToggle('Hide on only errors')
- @serialize() hideOnOnlyErrors = true
- @uiToggle('Hide on files load')
- @serialize() hideOnFilesLoad = true
- @uiToggle('Hide on scene object load')
- @serialize() hideOnSceneObjectLoad = false
- /**
- * Minimize when scene has objects
- * Note: also checks for scene.environment and doesnt minimize when environment is null or undefined
- * @default true
- */
- @uiToggle('Minimize on scene object load')
- @serialize() minimizeOnSceneObjectLoad = true
-
- @uiToggle('Show when files start loading')
- @serialize() showOnFilesLoading = true
- @uiToggle('Show when scene empty')
- @serialize() showOnSceneEmpty = true
-
- @uiInput('Hide delay (ms)')
- @serialize() hideDelay = 500
-
- @uiSlider('Background Opacity', [0, 1])
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() backgroundOpacity = 0.5
-
- @uiSlider('Background Blur', [0, 100])
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() backgroundBlur = 24
-
- @uiInput('Background Color')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() background = '#ffffff'
-
- @uiInput('Text Color')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() textColor = '#222222'
-
- static LS_DEFAULT_LOGO = 'https://threepipe.org/logo.svg'
-
- @uiInput('Logo Image')
- @onChange(LoadingScreenPlugin.prototype.refresh)
- @serialize() logoImage = LoadingScreenPlugin.LS_DEFAULT_LOGO
-
- private _isPreviewing = false
- private _previewState = new Map([['file.glb', {state: 'downloading', progress: 50}], ['environment.hdr', {state: 'adding'}]])
-
- @uiButton('Toggle preview')
- togglePreview() {
- this.maximize()
- this._isPreviewing = !this._isPreviewing
- this.refresh()
- if (this._isPreviewing)
- this.show()
- else
- this.hideWithDelay()
- }
-
- loadingElement = createDiv({classList: ['loadingScreenLoadingElement'], addToBody: false})
- filesElement = createDiv({classList: ['loadingScreenFilesElement'], addToBody: false})
- logoElement = createDiv({classList: ['loadingScreenLogoElement'], addToBody: false})
-
- constructor(container?: HTMLElement) {
- super('LoadingScreen', container)
- // const popupClose = createDiv({
- // id: 'assetManagerLoadingScreenClose',
- // addToBody: false,
- // innerHTML: '✕',
- // })
- // popupClose.addEventListener('click', () => {
- // this._mainDiv.style.display = 'none'
- // })
- // this._mainDiv.appendChild(popupClose)
-
- this._mainDiv.prepend(this.loadingElement)
- this._mainDiv.prepend(this.logoElement)
- this._mainDiv.appendChild(this.filesElement)
- }
-
- private _isHidden = false
-
- get visible() {
- return !this._isHidden
- }
-
- async hide() {
- this._isHidden = true
- this._mainDiv.style.opacity = '0'
- await timeout(502)
- if (this._isHidden) {
- this._mainDiv.style.display = 'none'
- this._showMainDiv()
- }
- }
- async hideWithDelay() {
- this._isHidden = true
- await timeout(this.hideDelay)
- if (!this._isHidden) return
- return this.hide()
- }
- show() {
- if (!this._isHidden) return
- this._isHidden = false
- this._showMainDiv()
- this._mainDiv.style.display = 'flex'
- }
-
- protected _showMainDiv() {
- // this._mainDiv.style.opacity = this.opacity.toString()
- this._mainDiv.style.opacity = '1'
- }
- @uiButton('Minimize')
- minimize() {
- this._mainDiv.classList.add('minimizedLoadingScreen')
- if (!this.showFileNames) this.loadingElement.style.display = 'block'
- }
- @uiButton('Maximize')
- maximize() {
- this._mainDiv.classList.remove('minimizedLoadingScreen')
- this.loadingElement.style.display = ''
- }
-
- private _temp = document.createElement('template')
- private _setHTML(elem: HTMLElement, html:string) {
- this._temp.innerHTML = html
- // Compare the parsed content instead of raw strings, as browsers might change html after setting.
- if (this._temp.innerHTML.trim() !== elem.innerHTML.trim()) elem.innerHTML = html
- }
-
- protected _updateMainDiv(processState: Map<string, {state: string, progress?: number|undefined}>, updateVisibility = true) {
- if (!this._viewer) return
- if (!this._contentDiv) return
- if (!this.enabled) {
- this._mainDiv.style.display = 'none'
- return
- }
- if (this.showFileNames) {
- let text = ''
- processState.forEach((v, k) => {
- text += (this.showProcessStates ? `<span class="loadingScreenProcessState">${v.state}</span>: ` : '') +
- (k || '').split('/').pop() +
- (this.showProgress && v.progress ? ' - ' + (v.progress.toFixed(0) + '%') : '') +
- '<br>'
- })
- this._setHTML(this.filesElement, text)
- } else {
- this._setHTML(this.filesElement, '')
- }
- const errors = [...processState.values()].filter(v => v.state === 'error')
- if (errors.length > 0 && errors.length === processState.size && !this.hideOnOnlyErrors) {
- this._setHTML(this._contentDiv, this.errorTextHeader)
- } else {
- this._setHTML(this._contentDiv, this.loadingTextHeader)
- }
- this._setHTML(this.loadingElement, this.spinners[this.loader].html)
- this._mainDiv.style.setProperty('--b-opacity', this.backgroundOpacity.toString())
- this._mainDiv.style.setProperty('--b-background', this.background)
- ;(this._mainDiv.style as any).backdropFilter = `blur(${this.backgroundBlur}px)`
- this._mainDiv.style.color = this.textColor
- this._setHTML(this.logoElement, this.logoImage ? `<img class="loadingScreenLogoImage" src="${this.logoImage}"/>` : '')
- if (updateVisibility) {
- this._updateVisibility(processState, errors.length)
- }
- }
-
- protected _updateVisibility(processState: Map<string, {state: string, progress?: number|undefined}>, errors: number) {
- if (!this._viewer) return false
- if (this.hideOnFilesLoad && (processState.size === 0 ||
- errors === processState.size && this.hideOnOnlyErrors) && !this._isHidden) {
- this.hideDelay ? this.hideWithDelay() : this.hide()
- return true
- } else if (processState.size > 0 && this.showOnFilesLoading && this._isHidden) {
- const sceneObjects = this._viewer.scene.modelRoot.children
- if (sceneObjects.length > 0 && this.minimizeOnSceneObjectLoad && this._viewer.scene.environment) this.minimize()
- else this.maximize()
- this.show()
- return true
- }
- return false
- }
-
- // disables showOnSceneEmpty
- isEditor = false
-
- private _sceneUpdate = (e: any) => {
- if (!this._viewer) return
- if (!e.hierarchyChanged) return
- const sceneObjects = this._viewer.scene.modelRoot.children
- if (sceneObjects.length === 0 && this.showOnSceneEmpty && !this.isEditor) {
- this.show()
- }
- if (sceneObjects.length > 0) {
- // case - objects loaded, clear current scene, load loaded objects
- // load - process state 0, hide with delay. clear scene shows loading screen, loading current object doesnt change process state...
- const processState = this._viewer.assetManager.processState
- const errors = [...processState.values()].filter(v => v.state === 'error')
- if (!this._updateVisibility(processState, errors.length)) {
- if (this.hideOnSceneObjectLoad)
- this.hideWithDelay()
- else if (this.minimizeOnSceneObjectLoad && this._viewer.scene.environment)
- timeout(this.hideDelay + 300).then(() => this.minimize())
- }
- } else if (this.minimizeOnSceneObjectLoad)
- this.maximize()
- }
-
- stylesheet?: HTMLStyleElement
- stylesheetLoader?: HTMLStyleElement[]
- onAdded(viewer: ThreeViewer) {
- this.stylesheet = createStyles(this.styles, viewer.container)
- this.stylesheetLoader = this.spinners.map(s => createStyles(s.styles, viewer.container))
-
- viewer.scene.addEventListener('sceneUpdate', this._sceneUpdate)
- super.onAdded(viewer)
- }
- onRemove(viewer: ThreeViewer) {
- viewer.scene.removeEventListener('sceneUpdate', this._sceneUpdate)
- this.stylesheet?.remove()
- this.stylesheet = undefined
- this.stylesheetLoader?.forEach(s => s.remove())
- this.stylesheetLoader = undefined
- return super.onRemove(viewer)
- }
- }
-
|