Skip to content

Commit 6e6ec71

Browse files
committed
refactor: module graph
1 parent 473f8ae commit 6e6ec71

File tree

3 files changed

+708
-4
lines changed

3 files changed

+708
-4
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
<script setup lang="ts" generic="T extends { id: string, imports: unknown[] }, I">
2+
import type { SessionContext } from '~~/shared/types'
3+
import type { ModuleGraphLink } from '~/composables/moduleGraph'
4+
import { linkHorizontal, linkVertical } from 'd3-shape'
5+
import { onMounted, unref, watch } from 'vue'
6+
import { useGraphDraggingScroll, useGraphZoom, useModuleGraph, useToggleGraphNodeExpanded } from '~/composables/moduleGraph'
7+
8+
const props = defineProps<{
9+
modules: T[]
10+
session: SessionContext
11+
}>()
12+
13+
const { isFirstCalculateGraph, childToParentMap, collapsedNodes, calculateGraph, container, width, height, scale, nodes, links, spacing, nodesRefMap } = useModuleGraph()
14+
const { isGrabbing, init } = useGraphDraggingScroll()
15+
const { zoomIn, zoomOut, ZOOM_MIN, ZOOM_MAX } = useGraphZoom()
16+
const { isGraphNodeToggling, toggleNode, expandAll, collapseAll } = useToggleGraphNodeExpanded({
17+
modules: props.modules,
18+
})
19+
20+
const createLinkHorizontal = linkHorizontal()
21+
.x(d => d[0])
22+
.y(d => d[1])
23+
24+
const createLinkVertical = linkVertical()
25+
.x(d => d[0])
26+
.y(d => d[1])
27+
28+
function generateLink(link: ModuleGraphLink<T, I>) {
29+
if (link.target.x! <= link.source.x!) {
30+
return createLinkVertical({
31+
source: [link.source.x! + unref(spacing.width) / 2 - unref(spacing.linkOffset), link.source.y!],
32+
target: [link.target.x! - unref(spacing.width) / 2 + unref(spacing.linkOffset), link.target.y!],
33+
})
34+
}
35+
return createLinkHorizontal({
36+
source: [link.source.x! + unref(spacing.width) / 2 - unref(spacing.linkOffset), link.source.y!],
37+
target: [link.target.x! - unref(spacing.width) / 2 + unref(spacing.linkOffset), link.target.y!],
38+
})
39+
}
40+
41+
function getLinkColor(_link: ModuleGraphLink<T, I>) {
42+
return 'stroke-#8885'
43+
}
44+
45+
onMounted(() => {
46+
init()
47+
48+
watch(
49+
() => props.modules,
50+
() => {
51+
isFirstCalculateGraph.value = true
52+
collapsedNodes.clear()
53+
childToParentMap.clear()
54+
calculateGraph()
55+
},
56+
{ immediate: true },
57+
)
58+
})
59+
</script>
60+
61+
<template>
62+
<div
63+
ref="container"
64+
w-full h-screen of-scroll relative select-none
65+
:class="isGrabbing ? 'cursor-grabbing' : ''"
66+
>
67+
<div
68+
:style="{
69+
width: `${width * scale}px`,
70+
height: `${height * scale}px`,
71+
}"
72+
>
73+
<!-- Make this <div> in order to expand the scroll bar -->
74+
<div
75+
flex="~ items-center justify-center"
76+
:style="{ transform: `scale(${scale})`, transformOrigin: '0 0' }"
77+
>
78+
<div
79+
absolute left-0 top-0
80+
:style="{
81+
width: `${width}px`,
82+
height: `${height}px`,
83+
}"
84+
class="bg-dots"
85+
/>
86+
<svg pointer-events-none absolute left-0 top-0 z-graph-link :width="width" :height="height">
87+
<g>
88+
<path
89+
v-for="link of links"
90+
:key="link.id"
91+
:d="generateLink(link)!"
92+
:class="getLinkColor(link)"
93+
:stroke-dasharray="link.import?.kind === 'dynamic-import' ? '3 6' : undefined"
94+
fill="none"
95+
/>
96+
</g>
97+
</svg>
98+
<template
99+
v-for="node of nodes"
100+
:key="node.data.module.id"
101+
>
102+
<template v-if="node.data.module.id !== '~root'">
103+
<div
104+
absolute
105+
class="group z-graph-node flex gap-1 items-center"
106+
:style="{
107+
left: `${node.x}px`,
108+
top: `${node.y}px`,
109+
transform: 'translate(-50%, -50%)',
110+
}"
111+
>
112+
<div
113+
flex="~ items-center gap-1"
114+
bg-glass
115+
border="~ base rounded"
116+
class="group-hover:bg-active block px2 p1"
117+
:style="{
118+
minWidth: `${unref(spacing.width)}px`,
119+
maxWidth: `${unref(spacing.width)}px`,
120+
maxHeight: `${unref(spacing.height)}px`,
121+
overflow: 'hidden',
122+
transition: 'all 0.3s ease',
123+
}"
124+
>
125+
<slot :node="node" :nodes-ref-map="nodesRefMap" />
126+
</div>
127+
128+
<!-- Expand/Collapse Button -->
129+
<div class="w-4">
130+
<button
131+
v-if="node.data.hasChildren"
132+
w-4
133+
h-4
134+
rounded-full
135+
flex="items-center justify-center"
136+
text-xs
137+
border="~ active"
138+
class="flex cursor-pointer z-graph-node-active bg-base"
139+
:disabled="isGraphNodeToggling"
140+
:class="{ 'cursor-not-allowed': isGraphNodeToggling, 'hover:bg-active': !isGraphNodeToggling }"
141+
:title="node.data.expanded ? 'Collapse' : 'Expand'"
142+
@click.stop="toggleNode(node.data.module.id)"
143+
>
144+
<div
145+
class="text-primary h-4"
146+
:class="[
147+
node.data.expanded ? 'i-ph-minus' : 'i-ph-plus',
148+
]"
149+
transition="transform duration-200"
150+
/>
151+
</button>
152+
</div>
153+
</div>
154+
</template>
155+
</template>
156+
</div>
157+
</div>
158+
<div
159+
fixed right-6 bottom-6 z-panel-nav flex="~ col gap-2 items-center"
160+
>
161+
<div w-10 flex="~ items-center justify-center">
162+
<DisplayTimeoutView :content="`${Math.round(scale * 100)}%`" class="text-sm" />
163+
</div>
164+
165+
<div bg-glass rounded-full border border-base shadow flex="~ col gap-1 p1">
166+
<button
167+
v-tooltip.left="'Expand All'"
168+
w-10 h-10 rounded-full hover:bg-active op-fade
169+
hover:op100 flex="~ items-center justify-center"
170+
:disabled="isGraphNodeToggling"
171+
:class="{ 'op50 cursor-not-allowed': isGraphNodeToggling, 'hover:bg-active': !isGraphNodeToggling }"
172+
title="Expand All"
173+
@click="expandAll()"
174+
>
175+
<div class="i-carbon:expand-categories" />
176+
</button>
177+
<button
178+
v-tooltip.left="'Collapse All'"
179+
w-10 h-10 rounded-full hover:bg-active op-fade
180+
hover:op100 flex="~ items-center justify-center"
181+
:disabled="isGraphNodeToggling"
182+
:class="{ 'op50 cursor-not-allowed': isGraphNodeToggling, 'hover:bg-active': !isGraphNodeToggling }"
183+
title="Collapse All"
184+
@click="collapseAll()"
185+
>
186+
<div class="i-carbon:collapse-categories" />
187+
</button>
188+
189+
<div border="t base" my1 />
190+
191+
<button
192+
v-tooltip.left="'Zoom In (Ctrl + =)'"
193+
:disabled="scale >= ZOOM_MAX"
194+
w-10 h-10 rounded-full hover:bg-active op-fade
195+
hover:op100 disabled:op20 disabled:bg-none
196+
disabled:cursor-not-allowed
197+
flex="~ items-center justify-center"
198+
title="Zoom In (Ctrl + =)"
199+
@click="zoomIn()"
200+
>
201+
<div i-ph-magnifying-glass-plus-duotone />
202+
</button>
203+
<button
204+
v-tooltip.left="'Zoom Out (Ctrl + -)'"
205+
:disabled="scale <= ZOOM_MIN"
206+
w-10 h-10 rounded-full hover:bg-active op-fade hover:op100
207+
disabled:op20 disabled:bg-none disabled:cursor-not-allowed
208+
flex="~ items-center justify-center"
209+
title="Zoom Out (Ctrl + -)"
210+
@click="zoomOut()"
211+
>
212+
<div i-ph-magnifying-glass-minus-duotone />
213+
</button>
214+
</div>
215+
</div>
216+
</div>
217+
</template>

0 commit comments

Comments
 (0)