Skip to content

Instantly share code, notes, and snippets.

@michaelevensen
Last active December 1, 2023 22:46
Show Gist options
  • Save michaelevensen/3f2d4b9901d1d17a50612c5326ca0921 to your computer and use it in GitHub Desktop.
Save michaelevensen/3f2d4b9901d1d17a50612c5326ca0921 to your computer and use it in GitHub Desktop.
Wrap anything in this and you get nice spring draggability. Just be aware that the relative positioning is `window`.
<script lang="ts">
import { spring } from 'svelte/motion';
export let position = { x: 0, y: 0 };
let dragging = false;
const start = () => {
dragging = true;
};
const stop = () => {
dragging = false;
};
const move = (evt: MouseEvent) => {
if (dragging) {
transform.update((prev) => ({
...prev,
x: prev.x + evt.movementX,
y: prev.y + evt.movementY
}));
}
};
$: if (dragging) {
transform.update((prev) => ({ ...prev, rotate: 10, scale: 1.05 }));
} else {
transform.update((prev) => ({ ...prev, rotate: 0, scale: 1 }));
}
export let transform = spring(
{
x: position.x,
y: position.y,
rotate: 0,
scale: 1
},
{
stiffness: 0.1,
damping: 0.25
}
);
</script>
<svelte:window on:mousemove={move} on:mouseup={stop} />
<div
role="button"
tabindex="0"
class="draggable"
on:mousedown={start}
style:transform={`
translateX(${$transform.x}px)
translateY(${$transform.y}px)
rotateX(${$transform.rotate}deg) rotateY(${$transform.rotate}deg)
scale(${$transform.scale})
`}
>
<slot />
</div>
<style>
.draggable {
width: fit-content;
transform-origin: 50% 50%;
transition: all 0.05s ease-out;
user-select: none;
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.draggable:active {
z-index: 999;
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment