Procházet zdrojové kódy

Refactor processStates to AssetManager.

master
Palash Bansal před 2 roky
rodič
revize
3ca2a4f00e
Žádný účet není propojen s e-mailovou adresou tvůrce revize

+ 186
- 127
src/assetmanager/AssetManager.ts Zobrazit soubor

* Utility class to manage import, export, and material management. * Utility class to manage import, export, and material management.
* @category Asset Manager * @category Asset Manager
*/ */
export class AssetManager extends EventDispatcher<BaseEvent&{data: ImportResult}, 'loadAsset'> {
export class AssetManager extends EventDispatcher<BaseEvent&{data?: ImportResult}, 'loadAsset'|'processStateUpdate'> {
readonly viewer: ThreeViewer readonly viewer: ThreeViewer
readonly importer: AssetImporter readonly importer: AssetImporter
readonly exporter: AssetExporter readonly exporter: AssetExporter
readonly materials: MaterialManager readonly materials: MaterialManager
private _storage?: Cache | Storage private _storage?: Cache | Storage
get storage() {return this._storage}
get storage() {
return this._storage
}


constructor(viewer: ThreeViewer, {simpleCache = false, storage}: AssetManagerOptions = {}) { constructor(viewer: ThreeViewer, {simpleCache = false, storage}: AssetManagerOptions = {}) {
super() super()
this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated) this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated)
this._initCacheStorage(simpleCache, storage ?? true) this._initCacheStorage(simpleCache, storage ?? true)


this.importer.addEventListener('processRaw', (event)=>{
// console.log('preprocess mat', mat)
const mat = event.data as IMaterial
if (!mat || !mat.isMaterial || !mat.uuid) return
if (this.materials?.findMaterial(mat.uuid)) {
console.warn('imported material uuid already exists, creating new uuid')
mat.uuid = generateUUID()
if (mat.userData.uuid) mat.userData.uuid = mat.uuid
}
// todo: check for name exists also
this.materials.registerMaterial(mat)
})

this.importer.addEventListener('processRawStart', (event)=>{
// console.log('preprocess mat', mat)
const res = event.data!
const options = event.options! as ProcessRawOptions
// if (!res.assetType) {
// if (res.isBufferGeometry) { // for eg stl todo
// res = new Mesh(res, new MeshStandardMaterial())
// }
// if (res.isObject3D) {
// }
// }
if (res.isObject3D) {
const cameras: Camera[] = []
const lights: Light[] = []
res.traverse((obj: any) => {
if (obj.material) {
const materials = Array.isArray(obj.material) ? obj.material : [obj.material]
const newMaterials = []
for (const material of materials) {
const mat = this.materials.convertToIMaterial(material, {createFromTemplate: options.replaceMaterials !== false}) || material
mat.uuid = material.uuid
mat.userData.uuid = material.uuid
newMaterials.push(mat)
}
if (Array.isArray(obj.material)) obj.material = newMaterials
else obj.material = newMaterials[0]
}
if (obj.isCamera) cameras.push(obj)
if (obj.isLight) lights.push(obj)
})
for (const camera of cameras) {
if ((camera as PerspectiveCamera2).assetType === 'camera') continue
// todo: OrthographicCamera
if (!(camera as PerspectiveCamera).isPerspectiveCamera || !camera.parent || options.replaceCameras === false) {
iCameraCommons.upgradeCamera.call(camera)
} else {
const newCamera: ICamera = (camera as any).iCamera ??
new PerspectiveCamera2('', this.viewer.canvas)
if (camera === newCamera) continue
camera.parent.children.splice(camera.parent.children.indexOf(camera), 1, newCamera)
newCamera.parent = camera.parent as any
newCamera.copy(camera as any)
camera.parent = null
;(newCamera as any).uuid = camera.uuid
newCamera.userData.uuid = camera.uuid
;(camera as any).iCamera = newCamera
// console.log('replacing camera', camera, newCamera)
}
}
for (const light of lights) {
if ((light as ILight).assetType === 'light') continue
if (!light.parent || options.replaceLights === false) {
iLightCommons.upgradeLight.call(light)
} else {
const newLight: ILight|undefined = (light as any).iLight ??
(light as any).isDirectionalLight ? new DirectionalLight2() :
(light as any).isPointLight ? new PointLight2() :
(light as any).isSpotLight ? new SpotLight2() :
(light as any).isAmbientLight ? new AmbientLight2() :
(light as any).isHemisphereLight ? new HemisphereLight2() :
(light as any).isRectAreaLight ? new RectAreaLight2() :
undefined
if (light === newLight || !newLight) continue
light.parent.children.splice(light.parent.children.indexOf(light), 1, newLight)
newLight.parent = light.parent as any
newLight.copy(light as any)
light.parent = null
;(newLight as any).uuid = light.uuid
newLight.userData.uuid = light.uuid
;(light as any).iLight = newLight
}
}

iObjectCommons.upgradeObject3D.call(res)
} else if (res.isMaterial) {
iMaterialCommons.upgradeMaterial.call(res)
// todo update res by generating new material?
} else if (res.isTexture) {
upgradeTexture.call(res)

if (event?.options?.generateMipmaps !== undefined)
res.generateMipmaps = event?.options.generateMipmaps
if (!res.generateMipmaps && !res.isRenderTargetTexture) { // todo: do we need to check more?
res.minFilter = res.minFilter === LinearMipmapLinearFilter ? LinearFilter : res.minFilter
res.magFilter = res.magFilter === LinearMipmapLinearFilter ? LinearFilter : res.magFilter
}

}
// todo other asset/object types?
})

this._setupObjectProcess()
this._setupProcessState()
this._addImporters() this._addImporters()
this._addExporters() this._addExporters()


} }


async addAsset<T extends ImportResult = ImportResult>(assetOrPath?: string | IAsset | IAsset[] | File | File[], options?: ImportAddOptions): Promise<(T|undefined)[]> {
async addAsset<T extends ImportResult = ImportResult>(assetOrPath?: string | IAsset | IAsset[] | File | File[], options?: ImportAddOptions): Promise<(T | undefined)[]> {
if (!this.importer || !this.viewer) return [] if (!this.importer || !this.viewer) return []
const imported = await this.importer.import<T>(assetOrPath, options) const imported = await this.importer.import<T>(assetOrPath, options)
if (!imported) { if (!imported) {
console.warn('Unable to import', assetOrPath, imported) console.warn('Unable to import', assetOrPath, imported)
return [] return []
} }
return this.loadImported<(T|undefined)[]>(imported, options)
return this.loadImported<(T | undefined)[]>(imported, options)
} }


// materials: IMaterial[] = [] // materials: IMaterial[] = []
// textures: ITexture[] = [] // textures: ITexture[] = []


// todo move this function to viewer // todo move this function to viewer
async loadImported<T extends ValOrArr<ImportResult|undefined> = ImportResult>(imported: T, {autoSetEnvironment = true, autoSetBackground = false, ...options}: AddAssetOptions = {}): Promise<T | never[]> {
const arr: (ImportResult|undefined)[] = Array.isArray(imported) ? imported : [imported]
async loadImported<T extends ValOrArr<ImportResult | undefined> = ImportResult>(imported: T, {
autoSetEnvironment = true,
autoSetBackground = false,
...options
}: AddAssetOptions = {}): Promise<T | never[]> {
const arr: (ImportResult | undefined)[] = Array.isArray(imported) ? imported : [imported]
let ret: T = Array.isArray(imported) ? [] : undefined as any let ret: T = Array.isArray(imported) ? [] : undefined as any


for (const obj of arr) { for (const obj of arr) {
case 'model': case 'model':
case 'light': case 'light':
case 'camera': case 'camera':
r = await this.viewer.addSceneObject(<IObject3D|RootSceneImportResult>obj, options) // todo update references in scene update event
r = await this.viewer.addSceneObject(<IObject3D | RootSceneImportResult>obj, options) // todo update references in scene update event
break break
case 'config': case 'config':
if (options?.importConfig !== false) await this.viewer.importConfig(<ISerializedConfig>obj) if (options?.importConfig !== false) await this.viewer.importConfig(<ISerializedConfig>obj)


// legacy // legacy
if (obj.type && typeof obj.type === 'string' && (Array.isArray((obj as any).plugins) || if (obj.type && typeof obj.type === 'string' && (Array.isArray((obj as any).plugins) ||
(obj as any).type === 'ThreeViewer' || this.viewer.getPlugin((obj as any).type))) {
(obj as any).type === 'ThreeViewer' || this.viewer.getPlugin((obj as any).type))) {
await this.viewer.importConfig(<ISerializedConfig>obj) await this.viewer.importConfig(<ISerializedConfig>obj)
} }
break break
} }
this.dispatchEvent({type: 'loadAsset', data: obj})
this.dispatchEvent({type: 'loadAsset', data: obj})
if (Array.isArray(ret)) ret.push(r) if (Array.isArray(ret)) ret.push(r)
else ret = r as T else ret = r as T
} }
* @param imported * @param imported
* @param options * @param options
*/ */
async addProcessedAssets<T extends ImportResult|undefined = ImportResult>(imported: (T|undefined)[], options?: AddAssetOptions): Promise<(T | undefined)[]> {
async addProcessedAssets<T extends ImportResult | undefined = ImportResult>(imported: (T | undefined)[], options?: AddAssetOptions): Promise<(T | undefined)[]> {
return this.loadImported(imported, options) return this.loadImported(imported, options)
} }


async addAssetSingle<T extends ImportResult = ImportResult>(asset?: string | IAsset | File, options?: ImportAssetOptions): Promise<T|undefined> {
async addAssetSingle<T extends ImportResult = ImportResult>(asset?: string | IAsset | File, options?: ImportAssetOptions): Promise<T | undefined> {
return !asset ? undefined : (await this.addAsset<T>(asset, options))?.[0] return !asset ? undefined : (await this.addAsset<T>(asset, options))?.[0]
} }


// processAndAddObjects // processAndAddObjects
async addRaw<T extends (ImportResult|undefined) = ImportResult>(res: T|T[], options: AddRawOptions = {}): Promise<(T|undefined)[]> {
async addRaw<T extends (ImportResult | undefined) = ImportResult>(res: T | T[], options: AddRawOptions = {}): Promise<(T | undefined)[]> {
const r = await this.importer.processRaw<T>(res, options) const r = await this.importer.processRaw<T>(res, options)
return this.loadImported<T[]>(r, options) return this.loadImported<T[]>(r, options)
} }
async addRawSingle<T extends ImportResult|undefined = ImportResult|undefined>(res: T, options: AddRawOptions = {}): Promise<T|undefined> {

async addRawSingle<T extends ImportResult | undefined = ImportResult | undefined>(res: T, options: AddRawOptions = {}): Promise<T | undefined> {
return (await this.addRaw<T>(res, options))?.[0] return (await this.addRaw<T>(res, options))?.[0]
} }


if (data.metadata?.type !== 'Material') { if (data.metadata?.type !== 'Material') {
console.warn('Invalid material data', data) console.warn('Invalid material data', data)
} }
JSONMaterialLoader.DeserializeMaterialJSON(data, this.viewer, meta, event.material).then(()=>{
JSONMaterialLoader.DeserializeMaterialJSON(data, this.viewer, meta, event.material).then(() => {
// //
}) })
} }
dispose() { dispose() {
this.importer.dispose() this.importer.dispose()
this.materials.dispose() this.materials.dispose()
this.processState.clear()
this.viewer.scene.removeEventListener('addSceneObject', this._sceneUpdated) this.viewer.scene.removeEventListener('addSceneObject', this._sceneUpdated)
this.viewer.scene.removeEventListener('materialChanged', this._sceneUpdated) this.viewer.scene.removeEventListener('materialChanged', this._sceneUpdated)
this.exporter.dispose() this.exporter.dispose()
], false), // todo: use ImageBitmapLoader if supported (better performance) ], false), // todo: use ImageBitmapLoader if supported (better performance)


new Importer<JSONMaterialLoader>(JSONMaterialLoader, new Importer<JSONMaterialLoader>(JSONMaterialLoader,
['mat', ...this.materials.templates.map(t=>t.typeSlug!).filter(v=>v)], // todo add others
[], false, (loader)=>{
['mat', ...this.materials.templates.map(t => t.typeSlug!).filter(v => v)], // todo add others
[], false, (loader) => {
if (loader) loader.viewer = this.viewer if (loader) loader.viewer = this.viewer
return loader return loader
}), }),


protected _addExporters() { protected _addExporters() {
const exporters: IExporter[] = [ const exporters: IExporter[] = [
{ext: ['gltf', 'glb'], extensions: [], ctor: (_, exporter)=>{
const ex = new GLTFExporter2()
// This should be added at the end.
ex.setup(this.viewer, exporter.extensions)
return ex
}},
{
ext: ['gltf', 'glb'], extensions: [], ctor: (_, exporter) => {
const ex = new GLTFExporter2()
// This should be added at the end.
ex.setup(this.viewer, exporter.extensions)
return ex
},
},
] ]


this.exporter.addExporter(...exporters) this.exporter.addExporter(...exporters)
} }




protected _setupObjectProcess() {
this.importer.addEventListener('processRaw', (event) => {
// console.log('preprocess mat', mat)
const mat = event.data as IMaterial
if (!mat || !mat.isMaterial || !mat.uuid) return
if (this.materials?.findMaterial(mat.uuid)) {
console.warn('imported material uuid already exists, creating new uuid')
mat.uuid = generateUUID()
if (mat.userData.uuid) mat.userData.uuid = mat.uuid
}
// todo: check for name exists also
this.materials.registerMaterial(mat)
})

this.importer.addEventListener('processRawStart', (event) => {
// console.log('preprocess mat', mat)
const res = event.data!
const options = event.options! as ProcessRawOptions
// if (!res.assetType) {
// if (res.isBufferGeometry) { // for eg stl todo
// res = new Mesh(res, new MeshStandardMaterial())
// }
// if (res.isObject3D) {
// }
// }
if (res.isObject3D) {
const cameras: Camera[] = []
const lights: Light[] = []
res.traverse((obj: any) => {
if (obj.material) {
const materials = Array.isArray(obj.material) ? obj.material : [obj.material]
const newMaterials = []
for (const material of materials) {
const mat = this.materials.convertToIMaterial(material, {createFromTemplate: options.replaceMaterials !== false}) || material
mat.uuid = material.uuid
mat.userData.uuid = material.uuid
newMaterials.push(mat)
}
if (Array.isArray(obj.material)) obj.material = newMaterials
else obj.material = newMaterials[0]
}
if (obj.isCamera) cameras.push(obj)
if (obj.isLight) lights.push(obj)
})
for (const camera of cameras) {
if ((camera as PerspectiveCamera2).assetType === 'camera') continue
// todo: OrthographicCamera
if (!(camera as PerspectiveCamera).isPerspectiveCamera || !camera.parent || options.replaceCameras === false) {
iCameraCommons.upgradeCamera.call(camera)
} else {
const newCamera: ICamera = (camera as any).iCamera ??
new PerspectiveCamera2('', this.viewer.canvas)
if (camera === newCamera) continue
camera.parent.children.splice(camera.parent.children.indexOf(camera), 1, newCamera)
newCamera.parent = camera.parent as any
newCamera.copy(camera as any)
camera.parent = null
;(newCamera as any).uuid = camera.uuid
newCamera.userData.uuid = camera.uuid
;(camera as any).iCamera = newCamera
// console.log('replacing camera', camera, newCamera)
}
}
for (const light of lights) {
if ((light as ILight).assetType === 'light') continue
if (!light.parent || options.replaceLights === false) {
iLightCommons.upgradeLight.call(light)
} else {
const newLight: ILight | undefined = (light as any).iLight ??
(light as any).isDirectionalLight ? new DirectionalLight2() :
(light as any).isPointLight ? new PointLight2() :
(light as any).isSpotLight ? new SpotLight2() :
(light as any).isAmbientLight ? new AmbientLight2() :
(light as any).isHemisphereLight ? new HemisphereLight2() :
(light as any).isRectAreaLight ? new RectAreaLight2() :
undefined
if (light === newLight || !newLight) continue
light.parent.children.splice(light.parent.children.indexOf(light), 1, newLight)
newLight.parent = light.parent as any
newLight.copy(light as any)
light.parent = null
;(newLight as any).uuid = light.uuid
newLight.userData.uuid = light.uuid
;(light as any).iLight = newLight
}
}

iObjectCommons.upgradeObject3D.call(res)
} else if (res.isMaterial) {
iMaterialCommons.upgradeMaterial.call(res)
// todo update res by generating new material?
} else if (res.isTexture) {
upgradeTexture.call(res)

if (event?.options?.generateMipmaps !== undefined)
res.generateMipmaps = event?.options.generateMipmaps
if (!res.generateMipmaps && !res.isRenderTargetTexture) { // todo: do we need to check more?
res.minFilter = res.minFilter === LinearMipmapLinearFilter ? LinearFilter : res.minFilter
res.magFilter = res.magFilter === LinearMipmapLinearFilter ? LinearFilter : res.magFilter
}

}
// todo other asset/object types?
})
}

/**
* State of download/upload/process/other processes in the viewer.
* Subscribes to importer and exporter by default, more can be added by plugins like {@link FileTransferPlugin}
*/
processState: Map<string, {state: string, progress: number | undefined}> = new Map()

/**
* Set process state for a path
* Progress should be a number between 0 and 100
* Pass undefined in value to remove the state
* @param path
* @param value
*/
setProcessState(path: string, value: {state: string, progress: number | undefined} | undefined) {
if (value === undefined) this.processState.delete(path)
else this.processState.set(path, value)
this.dispatchEvent({type: 'processStateUpdate'})
}

protected _setupProcessState() {
this.importer.addEventListener('importFile', (data: any) => {
this.setProcessState(data.path, data.state !== 'done' ? {
state: data.state,
progress: data.progress ? data.progress * 100 : undefined,
} : undefined)
})
this.importer.addEventListener('processRawStart', (data: any) => {
this.setProcessState(data.path, {
state: 'processing',
progress: undefined,
})
})
this.importer.addEventListener('processRaw', (data: any) => {
this.setProcessState(data.path, undefined)
})
this.exporter.addEventListener('exportFile', (data: any) => {
this.setProcessState(data.obj.name, data.state !== 'done' ? {
state: data.state,
progress: data.progress ? data.progress * 100 : undefined,
} : undefined)
})
}


// region deprecated // region deprecated


/** /**
* @param res * @param res
* @param options * @param options
*/ */
async addImported<T extends (ImportResult|undefined) = ImportResult>(res: T|T[], options: AddRawOptions = {}): Promise<(T|undefined)[]> {
async addImported<T extends (ImportResult | undefined) = ImportResult>(res: T | T[], options: AddRawOptions = {}): Promise<(T | undefined)[]> {
console.error('addImported is deprecated, use addRaw instead') console.error('addImported is deprecated, use addRaw instead')
return this.addRaw(res, options) return this.addRaw(res, options)
} }
*/ */
static readonly PluginType = 'AssetManager' static readonly PluginType = 'AssetManager'
// endregion // endregion

} }

+ 9
- 87
src/plugins/base/AAssetManagerProcessStatePlugin.ts Zobrazit soubor

import {createDiv, onChange, serialize} from 'ts-browser-helpers' import {createDiv, onChange, serialize} from 'ts-browser-helpers'
import {AViewerPluginSync, ThreeViewer} from '../../viewer' import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {uiToggle} from 'uiconfig.js' import {uiToggle} from 'uiconfig.js'
import {FileTransferPlugin} from '../export/FileTransferPlugin'


export abstract class AAssetManagerProcessStatePlugin<T extends string = ''> extends AViewerPluginSync<T> { export abstract class AAssetManagerProcessStatePlugin<T extends string = ''> extends AViewerPluginSync<T> {
@uiToggle('Enabled') @uiToggle('Enabled')
this._mainDiv.style.display = 'none' this._mainDiv.style.display = 'none'
} }
this._mainDiv.appendChild(this._contentDiv) this._mainDiv.appendChild(this._contentDiv)
this._onProcessStateUpdate = this._onProcessStateUpdate.bind(this)
} }


protected abstract _updateMainDiv(processState: Map<string, {state: string, progress?: number|undefined}>): void protected abstract _updateMainDiv(processState: Map<string, {state: string, progress?: number|undefined}>): void


processState: Map<string, {state: string, progress: number|undefined}> = new Map()
onAdded(viewer: ThreeViewer) { onAdded(viewer: ThreeViewer) {
super.onAdded(viewer) super.onAdded(viewer)


;(this.container ?? viewer.container).appendChild(this._mainDiv) ;(this.container ?? viewer.container).appendChild(this._mainDiv)
this._updateMainDiv(this.processState)

// todo remove all these listeners onRemove
viewer.assetManager.importer.addEventListener('importFile', (data: any) => {
if (data.state !== 'done') {
this.processState.set(data.path, {
state: data.state,
progress: data.progress ? data.progress * 100 : undefined,
})
} else {
this.processState.delete(data.path)
}
// console.log('importFile', data)
this._updateMainDiv(this.processState)
})
viewer.assetManager.importer.addEventListener('processRawStart', (data: any) => {
this.processState.set(data.path, {
state: 'processing',
progress: undefined,
})
this._updateMainDiv(this.processState)
})
viewer.assetManager.importer.addEventListener('processRaw', (data: any) => {
this.processState.delete(data.path)
this._updateMainDiv(this.processState)
})
viewer.assetManager.exporter.addEventListener('exportFile', (data: any) => {
if (data.state !== 'done') {
this.processState.set(data.obj.name, {
state: data.state,
progress: data.progress ? data.progress * 100 : undefined,
})
} else {
this.processState.delete(data.obj.name)
}
this._updateMainDiv(this.processState)
})
viewer.getPlugin<FileTransferPlugin>('FileTransferPlugin')?.addEventListener('transferFile', (data: any) => {
if (data.state !== 'done') {
this.processState.set(data.path, {
state: data.state,
progress: data.progress ? data.progress * 100 : undefined,
})
} else {
this.processState.delete(data.path)
}
this._updateMainDiv(this.processState)
})

// todo; remove or move to plugin
viewer.getPlugin/* <MaterialConfiguratorPlugin>*/('MaterialConfiguratorPlugin')?.addEventListener('progress' as any, (data: any) => {
if (data.state !== 'done') {
this.processState.set('MatpreviewGeneration', {
state: data.state,
progress: 0,
})
} else {
this.processState.delete('MatpreviewGeneration')
}
this._updateMainDiv(this.processState)
})
viewer.getPlugin/* <SwitchNodePlugin>*/('SwitchNodePlugin')?.addEventListener('progress' as any, (data: any) => {
if (data.state !== 'done') {
this.processState.set('SwitchNodeGeneration', {
state: data.state,
progress: 0,
})
} else {
this.processState.delete('SwitchNodeGeneration')
}
this._updateMainDiv(this.processState)
})
viewer.getPlugin('ThemePlugin')?.addEventListener('progress' as any, (data: any) => {
if (data.state !== 'done') {
this.processState.set('ThemeInit', {
state: data.state,
progress: 0,
})
} else {
this.processState.delete('ThemeInit')
}
this._updateMainDiv(this.processState)
})
this._updateMainDiv(viewer.assetManager.processState)
viewer.assetManager.addEventListener('processStateUpdate', this._onProcessStateUpdate)
}


protected _onProcessStateUpdate() {
if (!this._viewer) return
this._updateMainDiv(this._viewer.assetManager.processState)
} }


onRemove(viewer: ThreeViewer) { onRemove(viewer: ThreeViewer) {
this._mainDiv.remove() this._mainDiv.remove()
this._contentDiv?.remove()
this.processState.clear()
// this._contentDiv?.remove()
viewer.assetManager.removeEventListener('processStateUpdate', this._onProcessStateUpdate)
return super.onRemove(viewer) return super.onRemove(viewer)
} }
} }

+ 25
- 2
src/plugins/export/FileTransferPlugin.ts Zobrazit soubor

import {AViewerPluginSync} from '../../viewer'
import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {downloadBlob} from 'ts-browser-helpers' import {downloadBlob} from 'ts-browser-helpers'


export class FileTransferPlugin extends AViewerPluginSync<'transferFile'> { export class FileTransferPlugin extends AViewerPluginSync<'transferFile'> {


async exportFile(file: File|Blob, name?: string) { async exportFile(file: File|Blob, name?: string) {
name = name || (file as File).name || 'file_export' name = name || (file as File).name || 'file_export'
this.dispatchEvent({type: 'transferFile', path: name, state: 'exporting'})
this.dispatchEvent({type: 'transferFile', path: name, state: 'exporting', progress: 0})
await this.actions.exportFile(file, name, ({state, progress})=>{ await this.actions.exportFile(file, name, ({state, progress})=>{
this.dispatchEvent({type: 'transferFile', path: name, state: state ?? 'exporting', progress}) this.dispatchEvent({type: 'transferFile', path: name, state: state ?? 'exporting', progress})
}) })
}, },
} }



constructor() {
super()
this._updateProcessState = this._updateProcessState.bind(this)
}

onAdded(viewer: ThreeViewer) {
super.onAdded(viewer)
this.addEventListener('transferFile', this._updateProcessState as any)
}
onRemove(viewer: ThreeViewer) {
this.removeEventListener('transferFile', this._updateProcessState as any)
super.onRemove(viewer)
}

protected _updateProcessState(data: {path: string, state: string, progress?: number}) {
if (!this._viewer) return
this._viewer.assetManager.setProcessState(data.path, data.state !== 'done' ? {
state: data.state,
progress: data.progress ? data.progress * 100 : undefined,
} : undefined)
}

actions = {...this.defaultActions} actions = {...this.defaultActions}
} }

+ 3
- 2
src/plugins/interaction/LoadingScreenPlugin.ts Zobrazit soubor

html: '<span class="loader"></span>', html: '<span class="loader"></span>',
}] }]
refresh() { refresh() {
this._updateMainDiv(this._isPreviewing ? this._previewState : this.processState, false)
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}))) @uiDropdown('Loader', ['Spinner 1'].map((v, i) => ({value: i, label: v})))
stylesheet?: HTMLStyleElement stylesheet?: HTMLStyleElement
stylesheetLoader?: HTMLStyleElement[] stylesheetLoader?: HTMLStyleElement[]
onAdded(viewer: ThreeViewer) { onAdded(viewer: ThreeViewer) {
this.stylesheet = createStyles(styles, viewer.container)
this.stylesheet = createStyles(this.styles, viewer.container)
this.stylesheetLoader = this.spinners.map(s => createStyles(s.styles, viewer.container)) this.stylesheetLoader = this.spinners.map(s => createStyles(s.styles, viewer.container))


viewer.scene.addEventListener('sceneUpdate', this._sceneUpdate) viewer.scene.addEventListener('sceneUpdate', this._sceneUpdate)

Načítá se…
Zrušit
Uložit