Vue Diagram Editor component
Introduction
The main purpose of this component is to make it possible to use any component within each node of the diagram.
Vue Diagram Editor features:
- scoped-slot for node
- ripple (pulsable) node
- any number of instances per page
- customizable node color
- customizable node pulse color
Special thanks to the author of the
gwenaelp/vue-diagrams
package.
Getting Started
It's recommended to install vue-diagram-editor
via npm, and build your app using a bundler like
webpack.
xxxxxxxxxx
1
npm install vue-diagram-editor
Requires Vue 2.6+
Simple example
xxxxxxxxxx
1
<template>
2
<VueDiagramEditor
3
ref="diagram"
4
:node-color="nodeColor"
5
:node-pulsable="nodePulsable"
6
>
7
<pre slot="node" slot-scope="{node}"></pre>
8
</VueDiagramEditor>
9
</template>
10
11
<script>
12
import VueDiagramEditor from 'vue-diagram-editor';
13
import 'vue-diagram-editor/dist/vue-diagram-editor.css';
14
15
export default {
16
name: 'simple-example',
17
components: {
18
VueDiagramEditor
19
},
20
data: () => ({
21
nodes: {
22
'node-1': {
23
id: 'node-1',
24
title: 'My node 1',
25
size: {
26
width: 200,
27
height: 220
28
},
29
portsOut: {
30
default: 'out port default'
31
}
32
},
33
'node-2': {
34
id: 'node-2',
35
title: 'My node 2',
36
size: {
37
width: 200,
38
height: 220
39
},
40
coordinates: {
41
x: 280,
42
y: 100
43
},
44
portsIn: {
45
default: 'in port'
46
}
47
},
48
},
49
links: {
50
'link-1': {
51
id: 'link-1',
52
start_id: 'node-1',
53
start_port: 'default',
54
end_id: 'node-2',
55
end_port: 'default'
56
}
57
}
58
}),
59
mounted() {
60
this.init();
61
},
62
methods: {
63
init() {
64
this.$refs.diagram.setModel({
65
nodes: this.nodes,
66
links: this.links
67
});
68
},
69
format(node) {
70
return JSON.stringify(node, null, 2);
71
},
72
nodeColor(node) {
73
if (node.coordinates.x > 200) {
74
return '#0f0';
75
}
76
if (node.coordinates.y > 200) {
77
return '#f00';
78
}
79
80
return '#00f';
81
},
82
83
nodePulsable(node) {
84
return node.coordinates.y > 200;
85
}
86
}
87
};
88
</script>
89
90
If you just don't want to use webpack or any other bundlers,
you can simply include the standalone UMD build in your page.
In this way, make sure Vue as a dependency is included before vue-diagram-editor
.
xxxxxxxxxx
1
2
<html lang="en">
3
<head>
4
<meta charset="UTF-8">
5
<title>Title</title>
6
<script src="https://cdn.jsdelivr.net/npm/vue@2.6"></script>
7
<script src="https://cdn.jsdelivr.net/npm/vue-diagram-editor@^1/dist/vue-diagram-editor.umd.min.js"></script>
8
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vue-diagram-editor@^1/dist/vue-diagram-editor.min.css">
9
</head>
10
<body>
11
<div id="app">
12
<diagram-editor ref="diagram"></diagram-editor>
13
</div>
14
<script>
15
// register the component
16
Vue.component('diagram-editor', VueDiagramEditor.Diagram);
17
new Vue({
18
el: '#app',
19
data: {
20
nodes: {
21
'node-1': {
22
id: 'node-1',
23
title: 'My node 1',
24
size: {
25
width: 200,
26
height: 220
27
},
28
portsOut: {
29
default: ''
30
}
31
},
32
'node-2': {
33
id: 'node-2',
34
title: 'My node 2',
35
size: {
36
width: 200,
37
height: 220
38
},
39
coordinates: {
40
x: 280,
41
y: 100
42
},
43
portsIn: {
44
default: 'in port'
45
}
46
},
47
},
48
links: {
49
'link-1': {
50
id: 'link-1',
51
start_id: 'node-1',
52
start_port: 'default',
53
end_id: 'node-2',
54
end_port: 'default'
55
}
56
}
57
},
58
mounted() {
59
this.init();
60
},
61
methods: {
62
init() {
63
this.$refs.diagram.setModel({
64
nodes: this.nodes,
65
links: this.links
66
});
67
}
68
}
69
});
70
</script>
71
</body>
72
</html>
73
Data structure
The data structure of the Vue-Diagram-Editor has 2 main entities -
Node and Link.
The Vue-Diagram-Editor has the following data structure:
xxxxxxxxxx
1
{
2
"nodes": {
3
"node-1-id": {
4
"id": "node-1-id",
5
"title": "Title of node 1",
6
"deletable": false,
7
"coordinates": {
8
"x": 100,
9
"y": 100
10
},
11
"size": {
12
"width": 150,
13
"height": 200
14
},
15
"portsIn": {},
16
"portsOut": {
17
"outPortName": "Out port title"
18
},
19
"data": {
20
"userProperty": "user Property Value"
21
}
22
},
23
"node-2-id": {
24
"id": "node-2-id",
25
"title": "Title of node 2",
26
"deletable": true,
27
"coordinates": {
28
"x": 200,
29
"y": 150
30
},
31
"size": {
32
"width": 150,
33
"height": 200
34
},
35
"portsIn": {
36
"inPortName": "In port name"
37
},
38
"portsOut": {},
39
"data": {}
40
}
41
},
42
"links": {
43
"link-1-id": {
44
"start_id": "node-1-id",
45
"start_port": "outPortName",
46
"end_id": "node-2-id",
47
"end_port": "inPortName"
48
}
49
}
50
}
51
API
Node
Prop | Req... | Default | Description |
---|---|---|---|
id |
no | generated ulid identifier | Unique identifier of node |
title |
yes | - |
Title of node |
coordinates |
no | { x:10, y:10 } |
Node coordinates object. Must contain this two numerical properties: x and y
|
size |
no | { width:150, height:150 } |
Node size object. Must contain this two numerical properties: width and height
|
portsIn |
no | {} |
The node's incoming ports object. Object keys are port names and values are port headers |
portsOut |
no | {} |
The node's outgoing ports object. Object keys are port names and values are port headers |
data |
no | {} |
Custom data object. May be useful when handling events |
Link
Prop | Req... | Type/Default | Description |
---|---|---|---|
id |
no |
Type: String
Default: generated ulid identifier |
Unique identifier of link |
start_id |
yes |
Type: String
No default value
|
ID of the node from which this link starts |
start_port |
no |
Type: String
Default:
"default" |
The name of the outgoing port of the node from which this link begins |
end_id |
yes |
Type: String
No default value
|
ID of the node where this link ends |
end_port |
no |
Type: String
Default:
"default" |
The name of the incoming port of the node where this link ends |
Props
Name | Type / Default | Description |
---|---|---|
height |
Type: Number
Default:
500
|
Block height with Vue-Diagram-Editor |
zoomEnabled |
Type: Boolean
Default:
true
|
Allows to scale the diagram |
nodeColor |
Type: Function: String
Default:
node => "#66cc00"
|
The function takes object of Node as parameter and must return a string with a hexadecimal color
representation. Avoid heavy computation in this function
|
nodeDeletable |
Type: Function: Boolean
Default:
node => true
|
Shows or hides the delete node button |
nodePulsable |
Type: Function: Boolean
Default:
node => false
|
Enables or disables the ripple of a specific node. Avoid heavy computation in this function |
nodePulseColor |
Type: Function: String
Default:
node => "#f00"
|
Determines the color of the node's ripple
(in the case when nodePulsable returns true ).
Avoid heavy computation in this function
|
beforeDeleteNode |
Type: Function: Boolean
Default:
node => true
|
In the case when the node is deletable, it is executed immediately before deleting. If the function returns false, the node is not deleted. Avoid heavy computation in this function |
beforeDeleteLink |
Type: Function: Boolean
Default:
link => true
|
Executed immediately before the link is removed. If the function returns false, the link is not removed. Avoid heavy computation in this function |
portDisabled |
Type: Function: Boolean
Default:
({id,type,port}) => false
|
Determines if the port is blocked for communication.
If the port is disabled, you will not be able to create a new link or click on it.
Accepts an object with properties:
id - node identifier,type - port type (in or out ),port - port name |
portAvailable |
Type: Function: Boolean
Default:
({id,type,port,activePort}) => true
|
This function is executed at the moment of hovering to the port when a new link is creating.
Accepts an object with properties:
id - node identifier,type - port type (in or out ),port - port nameactivePort - Object with the data of the starting port of the link being created |
preventMouseEventsDefault |
Type: Boolean
Default:
true
|
Stops handling native events |
Methods
Name | Params | Return | Description |
---|---|---|---|
setModel(model) |
model.nodes - Array or collection of node structure objects model.links - Array or collection of link structure objects |
void |
The method completely re-initializes the diagram model |
serialize() |
- |
{nodes:[{...},{...}], links:[{...}]} |
Method returns an object with arrays of nodes and links |
addNode(node) |
node - node structure object |
void |
Method new node to the diagram model |
addLink(link) |
link - link structure object |
void |
Method new link to the diagram model |
updateNode(params) |
params.id node IDparams.name node property nameparams.value node property value |
void |
Update root property of node |
deleteNode(id) |
id - node ID |
void |
the method simulates a click on the button to delete a node |
deleteLink(id) |
id - link ID |
void |
the method lowers the deletion of the link. |
enableDblClickZoom() |
- |
void |
see |
disableDblClickZoom() |
- |
void |
see |
isDblClickZoomEnabled() |
- |
Boolean |
see |
enableMouseWheelZoom() |
- |
void |
see |
disableMouseWheelZoom() |
- |
void |
see |
isMouseWheelZoomEnabled() |
- |
Boolean |
see |
resetZoom() |
- |
void |
see |
updateBBox() |
- |
void |
see |
fit() |
- |
void |
see |
contain() |
- |
void |
see |
center() |
- |
void |
see |
Events
Name | Data | Description |
---|---|---|
select-node |
nodeId
|
When a node is selected, an event with the node identifier is emitted |
deleted-node |
nodeId
|
When deleting a node, an event with the node identifier is emitted |
deleted-link |
linkId
|
When deleting a link, an event with the identifier of the deleted link is emitted |
updated-node |
Node
|
Updated node object |
click-port |
xxxxxxxxxx { "id": "node-id", "type": "in", "port": "port_name" } |
The event is emitted when a port is clicked.
The event sends an object with a node identifier (id ),
port type (in or out ) and port name
|
created-link |
Link
|
The event is emitted after creating a new link |
Slots
Name | Props | Description |
---|---|---|
node |
{node,width,height} |
Yes, every node can have any view component!
Slot scoped params:
node - Nodewidth - content part widthheight - content part height |
Contributing Vue Diagram Editor
Best way to contribute is to create a pull request. In order to create a pull request:
- Fork this repository
- Clone repository fork (created in previous step) locally (on your machine)
- Ensure that you have nodejs and npm installed locally
- In console:
cd
into project foldernpm install && npm run dev
- After change is done lint project
npm run lint
- Commit only meaningful changes. Do not commit distribution files (dist folder). Distribution files are built only before a release
- Push your changes into your fork
- Create a pull request