125 lines
3.4 KiB
TypeScript
125 lines
3.4 KiB
TypeScript
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
|
|
}
|
|
}
|