Feat : add card drag
This commit is contained in:
+155
-25
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user