Feat : add card drag

This commit is contained in:
2024-07-08 10:46:44 +02:00
parent 9e985ad471
commit 6cdd846d3f
2 changed files with 161 additions and 30 deletions
+155 -25
View File
@@ -20,7 +20,7 @@ const props = withDefaults(defineProps<Props>(), {
noEffects: () => false,
});
const emit = defineEmits(["click", "effectClick"]);
const emit = defineEmits(["click", "effectClick", "drop", "move"]);
const settingsStore = useSettingsStore();
@@ -28,12 +28,32 @@ const childCount = ref<number>(0);
const card = ref<HTMLElement>();
const dragStatus = ref<{
hasClickedDown: boolean;
dragging: boolean;
intervalEvent?: ReturnType<typeof setTimeout>;
}>({
hasClickedDown: false,
dragging: false,
});
const initialOffsetX = ref(0);
const initialOffsetY = ref(0);
const offsetX = ref(0);
const offsetY = ref(0);
const offsetWidth = ref(0);
const offsetHeight = ref(0);
const translateX = ref(0);
const translateY = ref(0);
const extension = computed(() => {
if (settingsStore.cardStyle == CardStyles.SVG) {
return ".svg";
}
return ".png";
});
function cardClick() {
if (!props.card_id) return;
emit("click");
@@ -51,6 +71,8 @@ function mouseenter(e: MouseEvent) {
}
function mouseleave(e: MouseEvent) {
isZooming.value = false;
dragStatus.value.dragging = false;
clearTimeout(dragStatus.value.intervalEvent);
}
function rightClickDown(e: MouseEvent) {
@@ -61,8 +83,102 @@ function rightClickUp(e: MouseEvent) {
isZooming.value = false;
}
function startDrag(e: MouseEvent) {
dragStatus.value.dragging = true;
translateX.value = 0;
translateY.value = 0;
const cardElement = card.value;
if (!cardElement) {
return;
}
initialOffsetX.value = e.offsetX;
initialOffsetY.value = e.offsetY;
offsetX.value = cardElement.offsetLeft + e.offsetX;
offsetY.value = cardElement.offsetTop + e.offsetY;
translateX.value = e.pageX - offsetX.value;
translateY.value = e.pageY - offsetY.value;
}
function leftClickDown(e: MouseEvent) {
dragStatus.value.hasClickedDown = true;
window.addEventListener("mousemove", mouseMove, false);
}
function leftClickUpGlobal(e: MouseEvent) {
dragStatus.value.dragging = false;
clearTimeout(dragStatus.value.intervalEvent);
window.removeEventListener("mousemove", mouseMove, false);
}
function leftClickUp(e: MouseEvent) {
if (dragStatus.value.dragging == false && dragStatus.value.hasClickedDown) {
dragStatus.value.hasClickedDown = false;
cardClick();
return;
}
if (dragStatus.value.dragging && dragStatus.value.hasClickedDown) {
dragStatus.value.dragging = false;
dragStatus.value.hasClickedDown = false;
emit("drop", { x: e.pageX, y: e.pageY, uuid: props.card?._id });
}
}
const sensitivity = 0.5;
function mouseMove(e: MouseEvent) {
if (
dragStatus.value.hasClickedDown &&
!dragStatus.value.dragging &&
Math.sqrt(Math.abs(e.movementX * e.movementY)) > sensitivity
) {
startDrag(e);
}
const cardElement = card.value;
if (!cardElement) {
return;
}
// console.log(cardElement.offsetLeft);
offsetX.value = cardElement.offsetLeft + initialOffsetX.value;
offsetY.value = cardElement.offsetTop + initialOffsetY.value;
translateX.value = e.pageX - offsetX.value;
translateY.value = e.pageY - offsetY.value;
emit("move", { x: e.pageX, y: e.pageY, uuid: props.card?._id });
}
defineExpose({
offsetX,
offsetY,
offsetWidth,
offsetHeight,
uuid: props.card?._id,
});
onMounted(() => {
card.value?.style.setProperty("--random-seed", -Math.random() * 10 + "s");
window.addEventListener("mouseup", leftClickUpGlobal, false);
const cardElement = card.value;
if (!cardElement) {
return;
}
offsetX.value = cardElement.offsetLeft;
offsetY.value = cardElement.offsetTop;
offsetWidth.value = cardElement.offsetWidth;
offsetHeight.value = cardElement.offsetHeight;
cardElement.offsetWidth;
});
onRenderTriggered(() => {
const cardElement = card.value;
if (!cardElement) {
return;
}
offsetX.value = cardElement.offsetLeft;
offsetY.value = cardElement.offsetTop;
});
onUnmounted(() => {
window.removeEventListener("mouseup", leftClickUpGlobal, false);
// window.addEventListener("mousemove", mouseMove, false);
});
</script>
@@ -71,6 +187,7 @@ onMounted(() => {
ref="card"
class="card"
:class="{
dragging: dragStatus.dragging,
active: childCount > 0,
wrapped,
unlocked: !props.locked,
@@ -78,18 +195,13 @@ onMounted(() => {
no_effects: noEffects || !props.locked,
}"
@contextmenu.prevent="false"
@click.left="cardClick"
@mousedown.right="rightClickDown"
@mouseup.right="rightClickUp"
@mouseenter="mouseenter"
@mouseleave="mouseleave"
@mousedown.left="leftClickDown"
@mouseup.left="leftClickUp"
>
<div
id="contextMenuButtons"
:ref="(el) => { childCount = ((el as Element)?.childElementCount ?? 0) }"
>
<slot></slot>
</div>
<div id="overlay"><slot></slot></div>
<template v-if="props.card_id">
<!-- <svg
width="180"
@@ -146,10 +258,41 @@ onMounted(() => {
justify-content: center;
margin-bottom: 0px;
margin-top: var(--margin-bottom);
transition: all 0.075s cubic-bezier(1, 1.81, 0.59, 1.42);
transition: all 0.15s cubic-bezier(0.175, 0.885, 0.32, 1.275);
pointer-events: all;
max-height: var(--max-height);
max-width: var(--max-width);
/* cursor: grab; */
}
#overlay {
position: absolute;
z-index: 111;
}
.card.unlocked {
margin-top: 0px;
margin-bottom: var(--margin-bottom);
transform: translateY(calc(var(--margin-bottom) * -0.25));
filter: drop-shadow(
calc(var(--margin-bottom) * 0.3) var(--margin-bottom) 1px rgba(0, 0, 0, 0.6)
);
cursor: pointer;
}
.card:not(svg) {
cursor: grab;
}
.card.dragging {
transform: translateX(v-bind("translateX + 'px'"))
translateY(v-bind("translateY + 'px'"));
cursor: grabbing;
z-index: 999;
}
.card.dragging > svg {
transform: scale(110%);
}
.card.active {
@@ -172,15 +315,6 @@ onMounted(() => {
drop-shadow(-0.5px -0.5px 0.5px gray);
}
.card.unlocked {
margin-top: 0px;
margin-bottom: var(--margin-bottom);
transform: translateY(calc(var(--margin-bottom) * -0.25));
filter: drop-shadow(
calc(var(--margin-bottom) * 0.3) var(--margin-bottom) 1px rgba(0, 0, 0, 0.6)
);
}
.card.zoom {
transform: scale(200%);
z-index: 10;
@@ -207,10 +341,6 @@ onMounted(() => {
pointer-events: none;
}
.card.no_effects {
cursor: pointer;
}
#contextMenuButtons > * {
flex: 1;
border-radius: 12px;