Add click listener to netjson viewer
[oonf.git] / files / netjson_viewer / netjson_view.js
1 /* global variables */
2 var visNodes, visEdges, visNetwork;
3 var autoupdate_timeout, force_layout_timeout;
4 var xmlhttp;
5 var last_json_data = null
6 var last_displayed_graph = null;
7
8 var settings = {
9     checkbox_autoupdate:     "",
10     checkbox_dynamic_layout: "",
11     checkbox_ipv4:           "",
12     div_showdata:            "",
13     
14     common_edge_postfix: "",
15     common_node_prefix: {
16         ipv4: "",
17         ipv6: "",
18     },
19     netjsonurl: null,
20     selectedColor: {
21         border:     '#2BE97C',
22         background: '#D2FFE5',
23         highlight: {
24             border: '#2BE97C',
25             background: '#D2FFE5',
26         },
27     },
28
29     autoupdate_interval: 5000,
30     ipv4:                true,
31     autoupdate:          true,
32     dynamic_layout:      true,
33 };
34
35 String.prototype.startsWith = function (pattern) {
36     if (this.length < pattern.length) {
37         return false;
38     }
39     return pattern == this.substring(0, pattern.length);
40 };
41
42 String.prototype.endsWith = function (pattern) {
43     if (this.length < pattern.length) {
44         return false;
45     }
46     return pattern == this.substring(this.length - pattern.length);
47 };
48
49 function init_network() {
50     var options = {
51     };
52
53     // create an array with nodes
54     visNodes = new vis.DataSet([], options);
55
56     // create an array with edges
57     visEdges = new vis.DataSet([], options);
58
59     // create a network
60     var container = document.getElementById("networkgraph");
61     var visData = {
62         nodes: visNodes,
63         edges: visEdges
64     };
65
66     options = {
67         edges: {
68             smooth: {
69                 type: 'continuous'
70             }
71         },
72         physics: settings["dynamic_layout"],
73     };
74     visNetwork = new vis.Network(container, visData, options);
75   
76     firstLookup = true;
77     
78     visNetwork.on("click", graph_element_clicked);
79 }
80
81 function layout_nodes(element) {
82     var jsonNodes = element.nodes;
83     var newIds = []
84     var oldIds = []
85     
86     var prefix = "";
87     if (settings["ipv4"]) {
88         prefix = settings["common_node_prefix"]["ipv4"];
89     }
90     else {
91         prefix = settings["common_node_prefix"]["ipv6"];
92     }
93     
94     /* add new nodes */
95     newIds = []
96     oldIds = visNodes.getIds()
97     for (ni = 0; ni < jsonNodes.length; ni++) {
98         var nId = jsonNodes[ni].id;
99         var nColor = null;
100         
101         var nLabel = nId;
102         if (nId.startsWith(prefix)) {
103             nLabel = nId.substring(prefix.length);
104         }
105                         
106         newIds.push(nId);
107         if (jsonNodes[ni].id == element.router_id) {
108             nColor = settings["selectedColor"];
109         }
110
111         if (!visNodes.get(nId)) {   
112             visNodes.add(
113                 {
114                     id:        nId,
115                     label:     nLabel,
116                     mass:      4,
117                     color:     nColor,
118                     reference: jsonNodes[ni],
119                 }
120             );
121         }
122     }
123     
124     /* remove old nodes */
125     for (ni = 0; ni < oldIds.length; ni++) {
126         if (newIds.indexOf(oldIds[ni]) == -1) {
127             visNodes.remove(oldIds[ni]);
128         }
129     }
130 }
131
132 function layout_edges(element) {
133     var jsonEdges = element.links;
134     var newIds = []
135     var oldIds = []
136     var undirectedEdges = {}
137     
138     /* calculate unidirectional edges */
139     newIds = []
140     oldIds = visEdges.getIds()
141     for (ei = 0; ei < jsonEdges.length; ei++) {
142         var eFrom = jsonEdges[ei].source;
143         var eTo = jsonEdges[ei].target;
144         
145         if (eFrom > eTo) {
146             var tmp = eTo;
147             eTo = eFrom;
148             eFrom = tmp;
149         }
150
151         var uuid = eFrom + "-" + eTo;
152         
153         var edge = undirectedEdges[uuid];
154         if (edge == null) {
155             edge = {
156                 uuid:      eFrom + "-" + eTo,
157                 from:      eFrom,
158                 to:        eTo,
159                 width:     1,
160                 arrows:    "",
161                 fromLabel: "-",
162                 toLabel:   "-",
163                 reference: jsonEdges[ei],
164             };
165             undirectedEdges[uuid] = edge;
166         };
167                 
168         newIds.push(edge.uuid);
169         
170         var eLabel =  jsonEdges[ei].weight.toString();
171         if (jsonEdges[ei].properties) {
172             if (jsonEdges[ei].properties["weight_txt"]) {
173                 eLabel = jsonEdges[ei].properties["weight_txt"];
174             }
175             if (jsonEdges[ei].properties["outgoing_tree"] == "true") {
176                 edge.width=3;
177                 if (jsonEdges[ei].source == eFrom) {
178                     edge.arrows = "to";
179                 }
180                 else {
181                     edge.arrows = "from";
182                 }
183             }
184         }
185         
186         if (jsonEdges[ei].source == eFrom) {
187             edge.fromLabel = eLabel;
188         }
189         else {
190             edge.toLabel = eLabel;
191         }
192     }
193     
194     /* add new edges */
195     var postfix = settings["common_edge_postfix"];
196     for (ei = 0; ei < newIds.length; ei++) {
197         var edge = undirectedEdges[newIds[ei]];
198         var label = "";
199         
200         if (edge.fromLabel == edge.toLabel) {
201             label = edge.fromLabel;
202         }
203         else if (edge.fromLabel.endsWith(postfix)
204                 && edge.fromLabel.endsWith(postfix)) {
205             var flen = edge.fromLabel.length - postfix.length;
206             var tlen = edge.toLabel.length - postfix.length;
207         
208             label = edge.fromLabel.substring(0, flen).trim() + "/"
209                 + edge.toLabel.substring(0, tlen).trim()
210                 + " " + postfix;             
211         }
212         else {
213             label = edge.fromLabel + "/" + edge.toLabel;
214         }
215         
216         if (visEdges.get(edge.uuid)) {
217             visEdges.update(
218                 {
219                     id:          edge.uuid,
220                     label:       label,
221                     width:       edge.width,
222                     arrows:      edge.arrows,
223                 }
224             );
225         }
226         else {
227             visEdges.add(
228                 {
229                     id:          edge.uuid,
230                     from:        edge.from,
231                     to:          edge.to,
232                     label:       label,
233                     length:      200,
234                     width:       edge.width,
235                     arrows:      edge.arrows,
236                     font: {
237                         align:       "top",
238                     },
239                     reference:   edge.reference,
240                 }
241             );
242         }
243     }
244
245     /* remove old edges */
246     for (ei = 0; ei < oldIds.length; ei++) {
247         if (newIds.indexOf(oldIds[ei]) == -1) {
248             visEdges.remove(oldIds[ei]);
249         }
250     }
251 }
252
253 function layout_json_data(obj) {
254     if (obj.type != "NetworkCollection") {
255         return;
256     }
257
258     for (index = 0; index < obj.collection.length; index++) {
259         element = obj.collection[index];
260
261         if (element.type == "NetworkGraph") {
262             if (settings["ipv4"] && element.router_id.indexOf(':') != -1) {
263                 continue;
264             }
265             if (!settings["ipv4"] && element.router_id.indexOf('.') != -1) {
266                 continue;
267             }
268             
269             last_displayed_graph = element;
270             
271             layout_nodes(element);
272             layout_edges(element);
273             break;
274         }
275     }
276 }
277     
278 function xmlhttp_changed()
279 {
280     if (xmlhttp.readyState==XMLHttpRequest.DONE && xmlhttp.status==200) {
281         last_json_data = JSON.parse(xmlhttp.responseText);
282         layout_json_data(last_json_data);
283
284         if (settings["autoupdate"]) {
285             autoupdate_timeout = window.setTimeout(
286                     send_request, settings["autoupdate_interval"]);
287         }
288     }
289 }
290
291 function graph_element_clicked(param) {
292     var nodes = param.nodes;
293     var edges = param.edges;
294     
295     if (last_displayed_graph === null) {
296         return;
297     }
298
299     var showdata = document.getElementById(settings["div_showdata"]);
300     if (showdata === null) {
301         return;
302     }
303     
304     if (nodes.length == 1) {
305         /* node clicked */
306         var node = visNodes.get(nodes[0]);
307         if (node) {
308             showdata.innerHTML = "<h2>Node "+node.label+"</h2>"
309                 + "<ul>"
310                 + "<li><b>router_id:</b> " + node.id + "</li>"
311                 + "</ul>";
312         }
313     }
314     else if (edges.length == 1) {
315         /* edge clicked */
316         var edge = visEdges.get(edges[0]);
317         if (edge) {
318             showdata.innerHTML = "<h2>Edge</h2>"
319                 + "<ul>"
320                 + "<li><b>from:</b> " + edge.from + "</li>"
321                 + "<li><b>to:</b> " + edge.to + "</li>"
322                 + "</ul>";
323         }
324     }
325 }
326
327 function autoupdate_clicked() {
328     settings["autoupdate"] = this.checked;
329     if (this.checked === false) {
330         window.clearTimeout(autoupdate_timeout);
331     }
332     else {
333         send_request();
334     }    
335 }
336
337 function dynamiclayout_clicked() {
338     settings["dynamic_layout"] = this.checked;
339     visNetwork.setOptions({physics:this.checked});
340     if (force_layout_timeout) {
341         window.clearTimeout(force_layout_timeout);
342     }
343 }
344
345 function ipv4_clicked() {
346     settings["ipv4"] = this.checked;
347     if (last_json_data !== null) {
348         layout_json_data(last_json_data);
349         if (!settings["dynamic_layout"]) {
350             visNetwork.setOptions({physics:true});
351             visNetwork.stabilize();
352             force_layout_timeout = window.setTimeout(
353                 function() { visNetwork.setOptions({physics:false}); }, 500);
354         }
355     }
356 }
357
358 function send_request() {
359     xmlhttp.open("GET",settings["netjsonurl"],true);
360     xmlhttp.send();
361 }
362
363 function copy_settings(dst, src) {
364     for (var p in dst) {
365         if (dst.hasOwnProperty(p) && src.hasOwnProperty(p)) {
366             if (dst[p] !== null && typeof src[p] !== typeof dst[p]) {
367                 continue;
368             }
369             
370             if (src[p] !== null && typeof dst[p] === 'object' && typeof src[p] === 'object') {
371                 copy_settings(dst[p], src[p]);
372             }
373             else {
374                 dst[p] = src[p];
375             }
376         } 
377     }              
378 }
379
380 function set_checkbox_function(checkbox_id, setting_name, f) {
381     if (checkbox_id === null || settings[checkbox_id] == "") {
382         return;
383     }
384     
385     var checkbox = document.getElementById(settings[checkbox_id]);
386     if (checkbox) {
387         checkbox.onclick = f;
388         checkbox.checked = settings[setting_name];
389     }
390 }
391
392 function init_netjson_viewer(custom_settings) {
393     if (custom_settings !== null) {
394         copy_settings(settings, custom_settings);
395     }
396     if (settings["netjsonurl"] === null) {
397         console.log("Netjson URL setting missing");
398         return;
399     }
400     
401     set_checkbox_function("checkbox_autoupdate", "autoupdate", autoupdate_clicked);
402     set_checkbox_function("checkbox_dynamic_layout", "dynamic_layout", dynamiclayout_clicked);
403     set_checkbox_function("checkbox_ipv4", "ipv4", ipv4_clicked);
404     
405     xmlhttp = new XMLHttpRequest();
406     xmlhttp.onreadystatechange=xmlhttp_changed
407     init_network();
408     send_request();
409 }