@gradio/model3d 0.16.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/Index.svelte +6 -6
- package/dist/Index.svelte +6 -6
- package/dist/shared/Canvas3D.svelte +27 -12
- package/dist/shared/Canvas3D.svelte.d.ts +5 -21
- package/dist/shared/Canvas3DGS.svelte +20 -12
- package/dist/shared/Canvas3DGS.svelte.d.ts +4 -18
- package/dist/shared/Model3D.svelte +45 -34
- package/dist/shared/Model3D.svelte.d.ts +4 -18
- package/dist/shared/Model3DUpload.svelte +85 -61
- package/dist/shared/Model3DUpload.svelte.d.ts +24 -24
- package/package.json +4 -4
- package/shared/Canvas3D.svelte +27 -12
- package/shared/Canvas3DGS.svelte +20 -12
- package/shared/Model3D.svelte +45 -34
- package/shared/Model3DUpload.svelte +85 -61
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @gradio/model3d
|
|
2
2
|
|
|
3
|
+
## 0.16.1
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- [#12688](https://github.com/gradio-app/gradio/pull/12688) [`5206d47`](https://github.com/gradio-app/gradio/commit/5206d47b7730e6ffc8efd90d8157dd5388c18dc5) - Migrate Model3D to Svelte 5. Thanks @dawoodkhan82!
|
|
8
|
+
|
|
9
|
+
### Dependency updates
|
|
10
|
+
|
|
11
|
+
- @gradio/utils@0.11.1
|
|
12
|
+
- @gradio/client@2.0.2
|
|
13
|
+
|
|
3
14
|
## 0.16.0
|
|
4
15
|
|
|
5
16
|
### Features
|
package/Index.svelte
CHANGED
|
@@ -157,15 +157,15 @@
|
|
|
157
157
|
root={gradio.shared.root}
|
|
158
158
|
display_mode={gradio.props.display_mode}
|
|
159
159
|
clear_color={gradio.props.clear_color}
|
|
160
|
-
value={gradio.props.value}
|
|
160
|
+
bind:value={gradio.props.value}
|
|
161
161
|
camera_position={gradio.props.camera_position}
|
|
162
162
|
zoom_speed={gradio.props.zoom_speed}
|
|
163
163
|
bind:uploading
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
onchange={handle_change}
|
|
165
|
+
ondrag={handle_drag}
|
|
166
|
+
onclear={handle_clear}
|
|
167
|
+
onload={handle_load}
|
|
168
|
+
onerror={handle_error}
|
|
169
169
|
i18n={gradio.i18n}
|
|
170
170
|
max_file_size={gradio.shared.max_file_size}
|
|
171
171
|
upload={(...args) => gradio.shared.client.upload(...args)}
|
package/dist/Index.svelte
CHANGED
|
@@ -157,15 +157,15 @@
|
|
|
157
157
|
root={gradio.shared.root}
|
|
158
158
|
display_mode={gradio.props.display_mode}
|
|
159
159
|
clear_color={gradio.props.clear_color}
|
|
160
|
-
value={gradio.props.value}
|
|
160
|
+
bind:value={gradio.props.value}
|
|
161
161
|
camera_position={gradio.props.camera_position}
|
|
162
162
|
zoom_speed={gradio.props.zoom_speed}
|
|
163
163
|
bind:uploading
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
onchange={handle_change}
|
|
165
|
+
ondrag={handle_drag}
|
|
166
|
+
onclear={handle_clear}
|
|
167
|
+
onload={handle_load}
|
|
168
|
+
onerror={handle_error}
|
|
169
169
|
i18n={gradio.i18n}
|
|
170
170
|
max_file_size={gradio.shared.max_file_size}
|
|
171
171
|
upload={(...args) => gradio.shared.client.upload(...args)}
|
|
@@ -5,19 +5,28 @@
|
|
|
5
5
|
|
|
6
6
|
let BABYLON_VIEWER: typeof import("@babylonjs/viewer");
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
let {
|
|
9
|
+
value,
|
|
10
|
+
display_mode,
|
|
11
|
+
clear_color,
|
|
12
|
+
camera_position,
|
|
13
|
+
zoom_speed,
|
|
14
|
+
pan_speed
|
|
15
|
+
}: {
|
|
16
|
+
value: FileData;
|
|
17
|
+
display_mode: "solid" | "point_cloud" | "wireframe";
|
|
18
|
+
clear_color: [number, number, number, number];
|
|
19
|
+
camera_position: [number | null, number | null, number | null];
|
|
20
|
+
zoom_speed: number;
|
|
21
|
+
pan_speed: number;
|
|
22
|
+
} = $props();
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
let url = $derived(value.url);
|
|
16
25
|
|
|
17
26
|
let canvas: HTMLCanvasElement;
|
|
18
|
-
let viewer
|
|
19
|
-
let viewerDetails
|
|
20
|
-
let mounted = false;
|
|
27
|
+
let viewer = $state<Viewer>();
|
|
28
|
+
let viewerDetails = $state<Readonly<ViewerDetails>>();
|
|
29
|
+
let mounted = $state(false);
|
|
21
30
|
|
|
22
31
|
onMount(() => {
|
|
23
32
|
const initViewer = async (): Promise<void> => {
|
|
@@ -43,9 +52,14 @@
|
|
|
43
52
|
};
|
|
44
53
|
});
|
|
45
54
|
|
|
46
|
-
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (mounted) {
|
|
57
|
+
load_model(url);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
47
60
|
|
|
48
61
|
function setRenderingMode(pointsCloud: boolean, wireframe: boolean): void {
|
|
62
|
+
if (!viewerDetails) return;
|
|
49
63
|
viewerDetails.scene.forcePointsCloud = pointsCloud;
|
|
50
64
|
viewerDetails.scene.forceWireframe = wireframe;
|
|
51
65
|
}
|
|
@@ -81,6 +95,7 @@
|
|
|
81
95
|
zoom_speed: number,
|
|
82
96
|
pan_speed: number
|
|
83
97
|
): void {
|
|
98
|
+
if (!viewerDetails) return;
|
|
84
99
|
const camera = viewerDetails.camera;
|
|
85
100
|
if (camera_position[0] !== null) {
|
|
86
101
|
camera.alpha = (camera_position[0] * Math.PI) / 180;
|
|
@@ -101,7 +116,7 @@
|
|
|
101
116
|
}
|
|
102
117
|
|
|
103
118
|
export function reset_camera_position(): void {
|
|
104
|
-
if (viewerDetails) {
|
|
119
|
+
if (viewerDetails && viewer) {
|
|
105
120
|
viewer.resetCamera();
|
|
106
121
|
}
|
|
107
122
|
}
|
|
@@ -1,31 +1,15 @@
|
|
|
1
1
|
import type { FileData } from "@gradio/client";
|
|
2
|
-
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const Canvas3D: $$__sveltets_2_IsomorphicComponent<{
|
|
2
|
+
type $$ComponentProps = {
|
|
16
3
|
value: FileData;
|
|
17
4
|
display_mode: "solid" | "point_cloud" | "wireframe";
|
|
18
5
|
clear_color: [number, number, number, number];
|
|
19
6
|
camera_position: [number | null, number | null, number | null];
|
|
20
7
|
zoom_speed: number;
|
|
21
8
|
pan_speed: number;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}, {
|
|
25
|
-
[evt: string]: CustomEvent<any>;
|
|
26
|
-
}, {}, {
|
|
9
|
+
};
|
|
10
|
+
declare const Canvas3D: import("svelte").Component<$$ComponentProps, {
|
|
27
11
|
update_camera: (camera_position: [number | null, number | null, number | null], zoom_speed: number, pan_speed: number) => void;
|
|
28
12
|
reset_camera_position: () => void;
|
|
29
|
-
},
|
|
30
|
-
type Canvas3D =
|
|
13
|
+
}, "">;
|
|
14
|
+
type Canvas3D = ReturnType<typeof Canvas3D>;
|
|
31
15
|
export default Canvas3D;
|
|
@@ -3,19 +3,25 @@
|
|
|
3
3
|
import * as SPLAT from "gsplat";
|
|
4
4
|
import type { FileData } from "@gradio/client";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
let {
|
|
7
|
+
value,
|
|
8
|
+
zoom_speed,
|
|
9
|
+
pan_speed
|
|
10
|
+
}: {
|
|
11
|
+
value: FileData;
|
|
12
|
+
zoom_speed: number;
|
|
13
|
+
pan_speed: number;
|
|
14
|
+
} = $props();
|
|
15
|
+
|
|
16
|
+
let url = $derived(value.url);
|
|
11
17
|
|
|
12
18
|
let canvas: HTMLCanvasElement;
|
|
13
19
|
let scene: SPLAT.Scene;
|
|
14
20
|
let camera: SPLAT.Camera;
|
|
15
|
-
let renderer
|
|
21
|
+
let renderer = $state<SPLAT.WebGLRenderer | null>(null);
|
|
16
22
|
let controls: SPLAT.OrbitControls;
|
|
17
|
-
let mounted = false;
|
|
18
|
-
let frameId
|
|
23
|
+
let mounted = $state(false);
|
|
24
|
+
let frameId = $state<number | null>(null);
|
|
19
25
|
|
|
20
26
|
function reset_scene(): void {
|
|
21
27
|
if (frameId !== null) {
|
|
@@ -92,11 +98,13 @@
|
|
|
92
98
|
};
|
|
93
99
|
});
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
path: undefined
|
|
97
|
-
});
|
|
101
|
+
let path = $derived(value?.path);
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
$effect(() => {
|
|
104
|
+
if (canvas && mounted && path) {
|
|
105
|
+
reset_scene();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
100
108
|
</script>
|
|
101
109
|
|
|
102
110
|
<canvas bind:this={canvas}></canvas>
|
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
import type { FileData } from "@gradio/client";
|
|
2
|
-
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const Canvas3DGS: $$__sveltets_2_IsomorphicComponent<{
|
|
2
|
+
type $$ComponentProps = {
|
|
16
3
|
value: FileData;
|
|
17
4
|
zoom_speed: number;
|
|
18
5
|
pan_speed: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type Canvas3DGS = InstanceType<typeof Canvas3DGS>;
|
|
6
|
+
};
|
|
7
|
+
declare const Canvas3DGS: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type Canvas3DGS = ReturnType<typeof Canvas3DGS>;
|
|
23
9
|
export default Canvas3DGS;
|
|
@@ -7,27 +7,36 @@
|
|
|
7
7
|
import type Canvas3DGS from "./Canvas3DGS.svelte";
|
|
8
8
|
import type Canvas3D from "./Canvas3D.svelte";
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
null
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
let {
|
|
11
|
+
value,
|
|
12
|
+
display_mode = "solid",
|
|
13
|
+
clear_color = [0, 0, 0, 0],
|
|
14
|
+
label = "",
|
|
15
|
+
show_label,
|
|
16
|
+
i18n,
|
|
17
|
+
zoom_speed = 1,
|
|
18
|
+
pan_speed = 1,
|
|
19
|
+
camera_position = [null, null, null],
|
|
20
|
+
has_change_history = false
|
|
21
|
+
}: {
|
|
22
|
+
value: FileData | null;
|
|
23
|
+
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
24
|
+
clear_color?: [number, number, number, number];
|
|
25
|
+
label?: string;
|
|
26
|
+
show_label: boolean;
|
|
27
|
+
i18n: I18nFormatter;
|
|
28
|
+
zoom_speed?: number;
|
|
29
|
+
pan_speed?: number;
|
|
30
|
+
camera_position?: [number | null, number | null, number | null];
|
|
31
|
+
has_change_history?: boolean;
|
|
32
|
+
} = $props();
|
|
25
33
|
|
|
26
|
-
let current_settings = { camera_position, zoom_speed, pan_speed };
|
|
34
|
+
let current_settings = $state({ camera_position, zoom_speed, pan_speed });
|
|
35
|
+
let use_3dgs = $state(false);
|
|
36
|
+
let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
|
|
37
|
+
let Canvas3DComponent = $state<typeof Canvas3D>();
|
|
38
|
+
let canvas3d = $state<Canvas3D | undefined>();
|
|
27
39
|
|
|
28
|
-
let use_3dgs = false;
|
|
29
|
-
let Canvas3DGSComponent: typeof Canvas3DGS;
|
|
30
|
-
let Canvas3DComponent: typeof Canvas3D;
|
|
31
40
|
async function loadCanvas3D(): Promise<typeof Canvas3D> {
|
|
32
41
|
const module = await import("./Canvas3D.svelte");
|
|
33
42
|
return module.default;
|
|
@@ -36,25 +45,27 @@
|
|
|
36
45
|
const module = await import("./Canvas3DGS.svelte");
|
|
37
46
|
return module.default;
|
|
38
47
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
$effect(() => {
|
|
50
|
+
if (value) {
|
|
51
|
+
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
|
|
52
|
+
if (use_3dgs) {
|
|
53
|
+
loadCanvas3DGS().then((component) => {
|
|
54
|
+
Canvas3DGSComponent = component;
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
loadCanvas3D().then((component) => {
|
|
58
|
+
Canvas3DComponent = component;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
|
-
}
|
|
62
|
+
});
|
|
51
63
|
|
|
52
|
-
let canvas3d: Canvas3D | undefined;
|
|
53
64
|
function handle_undo(): void {
|
|
54
65
|
canvas3d?.reset_camera_position();
|
|
55
66
|
}
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
$effect(() => {
|
|
58
69
|
if (
|
|
59
70
|
!dequal(current_settings.camera_position, camera_position) ||
|
|
60
71
|
current_settings.zoom_speed !== zoom_speed ||
|
|
@@ -63,7 +74,7 @@
|
|
|
63
74
|
canvas3d?.update_camera(camera_position, zoom_speed, pan_speed);
|
|
64
75
|
current_settings = { camera_position, zoom_speed, pan_speed };
|
|
65
76
|
}
|
|
66
|
-
}
|
|
77
|
+
});
|
|
67
78
|
</script>
|
|
68
79
|
|
|
69
80
|
<BlockLabel
|
|
@@ -79,7 +90,7 @@
|
|
|
79
90
|
<IconButton
|
|
80
91
|
Icon={Undo}
|
|
81
92
|
label="Undo"
|
|
82
|
-
|
|
93
|
+
onclick={() => handle_undo()}
|
|
83
94
|
disabled={!has_change_history}
|
|
84
95
|
/>
|
|
85
96
|
{/if}
|
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
import type { FileData } from "@gradio/client";
|
|
2
2
|
import type { I18nFormatter } from "@gradio/utils";
|
|
3
|
-
|
|
4
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
5
|
-
$$bindings?: Bindings;
|
|
6
|
-
} & Exports;
|
|
7
|
-
(internal: unknown, props: Props & {
|
|
8
|
-
$$events?: Events;
|
|
9
|
-
$$slots?: Slots;
|
|
10
|
-
}): Exports & {
|
|
11
|
-
$set?: any;
|
|
12
|
-
$on?: any;
|
|
13
|
-
};
|
|
14
|
-
z_$$bindings?: Bindings;
|
|
15
|
-
}
|
|
16
|
-
declare const Model3D: $$__sveltets_2_IsomorphicComponent<{
|
|
3
|
+
type $$ComponentProps = {
|
|
17
4
|
value: FileData | null;
|
|
18
5
|
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
19
6
|
clear_color?: [number, number, number, number];
|
|
@@ -24,8 +11,7 @@ declare const Model3D: $$__sveltets_2_IsomorphicComponent<{
|
|
|
24
11
|
pan_speed?: number;
|
|
25
12
|
camera_position?: [number | null, number | null, number | null];
|
|
26
13
|
has_change_history?: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type Model3D = InstanceType<typeof Model3D>;
|
|
14
|
+
};
|
|
15
|
+
declare const Model3D: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type Model3D = ReturnType<typeof Model3D>;
|
|
31
17
|
export default Model3D;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { tick } from "svelte";
|
|
3
3
|
import { Upload, ModifyUpload } from "@gradio/upload";
|
|
4
4
|
import type { FileData, Client } from "@gradio/client";
|
|
5
5
|
import { BlockLabel } from "@gradio/atoms";
|
|
@@ -8,83 +8,107 @@
|
|
|
8
8
|
import type Canvas3DGS from "./Canvas3DGS.svelte";
|
|
9
9
|
import type Canvas3D from "./Canvas3D.svelte";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
let {
|
|
12
|
+
value = $bindable(),
|
|
13
|
+
display_mode = "solid",
|
|
14
|
+
clear_color = [0, 0, 0, 0],
|
|
15
|
+
label = "",
|
|
16
|
+
show_label,
|
|
17
|
+
root,
|
|
18
|
+
i18n,
|
|
19
|
+
zoom_speed = 1,
|
|
20
|
+
pan_speed = 1,
|
|
21
|
+
max_file_size = null,
|
|
22
|
+
uploading = $bindable(),
|
|
23
|
+
upload_promise = $bindable(),
|
|
24
|
+
camera_position = [null, null, null],
|
|
25
|
+
upload,
|
|
26
|
+
stream_handler,
|
|
27
|
+
onchange,
|
|
28
|
+
onclear,
|
|
29
|
+
ondrag,
|
|
30
|
+
onload,
|
|
31
|
+
onerror
|
|
32
|
+
}: {
|
|
33
|
+
value?: FileData | null;
|
|
34
|
+
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
35
|
+
clear_color?: [number, number, number, number];
|
|
36
|
+
label?: string;
|
|
37
|
+
show_label: boolean;
|
|
38
|
+
root: string;
|
|
39
|
+
i18n: I18nFormatter;
|
|
40
|
+
zoom_speed?: number;
|
|
41
|
+
pan_speed?: number;
|
|
42
|
+
max_file_size?: number | null;
|
|
43
|
+
uploading?: boolean;
|
|
44
|
+
upload_promise?: Promise<(FileData | null)[]> | null;
|
|
45
|
+
camera_position?: [number | null, number | null, number | null];
|
|
46
|
+
upload: Client["upload"];
|
|
47
|
+
stream_handler: Client["stream"];
|
|
48
|
+
onchange?: (value: FileData | null) => void;
|
|
49
|
+
onclear?: () => void;
|
|
50
|
+
ondrag?: (dragging: boolean) => void;
|
|
51
|
+
onload?: (value: FileData) => void;
|
|
52
|
+
onerror?: (error: string) => void;
|
|
53
|
+
} = $props();
|
|
23
54
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
55
|
+
let use_3dgs = $state(false);
|
|
56
|
+
let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
|
|
57
|
+
let Canvas3DComponent = $state<typeof Canvas3D>();
|
|
58
|
+
let canvas3d = $state<Canvas3D | undefined>();
|
|
59
|
+
let dragging = $state(false);
|
|
60
|
+
|
|
61
|
+
async function loadCanvas3D(): Promise<typeof Canvas3D> {
|
|
62
|
+
const module = await import("./Canvas3D.svelte");
|
|
63
|
+
return module.default;
|
|
64
|
+
}
|
|
65
|
+
async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
|
|
66
|
+
const module = await import("./Canvas3DGS.svelte");
|
|
67
|
+
return module.default;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
$effect(() => {
|
|
71
|
+
if (value) {
|
|
72
|
+
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
|
|
73
|
+
if (use_3dgs) {
|
|
74
|
+
loadCanvas3DGS().then((component) => {
|
|
75
|
+
Canvas3DGSComponent = component;
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
loadCanvas3D().then((component) => {
|
|
79
|
+
Canvas3DComponent = component;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
$effect(() => {
|
|
86
|
+
ondrag?.(dragging);
|
|
87
|
+
});
|
|
32
88
|
|
|
33
89
|
async function handle_upload({
|
|
34
90
|
detail
|
|
35
91
|
}: CustomEvent<FileData>): Promise<void> {
|
|
36
92
|
value = detail;
|
|
37
93
|
await tick();
|
|
38
|
-
|
|
39
|
-
|
|
94
|
+
onchange?.(value);
|
|
95
|
+
onload?.(value as FileData);
|
|
40
96
|
}
|
|
41
97
|
|
|
42
98
|
async function handle_clear(): Promise<void> {
|
|
43
99
|
value = null;
|
|
44
100
|
await tick();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let use_3dgs = false;
|
|
50
|
-
let Canvas3DGSComponent: typeof Canvas3DGS;
|
|
51
|
-
let Canvas3DComponent: typeof Canvas3D;
|
|
52
|
-
async function loadCanvas3D(): Promise<typeof Canvas3D> {
|
|
53
|
-
const module = await import("./Canvas3D.svelte");
|
|
54
|
-
return module.default;
|
|
55
|
-
}
|
|
56
|
-
async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
|
|
57
|
-
const module = await import("./Canvas3DGS.svelte");
|
|
58
|
-
return module.default;
|
|
59
|
-
}
|
|
60
|
-
$: if (value) {
|
|
61
|
-
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
|
|
62
|
-
if (use_3dgs) {
|
|
63
|
-
loadCanvas3DGS().then((component) => {
|
|
64
|
-
Canvas3DGSComponent = component;
|
|
65
|
-
});
|
|
66
|
-
} else {
|
|
67
|
-
loadCanvas3D().then((component) => {
|
|
68
|
-
Canvas3DComponent = component;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
101
|
+
onclear?.();
|
|
102
|
+
onchange?.(null);
|
|
71
103
|
}
|
|
72
104
|
|
|
73
|
-
let canvas3d: Canvas3D | undefined;
|
|
74
105
|
async function handle_undo(): Promise<void> {
|
|
75
106
|
canvas3d?.reset_camera_position();
|
|
76
107
|
}
|
|
77
108
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
drag: boolean;
|
|
82
|
-
load: FileData;
|
|
83
|
-
}>();
|
|
84
|
-
|
|
85
|
-
let dragging = false;
|
|
86
|
-
|
|
87
|
-
$: dispatch("drag", dragging);
|
|
109
|
+
function handle_error({ detail }: CustomEvent<string>): void {
|
|
110
|
+
onerror?.(detail);
|
|
111
|
+
}
|
|
88
112
|
</script>
|
|
89
113
|
|
|
90
114
|
<BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
|
|
@@ -100,7 +124,7 @@
|
|
|
100
124
|
filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
|
|
101
125
|
bind:dragging
|
|
102
126
|
bind:uploading
|
|
103
|
-
on:error
|
|
127
|
+
on:error={handle_error}
|
|
104
128
|
aria_label={i18n("model3d.drop_to_upload")}
|
|
105
129
|
>
|
|
106
130
|
<slot />
|
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
import type { FileData, Client } from "@gradio/client";
|
|
2
2
|
import type { I18nFormatter } from "@gradio/utils";
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
value?: FileData | null;
|
|
5
|
+
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
6
|
+
clear_color?: [number, number, number, number];
|
|
7
|
+
label?: string;
|
|
8
|
+
show_label: boolean;
|
|
9
|
+
root: string;
|
|
10
|
+
i18n: I18nFormatter;
|
|
11
|
+
zoom_speed?: number;
|
|
12
|
+
pan_speed?: number;
|
|
13
|
+
max_file_size?: number | null;
|
|
14
|
+
uploading?: boolean;
|
|
15
|
+
upload_promise?: Promise<(FileData | null)[]> | null;
|
|
16
|
+
camera_position?: [number | null, number | null, number | null];
|
|
17
|
+
upload: Client["upload"];
|
|
18
|
+
stream_handler: Client["stream"];
|
|
19
|
+
onchange?: (value: FileData | null) => void;
|
|
20
|
+
onclear?: () => void;
|
|
21
|
+
ondrag?: (dragging: boolean) => void;
|
|
22
|
+
onload?: (value: FileData) => void;
|
|
23
|
+
onerror?: (error: string) => void;
|
|
24
|
+
};
|
|
3
25
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
4
26
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
5
27
|
$$bindings?: Bindings;
|
|
@@ -18,34 +40,12 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
|
18
40
|
} ? Props extends Record<string, never> ? any : {
|
|
19
41
|
children?: any;
|
|
20
42
|
} : {});
|
|
21
|
-
declare const Model3DUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren
|
|
22
|
-
value: null | FileData;
|
|
23
|
-
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
24
|
-
clear_color?: [number, number, number, number];
|
|
25
|
-
label?: string;
|
|
26
|
-
show_label: boolean;
|
|
27
|
-
root: string;
|
|
28
|
-
i18n: I18nFormatter;
|
|
29
|
-
zoom_speed?: number;
|
|
30
|
-
pan_speed?: number;
|
|
31
|
-
max_file_size?: number | null;
|
|
32
|
-
uploading?: boolean;
|
|
33
|
-
upload_promise?: Promise<(FileData | null)[]> | null;
|
|
34
|
-
camera_position?: [number | null, number | null, number | null];
|
|
35
|
-
upload: Client["upload"];
|
|
36
|
-
stream_handler: Client["stream"];
|
|
37
|
-
}, {
|
|
43
|
+
declare const Model3DUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<$$ComponentProps, {
|
|
38
44
|
default: {};
|
|
39
45
|
}>, {
|
|
40
|
-
error: CustomEvent<any>;
|
|
41
|
-
change: CustomEvent<FileData | null>;
|
|
42
|
-
clear: CustomEvent<undefined>;
|
|
43
|
-
drag: CustomEvent<boolean>;
|
|
44
|
-
load: CustomEvent<FileData>;
|
|
45
|
-
} & {
|
|
46
46
|
[evt: string]: CustomEvent<any>;
|
|
47
47
|
}, {
|
|
48
48
|
default: {};
|
|
49
|
-
}, {},
|
|
49
|
+
}, {}, "value" | "uploading" | "upload_promise">;
|
|
50
50
|
type Model3DUpload = InstanceType<typeof Model3DUpload>;
|
|
51
51
|
export default Model3DUpload;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/model3d",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"dequal": "^2.0.3",
|
|
15
15
|
"gsplat": "^1.2.9",
|
|
16
16
|
"@gradio/atoms": "^0.20.0",
|
|
17
|
-
"@gradio/
|
|
17
|
+
"@gradio/client": "^2.0.2",
|
|
18
18
|
"@gradio/statustracker": "^0.12.1",
|
|
19
|
+
"@gradio/icons": "^0.15.0",
|
|
19
20
|
"@gradio/upload": "^0.17.3",
|
|
20
|
-
"@gradio/
|
|
21
|
-
"@gradio/utils": "^0.11.0"
|
|
21
|
+
"@gradio/utils": "^0.11.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@gradio/preview": "^0.15.1"
|
package/shared/Canvas3D.svelte
CHANGED
|
@@ -5,19 +5,28 @@
|
|
|
5
5
|
|
|
6
6
|
let BABYLON_VIEWER: typeof import("@babylonjs/viewer");
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
let {
|
|
9
|
+
value,
|
|
10
|
+
display_mode,
|
|
11
|
+
clear_color,
|
|
12
|
+
camera_position,
|
|
13
|
+
zoom_speed,
|
|
14
|
+
pan_speed
|
|
15
|
+
}: {
|
|
16
|
+
value: FileData;
|
|
17
|
+
display_mode: "solid" | "point_cloud" | "wireframe";
|
|
18
|
+
clear_color: [number, number, number, number];
|
|
19
|
+
camera_position: [number | null, number | null, number | null];
|
|
20
|
+
zoom_speed: number;
|
|
21
|
+
pan_speed: number;
|
|
22
|
+
} = $props();
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
let url = $derived(value.url);
|
|
16
25
|
|
|
17
26
|
let canvas: HTMLCanvasElement;
|
|
18
|
-
let viewer
|
|
19
|
-
let viewerDetails
|
|
20
|
-
let mounted = false;
|
|
27
|
+
let viewer = $state<Viewer>();
|
|
28
|
+
let viewerDetails = $state<Readonly<ViewerDetails>>();
|
|
29
|
+
let mounted = $state(false);
|
|
21
30
|
|
|
22
31
|
onMount(() => {
|
|
23
32
|
const initViewer = async (): Promise<void> => {
|
|
@@ -43,9 +52,14 @@
|
|
|
43
52
|
};
|
|
44
53
|
});
|
|
45
54
|
|
|
46
|
-
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (mounted) {
|
|
57
|
+
load_model(url);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
47
60
|
|
|
48
61
|
function setRenderingMode(pointsCloud: boolean, wireframe: boolean): void {
|
|
62
|
+
if (!viewerDetails) return;
|
|
49
63
|
viewerDetails.scene.forcePointsCloud = pointsCloud;
|
|
50
64
|
viewerDetails.scene.forceWireframe = wireframe;
|
|
51
65
|
}
|
|
@@ -81,6 +95,7 @@
|
|
|
81
95
|
zoom_speed: number,
|
|
82
96
|
pan_speed: number
|
|
83
97
|
): void {
|
|
98
|
+
if (!viewerDetails) return;
|
|
84
99
|
const camera = viewerDetails.camera;
|
|
85
100
|
if (camera_position[0] !== null) {
|
|
86
101
|
camera.alpha = (camera_position[0] * Math.PI) / 180;
|
|
@@ -101,7 +116,7 @@
|
|
|
101
116
|
}
|
|
102
117
|
|
|
103
118
|
export function reset_camera_position(): void {
|
|
104
|
-
if (viewerDetails) {
|
|
119
|
+
if (viewerDetails && viewer) {
|
|
105
120
|
viewer.resetCamera();
|
|
106
121
|
}
|
|
107
122
|
}
|
package/shared/Canvas3DGS.svelte
CHANGED
|
@@ -3,19 +3,25 @@
|
|
|
3
3
|
import * as SPLAT from "gsplat";
|
|
4
4
|
import type { FileData } from "@gradio/client";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
let {
|
|
7
|
+
value,
|
|
8
|
+
zoom_speed,
|
|
9
|
+
pan_speed
|
|
10
|
+
}: {
|
|
11
|
+
value: FileData;
|
|
12
|
+
zoom_speed: number;
|
|
13
|
+
pan_speed: number;
|
|
14
|
+
} = $props();
|
|
15
|
+
|
|
16
|
+
let url = $derived(value.url);
|
|
11
17
|
|
|
12
18
|
let canvas: HTMLCanvasElement;
|
|
13
19
|
let scene: SPLAT.Scene;
|
|
14
20
|
let camera: SPLAT.Camera;
|
|
15
|
-
let renderer
|
|
21
|
+
let renderer = $state<SPLAT.WebGLRenderer | null>(null);
|
|
16
22
|
let controls: SPLAT.OrbitControls;
|
|
17
|
-
let mounted = false;
|
|
18
|
-
let frameId
|
|
23
|
+
let mounted = $state(false);
|
|
24
|
+
let frameId = $state<number | null>(null);
|
|
19
25
|
|
|
20
26
|
function reset_scene(): void {
|
|
21
27
|
if (frameId !== null) {
|
|
@@ -92,11 +98,13 @@
|
|
|
92
98
|
};
|
|
93
99
|
});
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
path: undefined
|
|
97
|
-
});
|
|
101
|
+
let path = $derived(value?.path);
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
$effect(() => {
|
|
104
|
+
if (canvas && mounted && path) {
|
|
105
|
+
reset_scene();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
100
108
|
</script>
|
|
101
109
|
|
|
102
110
|
<canvas bind:this={canvas}></canvas>
|
package/shared/Model3D.svelte
CHANGED
|
@@ -7,27 +7,36 @@
|
|
|
7
7
|
import type Canvas3DGS from "./Canvas3DGS.svelte";
|
|
8
8
|
import type Canvas3D from "./Canvas3D.svelte";
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
null
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
let {
|
|
11
|
+
value,
|
|
12
|
+
display_mode = "solid",
|
|
13
|
+
clear_color = [0, 0, 0, 0],
|
|
14
|
+
label = "",
|
|
15
|
+
show_label,
|
|
16
|
+
i18n,
|
|
17
|
+
zoom_speed = 1,
|
|
18
|
+
pan_speed = 1,
|
|
19
|
+
camera_position = [null, null, null],
|
|
20
|
+
has_change_history = false
|
|
21
|
+
}: {
|
|
22
|
+
value: FileData | null;
|
|
23
|
+
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
24
|
+
clear_color?: [number, number, number, number];
|
|
25
|
+
label?: string;
|
|
26
|
+
show_label: boolean;
|
|
27
|
+
i18n: I18nFormatter;
|
|
28
|
+
zoom_speed?: number;
|
|
29
|
+
pan_speed?: number;
|
|
30
|
+
camera_position?: [number | null, number | null, number | null];
|
|
31
|
+
has_change_history?: boolean;
|
|
32
|
+
} = $props();
|
|
25
33
|
|
|
26
|
-
let current_settings = { camera_position, zoom_speed, pan_speed };
|
|
34
|
+
let current_settings = $state({ camera_position, zoom_speed, pan_speed });
|
|
35
|
+
let use_3dgs = $state(false);
|
|
36
|
+
let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
|
|
37
|
+
let Canvas3DComponent = $state<typeof Canvas3D>();
|
|
38
|
+
let canvas3d = $state<Canvas3D | undefined>();
|
|
27
39
|
|
|
28
|
-
let use_3dgs = false;
|
|
29
|
-
let Canvas3DGSComponent: typeof Canvas3DGS;
|
|
30
|
-
let Canvas3DComponent: typeof Canvas3D;
|
|
31
40
|
async function loadCanvas3D(): Promise<typeof Canvas3D> {
|
|
32
41
|
const module = await import("./Canvas3D.svelte");
|
|
33
42
|
return module.default;
|
|
@@ -36,25 +45,27 @@
|
|
|
36
45
|
const module = await import("./Canvas3DGS.svelte");
|
|
37
46
|
return module.default;
|
|
38
47
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
$effect(() => {
|
|
50
|
+
if (value) {
|
|
51
|
+
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
|
|
52
|
+
if (use_3dgs) {
|
|
53
|
+
loadCanvas3DGS().then((component) => {
|
|
54
|
+
Canvas3DGSComponent = component;
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
loadCanvas3D().then((component) => {
|
|
58
|
+
Canvas3DComponent = component;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
|
-
}
|
|
62
|
+
});
|
|
51
63
|
|
|
52
|
-
let canvas3d: Canvas3D | undefined;
|
|
53
64
|
function handle_undo(): void {
|
|
54
65
|
canvas3d?.reset_camera_position();
|
|
55
66
|
}
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
$effect(() => {
|
|
58
69
|
if (
|
|
59
70
|
!dequal(current_settings.camera_position, camera_position) ||
|
|
60
71
|
current_settings.zoom_speed !== zoom_speed ||
|
|
@@ -63,7 +74,7 @@
|
|
|
63
74
|
canvas3d?.update_camera(camera_position, zoom_speed, pan_speed);
|
|
64
75
|
current_settings = { camera_position, zoom_speed, pan_speed };
|
|
65
76
|
}
|
|
66
|
-
}
|
|
77
|
+
});
|
|
67
78
|
</script>
|
|
68
79
|
|
|
69
80
|
<BlockLabel
|
|
@@ -79,7 +90,7 @@
|
|
|
79
90
|
<IconButton
|
|
80
91
|
Icon={Undo}
|
|
81
92
|
label="Undo"
|
|
82
|
-
|
|
93
|
+
onclick={() => handle_undo()}
|
|
83
94
|
disabled={!has_change_history}
|
|
84
95
|
/>
|
|
85
96
|
{/if}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { tick } from "svelte";
|
|
3
3
|
import { Upload, ModifyUpload } from "@gradio/upload";
|
|
4
4
|
import type { FileData, Client } from "@gradio/client";
|
|
5
5
|
import { BlockLabel } from "@gradio/atoms";
|
|
@@ -8,83 +8,107 @@
|
|
|
8
8
|
import type Canvas3DGS from "./Canvas3DGS.svelte";
|
|
9
9
|
import type Canvas3D from "./Canvas3D.svelte";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
let {
|
|
12
|
+
value = $bindable(),
|
|
13
|
+
display_mode = "solid",
|
|
14
|
+
clear_color = [0, 0, 0, 0],
|
|
15
|
+
label = "",
|
|
16
|
+
show_label,
|
|
17
|
+
root,
|
|
18
|
+
i18n,
|
|
19
|
+
zoom_speed = 1,
|
|
20
|
+
pan_speed = 1,
|
|
21
|
+
max_file_size = null,
|
|
22
|
+
uploading = $bindable(),
|
|
23
|
+
upload_promise = $bindable(),
|
|
24
|
+
camera_position = [null, null, null],
|
|
25
|
+
upload,
|
|
26
|
+
stream_handler,
|
|
27
|
+
onchange,
|
|
28
|
+
onclear,
|
|
29
|
+
ondrag,
|
|
30
|
+
onload,
|
|
31
|
+
onerror
|
|
32
|
+
}: {
|
|
33
|
+
value?: FileData | null;
|
|
34
|
+
display_mode?: "solid" | "point_cloud" | "wireframe";
|
|
35
|
+
clear_color?: [number, number, number, number];
|
|
36
|
+
label?: string;
|
|
37
|
+
show_label: boolean;
|
|
38
|
+
root: string;
|
|
39
|
+
i18n: I18nFormatter;
|
|
40
|
+
zoom_speed?: number;
|
|
41
|
+
pan_speed?: number;
|
|
42
|
+
max_file_size?: number | null;
|
|
43
|
+
uploading?: boolean;
|
|
44
|
+
upload_promise?: Promise<(FileData | null)[]> | null;
|
|
45
|
+
camera_position?: [number | null, number | null, number | null];
|
|
46
|
+
upload: Client["upload"];
|
|
47
|
+
stream_handler: Client["stream"];
|
|
48
|
+
onchange?: (value: FileData | null) => void;
|
|
49
|
+
onclear?: () => void;
|
|
50
|
+
ondrag?: (dragging: boolean) => void;
|
|
51
|
+
onload?: (value: FileData) => void;
|
|
52
|
+
onerror?: (error: string) => void;
|
|
53
|
+
} = $props();
|
|
23
54
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
55
|
+
let use_3dgs = $state(false);
|
|
56
|
+
let Canvas3DGSComponent = $state<typeof Canvas3DGS>();
|
|
57
|
+
let Canvas3DComponent = $state<typeof Canvas3D>();
|
|
58
|
+
let canvas3d = $state<Canvas3D | undefined>();
|
|
59
|
+
let dragging = $state(false);
|
|
60
|
+
|
|
61
|
+
async function loadCanvas3D(): Promise<typeof Canvas3D> {
|
|
62
|
+
const module = await import("./Canvas3D.svelte");
|
|
63
|
+
return module.default;
|
|
64
|
+
}
|
|
65
|
+
async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
|
|
66
|
+
const module = await import("./Canvas3DGS.svelte");
|
|
67
|
+
return module.default;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
$effect(() => {
|
|
71
|
+
if (value) {
|
|
72
|
+
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
|
|
73
|
+
if (use_3dgs) {
|
|
74
|
+
loadCanvas3DGS().then((component) => {
|
|
75
|
+
Canvas3DGSComponent = component;
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
loadCanvas3D().then((component) => {
|
|
79
|
+
Canvas3DComponent = component;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
$effect(() => {
|
|
86
|
+
ondrag?.(dragging);
|
|
87
|
+
});
|
|
32
88
|
|
|
33
89
|
async function handle_upload({
|
|
34
90
|
detail
|
|
35
91
|
}: CustomEvent<FileData>): Promise<void> {
|
|
36
92
|
value = detail;
|
|
37
93
|
await tick();
|
|
38
|
-
|
|
39
|
-
|
|
94
|
+
onchange?.(value);
|
|
95
|
+
onload?.(value as FileData);
|
|
40
96
|
}
|
|
41
97
|
|
|
42
98
|
async function handle_clear(): Promise<void> {
|
|
43
99
|
value = null;
|
|
44
100
|
await tick();
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let use_3dgs = false;
|
|
50
|
-
let Canvas3DGSComponent: typeof Canvas3DGS;
|
|
51
|
-
let Canvas3DComponent: typeof Canvas3D;
|
|
52
|
-
async function loadCanvas3D(): Promise<typeof Canvas3D> {
|
|
53
|
-
const module = await import("./Canvas3D.svelte");
|
|
54
|
-
return module.default;
|
|
55
|
-
}
|
|
56
|
-
async function loadCanvas3DGS(): Promise<typeof Canvas3DGS> {
|
|
57
|
-
const module = await import("./Canvas3DGS.svelte");
|
|
58
|
-
return module.default;
|
|
59
|
-
}
|
|
60
|
-
$: if (value) {
|
|
61
|
-
use_3dgs = value.path.endsWith(".splat") || value.path.endsWith(".ply");
|
|
62
|
-
if (use_3dgs) {
|
|
63
|
-
loadCanvas3DGS().then((component) => {
|
|
64
|
-
Canvas3DGSComponent = component;
|
|
65
|
-
});
|
|
66
|
-
} else {
|
|
67
|
-
loadCanvas3D().then((component) => {
|
|
68
|
-
Canvas3DComponent = component;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
101
|
+
onclear?.();
|
|
102
|
+
onchange?.(null);
|
|
71
103
|
}
|
|
72
104
|
|
|
73
|
-
let canvas3d: Canvas3D | undefined;
|
|
74
105
|
async function handle_undo(): Promise<void> {
|
|
75
106
|
canvas3d?.reset_camera_position();
|
|
76
107
|
}
|
|
77
108
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
drag: boolean;
|
|
82
|
-
load: FileData;
|
|
83
|
-
}>();
|
|
84
|
-
|
|
85
|
-
let dragging = false;
|
|
86
|
-
|
|
87
|
-
$: dispatch("drag", dragging);
|
|
109
|
+
function handle_error({ detail }: CustomEvent<string>): void {
|
|
110
|
+
onerror?.(detail);
|
|
111
|
+
}
|
|
88
112
|
</script>
|
|
89
113
|
|
|
90
114
|
<BlockLabel {show_label} Icon={File} label={label || "3D Model"} />
|
|
@@ -100,7 +124,7 @@
|
|
|
100
124
|
filetype={[".stl", ".obj", ".gltf", ".glb", "model/obj", ".splat", ".ply"]}
|
|
101
125
|
bind:dragging
|
|
102
126
|
bind:uploading
|
|
103
|
-
on:error
|
|
127
|
+
on:error={handle_error}
|
|
104
128
|
aria_label={i18n("model3d.drop_to_upload")}
|
|
105
129
|
>
|
|
106
130
|
<slot />
|