import ObjectLoader from '@speckle/objectloader' import Converter from './converter/Converter' import EventEmitter from './EventEmitter' /** * Helper wrapper around the ObjectLoader class, with some built in assumptions. */ export default class ViewerObjectLoader { private _objectUrl: string private objectId: string private token: string private loader: ObjectLoader private converter: Converter private cancel = false private emiter: EventEmitter public get objectUrl(): string { return this._objectUrl } constructor(parentEmitter: EventEmitter, objectUrl, authToken, enableCaching) { this.emiter = parentEmitter this._objectUrl = objectUrl this.token = null try { this.token = authToken || localStorage.getItem('AuthToken') } catch (error) { // Accessing localStorage may throw when executing on sandboxed document, ignore. } if (!this.token) { console.warn( 'Viewer: no auth token present. Requests to non-public stream objects will fail.' ) } // example url: `https://staging.speckle.dev/streams/a75ab4f10f/objects/f33645dc9a702de8af0af16bd5f655b0` const url = new URL(objectUrl) const segments = url.pathname.split('/') if ( segments.length < 5 || url.pathname.indexOf('streams') === -1 || url.pathname.indexOf('objects') === -1 ) { throw new Error('Unexpected object url format.') } const serverUrl = url.origin const streamId = segments[2] this.objectId = segments[4] this.loader = new ObjectLoader({ serverUrl, token: this.token, streamId, objectId: this.objectId, options: { enableCaching } }) this.converter = new Converter(this.loader) this.cancel = false } public async load() { const start = performance.now() let first = true let current = 0 let total = 0 let viewerLoads = 0 let firstObjectPromise = null for await (const obj of this.loader.getObjectIterator()) { if (this.cancel) { this.emiter.emit('load-progress', { progress: 1, id: this.objectId, url: this.objectUrl }) // to hide progress bar, easier on the frontend this.emiter.emit('load-cancelled', { id: this.objectId, url: this.objectUrl }) return } await this.converter.asyncPause() if (first) { // console.log(obj) firstObjectPromise = this.converter.traverse(this.objectUrl, obj, async () => { await this.converter.asyncPause() // objectWrapper.meta.__importedUrl = this.objectUrl viewerLoads++ }) first = false total = obj.totalChildrenCount } current++ this.emiter.emit('load-progress', { progress: current / (total + 1), id: this.objectId }) } if (firstObjectPromise) { await firstObjectPromise } // await this.viewer.sceneManager.postLoadFunction() console.warn( `Loaded object ${this.objectId} in ${(performance.now() - start) / 1000} seconds` ) this.emiter.emit('load-complete', this.objectUrl) if (viewerLoads === 0) { console.warn(`Viewer: no 3d objects found in object ${this.objectId}`) this.emiter.emit('load-warning', { message: `No displayable objects found in object ${this.objectId}.` }) } } cancelLoad() { this.cancel = true } }