Spaces:
Running
Running
| <script lang="ts"> | |
| import { onMount, onDestroy } from "svelte"; | |
| import type { IViewer } from "./viewers/IViewer"; | |
| import { createViewer } from "./viewers/ViewerFactory"; | |
| import { ArrowLeft, Cube, WatsonHealth3DPrintMesh } from "carbon-icons-svelte"; | |
| import type { Config } from "./utils/Config"; | |
| import { getConfig } from "./utils/getConfig"; | |
| interface Scene { | |
| name: string; | |
| url: string; | |
| thumbnail: string; | |
| } | |
| export let modelName: string; | |
| export let scene: Scene; | |
| export let onBack: () => void; | |
| let container: HTMLDivElement; | |
| let canvas: HTMLCanvasElement; | |
| let overlay: HTMLDivElement; | |
| let loadingBarFill: HTMLDivElement; | |
| let viewer: IViewer; | |
| let displayName: string; | |
| async function loadScene() { | |
| overlay.style.display = "flex"; | |
| displayName = (await getConfig(modelName)).DisplayName || modelName; | |
| viewer = await createViewer(scene.url, canvas, (progress) => { | |
| loadingBarFill.style.width = `${progress * 100}%`; | |
| }); | |
| window.addEventListener("resize", handleResize); | |
| window.addEventListener("keydown", handleKeyDown); | |
| handleResize(); | |
| overlay.style.display = "none"; | |
| } | |
| function handleResize() { | |
| if (!canvas || !container) return; | |
| requestAnimationFrame(() => { | |
| canvas.width = container.clientWidth; | |
| canvas.height = container.clientHeight; | |
| }); | |
| } | |
| function handleKeyDown(e: KeyboardEvent) { | |
| if (e.code === "KeyP") { | |
| capture(); | |
| } | |
| } | |
| async function capture() { | |
| const data = await viewer.capture(); | |
| if (!data) { | |
| console.error("Failed to capture screenshot"); | |
| return; | |
| } | |
| const a = document.createElement("a"); | |
| a.href = data; | |
| a.download = `${scene.name}.png`; | |
| a.click(); | |
| } | |
| onMount(loadScene); | |
| onDestroy(() => { | |
| viewer?.dispose(); | |
| if (typeof window !== "undefined") { | |
| window.removeEventListener("resize", handleResize); | |
| window.removeEventListener("keydown", handleKeyDown); | |
| } | |
| }); | |
| </script> | |
| <div class="header"> | |
| <div class="back" aria-label="Back" aria-hidden="true" on:click={onBack}> | |
| <ArrowLeft size={24} /> | |
| </div> | |
| <div class="spacer" /> | |
| <button class="title-button" on:click={loadScene}> | |
| <!-- svelte-ignore a11y-click-events-have-key-events --> | |
| <!-- svelte-ignore a11y-no-static-element-interactions --> | |
| <h2> | |
| {#if displayName} | |
| <span class="muted" on:click={onBack}>{displayName}/</span>{scene.name.length > 16 | |
| ? `${scene.name.slice(0, 16)}...` | |
| : scene.name} | |
| {:else} | |
| Loading... | |
| {/if} | |
| </h2> | |
| </button> | |
| <div class="desktop-spacer" /> | |
| </div> | |
| <div class="canvas-container" bind:this={container}> | |
| <div bind:this={overlay} class="loading-overlay"> | |
| <div class="loading-bar"> | |
| <div bind:this={loadingBarFill} class="loading-bar-fill" /> | |
| </div> | |
| </div> | |
| <canvas class="viewer-canvas" bind:this={canvas} width={800} height={600}> </canvas> | |
| <div class="stats"> | |
| {#if viewer} | |
| <p>vertex count: {viewer.vertexCount}</p> | |
| {/if} | |
| </div> | |
| {#if viewer && !viewer.topoOnly} | |
| <div class="mode-toggle"> | |
| <label> | |
| <input | |
| type="radio" | |
| name="modeB" | |
| value="default" | |
| checked | |
| on:change={() => viewer.setRenderMode("default")} | |
| /> | |
| <Cube class="mode-toggle-icon" /> | |
| </label> | |
| <label> | |
| <input | |
| type="radio" | |
| name="modeB" | |
| value="wireframe" | |
| on:change={() => viewer.setRenderMode("wireframe")} | |
| /> | |
| <WatsonHealth3DPrintMesh class="mode-toggle-icon" /> | |
| </label> | |
| </div> | |
| {/if} | |
| </div> | |