Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 8ed8cecb

Přidáno uživatelem Pavel Fidranský před více než 6 roky(ů)

various fixes

Zobrazit rozdíly:

sources/src/main/webapp/css/components/header.css
1 1
.header {
2 2
	position: relative;
3 3
	width: 100%;
4
	height: 60px;
4 5
	background: -webkit-linear-gradient(top, #f0f9ff 0%,#cbebff 47%,#a1dbff 100%);
5 6
}
6 7

  
sources/src/main/webapp/css/components/navbar.css
1 1
.navbar {
2
	height: 43px;
2 3
	background: -webkit-linear-gradient(top, #1e5799 0%,#7db9e8 100%);
3 4
	color: #cceefc;
4 5
}
sources/src/main/webapp/css/components/sidebar.css
1 1
.sidebar {
2
    z-index: 0;
2 3
	display: flex;
3 4
	flex-basis: 350px;
4 5
	flex-direction: column;
......
18 19
	max-width: 100%;
19 20
}
20 21

  
21
.sidebar-navbar {
22
    position: fixed;
23
    width: 350px;
24
    padding-top: 10px;
25
    padding-bottom: 10px;
26
}
27

  
28
.sidebar-navbar .button {
29
	height: 30px;
30
}
31

  
32
.sidebar-navbar .button img {
33
	max-height: 20px;
34
	margin-top: -4px;
35
	margin-right: 5px;
36
	vertical-align: -4px;
37
}
38

  
39
.sidebar-container {
40
	margin-top: 50px;
41
	overflow-y: overlay;
42
}
43

  
44 22
.sidebar .node-container {
45 23
	position: relative;
24
	overflow-y: overlay;
46 25
}
47 26

  
48 27
.sidebar .node-container-title {
49 28
	font-size: 1.2em;
50 29
	padding-left: 0.5em;
51 30
	padding-right: 0.5em;
31
	cursor: pointer;
52 32
}
53 33

  
54 34
.sidebar .button-group {
55 35
	position: absolute;
56
	top: 0;
57
	right: 1em;
36
    top: 1em;
37
	right: 1.5em;
58 38
}
59 39

  
60 40
.sidebar .button-group > * {
......
94 74
.sidebar .excluded-nodes {
95 75
    min-height: 20%;
96 76
    border-top: 1px solid #7db9e8;
97
    overflow-y: auto;
98 77
}
99 78

  
100 79
.sidebar .excluded-nodes .button-group {
sources/src/main/webapp/js/components/attribute.js
25 25
		]);
26 26

  
27 27
		return this._rootElement;
28
	};
28
	}
29 29

  
30 30
	/**
31 31
	 * @private
sources/src/main/webapp/js/components/groupVertexList.js
36 36
		this._rootElement.setAttribute('class', 'group-vertex-list');
37 37

  
38 38
		return this._rootElement;
39
	};
39
	}
40 40

  
41 41
	/**
42 42
	 * Adds a new vertex to the list. Binds user interactions to local handler functions.
sources/src/main/webapp/js/components/navbar.js
313 313
						applyLayoutImg.setAttribute('src', 'images/layout_on.png');
314 314

  
315 315
						layouting = true;
316
						layoutingInterval = window.setInterval(app.viewportComponent.forceDirected.run, 10);
316
						layoutingInterval = window.setInterval(() => app.viewportComponent.forceDirected.run(), 10);
317 317
					}
318 318
				},
319 319
			}, [
sources/src/main/webapp/js/components/node.js
59 59
		this._symbolListComponent.removeChild(symbol);
60 60
	}
61 61

  
62
	/**
63
	 * @returns {string} Unique identifier of a graph node (group or vertex).
64
	 */
65
	get uniqueId() {
66
		let prefix;
67
		if (this instanceof Vertex) {
68
			prefix = 'vertex-';
69
		} else if (this instanceof Group) {
70
			prefix = 'group-';
71
		} else {
72
			prefix = '';
73
		}
74

  
75
		return prefix + this.id;
76
	}
77

  
62 78
	/**
63 79
	 * @returns {Coordinates} Current position of the node.
64 80
	 */
sources/src/main/webapp/js/components/sidebar.js
8 8
		/** @prop {SidebarExcludedNodeList} excludedNodeListComponent */
9 9
		this.excludedNodeListComponent = new SidebarExcludedNodeList;
10 10
		/** @prop {Minimap} minimapComponent */
11
		this.minimapComponent = new Minimap;
11
		this.minimapComponent = new Minimap('#graph');
12 12
		/** @prop {StatusBar} statusBarComponent */
13 13
		this.statusBarComponent = new StatusBar;
14 14
	}
......
18 18
			class: 'sidebar',
19 19
			id: 'sidebar',
20 20
		}, [
21
			DOM.h('nav', {
22
				class: 'sidebar-navbar',
23
				id: 'uploadMenu',
24
			}, [
25
				// toggle unconnected list button
26
				DOM.h('button', {
27
					class: 'button',
28
					id: 'unconnectedButton',
29
					title: 'Unconnected nodes',
30
					innerText: 'Unconnected nodes',
31
					onClick: () => {
32
						this.unconnectedNodeListComponent.toggle();
33
						app.redrawEdges();
34
					},
35
				}, [
36
					DOM.h('img', {
37
						src: 'images/tochange/unconnected.gif',
38
						alt: 'Icon of "toggle unconnected nodes list" action',
39
					}),
40
				]),
41
			]),
42
			DOM.h('div', {
43
				class: 'sidebar-container',
44
			}, [
45
				this.unconnectedNodeListComponent.render(),
46
			]),
21
			this.unconnectedNodeListComponent.render(),
47 22
			this.excludedNodeListComponent.render(),
48 23
			DOM.h('div', {
49 24
				class: 'sidebar-bottom',
sources/src/main/webapp/js/components/sidebarExcludedNodeList.js
10 10
		super({
11 11
			title: 'Excluded nodes',
12 12
			class: 'node-container excluded-nodes',
13
			id: '',	// TODO: remove as soon as Sidebar is reworked
13
			id: 'excludedNodeListComponent',
14 14
		});
15 15
	}
16 16

  
sources/src/main/webapp/js/components/sidebarNodeList.js
79 79
		this._nodeListElement = DOM.h('ul', {
80 80
			class: 'node-list',
81 81
		});
82
		
83
		// content
84
		const containerContent = DOM.h('div', {
85
			class: 'node-container-content',
86
			hidden: 'hidden',
87
		}, [
88
			this._buttonGroupElement,
89
			this._sortOptionsElement,
90
			this._nodeListElement,
91
		]);
82 92

  
83 93
		// root
84 94
		this._rootElement = DOM.h('div', {
......
90 100
			DOM.h('h2', {
91 101
				class: 'node-container-title',
92 102
				innerText: this._properties.title,
103
				onClick: () => {
104
					if (containerContent.hasAttribute('hidden')) {
105
						containerContent.removeAttribute('hidden');
106
					} else {
107
						containerContent.setAttribute('hidden', 'hidden');
108
					}
109

  
110
					app.redrawEdges();
111
				},
93 112
			}),
94
			this._buttonGroupElement,
95
			this._sortOptionsElement,
96
			this._nodeListElement,
113
			// content
114
			containerContent,
97 115
		]);
98 116

  
99 117
		return this._rootElement;
......
115 133
	}
116 134

  
117 135
	_sortByCount(sortOrder) {
118
		nodeList.sort((a, b) => {
119
			var aCount = (a instanceof Group) ? a.countVertices : 1;
120
			var bCount = (b instanceof Group) ? b.countVertices : 1;
136
		this._nodeList.sort((a, b) => {
137
			var aCount = (a instanceof Group) ? a.countVertices() : 1;
138
			var bCount = (b instanceof Group) ? b.countVertices() : 1;
121 139

  
122 140
			return sortOrder * (aCount - bCount);
123 141
		});
sources/src/main/webapp/js/components/sidebarUnconnectedNodeList.js
7 7
			title: 'Unconnected vertices',
8 8
			class: 'node-container unconnected-nodes',
9 9
			id: 'unconnectedNodeListComponent',
10
			hidden: 'hidden',
11 10
		});
12 11
	}
13 12

  
sources/src/main/webapp/js/components/statusBar.js
41 41
	 */
42 42
	reset() {
43 43
		this._componentCounterElement.innerText = '';
44
	};
44
	}
45 45

  
46 46
	/**
47 47
	 * @private
sources/src/main/webapp/js/components/vertexContextMenuList.js
27 27
		]);
28 28

  
29 29
		return this._rootElement;
30
	};
30
	}
31 31

  
32 32
	/**
33 33
	 * Sets a vertex that this context menu is bound to. The vertex is then added to a group.
sources/src/main/webapp/js/services/forceDirected.js
1
/**
2
 * @constructor
3
 */
4
function ForceDirected() {
5

  
6
	var forceField = {};
7
	var canvas = 0;
8

  
9
	// parametry layoutu
10
	var inumber = 30; // pocet iteraci; default 300
11
	var inumberClick = 20; // pocet iteraci u tlacitka
12
	var repulsiveStrength = 400; // odpudiva sila (prima umera); default 450
13
	var attractiveStrength = 510; // pritazliva sila (neprima umera, nesmi byt 0); default 110
14
	var dampeningEffect = 1000; // tlumeni sily (nesmi byt 0); default 200
15
	var borderRatio = 1; // hranice layoutu (cislo kterym se deli velikost canvasu)
16
	// tahle funkce se mi nelibi, je treba to vyresit jinak, nici to layout (nechat na 1)
1
class ForceDirected {
2
	/**
3
	 * @constructor
4
	 */
5
	constructor() {
6
		this._forceField = {};
7
		this._canvas = 0;
8

  
9
		// parametry layoutu
10
		this._repulsiveStrength = 400; // odpudiva sila (prima umera); default 450
11
		this._attractiveStrength = 510; // pritazliva sila (neprima umera, nesmi byt 0); default 110
12
		this._dampeningEffect = 1000; // tlumeni sily (nesmi byt 0); default 200
13
		this._borderRatio = 1; // hranice layoutu (cislo kterym se deli velikost canvasu)
14
		// tahle funkce se mi nelibi, je treba to vyresit jinak, nici to layout (nechat na 1)
15
	}
17 16

  
18 17
	/**
19 18
	 * Force directed layout for visible components.
20 19
	 */
21
	this.run = function() {
22
		var border = canvas / borderRatio;
20
	run() {
21
		var border = this._canvas / this._borderRatio;
23 22

  
24
		var visibleNodes = app.viewportComponent.nodeList,
25
			otherVisibleNodes = [];
23
		var visibleNodes = app.viewportComponent.nodeList;
24
		var otherVisibleNodes = [];
26 25

  
27 26
		for (let i = 0; i < visibleNodes.length; i++) {
28
			forceField[Utils.getUniqueId(visibleNodes[i])] = [0, 0];
27
			this._forceField[visibleNodes[i].uniqueId] = [0, 0];
29 28
		}
30 29

  
31 30
		// calculate repulsive force
......
53 52
				var distance = Math.sqrt(sum);
54 53

  
55 54
				if (distance !== 0) {
56
					forceField[Utils.getUniqueId(currNode)][0] += Math.floor(x * (repulsiveStrength / distance));
57
					forceField[Utils.getUniqueId(currNode)][1] += Math.floor(y * (repulsiveStrength / distance));
55
					this._forceField[currNode.uniqueId][0] += Math.floor(x * (this._repulsiveStrength / distance));
56
					this._forceField[currNode.uniqueId][1] += Math.floor(y * (this._repulsiveStrength / distance));
58 57
				}
59 58
			}
60 59
		}
61 60

  
62 61
		// calculate attractive forces
63
		for (let i = 0; i < visibleNodes.length; i++){
62
		for (let i = 0; i < visibleNodes.length; i++) {
64 63
			let currNode = visibleNodes[i];
65 64

  
66 65
			let inEdgeList = currNode.inEdgeList;
......
77 76
				var sum = Math.pow(x, 2) + Math.pow(y, 2);
78 77
				var distance = Math.sqrt(sum);
79 78

  
80
				forceField[Utils.getUniqueId(currNode)][0] += Math.round(-1 * x * (distance / attractiveStrength));
81
				forceField[Utils.getUniqueId(currNode)][1] += Math.round(-1 * y * (distance / attractiveStrength));
79
				this._forceField[currNode.uniqueId][0] += Math.round(-1 * x * (distance / this._attractiveStrength));
80
				this._forceField[currNode.uniqueId][1] += Math.round(-1 * y * (distance / this._attractiveStrength));
82 81
			}
83 82

  
84 83
			let outEdgeList = currNode.outEdgeList;
......
95 94
				var sum = Math.pow(x, 2) + Math.pow(y, 2);
96 95
				var distance = Math.sqrt(sum);
97 96

  
98
				forceField[Utils.getUniqueId(currNode)][0] += Math.round(-1 * x * (distance / attractiveStrength));
99
				forceField[Utils.getUniqueId(currNode)][1] += Math.round(-1 * y * (distance / attractiveStrength));
97
				this._forceField[currNode.uniqueId][0] += Math.round(-1 * x * (distance / this._attractiveStrength));
98
				this._forceField[currNode.uniqueId][1] += Math.round(-1 * y * (distance / this._attractiveStrength));
100 99
			}
101 100
		}
102 101

  
......
104 103
		for (let i = 0; i < visibleNodes.length; i++){
105 104
			var currNode = visibleNodes[i],
106 105

  
107
				halfCan = canvas / 2,
106
				halfCan = this._canvas / 2,
108 107

  
109 108
				deltaX = currNode.position.x - halfCan,
110 109
				deltaY = currNode.position.y - halfCan;
......
112 111
			// tohle drzi layout uprostred, chtelo by to vymyslet nejak lip, docela ho to kurvi
113 112
			/*
114 113
			 if (deltaX > 0) {
115
			 currNode.x = Math.min(currNode.position.x, (canvas/2)+border);
114
			 currNode.x = Math.min(currNode.position.x, (this._canvas/2)+border);
116 115
			 } else {
117
			 currNode.x = Math.max(currNode.position.x, (canvas/2)-border);
116
			 currNode.x = Math.max(currNode.position.x, (this._canvas/2)-border);
118 117
			 }
119 118
			 if (deltaY > 0) {
120
			 currNode.y = Math.min(currNode.position.y, (canvas/2)+border);
119
			 currNode.y = Math.min(currNode.position.y, (this._canvas/2)+border);
121 120
			 } else {
122
			 currNode.y = Math.max(currNode.position.y, (canvas/2)-border);
121
			 currNode.y = Math.max(currNode.position.y, (this._canvas/2)-border);
123 122
			 }
124 123
			 */
125 124

  
......
138 137
			}
139 138

  
140 139
			// force dampening
141
			var forceX = Math.floor(forceField[Utils.getUniqueId(currNode)][0] / dampeningEffect),
142
				forceY = Math.floor(forceField[Utils.getUniqueId(currNode)][1] / dampeningEffect);
140
			var forceX = Math.floor(this._forceField[currNode.uniqueId][0] / this._dampeningEffect),
141
				forceY = Math.floor(this._forceField[currNode.uniqueId][1] / this._dampeningEffect);
143 142

  
144 143
			// adding a random effect
145 144
			/*
......
159 158
				currNode.move(coords);
160 159
			}
161 160
		}
162
	};
163
}
161
	}
162
}
sources/src/main/webapp/js/services/markSymbol.js
1 1
/**
2 2
* This class represents creation of symbols.
3
 * @constructor
4 3
*/
5
function MarkSymbol() {
6
	var CONST_MARK_SYMBOLS = ["☺", "☻", "♥", "♦", "♣", "♠", "♫", "☼", "►", "◄",
7
	"▲", "▼", "■", "▬", "░", "▒", "↕", "↑", "↓", "→", "←", "↔", "╣", "╩", "╠",
8
	"╚", "╝", "║", "╔", "╦", "═", "╬", "╗", "┴", "┬", "∟", "┌", "├", "┤",
9
	"⌂", "+", "-", "*", "÷", "×", "=", "±", "Ø", "~", "«", "»", "¤", "¶", "§",
10
	"‼", "!", "#", "$", "%", "&", "@", "A", "B", "C", "D", "E", "F", "G", "H",
11
	"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
12
	"X", "Y", "Z",   "©", "®", "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ",
13
	"λ", "μ", "ν", "ξ", "π", "ρ", "σ", "τ", "υ", "φ", "χ", "ψ", "ω", "Ω", "Φ",
14
	"Σ", "Λ", "Δ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
15
	
16
	var CONST_MARK_COLORS = ["#DC143C", "#B23AEE", "#63B8FF", "#3D9140", "#B3EE3A",
17
	"#FFD700", "#B7B7B7", "#FF8000"];
18

  
19
	var removeMarkSymbolList = [];
20
	var index = 0;
21
	var symbolIndex = -1;
22
	var colorIndex = -1;
23
	var startColorIndex = 0;
4
class MarkSymbol {
5
	/**
6
	 * @constructor
7
	 */
8
	constructor() {
9
		this._removedSymbolList = [];
10
		this._index = 0;
11
		this._symbolIndex = -1;
12
		this._colorIndex = -1;
13
		this._startColorIndex = 0;
14
	}
24 15

  
25 16
	/**
26 17
	* Returns symbol with unique char and color.
27 18
	*/
28
	this.getMarkSymbol = function() {
29
		if (removeMarkSymbolList.length > 0) {
30
			return removeMarkSymbolList.shift();
19
	getMarkSymbol() {
20
		if (this._removedSymbolList.length > 0) {
21
			return this._removedSymbolList.shift();
31 22
		}
32 23
		
33
		symbolIndex++;
34
		colorIndex++;
24
		this._symbolIndex++;
25
		this._colorIndex++;
35 26
		
36
		if (colorIndex === CONST_MARK_COLORS.length) {
37
			colorIndex = 0;
27
		if (this._colorIndex === MarkSymbol.CONST_MARK_COLORS.length) {
28
			this._colorIndex = 0;
38 29
		}
39 30
		
40
		if (symbolIndex === CONST_MARK_SYMBOLS.length) {
41
			if (startColorIndex === CONST_MARK_COLORS.length) {
42
				startColorIndex = 0;
31
		if (this._symbolIndex === MarkSymbol.CONST_MARK_SYMBOLS.length) {
32
			if (this._startColorIndex === MarkSymbol.CONST_MARK_COLORS.length) {
33
				this._startColorIndex = 0;
43 34
			}
44
			
45
			symbolIndex = 0;
46
			startColorIndex++;
47
			colorIndex = startColorIndex;
35

  
36
			this._symbolIndex = 0;
37
			this._startColorIndex++;
38
			this._colorIndex = this._startColorIndex;
48 39
		}
49 40
		
50
		return [CONST_MARK_SYMBOLS[symbolIndex], CONST_MARK_COLORS[colorIndex], 'symbol-' + index++];
51
	};
41
		return [
42
			MarkSymbol.CONST_MARK_SYMBOLS[this._symbolIndex],
43
			MarkSymbol.CONST_MARK_COLORS[this._colorIndex],
44
			'symbol-' + this._index++,
45
		];
46
	}
52 47

  
53 48
	/**
54 49
	 * Save removed symbol (char + color) to the list of removes symbols.
55 50
	 *
56 51
	 * @param symbol symbol to be removed
57 52
	 */
58
	this.removeSymbol = function(symbol) {
59
		removeMarkSymbolList.push(symbol);
60
	};
53
	removeSymbol(symbol) {
54
		this._removedSymbolList.push(symbol);
55
	}
61 56
}
57

  
58
MarkSymbol.CONST_MARK_SYMBOLS = [
59
	"☺", "☻", "♥", "♦", "♣", "♠", "♫", "☼", "►", "◄", "▲", "▼", "■", "▬",
60
	"░", "▒", "↕", "↑", "↓", "→", "←", "↔", "╣", "╩", "╠", "╚", "╝", "║",
61
	"╔", "╦", "═", "╬", "╗", "┴", "┬", "∟", "┌", "├", "┤", "⌂", "+", "-",
62
	"*", "÷", "×", "=", "±", "Ø", "~", "«", "»", "¤", "¶", "§", "‼", "!",
63
	"#", "$", "%", "&", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I",
64
	"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
65
	"X", "Y", "Z", "©", "®", "α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι",
66
	"κ", "λ", "μ", "ν", "ξ", "π", "ρ", "σ", "τ", "υ", "φ", "χ", "ψ", "ω",
67
	"Ω", "Φ", "Σ", "Λ", "Δ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
68
];
69

  
70
MarkSymbol.CONST_MARK_COLORS = [
71
	"#DC143C", "#B23AEE", "#63B8FF", "#3D9140", "#B3EE3A",
72
	"#FFD700", "#B7B7B7", "#FF8000",
73
];
sources/src/main/webapp/js/services/zoom.js
1
/**
2
 * @constructor
3
 * @param {float} defaultScale Default zoom scale.
4
 */
5
function Zoom(defaultScale) {
6
	/** @prop {float} scale Current zoom scale. */
7
	this.scale = defaultScale || 1;
8
	
9
	var steps = [ 0.1, 0.25, 0.4, 0.55, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.45, 1.6, 1.75, 1.9, 2.5, 3.5, 5 ];
10
	var step = steps.indexOf(this.scale);
11
	
1
class Zoom {
2
	/**
3
	 * @param {float} scale Default zoom scale.
4
	 */
5
	constructor(scale = 1) {
6
		this.scale = scale;
7

  
8
		this._steps = [ 0.1, 0.25, 0.4, 0.55, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.45, 1.6, 1.75, 1.9, 2.5, 3.5, 5 ];
9
		this._step = this._steps.indexOf(this.scale);
10
	}
11

  
12 12
	/**
13 13
	 * Zoom in. If the current scale is maximal, it does nothing.
14 14
	 */
15
	this.zoomIn = function() {
16
		if (step === steps.length - 1) return;
15
	zoomIn() {
16
		if (this._step === this._steps.length - 1) return;
17 17

  
18
		if (step === 0) {
18
		if (this._step === 0) {
19 19
			document.querySelector('#zoomOut').classList.remove('disabled');
20 20
			document.querySelector('#zoomOut img').src = 'images/zoom_out.png';
21 21
		}
22 22

  
23
		step++;
24
		zoomChanged.call(this);
23
		this._step++;
24
		this._onChange();
25 25

  
26
		if (step === steps.length - 1) {
26
		if (this._step === this._steps.length - 1) {
27 27
			document.querySelector('#zoomIn').classList.add('disabled');
28 28
			document.querySelector('#zoomIn img').src = 'images/zoom_in_disabled.png';
29 29
		}
30
	};
30
	}
31 31
	
32 32
	/**
33 33
	 * Zoom out. If the current scale is minimal, it does nothing.
34 34
	 */
35
	this.zoomOut = function() {
36
		if (step === 0) return;
35
	zoomOut() {
36
		if (this._step === 0) return;
37 37

  
38
		if (step === steps.length - 1) {
38
		if (this._step === this._steps.length - 1) {
39 39
			document.querySelector('#zoomIn').classList.remove('disabled');
40 40
			document.querySelector('#zoomIn img').src = 'images/zoom_in.png';
41 41
		}
42 42

  
43
		step--;
44
		zoomChanged.call(this);
43
		this._step--;
44
		this._onChange();
45 45

  
46
		if (step === 0) {
46
		if (this._step === 0) {
47 47
			document.querySelector('#zoomOut').classList.add('disabled');
48 48
			document.querySelector('#zoomOut img').src = 'images/zoom_out_disabled.png';
49 49
		}
50
	};
50
	}
51 51
	
52 52
	/**
53 53
	 * Change current zoom scale according to currently selected step.
54 54
	 */
55
	function zoomChanged() {
56
		this.scale = steps[step];
55
	_onChange() {
56
		this.scale = this._steps[this._step];
57 57
		
58 58
		document.getElementById('zoomValue').innerText = Math.round(this.scale * 100) + '%';
59 59
		document.getElementById('graph').setAttribute('transform', 'scale(' + this.scale + ')');
60 60

  
61 61
		// TODO: zoom to mouse position / center
62
		
62

  
63 63
		app.redrawEdges();
64 64
	}
65 65
}
sources/src/main/webapp/js/utils/utils.js
56 56

  
57 57
		return false;
58 58
	}
59

  
60
    /**
61
     * @param {(Vertex|Group)} node Graph node.
62
     * @returns {string} Unique identifier of a graph node (group or vertex).
63
     */
64
    static getUniqueId(node) {
65
    	if (Utils.isUndefined(node)) return '';
66

  
67
    	var prefix;
68
        if (node instanceof Vertex) {
69
            prefix = 'vertex-';
70
        } else if (node instanceof Group) {
71
            prefix = 'group-';
72
        } else {
73
            prefix = '';
74
        }
75

  
76
        return prefix + node.id;
77
    }
78 59
}

Také k dispozici: Unified diff