3d-arena / src /routes /Viewer.svelte
dylanebert's picture
dylanebert HF staff
vote layout
c99cc8d
raw
history blame
No virus
2.95 kB
<script lang="ts">
import { onMount, onDestroy } from "svelte";
import type { IViewer } from "./viewers/IViewer";
import { createViewer } from "./viewers/ViewerFactory";
import ArrowLeft from "carbon-icons-svelte/lib/ArrowLeft.svelte";
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;
async function loadScene() {
overlay.style.display = "flex";
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(() => {
const maxWidth = container.clientHeight * (16 / 9);
const maxHeight = container.clientWidth * (9 / 16);
canvas.width = Math.min(container.clientWidth, maxWidth);
canvas.height = Math.min(container.clientHeight, maxHeight);
});
}
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 = "screenshot.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><span class="muted" on:click={onBack}>{modelName}/</span>{scene.name}</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 bind:this={canvas} width={800} height={600} />
</div>