Paths
A path is an object that passes over a series of edges.
A path is represented as a list of edge IDs so that the path can identify the edges it passes through, even when there are multiple edges between the same nodes.
Basic
A simple example is shown below.
<script setup lang="ts"> import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge5", "edge7"] }, path2: { edges: ["edge2", "edge4", "edge6", "edge10"] }, } </script> <template> <v-network-graph :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="data.configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Nodes, Edges, Layouts, defineConfigs } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, node7: { name: "Node 7" }, node8: { name: "Node 8" }, node9: { name: "Node 9" }, node10: { name: "Node 10" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node5", target: "node7" }, edge8: { source: "node5", target: "node8" }, edge9: { source: "node6", target: "node9" }, edge10: { source: "node6", target: "node10" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } const configs = defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff", }, hover: { color: "#88bbff", }, label: { visible: false, fontSize: 8, }, }, edge: { gap: 12, normal: { color: "#6699cc", }, }, path: { visible: true, path: { width: 10, }, }, }) export default { nodes, edges, layouts, configs, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
TIP
When there are multiple edges between the same pair of nodes and each of them has a path through it, suggest changing the edge gaps from the default.
TIP
By default, the path color is automatically selected from a several colors, but the same color may be selected for some paths. It is also possible to specify colors individually, see the following sample.
Coloring
The following is a sample of how to specify the color of each path, based on the color values in the path data.
<script setup lang="ts"> import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge5", "edge7"], color: "#ff00ff66", // #rrggbbaa <- with alpha }, path2: { edges: ["edge2", "edge4", "edge6", "edge10"], color: "#00aa0066", // #rrggbbaa <- with alpha }, } const configs = vNG.defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff" }, hover: { color: "#88bbff" }, label: { visible: false, fontSize: 8 }, }, edge: { gap: 12, normal: { color: "#6699cc" }, }, path: { visible: true, normal: { width: 10, color: p => p.color, }, }, }) </script> <template> <v-network-graph :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { Nodes, Edges, Layouts } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, node7: { name: "Node 7" }, node8: { name: "Node 8" }, node9: { name: "Node 9" }, node10: { name: "Node 10" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node5", target: "node7" }, edge8: { source: "node5", target: "node8" }, edge9: { source: "node6", target: "node9" }, edge10: { source: "node6", target: "node10" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } export default { nodes, edges, layouts, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Animation
Paths can also be animated in the same way as in Edge.
<script setup lang="ts"> import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge5", "edge7"] }, path2: { edges: ["edge2", "edge4", "edge6", "edge10"] }, } const configs = vNG.defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff" }, hover: { color: "#88bbff" }, label: { visible: false, fontSize: 8 }, }, edge: { gap: 12, normal: { color: "#6699cc" }, }, path: { visible: true, normal: { width: 10, dasharray: "10 16", animate: true, animationSpeed: 40, }, }, }) </script> <template> <v-network-graph :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { Nodes, Edges, Layouts } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, node7: { name: "Node 7" }, node8: { name: "Node 8" }, node9: { name: "Node 9" }, node10: { name: "Node 10" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node5", target: "node7" }, edge8: { source: "node5", target: "node8" }, edge9: { source: "node6", target: "node9" }, edge10: { source: "node6", target: "node10" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } export default { nodes, edges, layouts, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Select paths
Set configs.path.selectable
to true to make the path selectable by clicking or touching. If you specify a number instead of true
, it will be taken as the maximum number of selectable paths.
Specify 2-way binding for selected-paths
prop to get an array of path IDs selected. It is also possible to control the selection state on the network graph by setting a value to the same prop.
INFO
Since the paths cover the edges, by default the paths do not handle mouse/touch events. To make the path selectable by mouse/touch, it is necessary to set the configuration configs.path.clickable
to true.
Also, to enable mouse hover response, set configs.path.hoverable
to true.
<script setup lang="ts"> import { reactive, ref, watch } from "vue" import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge5", "edge7"] }, path2: { edges: ["edge2", "edge4", "edge6", "edge10"] }, } const initialConfigs = vNG.defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff" }, hover: { color: "#88bbff" }, label: { visible: false, fontSize: 8 }, }, edge: { gap: 12, normal: { color: "#6699cc" }, }, path: { visible: true, selectable: true as boolean | number, clickable: true, hoverable: true, normal: { width: 10, }, }, }) const configs = reactive(initialConfigs) const selectedPaths = ref<string[]>([]) const limit = ref(-1) watch(limit, v => { selectedPaths.value = [] // reset switch (v) { case 0: // disabled configs.path.selectable = false break case 1: // limit configs.path.selectable = v break case -1: // unlimited default: configs.path.selectable = true break } }) </script> <template> <div class="demo-control-panel"> <label>Selected:</label> <el-select v-model="selectedPaths" :disabled="limit === 0" multiple :multiple-limit="limit" placeholder="Select" > <el-option v-for="(node, key) in paths" :key="key" :label="node.name" :value="key" /> </el-select> <label>Limit:</label> <el-select v-model="limit" :width="400"> <el-option label="0 (disable)" :value="0" /> <el-option label="1 path" :value="1" /> <el-option label="unlimited" :value="-1" /> </el-select> </div> <v-network-graph v-model:selected-paths="selectedPaths" :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { Nodes, Edges, Layouts } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, node7: { name: "Node 7" }, node8: { name: "Node 8" }, node9: { name: "Node 9" }, node10: { name: "Node 10" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node5", target: "node7" }, edge8: { source: "node5", target: "node8" }, edge9: { source: "node6", target: "node9" }, edge10: { source: "node6", target: "node10" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } export default { nodes, edges, layouts, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Customize appearances
<script setup lang="ts"> import { reactive } from "vue" import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge5", "edge7"] }, path2: { edges: ["edge2", "edge4", "edge6", "edge10"] }, } const initialConfigs = vNG.defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff", }, hover: { color: "#88bbff", }, label: { visible: false, fontSize: 8, }, }, edge: { gap: 12, normal: { color: "#6699cc", }, }, path: { visible: true, clickable: true, hoverable: true, selectable: true, curveInNode: false, end: "centerOfNode", // "centerOfNode" or "edgeOfNode" margin: 0, normal: { width: 10, color: "#ff800088", dasharray: "", linecap: "round", linejoin: "round", animate: false, animationSpeed: 50, }, hover: { width: 12, color: "#ff000088", dasharray: "", linecap: "round", linejoin: "round", animate: false, animationSpeed: 50, }, selected: { width: 12, color: "#ff000088", dasharray: "6 16", linecap: "round", linejoin: "round", animate: true, animationSpeed: 30, }, }, }) const configs = reactive(initialConfigs) </script> <template> <div class="demo-control-panel"> <el-tabs type="border-card"> <el-tab-pane label="General"> <demo-path-config-panel v-model:end="configs.path.end" v-model:margin="configs.path.margin" v-model:curveInNode="configs.path.curveInNode" v-model:clickable="configs.path.clickable" v-model:hoverable="configs.path.hoverable" v-model:selectable="configs.path.selectable" /> </el-tab-pane> <el-tab-pane label="Stroke"> <el-tabs> <el-tab-pane label="normal"> <demo-path-stroke-config-panel v-model:width="configs.path.normal.width" v-model:color="configs.path.normal.color" v-model:dasharray="configs.path.normal.dasharray" v-model:linecap="configs.path.normal.linecap" v-model:animate="configs.path.normal.animate" v-model:animationSpeed="configs.path.normal.animationSpeed" /> </el-tab-pane> <el-tab-pane label="hover"> <demo-path-stroke-config-panel v-model:width="configs.path.hover.width" v-model:color="configs.path.hover.color" v-model:dasharray="configs.path.hover.dasharray" v-model:linecap="configs.path.hover.linecap" v-model:animate="configs.path.hover.animate" v-model:animationSpeed="configs.path.hover.animationSpeed" /></el-tab-pane> <el-tab-pane label="selected"> <demo-path-stroke-config-panel v-model:width="configs.path.selected.width" v-model:color="configs.path.selected.color" v-model:dasharray="configs.path.selected.dasharray" v-model:linecap="configs.path.selected.linecap" v-model:animate="configs.path.selected.animate" v-model:animationSpeed="configs.path.selected.animationSpeed" /></el-tab-pane> </el-tabs> </el-tab-pane> </el-tabs> </div> <v-network-graph :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { Nodes, Edges, Layouts } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, node7: { name: "Node 7" }, node8: { name: "Node 8" }, node9: { name: "Node 9" }, node10: { name: "Node 10" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node5", target: "node7" }, edge8: { source: "node5", target: "node8" }, edge9: { source: "node6", target: "node9" }, edge10: { source: "node6", target: "node10" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } export default { nodes, edges, layouts, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Z-order
The z-index of paths can be specified to control the order of the paths in the z-direction.
Since there is no concept of z-index in SVG, this feature is achieved by sorting the internal path objects. It is disabled by default for performance reasons. If configs.path.zOrder.enabled
is set to true
, this feature will be enabled.
In addition to specifying the z-index based on the properties of the path itself, it is also possible to move to the topmost when it is mouse hovered or selected.
<script setup lang="ts"> import { reactive } from "vue" import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge6", "edge10"], zIndex: 2, color: "#ff66ffdd", }, path2: { edges: ["edge2", "edge4", "edge5", "edge7"], zIndex: 1, color: "#44cc44dd", }, } const initialConfigs = vNG.defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff", }, hover: { color: "#88bbff", }, label: { visible: false, fontSize: 8, }, }, edge: { gap: 12, normal: { color: "#6699cc", }, }, path: { visible: true, curveInNode: false, end: "centerOfNode", // "centerOfNode" or "edgeOfNode" margin: 0, normal: { width: 8, color: p => p.color, dasharray: "", linecap: "round", linejoin: "round", animate: false, animationSpeed: 50, }, clickable: true, hoverable: true, selectable: true, zOrder: { enabled: true, zIndex: n => n.zIndex, bringToFrontOnHover: true, bringToFrontOnSelected: true, }, }, }) const configs = reactive(initialConfigs) </script> <template> <div class="demo-control-panel"> <el-checkbox v-model="configs.path.zOrder.bringToFrontOnHover"> Bring to front on hover </el-checkbox> <el-checkbox v-model="configs.path.zOrder.bringToFrontOnSelected"> Bring to front on selected </el-checkbox> </div> <v-network-graph :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { Nodes, Edges, Layouts } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, node7: { name: "Node 7" }, node8: { name: "Node 8" }, node9: { name: "Node 9" }, node10: { name: "Node 10" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node5", target: "node7" }, edge8: { source: "node5", target: "node8" }, edge9: { source: "node6", target: "node9" }, edge10: { source: "node6", target: "node10" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } export default { nodes, edges, layouts, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
With curved edges
Paths can be drawn on curved edges as well.
<script setup lang="ts"> import * as vNG from "v-network-graph" import data from "./data" const paths: vNG.Paths = { path1: { edges: ["edge1", "edge3", "edge5"] }, path2: { edges: ["edge2", "edge4", "edge6"] }, } const configs = vNG.defineConfigs({ node: { normal: { type: "circle", radius: 20, color: "#99ccff", }, hover: { color: "#88bbff", }, label: { visible: false, fontSize: 8, }, }, edge: { gap: 40, normal: { color: "#6699cc", }, type: "curve", }, path: { visible: true, curveInNode: true, normal: { width: 10, }, }, }) </script> <template> <v-network-graph :nodes="data.nodes" :edges="data.edges" :layouts="data.layouts" :paths="paths" :configs="configs" /> </template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import { Nodes, Edges, Layouts } from "v-network-graph" const nodes: Nodes = { node1: { name: "Node 1" }, node2: { name: "Node 2" }, node3: { name: "Node 3" }, node4: { name: "Node 4" }, node5: { name: "Node 5" }, node6: { name: "Node 6" }, } const edges: Edges = { edge1: { source: "node1", target: "node2" }, edge2: { source: "node3", target: "node2" }, edge3: { source: "node2", target: "node4" }, edge4: { source: "node2", target: "node4" }, edge5: { source: "node4", target: "node5" }, edge6: { source: "node4", target: "node6" }, edge7: { source: "node3", target: "node2" }, edge8: { source: "node4", target: "node5" }, } const layouts: Layouts = { nodes: { node1: { x: 0, y: 0 }, node2: { x: 100, y: 60 }, node3: { x: 0, y: 110 }, node4: { x: 250, y: 60 }, node5: { x: 350, y: 10 }, node6: { x: 350, y: 110 }, node7: { x: 450, y: 10 }, node8: { x: 450, y: 60 }, node9: { x: 450, y: 110 }, node10: { x: 450, y: 160 }, }, } export default { nodes, edges, layouts, }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42