blob: 1493ae1195a250d4230b9da92e07c85fe6783c0f [file] [log] [blame]
Javier López-Contreras6d1d72d2018-12-27 23:17:18 +01001// *********** HERE STARTS circle-mode.js *************
2
3window.addEventListener("load", initCircleMode);
4
5circleMode = false;
6
7function initCircleMode() {
8 document.querySelector("#circle-mode").addEventListener('click', function() {
9 if(circleMode) {
10 circleMode = false;
11 document.querySelector("#circle-mode i").innerText = "trip_origin";
12
13 s.graph.nodes().forEach(function(n) {
14 n.x = n.originalX;
15 n.y = n.originalY;
16 n.size = 10;
17 });
18
19 s.refresh();
20
21 }
22 else {
23 circleMode = true;
24 document.querySelector("#circle-mode i").innerText = "shuffle";
25
26 s.graph.nodes().forEach(function(n) {
27 n.x = n.circleX;
28 n.y = n.circleY;
29 });
30
31 s.refresh();
32 }
33 });
34}
35
36function isInRect (x, y, rect) {
37 if (x < -10000 || x > 10000) return true;
38 if (y < -10000 || y > 10000) return true;
39
40 var ans = true;
41 var c = crossProd (rect[0], rect[1], x, y);
42
43 for(var i=1; i<4; i++) {
44 var temp = crossProd (rect[i], rect[(i+1)%4], x, y);
45 if (c*temp < 0) ans = false;
46 }
47 return ans;
48}
49
50function crossProd(r1, r2, x, y) {
51 return r1[0]*r2[1] + r2[0]*y + x*r1[1] - r1[0]*y - r2[0]*r1[1] - x*r2[1];
52}
53
54
55// *********** HERE STARTS graf.js *************
56
57window.addEventListener("load", initGraf);
58
59// s is the sigma graph
60// graf is the JSON graph
61var s, graf;
62
63// query dario JSON for the graph information
64function xhr(method, url, params, callback) {
65 var http = new XMLHttpRequest();
66 if (method == "POST") {
67 http.open(method, url, true);
68 } else {
69 if (params != "") {
70 http.open(method, url+"?"+params, true);
71 } else {
72 http.open(method, url, true);
73 }
74 }
75 http.onload = function() {
76 if(this.status != 200) {
77 console.warn("Attention, status code "+this.status+" when loading via xhr url "+url);
78 }
79 callback(this.responseText, this.status);
80 };
81 if (method == "POST") {
82 http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
83 http.send(params);
84 } else {
85 http.send();
86 }
87}
88
89
90function initGraf() {
91 // create new methods for sigma library
92 updateSigma();
93
94 // create graf, s is the sigma graf
95 s = new sigma({
96 renderers: [{
97 container: "graf",
98 type: "webgl"
99 }],
100 settings: {
101 defaultEdgeColor: "#fff",
102 edgeColor: "default",
103 defaultLabelColor: "#fff",
104 autoRescale: false,
105 zoomMax: 30,
106 // enableEdgeHovering: true,
107 font: "Roboto",
108 labelThreshold: 5
109 }
110 });
111
112
113 // query for JSON for graph data
114 xhr("GET", "api.php", "action=getgraf", function(responseText, status) {
115 // graf is the JSON data
116 graf = JSON.parse(responseText);
117
118 // does graf.nodes have a size attribute?
119 var rectBorrar = [[0,0], [0,0], [0,0], [0,0]];
120 for (var i in graf.nodes) {
121 if (graf.nodes[i].name == "Erase") rectBorrar[0] = [ graf.nodes[i].x , graf.nodes[i].y ];
122 if (graf.nodes[i].name == "Borrar") rectBorrar[1] = [ graf.nodes[i].x , graf.nodes[i].y ];
123 if (graf.nodes[i].name == "Esborrar") rectBorrar[2] = [ graf.nodes[i].x , graf.nodes[i].y ];
124 if (graf.nodes[i].name == "Delete") rectBorrar[3] = [ graf.nodes[i].x , graf.nodes[i].y ];
125 }
126
127 var sizegraf = 0;
128 for (var i in graf.nodes) {
129 if ( isInRect(graf.nodes[i].x, graf.nodes[i].y, rectBorrar) ) continue;
130 sizegraf++;
131 }
132 var nnode = 0;
133 for (var i in graf.nodes) {
134 var ncolor = null;
135
136 if(graf.nodes[i].sex =="F") ncolor = "#d61c08";
137 else if(graf.nodes[i].sex == "M") ncolor = "#0159aa";
138 else ncolor = "#0ca80a";
139
140 // post-processing for year corrections
141 if(1970 < graf.nodes[i].year && graf.nodes[i].year < 2004) graf.nodes[i].year += 18;
142
143 var newX = 5000*Math.cos( 2*Math.PI*nnode/sizegraf );
144 var newY = 5000*Math.sin( 2*Math.PI*nnode/sizegraf );
145
146 if (isInRect(graf.nodes[i].x, graf.nodes[i].y, rectBorrar) ) continue;
147
148 s.graph.addNode({
149 // we add color, originalColor, size, originalX..Y, circleX..Y atributes
150 id: graf.nodes[i].id,
151 year: graf.nodes[i].year,
152 sex: graf.nodes[i].sex,
153 label: graf.nodes[i].name,
154 x: graf.nodes[i].x,
155 y: graf.nodes[i].y,
156 circleX: newX,
157 circleY: newY,
158 originalX: graf.nodes[i].x,
159 originalY: graf.nodes[i].y,
160 size: 10,
161 color: ncolor,
162 originalColor: ncolor
163 });
164 nnode++;
165
166 }
167
168 for (var i in graf.edges) {
169 if (isInRect(graf.nodes[graf.edges[i].a].x, graf.nodes[graf.edges[i].a].y, rectBorrar)) continue;
170 if (isInRect(graf.nodes[graf.edges[i].b].x, graf.nodes[graf.edges[i].b].y, rectBorrar)) continue;
171
172 s.graph.addEdge({
173 id: i,
174 source: graf.edges[i].a,
175 target: graf.edges[i].b,
176 size: Math.min(4, Math.max((7/(2*Math.pow(20, 2)))*Math.pow(graf.edges[i].votes, 2) + 1/2, 0.5))
177 });
178
179 }
180
181 s.bind('clickNode', function(e) {
182 var nodeId = e.data.node.id,
183 toKeep = s.graph.neighbors(nodeId);
184 // toKeep[nodeId] = e.data.node;
185
186
187 s.graph.nodes().forEach(function(n) {
188 if (toKeep[n.id] || n.id == nodeId) {
189 n.color = n.originalColor;
190 } else {
191 n.color = '#333';
192 }
193 });
194
195 s.graph.edges().forEach(function(e) {
196 if ((e.source == nodeId || e.target == nodeId) && (toKeep[e.source] || toKeep[e.target])) {
197 e.color = '#fff';
198 } else {
199 e.color = '#333';
200 }
201 });
202
203 if (circleMode) {
204 s.graph.nodes().forEach(function (n) {
205 n.x = n.circleX;
206 n.y = n.circleY;
207 n.size = 10;
208 });
209
210 e.data.node.x = 0;
211 e.data.node.y = 0;
212 e.data.node.size = 30;
213 }
214
215 s.refresh();
216
217 dialog.show(nodeId, toKeep);
218 });
219
220
221 s.refresh();
222 initSearchBar();
223
224 autocomplete(document.querySelector("#search-input"), graf.nodes, "search");
225 });
226}
227
228function updateSigma() {
229 // returns set of neighouts
230 sigma.classes.graph.addMethod("neighbors", function(nodeId) {
231 var k,
232 neighbors = {},
233 index = this.allNeighborsIndex[nodeId] || [];
234
235 for (k in index) {
236 neighbors[k] = this.nodesIndex[k];
237 }
238
239 return neighbors;
240 });
241
242 // returns number of neighbours from a set of years
243 sigma.classes.graph.addMethod("numNeighborsFromYears", function(nodeId, showYearsCopy) {
244 var k,
245 neighbors = 0,
246 index = this.allNeighborsIndex[nodeId] || [];
247
248 for (k in index) {
249 if(this.nodesIndex){
250 if (showYearsCopy.has("" + this.nodesIndex[k].year)) neighbors++;
251 else if (this.nodesIndex[k].year == 0) neighbors++;
252 }
253 }
254
255 return neighbors;
256 });
257}
258
259
260// *********** HERE STARTS limit-years.js *************
261
262window.addEventListener("load", addYearList);
263
264var limitYears = false;
265var showYears = new Set();
266
267function repaint() {
268 //targetYear: graf.nodes[e.source].year,
269 if(limitYears) {
270 var added = new Set();
271
272 s.graph.nodes().forEach(function(n) {
273 var numNeig = s.graph.numNeighborsFromYears(n.id, showYears);
274
275 if ((n.year == 0 && (n.sex == 'F' || n.sex == 'M') )
276 || numNeig == 0
277 || (!showYears.has("" + n.year) && (n.year != 0) )) {
278 n.hidden = true;
279 }
280 else {
281 n.hidden = false;
282 added.add(n.id);
283 }
284 });
285
286 s.graph.edges().forEach(function(e) {
287 if(!added.has(e.source) && !added.has(e.target)){
288 e.hidden = true;
289 }
290 else e.hidden = false;
291 });
292 }
293 else {
294 s.graph.nodes().forEach(function(n) {
295 n.hidden = false;
296 });
297
298 s.graph.edges().forEach(function(e) {
299 e.hidden = false;
300 });
301 }
302}
303
304function altYearList() {
305 var yearlist = document.querySelector("#year-list");
306
307 if(yearlist.style.display == "none"){
308 yearlist.style.display = "block";
309 document.querySelector("#settings i").innerText = "close";
310 yearLimits = true;
311 }
312 else{
313 yearlist.style.display = "none";
314 document.querySelector("#settings i").innerText = "settings";
315 yearLimits = true;
316 }
317}
318
319function addYearList() {
320 var ylistspan = document.querySelector("#year-list-span")
321 for(var year=2006; year<2019; year++) {
322 var yin = document.createElement("input");
323 yin.type = "checkbox";
324 yin.class = "mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored";
325 yin.name = "" + year;
326 yin.addEventListener("change", function(){
327 limitYears = true;
328
329 if(this.checked) {
330 showYears.add(this.name);
331 }
332 else {
333 showYears.delete(this.name);
334 }
335
336 if(showYears.size == 0) limitYears = false;
337
338 repaint();
339
340 s.refresh();
341 });
342
343 var lab = document.createElement("label");
344 lab.innerHTML = "" + year + "<br>";
345
346 ylistspan.appendChild(yin);
347 ylistspan.appendChild(lab);
348 }
349
350 document.querySelector("#settings").addEventListener("click", altYearList);
351}
352
353// *********** HERE STARTS search-bar.js *************
354
355
356function altSearchBar() {
357 if (document.querySelector(".md-google-search__metacontainer").style.display == "none") {
358 document.querySelector(".md-google-search__metacontainer").style.display = "block";
359 document.querySelector("#search i").innerText = "fullscreen";
360 } else {
361 document.querySelector(".md-google-search__metacontainer").style.display = "none";
362 document.querySelector(".autocomplete-container").style.display = "none";
363 document.querySelector("#search i").innerText = "search";
364 }
365}
366
367function initSearchBar() {
368 document.querySelector("#search").addEventListener("click", altSearchBar);
369 if (window.innerWidth > 700) altSearchBar();
370}
371// *********** HERE STARTS dialog.js *************
372
373window.addEventListener("load", initDialog);
374
375var dialog = {
376 fill: function(data, text, html=false) {
377 var el = document.querySelectorAll("*[data-fill=\""+data+"\"]");
378 for (var i in el) {
379 if (html === true) {
380 el[i].innerHTML = text;
381 } else {
382 el[i].innerText = text;
383 }
384 }
385 },
386 show: function(id, neighbors) {
387 var neighbors = Object.values(neighbors);
388
389 this.fill("name", graf.nodes[id].name);
390 this.fill("year", graf.nodes[id].year);
391 this.fill("sex", graf.nodes[id].sex);
392 this.fill("id", "#"+id);
393 this.fill("n-edges", neighbors.length);
394
395 var list = "";
396 neighbors.forEach(function (a) {
397 list += "<li><b>"+graf.nodes[id].name+" - "+a.label+":</b> "+(graf.edges[id+"_"+a.id] ? graf.edges[id+"_"+a.id].votes : graf.edges[a.id+"_"+id].votes)+" vots</li>";
398 });
399 this.fill("edges", list, true);
400
401 if (window.innerWidth > 700) {
402 document.querySelector("#dialog").style.display = "block";
403 document.querySelector("#backdrop-container").style.display = "block";
404 } else {
405 document.querySelector("#summary-dialog").style.display = "block";
406 }
407 },
408 close: function() {
409 document.querySelector("#dialog").style.display = "none";
410 document.querySelector("#summary-dialog").style.display = "none";
411 document.querySelector("#backdrop-container").style.display = "none";
412
413 s.graph.nodes().forEach(function(n) {
414 n.color = n.originalColor;
415 });
416
417 s.graph.edges().forEach(function(e) {
418 e.color = e.originalColor;
419 });
420
421 if(circleMode) {
422 s.graph.nodes().forEach(function (n) {
423 n.x = n.circleX;
424 n.y = n.circleY;
425 n.size = 10;
426 });
427 }
428 else {
429 s.graph.nodes().forEach(function (n) {
430 n.x = n.originalX;
431 n.y = n.originalY;
432 n.size = 10;
433 });
434 }
435 s.refresh();
436
437 },
438 max: function() {
439 document.querySelector("#summary-dialog").style.display = "none";
440 document.querySelector("#dialog").style.display = "block";
441 },
442 min: function() {
443 document.querySelector("#dialog").style.display = "none";
444 document.querySelector("#summary-dialog").style.display = "block";
445 }
446};
447
448
449function initDialog() {
450 document.querySelector("#quit-dialog").addEventListener("click", dialog.close);
451 document.querySelector("#quit2-dialog").addEventListener("click", dialog.close);
452 document.querySelector("#max-dialog").addEventListener("click", dialog.max);
453 document.querySelector("#min-dialog").addEventListener("click", dialog.min);
454}
455
456// *********** HERE STARTS camera.js *************
457
458
459window.addEventListener('load', initCamera);
460
461function cameraGoto(nodeX, nodeY) {
462 sigma.misc.animation.camera( s.camera,
463 { x: nodeX, y: nodeY, ratio: 1 },
464 { duration: s.settings('animationsTime') || 300 }
465 );
466}
467
468function is_touch_device() {
469 var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
470 var mq = function(query) {
471 return window.matchMedia(query).matches;
472 }
473
474 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
475 return true;
476 }
477
478 // include the 'heartz' as a way to have a non matching MQ to help terminate the join
479 // https://git.io/vznFH
480 var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
481 return mq(query);
482}
483
484function initCamera() {
485
486 if(!is_touch_device()) {
487
488 document.querySelector("#zoomin").addEventListener("click", function() {
489 s.camera.goTo({
490 ratio: Math.max(s.camera.settings("zoomMin"), s.camera.ratio / Math.sqrt(2))
491 });
492 });
493
494 document.querySelector("#zoomout").addEventListener("click", function() {
495 s.camera.goTo({
496 ratio: Math.min(s.camera.settings("zoomMax"), s.camera.ratio * Math.sqrt(2))
497 });
498 });
499 }
500 else{
501 document.querySelector("#zoomin").style.display = "none";
502 document.querySelector("#zoomout").style.display = "none";
503
504 document.querySelector("#circle-mode").style.bottom = "110px";
505 document.querySelector("#settings").style.bottom = "60px";
506 document.querySelector("#search").style.bottom = "10px";
507 }
508}
509
510// *********** HERE STARTS easter-egg.js *************
511
512window.addEventListener("load", initEasterEgg);
513
514var seq = [38, 38, 40, 40, 37, 39, 37, 39, 65, 66, 13];
515var cur = 0;
516
517function justdoit() {
518 s.graph.nodes().forEach(function(n) {
519 switch(n.color) {
520 case "#d61c08":
521 n.color = "#0159aa";
522 break;
523
524 case "#0159aa":
525 n.color = "#0ca80a";
526 break;
527
528 case "#0ca80a":
529 n.color = "#d61c08";
530 break;
531 }
532 });
533
534 s.refresh();
535 setTimeout(justdoit, 333);
536}
537
538
539function initEasterEgg() {
540 document.addEventListener("keydown", function() {
541 if (event.key == "f" && event.target.getAttribute("id") != "search-input") altSearchBar();
542 if (event.which == seq[cur]) {
543 if (cur < seq.length) {
544 ++cur;
545 if (cur == seq.length) {
546 justdoit();
547 }
548 }
549 } else cur = 0;
550 });
551}