diff --git a/packages/viewer-sandbox/index.html b/packages/viewer-sandbox/index.html index 4dbcaf405..27a18c075 100644 --- a/packages/viewer-sandbox/index.html +++ b/packages/viewer-sandbox/index.html @@ -8,15 +8,27 @@ -
+
+ diff --git a/packages/viewer-sandbox/src/Sandbox.ts b/packages/viewer-sandbox/src/Sandbox.ts new file mode 100644 index 000000000..9b2ec8b39 --- /dev/null +++ b/packages/viewer-sandbox/src/Sandbox.ts @@ -0,0 +1,46 @@ +import { Viewer } from '@speckle/viewer' +import { Pane } from 'tweakpane' +import UrlHelper from './UrlHelper' + +export default class Sandbox { + private viewer: Viewer + private pane: Pane + + private static urlParams = { + url: 'https://latest.speckle.dev/streams/010b3af4c3/objects/a401baf38fe5809d0eb9d3c902a36e8f' + } + + public constructor(viewer: Viewer) { + this.viewer = viewer + this.pane = new Pane({ title: 'Sandbox', expanded: true }) + } + + public makeGenericUI() { + this.pane.addInput(Sandbox.urlParams, 'url') + + const loadButton = this.pane.addButton({ + title: 'Load Url' + }) + + loadButton.on('click', () => { + this.loadUrl(Sandbox.urlParams.url) + }) + + const clearButton = this.pane.addButton({ + title: 'Clear All' + }) + + clearButton.on('click', () => { + this.viewer.unloadAll() + }) + } + + public async loadUrl(url: string) { + const objUrls = await UrlHelper.getResourceUrls(url) + for (const url of objUrls) { + console.log(`Loading ${url}`) + await this.viewer.loadObject(url) + } + localStorage.setItem('last-load-url', url) + } +} diff --git a/packages/viewer-sandbox/src/UrlHelper.ts b/packages/viewer-sandbox/src/UrlHelper.ts new file mode 100644 index 000000000..0b0be7f92 --- /dev/null +++ b/packages/viewer-sandbox/src/UrlHelper.ts @@ -0,0 +1,73 @@ +interface CommitReferencedObjectUrl { + origin: string + streamId: string + commitId: string +} + +export default class UrlHelper { + static async getResourceUrls(url: string): Promise { + const parsed = new URL(url) + const streamId = url.split('/streams/')[1].substring(0, 10) + + const objsUrls = [] + // supports commit based urls + if (url.includes('commits')) { + const commitId = url.split('/commits/')[1].substring(0, 10) + const objUrl = await this.getCommitReferencedObjectUrl({ + origin: parsed.origin, + streamId, + commitId + }) + objsUrls.push(objUrl) + } + + // object based urls + if (url.includes('objects')) objsUrls.push(url) + + // supports urls that include overlay queries + // e.g., https://speckle.xyz/streams/a632e7a784/objects/457c45feffa6f954572e5e86fb6d4f25?overlay=cf8dc76247,f5adc1d991b3dceb4b5ad6b50f919a0e + if (url.includes('overlay=')) { + const searchParams = new URLSearchParams(parsed.search) + const resIds = searchParams.get('overlay')?.split(',') + if (resIds !== undefined) { + for (const resId of resIds) { + if (resId.length === 10) { + objsUrls.push( + await this.getCommitReferencedObjectUrl({ + origin: parsed.origin, + streamId, + commitId: resId + } as CommitReferencedObjectUrl) + ) + } else { + objsUrls.push(`${parsed.origin}/streams/${streamId}/objects/${resId}`) + } + } + } + } + + return objsUrls + } + + private static async getCommitReferencedObjectUrl(ref: CommitReferencedObjectUrl) { + const res = await fetch(`${ref.origin}/graphql`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: ` + query Stream($streamId: String!, $commitId: String!) { + stream(id: $streamId) { + commit(id: $commitId) { + referencedObject + } + } + } + `, + variables: { streamId: ref.streamId, commitId: ref.commitId } + }) + }) + + const { data } = await res.json() + return `${ref.origin}/streams/${ref.streamId}/objects/${data.stream.commit.referencedObject}` + } +} diff --git a/packages/viewer-sandbox/src/main.ts b/packages/viewer-sandbox/src/main.ts index 5041b2ce6..83d33e91a 100644 --- a/packages/viewer-sandbox/src/main.ts +++ b/packages/viewer-sandbox/src/main.ts @@ -1,6 +1,6 @@ -import { Pane } from 'tweakpane' import { Viewer } from '@speckle/viewer' import './style.css' +import Sandbox from './Sandbox' const container = document.querySelector('#renderer') as HTMLElement if (!container) { @@ -14,19 +14,6 @@ window.addEventListener('load', () => { viewer.onWindowResize() }) -// Tweakpane setup -const PARAMS = { - factor: 123, - title: 'hello', - color: '#ff0055' -} - -const pane = new Pane() - -pane.addInput(PARAMS, 'factor') -pane.addInput(PARAMS, 'title') -pane.addInput(PARAMS, 'color') - // Load demo object viewer.loadObject( 'https://speckle.xyz/streams/99abc74dd4/objects/ab503a2025e706717bff467ef8f96488' @@ -37,3 +24,6 @@ viewer.on<{ progress: number; id: string; url: string }>('load-progress', (a) => viewer.onWindowResize() } }) + +const sandbox = new Sandbox(viewer) +sandbox.makeGenericUI() diff --git a/packages/viewer-sandbox/src/style.css b/packages/viewer-sandbox/src/style.css index b562c7eb3..e65a1e89f 100644 --- a/packages/viewer-sandbox/src/style.css +++ b/packages/viewer-sandbox/src/style.css @@ -12,3 +12,30 @@ height: 100%; width: 100%; } + +.button { + border: 0; + line-height: 1.5; + padding: 0 20px; + font-size: 1rem; + text-align: center; + color: #fff; + text-shadow: 1px 1px 1px #000; + border-radius: 2px; + background-color: rgb(129, 129, 129); + background-image: linear-gradient( + to top left, + rgba(0, 0, 0, 0.2), + rgba(0, 0, 0, 0.2) 30%, + rgba(0, 0, 0, 0) + ); + box-shadow: inset 2px 2px 3px rgba(255, 255, 255, 0.6), + inset -2px -2px 3px rgba(0, 0, 0, 0.6); +} + +.input { + margin-bottom: 5px; + left: 0px; + border-radius: 0.1rem; + border: 4px solid rgb(129, 129, 129); +} diff --git a/packages/viewer-sandbox/src/type-augmentations/viewer.d.ts b/packages/viewer-sandbox/src/type-augmentations/viewer.d.ts index 54b442d7d..a55c46485 100644 --- a/packages/viewer-sandbox/src/type-augmentations/viewer.d.ts +++ b/packages/viewer-sandbox/src/type-augmentations/viewer.d.ts @@ -12,6 +12,7 @@ declare module '@speckle/viewer' { }) async loadObject(url: string, token?: string, enableCaching? = true): Promise + async unloadAll() onWindowResize(): void on( event: string,