Spaces:
Running
Running
<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 --> | |