File size: 2,457 Bytes
ca4340e
18b0fa5
 
 
 
 
 
ca4340e
 
18b0fa5
ca4340e
 
 
 
 
 
 
 
 
18b0fa5
 
ca4340e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18b0fa5
ca4340e
 
 
 
 
18b0fa5
ca4340e
18b0fa5
ca4340e
 
 
 
 
 
 
 
 
 
 
 
 
18b0fa5
ca4340e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18b0fa5
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
<script lang="ts">
	import { T } from "@threlte/core";
	import { TransformControls, interactivity } from "@threlte/extras";
	import type { Snippet } from "svelte";
	import { Spring } from "svelte/motion";
	import { useCursor } from "@threlte/extras";
	import { setContext } from "svelte";

	interface Props {
		content: Snippet<[{ isHighlighted: boolean }]>; // renderable
		enableEdit?: boolean;
		hoverColor?: string;
		defaultColor?: string;
		hoverOpacity?: number;
	}

	let {
		content,
		enableEdit = $bindable(true),
		hoverColor = "#ffa348",
		hoverOpacity = 0.5
	}: Props = $props();

	interactivity();
	const scale = new Spring(1);

	// Position state to persist transforms
	let position = $state<[number, number, number]>([0, 0, 0]);
	let rotation = $state<[number, number, number]>([0, 0, 0]);

	// Hover state
	let isHovered = $state(false);
	let isSelected = $state(false);
	let isHighlighted = $derived(enableEdit && (isSelected || isHovered));

	$effect(() => {
		// If isHighlighted is true, set the color to hoverColor and opacity to hoverOpacity
		if (isHighlighted) {
			scale.target = 1.05;
		} else {
			scale.target = 1;
		}
	});

	const { onPointerEnter, onPointerLeave } = useCursor();

	// Handle keyboard events for deselection
	$effect(() => {
		const handleKeyDown = (event: KeyboardEvent) => {
			if (event.key === "Escape" && isSelected) {
				isSelected = false;
			}
		};

		if (isSelected) {
			document.addEventListener("keydown", handleKeyDown);
			return () => {
				document.removeEventListener("keydown", handleKeyDown);
			};
		}
	});

	// Handle transform changes
	const handleTransform = (ref: any) => {
		ref.updateMatrix();
		// Update our position state from the object's current position
		position = ref.position.toArray();
		rotation = ref.rotation.toArray();
	};
</script>

<T.Group
	{position}
	{rotation}
	onclick={() => {
		isSelected = true;
	}}
	onpointerenter={() => {
		onPointerEnter();
		isHovered = true;
	}}
	onpointerleave={() => {
		onPointerLeave();
		isHovered = false;
	}}
	scale={scale.current}
>
	{#snippet children({ ref })}
		{@render content({ isHighlighted })}
		{#if isSelected && enableEdit}
			<TransformControls
				object={ref}
				mode="translate"
				showY={false}
				axis="XZ"
				space="world"
				on:objectChange={() => handleTransform(ref)}
				on:mouseUp={() => handleTransform(ref)}
			/>
		{/if}
	{/snippet}
</T.Group>

<!-- From https://github.com/brean/urdf-viewer -->