File size: 3,617 Bytes
0ad74ed |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
<script lang="ts">
import { createEventDispatcher, tick } from "svelte";
import { Upload, ModifyUpload } from "@gradio/upload";
import type { FileData, Client } from "@gradio/client";
import { BlockLabel } from "@gradio/atoms";
import { File } from "@gradio/icons";
import type { I18nFormatter } from "@gradio/utils";
import type Canvas3DGS from "./Canvas3DGS.svelte";
import type Canvas3D from "./Canvas3D.svelte";
export let value: null | FileData;
export let display_mode: "solid" | "point_cloud" | "wireframe" = "solid";
export let clear_color: [number, number, number, number] = [0, 0, 0, 0];
export let label = "";
export let show_label: boolean;
export let root: string;
export let i18n: I18nFormatter;
export let zoom_speed = 1;
export let pan_speed = 1;
export let max_file_size: number | null = null;
export let uploading = false;
// alpha, beta, radius
export let camera_position: [number | null, number | null, number | null] = [
null,
null,
null
];
export let upload: Client["upload"];
export let stream_handler: Client["stream"];
async function handle_upload({
detail
}: CustomEvent<FileData>): Promise<void> {
value = detail;
await tick();
dispatch("change", value);
dispatch("load", value);
}
async function handle_clear(): Promise<void> {
value = null;
await tick();
dispatch("clear");
dispatch("change");
}
let use_3dgs = false;
let Canvas3DGSComponent: typeof Canvas3DGS;
let Canvas3DComponent: typeof Canvas3D;
async function loadCanvas3D(): Promise<typeof Canvas3D> {
const module = await import("./Canvas3D.svelte");
return module.default;
}
async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
const module = await import("./Canvas3DGS.svelte");
return module.default;
}
$: if (value) {
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
if (use_3dgs) {
loadCanvas3DGS().then((component) => {
Canvas3DGSComponent = component;
});
} else {
loadCanvas3D().then((component) => {
Canvas3DComponent = component;
});
}
}
let canvas3d: Canvas3D | undefined;
async function handle_undo(): Promise<void> {
canvas3d?.reset_camera_position(camera_position, zoom_speed, pan_speed);
}
const dispatch = createEventDispatcher<{
change: FileData | null;
clear: undefined;
drag: boolean;
load: FileData;
}>();
let dragging = false;
$: dispatch("drag", dragging);
</script>
<BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
{#if value === null}
<Upload
{upload}
{stream_handler}
on:load={handle_upload}
{root}
{max_file_size}
filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
bind:dragging
bind:uploading
on:error
>
<slot />
</Upload>
{:else}
<div class="input-model">
<ModifyUpload
undoable={!use_3dgs}
on:clear={handle_clear}
{i18n}
on:undo={handle_undo}
/>
{#if use_3dgs}
<svelte:component
this={Canvas3DGSComponent}
{value}
{zoom_speed}
{pan_speed}
/>
{:else}
<svelte:component
this={Canvas3DComponent}
bind:this={canvas3d}
{value}
{display_mode}
{clear_color}
{camera_position}
{zoom_speed}
{pan_speed}
/>
{/if}
</div>
{/if}
<style>
.input-model {
display: flex;
position: relative;
justify-content: center;
align-items: center;
width: var(--size-full);
height: var(--size-full);
border-radius: var(--block-radius);
overflow: hidden;
}
.input-model :global(canvas) {
width: var(--size-full);
height: var(--size-full);
object-fit: contain;
overflow: hidden;
}
</style>
|