mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
feat: add dragging
This commit is contained in:
1 parent
1572b2ea06
commit
ca36f6391a
2 files changed
+80
-54
No files matched your search
@@ -1,10 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted, watch } from 'vue'
|
||||||
import { IQuest } from '@linux-odyssey/models'
|
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useToast } from 'vue-toastification'
|
import { useToast } from 'vue-toastification'
|
||||||
import { DAG } from '@linux-odyssey/utils'
|
import { DAG } from '@linux-odyssey/utils'
|
||||||
import api from '../utils/api'
|
import { getQuests } from '../utils/api'
|
||||||
import useUserProfile from '../store/userProfile'
|
import useUserProfile from '../store/userProfile'
|
||||||
|
|
||||||
const store = useUserProfile()
|
const store = useUserProfile()
|
||||||
@@ -14,22 +13,12 @@ const toast = useToast()
|
|||||||
const svgWidth = ref(window.innerWidth)
|
const svgWidth = ref(window.innerWidth)
|
||||||
const svgHeight = ref(window.innerHeight)
|
const svgHeight = ref(window.innerHeight)
|
||||||
|
|
||||||
const marginX = 80
|
const marginX = 100
|
||||||
const marginY = 80
|
const marginY = 100
|
||||||
|
|
||||||
const nodeWidth = 150
|
const nodeWidth = 150
|
||||||
const nodeHeight = 50
|
const nodeHeight = 50
|
||||||
|
|
||||||
async function getQuests() {
|
|
||||||
try {
|
|
||||||
const res = await api.get<IQuest[]>('/quests')
|
|
||||||
return res.data
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Node = {
|
type Node = {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
@@ -49,6 +38,28 @@ const graphData = ref<{ nodes: Node[]; edges: Edge[] }>({
|
|||||||
edges: [],
|
edges: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isDragging = ref(false)
|
||||||
|
const dragStartX = ref(0)
|
||||||
|
const dragStartY = ref(0)
|
||||||
|
const offsetX = ref(0)
|
||||||
|
const offsetY = ref(0)
|
||||||
|
|
||||||
|
function startDrag(event: MouseEvent) {
|
||||||
|
isDragging.value = true
|
||||||
|
dragStartX.value = event.clientX - offsetX.value
|
||||||
|
dragStartY.value = event.clientY - offsetY.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function drag(event: MouseEvent) {
|
||||||
|
if (!isDragging.value) return
|
||||||
|
offsetX.value = event.clientX - dragStartX.value
|
||||||
|
offsetY.value = event.clientY - dragStartY.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function endDrag() {
|
||||||
|
isDragging.value = false
|
||||||
|
}
|
||||||
|
|
||||||
async function computeGraphData() {
|
async function computeGraphData() {
|
||||||
if (!store.progress) return
|
if (!store.progress) return
|
||||||
|
|
||||||
@@ -112,47 +123,57 @@ watch(() => store.progress, computeGraphData, { deep: true })
|
|||||||
>
|
>
|
||||||
踏上你的Linux冒險之旅吧!
|
踏上你的Linux冒險之旅吧!
|
||||||
</h1>
|
</h1>
|
||||||
<svg :width="svgWidth" :height="svgHeight" class="absolute">
|
<svg
|
||||||
<!-- <g
|
:width="svgWidth"
|
||||||
v-for="edge in graphData.edges"
|
:height="svgHeight"
|
||||||
:key="`${edge.source.id}-${edge.target.id}`"
|
class="absolute"
|
||||||
>
|
@mousedown="startDrag"
|
||||||
<line
|
@mousemove="drag"
|
||||||
:x1="edge.source.x"
|
@mouseup="endDrag"
|
||||||
:y1="edge.source.y"
|
@mouseleave="endDrag"
|
||||||
:x2="edge.target.x"
|
>
|
||||||
:y2="edge.target.y"
|
<g :transform="`translate(${offsetX}, ${offsetY})`">
|
||||||
:stroke="edge.target.unlocked ? '#ADADB5' : '#454552'"
|
<!-- <g
|
||||||
:stroke-dasharray="edge.target.unlocked ? 'none' : '5,5'"
|
v-for="edge in graphData.edges"
|
||||||
stroke-width="3"
|
:key="`${edge.source.id}-${edge.target.id}`"
|
||||||
/>
|
|
||||||
</g> -->
|
|
||||||
<g
|
|
||||||
v-for="node in graphData.nodes"
|
|
||||||
:key="node.id"
|
|
||||||
@click="handleNodeClick(node)"
|
|
||||||
>
|
|
||||||
<rect
|
|
||||||
:x="node.x - nodeWidth / 2"
|
|
||||||
:y="node.y - nodeHeight / 2"
|
|
||||||
:width="nodeWidth"
|
|
||||||
:height="nodeHeight"
|
|
||||||
rx="10"
|
|
||||||
ry="10"
|
|
||||||
:fill="
|
|
||||||
node.completed ? '#00bb00' : node.unlocked ? '#ADADB5' : '#505050'
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<text
|
|
||||||
:x="node.x"
|
|
||||||
:y="node.y"
|
|
||||||
text-anchor="middle"
|
|
||||||
alignment-baseline="middle"
|
|
||||||
fill="white"
|
|
||||||
font-size="16"
|
|
||||||
>
|
>
|
||||||
{{ node.title }}
|
<line
|
||||||
</text>
|
:x1="edge.source.x"
|
||||||
|
:y1="edge.source.y"
|
||||||
|
:x2="edge.target.x"
|
||||||
|
:y2="edge.target.y"
|
||||||
|
:stroke="edge.target.unlocked ? '#ADADB5' : '#454552'"
|
||||||
|
:stroke-dasharray="edge.target.unlocked ? 'none' : '5,5'"
|
||||||
|
stroke-width="3"
|
||||||
|
/>
|
||||||
|
</g> -->
|
||||||
|
<g
|
||||||
|
v-for="node in graphData.nodes"
|
||||||
|
:key="node.id"
|
||||||
|
@click="handleNodeClick(node)"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
:x="node.x - nodeWidth / 2"
|
||||||
|
:y="node.y - nodeHeight / 2"
|
||||||
|
:width="nodeWidth"
|
||||||
|
:height="nodeHeight"
|
||||||
|
rx="10"
|
||||||
|
ry="10"
|
||||||
|
:fill="
|
||||||
|
node.completed ? '#00bb00' : node.unlocked ? '#ADADB5' : '#505050'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<text
|
||||||
|
:x="node.x"
|
||||||
|
:y="node.y"
|
||||||
|
text-anchor="middle"
|
||||||
|
alignment-baseline="middle"
|
||||||
|
fill="white"
|
||||||
|
font-size="16"
|
||||||
|
>
|
||||||
|
{{ node.title }}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -43,3 +43,8 @@ export async function getActiveSession(
|
|||||||
})
|
})
|
||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getQuests(): Promise<IQuest[]> {
|
||||||
|
const res = await api.get<IQuest[]>('/quests')
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
Reference in new issue
Block a user