현재 대시보드를 개발하면서 기록하고 싶은 이슈가 있어 이 글을 작성하게 되었다.
개발 중인 대시보드에는 여러 개의 영역이 있고 각 영역마다 드래그&드롭 하여 위치를 변경할 수 있다.
일반적인 영역의 경우 아무 문제 없이 동작하지만, 차트를 포함한 영역의 경우 드래그 중일 때 차트가 사라지고 드롭 후에 차트가 다시 생기는 문제가 있었다.
나는 드래그는 vue-draggable-next 라이브러리를 사용하였고, 차트는 vue-chartjs를 사용하여 개발하였는데,
처음에는 라이브러리의 문제인 줄 알고 차트와 드래그 기능을 직접 만들어보았지만 여전히 같은 문제가 발생하였다.
원인은 아직 파악하지 못하였고,
드래그 시작 할 때 차트의 canvas 부분을 이미지로 만들어서 그 이미지를 보여주는 방식으로 해결하였다.
아래는 해결한 코드!
<template>
<VueDraggableNext
v-model="data.filteredWidgets"
class="dashboard-content"
ghost-class="ghost"
chosen-class="active"
:delay="300"
:delayOnTouchOnly="true"
@end="dragEnd"
@start="dragStart"
>
<template v-for="item in data.filteredWidgets">
<widget :list="[item]" :close-btn="true" @remove="remove">
<template #content>
<component
:is="item.component"
:key="item.programCode"
:list="item.data"
/>
</template>
</widget>
</template>
</VueDraggableNext>
</template>
<script setup>
const dragStart = (type) => {
const originalContent = document.querySelector(
".dashboard-content .sortable-drag",
);
if (originalContent) {
originalContent.style.opacity = 1;
}
// 드래그 중인 요소에 차트를 포함한 경우 캔버스 영역을 이미지로 만들어서 해당 이미지로 노출
const originalWidgetContent =
originalContent?.querySelector(".widget-content");
const originalCanvas = originalWidgetContent?.querySelector("canvas");
const draggedContent = document.querySelector(
".dashboard-content > .active .widget-content",
);
const draggedCanvas = draggedContent?.querySelector("canvas");
if (draggedCanvas && originalCanvas) {
const canvasImg = new Image(
draggedCanvas.clientWidth,
draggedCanvas.clientHeight,
);
canvasImg.src = draggedCanvas.toDataURL("image/jpeg");
originalWidgetContent?.replaceChild(canvasImg, originalCanvas);
}
const ghostContainer = document.querySelector(".dashboard-content .active");
const ghostWidgetContainer =
ghostContainer?.querySelector(".widget-container");
const ghostContent = ghostWidgetContainer?.querySelector(".widget-content");
if (ghostContent) {
ghostContent.style.visibility = "hidden";
ghostWidgetContainer.classList.add("focus");
ghostContainer.classList.remove("active");
}
};
const dragEnd = () => {
const ghostContainers = document.querySelectorAll(
".dashboard-content .widget-container",
);
if (ghostContainers?.length) {
ghostContainers.forEach((item) => {
const ghostContent = item.querySelector(".widget-content");
if (ghostContent?.style) {
item.querySelector(".widget-content").style.visibility = "visible";
}
item.classList.remove("focus");
});
}
}
</script>
'FrontEnd' 카테고리의 다른 글
[iOS] 사파리에서 전화번호/팩스번호/사업자번호 자동 인식 문제 (0) | 2025.01.17 |
---|---|
Vue3 - 브라우저 뒤로가기 시 이벤트 제어 (0) | 2024.03.19 |
Vite (0) | 2023.11.12 |
Vue3 - Composition API 사용법 (1) | 2023.11.12 |
Vue2와 Vue3의 차이 (0) | 2023.11.09 |