Projekt

Obecné

Profil

Stáhnout (9.34 KB) Statistiky
| Větev: | Tag: | Revize:
1

    
2
/**
3
* Representation of EFP interface functionality.
4
*/
5
var EFPs = {
6
	elementName : "#EFPselector",
7
	graph : null,
8
	// map {EFP name, EFP ID}
9
	efpsIds : {},
10
	// array [EFP ID, edge ID]
11
	efpsStruct : new Array(),
12
	currentEfpSeclected : null,
13
	minDiameter : null,
14
	maxDiameter : null,
15
	// left - required - misticka
16
	minEfpsValuesLeft : {},
17
	maxEfpsValuesLeft : {},
18
	// right - provided - lizatko
19
	minEfpsValuesRight : {},
20
	maxEfpsValuesRight : {},
21
	
22
	/**
23
	* Init.
24
	*
25
	* @param graph
26
	*/
27
	init : function(graph) {
28
		this.graph = graph;
29
		this.minDiameter = GraphManager.efpMinIntDiameter;
30
		this.maxDiameter = GraphManager.efpMaxIntDiameter;
31
		
32
		// min is really min
33
		if (parseFloat(this.minDiameter) > parseFloat(this.maxDiameter)) {
34
			var tmp = this.minDiameter;
35
			this.minDiameter = this.maxDiameter;
36
			this.maxDiameter = tmp;
37
		}
38
		
39
		this.currentEfpSeclected = $(this.elementName).val();
40
		this.associateEfpsToEdgeIds();
41
	},
42
	
43
	/**
44
	* Make cached association EFP;edgeID.
45
	*/
46
	associateEfpsToEdgeIds : function() {
47
		// array of EFPs
48
		var efpsCount = $(this.elementName + " option").length - 1;
49
		
50
		var tmp = 0;
51
		
52
		// hack for "this" when entering to
53
		var ids = this.efpsIds;
54
		var minEfpsLeft = this.minEfpsValuesLeft;
55
		var maxEfpsLeft = this.maxEfpsValuesLeft;
56
		var minEfpsRight = this.minEfpsValuesRight;
57
		var maxEfpsRight = this.maxEfpsValuesRight;
58
		
59
		// fill map
60
		$("#EFPselector option").each(function(e) {
61
			if ($(this).val() != "") {
62
				ids[$(this).val()] = tmp++;
63
				
64
				// init the min/max arrays
65
				minEfpsLeft[$(this).val()] = Number.MAX_VALUE;
66
				maxEfpsLeft[$(this).val()] = -Number.MAX_VALUE;
67
				
68
				minEfpsRight[$(this).val()] = Number.MAX_VALUE;
69
				maxEfpsRight[$(this).val()] = -Number.MAX_VALUE;
70
			}
71
		});
72
		
73
		for ( var i = 0; i < efpsCount; i++) {
74
			// efpsStruct[i].push(new Array());
75
			this.efpsStruct[i] = new Array();
76
		}
77
		
78
		// edges
79
		for (var i = 0; i < this.graph.edges.length; i++) {
80
			var features = this.graph.edges[i].features;
81
			
82
			// features
83
			for (var j = 0; j < features.length; j++) {
84
				var efps = features[j].efps;
85
				
86
				// efps
87
				for (var k = 0; k < efps.length; k++) {
88
					if (efps[k].efpName != "") {
89
						var tmpEfpId = this.efpsIds[efps[k].efpName];
90
						var tmpEdgeId = this.graph.edges[i].id;
91
						
92
						// assign edge to the efps
93
						if (this.efpsStruct[tmpEfpId].indexOf(tmpEdgeId) < 0) {
94
							// check if the EFP values are really valid numbers
95
							if(!isNaN(efps[k].leftEfpValue) && !isNaN(efps[k].rightEfpValue)) {
96
								this.efpsStruct[tmpEfpId].push(tmpEdgeId);;
97
							}
98
						}
99
						
100
						/* LEFT numeric values */
101
						if (!isNaN(efps[k].leftEfpValue)) {
102
							// check and set min
103
							if (parseFloat(efps[k].leftEfpValue) < parseFloat(this.minEfpsValuesLeft[efps[k].efpName])) {
104
								this.minEfpsValuesLeft[efps[k].efpName] = efps[k].leftEfpValue;
105
							}
106
							
107
							// check and set max
108
							if (parseFloat(efps[k].leftEfpValue) > parseFloat(this.maxEfpsValuesLeft[efps[k].efpName])) {
109
								this.maxEfpsValuesLeft[efps[k].efpName] = efps[k].leftEfpValue;
110
							}
111
						}
112
						
113
						/* RIGHT numeric values */
114
						if (!isNaN(efps[k].rightEfpValue)) {
115
							// check and set min
116
							if (parseFloat(efps[k].rightEfpValue) < parseFloat(this.minEfpsValuesRight[efps[k].efpName])) {
117
								this.minEfpsValuesRight[efps[k].efpName] = efps[k].rightEfpValue;
118
							}
119
							
120
							// check and set max
121
							if (parseFloat(efps[k].rightEfpValue) > parseFloat(this.maxEfpsValuesRight[efps[k].efpName])) {
122
								this.maxEfpsValuesRight[efps[k].efpName] = efps[k].rightEfpValue;
123
							}
124
						}
125
					}
126
				}
127
			}
128
		}
129
	},
130
	
131
	/**
132
	* Triggered after a change of selected EFP.
133
	*
134
	* @param element
135
	*/
136
	recalculate : function(element) {
137
		var efpName = $(element).val();
138
		
139
		// empty selected => reset
140
		if (efpName == "") {
141
			this.changeEdges(this.currentEfpSeclected, true);
142
			
143
			this.currentEfpSeclected = efpName;
144
			
145
			return;
146
		}
147
		
148
		// is already empty => no need for a reset
149
		if (this.currentEfpSeclected != "") {
150
			this.changeEdges(this.currentEfpSeclected, true);
151
		}
152
		
153
		this.changeEdges(efpName, false);
154
		
155
		// set new selected value
156
		this.currentEfpSeclected = efpName;
157
	},
158
	
159
	/**
160
	*
161
	* Calculate average of all selected EFPs on given edge.
162
	*
163
	* @param efpName
164
	* @param edge
165
	* @returns {Array}
166
	*/
167
	calculateEfpAvg : function(efpName, edge) {
168
		var foundEFps = 0;
169
		var avgStructLeftRight = [Number(0),Number(0)];
170
		
171
		// get the EFP and its values
172
		for(var j = 0; j < edge.features.length; j++) {
173
			var tmpEdgeFeature = edge.features[j];
174
			
175
			for(var k = 0; k < tmpEdgeFeature.efps.length; k++) {
176
				var tmpEdgeFeatureEfp = tmpEdgeFeature.efps[k];
177
				
178
				// set the EFP if matched and numeric
179
				if(tmpEdgeFeatureEfp.efpName == efpName){
180
					if(!isNaN(tmpEdgeFeatureEfp.leftEfpValue) && !isNaN(tmpEdgeFeatureEfp.rightEfpValue)) {
181
						foundEFps++;
182
						
183
						avgStructLeftRight[0] += parseFloat(tmpEdgeFeatureEfp.leftEfpValue);
184
						avgStructLeftRight[0] /= foundEFps;
185
						
186
						avgStructLeftRight[1] += parseFloat(tmpEdgeFeatureEfp.rightEfpValue);
187
						avgStructLeftRight[1] /= foundEFps;
188
						}else {
189
						// found some non-numeric -> error state
190
						return null;
191
					}
192
				}
193
			}
194
		}
195
		
196
		return avgStructLeftRight;
197
	},
198
	
199
	/**
200
	*
201
	* @param efpName
202
	* @param reset
203
	*/
204
	changeEdges : function(efpName, reset) {
205
		var diameterLeft = null, diameterRight = this.minDiameter;
206
		var tmpEfpId = this.efpsIds[efpName];
207
		
208
		var singleSelectedEfpInDiagram = false;
209
		
210
		var kLeft = null, qLeft = null, kRight = null, qRight = null;
211
		
212
		// [minDiameter][maxDiameter] of chosen EFP
213
		var minMaxDiameterOfEfpLeft = [this.minEfpsValuesLeft[efpName], this.maxEfpsValuesLeft[efpName]];
214
		var minMaxDiameterOfEfpRight = [this.minEfpsValuesRight[efpName], this.maxEfpsValuesRight[efpName]];
215
		
216
		// check if we won't run into the DIV 0
217
		if((minMaxDiameterOfEfpLeft[0] - minMaxDiameterOfEfpLeft[1]) == 0 || (minMaxDiameterOfEfpRight[0] - minMaxDiameterOfEfpRight[1]) == 0){
218
			singleSelectedEfpInDiagram = true;
219
			}else {
220
			// y = k * x + q
221
			kLeft = (this.minDiameter - this.maxDiameter) / (minMaxDiameterOfEfpLeft[0] - minMaxDiameterOfEfpLeft[1]);
222
			qLeft = this.maxDiameter - kLeft * minMaxDiameterOfEfpLeft[1];
223
			
224
			kRight = (this.minDiameter - this.maxDiameter) / (minMaxDiameterOfEfpRight[0] - minMaxDiameterOfEfpRight[1]);
225
			qRight = this.maxDiameter - kRight * minMaxDiameterOfEfpRight[1];
226
		}
227
		
228
		// iterates through all edges which have the selected EFP
229
		for (var i = 0; i < this.efpsStruct[tmpEfpId].length; i++) {
230
			var tmpEdgeId = this.efpsStruct[tmpEfpId][i];
231
			diameterLeft = this.minDiameter;
232
			diameterRight = this.minDiameter;
233
			
234
			// calculate avg
235
			var selectedEfpAvg = this.calculateEfpAvg(efpName, this.graph.edges[tmpEdgeId - 1]);
236
			
237
			if (reset) {
238
				// remove tick symbol
239
				var lolliToRemove = document.getElementById("lollipop-tick" + tmpEdgeId);
240
				
241
				if(lolliToRemove != null) {
242
					var lolliParent = lolliToRemove.parentNode;
243
					lolliParent.removeChild(lolliToRemove);
244
				}
245
				
246
				}else {
247
				if(selectedEfpAvg != null && !singleSelectedEfpInDiagram) {
248
					// calculate the size - linear scaling
249
					diameterLeft = kLeft * selectedEfpAvg[0] + qLeft;
250
					diameterRight = kRight * selectedEfpAvg[1] + qRight;
251
				}
252
			}
253
			
254
			// set circle radius
255
			$(".lollipop[data-edgeid='" + tmpEdgeId + "'] circle").attr("r", diameterRight / 2);
256
			
257
			
258
			if (!reset) {
259
				if(selectedEfpAvg != null) {
260
					// set path dimensions
261
					var yDistance = diameterLeft / 2 + 4;
262
					// X distance of half-circle's "draggers" should be equal to 2/3 of circle diameter (eg. circle diametr=24, draggers=16)
263
					var xDistance = yDistance * 4 / 3;
264
					var distanceOffsetToRight = diameterRight / 2;
265
					// add distance between lolli and circle
266
					var dString = 'M' + distanceOffsetToRight + ',' + -yDistance + ' C' + (xDistance + distanceOffsetToRight) + ',' + -yDistance + ' ' + (xDistance + distanceOffsetToRight) + ',' + yDistance + ' ' + distanceOffsetToRight + ',' + yDistance;
267
					
268
					$(".lollipop[data-edgeid='" + tmpEdgeId + "'] path").first().attr("d", dString);
269
				}
270
				
271
				// add tick symbol if needed
272
				if(this.graph.edges[tmpEdgeId-1].edgeStatusOk) {
273
					// create tick element
274
					var tick = document.createElementNS('http://www.w3.org/2000/svg','path');
275
					tick.setAttribute('class','SamplePath');
276
					tick.setAttribute('id', 'lollipop-tick' + tmpEdgeId);
277
					tick.setAttribute('d','M-4,-2 C-3,12 1,0 5,-7');
278
					tick.setAttribute('stroke','green');
279
					
280
					// get the angle
281
					var xforms = $(".lollipop[data-edgeid='" + tmpEdgeId + "']").attr('transform');
282
					var parts  = /rotate\(\s*([^\s,)]+)[ ,]([^\s,)]+)[ ,]([^\s,)]+)/.exec(xforms);
283
					var angle = parts[1];
284
					
285
					// prevent rotation
286
					tick.setAttribute('transform','rotate(' + (-angle) + ',0,0) translate(0,0)');
287
					
288
					// add the tick
289
					var lollipop = $(".lollipop[data-edgeid='" + tmpEdgeId + "']")[0];
290
					lollipop.appendChild(tick);
291
				}
292
				}else {
293
				// set path dimensions
294
				var yDistance = diameterLeft / 2 + 4;
295
				// X distance of half-circle's "draggers" should be equal to 2/3 of circle diameter (eg. circle diametr=24, draggers=16)
296
				var xDistance = yDistance * 4 / 3;
297
				var dString = 'M0,' + -yDistance + ' C' + xDistance + ',' + -yDistance + ' ' + xDistance + ',' + yDistance + ' 0,' + yDistance;
298
				
299
				$(".lollipop[data-edgeid='" + tmpEdgeId + "'] path").first().attr("d", dString);
300
			}
301
		}
302
		
303
	},
304
	
305
};
(4-4/19)