@@ -13,24 +13,25 @@ import { onMounted, ref, useTemplateRef, watch } from 'vue'
1313
1414const props = defineProps <{ model: NodeLinkGraph }>()
1515
16+ export interface NodeLinkGraph {
17+ nodes: Record <string , GraphNodeDatum >
18+ links: GraphLinkDatum []
19+ }
20+
1621export interface GraphNodeDatum extends SimulationNodeDatum {
1722 id: string
1823 group: string
1924 name? : string
2025 dark? : boolean
2126 condition? : string
2227 level? : number
28+ parent? : string
2329}
2430
2531export interface GraphLinkDatum extends SimulationLinkDatum <GraphNodeDatum > {
2632 source: string | GraphNodeDatum
2733 target: string | GraphNodeDatum
28- value: number
29- }
30-
31- export interface NodeLinkGraph {
32- nodes: GraphNodeDatum []
33- links: GraphLinkDatum []
34+ isDataLink: boolean
3435}
3536
3637// Component State -------------------------------------------------------------
@@ -40,6 +41,7 @@ const selectedNode = ref<GraphNodeDatum | null>(null)
4041const zoom = ref <number >(1.0 )
4142const svgWidth = ref <number >(320 )
4243const svgHeight = ref <number >(100 )
44+ const showControlLinks = ref <boolean >(true )
4345
4446// Component Methods -----------------------------------------------------------
4547
@@ -60,24 +62,31 @@ function onSelectNode(node: GraphNodeDatum | null): void {
6062}
6163
6264function groupColors(group : string ): string {
63- if (group === LaunchActionType .ARG ) return ' #f6f294 '
64- if (group === LaunchActionType .NODE ) return ' #00bd7e '
65- if (group === LaunchActionType .INCLUDE ) return ' #7fafe3 '
65+ if (group === LaunchActionType .ARG ) return ' var(--color-green) '
66+ if (group === LaunchActionType .NODE ) return ' var(--color-blue) '
67+ if (group === LaunchActionType .INCLUDE ) return ' var(--color-yellow) '
6668 return ' gray'
6769}
6870
71+ function isAnyLink(): boolean {
72+ return true
73+ }
74+
75+ function isDataLink(d : GraphLinkDatum ): boolean {
76+ return d .isDataLink
77+ }
78+
6979function buildModelElement(): SVGElement {
7080 // Specify the color scale.
7181 // const color = d3.scaleOrdinal(d3.schemeCategory10)
7282 const color = groupColors
7383
74- const nodeStrokeColor = (d : GraphNodeDatum ): string => color (d .group )
75- const nodeFillColor = (d : GraphNodeDatum ): string => (d .dark ? ' var(--color-background)' : ' #666' )
76-
7784 // The force simulation mutates links and nodes, so create a copy
7885 // so that re-evaluating this cell produces the same result.
79- const links = props .model .links .map ((d ) => ({ ... d }))
80- const nodes = props .model .nodes .map ((d ) => ({ ... d }))
86+ const links = props .model .links
87+ .filter (showControlLinks .value ? isAnyLink : isDataLink )
88+ .map ((d ) => ({ ... d }))
89+ const nodes = Object .values (props .model .nodes ).map ((d ) => ({ ... d }))
8190
8291 // Create a simulation with several forces.
8392 const simulation = d3
@@ -114,7 +123,7 @@ function buildModelElement(): SVGElement {
114123 .append (' marker' )
115124 .attr (' id' , ' link-arrowhead' )
116125 .attr (' viewBox' , ' 0 -3 6 6' )
117- .attr (' refX' , 22 ) // about half of the link distance
126+ .attr (' refX' , 25 ) // about half of the link distance
118127 .attr (' refY' , 0 )
119128 .attr (' markerWidth' , 6 )
120129 .attr (' markerHeight' , 6 )
@@ -125,16 +134,25 @@ function buildModelElement(): SVGElement {
125134 .style (' stroke-opacity' , 0.6 )
126135 .style (' fill' , ' var(--color-text)' )
127136
137+ const linkStrokeDasharray = (d : GraphLinkDatum ): string => (d .isDataLink ? ' ' : ' 3 1' )
138+ const linkMarkerEnd = (d : GraphLinkDatum ): string => (d .isDataLink ? ' url(#link-arrowhead)' : ' ' )
139+
128140 // Add a line for each link
129141 const link = svg
130142 .append (' g' )
131143 .attr (' stroke' , ' var(--color-text)' )
132- .attr (' stroke-opacity' , 0.6 )
144+ // .attr('stroke-opacity', 0.6)
133145 .selectAll (' line' )
134146 .data (links )
135147 .join (' line' )
136- .attr (' stroke-width' , (d ) => Math .sqrt (d .value ))
137- .style (' marker-end' , ' url(#link-arrowhead)' )
148+ .attr (' stroke-width' , 1 )
149+ .attr (' stroke-dasharray' , linkStrokeDasharray )
150+ .style (' marker-end' , linkMarkerEnd )
151+
152+ const nodeStrokeColor = (d : GraphNodeDatum ): string => color (d .group )
153+ const nodeFillColor = (d : GraphNodeDatum ): string => (d .dark ? ' var(--color-background)' : ' #666' )
154+ const nodeStrokeDasharray = (d : GraphNodeDatum ): string => (! d .condition ? ' ' : ' 2 1' )
155+ const nodeRadius = (d : GraphNodeDatum ): number => (d .level || 0 ) * 5 + 10
138156
139157 // Add a circle for each node
140158 const node = svg
@@ -143,9 +161,9 @@ function buildModelElement(): SVGElement {
143161 .selectAll <SVGCircleElement , GraphNodeDatum >(' circle' )
144162 .data (nodes )
145163 .join (' circle' )
146- .attr (' r' , ( d ) => ( d . level || 0 ) * 5 + 10 )
164+ .attr (' r' , nodeRadius )
147165 .attr (' stroke' , nodeStrokeColor ) // (d.dark ? '#333' : color(d.group))
148- .attr (' stroke-dasharray' , ( d ) => ( ! d . condition ? ' ' : ' 2 1 ' ) )
166+ .attr (' stroke-dasharray' , nodeStrokeDasharray )
149167 .attr (' fill' , nodeFillColor )
150168
151169 node .append (' title' ).text ((d ) => d .name || d .id )
@@ -269,6 +287,11 @@ function onZoomChanged(/*newValue: number*/): void {
269287 }
270288}
271289
290+ function onShowControlLinks() {
291+ showControlLinks .value = ! showControlLinks .value
292+ resetSvgElement ()
293+ }
294+
272295watch (zoom , onZoomChanged )
273296
274297watch (() => props .model , resetSvgElement , { flush: ' post' })
@@ -283,6 +306,10 @@ onMounted(resetSvgElement)
283306 <div class =" toolbar" >
284307 <button @click =" onZoomOut" >Zoom -</button >
285308 <button @click =" onZoomIn" >Zoom +</button >
309+ <label >
310+ <input type =" checkbox" :checked =" showControlLinks" @click =" onShowControlLinks" />
311+ Control Links
312+ </label >
286313 </div >
287314 <div class =" panel" ref =" dependencyGraphContainer" >
288315 <p class =" floating-label" v-if =" selectedNode != null" >
0 commit comments