GREEN|CSV[.1]

>_Sandbox >_About

Drag to change the side

Dragme

Component Source

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";

const box = ref({ x: 0, y: 100 });
const isDragging = ref(false);
const dragStart = ref({ x: 0, y: 0 });
const containerRef = ref<HTMLElement | null>(null);

function onMouseDown(event: MouseEvent) {
    isDragging.value = true;

    const container = containerRef.value;
    if (!container) return;

    const rect = container.getBoundingClientRect();
    dragStart.value = {
        x: event.clientX - rect.left - box.value.x,
        y: event.clientY - rect.top - box.value.y,
    };
}

function onMouseMove(event: MouseEvent) {
    if (!isDragging.value) return;

    const container = containerRef.value;
    if (!container) return;

    const rect = container.getBoundingClientRect();
    const elementWidth = 80;

    let newX = event.clientX - rect.left - dragStart.value.x;
    let newY = event.clientY - rect.top - dragStart.value.y;

    // Keep within bounds
    newX = Math.max(0, Math.min(newX, rect.width - elementWidth));
    newY = Math.max(0, Math.min(newY, rect.height - 80));

    box.value = { x: newX, y: newY };
}

function onMouseUp() {
    if (!isDragging.value) return;    
    isDragging.value = false;

    const container = containerRef.value;
    if (!container) return;

    const rect = container.getBoundingClientRect();
    const elementWidth = 80;
    const centerX = box.value.x + elementWidth / 2;

    if (centerX < rect.width / 2) {
        box.value.x = 0;
    } else {
        box.value.x = rect.width - elementWidth;
    }
}

onMounted(() => {
    window.addEventListener("mousemove", onMouseMove);
    window.addEventListener("mouseup", onMouseUp);
});

onUnmounted(() => {
    window.removeEventListener("mousemove", onMouseMove);
    window.removeEventListener("mouseup", onMouseUp);
});
</script>

<template>
    <div class="p-5 flex items-center justify-center bg-pink-600">        
        <div
            ref="containerRef"
            class="relative w-[600px] h-[400px] border-2 border-cyan-400"
        >
            <div
                class="absolute left-1/2 top-0 bottom-0 border-l-2 border-dotted border-cyan-300"
            ></div>

            <div
                 class="absolute w-[80px] h-[80px] bg-violet-600 select-none" 
                :style="{
                    left: box.x + 'px',
                    top: box.y + 'px',
                }"
                @mousedown="onMouseDown"
            >
                Dragme
            </div>
        </div>
    </div>
</template>