Projekt

Obecné

Profil

Stáhnout (5.05 KB) Statistiky
| Větev: | Tag: | Revize:
1 1e2b2c27 Tomáš Šimandl
/**
2
 * @constructor
3
 */
4
function ForceDirected() {
5
6
	var forceField = {};
7
	var canvas = 0;
8
9
	// parametry layoutu
10
	var inumber = 30; // pocet iteraci; default 300
11
	var inumberClick = 20; // pocet iteraci u tlacitka
12
	var repulsiveStrength = 400; // odpudiva sila (prima umera); default 450
13
	var attractiveStrength = 510; // pritazliva sila (neprima umera, nesmi byt 0); default 110
14
	var dampeningEffect = 1000; // tlumeni sily (nesmi byt 0); default 200
15
	var borderRatio = 1; // hranice layoutu (cislo kterym se deli velikost canvasu)
16
	// tahle funkce se mi nelibi, je treba to vyresit jinak, nici to layout (nechat na 1)
17
18
	/**
19
	 * Force directed layout for visible components.
20
	 */
21
	this.run = function() {
22
		var border = canvas / borderRatio;
23
24
		var visibleNodes = app.viewportComponent.getNodeList(),
25
			otherVisibleNodes = [];
26
27
		var i = 0,
28
			j = 0;
29
30
		for (i = 0; i < visibleNodes.length; i++) {
31
			forceField[getId(visibleNodes[i])] = [0, 0];
32
		}
33
34
		// calculate repulsive force
35
		for (i = 0; i < visibleNodes.length; i++) {
36
			var currNode = visibleNodes[i];
37
38
			// other nodes
39
			for (var j = 0; j < visibleNodes.length; j++){
40
				otherVisibleNodes[j] = visibleNodes[j];
41
			}
42
			otherVisibleNodes.splice(i, 1);
43
44
			// iterate over other nodes
45
			for (j = 0; j < otherVisibleNodes.length; j++) {
46
				var otherNode = otherVisibleNodes[j];
47
48
				var currPosition = currNode.getPosition();
49
				var otherPosition = otherNode.getPosition();
50
51
				// calculate force
52
				var x = currPosition.x - otherPosition.x;
53
				var y = currPosition.y - otherPosition.y;
54
				
55
				var sum = Math.pow(x, 2) + Math.pow(y, 2);
56
				var distance = Math.sqrt(sum);
57
58
				if (distance !== 0) {
59
					forceField[getId(currNode)][0] += Math.floor(x * (repulsiveStrength / distance));
60
					forceField[getId(currNode)][1] += Math.floor(y * (repulsiveStrength / distance));
61
				}
62
			}
63
		}
64
65
		// calculate attractive forces
66
		for (i = 0; i < visibleNodes.length; i++){
67
			var currNode = visibleNodes[i];
68
69
			for (j = 0; j < currNode.getInEdgeList().length; j++) {
70
				var otherNode = currNode.getInEdgeList()[j].getFrom();
71
72
				var currPosition = currNode.getPosition();
73
				var otherPosition = otherNode.getPosition();
74
75
				// calculate force
76
				var x = currPosition.x - otherPosition.x;
77
				var y = currPosition.y - otherPosition.y;
78
79
				var sum = Math.pow(x, 2) + Math.pow(y, 2);
80
				var distance = Math.sqrt(sum);
81
82
				forceField[getId(currNode)][0] += Math.round(-1 * x * (distance / attractiveStrength));
83
				forceField[getId(currNode)][1] += Math.round(-1 * y * (distance / attractiveStrength));
84
			}
85
86
			for (j = 0; j < currNode.getOutEdgeList().length; j++) {
87
				var otherNode = currNode.getOutEdgeList()[j].getTo();
88
89
				var currPosition = currNode.getPosition();
90
				var otherPosition = otherNode.getPosition();
91
92
				// calculate force
93
				var x = currPosition.x - otherPosition.x;
94
				var y = currPosition.y - otherPosition.y;
95
96
				var sum = Math.pow(x, 2) + Math.pow(y, 2);
97
				var distance = Math.sqrt(sum);
98
99
				forceField[getId(currNode)][0] += Math.round(-1 * x * (distance / attractiveStrength));
100
				forceField[getId(currNode)][1] += Math.round(-1 * y * (distance / attractiveStrength));
101
			}
102
		}
103
104
		// applying the force
105
		for (i = 0; i < visibleNodes.length; i++){
106
			var currNode = visibleNodes[i],
107
108
				halfCan = canvas / 2,
109
110
				deltaX = currNode.getPosition().x - halfCan,
111
				deltaY = currNode.getPosition().y - halfCan;
112
113
			// tohle drzi layout uprostred, chtelo by to vymyslet nejak lip, docela ho to kurvi
114
			/*
115
			 if (deltaX > 0) {
116
			 currNode.x = Math.min(currNode.getPosition().x, (canvas/2)+border);
117
			 } else {
118
			 currNode.x = Math.max(currNode.getPosition().x, (canvas/2)-border);
119
			 }
120
			 if (deltaY > 0) {
121
			 currNode.y = Math.min(currNode.getPosition().y, (canvas/2)+border);
122
			 } else {
123
			 currNode.y = Math.max(currNode.getPosition().y, (canvas/2)-border);
124
			 }
125
			 */
126
127
			// kolecko
128
			var dist = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, +2)),
129
				maxDist = Math.sqrt(Math.pow(border, 2) + Math.pow(border, +2));
130
131
			if (dist > maxDist){
132
				var ratio = maxDist / dist,
133
134
					newX = deltaX * ratio,
135
					newY = deltaY * ratio;
136
137
				currNode.x += newX - deltaX;
138
				currNode.y += newY - deltaY;
139
			}
140
141
			// force dampening
142
			var forceX = Math.floor(forceField[getId(currNode)][0] / dampeningEffect),
143
				forceY = Math.floor(forceField[getId(currNode)][1] / dampeningEffect);
144
145
			// adding a random effect
146
			/*
147
			 forceX += -3+Math.floor((Math.random()*6)+1);
148
			 forceY += -3+Math.floor((Math.random()*6)+1);
149
			 */
150
151
152
			// moving a component
153
			if (Math.abs(forceX) > 1 || Math.abs(forceY) > 1) {
154
				var coords = new Coordinates(
155
					currNode.getPosition().x + forceX,
156
					currNode.getPosition().y + forceY,
157
				);
158
159
				currNode.setPosition(coords);
160
				currNode.move(coords);
161
			}
162
		}
163
	};
164
165
	/**
166
	 * @param {(Vertex|Group)} node Graph node.
167
	 * @returns {string} Unique identifier of a graph node (group or vertex).
168
	 */
169
	function getId(node) {
170
		var prefix;
171
		if (node instanceof Vertex) {
172
			prefix = 'vertex-';
173
		} else if (node instanceof Group) {
174
			prefix = 'group-';
175
		} else {
176
			prefix = '';
177
		}
178
179
		return prefix + node.id;
180
	}
181
182
}