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