commit a4090428f83fbf9f3f53559bdb8c2b4f48652b9a
Author: Pavel Fidranský <fidransky@outlook.com>
Date:   Sat Oct 27 08:47:10 2018 +0200

    reworked Vertex, Group and Edge to ES6 classes; Vertex and Group extend newly created Node class

diff --git a/sources/src/main/webapp/css/components/sidebar.css b/sources/src/main/webapp/css/components/sidebar.css
index 8469989..b02843a 100644
--- a/sources/src/main/webapp/css/components/sidebar.css
+++ b/sources/src/main/webapp/css/components/sidebar.css
@@ -194,29 +194,29 @@
 	border: 3px solid red;
 }
 
-.sidebar .node--highlighted-required .vertex-name,
-.sidebar .node--highlighted-required .group-name {
+.sidebar .node--highlighted-as-required .vertex-name,
+.sidebar .node--highlighted-as-required .group-name {
 	background: red;
 }
 
-.sidebar .node--highlighted-provided .vertex-name,
-.sidebar .node--highlighted-provided .group-name {
+.sidebar .node--highlighted-as-provided .vertex-name,
+.sidebar .node--highlighted-as-provided .group-name {
 	background: #5896FF;
 }
 
-.sidebar .node--highlighted-required.node--highlighted-provided .vertex-name,
-.sidebar .node--highlighted-required.node--highlighted-provided .group-name {
+.sidebar .node--highlighted-as-required.node--highlighted-as-provided .vertex-name,
+.sidebar .node--highlighted-as-required.node--highlighted-as-provided .group-name {
 	background: linear-gradient(to right, red, #5896FF);
 }
 
-.sidebar .node--highlighted-required .provided-counter .outer-floater,
-.sidebar .node--highlighted-required-neighbours .required-counter .outer-floater,
-.sidebar .node--highlighted-provided .required-counter .outer-floater,
-.sidebar .node--highlighted-provided-neighbours .provided-counter .outer-floater,
-.sidebar .node--highlighted-required .provided-counter .outer-port,
-.sidebar .node--highlighted-required-neighbours .required-counter .outer-port,
-.sidebar .node--highlighted-provided .required-counter .outer-port,
-.sidebar .node--highlighted-provided-neighbours .provided-counter .outer-port {
+.sidebar .node--highlighted-as-required .provided-counter .outer-floater,
+.sidebar .node--highlighted-as-required-neighbours .required-counter .outer-floater,
+.sidebar .node--highlighted-as-provided .required-counter .outer-floater,
+.sidebar .node--highlighted-as-provided-neighbours .provided-counter .outer-floater,
+.sidebar .node--highlighted-as-required .provided-counter .outer-port,
+.sidebar .node--highlighted-as-required-neighbours .required-counter .outer-port,
+.sidebar .node--highlighted-as-provided .required-counter .outer-port,
+.sidebar .node--highlighted-as-provided-neighbours .provided-counter .outer-port {
 	display: block;
 }
 
diff --git a/sources/src/main/webapp/css/components/viewport.css b/sources/src/main/webapp/css/components/viewport.css
index 71aeade..79373bc 100644
--- a/sources/src/main/webapp/css/components/viewport.css
+++ b/sources/src/main/webapp/css/components/viewport.css
@@ -20,12 +20,12 @@
 	stroke: red;
 }
 
-.viewport .edge--highlighted-required {
+.viewport .edge--highlighted-as-required {
 	stroke: red;
     stroke-width: 2;
 }
 
-.viewport .edge--highlighted-provided {
+.viewport .edge--highlighted-as-provided {
 	stroke: #5896FF;
     stroke-width: 2;
 }
@@ -60,20 +60,20 @@
 	stroke-width: 3;
 }
 
-.viewport .node--highlighted-required > rect {
+.viewport .node--highlighted-as-required > rect {
 	fill: red;
 }
 
-.viewport .node--highlighted-provided > rect {
+.viewport .node--highlighted-as-provided > rect {
 	fill: #5896FF;
 }
 
-.viewport .node--highlighted-archetype > rect {
+.viewport .node--highlighted-as-archetype > rect {
 	fill: yellowgreen;
 }
 
-.viewport .node--highlighted-required.node--highlighted-provided > rect {
-	fill: url(#node--highlighted-required-provided);
+.viewport .node--highlighted-as-required.node--highlighted-as-provided > rect {
+	fill: url(#node--highlighted-as-required-provided);
 }
 
 .viewport .node--dragged > rect {
diff --git a/sources/src/main/webapp/js/components/edge.js b/sources/src/main/webapp/js/components/edge.js
index 4f8fc2a..2cd20d9 100644
--- a/sources/src/main/webapp/js/components/edge.js
+++ b/sources/src/main/webapp/js/components/edge.js
@@ -1,325 +1,307 @@
 /**
  * Class representing an edge of a graph in viewport.
- * @constructor
- * @param {object} props Properties of the edge.
  */
-function Edge(props) {
-	/** @prop {integer} id Unique identifier of the edge. */
-	this.id = props.id;
+class Edge {
+	/**
+	 * @constructor
+	 * @param {object} props Properties of the edge.
+	 */
+	constructor(props) {
+		/** @prop {integer} id Unique identifier of the edge. */
+		this.id = props.id;
+		/** @prop {array} subedgeInfo */
+		this.subedgeInfo = props.subedgeInfo;
 
-	var rootElement;
+		this._isHidden = false;
+		this._isDimmed = false;
+		this._isHighlighted = false;
+		this._isHighlightedAsRequired = false;
+		this._isHighlightedAsProvided = false;
 
-	var hidden = false;
-	var dimmed = false;
-	var highlighted = false;
-	var highlightedRequired = false;
-	var highlightedProvided = false;
+		this._fromNode = null;
+		this._toNode = null;
 
-	var fromNode = null;
-	var toNode = null;
+		this._start = null;
+		this._end = null;
+	}
 
-	var start = new Coordinates(0, 0);
-	var end = new Coordinates(0, 0);
-	
 	/**
 	 * Sets origin vertex of the edge without moving the starting point.
 	 * @param {Vertex} node Vertex that this edge is going from.
 	 */
-	this.setFrom = function(node) {
+	set from(node) {
 		if (!(node instanceof Vertex)) {
-			throw new TypeError(node.toString() + 'is not instance of Vertex');
+			throw new TypeError(node.toString() + ' is not an instance of Vertex');
 		}
 
-		fromNode = node;
+		this._fromNode = node;
+		this._start = node.center;
+	}
 
-		setStart(node.getCenter());
-	};
-	
 	/**
-	 * Returns origin vertex of the edge.
+	 * @returns {Vertex} origin vertex of the edge.
 	 */
-	this.getFrom = function() {
-		return fromNode;
-	};
+	get from() {
+		return this._fromNode;
+	}
 	
 	/**
 	 * Sets target vertex of the edge without moving the ending point.
 	 * @param {Vertex} node Vertex that this edge is going to.
 	 */
-	this.setTo = function(node) {
+	set to(node) {
 		if (!(node instanceof Vertex)) {
-			throw new TypeError(node.toString() + 'is not instance of Vertex');
+			throw new TypeError(node.toString() + ' is not an instance of Vertex');
 		}
 
-		toNode = node;
-
-		setEnd(node.getCenter());
-	};
+		this._toNode = node;
+		this._end = node.center;
+	}
 	
 	/**
-	 * Returns target vertex of the edge.
+	 * @returns {Vertex} target vertex of the edge
 	 */
-	this.getTo = function() {
-		return toNode;
-	};
+	get to() {
+		return this._toNode;
+	}
 	
 	/**
 	 * Moves starting point of the edge to new coordinates and rotates the lollipop.
 	 * @param {Coordinates} coords New starting coordinates of the edge.
 	 */
-	this.moveStart = function(coords) {
-		setStart(coords);
-		
-		var lines = rootElement.querySelectorAll('.line');
-		lines.forEach(function(line) {
-			line.setAttribute('x1', start.x);
-			line.setAttribute('y1', start.y);
+	set start(coords) {
+		if (!(coords instanceof Coordinates)) {
+			throw new TypeError(coords.toString() + ' is not an instance of Coordinates');
+		}
+
+		this._start = coords;
+
+		this._lineElements.forEach(line => {
+			line.setAttribute('x1', this._start.x);
+			line.setAttribute('y1', this._start.y);
 		});
-		
-		// arrow position and rotation
-		var position = getArrowPosition.call(this);
-		var rotation = getArrowRotation.call(this);
 
-		var arrow = rootElement.querySelector('.arrow');
-		arrow.setAttribute('transform', `rotate(${rotation}, ${position.x},${position.y}) translate(${position.x},${position.y})`);
-	};
-	
+		// icon position and rotation
+		let position = this._iconPosition;
+		let rotation = this._iconRotation;
+
+		this._iconElement.setAttribute('transform', `rotate(${rotation}, ${position.x},${position.y}) translate(${position.x},${position.y})`);
+	}
+
 	/**
 	 * Moved ending point of the edge to new coordinates and rotates the arrow.
 	 * @param {Coordinates} coords New ending coordinates of the edge.
 	 */
-	this.moveEnd = function(coords) {
-		setEnd(coords);
-		
-		var lines = rootElement.querySelectorAll('.line');
-		lines.forEach(function(line) {
-			line.setAttribute('x2', end.x);
-			line.setAttribute('y2', end.y);
+	set end(coords) {
+		if (!(coords instanceof Coordinates)) {
+			throw new TypeError(coords.toString() + ' is not an instance of Coordinates');
+		}
+
+		this._end = coords;
+
+		this._lineElements.forEach(line => {
+			line.setAttribute('x2', this._end.x);
+			line.setAttribute('y2', this._end.y);
 		});
 		
-		// arrow position and rotation
-		var position = getArrowPosition.call(this);
-		var rotation = getArrowRotation.call(this);
+		// icon position and rotation
+		let position = this._iconPosition;
+		let rotation = this._iconRotation;
 
-		var arrow = rootElement.querySelector('.arrow');
-		arrow.setAttribute('transform', `rotate(${rotation}, ${position.x},${position.y}) translate(${position.x},${position.y})`);
-	};
+		this._iconElement.setAttribute('transform', `rotate(${rotation}, ${position.x},${position.y}) translate(${position.x},${position.y})`);
+	}
 
 	/**
 	 * Toggles visibility of the edge.
 	 * @param {boolean} newValue True to hide the edge, false to display it.
 	 */
-	this.setHidden = function(newValue) {
-		hidden = newValue;
+	set isHidden(newValue) {
+		this._isHidden = newValue;
 
 		if (newValue) {
-			rootElement.classList.add('hidden');
+			this._rootElement.classList.add('hidden');
 		} else {
-			rootElement.classList.remove('hidden');
+			this._rootElement.classList.remove('hidden');
 		}
-	};
+	}
 
 	/**
 	 * Toggles transparency of the edge.
 	 * @param {boolean} newValue True to set the edge semitransparent, false to display it normally.
 	 */
-	this.setDimmed = function(newValue) {
-		dimmed = newValue;
+	set isDimmed(newValue) {
+		this._isDimmed = newValue;
 
 		if (newValue) {
-			rootElement.classList.add('edge--dimmed');
+			this._rootElement.classList.add('edge--dimmed');
 		} else {
-			rootElement.classList.remove('edge--dimmed');
+			this._rootElement.classList.remove('edge--dimmed');
 		}
-	};
+	}
 
-    /**
-     * @returns true if the edge is currently highlighted (in any way), otherwise false
-     */
-	this.isHighlighted = function () {
-		return highlighted;
-    };
+	/**
+	 * @returns true if the edge is currently highlighted (in any way), otherwise false
+	 */
+	get isHighlighted() {
+		return this._isHighlighted;
+	}
 
 	/**
 	 * Toggles highlighting of the edge.
 	 * @param {boolean} newValue True to highlight the edge, false to unhighlight.
 	 */
-	this.setHighlighted = function(newValue) {
-		highlighted = newValue;
+	set isHighlighted(newValue) {
+		this._isHighlighted = newValue;
 
 		if (newValue) {
-			rootElement.classList.add('edge--highlighted');
+			this._rootElement.classList.add('edge--highlighted');
 		} else {
-			rootElement.classList.remove('edge--highlighted');
+			this._rootElement.classList.remove('edge--highlighted');
 		}
-	};
+	}
 	
 	/**
 	 * Toggles highlighting of the edge between vertex and its requirement.
 	 * @param {boolean} newValue True to highlight the edge as required, false to unhighlight.
 	 */
-	this.setHighlightedRequired = function(newValue) {
-		highlightedRequired = newValue;
+	set isHighlightedAsRequired(newValue) {
+		this._isHighlightedAsRequired = newValue;
 
 		if (newValue) {
-			rootElement.classList.add('edge--highlighted-required');
-			rootElement.classList.remove('edge--highlighted-provided');
+			this._rootElement.classList.add('edge--highlighted-as-required');
+			this._rootElement.classList.remove('edge--highlighted-as-provided');
 
 		} else {
-			rootElement.classList.remove('edge--highlighted-required');
+			this._rootElement.classList.remove('edge--highlighted-as-required');
 		}
-	};
+	}
 	
 	/**
 	 * Toggles highlighting of the edge between vertex and its dependent.
 	 * @param {boolean} newValue True to highlight the edge as provided, false to unhighlight.
 	 */
-	this.setHighlightedProvided = function(newValue) {
-		highlightedProvided = newValue;
+	set isHighlightedAsProvided(newValue) {
+		this._isHighlightedAsProvided = newValue;
 
 		if (newValue) {
-			rootElement.classList.remove('edge--highlighted-required');
-			rootElement.classList.add('edge--highlighted-provided');
+			this._rootElement.classList.remove('edge--highlighted-as-required');
+			this._rootElement.classList.add('edge--highlighted-as-provided');
 
 		} else {
-			rootElement.classList.remove('edge--highlighted-provided');
+			this._rootElement.classList.remove('edge--highlighted-as-provided');
 		}
-	};
-	
+	}
+
 	/**
 	 * Creates a new DOM element representing the edge in memory. Binds user interactions to local handler functions.
 	 * @returns {Element} SVG DOM element.
 	 */
-	this.render = function() {
-		rootElement = DOM.createSvgElement('g', {
-			'class': 'edge',
-			'data-id': props.id,
-			'data-from': props.from,
-			'data-to': props.to,
-		});
+	render() {
+		// icon
+		let position = this._iconPosition;
+		let rotation = this._iconRotation;
 
-		rootElement.appendChild(DOM.createSvgElement('line', {
-			'class': 'line',
-			'x1': start.x,
-			'y1': start.y,
-			'x2': end.x,
-			'y2': end.y,
-			'stroke': 'white',
-			'stroke-width': 5,
-		}));
-		
-		rootElement.appendChild(DOM.createSvgElement('line', {
-			'class': 'line',
-			'x1': start.x,
-			'y1': start.y,
-			'x2': end.x,
-			'y2': end.y,
-		}));
-
-		// arrow position and rotation
-		var position = getArrowPosition.call(this);
-		var rotation = getArrowRotation.call(this);
-		
-		// arrow
-		var arrow = DOM.createSvgElement('g', {
-			'class': 'arrow',
-			'data-edgeId': this.id,
-			'transform': `rotate(${rotation}, ${position.x},${position.y}) translate(${position.x},${position.y})`,
-		});
-		arrow.appendChild(DOM.createSvgElement('polygon', {
-			'points': '0,-10 30,0 0,10',
+		this._iconElement = DOM.s('g', {
+			class: 'arrow',
+			transform: `rotate(${rotation}, ${position.x},${position.y}) translate(${position.x},${position.y})`,
+			onClick: this._onEdgeClick.bind(this),
+		}, [
+			DOM.s('polygon', {
+				points: '0,-10 30,0 0,10',
+			}),
+		]);
+
+		// lines
+		this._lineElements = [
+			DOM.s('line', {
+				class: 'line',
+				x1: this._start.x,
+				y1: this._start.y,
+				x2: this._end.x,
+				y2: this._end.y,
+				stroke: 'white',
+				'stroke-width': 5,
+			}),
+			DOM.s('line', {
+				class: 'line',
+				x1: this._start.x,
+				y1: this._start.y,
+				x2: this._end.x,
+				y2: this._end.y,
+			}),
+		];
 
-		}));
-		arrow.addEventListener('click', click.bind(this));
-		rootElement.appendChild(arrow);
+		// root
+		this._rootElement = DOM.s('g', {
+			class: 'edge',
+			'data-id': this.id,
+			'data-from': this.from.name,
+			'data-to': this.to.name,
+		}, [].concat(this._lineElements, this._iconElement));
 
-		return rootElement;
-	};
+		return this._rootElement;
+	}
 	
 	/**
 	 * Removes the DOM element representing the edge from document.
 	 */
-	this.remove = function() {
-		rootElement.remove();
-	};
+	remove() {
+		this._rootElement.remove();
+	}
 
 	/**
 	 * Exports the edge to a new, plain JS object.
 	 * @returns {Object} exported edge
 	 */
-	this.export = function() {
+	export() {
 		return {
-			subedgeInfo: props.subedgeInfo,
-			from: this.getFrom().id,
-			to: this.getTo().id,
+			subedgeInfo: this.subedgeInfo,
+			from: this.from.id,
+			to: this.to.id,
 			text: '',
 			id: this.id,
 		};
-	};
+	}
 
 	/**
 	 * Edge click interaction. Highlights the edge and vertices related to it. Reveals edge popover.
 	 * @param {Event} e Click event.
 	 */
-	function click(e) {
-		app.viewportComponent.edgePopoverComponent.body = props.subedgeInfo;
+	_onEdgeClick(e) {
+		app.viewportComponent.edgePopoverComponent.body = this.subedgeInfo;
 		app.viewportComponent.edgePopoverComponent.position = new Coordinates(e.clientX, e.clientY);
 		app.viewportComponent.edgePopoverComponent.open();
 
 		// unhighlight other edges
-		app.edgeList.filter(function(edge) {
+		app.edgeList.filter(edge => {
 			return edge !== this;
-		}, this).forEach(function(edge) {
-			edge.setHighlighted(false);
-			edge.getFrom().setHighlighted(false);
-			edge.getTo().setHighlighted(false);
+		}).forEach(edge => {
+			edge.from.isHighlighted = false;
+			edge.to.isHighlighted = false;
+			edge.isHighlighted = false;
 		});
 
 		// highlight this edge
-		this.setHighlighted(!highlighted);
-		this.getFrom().setHighlighted(highlighted);
-		this.getTo().setHighlighted(highlighted);
+		this.from.isHighlighted = !this.isHighlighted;
+		this.to.isHighlighted = !this.isHighlighted;
+		this.isHighlighted = !this.isHighlighted;
 	}
-	
-	/**
-	 * Sets new coordinates of the starting point of the edge.
-	 * @param {Coordinates} coords New starting coordinates of the edge.
-	 */
-	function setStart(coords) {
-		if (!(coords instanceof Coordinates)) {
-			throw new TypeError(coords.toString() + 'is not instance of Coordinates');
-		}
 
-		start = coords;
-	}
-	
 	/**
-	 * Sets new coordinates of the ending point of the edge.
-	 * @param {Coordinates} coords New ending coordinates of the edge.
+	 * @returns {Coordinates} Current position of the icon.
 	 */
-	function setEnd(coords) {
-		if (!(coords instanceof Coordinates)) {
-			throw new TypeError(coords.toString() + 'is not instance of Coordinates');
-		}
-
-		end = coords;
-	}
-	
-	/**
-	 * @returns {Coordinates} Current position of the arrow.
-	 */
-	function getArrowPosition() {
-		// arrow is placed at 2/3 of the distance from start to end
+	get _iconPosition() {
+		// icon is placed at 2/3 of the distance from start to end
 		return new Coordinates(
-			(start.x + 2 * end.x) / 3,
-			(start.y + 2 * end.y) / 3,
+			(this._start.x + 2 * this._end.x) / 3,
+			(this._start.y + 2 * this._end.y) / 3,
 		);
 	}
-	
+
 	/**
-	 * @returns {float} Current rotation of the arrow in degrees.
+	 * @returns {float} Current rotation of the icon in degrees.
 	 */
-	function getArrowRotation() {
-		return -1 * Math.atan2(end.x - start.x, end.y - start.y) * 180 / Math.PI + 90;
+	get _iconRotation() {
+		return -1 * Math.atan2(this._end.x - this._start.x, this._end.y - this._start.y) * 180 / Math.PI + 90;
 	}
 }
diff --git a/sources/src/main/webapp/js/components/floatingPoint.js b/sources/src/main/webapp/js/components/floatingPoint.js
index c426af3..0495594 100644
--- a/sources/src/main/webapp/js/components/floatingPoint.js
+++ b/sources/src/main/webapp/js/components/floatingPoint.js
@@ -39,7 +39,7 @@ function FloatingPoint() {
 			throw new TypeError(edge.toString() + 'is not instance of Edge');
 		}
 
-		edge.moveEnd(this.getPosition());
+		edge.end = this.getPosition();
 		
 		inEdgeList.push(edge);
 	};
@@ -53,7 +53,7 @@ function FloatingPoint() {
 			throw new TypeError(edge.toString() + 'is not instance of Edge');
 		}
 
-		edge.moveStart(this.getPosition());
+		edge.start = this.getPosition();
 		
 		outEdgeList.push(edge);
 	};
@@ -97,29 +97,29 @@ function FloatingPoint() {
 			var edgeOffsetY = 0;
 		}
 
-		var archetypeList = Object.keys(node.getRelatedArchetypeMap()).map(function(archetypeIndex) {
+		var archetypeList = Object.keys(node.relatedArchetypeMap).map(function(archetypeIndex) {
 			return parseInt(archetypeIndex);
 		});
 		var archetypeIconOrder;
 
 		// redraw dependent edges
 		inEdgeList.forEach(function(edge) {
-			archetypeIconOrder = archetypeList.indexOf(edge.getFrom().archetype);
+			archetypeIconOrder = archetypeList.indexOf(edge.from.archetype);
 
-			edge.moveEnd(new Coordinates(
+			edge.end = new Coordinates(
 				position.x / app.zoom.scale,
 				(position.y + edgeOffsetY + archetypeIconOrder * 20) / app.zoom.scale,
-			));
 		}, this);
+			);
 
 		outEdgeList.forEach(function(edge) {
-			archetypeIconOrder = archetypeList.indexOf(edge.getTo().archetype);
+			archetypeIconOrder = archetypeList.indexOf(edge.to.archetype);
 
-			edge.moveStart(new Coordinates(
+			edge.start = new Coordinates(
 				position.x / app.zoom.scale,
 				(position.y + edgeOffsetY + archetypeIconOrder * 20) / app.zoom.scale,
-			));
 		}, this);
+			);
 	};
 
 	/**
@@ -152,7 +152,7 @@ function FloatingPoint() {
 	 * @param {boolean} newValue True to highlight the node as required, otherwise false.
 	 */
 	this.setHighlightedRequired = function(newValue) {
-		node.setHighlightedRequired(newValue);
+		node.isHighlightedAsRequired = newValue;
 	};
 
 	/**
@@ -160,6 +160,6 @@ function FloatingPoint() {
 	 * @param {boolean} newValue True to highlight the node as provided, otherwise false.
 	 */
 	this.setHighlightedProvided = function(newValue) {
-		node.setHighlightedProvided(newValue);
+		node.isHighlightedAsProvided = newValue;
 	};
 }
diff --git a/sources/src/main/webapp/js/components/group.js b/sources/src/main/webapp/js/components/group.js
index b515143..e9e1e1d 100644
--- a/sources/src/main/webapp/js/components/group.js
+++ b/sources/src/main/webapp/js/components/group.js
@@ -1,369 +1,174 @@
 /**
  * Class representing a group of vertices in graph. A group is composed from one or more vertices.
- * @constructor
- * @param {object} props Properties of the group.
  */
-function Group(props) {
-	/** @prop {integer} id Unique identifier of the group. */
-	this.id = props.hasOwnProperty('id') ? props.id : app.groupList.length + 1;
-	/** @prop {string} name Name of the group. */
-	this.name = props.hasOwnProperty('name') ? props.name : 'Group ' + this.id;
-	/** @prop {array} symbol Symbol of the group. */
-	this.symbol = app.markSymbol.getMarkSymbol();
-
-	var rootElement;
-	var vertexListComponent;
-
-	var position = new Coordinates(0, 0);
-	var size = {
-		width: 70,
-		height: 70,
-	};
-	var floater = null;
-
-	var pan = false;
-	var excluded = false;
-    var iconsDisplayed = false;
-
-	var highlighted = false;
-	var highlightedRequiredNeighbours = false;
-	var highlightedProvidedNeighbours = false;
-	var highlightedArchetypeNeighbours = false;
-	var found = false;
-	var dimmed = false;
-
-	var vertexList = [];
-	var relatedArchetypeMap = {};
+class Group extends Node {
+	/**
+	 * @constructor
+	 * @param {object} props Properties of the group.
+	 */
+	constructor(props) {
+		super(props);
+
+		this._size = new Dimensions(70, 70);
+
+		this._vertexList = [];
+	}
+
+	/**
+	 * @returns {Group} newly created group
+	 */
+	static create() {
+		return new Group({
+			id: app.groupList.length + 1,
+			name: 'Group ' + (app.groupList.length + 1),
+		});
+	}
 
 	/**
 	 * Adds a new vertex to the group. The vertex is set as excluded and its DOM element is removed from document. Its edges are moved so that they end at the group.
 	 * @param {Vertex} vertex Vertex to be added to the group.
 	 */
-	this.addVertex = function(vertex) {
+	addVertex(vertex) {
 		if (!(vertex instanceof Vertex)) {
-			throw new TypeError(vertex.toString() + 'is not instance of Vertex');
+			throw new TypeError(vertex.toString() + ' is not an instance of Vertex');
 		}
 
-		if (vertexList.length === 0) {
-			position = vertex.getPosition();
+		if (this._vertexList.length === 0) {
+			this.position = vertex.position;
 		}
 
-		var isIconShown = this.isIconsDisplayed();
-		if(isIconShown) showIconClick.bind(this)(null);
-
-		vertex.removeIcon();
-		vertex.setGroup(this);
-		vertex.setExcluded(this.isExcluded());
-		vertex.remove(this.isExcluded());	// edges of the vertex should be removed from DOM only if group is excluded
+		vertex.group = this;
+		vertex.isExcluded = this.isExcluded;
+		vertex.remove(this.isExcluded);	// edges of the vertex should be removed from DOM only if group is excluded
 
-		vertex.getInEdgeList().forEach(function(edge) {
-			if (this.isExcluded()) {
+		let inEdgeList = vertex.inEdgeList;
+		inEdgeList.forEach(edge => {
+			if (this.isExcluded) {
 				floater.addInEdge(edge);
 			} else {
-				edge.moveEnd(this.getCenter());
+				edge.end = this.center;
 			}
-		}, this);
+		});
 
-		vertex.getOutEdgeList().forEach(function(edge) {
-			if (this.isExcluded()) {
+		let outEdgeList = vertex.outEdgeList;
+		outEdgeList.forEach(edge => {
+			if (this.isExcluded) {
 				floater.addOutEdge(edge);
 			} else {
-				edge.moveStart(this.getCenter());
+				edge.start = this.center;
 			}
-		}, this);
+		});
 
-		var vertexRelatedArchetypeMap = vertex.getRelatedArchetypeMap();
-		for (var archetypeIndex in vertexRelatedArchetypeMap) {
-			if (!relatedArchetypeMap.hasOwnProperty(archetypeIndex)) {
-				relatedArchetypeMap[archetypeIndex] = 0;
+		let vertexRelatedArchetypeMap = vertex.relatedArchetypeMap;
+		for (let archetypeIndex in vertexRelatedArchetypeMap) {
+			if (this.relatedArchetypeMap.hasOwnProperty(archetypeIndex) === false) {
+				this.relatedArchetypeMap[archetypeIndex] = 0;
 			}
-	
-			relatedArchetypeMap[archetypeIndex] += vertexRelatedArchetypeMap[archetypeIndex];
+
+			this.relatedArchetypeMap[archetypeIndex] += vertexRelatedArchetypeMap[archetypeIndex];
 		}
 
-		app.viewportComponent.removeVertex(vertex);
+		app.viewportComponent.removeNode(vertex);
 
-		if (vertexListComponent) {
-			vertexListComponent.appendChild(vertex);
+		if (this._vertexListComponent) {
+			this._vertexListComponent.appendChild(vertex);
 		}
 
-		vertexList.push(vertex);
-        if(isIconShown) showIconClick.bind(this)(null);
-	};
+		this._vertexList.push(vertex);
+	}
 
 	/**
 	 * Removes a vertex from the group. The vertex is returned back to the viewport and its edges are moved to it.
 	 * @param {Vertex} vertex Vertex to be removed from the group.
 	 */
-	this.removeVertex = function(vertex) {
+	removeVertex(vertex) {
 		if (!(vertex instanceof Vertex)) {
-			throw new TypeError(vertex.toString() + 'is not instance of Vertex');
+			throw new TypeError(vertex.toString() + ' is not an instance of Vertex');
 		}
 
-		vertex.setGroup(null);
+		vertex.group = null;
 
-		vertex.getInEdgeList().forEach(function(edge) {
-			edge.moveEnd(this.getCenter());
-		}, vertex);
+		let inEdgeList = vertex.inEdgeList;
+		inEdgeList.forEach(edge => {
+			edge.end = vertex.center;
+		});
 
-		vertex.getOutEdgeList().forEach(function(edge) {
-			edge.moveStart(this.getCenter());
-		}, vertex);
+		let outEdgeList = vertex.outEdgeList;
+		outEdgeList.forEach(edge => {
+			edge.start = vertex.center;
+		});
 
-		var vertexRelatedArchetypeMap = vertex.getRelatedArchetypeMap();
-		for (var archetypeIndex in vertexRelatedArchetypeMap) {
-			relatedArchetypeMap[archetypeIndex] -= vertexRelatedArchetypeMap[archetypeIndex];
+		let vertexRelatedArchetypeMap = vertex.relatedArchetypeMap;
+		for (let archetypeIndex in vertexRelatedArchetypeMap) {
+			this.relatedArchetypeMap[archetypeIndex] -= vertexRelatedArchetypeMap[archetypeIndex];
 		}
 
-		app.viewportComponent.addVertex(vertex);
+		app.viewportComponent.addNode(vertex);
 
-		if (vertexListComponent) {
-			vertexListComponent.removeChild(vertex);
+		if (this._vertexListComponent) {
+			this._vertexListComponent.removeChild(vertex);
 		}
 
-		vertexList.splice(vertexList.indexOf(vertex), 1);
-	};
-	
+		this._vertexList.splice(this._vertexList.indexOf(vertex), 1);
+	}
+
 	/**
-	 * @returns {array<Vertex>} List of vertices added to the group.
+	 * @returns {array<Vertex>} List of vertices added to this group.
 	 */
-	this.getVertexList = function() {
-		return vertexList;
-	};
+	get vertexList() {
+		return this._vertexList;
+	}
+
+	/**
+	 * @returns {integer} Number of vertices added to this group.
+	 */
+	countVertices() {
+		return this._vertexList.length;
+	}
 
 	/**
 	 * @returns {array<Edge>} List of edges going to vertices added to the group.
 	 */
-	this.getInEdgeList = function() {
-		var edgeList = [];
+	get inEdgeList() {
+		let edgeList = [];
 
-		vertexList.forEach(function(vertex) {
-			vertex.getInEdgeList().filter(function(edge) {
+		this._vertexList.forEach(vertex => {
+			let inEdgeList = vertex.inEdgeList;
+			inEdgeList.filter(edge => {
 				return edgeList.indexOf(edge) === -1;
-			}).forEach(function(edge) {
+			}).forEach(edge => {
 				edgeList.push(edge);
 			});
 		});
 
 		return edgeList;
-	};
+	}
 
 	/**
 	 * @returns {array<Edge>} List of edges going from vertices added to the group.
 	 */
-	this.getOutEdgeList = function() {
-		var edgeList = [];
+	get outEdgeList() {
+		let edgeList = [];
 
-		vertexList.forEach(function(vertex) {
-			vertex.getOutEdgeList().filter(function(edge) {
+		this._vertexList.forEach(vertex => {
+			let outEdgeList = vertex.outEdgeList;
+			outEdgeList.filter(edge => {
 				return edgeList.indexOf(edge) === -1;
-			}).forEach(function(edge) {
+			}).forEach(edge => {
 				edgeList.push(edge);
 			});
 		});
 
 		return edgeList;
-	};
-
-	/**
-	 * @returns {array<Edge>} List of all edges related to vertices added to the group.
-	 */
-	this.getEdgeList = function() {
-		// TODO: some edges get duplicated in the resulting array this way
-
-		return [].concat(this.getInEdgeList(), this.getOutEdgeList());
-	};
-
-	/**
-	 * @returns {object} Map with archetype indexes as keys and counters of their instances as values.
-	 */
-	this.getRelatedArchetypeMap = function() {
-		return relatedArchetypeMap;
-	};
-
-	/**
-	 * @returns {Coordinates} Current position of the group in graph.
-	 */
-	this.getPosition = function() {
-		return position;
-	};
-
-	/**
-	 * Updates the current position of the group in graph.
-	 */
-	this.setPosition = function(coords) {
-		if (!(coords instanceof Coordinates)) {
-			throw new TypeError(coords.toString() + 'is not instance of Coordinates');
-		}
-
-		position = coords;
-	};
-
-	/**
-	 * @returns {Coordinates} Centre of the group.
-	 */
-	this.getCenter = function() {
-		return new Coordinates(
-			position.x + size.width / 2,
-			position.y + size.height / 2,
-		);
-	};
-
-	/**
-	 * Moves the group to a new position in graph. Edges related to vertices in the group are moved as well.
-	 * @param {Coordinates} coords Coordinates to be moved to.
-	 */
-	this.move = function(coords) {
-		if (!(coords instanceof Coordinates)) {
-			throw new TypeError(coords.toString() + 'is not instance of Coordinates');
-		}
-
-		rootElement.setAttribute('x', coords.x);
-		rootElement.setAttribute('y', coords.y);
-
-		vertexList.forEach(function(vertex) {
-			vertex.getInEdgeList().forEach(function(edge) {
-				edge.moveEnd(new Coordinates(
-					coords.x + size.width / 2,
-					coords.y + size.height / 2,
-				));
-			});
-
-			vertex.getOutEdgeList().forEach(function(edge) {
-				edge.moveStart(new Coordinates(
-					coords.x + size.width / 2,
-					coords.y + size.height / 2,
-				));
-			});
-		}, this);
-	};
-
-	/**
-	 * Sets the group as found. Highlighting is skipped when the group is excluded.
-	 * @param {boolean} newValue True to mark the group as found, otherwise false.
-	 */
-	this.setFound = function(newValue) {
-		found = newValue;
-
-		if (excluded) return;
-		
-		if (newValue) {
-			rootElement.classList.add('node--found');
-		} else {
-			rootElement.classList.remove('node--found');
-		}
-	};
-
-	/**
-	 * Toggles transparency of the group.
-	 * @param {boolean} newValue True to set the group semitransparent, false to display it normally.
-	 */
-	this.setDimmed = function(newValue) {
-		dimmed = newValue;
-
-		if (excluded) return;
-
-		if (newValue) {
-			rootElement.classList.add('node--dimmed');
-		} else {
-			rootElement.classList.remove('node--dimmed');
-		}
-	};
-
-    /**
-     * @returns {boolean} true if icon in all neighbours should be displayed, false otherwise
-     */
-    this.isIconsDisplayed = function () {
-        return iconsDisplayed;
-    };
-
-	/**
-	 * @returns true if the group is currently highlighted (in any way), otherwise false
-	 */
-	this.isHighlighted = function() {
-		return highlighted;
-	};
-
-	/**
-	 * Toggles highlighting of the group.
-	 * @param {boolean} newValue True to highlight the group, false to unhighlight.
-	 */
-	this.setHighlighted = function(newValue) {
-		highlighted = newValue;
-
-		if (newValue) {
-			rootElement.classList.add('node--highlighted');
-		} else {
-			rootElement.classList.remove('node--highlighted');
-		}
-	};
-
-	/**
-	 * Toggles inner state of the group marking whether highlighting of its requirements is active.
-	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
-	 */
-	this.setHighlightedRequiredNeighbours = function(newValue) {
-		highlightedRequiredNeighbours = newValue;
-	};
-
-	/**
-	 * Toggles inner state of the group marking whether highlighting of its dependents is active.
-	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
-	 */
-	this.setHighlightedProvidedNeighbours = function(newValue) {
-		highlightedProvidedNeighbours = newValue;
-	};
-
-	/**
-	 * Toggles inner state of the group marking whether highlighting of instances of a vertex archetype is active.
-	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
-	 */
-	this.setHighlightedArchetypeNeighbours = function(newValue) {
-		highlightedArchetypeNeighbours = newValue;
-	};
-
-	/**
-	 * Toggles highlighting of the group to mark it as requirement of some other node.
-	 * @param {boolean} newValue True to highlight, false to unhighlight.
-	 */
-	this.setHighlightedRequired = function(newValue) {
-		if (newValue) {
-			rootElement.classList.add('node--highlighted-required');
-		} else {
-			rootElement.classList.remove('node--highlighted-required');
-		}
-	};
-	
-	/**
-	 * Toggles highlighting of the group to mark it as dependent of some other node.
-	 * @param {boolean} newValue True to highlight, false to unhighlight.
-	 */
-	this.setHighlightedProvided = function(newValue) {
-		if (newValue) {
-			rootElement.classList.add('node--highlighted-provided');
-		} else {
-			rootElement.classList.remove('node--highlighted-provided');
-		}
-	};
-	
-	/**
-	 * Toggles highlighting of the group to mark it as instance of archetype related to some other node.
-	 * @param {boolean} newValue True to highlight, false to unhighlight.
-	 */
-	this.setHighlightedArchetype = function(newValue) {
-		if (newValue) {
-			rootElement.classList.add('node--highlighted-archetype');
-		} else {
-			rootElement.classList.remove('node--highlighted-archetype');
-		}
-	};
+	}
 
 	/**
-	 * @returns {boolean} True is the group is currently excluded from the viewport, otherwise false.
+	 * For some reason must be here to work.
+	 * @inheritdoc
 	 */
-	this.isExcluded = function() {
-		return excluded;
-	};
+	get isExcluded() {
+		return super.isExcluded;
+	}
 
 	/**
 	 * Toggles excluded state of the group. If the group is set excluded, a new floating point is created to connect it with 
@@ -371,634 +176,273 @@ function Group(props) {
 	 * Any node is called excluded when it is not visible in the viewport but instead in the sidebar.
 	 * @param {boolean} newValue True to set the group as excluded, otherwise false.
 	 */
-	this.setExcluded = function(newValue) {
-		excluded = newValue;
+	set isExcluded(newValue) {
+		super.isExcluded = newValue;
 
-		vertexList.forEach(function(vertex) {
-			vertex.setExcluded(newValue);
+		this._vertexList.forEach(vertex => {
+			vertex.isExcluded = newValue;
 		});
-
-		if (newValue) {
-			// set floater
-			floater = new FloatingPoint;
-			floater.setNode(this);
-			app.sidebarComponent.addFloater(floater);
-
-		} else {
-			// remove floater
-			app.sidebarComponent.removeFloater(floater);
-			delete floater;
-		}
-	};
-
-	/**
-	 * Excludes the group from the viewport. Removes group DOM element and hides its edges. If showIcon is set to True
-     * display icon in all neighbour vertices.
-     * @param {boolean} showIcon True to display icon in all neighbours, False otherwise
-	 */
-	this.exclude = function(showIcon) {
-		this.setExcluded(true);
-		this.remove(true);
-
-		app.viewportComponent.removeGroup(this);
-
-        if(showIcon){
-            showIconClick.bind(this)(null)
-        }
-	};
+	}
 
 	/**
 	 * Includes the group in the viewport. Afterwards, edges related to the group are moved to the current position of the group.
 	 */
-	this.include = function() {
-		this.removeFromSidebarList();
-
-        if(iconsDisplayed) {
-            showIconClick.bind(this)(null);
-        }
-        	
-        this.setExcluded(false);
-		this.remove(false);
-
-		app.viewportComponent.addGroup(this);
+	include() {
+		super.include();
 
 		// set edges' ends
-		var inEdgeList = this.getInEdgeList();
-		inEdgeList.forEach(function(edge) {
-			edge.moveEnd(this.getCenter());
-		}, this);
-
-		var outEdgeList = this.getOutEdgeList();
-		outEdgeList.forEach(function(edge) {
-			edge.moveStart(this.getCenter());
-		}, this);
-	};
-
-	/**
-	 * Hook function used to remove the group from the sidebar list it is located in before it is moved to the viewport.
-	 */
-	this.removeFromSidebarList = Utils.noop;
-
-	/**
-	 * Creates a new DOM element representing the group in memory. The element being created depends on whether the group
-	 * is excluded at the moment. Binds user interactions to local handler functions.
-	 * @returns {Element} depending on whether the group is excluded.
-	 */
-	this.render = function() {
-		rootElement = excluded ? renderExcluded.call(this) : renderIncluded.call(this);
-
-		this.setHighlighted(highlighted);
-
-		return rootElement;
-	};
-
-	/**
-	 * Removes the DOM element representing the group from document.
-	 * @param {boolean} hideEdges True to hide edges of vertices in the group in the viewport. Edges are (almost) never really
-	 * removed but rather hidden for cases when a node is included back in the viewport.
-	 */
-	this.remove = function(hideEdges) {
-		rootElement.remove();
-
-		// hide edges
-		var inEdgeList = this.getInEdgeList();
-		inEdgeList.filter(function(edge) {
-			return !edge.getFrom().isExcluded();
-		}).forEach(function(edge) {
-			edge.setHidden(hideEdges);
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.forEach(edge => {
+			edge.end = this.center;
 		});
 
-		var outEdgeList = this.getOutEdgeList();
-		outEdgeList.filter(function(edge) {
-			return !edge.getTo().isExcluded();
-		}).forEach(function(edge) {
-			edge.setHidden(hideEdges);
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.forEach(edge => {
+			edge.start = this.center;
 		});
-	};
+	}
 
 	/**
 	 * Exports the group to a new, plain JS object.
 	 * @returns {Object} exported group
 	 */
-	this.export = function() {
-		var verticesId = vertexList.map(function(vertex) {
-			return vertex.id;
-		});
-
+	export() {
 		return {
 			id: this.id,
 			name: this.name,
-			verticesId: verticesId,
+			verticesId: this.vertexList.map(vertex => vertex.id),
 			verticesEdgeFromId: [],	// TODO: what to put in here? ids of vertices which outgoing edges are visible in graph
 			verticesEdgeToId: [],	// TODO: what to put in here? ids of vertices which incoming edges are visible in graph
-			position: position,
+			position: this.position,
 		};
-	};
+	}
 
 	/**
-	 * @returns {Element} SVG DOM element.
+	 * @returns {SVGElement} SVG DOM element.
 	 */
-	function renderIncluded() {
-		rootElement = DOM.createSvgElement('svg', {
-			'class': 'node group',
-			'x': position.x,
-			'y': position.y,
+	_renderIncluded() {
+		this._rootElement = DOM.s('svg', {
+			class: 'node group',
+			x: this.position.x,
+			y: this.position.y,
 			'data-id': this.id,
+			onClick: this._onNodeClick.bind(this),
+			onMouseDown: this._onNodeMouseDown.bind(this),
+		}, [
+			DOM.s('rect', {
+				width: this.size.width,
+				height: this.size.height,
+				x: 1,
+				y: 1,
+				fill: this.symbol[1],
+				stroke: 'black',
+				'stroke-width': 1,
+			}),
+			// name
+			DOM.s('foreignObject', {
+				x: 4,
+				y: 4,
+				width: 46,
+				height: 16,
+				onClick: this._onNameClick.bind(this),
+			}, [
+				DOM.h('span', {
+					class: 'group-name',
+					innerText: this.name,
+				}),
+			]),
+			// symbol
+			DOM.s('text', {
+				class: 'group-symbol',
+				x: 10,
+				y: 60,
+			}, [
+				DOM.t(this.symbol[0]),
+			]),
+			// dissolve button
+			DOM.s('g', {
+				class: 'button dissolve-button',
+				onClick: this._onDissolveClick.bind(this),
+			}, [
+				DOM.s('rect', {
+					rx: 4,
+					ry: 4,
+					x: 54,
+					y: 4,
+					height: 14,
+					width: 14,
+				}),
+				DOM.s('line', {
+					x1: 57,
+					y1: 7,
+					x2: 65,
+					y2: 15,
+				}),
+				DOM.s('line', {
+					x1: 65,
+					y1: 7,
+					x2: 57,
+					y2: 15,
+				}),
+			]),
+		]);
+
+		// symbol list
+		this._symbolListComponent = new NodeSymbolList;
+		this._rootElement.appendChild(this._symbolListComponent.render());
+
+		this._symbolList.forEach(symbol => {
+			this._symbolListComponent.appendChild(symbol);
 		});
-		rootElement.addEventListener('click', click.bind(this));
-		rootElement.addEventListener('mousedown', mouseDown.bind(this));
-
-		rootElement.appendChild(DOM.createSvgElement('rect', {
-			'width': size.width,
-			'height': size.height,
-			'x': 1,
-			'y': 1,
-			'fill': this.symbol[1],
-			'stroke': 'black',
-			'stroke-width': 1,
-		}));
-
-		// name
-		var nameTextInner = DOM.createHtmlElement('span', {
-			'class': 'group-name',
-		});
-		nameTextInner.appendChild(DOM.createTextElement(this.name));
 
-		var nameText = DOM.createSvgElement('foreignObject', {
-			'x': 4,
-			'y': 4,
-			'width': 46,
-			'height': 16,
-		});
-		nameText.appendChild(nameTextInner);
-		nameText.addEventListener('click', nameClick.bind(this));
-		rootElement.appendChild(nameText);
-
-		// symbol
-		var symbolText = DOM.createSvgElement('text', {
-			'class': 'group-symbol',
-			'x': 10,
-			'y': 60,
-		});
-		symbolText.appendChild(document.createTextNode(this.symbol[0]));
-		rootElement.appendChild(symbolText);
-
-		// dissolve button
-		var dissolveButton = DOM.createSvgElement('g', {
-			'class': 'button dissolve-button',
-		});
-		dissolveButton.appendChild(DOM.createSvgElement('rect', {
-			'rx': 4,
-			'ry': 4,
-			'x': 54,
-			'y': 4,
-			'height': 14,
-			'width': 14,
-		}));
-		dissolveButton.appendChild(DOM.createSvgElement('line', {
-			'x1': 57,
-			'y1': 7,
-			'x2': 65,
-			'y2': 15,
-		}));
-		dissolveButton.appendChild(DOM.createSvgElement('line', {
-			'x1': 65,
-			'y1': 7,
-			'x2': 57,
-			'y2': 15,
-		}));
-		dissolveButton.addEventListener('click', dissolveClick.bind(this));
-		rootElement.appendChild(dissolveButton);
-
-		return rootElement;
+		return this._rootElement;
 	}
 
 	/**
-	 * @returns {Element} HTML DOM element.
+	 * @returns {HTMLElement} HTML DOM element.
 	 */
-	function renderExcluded() {
-		rootElement = DOM.createHtmlElement('li', {
-			'class': 'node group',
-			'data-id': this.id,
+	_renderExcluded() {
+		const svg = DOM.s('svg', {
+			xmlns: 'http://www.w3.org/2000/svg',
+			height: 60,
+			width: 46,
 		});
 
-		var svg = DOM.createSvgElement('svg', {
-			'xmlns': 'http://www.w3.org/2000/svg',
-			'height': 60,
-			'width': 46,
-		});
-		rootElement.appendChild(svg);
-
 		// related archetypes
-		var relatedArchetypesGroup = DOM.createSvgElement('g', {
-			'transform': 'translate(10, 15)',
+		const relatedArchetypesGroup = DOM.s('g', {
+			transform: 'translate(10, 15)',
 		});
 		svg.appendChild(relatedArchetypesGroup);
 
-		var archetypeIconOrder = 0;
-		for (var archetypeIndex in relatedArchetypeMap) {
-			var relatedArchetype = DOM.createSvgElement('g', {
-				'class': 'related-archetype',
-				'transform': `translate(0, ${archetypeIconOrder * 20})`,
-			});
-			relatedArchetypesGroup.appendChild(relatedArchetype);
-
-			// counter
-			var relatedArchetypeCounter = DOM.createSvgElement('text');
-			relatedArchetypeCounter.appendChild(DOM.createTextElement(relatedArchetypeMap[archetypeIndex]));
-			relatedArchetype.appendChild(relatedArchetypeCounter);
-
-			// icon
-			var relatedArchetypeIcon = DOM.createSvgElement('use', {
-				'href': '#vertexArchetypeIcon-' + app.archetype.vertex[archetypeIndex].name,
-				'class': 'archetype-icon',
-				'transform': `translate(15, -10)`,
-			});
-			relatedArchetypeIcon.addEventListener('click', relatedArchetypeClick.bind(this, parseInt(archetypeIndex))); // TODO when icon == null can not click on item
-			relatedArchetype.appendChild(relatedArchetypeIcon);
-
-			// line
-			relatedArchetype.appendChild(DOM.createSvgElement('line', {
-				'x1': 30,
-				'y1': -5,
-				'x2': 36,
-				'y2': -5,
-			}));
+		let archetypeIconOrder = 0;
+		for (let archetypeIndex in this.relatedArchetypeMap) {
+			relatedArchetypesGroup.appendChild(DOM.s('g', {
+				class: 'related-archetype',
+				transform: `translate(0, ${archetypeIconOrder * 20})`,
+			}, [
+				// counter
+				DOM.s('text', {}, [
+					DOM.t(this.relatedArchetypeMap[archetypeIndex]),
+				]),
+				// icon
+				DOM.s('use', {
+					href: '#vertexArchetypeIcon-' + app.archetype.vertex[archetypeIndex].name,
+					class: 'archetype-icon',
+					transform: `translate(15, -10)`,
+					onClick: this._onRelatedArchetypeIconClick.bind(this, parseInt(archetypeIndex)), // TODO when icon == null can not click on item
+				}),
+				// line
+				DOM.s('line', {
+					x1: 30,
+					y1: -5,
+					x2: 36,
+					y2: -5,
+				}),
+			]));
 
 			archetypeIconOrder++;
 		}
 
-		// symbol
-		var symbolText = DOM.createHtmlElement('span', {
-			'class': 'group-symbol',
-			'style': 'background-color: ' + this.symbol[1] + ';',
-			'x': 10,
-			'y': 55,
-		});
-		symbolText.appendChild(document.createTextNode(this.symbol[0]));
-		symbolText.addEventListener('click', click.bind(this));
-		rootElement.appendChild(symbolText);
-
-		// name
-		var nameText = DOM.createHtmlElement('span', {
-			'class': 'group-name',
-		});
-		nameText.appendChild(document.createTextNode(this.name));
-		nameText.addEventListener('click', nameClick.bind(this));
-		rootElement.appendChild(nameText);
-
 		// vertex list
-		vertexListComponent = new GroupVertexList(this);
-		rootElement.appendChild(vertexListComponent.render());
-
-		vertexList.forEach(function(vertex) {
-			vertexListComponent.appendChild(vertex);
-		}, this);
+		this._vertexListComponent = new GroupVertexList(this);
 
-		// buttons
-		var buttonGroup = DOM.createHtmlElement('div', {
-			'class': 'button-group',
-		});
-		rootElement.appendChild(buttonGroup);
-
-        // show symbol button
-        var showSymbolButton = DOM.createHtmlElement('button', {
-            'class': 'show-symbol-button button',
-            'style': 'background-color: ' + this.symbol[1] + ';',
-            'title': 'Show symbol next to all neighbouring components',
-        });
-        showSymbolButton.appendChild(document.createTextNode(this.symbol[0]));
-        showSymbolButton.addEventListener('click', showIconClick.bind(this));
-        buttonGroup.appendChild(showSymbolButton);
-
-		// include button
-		var includeButton = DOM.createHtmlElement('button', {
-			'class': 'include-button button',
-			'title': 'Display group in viewport',
-		});
-		includeButton.appendChild(DOM.createHtmlElement('img', {
-			'src': 'images/button_cancel.png',
-			'alt': 'Icon of "display group in viewport" action',
-		}));
-		includeButton.addEventListener('click', includeClick.bind(this));
-		buttonGroup.appendChild(includeButton);
+		// root
+		this._rootElement = DOM.h('li', {
+			class: 'node group',
+			'data-id': this.id,
+		}, [
+			svg,
+			// symbol
+			DOM.h('span', {
+				class: 'group-symbol',
+				style: 'background-color: ' + this.symbol[1] + ';',
+				x: 10,
+				y: 55,
+				innerText: this.symbol[0],
+				onClick: this._onNodeClick.bind(this),
+			}),
+			// name
+			DOM.h('span', {
+				class: 'group-name',
+				innerText: this.name,
+				onClick: this._onNameClick.bind(this),
+			}),
+			// vertex list
+			this._vertexListComponent.render(),
+			// buttons
+			DOM.h('div', {
+				class: 'button-group',
+			}, [
+				// show symbol button
+				DOM.h('button', {
+					class: 'show-symbol-button button',
+					style: 'background-color: ' + this.symbol[1] + ';',
+					title: 'Show symbol next to all neighbouring components',
+					innerText: this.symbol[0],
+					onClick: this._onShowNeighbourIconsClick.bind(this),
+				}),
+				// include button
+				DOM.h('button', {
+					class: 'include-button button',
+					title: 'Display group in viewport',
+					onClick: this.include.bind(this),
+				}, [
+					DOM.h('img', {
+						src: 'images/button_cancel.png',
+						alt: 'Icon of "display group in viewport" action',
+					}),
+				]),
+			]),
+		]);
 
 		// set floater
-		floater.setElement(rootElement);
+		this._proxy.setElement(this._rootElement);
 
 		// set edges' ends
-		var inEdgeList = this.getInEdgeList();
-		inEdgeList.forEach(function(edge) {
-			floater.addInEdge(edge);
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.forEach(edge => {
+			this._proxy.addInEdge(edge);
 		});
 
-		var outEdgeList = this.getOutEdgeList();
-		outEdgeList.forEach(function(edge) {
-			floater.addOutEdge(edge);
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.forEach(edge => {
+			this._proxy.addOutEdge(edge);
 		});
 
-		return rootElement;
+		return this._rootElement;
 	}
 
-	/**
-	 * Group click interaction. Based on whether the group is excluded and currently selected mouse mode (move, exclude),
-	 * the group is either highlighted or moved within the graph.
-	 */
-	function click() {
-		if (excluded) {
-			this.setHighlightedWithNeighbours(!highlighted);
-			return;
-		}
-
-		if (pan) {
-			pan = false;
-			return;
-		}
-
-		switch (document.modeForm.mode.value) {
-			case 'move':
-				this.setHighlightedWithNeighbours(!highlighted);
-				break;
-
-			case 'exclude':
-				this.exclude.call(this);
-
-				app.sidebarComponent.excludedNodeListComponent.add(this);
-				break;
-		}
-	}
-
-    /**
-	 * Method add or remove highlighting of group and all neighbours.
-     *
-	 * @param newHighlighted true to highlight, false otherwise
-     */
-    this.setHighlightedWithNeighbours = function (newHighlighted) {
-        this.setHighlighted(newHighlighted);
-        this.setHighlightedRequiredNeighbours(highlighted);
-        this.setHighlightedProvidedNeighbours(highlighted);
-
-        prepareHighlighting.call(this);
-        highlightRequiredNeighbours.call(this);
-        highlightProvidedNeighbours.call(this);
-    };
-
 	/**
 	 * Group name click interaction. Reveals a prompt for new group name.
 	 * @param {Event} e Click event.
 	 */
-	function nameClick(e) {
+	_onNameClick(e) {
 		e.stopPropagation();
 
-		var newValue = prompt('Enter new group name:', this.name);
+		let newValue = prompt('Enter new group name:', this.name);
 		if (newValue !== null) {
 			this.name = newValue;
 
-			rootElement.querySelector('.group-name').innerText = this.name;
+			this._rootElement.querySelector('.group-name').innerText = this.name;
 		}
 	}
 
-    /**
-     * Displays symbol of the group next to all nodes that it is connected with.
-     * @param {MouseEvent} e Click event.
-     */
-    function showIconClick(e) {
-        iconsDisplayed = !iconsDisplayed;
-
-        var neighbourList = [];
-
-        this.getInEdgeList().filter(function (edge) {
-            return !edge.getFrom().isExcluded();
-        }).forEach(function (edge) {
-            if (!neighbourList.includes(edge.getFrom())) {
-                neighbourList.push(edge.getFrom());
-            }
-        });
-
-        this.getOutEdgeList().filter(function (edge) {
-            return !edge.getTo().isExcluded();
-        }).forEach(function (edge) {
-            if (!neighbourList.includes(edge.getTo())) {
-                neighbourList.push(edge.getTo());
-            }
-        });
-
-        neighbourList.forEach(function(node) {
-            if (iconsDisplayed) {
-                node.addSymbol(this.symbol);
-            } else {
-                node.removeSymbol(this.symbol);
-            }
-        }, this);
-    }
-
-	/**
-	 * Includes the group back to the viewport.
-	 */
-	function includeClick() {
-		this.include.call(this);
-	}
-
 	/**
 	 * Dissolves the group so that its vertices are displayed separately again. The group itself is destroyed.
 	 * @param {Event} e Click event.
 	 */
-	function dissolveClick(e) {
-		e.stopPropagation();
-
-		this.remove.call(this, false);
-
-		var vertexListCopy = vertexList.slice(0);
-		vertexListCopy.forEach(function(vertex) {
-			this.removeVertex.call(this, vertex);
-		}, this);
-
-		app.viewportComponent.removeGroup(this);
-
-		app.groupList.splice(app.groupList.indexOf(this), 1);
-	}
-	
-	/**
-	 * Archetype icon click interaction. Toggles highlighting of neighbour vertices which are instances of a vertex archetype.
-	 * @param {integer} archetypeIndex Index of the vertex archetype.
-	 * @param {MouseEvent} e Click event.
-	 */
-	function relatedArchetypeClick(archetypeIndex, e) {
-		e.stopPropagation();
-
-		this.setHighlighted(!highlighted);
-		this.setHighlightedArchetypeNeighbours(highlighted);
-
-		prepareHighlighting.call(this);
-		highlightArchetypeNeighbours.call(this, archetypeIndex);
-	}
-	
-	/**
-	 * Handles drag and drop interaction with the group. At the moment mouse button is pressed, it is not yet known whether 
-	 * it is just clicked or dragged.
-	 * @param {Event} e Mouse down event.
-	 */
-	function mouseDown(e) {
+	_onDissolveClick(e) {
 		e.stopPropagation();
-		app.closeFloatingComponents();
-		
-		var self = this;
-		var start = new Coordinates(e.clientX, e.clientY);
-		
-		rootElement.classList.add('node--dragged');
-		
-		document.body.addEventListener('mousemove', mouseMove);
-		document.body.addEventListener('mouseup', mouseUp);
-		document.body.addEventListener('mouseleave', mouseUp);
-		
-		/**
-		 * At the moment mouse is moved, the group is clearly being dragged. The group is moved to the current position of mouse.
-		 * @param {Event} e Mouse move event.
-		 */
-		function mouseMove(e) {
-			pan = true;
-			
-			self.move(new Coordinates(
-				position.x - (start.x - e.clientX) / app.zoom.scale,
-				position.y - (start.y - e.clientY) / app.zoom.scale,
-			));
-		}
-
-		/**
-		 * At the moment mouse button is released, dragging is done and its final position is set to the group.
-		 * @param {Event} e Mouse up event.
-		 */
-		function mouseUp(e) {
-			self.setPosition(new Coordinates(
-				+rootElement.getAttribute('x'),
-				+rootElement.getAttribute('y'),
-			));
-			
-			rootElement.classList.remove('node--dragged');
-			
-			document.body.removeEventListener('mousemove', mouseMove);
-			document.body.removeEventListener('mouseup', mouseUp);
-			document.body.removeEventListener('mouseleave', mouseUp);
-		}
-	}
-	
-	/**
-	 * Prepares highlighting of all graph components so that only the wished ones need to be modified.
-	 */
-	function prepareHighlighting() {
-		this.setDimmed(false);
-
-		this.setHighlightedRequired(false);
-		this.setHighlightedProvided(false);
-		this.setHighlightedArchetype(false);
-
-		if (highlighted) {
-			// dim and unhighlight all nodes but this
-			app.nodeList.forEach(function(node) {
-				if (node === this) return;
-
-				node.setDimmed(true);
-
-				node.setHighlighted(false);
-				node.setHighlightedRequired(false);
-				node.setHighlightedProvided(false);
-				node.setHighlightedArchetype(false);
-			}, this);
-
-			// dim and unhighlight all edges
-			app.edgeList.forEach(function(edge) {
-				edge.setDimmed(true);
-
-				edge.setHighlighted(false);
-				edge.setHighlightedRequired(false);
-				edge.setHighlightedProvided(false);
-			});
-
-		} else {
-			app.nodeList.forEach(function(node) {
-				if (node === this) return;
-
-				node.setDimmed(false);
-
-				node.setHighlighted(false);
-				node.setHighlightedRequired(false);
-				node.setHighlightedProvided(false);
-				node.setHighlightedArchetype(false);
-			}, this);
-
-			app.edgeList.forEach(function(edge) {
-				edge.setHidden(edge.getFrom().isExcluded() || edge.getTo().isExcluded());
-
-				edge.setDimmed(false);
-
-				edge.setHighlighted(false);
-				edge.setHighlightedRequired(false);
-				edge.setHighlightedProvided(false);
-			});
-		}
-	}
-
-	/**
-	 * Highlights only neighbours of vertices in the group that are required.
-	 */
-	function highlightRequiredNeighbours() {
-		if (highlightedRequiredNeighbours === false) return;
-
-		this.getInEdgeList().forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.getFrom().setDimmed(false);
-			edge.setDimmed(false);
-
-			edge.setHighlightedRequired(true);
-			edge.getFrom().setHighlightedRequired(true);
-		});
-	}
-
-	/**
-	 * Highlights only neighbours of vertices in the group that are provided.
-	 */
-	function highlightProvidedNeighbours() {
-		if (highlightedProvidedNeighbours === false) return;
 
-		this.getOutEdgeList().forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.setDimmed(false);
-			edge.getTo().setDimmed(false);
-
-			edge.setHighlightedProvided(true);
-			edge.getTo().setHighlightedProvided(true);
-		});
-	}
-
-	/**
-	 * Highlights only neighbours of the group that are instances of the archetype.
-	 * @param {integer} archetypeIndex Index of the vertex archetype.
-	 */
-	function highlightArchetypeNeighbours(archetypeIndex) {
-		if (highlightedArchetypeNeighbours === false) return;
-
-		this.getInEdgeList().filter(function(edge) {
-			return edge.getFrom().archetype === archetypeIndex;
-		}).forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.setDimmed(false);
-			edge.getFrom().setDimmed(false);
+		this.remove(false);
 
-			edge.getFrom().setHighlightedArchetype(true);
+		let vertexListCopy = this._vertexList.slice(0);
+		vertexListCopy.forEach(vertex => {
+			this.removeVertex(vertex);
 		});
 
-		this.getOutEdgeList().filter(function(edge) {
-			return edge.getTo().archetype === archetypeIndex;
-		}).forEach(function(edge) {
-			edge.setHidden(false);
+		app.viewportComponent.removeNode(this);
 
-			edge.setDimmed(false);
-			edge.getTo().setDimmed(false);
-
-			edge.getTo().setHighlightedArchetype(true);
-		});
+		app.groupList.splice(app.groupList.indexOf(this), 1);
 	}
 }
diff --git a/sources/src/main/webapp/js/components/groupVertexList.js b/sources/src/main/webapp/js/components/groupVertexList.js
index 4453b09..66bb8c1 100644
--- a/sources/src/main/webapp/js/components/groupVertexList.js
+++ b/sources/src/main/webapp/js/components/groupVertexList.js
@@ -20,7 +20,7 @@ class GroupVertexList {
 	 * @returns {Element} HTML or SVG DOM element depending on whether the group is excluded.
 	 */
 	render() {
-		if (this._group.isExcluded()) {
+		if (this._group.isExcluded) {
 			this._rootElement = DOM.h('ul');
 		} else {
 			this._rootElement = DOM.s('g', {
@@ -28,6 +28,11 @@ class GroupVertexList {
 			});
 		}
 
+		let vertexList = this._group.vertexList;
+		vertexList.forEach(vertex => {
+			this.appendChild(vertex);
+		});
+
 		this._rootElement.setAttribute('class', 'group-vertex-list');
 
 		return this._rootElement;
@@ -40,7 +45,7 @@ class GroupVertexList {
 	 */
 	appendChild(vertex) {
 		let listItemElement;
-		if (this._group.isExcluded()) {
+		if (this._group.isExcluded) {
 			listItemElement = DOM.h('li');
 		} else {
 			listItemElement = DOM.s('text', {
diff --git a/sources/src/main/webapp/js/components/navbar.js b/sources/src/main/webapp/js/components/navbar.js
index 5a2351d..c7b29d4 100644
--- a/sources/src/main/webapp/js/components/navbar.js
+++ b/sources/src/main/webapp/js/components/navbar.js
@@ -137,12 +137,12 @@ class Navbar {
 
 			var found = 0;
 			
-			app.viewportComponent.nodeList.forEach(function(node) {
+			app.viewportComponent.getNodeList().forEach(node => {
 				if (node.name.toLowerCase().includes(term.toLowerCase())) {
-					node.setFound(true);
+					node.isFound = true;
 					found++;
 				} else {
-					node.setFound(false);
+					node.isFound = false;
 				}
 			});
 
@@ -150,8 +150,8 @@ class Navbar {
 		}
 
 		function resetSearch() {
-			app.viewportComponent.nodeList.forEach(function(node) {
-				node.setFound(false);
+			app.viewportComponent.getNodeList().forEach(node => {
+				node.isFound = false;
 			});
 
 			searchInput.value = '';
@@ -257,7 +257,7 @@ class Navbar {
 					});
 
 					if (verticesWithMostEdges.length > 0) {
-						var group = new Group({});
+						let group = Group.create();
 
 						verticesWithMostEdges.forEach(function(vertex) {
 							group.addVertex(vertex);
@@ -266,7 +266,7 @@ class Navbar {
 						app.nodeList.push(group);
 						app.groupList.push(group);
 
-						app.viewportComponent.addGroup(group);
+						app.viewportComponent.addNode(group);
 					}
 				},
 			}, [
diff --git a/sources/src/main/webapp/js/components/node.js b/sources/src/main/webapp/js/components/node.js
new file mode 100644
index 0000000..6e4d197
--- /dev/null
+++ b/sources/src/main/webapp/js/components/node.js
@@ -0,0 +1,631 @@
+/**
+ * Class representing a node in graph.
+ */
+class Node {
+	/**
+	 * @constructor
+	 * @param {object} props Properties of the node.
+	 */
+	constructor(props) {
+		/** @prop {integer} id Unique identifier of the node. */
+		this.id = props.id;
+		/** @prop {string} name Name of the node. */
+		this.name = props.name;
+		/** @prop {array} symbol Symbol of the node. */
+		this.symbol = app.markSymbol.getMarkSymbol();
+		/** @prop {function} removeFromSidebarList Hook function used to remove the node from the sidebar list it is located in before it is moved to the viewport. */
+		this.removeFromSidebarList = Utils.noop;
+
+		this._position = null;
+		this._size = null;
+		this._proxy = null;
+
+		this._panning = false;
+
+		this._isExcluded = false;
+		this._isFound = false;
+		this._isDimmed = false;
+		this._isHighlighted = false;
+		this._isRequiredNeighboursHighlighted = false;
+		this._isProvidedNeighboursHighlighted = false;
+		this._isArchetypeNeighboursHighlighted = false;
+		this._isNeighbourIconsDisplayed = false;
+
+		this._symbolList = [];
+		this._relatedArchetypeMap = {};
+	}
+
+	/**
+	 * Adds symbol to the list of symbols displayed next to the node.
+	 * @param {array} symbol Node symbol to be added.
+	 */
+	addSymbol(symbol) {
+		this._symbolList.push(symbol);
+
+		if (this.isExcluded) return;
+
+		this._symbolListComponent.appendChild(symbol);
+	}
+
+	/**
+	 * Removes symbol from the list of symbols displayed next to the node.
+	 * @param {array} symbol Node symbol to be removed.
+	 */
+	removeSymbol(symbol) {
+		this._symbolList.splice(this._symbolList.indexOf(symbol), 1);
+
+		if (this.isExcluded) return;
+
+		this._symbolListComponent.removeChild(symbol);
+	}
+
+	/**
+	 * @returns {Coordinates} Current position of the node.
+	 */
+	get position() {
+		return this._position;
+	}
+	
+	/**
+	 * Updates the current position of the node in graph.
+	 * @param {Coordinates} New position of the node.
+	 */
+	set position(coords) {
+		if (!(coords instanceof Coordinates)) {
+			throw new TypeError(coords.toString() + ' is not an instance of Coordinates');
+		}
+
+		this._position = coords;
+	}
+
+	/**
+	 * @returns {Coordinates} Centre of the node.
+	 */
+	get center() {
+		return new Coordinates(
+			this._position.x + (this._size.width / 2),
+			this._position.y + (this._size.height / 2),
+		);
+	}
+
+	/**
+	 * @returns {Dimensions} Dimensions of the node.
+	 */
+	get size() {
+		return this._size;
+	}
+
+	/**
+	 * Moves the node to a new position in graph. Edges related to the node are moved as well.
+	 * @param {Coordinates} coords Coordinates to be moved to.
+	 */
+	move(coords) {
+		if (!(coords instanceof Coordinates)) {
+			throw new TypeError(coords.toString() + ' is not an instance of Coordinates');
+		}
+
+		this._rootElement.setAttribute('x', coords.x);
+		this._rootElement.setAttribute('y', coords.y);
+
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.forEach(edge => {
+			edge.end = new Coordinates(
+				coords.x + (this._size.width / 2),
+				coords.y + (this._size.height / 2),
+			);
+		});
+
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.forEach(edge => {
+			edge.start = new Coordinates(
+				coords.x + (this._size.width / 2),
+				coords.y + (this._size.height / 2),
+			);
+		});
+	}
+
+	/**
+	 * @returns {object} Map with archetype indexes as keys and counters of their instances as values.
+	 */
+	get relatedArchetypeMap() {
+		return this._relatedArchetypeMap;
+	}
+
+	/**
+	 * Sets the node as found. Highlighting is skipped when the node is excluded.
+	 * @param {boolean} newValue True to mark the node as found, otherwise false.
+	 */
+	set isFound(newValue) {
+		this._isFound = newValue;
+
+		if (this.isExcluded) return;
+		
+		if (newValue) {
+			this._rootElement.classList.add('node--found');
+		} else {
+			this._rootElement.classList.remove('node--found');
+		}
+	}
+
+	/**
+	 * Toggles transparency of the node. Style change is skipped when the node is excluded.
+	 * @param {boolean} newValue True to dim the node, false to display it normally.
+	 */
+	set isDimmed(newValue) {
+		this._isDimmed = newValue;
+
+		if (this.isExcluded) return;
+
+		if (newValue) {
+			this._rootElement.classList.add('node--dimmed');
+		} else {
+			this._rootElement.classList.remove('node--dimmed');
+		}
+	}
+
+	/**
+	 * @returns true if the node is currently highlighted (in any way), otherwise false
+	 */
+	get isHighlighted() {
+		return this._isHighlighted;
+	}
+
+	/**
+	 * Toggles highlighting of the node.
+	 * @param {boolean} newValue True to highlight the node, false to unhighlight.
+	 */
+	set isHighlighted(newValue) {
+		this._isHighlighted = newValue;
+
+		if (newValue) {
+			this._rootElement.classList.add('node--highlighted');
+		} else {
+			this._rootElement.classList.remove('node--highlighted');
+		}
+	}
+
+	/**
+	 * Toggles inner state of the node marking whether highlighting of its requirements is active.
+	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
+	 */
+	set isRequiredNeighboursHighlighted(newValue) {
+		this._isRequiredNeighboursHighlighted = newValue;
+	}
+
+	/**
+	 * Toggles inner state of the node marking whether highlighting of its dependents is active.
+	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
+	 */
+	set isProvidedNeighboursHighlighted(newValue) {
+		this._isProvidedNeighboursHighlighted = newValue;
+	}
+
+	/**
+	 * Toggles inner state of the node marking whether highlighting of instances of a node archetype is active.
+	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
+	 */
+	set isArchetypeNeighboursHighlighted(newValue) {
+		this._isArchetypeNeighboursHighlighted = newValue;
+	}
+
+	/**
+	 * Toggles highlighting of the node to mark it as requirement of some other node.
+	 * @param {boolean} newValue True to highlight, false to unhighlight.
+	 */
+	set isHighlightedAsRequired(newValue) {
+		if (newValue) {
+			this._rootElement.classList.add('node--highlighted-as-required');
+		} else {
+			this._rootElement.classList.remove('node--highlighted-as-required');
+		}
+	}
+	
+	/**
+	 * Toggles highlighting of the node to mark it as dependent of some other node.
+	 * @param {boolean} newValue True to highlight, false to unhighlight.
+	 */
+	set isHighlightedAsProvided(newValue) {
+		if (newValue) {
+			this._rootElement.classList.add('node--highlighted-as-provided');
+		} else {
+			this._rootElement.classList.remove('node--highlighted-as-provided');
+		}
+	}
+	
+	/**
+	 * Toggles highlighting of the node to mark it as instance of archetype related to some other node.
+	 * @param {boolean} newValue True to highlight, false to unhighlight.
+	 */
+	set isHighlightedAsArchetype(newValue) {
+		if (newValue) {
+			this._rootElement.classList.add('node--highlighted-as-archetype');
+		} else {
+			this._rootElement.classList.remove('node--highlighted-as-archetype');
+		}
+	}
+
+	/**
+	 * Method add or remove highlighting of vertex and all neighbours.
+	 *
+	 * @param newValue true to highlight, false otherwise
+	 */
+	highlightWithNeighbours(newValue) {
+		this.isHighlighted = newValue;
+		this.isRequiredNeighboursHighlighted = newValue;
+		this.isProvidedNeighboursHighlighted = newValue;
+
+		this._prepareHighlighting();
+		this._highlightRequiredNeighbours();
+		this._highlightProvidedNeighbours();
+	}
+
+	/**
+	 * @returns {boolean} True is the node is currently excluded from the viewport, otherwise false.
+	 */
+	get isExcluded() {
+		return this._isExcluded;
+	}
+
+	/**
+	 * Toggles excluded state of the node. If the node is set excluded, a new floating point is created to connect it with 
+	 * related nodes in the viewport. Otherwise, the floating point is deleted.
+	 * Any node is called excluded when it is not visible in the viewport but instead in the sidebar.
+	 * @param {boolean} newValue True to set the node as excluded, otherwise false.
+	 */
+	set isExcluded(newValue) {
+		this._isExcluded = newValue;
+
+		if (this instanceof Vertex && this._group !== null) return;
+
+		if (newValue) {
+			// set floater
+			this._proxy = new FloatingPoint;
+			this._proxy.setNode(this);
+			app.sidebarComponent.addFloater(this._proxy);
+
+		} else {
+			// remove floater
+			app.sidebarComponent.removeFloater(this._proxy);
+			this._proxy = null;
+		}
+	}
+
+	/**
+	 * Excludes the node from the viewport. Removes node DOM element and hides its edges. If showIcon is set to True
+	 * display icon in all neighbour vertices.
+	 * @param {boolean} showIcon True to display icon in all neighbours, False otherwise
+	 */
+	exclude() {
+		this.isExcluded = true;
+		this.remove(true);
+
+		app.viewportComponent.removeNode(this);
+	}
+
+	/**
+	 * Includes the node in the viewport. Afterwards, edges related to the node are moved to the current position of the node.
+	 */
+	include() {
+		this.removeFromSidebarList();
+
+		this.isExcluded = false;
+		this.remove(false);
+
+		app.viewportComponent.addNode(this);
+	}
+
+	/**
+	 * Creates a new DOM element representing the node in memory. The element being created depends on whether the node
+	 * is excluded at the moment. Binds user interactions to local handler functions.
+	 * @returns {Element} HTML or SVG DOM element depending on whether the node is excluded.
+	 */
+	render() {
+		this._rootElement = this.isExcluded ? this._renderExcluded() : this._renderIncluded();
+
+		return this._rootElement;
+	}
+	
+	/**
+	 * Removes the DOM element representing the node from document.
+	 * @param {boolean} hideEdges True to hide edges related to the node in the viewport. Edges are (almost) never really
+	 * removed but rather hidden for cases when a node is included back in the viewport.
+	 */
+	remove(hideEdges) {
+		this._rootElement.remove();
+
+		// toggle edges
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.filter(edge => {
+			return !edge.from.isExcluded;
+		}).forEach(edge => {
+			edge.isHidden = hideEdges;
+		});
+
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.filter(edge => {
+			return !edge.to.isExcluded;
+		}).forEach(edge => {
+			edge.isHidden = hideEdges;
+		});
+
+		// hide neighbour symbols
+		if (this._isNeighbourIconsDisplayed) {
+			this._onShowNeighbourIconsClick();
+		}
+	};
+
+	/**
+	 * Exports the node to a new, plain JS object.
+	 * @returns {Object} exported node
+	 */
+	export() {
+		throw new AbstractMethodError;
+	}
+
+	/**
+	 * @returns {SVGElement} SVG DOM element.
+	 */
+	_renderIncluded() {
+		throw new AbstractMethodError;
+	}
+
+	/**
+	 * @returns {HTMLElement} HTML DOM element.
+	 */
+	_renderExcluded() {
+		throw new AbstractMethodError;
+	}
+
+	/**
+	 * Node click interaction. Based on whether the node is excluded and currently selected mouse mode (move, exclude),
+	 * the node is either highlighted or moved within the graph.
+	 */
+	_onNodeClick(e) {
+		e.stopPropagation();
+
+		if (this.isExcluded) {
+			this.highlightWithNeighbours(!this.isHighlighted);
+
+		} else {
+			if (this._panning === true) {
+				this._panning = false;
+				return;
+			}
+
+			switch (document.modeForm.mode.value) {
+				case 'move':
+					this.highlightWithNeighbours(!this.isHighlighted);
+					break;
+
+				case 'exclude':
+					this.exclude();
+
+					app.sidebarComponent.excludedNodeListComponent.add(this);
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Handles drag and drop interaction with the node. At the moment mouse button is pressed, it is not yet known whether 
+	 * it is just clicked or dragged.
+	 * @param {Event} e Mouse down event.
+	 */
+	_onNodeMouseDown(e) {
+		e.stopPropagation();
+		app.closeFloatingComponents();
+		
+		let that = this;
+		let start = new Coordinates(e.clientX, e.clientY);
+
+		this._rootElement.classList.add('node--dragged');
+		
+		document.body.addEventListener('mousemove', mouseMove);
+		document.body.addEventListener('mouseup', mouseUp);
+		document.body.addEventListener('mouseleave', mouseUp);
+
+		/**
+		 * At the moment mouse is moved, the node is clearly being dragged. The node is moved to the current position of mouse.
+		 * @param {Event} e Mouse move event.
+		 */
+		function mouseMove(e) {
+			that._panning = true;
+
+			that.move(new Coordinates(
+				that.position.x - (start.x - e.clientX) / app.zoom.scale,
+				that.position.y - (start.y - e.clientY) / app.zoom.scale,
+			));
+		}
+
+		/**
+		 * At the moment mouse button is released, dragging is done and its final position is set to the node.
+		 * @param {Event} e Mouse up event.
+		 */
+		function mouseUp() {
+			that.position = new Coordinates(
+				+that._rootElement.getAttribute('x'),
+				+that._rootElement.getAttribute('y'),
+			);
+
+			that._rootElement.classList.remove('node--dragged');
+			
+			document.body.removeEventListener('mousemove', mouseMove);
+			document.body.removeEventListener('mouseup', mouseUp);
+			document.body.removeEventListener('mouseleave', mouseUp);
+		}
+	}
+
+	/**
+	 * Displays symbol of the node next to all nodes that this node is connected with.
+	 */
+	_onShowNeighbourIconsClick() {
+		this._isNeighbourIconsDisplayed = !this._isNeighbourIconsDisplayed;
+
+		let neighbourNodeList = [];
+
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.filter(edge => {
+			return !edge.from.isExcluded;
+		}).forEach(edge => {
+			if (neighbourNodeList.includes(edge.from) === false) {
+				neighbourNodeList.push(edge.from);
+			}
+		});
+
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.filter(edge => {
+			return !edge.to.isExcluded;
+		}).forEach(edge => {
+			if (neighbourNodeList.includes(edge.to) === false) {
+				neighbourNodeList.push(edge.to);
+			}
+		});
+
+		neighbourNodeList.forEach(node => {
+			if (this._isNeighbourIconsDisplayed) {
+				node.addSymbol(this.symbol);
+			} else {
+				node.removeSymbol(this.symbol);
+			}
+		});
+	}
+
+	/**
+	 * Archetype icon click interaction. Toggles highlighting of neighbour vertices which are instances of a vertex archetype.
+	 * @param {integer} archetypeIndex Index of the vertex archetype.
+	 * @param {MouseEvent} e Click event.
+	 */
+	_onRelatedArchetypeIconClick(archetypeIndex, e) {
+		e.stopPropagation();
+
+		this.isArchetypeNeighboursHighlighted = !this.isHighlighted;
+		this.isHighlighted = !this.isHighlighted;
+
+		this._prepareHighlighting();
+		this._highlightArchetypeNeighbours(archetypeIndex);
+	}
+
+	/**
+	 * * Prepares highlighting of all graph components so that only the wished ones need to be modified.
+	 */
+	_prepareHighlighting() {
+		this.isDimmed = false;
+
+		this.isHighlightedAsRequired = false;
+		this.isHighlightedAsProvided = false;
+		this.isHighlightedAsArchetype = false;
+
+		if (this.isHighlighted) {
+			// dim and unhighlight all nodes but this
+			app.nodeList.forEach(node => {
+				if (node === this) return;
+
+				node.isDimmed = true;
+
+				node.isHighlighted = false;
+				node.isHighlightedAsRequired = false;
+				node.isHighlightedAsProvided = false;
+				node.isHighlightedAsArchetype = false;
+			});
+
+			// dim and unhighlight all edges
+			app.edgeList.forEach(edge => {
+				edge.isDimmed = true;
+
+				edge.isHighlighted = false;
+				edge.isHighlightedAsRequired = false;
+				edge.isHighlightedAsProvided = false;
+			});
+
+		} else {
+			app.nodeList.forEach(node => {
+				if (node === this) return;
+
+				node.isDimmed = false;
+
+				node.isHighlighted = false;
+				node.isHighlightedAsRequired = false;
+				node.isHighlightedAsProvided = false;
+				node.isHighlightedAsArchetype = false;
+			});
+
+			app.edgeList.forEach(edge => {
+				edge.isHidden = edge.from.isExcluded || edge.to.isExcluded;
+
+				edge.isDimmed = false;
+
+				edge.isHighlighted = false;
+				edge.isHighlightedAsRequired = false;
+				edge.isHighlightedAsProvided = false;
+			});
+		}
+	}
+
+	/**
+	 * Highlights only neighbours of the vertex that are required.
+	 */
+	_highlightRequiredNeighbours() {
+		if (this._isRequiredNeighboursHighlighted === false) return;
+
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.forEach(edge => {
+			edge.isHidden = false;
+
+			edge.isDimmed = false;
+			edge.from.isDimmed = false;
+
+			edge.isHighlightedAsRequired = true;
+			edge.from.isHighlightedAsRequired = true;
+		});
+	}
+
+	/**
+	 * Highlights only neighbours of the vertex that are provided.
+	 */
+	_highlightProvidedNeighbours() {
+		if (this._isProvidedNeighboursHighlighted === false) return;
+
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.forEach(edge => {
+			edge.isHidden = false;
+
+			edge.isDimmed = false;
+			edge.to.isDimmed = false;
+
+			edge.isHighlightedAsProvided = true;
+			edge.to.isHighlightedAsProvided = true;
+		});
+	}
+
+	/**
+	 * Highlights only neighbours of the vertex that are instances of the archetype.
+	 * @param {integer} archetypeIndex Index of the vertex archetype.
+	 */
+	_highlightArchetypeNeighbours(archetypeIndex) {
+		if (this._isArchetypeNeighboursHighlighted === false) return;
+
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.filter(edge => {
+			return edge.from.archetype === archetypeIndex;
+		}).forEach(edge => {
+			edge.isHidden = false;
+
+			edge.isDimmed = false;
+			edge.from.isDimmed = false;
+
+			edge.from.isHighlightedAsArchetype = true;
+		});
+
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.filter(edge => {
+			return edge.to.archetype === archetypeIndex;
+		}).forEach(edge => {
+			edge.isHidden = false;
+
+			edge.isDimmed = false;
+			edge.to.isDimmed = false;
+
+			edge.to.isHighlightedAsArchetype = true;
+		});
+	}
+}
diff --git a/sources/src/main/webapp/js/components/nodeSymbolList.js b/sources/src/main/webapp/js/components/nodeSymbolList.js
new file mode 100644
index 0000000..1791c9c
--- /dev/null
+++ b/sources/src/main/webapp/js/components/nodeSymbolList.js
@@ -0,0 +1,78 @@
+/**
+ * Class representing list of symbols displayed next to a node to mark its relation to another, excluded node.
+ * @see Node
+ */
+class NodeSymbolList {
+	/**
+	 * @constructor
+	 */
+	constructor() {
+		this._width = 20;
+		this._height = 20;
+	}
+
+	/**
+	 * Creates a new DOM element representing the list of symbols in memory.
+	 * @public
+	 * @returns {SVGElement} SVG DOM element.
+	 */
+	render() {
+		this._rootElement = DOM.s('g', {
+			transform: 'translate(0, 30)',
+		});
+
+		return this._rootElement;
+	}
+
+	/**
+	 * Adds a new symbol to the list.
+	 * @public
+	 * @param {array} symbol Symbol to be added to the list.
+	 */
+	appendChild(symbol) {
+		this._rootElement.appendChild(DOM.s('g', {
+			class: 'neighbour-node-symbol ' + symbol[2],
+		}, [
+			DOM.s('rect', {
+				x: 0,
+				y: 0,
+				width: this._width,
+				height: this._height,
+				fill: symbol[1],
+			}),
+			DOM.s('text', {
+				x: 6,
+				y: 15,
+			}, [
+				DOM.t(symbol[0]),
+			]),
+		]));
+
+		this._reorderSymbols();
+	}
+
+	/**
+	 * Removes a symbol from the list.
+	 * @public
+	 * @param {array} symbol Symbol to be removed from the list.
+	 */
+	removeChild(symbol) {
+		let symbolGroup = this._rootElement.querySelector('.' + symbol[2]);
+
+		symbolGroup.remove();
+
+		this._reorderSymbols();
+	}
+
+	/**
+	 * Changes the order of symbols displayed in the list. It is used to refresh their position after one is added or removed.
+	 * @private
+	 */
+	_reorderSymbols() {
+		for (var i = 0; i < this._rootElement.children.length; i++) {
+			let symbolGroup = this._rootElement.children[i];
+
+			symbolGroup.setAttribute('transform', `translate(${i * this._width + 1}, 1)`);
+		}
+	}
+}
diff --git a/sources/src/main/webapp/js/components/sidebarExcludedNodeList.js b/sources/src/main/webapp/js/components/sidebarExcludedNodeList.js
index d1447ee..c102a05 100644
--- a/sources/src/main/webapp/js/components/sidebarExcludedNodeList.js
+++ b/sources/src/main/webapp/js/components/sidebarExcludedNodeList.js
@@ -18,8 +18,8 @@ function SidebarExcludedNodeList(props) {
 	};
 
 	this.add = function(node) {
-		if (!(node instanceof Vertex) && !(node instanceof Group)) {
-			throw new TypeError(node.toString() + 'is instance of neither Vertex nor Group');
+		if (!(node instanceof Node)) {
+			throw new TypeError(node.toString() + ' is not an instance of Node');
 		}
 
 		// set remove hook
@@ -34,8 +34,8 @@ function SidebarExcludedNodeList(props) {
 	};
 
 	this.remove = function(node) {
-		if (!(node instanceof Vertex) && !(node instanceof Group)) {
-			throw new TypeError(node.toString() + 'is instance of neither Vertex nor Group');
+		if (!(node instanceof Node)) {
+			throw new TypeError(node.toString() + ' is not an instance of Node');
 		}
 
 		// unset remove hook
diff --git a/sources/src/main/webapp/js/components/sidebarUnconnectedNodeList.js b/sources/src/main/webapp/js/components/sidebarUnconnectedNodeList.js
index c832f18..d28ff39 100644
--- a/sources/src/main/webapp/js/components/sidebarUnconnectedNodeList.js
+++ b/sources/src/main/webapp/js/components/sidebarUnconnectedNodeList.js
@@ -111,7 +111,7 @@ function SidebarUnconnectedNodeList(props) {
 
 	function excludeAll() {
 		app.vertexList.filter(function(vertex) {
-			return vertex.isUnconnected();
+			return vertex.isUnconnected;
 		}).forEach(function(vertex) {
 			vertex.exclude();
 			this.add(vertex);
diff --git a/sources/src/main/webapp/js/components/vertex.js b/sources/src/main/webapp/js/components/vertex.js
index a9e3f15..78c29dd 100644
--- a/sources/src/main/webapp/js/components/vertex.js
+++ b/sources/src/main/webapp/js/components/vertex.js
@@ -1,988 +1,419 @@
 /**
  * Class representing a vertex in graph.
- * @constructor
- * @param {object} props Properties of the vertex.
  */
-function Vertex(props) {
-	/** @prop {integer} id Unique identifier of the vertex. */
-	this.id = props.id;
-	/** @prop {integer} archetype Identifier of the vertex archetype. */
-	this.archetype = props.archetype;
-	/** @prop {string} name Name of the vertex. */
-	this.name = props.name;
-	/** @prop {array} symbol Symbol of the group. */
-	this.symbol = app.markSymbol.getMarkSymbol();
-
-	const oneCharacterWidth = 8.3;	// approximate width (in pixels) of one character using Consolas at 15px font size
-	const minimumWidth = 200;
-	const relatedArchetypeIconWidth = 20;
-
-	var rootElement;
-	var symbolListComponent;
-
-	var position = new Coordinates(0, 0);
-	var size = {
-		width: Math.max(30 + this.name.length * oneCharacterWidth, minimumWidth),
-		height: 30,
-	};
-	var group = null;
-	var floater = null;
-
-	var pan = false;
-	var excluded = false;
-	var iconsDisplayed = false;
-
-	var highlighted = false;
-	var highlightedRequiredNeighbours = false;
-	var highlightedProvidedNeighbours = false;
-	var highlightedArchetypeNeighbours = false;
-	var found = false;
-	var dimmed = false;
-
-	var inEdgeList = [];
-	var outEdgeList = [];
-	var symbolList = [];
-	var relatedArchetypeMap = {};
-	
+class Vertex extends Node {
 	/**
-	 * Adds a new edge ending in the vertex. Its ending point is moved to the current position of the vertex.
-	 * @param {Edge} edge Edge going to the vertex.
-	 */
-	this.addInEdge = function(edge) {
-		if (!(edge instanceof Edge)) {
-			throw new TypeError(edge.toString() + 'is not instance of Edge');
-		}
-		
-		edge.setTo(this);
-		
-		inEdgeList.push(edge);
-	};
-	
-	/**
-	 * Adds a new edge starting in the vertex. Its starting point is moved to the current position of the vertex.
-	 * @param {Edge} edge Edge going from the vertex.
+	 * @constructor
+	 * @param {object} props Properties of the vertex.
 	 */
-	this.addOutEdge = function(edge) {
-		if (!(edge instanceof Edge)) {
-			throw new TypeError(edge.toString() + 'is not instance of Edge');
-		}
-		
-		edge.setFrom(this);
-		
-		outEdgeList.push(edge);
-	};
+	constructor(props) {
+		super(props);
 
-	/**
-	 * @returns {array<Edge>} Array of edges incoming to the vertex.
-	 */
-	this.getInEdgeList = function() {
-		return inEdgeList;
-	};
+		// constants
+		this._oneCharacterWidth = 8.3;	// approximate width (in pixels) of one character using Consolas at 15px font size
+		this._minimumWidth = 200;
+		this._relatedArchetypeIconWidth = 20;
 
-	/**
-	 * @returns {array<Edge>} Array of edges outgoing from the vertex.
-	 */
-	this.getOutEdgeList = function() {
-		return outEdgeList;
-	};
+		// properties
+		/** @prop {integer} archetype Identifier of the vertex archetype. */
+		this.archetype = props.archetype;
+		/** @prop {array} attributes TODO: jsDoc */
+		this.attributes = props.attributes;
 
-	/**
-	 * @returns {integer} Number of incoming/outgoing edges.
-	 */
-	this.countEdges = function() {
-		return inEdgeList.length + outEdgeList.length;
-	};
+		this._size = new Dimensions(
+			Math.max(30 + this.name.length * this._oneCharacterWidth, this._minimumWidth),
+			30,
+		);
 
-	/**
-	 * Increments counter of instances of a vertex archetype by one.
-	 * @param {integer} archetypeIndex Index of the vertex archetype.
-	 */
-	this.incrementRelatedArchetype = function(archetypeIndex) {
-		if (!relatedArchetypeMap.hasOwnProperty(archetypeIndex)) {
-			relatedArchetypeMap[archetypeIndex] = 0;
-		}
+		this._group = null;
 
-		relatedArchetypeMap[archetypeIndex]++;
-	};
+		this._inEdgeList = [];
+		this._outEdgeList = [];
+	}
 
 	/**
-	 * @returns {object} Map with archetype indexes as keys and counters of their instances as values.
+	 * @inheritdoc
 	 */
-	this.getRelatedArchetypeMap = function() {
-		return relatedArchetypeMap;
-	};
+	addSymbol(symbol) {
+		super.addSymbol(symbol);
+
+		if (this._group !== null) {
+			this._group.addSymbol(symbol);
+		}
+	}
 
 	/**
-	 * @returns {integer} Number of unique vertex archetypes related to the vertex.
+	 * @inheritdoc
 	 */
-	this.countRelatedArchetypes = function() {
-		return Object.keys(relatedArchetypeMap).length;
-	};
+	removeSymbol(symbol) {
+		super.removeSymbol(symbol);
+
+		if (this._group !== null) {
+			this._group.removeSymbol(symbol);
+		}
+	}
 
 	/**
-	 * Adds symbol to the list of symbols displayed next to the vertex.
-	 * @param {array} symbol Node symbol to be added.
+	 * Adds a new edge ending in the vertex. Its ending point is moved to the current position of the vertex.
+	 * @param {Edge} edge Edge going to the vertex.
 	 */
-	this.addSymbol = function(symbol) {
-		symbolList.push(symbol);
+	addInEdge(edge) {
+		if (!(edge instanceof Edge)) {
+			throw new TypeError(edge.toString() + ' is not an instance of Edge');
+		}
 
-		if (excluded) return;
+		edge.to = this;
 
-		symbolListComponent.appendChild(symbol);
-	};
+		this._inEdgeList.push(edge);
+	}
 
 	/**
-	 * Removes symbol from the list of symbols displayed next to the vertex.
-	 * @param {array} symbol Node symbol to be removed.
+	 * Adds a new edge starting in the vertex. Its starting point is moved to the current position of the vertex.
+	 * @param {Edge} edge Edge going from the vertex.
 	 */
-	this.removeSymbol = function(symbol) {
-		symbolList.splice(symbolList.indexOf(symbol), 1);
+	addOutEdge(edge) {
+		if (!(edge instanceof Edge)) {
+			throw new TypeError(edge.toString() + ' is not an instance of Edge');
+		}
 
-		if (excluded) return;
+		edge.from = this;
+
+		this._outEdgeList.push(edge);
+	}
 
-		symbolListComponent.removeChild(symbol);
-	};
-	
 	/**
-	 * @returns {Coordinates} Current position of the vertex.
+	 * @returns {array<Edge>} Array of edges incoming to the vertex.
 	 */
-	this.getPosition = function() {
-		return position;
-	};
+	get inEdgeList() {
+		return this._inEdgeList;
+	}
 
 	/**
-	 * Updates the current position of the vertex in graph.
-	 * @param {Coordinates} New position of the vertex.
+	 * @returns {array<Edge>} Array of edges outgoing from the vertex.
 	 */
-	this.setPosition = function(coords) {
-		if (!(coords instanceof Coordinates)) {
-			throw new TypeError(coords.toString() + 'is not instance of Coordinates');
-		}
-
-		position = coords;
-	};
+	get outEdgeList() {
+		return this._outEdgeList;
+	}
 
 	/**
-	 * @returns {Coordinates} Centre of the vertex.
+	 * @returns {integer} Number of incoming/outgoing edges.
 	 */
-	this.getCenter = function() {
-		return new Coordinates(
-			position.x + size.width / 2,
-			position.y + size.height / 2,
-		);
-	};
+	countEdges() {
+		return this._inEdgeList.length + this._outEdgeList.length;
+	}
 
 	/**
-	 * Moves the vertex to a new position in graph. Edges related to the vertex are moved as well.
-	 * @param {Coordinates} coords Coordinates to be moved to.
+	 * Increments counter of instances of a vertex archetype by one.
+	 * @param {integer} archetypeIndex Index of the vertex archetype.
 	 */
-	this.move = function(coords) {
-		if (!(coords instanceof Coordinates)) {
-			throw new TypeError(coords.toString() + 'is not instance of Coordinates');
+	incrementRelatedArchetype(archetypeIndex) {
+		if (this.relatedArchetypeMap.hasOwnProperty(archetypeIndex) === false) {
+			this.relatedArchetypeMap[archetypeIndex] = 0;
 		}
 
-		rootElement.setAttribute('x', coords.x);
-		rootElement.setAttribute('y', coords.y);
-
-		inEdgeList.forEach(function(edge) {
-			edge.moveEnd(new Coordinates(
-				coords.x + size.width / 2,
-				coords.y + size.height / 2
-			));
-		});
-	
-		outEdgeList.forEach(function(edge) {
-			edge.moveStart(new Coordinates(
-				coords.x + size.width / 2,
-				coords.y + size.height / 2
-			));
-		});
-	};
+		this.relatedArchetypeMap[archetypeIndex]++;
+	}
 
 	/**
 	 * @returns {Group} Group this vertex is currently part of. If the vertex stands alone, null is returned.
 	 */
-	this.getGroup = function() {
-		return group;
-	};
+	get group() {
+		return this._group;
+	}
 
 	/**
 	 * Sets a new group that the vertex is added to. If the vertex is currently excluded, its floating point is destroyed.
 	 * @param {Group} newValue Group this vertex is a part of.
 	 */
-	this.setGroup = function(newValue) {
+	set group(newValue) {
 		if (!(newValue instanceof Group) && newValue !== null) {
 			throw new TypeError(newValue.toString() + 'is neither instance of Group nor null');
 		}
 
-		group = newValue;
+		this._group = newValue;
 
-		if (newValue && this.isExcluded()) {
+		if (newValue && this.isExcluded) {
 			// remove floater
-			app.sidebarComponent.removeFloater(floater);
-			delete floater;
-		}
-	};
-
-	/**
-	 * Sets the vertex as found. Highlighting is skipped when the vertex is excluded.
-	 * @param {boolean} newValue True to mark the vertex as found, otherwise false.
-	 */
-	this.setFound = function(newValue) {
-		found = newValue;
-
-		if (excluded) return;
-		
-		if (newValue) {
-			rootElement.classList.add('node--found');
-		} else {
-			rootElement.classList.remove('node--found');
-		}
-	};
-
-	/**
-	 * Toggles transparency of the vertex. Style change is skipped when the vertex is excluded.
-	 * @param {boolean} newValue True to dim the vertex, false to display it normally.
-	 */
-	this.setDimmed = function(newValue) {
-		dimmed = newValue;
-
-		if (excluded) return;
-
-		if (newValue) {
-			rootElement.classList.add('node--dimmed');
-		} else {
-			rootElement.classList.remove('node--dimmed');
-		}
-	};
-
-    /**
-     * @returns {boolean} true if icon in all neighbours should be displayed, false otherwise
-     */
-	this.isIconsDisplayed = function () {
-		return iconsDisplayed;
-    };
-
-	this.removeIcon = function () {
-		if(iconsDisplayed) {
-			showIconClick.bind(this)(null)
-		}
-    };
-
-	/**
-	 * @returns true if the vertex is currently highlighted (in any way), otherwise false
-	 */
-	this.isHighlighted = function() {
-		return highlighted;
-	};
-
-	/**
-	 * Toggles highlighting of the vertex.
-	 * @param {boolean} newValue True to highlight the vertex, false to unhighlight.
-	 */
-	this.setHighlighted = function(newValue) {
-		highlighted = newValue;
-
-		if (newValue) {
-			rootElement.classList.add('node--highlighted');
-		} else {
-			rootElement.classList.remove('node--highlighted');
-		}
-	};
-
-	/**
-	 * Toggles inner state of the vertex marking whether highlighting of its requirements is active.
-	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
-	 */
-	this.setHighlightedRequiredNeighbours = function(newValue) {
-		highlightedRequiredNeighbours = newValue;
-	};
-
-	/**
-	 * Toggles inner state of the vertex marking whether highlighting of its dependents is active.
-	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
-	 */
-	this.setHighlightedProvidedNeighbours = function(newValue) {
-		highlightedProvidedNeighbours = newValue;
-	};
-
-	/**
-	 * Toggles inner state of the vertex marking whether highlighting of instances of a vertex archetype is active.
-	 * @param {boolean} newValue True to highlight the neighbours, false to unhighlight.
-	 */
-	this.setHighlightedArchetypeNeighbours = function(newValue) {
-		highlightedArchetypeNeighbours = newValue;
-	};
-
-	/**
-	 * Toggles highlighting of the vertex to mark it as requirement of some other node.
-	 * @param {boolean} newValue True to highlight, false to unhighlight.
-	 */
-	this.setHighlightedRequired = function(newValue) {
-		if (newValue) {
-			rootElement.classList.add('node--highlighted-required');
-		} else {
-			rootElement.classList.remove('node--highlighted-required');
+			app.sidebarComponent.removeFloater(this._proxy);
+			this._proxy = null;
 		}
+	}
 
-		if (group !== null) {
-			group.setHighlightedRequired(newValue);
-		}
-	};
-	
 	/**
-	 * Toggles highlighting of the vertex to mark it as dependent of some other node.
-	 * @param {boolean} newValue True to highlight, false to unhighlight.
+	 * @inheritdoc
 	 */
-	this.setHighlightedProvided = function(newValue) {
-		if (newValue) {
-			rootElement.classList.add('node--highlighted-provided');
-		} else {
-			rootElement.classList.remove('node--highlighted-provided');
-		}
+	set isHighlightedAsRequired(newValue) {
+		super.isHighlightedAsRequired = newValue;
 
-		if (group !== null) {
-			group.setHighlightedProvided(newValue);
-		}
-	};
-	
-	/**
-	 * Toggles highlighting of the vertex to mark it as instance of archetype related to some other node.
-	 * @param {boolean} newValue True to highlight, false to unhighlight.
-	 */
-	this.setHighlightedArchetype = function(newValue) {
-		if (newValue) {
-			rootElement.classList.add('node--highlighted-archetype');
-		} else {
-			rootElement.classList.remove('node--highlighted-archetype');
+		if (this._group !== null) {
+			this._group.isHighlightedAsRequired = newValue;
 		}
-	
-		if (group !== null) {
-			group.setHighlightedArchetype(newValue);
-		}
-	};
-
-	/**
-	 * @returns {boolean} True is the vertex is currently excluded from the viewport, otherwise false.
-	 */
-	this.isExcluded = function() {
-		return excluded;
-	};
+	}
 
 	/**
-	 * Toggles excluded state of the vertex. If the vertex is set excluded, a new floating point is created to connect it with 
-	 * related nodes in the viewport. Otherwise, the floating point is deleted.
-	 * Any node is called excluded when it is not visible in the viewport but instead in the sidebar.
-	 * @param {boolean} newValue True to set the vertex as excluded, otherwise false.
+	 * @inheritdoc
 	 */
-	this.setExcluded = function(newValue) {
-		excluded = newValue;
-
-		if (group !== null) return;
-
-		if (newValue) {
-			// set floater
-			floater = new FloatingPoint;
-			floater.setNode(this);
-			app.sidebarComponent.addFloater(floater);
+	set isHighlightedAsProvided(newValue) {
+		super.isHighlightedAsProvided = newValue;
 
-		} else {
-			// remove floater
-			app.sidebarComponent.removeFloater(floater);
-			delete floater;
+		if (this._group !== null) {
+			this._group.isHighlightedAsProvided = newValue;
 		}
-	};
+	}
 
 	/**
-	 * Excludes the vertex from the viewport. Removes vertex DOM element and hides its edges. If showIcon is set to True
-	 * display icon in all neighbour vertices.
-	 * @param {boolean} showIcon True to display icon in all neighbours, False otherwise
+	 * @inheritdoc
 	 */
-	this.exclude = function(showIcon = false) {
-		this.setExcluded(true);
-		this.remove(true);
+	set isHighlightedAsArchetype(newValue) {
+		super.isHighlightedAsArchetype = newValue;
 
-		app.viewportComponent.removeVertex(this);
-
-		if(showIcon){
-			showIconClick.bind(this)(null)
+		if (this._group !== null) {
+			this._group.isHighlightedAsArchetype = newValue;
 		}
-	};
+	}
 
 	/**
 	 * Includes the vertex in the viewport. Afterwards, edges related to the vertex are moved to the current position of the vertex.
 	 */
-	this.include = function() {
-		this.removeFromSidebarList();
-
-        this.removeIcon();
-        this.setExcluded(false);
-        this.remove(false);
-
-		app.viewportComponent.addVertex(this);
+	include() {
+		super.include();
 
 		// set edges' ends
-		var inEdgeList = this.getInEdgeList();
-		inEdgeList.forEach(function(edge) {
-			edge.setTo(this);
-			edge.moveEnd(this.getCenter());
-		}, this);
-
-		var outEdgeList = this.getOutEdgeList();
-		outEdgeList.forEach(function(edge) {
-			edge.setFrom(this);
-			edge.moveStart(this.getCenter());
-		}, this);
-	};
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.forEach(edge => {
+			edge.to = this;
+			edge.end = this.center;
+		});
 
-	/**
-	 * Hook function used to remove the vertex from the sidebar list it is located in before it is moved to the viewport.
-	 */
-	this.removeFromSidebarList = Utils.noop;
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.forEach(edge => {
+			edge.from = this;
+			edge.start = this.center;
+		});
+	}
 
 	/**
 	 * @returns {boolean} True if the vertex is not connected to any other nodes.
 	 */
-	this.isUnconnected = function() {
-		return inEdgeList.length === 0 && outEdgeList.length === 0;
-	};
-
-	/**
-	 * Creates a new DOM element representing the vertex in memory. The element being created depends on whether the vertex
-	 * is excluded at the moment. Binds user interactions to local handler functions.
-	 * @returns {Element} HTML or SVG DOM element depending on whether the vertex is excluded.
-	 */
-	this.render = function() {
-		rootElement = excluded ? renderExcluded.call(this) : renderIncluded.call(this);
-
-		this.setHighlighted(highlighted);
-
-		return rootElement;
-	};
-	
-	/**
-	 * Removes the DOM element representing the vertex from document.
-	 * @param {boolean} hideEdges True to hide edges related to the vertex in the viewport. Edges are (almost) never really
-	 * removed but rather hidden for cases when a node is included back in the viewport.
-	 */
-	this.remove = function(hideEdges) {
-		rootElement.remove();
-
-		// toggle edges
-		inEdgeList.filter(function(edge) {
-			return !edge.getFrom().isExcluded();
-		}).forEach(function(edge) {
-			edge.setHidden(hideEdges);
-		});
-
-		outEdgeList.filter(function(edge) {
-			return !edge.getTo().isExcluded();
-		}).forEach(function(edge) {
-			edge.setHidden(hideEdges);
-		});
-	};
+	get isUnconnected() {
+		return this.inEdgeList.length === 0 && this.outEdgeList.length === 0;
+	}
 
 	/**
 	 * Exports the vertex to a new, plain JS object.
 	 * @returns {Object} exported vertex
 	 */
-	this.export = function() {
+	export() {
 		return {
 			archetype: this.archetype,
-			attributes: props.attributes,
+			attributes: this.attributes,
 			id: this.id,
 			text: '',
 			name: this.name,
-			position: position,
+			position: this.position,
 		};
-	};
+	}
 
 	/**
-	 * @returns {Element} SVG DOM element.
+	 * @returns {SVGElement} SVG DOM element.
 	 */
-	function renderIncluded() {
-		rootElement = DOM.createSvgElement('svg', {
-			'class': 'node vertex',
-			'x': position.x,
-			'y': position.y,
+	_renderIncluded() {
+		this._rootElement = DOM.s('svg', {
+			class: 'node vertex',
+			x: this.position.x,
+			y: this.position.y,
 			'data-id': this.id,
 			'data-name': this.name,
-		});
-		rootElement.addEventListener('click', click.bind(this));
-		rootElement.addEventListener('dblclick', Utils.stopPropagation);
-		rootElement.addEventListener('contextmenu', contextMenu.bind(this));
-		rootElement.addEventListener('mousedown', mouseDown.bind(this));
-		
-		rootElement.appendChild(DOM.createSvgElement('rect', {
-			'height': size.height,
-			'width': size.width + this.countRelatedArchetypes() * relatedArchetypeIconWidth,
-			'x': 1,
-			'y': 1,
-		}));
-
-		// archetype icon
-		var archetypeIcon = DOM.createSvgElement('use', {
-			'href': '#vertexArchetypeIcon-' + app.archetype.vertex[this.archetype].name,
-			'class': 'archetype-icon',
-			'transform': 'translate(8, 8)',
-		});
-		archetypeIcon.addEventListener('click', archetypeClick.bind(this)); // TODO when icon == null can not click on item
+			onClick: this._onNodeClick.bind(this),
+			onDblClick: Utils.stopPropagation,
+			onContextMenu: this._onNodeContextMenu.bind(this),
+			onMouseDown: this._onNodeMouseDown.bind(this),
+		}, [
+			DOM.s('rect', {
+				width: this.size.width + Object.keys(this.relatedArchetypeMap).length * this._relatedArchetypeIconWidth,
+				height: this.size.height,
+				x: 1,
+				y: 1,
+			}),
+			// vertex archetype
+			DOM.s('use', {
+				href: '#vertexArchetypeIcon-' + app.archetype.vertex[this.archetype].name,
+				class: 'archetype-icon',
+				transform: 'translate(8, 8)',
+				onClick: this._onArchetypeIconClick.bind(this),
+			}),
+			// vertex name
+			DOM.s('text', {
+				fill: 'black',
+				x: 25,
+				y: 20,
+			}, [
+				DOM.t(this.name),
+			]),
+		]);
 
-		rootElement.appendChild(archetypeIcon);
+		// symbol list
+		this._symbolListComponent = new NodeSymbolList;
+		this._rootElement.appendChild(this._symbolListComponent.render());
 
-		// name
-		var nameText = DOM.createSvgElement('text', {
-			'fill': 'black',
-			'x': 25,
-			'y': 20,
+		this._symbolList.forEach(symbol => {
+			this._symbolListComponent.appendChild(symbol);
 		});
-		nameText.appendChild(document.createTextNode(this.name));
-		rootElement.appendChild(nameText);
 
 		// related archetype icons
-		var relatedArchetypeListContainer = DOM.createSvgElement('g', {
-			'transform': `translate(${size.width}, 0)`,
+		const relatedArchetypeListContainer = DOM.s('g', {
+			transform: `translate(${this.size.width}, 0)`,
 		});
-		rootElement.appendChild(relatedArchetypeListContainer);
-
-		var archetypeIconOrder = 0;
-		for (var archetypeIndex in relatedArchetypeMap) {
-			var relatedArchetypeIcon = DOM.createSvgElement('use', {
-				'href': '#vertexArchetypeIcon-' + app.archetype.vertex[archetypeIndex].name,
-				'class': 'archetype-icon',
-				'transform': `translate(${archetypeIconOrder * relatedArchetypeIconWidth}, 8)`,
-			});
-			relatedArchetypeIcon.addEventListener('click', relatedArchetypeClick.bind(this, parseInt(archetypeIndex))); // TODO when icon == null can not click on item
-
-			relatedArchetypeListContainer.appendChild(relatedArchetypeIcon);
+		this._rootElement.appendChild(relatedArchetypeListContainer);
+
+		let archetypeIconOrder = 0;
+		for (let archetypeIndex in this.relatedArchetypeMap) {
+			relatedArchetypeListContainer.appendChild(DOM.s('use', {
+				href: '#vertexArchetypeIcon-' + app.archetype.vertex[archetypeIndex].name,
+				class: 'archetype-icon',
+				transform: `translate(${archetypeIconOrder * this._relatedArchetypeIconWidth}, 8)`,
+				onClick: this._onRelatedArchetypeIconClick.bind(this, parseInt(archetypeIndex)), // TODO when icon == null can not click on item
+			}));
 
 			archetypeIconOrder++;
 		}
 
-		// symbol list
-		symbolListComponent = new VertexSymbolList;
-		rootElement.appendChild(symbolListComponent.render());
-
-		symbolList.forEach(function(symbol) {
-			symbolListComponent.appendChild(symbol);
-		}, this);
-
-		return rootElement;
+		return this._rootElement;
 	}
 
 	/**
-	 * @returns {Element} HTML DOM element.
+	 * @returns {HTMLElement} HTML DOM element.
 	 */
-	function renderExcluded() {
-		rootElement = DOM.createHtmlElement('li', {
-			'class': 'node vertex',
-			'data-id': this.id,
+	_renderExcluded() {
+		const svg = DOM.s('svg', {
+			xmlns: 'http://www.w3.org/2000/svg',
+			height: 60,
+			width: 46,
 		});
 
-		var svg = DOM.createSvgElement('svg', {
-			'xmlns': 'http://www.w3.org/2000/svg',
-			'height': 60,
-			'width': 46,
-		});
-		rootElement.appendChild(svg);
-
 		// related archetypes
-		var relatedArchetypesGroup = DOM.createSvgElement('g', {
-			'transform': 'translate(10, 15)',
+		const relatedArchetypesGroup = DOM.s('g', {
+			transform: 'translate(10, 15)',
 		});
 		svg.appendChild(relatedArchetypesGroup);
 
-		var archetypeIconOrder = 0;
-		for (var archetypeIndex in relatedArchetypeMap) {
-			var relatedArchetype = DOM.createSvgElement('g', {
-				'class': 'related-archetype',
-				'transform': `translate(0, ${archetypeIconOrder * 20})`,
-			});
-			relatedArchetypesGroup.appendChild(relatedArchetype);
-
-			// counter
-			var relatedArchetypeCounter = DOM.createSvgElement('text');
-			relatedArchetypeCounter.appendChild(DOM.createTextElement(relatedArchetypeMap[archetypeIndex]));
-			relatedArchetype.appendChild(relatedArchetypeCounter);
-
-			// icon
-			var relatedArchetypeIcon = DOM.createSvgElement('use', {
-				'href': '#vertexArchetypeIcon-' + app.archetype.vertex[archetypeIndex].name,
-				'class': 'archetype-icon',
-				'transform': `translate(15, -10)`,
-			});
-			relatedArchetypeIcon.addEventListener('click', relatedArchetypeClick.bind(this, parseInt(archetypeIndex))); // TODO when icon == null can not click on item
-			relatedArchetype.appendChild(relatedArchetypeIcon);
-
-			// line
-			relatedArchetype.appendChild(DOM.createSvgElement('line', {
-				'x1': 30,
-				'y1': -5,
-				'x2': 36,
-				'y2': -5,
-			}));
+		let archetypeIconOrder = 0;
+		for (let archetypeIndex in this.relatedArchetypeMap) {
+			relatedArchetypesGroup.appendChild(DOM.s('g', {
+				class: 'related-archetype',
+				transform: `translate(0, ${archetypeIconOrder * 20})`,
+			}, [
+				// counter
+				DOM.s('text', {}, [
+					DOM.t(this.relatedArchetypeMap[archetypeIndex]),
+				]),
+				// icon
+				DOM.s('use', {
+					href: '#vertexArchetypeIcon-' + app.archetype.vertex[archetypeIndex].name,
+					class: 'archetype-icon',
+					transform: `translate(15, -10)`,
+					onClick: this._onRelatedArchetypeIconClick.bind(this, parseInt(archetypeIndex)), // TODO when icon == null can not click on item
+				}),
+				// line
+				DOM.s('line', {
+					x1: 30,
+					y1: -5,
+					x2: 36,
+					y2: -5,
+				}),
+			]));
 
 			archetypeIconOrder++;
 		}
 
-		// name
-		var nameText = DOM.createHtmlElement('div', {
-			'class': 'vertex-name',
-			'title': this.name,
-		});
-		nameText.appendChild(document.createTextNode(this.name));
-		nameText.addEventListener('click', click.bind(this));
-		rootElement.appendChild(nameText);
-
-		// buttons
-		var buttonGroup = DOM.createHtmlElement('div', {
-			'class': 'button-group',
-		});
-		rootElement.appendChild(buttonGroup);
-
-		// show symbol button
-		var showSymbolButton = DOM.createHtmlElement('button', {
-			'class': 'show-symbol-button button',
-			'style': 'background-color: ' + this.symbol[1] + ';',
-			'title': 'Show symbol next to all neighbouring components',
-		});
-		showSymbolButton.appendChild(document.createTextNode(this.symbol[0]));
-		showSymbolButton.addEventListener('click', showIconClick.bind(this));
-		buttonGroup.appendChild(showSymbolButton);
-
-		// include button
-		var includeButton = DOM.createHtmlElement('button', {
-			'class': 'include-button button',
-			'title': 'Display node in viewport',
-		});
-		includeButton.appendChild(DOM.createHtmlElement('img', {
-			'src': 'images/button_cancel.png',
-			'alt': 'Icon of "Icon of "display node in viewport" action" action',
-		}));
-		includeButton.addEventListener('click', includeClick.bind(this));
-		buttonGroup.appendChild(includeButton);
+		// root
+		this._rootElement = DOM.h('li', {
+			class: 'node vertex',
+			'data-id': this.id,
+		}, [
+			svg,
+			// name
+			DOM.h('div', {
+				class: 'vertex-name',
+				title: this.name,
+				innerText: this.name,
+				onClick: this._onNodeClick.bind(this),
+			}),
+			// buttons
+			DOM.h('div', {
+				class: 'button-group',
+			}, [
+				DOM.h('button', {
+					class: 'show-symbol-button button',
+					style: 'background-color: ' + this.symbol[1] + ';',
+					title: 'Show symbol next to all neighbouring components',
+					innerText: this.symbol[0],
+					onClick: this._onShowNeighbourIconsClick.bind(this),
+				}),
+				DOM.h('button', {
+					class: 'include-button button',
+					title: 'Display node in viewport',
+					onClick: this.include.bind(this),
+				}, [
+					DOM.h('img', {
+						src: 'images/button_cancel.png',
+						alt: 'Icon of "Icon of "display node in viewport" action" action',
+					}),
+				]),
+			]),
+		]);
 
 		// set floater element
-		floater.setElement(rootElement);
+		this._proxy.setElement(this._rootElement);
 
 		// set edges' ends
-		var inEdgeList = this.getInEdgeList();
-		inEdgeList.forEach(function(edge) {
-			floater.addInEdge(edge);
+		let inEdgeList = this.inEdgeList;
+		inEdgeList.forEach(edge => {
+			this._proxy.addInEdge(edge);
 		});
 
-		var outEdgeList = this.getOutEdgeList();
-		outEdgeList.forEach(function(edge) {
-			floater.addOutEdge(edge);
+		let outEdgeList = this.outEdgeList;
+		outEdgeList.forEach(edge => {
+			this._proxy.addOutEdge(edge);
 		});
 
-		return rootElement;
+		return this._rootElement;
 	}
-	
-	/**
-	 * Vertex click interaction. Based on whether the vertex is excluded and currently selected mouse mode (move, exclude),
-	 * the vertex is either highlighted or moved within the graph.
-	 */
-	function click(e) {
-		e.stopPropagation();
-
-		if (excluded) {
-            this.setHighlightedWithNeighbours(!highlighted);
-			return;
-		}
-
-		if (pan) {
-			pan = false;
-			return;
-		}
-
-		switch (document.modeForm.mode.value) {
-			case 'move':
-				this.setHighlightedWithNeighbours(!highlighted);
-				break;
-
-			case 'exclude':
-				this.exclude.call(this);
-
-				app.sidebarComponent.excludedNodeListComponent.add(this);
-				break;
-		}
-	}
-
-    /**
-     * Method add or remove highlighting of vertex and all neighbours.
-     *
-     * @param newHighlighted true to highlight, false otherwise
-     */
-	this.setHighlightedWithNeighbours = function (newHighlighted) {
-        this.setHighlighted(newHighlighted);
-        this.setHighlightedRequiredNeighbours(highlighted);
-        this.setHighlightedProvidedNeighbours(highlighted);
-
-        prepareHighlighting.call(this);
-        highlightRequiredNeighbours.call(this);
-        highlightProvidedNeighbours.call(this);
-    };
 
 	/**
 	 * Reveals vertex popover.
 	 * @param {MouseEvent} e Click event.
 	 */
-	function archetypeClick(e) {
+	_onArchetypeIconClick(e) {
 		e.stopPropagation();
 
 		app.viewportComponent.vertexPopoverComponent.title = this.name + ` (${app.archetype.vertex[this.archetype].name})`;
-		app.viewportComponent.vertexPopoverComponent.body = props.attributes;
+		app.viewportComponent.vertexPopoverComponent.body = this.attributes;
 		app.viewportComponent.vertexPopoverComponent.position = new Coordinates(e.clientX, e.clientY);
 		app.viewportComponent.vertexPopoverComponent.open();
 	}
-	
-	/**
-	 * Archetype icon click interaction. Toggles highlighting of neighbour vertices which are instances of a vertex archetype.
-	 * @param {integer} archetypeIndex Index of the vertex archetype.
-	 * @param {MouseEvent} e Click event.
-	 */
-	function relatedArchetypeClick(archetypeIndex, e) {
-		e.stopPropagation();
-
-		this.setHighlighted(!highlighted);
-		this.setHighlightedArchetypeNeighbours(highlighted);
-
-		prepareHighlighting.call(this);
-		highlightArchetypeNeighbours.call(this, archetypeIndex);
-	}
-
-	/**
-	 * Displays symbol of the vertex next to all nodes that it is connected with.
-	 * @param {MouseEvent} e Click event.
-	 */
-	function showIconClick(e) {
-		iconsDisplayed = !iconsDisplayed;
-
-		var neighbourList = [];
-
-		inEdgeList.filter(function(edge) {
-			return !edge.getFrom().isExcluded();
-		}).forEach(function(edge) {
-			if(!neighbourList.includes(edge.getFrom())) {
-				neighbourList.push(edge.getFrom());
-			}
-		});
-
-		outEdgeList.filter(function(edge) {
-			return !edge.getTo().isExcluded();
-		}).forEach(function(edge) {
-			if(!neighbourList.includes(edge.getTo())) {
-				neighbourList.push(edge.getTo());
-			}
-		});
-
-		neighbourList.forEach(function(node) {
-			if (iconsDisplayed) {
-				node.addSymbol(this.symbol);
-			} else {
-				node.removeSymbol(this.symbol);
-			}
-		}, this);
-	}
-
-	/**
-	 * Includes the group back to the viewport.
-	 */
-	function includeClick() {
-		this.include.call(this);
-	}
 
 	/**
 	 * Vertex right click interaction. Displays context menu filled with items representing groups that the vertex can be added to.
 	 * @param {Event} e Context menu event.
 	 */
-	function contextMenu(e) {
+	_onNodeContextMenu(e) {
 		e.preventDefault();
 
-		var excludedNodeList = app.sidebarComponent.excludedNodeListComponent.getNodeList();
-		var includedGroupList = app.viewportComponent.getGroupList();
+		let excludedNodeList = app.sidebarComponent.excludedNodeListComponent.getNodeList();
+		let includedGroupList = app.viewportComponent.getGroupList();
 
-		var nodeList = [].concat(excludedNodeList, includedGroupList);
+		let nodeList = [].concat(excludedNodeList, includedGroupList);
 		if (nodeList.length === 0) return;
 
 		app.viewportComponent.contextMenuComponent.vertex = this;
 		app.viewportComponent.contextMenuComponent.position = new Coordinates(e.clientX, e.clientY);
 
 		// fill list with items
-		nodeList.forEach(function(node) {
+		nodeList.forEach(node => {
 			app.viewportComponent.contextMenuComponent.addNode(node);
 		});
 
 		app.viewportComponent.contextMenuComponent.open();
 	}
-	
-	/**
-	 * Handles drag and drop interaction with the vertex. At the moment mouse button is pressed, it is not yet known whether 
-	 * it is just clicked or dragged.
-	 * @param {Event} e Mouse down event.
-	 */
-	function mouseDown(e) {
-		e.stopPropagation();
-		app.closeFloatingComponents();
-		
-		var self = this;
-		var start = new Coordinates(e.clientX, e.clientY);
-
-		rootElement.classList.add('node--dragged');
-		
-		document.body.addEventListener('mousemove', mouseMove);
-		document.body.addEventListener('mouseup', mouseUp);
-		document.body.addEventListener('mouseleave', mouseUp);
-
-		/**
-		 * At the moment mouse is moved, the vertex is clearly being dragged. The vertex is moved to the current position of mouse.
-		 * @param {Event} e Mouse move event.
-		 */
-		function mouseMove(e) {
-			pan = true;
-
-			self.move(new Coordinates(
-				position.x - (start.x - e.clientX) / app.zoom.scale,
-				position.y - (start.y - e.clientY) / app.zoom.scale,
-			));
-		}
-
-		/**
-		 * At the moment mouse button is released, dragging is done and its final position is set to the vertex.
-		 * @param {Event} e Mouse up event.
-		 */
-		function mouseUp(e) {
-			self.setPosition(new Coordinates(
-				+rootElement.getAttribute('x'),
-				+rootElement.getAttribute('y'),
-			));
-
-			rootElement.classList.remove('node--dragged');
-			
-			document.body.removeEventListener('mousemove', mouseMove);
-			document.body.removeEventListener('mouseup', mouseUp);
-			document.body.removeEventListener('mouseleave', mouseUp);
-		}
-	}
-
-	/**
-	 * * Prepares highlighting of all graph components so that only the wished ones need to be modified.
-	 */
-	function prepareHighlighting() {
-		this.setDimmed(false);
-
-		this.setHighlightedRequired(false);
-		this.setHighlightedProvided(false);
-		this.setHighlightedArchetype(false);
-
-		if (highlighted) {
-			// dim and unhighlight all nodes but this
-			app.nodeList.forEach(function(node) {
-				if (node === this) return;
-
-				node.setDimmed(true);
-
-				node.setHighlighted(false);
-				node.setHighlightedRequired(false);
-				node.setHighlightedProvided(false);
-				node.setHighlightedArchetype(false);
-			}, this);
-
-			// dim and unhighlight all edges
-			app.edgeList.forEach(function(edge) {
-				edge.setDimmed(true);
-
-				edge.setHighlighted(false);
-				edge.setHighlightedRequired(false);
-				edge.setHighlightedProvided(false);
-			});
-
-		} else {
-			app.nodeList.forEach(function(node) {
-				if (node === this) return;
-
-				node.setDimmed(false);
-
-				node.setHighlighted(false);
-				node.setHighlightedRequired(false);
-				node.setHighlightedProvided(false);
-				node.setHighlightedArchetype(false);
-			}, this);
-
-			app.edgeList.forEach(function(edge) {
-				edge.setHidden(edge.getFrom().isExcluded() || edge.getTo().isExcluded());
-
-				edge.setDimmed(false);
-
-				edge.setHighlighted(false);
-				edge.setHighlightedRequired(false);
-				edge.setHighlightedProvided(false);
-			});
-		}
-	}
-
-	/**
-	 * Highlights only neighbours of the vertex that are required.
-	 */
-	function highlightRequiredNeighbours() {
-		if (highlightedRequiredNeighbours === false) return;
-
-		inEdgeList.forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.setDimmed(false);
-			edge.getFrom().setDimmed(false);
-
-			edge.setHighlightedRequired(true);
-			edge.getFrom().setHighlightedRequired(true);
-		});
-	}
-
-	/**
-	 * Highlights only neighbours of the vertex that are provided.
-	 */
-	function highlightProvidedNeighbours() {
-		if (highlightedProvidedNeighbours === false) return;
-
-		outEdgeList.forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.setDimmed(false);
-			edge.getTo().setDimmed(false);
-
-			edge.setHighlightedProvided(true);
-			edge.getTo().setHighlightedProvided(true);
-		});
-	}
-
-	/**
-	 * Highlights only neighbours of the vertex that are instances of the archetype.
-	 * @param {integer} archetypeIndex Index of the vertex archetype.
-	 */
-	function highlightArchetypeNeighbours(archetypeIndex) {
-		if (highlightedArchetypeNeighbours === false) return;
-
-		inEdgeList.filter(function(edge) {
-			return edge.getFrom().archetype === archetypeIndex;
-		}).forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.setDimmed(false);
-			edge.getFrom().setDimmed(false);
-
-			edge.getFrom().setHighlightedArchetype(true);
-		});
-
-		outEdgeList.filter(function(edge) {
-			return edge.getTo().archetype === archetypeIndex;
-		}).forEach(function(edge) {
-			edge.setHidden(false);
-
-			edge.setDimmed(false);
-			edge.getTo().setDimmed(false);
-
-			edge.getTo().setHighlightedArchetype(true);
-		});
-	}
 }
diff --git a/sources/src/main/webapp/js/components/vertexContextMenuList.js b/sources/src/main/webapp/js/components/vertexContextMenuList.js
index aadb956..309de75 100644
--- a/sources/src/main/webapp/js/components/vertexContextMenuList.js
+++ b/sources/src/main/webapp/js/components/vertexContextMenuList.js
@@ -54,7 +54,7 @@ class VertexContextMenuList {
 	 * @param {(Vertex|Group)} node Graph node to be displayed in the context menu.
 	 */
 	addNode(node) {
-		if (node instanceof Vertex && node.getGroup() !== null) {
+		if (node instanceof Vertex && node.group !== null) {
 			throw new Error('Vertex is already a member of some group.');
 		}
 
@@ -101,7 +101,7 @@ class VertexContextMenuList {
 		let group;
 		if (node instanceof Vertex) {
 			// create a new group
-			group = new Group({});
+			group = Group.create();
 			group.setExcluded(true);
 			group.addVertex(node);
 
diff --git a/sources/src/main/webapp/js/components/vertexSymbolList.js b/sources/src/main/webapp/js/components/vertexSymbolList.js
deleted file mode 100644
index dc74e54..0000000
--- a/sources/src/main/webapp/js/components/vertexSymbolList.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Class representing list of symbols displayed next to a vertex to marks its relation to other an other, excluded vertices.
- * @see Vertex
- */
-class VertexSymbolList {
-	/**
-	 * @constructor
-	 */
-	constructor() {
-		this._width = 20;
-		this._height = 20;
-	}
-
-	/**
-	 * Creates a new DOM element representing the list of symbols in memory.
-	 * @public
-	 * @returns {SVGElement} SVG DOM element.
-	 */
-	render() {
-		this._rootElement = DOM.s('g', {
-			transform: 'translate(0, 30)',
-		});
-
-		return this._rootElement;
-	}
-
-	/**
-	 * Adds a new symbol to the list.
-	 * @public
-	 * @param {array} symbol Symbol to be added to the list.
-	 */
-	appendChild(symbol) {
-		this._rootElement.appendChild(DOM.s('g', {
-			class: 'neighbour-node-symbol ' + symbol[2],
-		}, [
-			DOM.s('rect', {
-				x: 0,
-				y: 0,
-				width: this._width,
-				height: this._height,
-				fill: symbol[1],
-			}),
-			DOM.s('text', {
-				x: 6,
-				y: 15,
-			}, [
-				DOM.t(symbol[0]),
-			]),
-		]));
-
-		this._reorderSymbols();
-	}
-
-	/**
-	 * Removes a symbol from the list.
-	 * @public
-	 * @param {array} symbol Symbol to be removed from the list.
-	 */
-	removeChild(symbol) {
-		let symbolGroup = this._rootElement.querySelector('.' + symbol[2]);
-
-		symbolGroup.remove();
-
-		this._reorderSymbols();
-	}
-
-	/**
-	 * Changes the order of symbols displayed in the list. It is used to refresh their position after one is added or removed.
-	 * @private
-	 */
-	_reorderSymbols() {
-		for (var i = 0; i < this._rootElement.children.length; i++) {
-			let symbolGroup = this._rootElement.children[i];
-
-			symbolGroup.setAttribute('transform', `translate(${i * this._width + 1}, 1)`);
-		}
-	}
-}
diff --git a/sources/src/main/webapp/js/components/viewport.js b/sources/src/main/webapp/js/components/viewport.js
index 5e72855..6746c0e 100644
--- a/sources/src/main/webapp/js/components/viewport.js
+++ b/sources/src/main/webapp/js/components/viewport.js
@@ -33,50 +33,40 @@ function Viewport() {
 
 		edgeList.push(edge);
 
-		if (edge.getFrom() === null || edge.getFrom().isExcluded()) return;
-		if (edge.getTo() === null || edge.getTo().isExcluded()) return;
+		if (edge.from === null || edge.from.isExcluded) return;
+		if (edge.to === null || edge.to.isExcluded) return;
 
 		edgesContainer.appendChild(edge.render());
 	};
 
-	this.addVertex = function(vertex) {
-		if (!(vertex instanceof Vertex)) {
-			throw new TypeError(vertex.toString() + 'is not instance of Vertex');
+	this.addNode = function(node) {
+		if (!(node instanceof Node)) {
+			throw new TypeError(node.toString() + ' is not an instance of Node');
 		}
 
-		nodeList.push(vertex);
-		vertexList.push(vertex);
+		nodeList.push(node);
 
-		verticesContainer.appendChild(vertex.render());
-	};
-
-	this.removeVertex = function(vertex) {
-		if (!(vertex instanceof Vertex)) {
-			throw new TypeError(vertex.toString() + 'is not instance of Vertex');
+		if (node instanceof Vertex) {
+			vertexList.push(node);
+			verticesContainer.appendChild(node.render());
+		} else if (node instanceof Group) {
+			groupList.push(node);
+			groupsContainer.appendChild(node.render());
 		}
-
-		nodeList.splice(nodeList.indexOf(vertex), 1);
-		vertexList.splice(vertexList.indexOf(vertex), 1);
 	};
 
-	this.addGroup = function(group) {
-		if (!(group instanceof Group)) {
-			throw new TypeError(group.toString() + 'is not instance of Group');
+	this.removeNode = function(node) {
+		if (!(node instanceof Node)) {
+			throw new TypeError(node.toString() + ' is not an instance of Node');
 		}
 
-		nodeList.push(group);
-		groupList.push(group);
-
-		groupsContainer.appendChild(group.render());
-	};
+		nodeList.splice(nodeList.indexOf(node), 1);
 
-	this.removeGroup = function(group) {
-		if (!(group instanceof Group)) {
-			throw new TypeError(group.toString() + 'is not instance of Group');
+		if (node instanceof Vertex) {
+			vertexList.splice(vertexList.indexOf(node), 1);
+		} else if (node instanceof Group) {
+			groupList.splice(groupList.indexOf(node), 1);
 		}
-
-		nodeList.splice(nodeList.indexOf(group), 1);
-		groupList.splice(groupList.indexOf(group), 1);
 	};
 	
 	this.getEdgeList = function() {
@@ -96,11 +86,10 @@ function Viewport() {
 	};
 
 	this.addSvgDefinition = function(id, svgString) {
-		var g = DOM.createSvgElement('g', {
-			'id': id,
-		});
-		g.innerHTML = svgString;
-		definitions.appendChild(g);
+		definitions.appendChild(DOM.s('g', {
+			id,
+			innerHTML: svgString,
+		}));
 	};
 
 	this.getSize = function() {
@@ -128,7 +117,7 @@ function Viewport() {
 
 		var nodeList = app.viewportComponent.getNodeList();
 		nodeList.forEach(function(node) {
-			var center = node.getCenter();
+			var center = node.center;
 
 			sumOfCenters.x += center.x;
 			sumOfCenters.y += center.y;
@@ -186,7 +175,7 @@ function Viewport() {
 		mainSvg.appendChild(definitions);
 
 		var linearGradient = DOM.createSvgElement('linearGradient', {
-			'id': 'node--highlighted-required-provided',
+			'id': 'node--highlighted-as-required-provided',
 		});
 		linearGradient.appendChild(DOM.createSvgElement('stop', {
 			'offset': '0%',
diff --git a/sources/src/main/webapp/js/services/forceDirected.js b/sources/src/main/webapp/js/services/forceDirected.js
index 0d2499e..94e6e73 100644
--- a/sources/src/main/webapp/js/services/forceDirected.js
+++ b/sources/src/main/webapp/js/services/forceDirected.js
@@ -66,11 +66,12 @@ function ForceDirected() {
 		for (i = 0; i < visibleNodes.length; i++){
 			var currNode = visibleNodes[i];
 
-			for (j = 0; j < currNode.getInEdgeList().length; j++) {
-				var otherNode = currNode.getInEdgeList()[j].getFrom();
+			let inEdgeList = currNode.inEdgeList;
+			for (let j = 0; j < inEdgeList.length; j++) {
+				let otherNode = inEdgeList[j].from;
 
-				var currPosition = currNode.getPosition();
-				var otherPosition = otherNode.getPosition();
+				var currPosition = currNode.position;
+				var otherPosition = otherNode.position;
 
 				// calculate force
 				var x = currPosition.x - otherPosition.x;
@@ -83,11 +84,12 @@ function ForceDirected() {
 				forceField[Utils.getUniqueId(currNode)][1] += Math.round(-1 * y * (distance / attractiveStrength));
 			}
 
-			for (j = 0; j < currNode.getOutEdgeList().length; j++) {
-				var otherNode = currNode.getOutEdgeList()[j].getTo();
+			let outEdgeList = currNode.outEdgeList;
+			for (let j = 0; j < outEdgeList.length; j++) {
+				let otherNode = outEdgeList[j].to;
 
-				var currPosition = currNode.getPosition();
-				var otherPosition = otherNode.getPosition();
+				var currPosition = currNode.position;
+				var otherPosition = otherNode.position;
 
 				// calculate force
 				var x = currPosition.x - otherPosition.x;
@@ -156,7 +158,7 @@ function ForceDirected() {
 					currNode.getPosition().y + forceY,
 				);
 
-				currNode.setPosition(coords);
+				currNode.position = coords;
 				currNode.move(coords);
 			}
 		}
diff --git a/sources/src/main/webapp/js/services/graphExporter.js b/sources/src/main/webapp/js/services/graphExporter.js
index bb0a3ae..3b58e5d 100644
--- a/sources/src/main/webapp/js/services/graphExporter.js
+++ b/sources/src/main/webapp/js/services/graphExporter.js
@@ -27,20 +27,12 @@ function GraphExporter() {
 		var sideBar = excludedNodeList.map(function(node) {
 			return {
 				id: Utils.getUniqueId(node),
-                isIconsDisplayed: node.isIconsDisplayed(),
+				isIconsDisplayed: node.isIconsDisplayed,
 			};
 		});
 
-        var highlightedEdge = app.edgeList.find(function (edge) {
-            return edge.isHighlighted()
-        });
-
-        // when edge is highlighted another vertex can not be highlighted
-        if (Utils.isUndefined(highlightedEdge)) {
-            var highlightedVertex = app.nodeList.find(function (vertex) {
-                return vertex.isHighlighted()
-            });
-        }
+		let highlightedEdge = app.edgeList.find(edge => edge.isHighlighted);
+		let highlightedVertex = app.nodeList.find(vertex => vertex.isHighlighted);
 
 		return {
 			attributeTypes: app.attributeTypeList,
@@ -51,7 +43,7 @@ function GraphExporter() {
 			possibleEnumValues: app.possibleEnumValues,
 			groups: groups,
 			sideBar: sideBar,
-            highlightedVertex: Utils.getUniqueId(highlightedVertex),
+			highlightedVertex: Utils.isUndefined(highlightedVertex) ? '' : Utils.getUniqueId(highlightedVertex),
 			highlightedEdge: Utils.isUndefined(highlightedEdge) ? '' : highlightedEdge.id,
 		};
 	}
diff --git a/sources/src/main/webapp/js/services/graphLoader.js b/sources/src/main/webapp/js/services/graphLoader.js
index cef32be..37e2688 100644
--- a/sources/src/main/webapp/js/services/graphLoader.js
+++ b/sources/src/main/webapp/js/services/graphLoader.js
@@ -28,23 +28,23 @@ function GraphLoader() {
 			app.viewportComponent.addSvgDefinition('vertexArchetypeIcon-' + vertexArchetype.name, vertexArchetype.icon);
 		});
 
-        var highlightedNodeId;
-        var highlightedNodeType;
-        if (Utils.isDefined(data.highlightedVertex) && data.highlightedVertex.length > 0) {
-            var highlightedNodeAttr = data.highlightedVertex.split("-");
-            if (highlightedNodeAttr.length === 2) {
-                highlightedNodeType = highlightedNodeAttr[0];
-                highlightedNodeId = parseInt(highlightedNodeAttr[1], 10);
-            }
-        }
-        if (Utils.isDefined(data.highlightedEdge) && data.highlightedEdge.length > 0) {
-            var highlightedEdgeId = parseInt(data.highlightedEdge, 10);
-        }
+		var highlightedNodeId;
+		var highlightedNodeType;
+		if (Utils.isDefined(data.highlightedVertex) && data.highlightedVertex.length > 0) {
+			var highlightedNodeAttr = data.highlightedVertex.split("-");
+			if (highlightedNodeAttr.length === 2) {
+				highlightedNodeType = highlightedNodeAttr[0];
+				highlightedNodeId = parseInt(highlightedNodeAttr[1], 10);
+			}
+		}
+		if (Utils.isDefined(data.highlightedEdge) && data.highlightedEdge.length > 0) {
+			var highlightedEdgeId = parseInt(data.highlightedEdge, 10);
+		}
 
-        var highlightedNode = undefined;
-        var highlightedEdge = undefined;
+		var highlightedNode = undefined;
+		var highlightedEdge = undefined;
 
-        // construct vertices
+		// construct vertices
 		var vertexMap = {};
 		data.vertices.forEach(function(component) {
 			var vertex = new Vertex(component);
@@ -56,14 +56,14 @@ function GraphLoader() {
 			var position = component.position;
 
 			if (position === null || Utils.isUndefined(position)) {
-                // set random
-                vertex.setPosition(new Coordinates(
-                    Math.floor(Math.random() * canvasSize),
-                    Math.floor(Math.random() * canvasSize),
-                ));
-
-            } else {
-                vertex.setPosition(new Coordinates(position.x, position.y));
+				// set random
+				vertex.position = new Coordinates(
+					Math.floor(Math.random() * canvasSize),
+					Math.floor(Math.random() * canvasSize),
+				);
+
+			} else {
+				vertex.position = new Coordinates(position.x, position.y);
 			}
 
 			app.nodeList.push(vertex);
@@ -111,7 +111,7 @@ function GraphLoader() {
 
 		// find unconnected vertices
 		app.vertexList.filter(function(vertex) {
-			return vertex.isUnconnected();
+			return vertex.isUnconnected;
 		}).forEach(function(vertex) {
 			vertex.exclude();
 			app.sidebarComponent.unconnectedNodeListComponent.add(vertex);
@@ -128,15 +128,15 @@ function GraphLoader() {
 			// position
 			var position = component.position;
 			if (position === null || Utils.isUndefined(position)) {
-                // set random
-                group.setPosition(new Coordinates(
-                    Math.floor(Math.random() * canvasSize),
-                    Math.floor(Math.random() * canvasSize),
-                ));
-
-            } else {
-                group.setPosition(new Coordinates(position.x, position.y));
-            }
+				// set random
+				group.position = new Coordinates(
+					Math.floor(Math.random() * canvasSize),
+					Math.floor(Math.random() * canvasSize),
+				);
+
+			} else {
+				group.position = new Coordinates(position.x, position.y);
+			}
 
 			// vertices
 			app.vertexList.filter(function(vertex) {
@@ -148,7 +148,7 @@ function GraphLoader() {
 			app.nodeList.push(group);
 			app.groupList.push(group);
 
-			app.viewportComponent.addGroup(group);
+			app.viewportComponent.addNode(group);
 		});
 
 		// exclude nodes
@@ -173,7 +173,7 @@ function GraphLoader() {
 			});
 
 			if (Utils.isDefined(node)) {
-				node.exclude(excludedNode.isIconsDisplayed);
+				node.exclude();
 
 				app.sidebarComponent.excludedNodeListComponent.add(node);
 			}
@@ -186,11 +186,14 @@ function GraphLoader() {
 		app.sidebarComponent.statusBarComponent.componentCount = data.vertices.length;
 
 		if (Utils.isDefined(highlightedEdge)) {
-            highlightedEdge.setHighlighted(true);
-            highlightedEdge.getFrom().setHighlighted(true);
-            highlightedEdge.getTo().setHighlighted(true);
-        }
-		if (Utils.isDefined(highlightedNode)) highlightedNode.setHighlightedWithNeighbours(true);
+			highlightedEdge.isHighlighted = true;
+			highlightedEdge.from.isHighlighted = true;
+			highlightedEdge.to.isHighlighted = true;
+		}
+
+		if (Utils.isDefined(highlightedNode)) {
+			highlightedNode.highlightWithNeighbours(true);
+		}
 	};
 
 }
\ No newline at end of file
diff --git a/sources/src/main/webapp/showGraph.jsp b/sources/src/main/webapp/showGraph.jsp
index fb85492..59076b5 100644
--- a/sources/src/main/webapp/showGraph.jsp
+++ b/sources/src/main/webapp/showGraph.jsp
@@ -37,6 +37,7 @@
 		<script src="js/components/generic/modalWindow.js"></script>
 		<script src="js/components/generic/popover.js"></script>
 		<script src="js/components/generic/popup.js"></script>
+		<script src="js/components/node.js"></script>
 		<script src="js/components/attribute.js"></script>
 		<script src="js/components/edge.js"></script>
 		<script src="js/components/edgePopover.js"></script>
@@ -47,6 +48,7 @@
 		<script src="js/components/loginPopup.js"></script>
 		<script src="js/components/minimap.js"></script>
 		<script src="js/components/navbar.js"></script>
+		<script src="js/components/nodeSymbolList.js"></script>
 		<script src="js/components/registerPopup.js"></script>
 		<script src="js/components/saveDiagramModalWindow.js"></script>
 		<script src="js/components/sidebar.js"></script>
@@ -57,7 +59,6 @@
 		<script src="js/components/vertex.js"></script>
 		<script src="js/components/vertexContextMenuList.js"></script>
 		<script src="js/components/vertexPopover.js"></script>
-		<script src="js/components/vertexSymbolList.js"></script>
 		<script src="js/components/viewport.js"></script>
 
 		<script src="js/errors/httpError.js"></script>
