Projekt

Obecné

Profil

Stáhnout (9.28 KB) Statistiky
| Větev: | Tag: | Revize:
1
/**
2
 * Main class of the application.
3
 * @constructor
4
 */
5
function App() {
6
	/** @prop {Constants} constants */
7
	this.constants = new Constants;
8
	/** @prop {GraphLoader} graphLoader */
9
	this.graphLoader = new GraphLoader;
10
	/** @prop {GraphExporter} graphExporter */
11
	this.graphExporter = new GraphExporter;
12
	/** @prop {GraphHistory} graphHistory */
13
	this.graphHistory = new GraphHistory;
14
	/** @prop {JavaComponentChanger} componentChanger */
15
	this.componentChanger = new JavaComponentChanger;
16
	/** @prop {Loader} loader */
17
	this.loader = new Loader;
18
	/** @prop {Zoom} zoom */
19
	this.zoom = new Zoom(0.8);
20
	/** @prop {Utils} utils */
21
	this.utils = new Utils;
22
	/** @prop {DOM} dom */
23
	this.dom = new DOM;
24
	/** @prop {Cookies} cookies */
25
	this.cookies = new Cookies;
26
	/** @prop {MarkSymbol} markSymbol */
27
	this.markSymbol = new MarkSymbol;
28

    
29
	/** @prop {string} HOME_URL Application home URL. */
30
	this.HOME_URL = null;
31
	/** @prop {object} API Application programming interface paths. */
32
	this.API = {
33
		loadGraph: 'api/graph-data',
34
		loadDiagram: 'api/diagram',
35
	};
36

    
37
	/** @prop {float} headerHeight Current height of the application header. */
38
	this.headerHeight = getHeaderHeight();
39

    
40
	/** @prop {Sidebar} sidebarComponent */
41
	this.sidebarComponent = null;
42
	/** @prop {Viewport} viewportComponent */
43
	this.viewportComponent = null;
44

    
45
	/** @prop {array<Edge>} edgeList */
46
	this.edgeList = [];
47
	/** @prop {array<(Vertex|Group)>} nodeList */
48
	this.nodeList = [];
49
	/** @prop {array<Vertex>} vertexList */
50
	this.vertexList = [];
51
	/** @prop {array<Group>} groupList */
52
	this.groupList = [];
53

    
54
	/**
55
	 * Loads graph using diagram (if available).
56
	 * @param diagramId Diagram identifier.
57
	 * @param diagramHash Diagram hash.
58
	 */
59
	this.diagramLoader = function(diagramId, diagramHash) {
60
		return loadGraphData.bind(this, diagramId, diagramHash, null, null);
61
	};
62

    
63
	/**
64
	 * Loads graph using EFP data.
65
	 * @param {boolean} withEfps Is EFPs in graph?
66
	 * @param {object} efpSettings EFP settings.
67
	 */
68
	this.efpLoader = function(withEfps, efpSettings) {
69
		return loadGraphData.bind(this, null, null, withEfps, efpSettings);
70
	};
71

    
72
	/**
73
	 * Initiates the application.
74
	 * @param {function} startFn Function to be run to load graph data.
75
	 */
76
	this.run = function(startFn) {
77
		console.log('running...');
78

    
79
		bootstrap.call(this);
80
		startFn.call(this);
81
	};
82

    
83
	/**
84
	 * Resets the application to the state as it was when the graph was loaded for the first time.
85
	 */
86
	this.reset = function() {
87
		app.viewportComponent.reset();
88
		app.sidebarComponent.reset();
89

    
90
		app.edgeList = [];
91
		app.nodeList = [];
92
		app.vertexList = [];
93
		app.groupList = [];
94
	};
95

    
96
	/**
97
	 * Finds a vertex by its name.
98
	 * @param {string} name Name of the searched vertex.
99
	 */
100
	this.findVertexByName = function(name) {
101
		return app.vertexList.find(function(existingVertex) {
102
			return existingVertex.name == this;
103
		}, name);
104
	}
105

    
106
	/**
107
	 * Closes components floating above viewport (context menu and popovers).
108
	 */
109
	this.closeFloatingComponents = function() {
110
		app.viewportComponent.contextMenuComponent.close();
111
		app.viewportComponent.vertexPopoverComponent.close();
112
		app.viewportComponent.edgePopoverComponent.close();
113
	};
114

    
115
	/**
116
	 * Redraws edges leading from viewport to sidebar.
117
	 */
118
	this.redrawEdges = function() {
119
		app.sidebarComponent.refreshFloaters();
120
	};
121

    
122
	/**
123
	 * Binds user interactions to local handler functions.
124
	 */
125
	function bootstrap() {
126
		var self = this;
127

    
128
		self.loader.enable();
129

    
130
		var content = document.getElementById('content');
131

    
132
		self.viewportComponent = new Viewport;
133
		content.appendChild(self.viewportComponent.render());
134

    
135
		self.sidebarComponent = new Sidebar;
136
		content.appendChild(self.sidebarComponent.render());
137

    
138
		// context menu
139
		document.body.addEventListener('mousedown', function() {
140
			self.closeFloatingComponents();
141
		});
142

    
143
		// zoom
144
		document.getElementById('zoomIn').addEventListener('click', function(e) {
145
			self.zoom.zoomIn();
146
		});
147
		
148
		document.getElementById('zoomOut').addEventListener('click', function(e) {
149
			self.zoom.zoomOut();
150
		});
151

    
152
		document.getElementById('zoomValue').innerText = Math.round(self.zoom.scale * 100) + '%';
153
		document.getElementById('graph').setAttribute('transform', 'scale(' + self.zoom.scale + ')');
154

    
155
		// search
156
		document.getElementById('searchText').addEventListener('keyup', function(e) {
157
			// enter key
158
			if (e.keyCode === 13) {
159
				search(this.value);
160
				return;
161
			}
162

    
163
			// escape key
164
			if (e.keyCode === 27) {
165
				resetSearch();
166
				return;
167
			}
168
		});
169
		
170
		document.getElementById('search').addEventListener('click', function(e) {
171
			search(document.getElementById('searchText').value);
172
		});
173
		
174
		document.getElementById('countOfFound').addEventListener('click', resetSearch);
175
		
176
		function search(term) {
177
			if (term.length < 2) return;
178

    
179
			var found = 0;
180
			
181
			var vertexList = self.viewportComponent.getVertexList();
182
			vertexList.forEach(function(vertex) {
183
				if (!vertex.name.toLowerCase().includes(term.toLowerCase())) {
184
					vertex.setFound(false);
185
					return;
186
				}
187

    
188
				found++;
189

    
190
				vertex.setFound(true);
191
			});
192
			
193
			document.getElementById('countOfFound').innerText = found;
194
		}
195

    
196
		function resetSearch(e) {
197
			var vertexList = self.viewportComponent.getVertexList();
198
			vertexList.forEach(function(vertex) {
199
				vertex.setFound(false);
200
			});
201

    
202
			document.getElementById('searchText').value = '';
203
			document.getElementById('countOfFound').innerText = 0;
204
		}
205
		
206
		// exclude vertices with most edges button
207
		document.getElementById('mostEdge').addEventListener('click', function(e) {
208
			var vertexList = self.viewportComponent.getVertexList();
209
			if (vertexList.length === 0) return;
210

    
211
			var vertexWithMostEdges = vertexList.reduce(function(prev, vertex) {
212
				return vertex.countEdges() > prev.countEdges() ? vertex : prev;
213
			});
214
			
215
			if (vertexWithMostEdges !== null) {
216
				vertexWithMostEdges.exclude();
217
				self.sidebarComponent.excludedNodeListComponent.add(vertexWithMostEdges);
218
			}
219
		});
220
		
221
		// exclude vertices with most edges to group button
222
		document.getElementById('vertexToGroup').addEventListener('click', function(e) {
223
			var vertexList = self.viewportComponent.getVertexList();
224
			if (vertexList.length === 0) return;
225

    
226
			var vertexWithMostEdges = vertexList.reduce(function(prev, vertex) {
227
				return vertex.countEdges() > prev.countEdges() ? vertex : prev;
228
			});
229

    
230
			var verticesWithMostEdges = vertexList.filter(function(vertex) {
231
				return vertex.countEdges() === vertexWithMostEdges.countEdges();
232
			});
233

    
234
			if (verticesWithMostEdges.length > 0) {
235
				var group = new Group;
236

    
237
				verticesWithMostEdges.forEach(function(vertex) {
238
					group.addVertex(vertex);
239
				});
240

    
241
				self.nodeList.push(group);
242
				self.groupList.push(group);
243

    
244
				self.viewportComponent.addGroup(group);
245
			}
246
		});
247

    
248
		// apply force-directed layout
249
		var layouting = false;
250
		var layoutingInterval;
251

    
252
		document.getElementById('applyLayout').addEventListener('click', function() {
253
			if (layouting) {
254
				document.getElementById('applyLayoutImg').setAttribute('src', 'images/layout_off.png');
255

    
256
				layouting = false;
257
				clearInterval(layoutingInterval);
258

    
259
			} else {
260
				document.getElementById('applyLayoutImg').setAttribute('src', 'images/layout_on.png');
261

    
262
				layouting = true;
263
				layoutingInterval = window.setInterval(app.viewportComponent.forceDirected.run, 10);
264
			}
265
		});
266
		
267
		// save as PNG button
268
		document.getElementById('btnSaveDiagram').addEventListener('click', function(e) {
269
			saveSvgAsPng(document.getElementById('svg1'), 'diagram.png', {
270
				scale: 1,
271
			});
272
		});
273
		
274
		// window resize
275
		window.addEventListener('resize', function(e) {
276
			self.headerHeight = getHeaderHeight();
277
			self.redrawEdges();
278
		});
279
	}
280

    
281
	/**
282
	 * Loads graph data of a diagram.
283
	 * @param {string} diagramId Identifier of the diagram to be loaded.
284
	 * @param {string} diagramHash Hash of the diagram to be loaded.
285
	 * @param {boolean} withEfps Load diagram with extra-functional properties.
286
	 * @param {object} efpSettings Settings of EFP graph.
287
	 */
288
	function loadGraphData(diagramId, diagramHash, withEfps, efpSettings) {
289
		var self = this;
290

    
291
		self.loader.enable();
292

    
293
		var loadGraphURL = self.API.loadGraph;
294
		var loadDiagramURL = self.API.loadDiagram;
295

    
296
		if (diagramId !== 'null') {
297
			loadGraphURL += '?diagramId=' + diagramId;
298
			loadDiagramURL += '?diagramId=' + diagramId;
299
		}
300

    
301
		if (diagramHash !== 'null') {
302
			loadGraphURL +=  '&diagramHash=' + diagramHash;
303
			loadDiagramURL += '&diagramHash=' + diagramHash;
304
		}
305

    
306
		// TODO: how to handle EFPs? see old code for details
307
		if (withEfps !== null) {
308
			// Build graph with EFPs
309
			//GraphManager.isEfpGraph = true;
310
	
311
			// set EFP settings
312
			//GraphManager.efpMinIntDiameter = efpSettings.minInterfaceDiameter;
313
			//GraphManager.efpMaxIntDiameter = efpSettings.maxInterfaceDiameter;
314
		}
315

    
316
		// exported data of graph
317
		var graphExportData = null;
318

    
319
		// get vertex position data
320
		$.getJSON(loadDiagramURL).then(function(data) {
321
			graphExportData = JSON.parse(data.vertices_position);
322

    
323
			// get graph data
324
			return $.getJSON(loadGraphURL);
325

    
326
		}, function() {
327
			// get graph data
328
			return $.getJSON(loadGraphURL);
329

    
330
		}).then(function(data) {
331
			// construct graph
332
			self.graphLoader.run(data, graphExportData);
333

    
334
			self.loader.disable();
335

    
336
		}, function() {
337
			// go to the upload page
338
			window.location.replace('./upload-files');
339
		});
340
	}
341

    
342
	/**
343
	 * @returns {integer} Height of the header.
344
	 */
345
	function getHeaderHeight() {
346
		return document.getElementById('header').offsetHeight;
347
	}
348
}
(1-1/11)