|
1 | 1 | <template> |
2 | | - <main class="relative h-screen-main grid place-items-center"> |
| 2 | + <main class="relative h-screen-main grid place-items-center select-none"> |
3 | 3 | <Head> |
4 | 4 | <Title>Sub Skill Tree - {{ subTreeName }}</Title> |
5 | 5 | </Head> |
|
17 | 17 | v-else-if="nodes && nodes.length" |
18 | 18 | class="map w-screen h-fit m-auto max-w-[100vw] h-screen-main overflow-scroll" |
19 | 19 | ref="mainRef" |
| 20 | + @mousedown="startDrag" |
| 21 | + :class="{ 'cursor-grabbing': isDragging }" |
20 | 22 | > |
21 | 23 | <svg :width="mapWidth" :height="mapHeight" :viewBox="mapViewBox"> |
22 | 24 | <g v-if="setupComplete && selectedNode.id == ''"> |
|
69 | 71 |
|
70 | 72 | <script lang="ts"> |
71 | 73 | import { useI18n } from "vue-i18n"; |
72 | | -import type { Ref } from "vue"; |
| 74 | +import { useSubSkillTree, getSubSkillTree, createPathwaysForTree } from "~/composables/skilltree"; |
73 | 75 |
|
74 | 76 | export default { |
75 | 77 | head: { |
@@ -359,6 +361,50 @@ export default { |
359 | 361 | { immediate: true, deep: true } |
360 | 362 | ); |
361 | 363 |
|
| 364 | + // ! ======================================================= Dragging |
| 365 | + const isDragging = ref(false); |
| 366 | + const startX = ref(0); |
| 367 | + const startY = ref(0); |
| 368 | + const scrollLeft = ref(0); |
| 369 | + const scrollTop = ref(0); |
| 370 | +
|
| 371 | + const startDrag = (event: MouseEvent) => { |
| 372 | + if (event.button !== 0) return; |
| 373 | +
|
| 374 | + const target = event.target as HTMLElement; |
| 375 | + if (target.tagName === "foreignObject" || target.tagName === "path") return; |
| 376 | +
|
| 377 | + isDragging.value = true; |
| 378 | + startX.value = event.pageX - mainRef.value!.offsetLeft; |
| 379 | + startY.value = event.pageY - mainRef.value!.offsetTop; |
| 380 | + scrollLeft.value = mainRef.value!.scrollLeft; |
| 381 | + scrollTop.value = mainRef.value!.scrollTop; |
| 382 | + document.addEventListener("mousemove", drag); |
| 383 | + document.addEventListener("mouseup", stopDrag); |
| 384 | + }; |
| 385 | +
|
| 386 | + const drag = (event: MouseEvent) => { |
| 387 | + if (!isDragging.value) return; |
| 388 | + event.preventDefault(); |
| 389 | + const x = event.pageX - mainRef.value!.offsetLeft; |
| 390 | + const y = event.pageY - mainRef.value!.offsetTop; |
| 391 | + const walkX = x - startX.value; |
| 392 | + const walkY = y - startY.value; |
| 393 | +
|
| 394 | + mainRef.value!.scrollLeft = scrollLeft.value - walkX; |
| 395 | + mainRef.value!.scrollTop = scrollTop.value - walkY; |
| 396 | +
|
| 397 | + if (event.clientX <= 0 || event.clientX >= window.innerWidth || event.clientY <= 0 || event.clientY >= window.innerHeight) { |
| 398 | + stopDrag(); |
| 399 | + } |
| 400 | + }; |
| 401 | +
|
| 402 | + const stopDrag = () => { |
| 403 | + isDragging.value = false; |
| 404 | + document.removeEventListener("mousemove", drag); |
| 405 | + document.removeEventListener("mouseup", stopDrag); |
| 406 | + }; |
| 407 | +
|
362 | 408 | return { |
363 | 409 | setupComplete, |
364 | 410 | loading, |
@@ -387,6 +433,9 @@ export default { |
387 | 433 | t, |
388 | 434 | subTreeName, |
389 | 435 | breadcrumbs, |
| 436 | +
|
| 437 | + isDragging, |
| 438 | + startDrag, |
390 | 439 | }; |
391 | 440 | }, |
392 | 441 | }; |
|
0 commit comments