Use the host compiler for build tool c-ify.
[darkstat-debian] / static / graph.js
1 /* darkstat 3
2 * copyright (c) 2006-2008 Emil Mikulic.
3 *
4 * graph.js: graph renderer
5 *
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
8 *
9 * At some point, this script worked correctly in:
10 * - Firefox 1.5.0.4, 2.0.0.1, 3.0
11 * - IE 6.0
12 * - Opera 8.53, 9.50
13 * - Konqueror 3.5.9, 4.0.80, 4.0.83
14 *
15 * Consumer needs to supply the following variables:
16 * - graph_width
17 * - graph_height
18 * - bar_gap
19 *
20 * - graphs [ {id, name, title, bar_secs} ]
21 * - graphs_uri
22 *
23 * - window.onload = graphs_init
24 */
25
26 function killChildren(elem) {
27 while (elem.childNodes.length > 0)
28 elem.removeChild( elem.childNodes.item(0) );
29 }
30
31 function setClass(elem, c) {
32 elem.setAttribute("class", c);
33 elem.setAttribute("className", c); /* for MSIE */
34 }
35
36 function setStyle(elem, s) {
37 elem.setAttribute("style", s);
38 elem.style.cssText = s; /* for MSIE */
39 }
40
41 function makeElemClass(e, c) {
42 var r = document.createElement(e);
43 setClass(r, c);
44 return r;
45 }
46
47 function makeClear() {
48 var r = document.createElement("div");
49 setStyle(r, "clear:both");
50 return r;
51 }
52
53 function thousands(n) {
54 var s = String(n);
55 var out = "";
56 while (s.length > 3) {
57 out = "," + s.substr(s.length - 3, 3) + out;
58 s = s.substr(0, s.length - 3);
59 }
60 return s+out;
61 }
62
63 function fkbps(bps) {
64 bps /= 1024;
65 return bps.toFixed(1);
66 }
67
68 function kbps(bps) {
69 bps /= 1024;
70 if (bps < 1) return bps.toPrecision(2);
71 else return bps.toFixed(1);
72 }
73
74 function min(a,b) { return (a<b)?a:b; }
75 function max(a,b) { return (a>b)?a:b; }
76
77 var xh, autoreload=false;
78
79 function graphs_init() {
80 var gr = document.getElementById("graphs");
81
82 /* update message */
83 var msg = document.createElement("div");
84 msg.appendChild(document.createTextNode("Graphs are being loaded..."));
85 msg.appendChild(document.createElement("br"));
86 msg.appendChild(document.createElement("br"));
87 killChildren(gr);
88 gr.appendChild(msg);
89 graphs.msg = msg;
90
91 for (var i=0; i<graphs.length; i++) {
92 var g = makeElemClass("div", "outergraph");
93 gr.appendChild(g);
94 graphs[i].graph = g;
95 if (i % 2 == 1) gr.appendChild(makeClear());
96 }
97
98 /* create buttons */
99 var b_reload = document.createElement("a");
100 b_reload.setAttribute("id", "graph_reload");
101 b_reload.setAttribute("href", "javascript:graph_reload()");
102 b_reload.appendChild(document.createTextNode("reload graphs"));
103
104 var b_autoreload = document.createElement("a");
105 b_autoreload.setAttribute("id", "graph_autoreload");
106 b_autoreload.setAttribute("href", "javascript:graph_autoreload()");
107 b_autoreload.appendChild(document.createTextNode("off"));
108
109 var b = document.createElement("div");
110 b.appendChild(b_reload);
111 b.appendChild(document.createTextNode(" - automatic reload is: "));
112 b.appendChild(b_autoreload);
113 gr.appendChild(b);
114
115 graph_reload();
116 }
117
118 function graph_reload() {
119 if (!autoreload)
120 document.getElementById("graph_reload").innerHTML = "loading...";
121 xh = (window.ActiveXObject)
122 ? new ActiveXObject("Microsoft.XMLHTTP")
123 : new XMLHttpRequest();
124 var asyncFlag = true;
125 xh.open("GET", graphs_uri, asyncFlag);
126 // try to nerf caching:
127 xh.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
128 xh.onreadystatechange = poll;
129 xh.send(null);
130 }
131
132 function graph_autoreload() {
133 // toggle
134 autoreload = !autoreload;
135 document.getElementById("graph_autoreload").innerHTML =
136 autoreload ? "on" : "off";
137 if (autoreload) reload_loop();
138 }
139
140 function reload_loop() {
141 if (autoreload) {
142 graph_reload();
143 setTimeout("reload_loop()", 1000);
144 }
145 }
146
147 function poll() {
148 var STATE_COMPLETE = 4;
149 if (xh && xh.readyState == STATE_COMPLETE) {
150 for (var i=0; i<graphs.length; i++)
151 {
152 g = xh.responseXML.getElementsByTagName(graphs[i].name);
153 buildGraph(graphs[i].graph, graphs[i].title, graphs[i].bar_secs,
154 g[0].getElementsByTagName("e"));
155 }
156 document.getElementById("graph_reload").innerHTML = "reload graphs";
157 killChildren(graphs.msg);
158 head = xh.responseXML.childNodes[0];
159 for (var n in {"tb":0, "tp":0, "pc":0, "pd":0})
160 document.getElementById(n).innerHTML = thousands(head.getAttribute(n));
161 document.getElementById("rf").innerHTML = head.getAttribute("rf");
162 }
163 }
164
165 function addBar(graph, title, barclass, width, height, left, bottom) {
166 if (height == 0) return; /* not visible */
167 var bar = makeElemClass("div", barclass);
168 bar.setAttribute("title", title);
169 setStyle(bar,
170 "width:"+width+"px; "+
171 "height:"+height+"px; "+
172 "position: absolute; "+
173 "left:"+left+"px; "+
174 "bottom:"+bottom+"px;");
175 graph.appendChild(bar);
176 }
177
178 function buildGraph(graph, title, bar_secs, elems) {
179 var total_max = 0;
180 var data = []; /* list of [in, out] */
181 for (var i=0; i<elems.length; i++) {
182 var elem = elems.item(i);
183 var b_pos = Number( elem.getAttribute("p") );
184 var b_in = Number( elem.getAttribute("i") );
185 var b_out = Number( elem.getAttribute("o") );
186 var b_total = b_in + b_out;
187 /* FIXME: what happens when a bar's value is >4G? */
188 if (b_total > total_max)
189 total_max = b_total;
190 data.push( [b_pos, b_in, b_out] );
191 }
192
193 var igraph = makeElemClass("div", "graph"); // inner graph
194 setStyle(igraph,
195 "width:"+graph_width+"px; "+
196 "height:"+graph_height+"px; "+
197 "position:relative;");
198
199 var nbars = data.length;
200 var b_width = (graph_width - bar_gap * (nbars-1)) / nbars;
201 var next_xofs = 0;
202
203 var min_i = 0, min_o = 0,
204 max_i = 0, max_o = 0,
205 tot_i = 0, tot_o = 0;
206
207 for (var i=0; i<nbars; i++) {
208 var b_p = data[i][0];
209 var b_i = data[i][1];
210 var b_o = data[i][2];
211
212 if (b_i>0) { if (min_i == 0) min_i = b_i; else min_i = min(min_i, b_i); }
213 max_i = max(max_i, b_i);
214 tot_i += b_i;
215
216 if (b_o>0) { if (min_o == 0) min_o = b_o; else min_o = min(min_o, b_o); }
217 max_o = max(max_o, b_o);
218 tot_o += b_o;
219
220 var xofs = next_xofs;
221
222 next_xofs = Math.round((b_width + bar_gap) * (i+1));
223 var curr_w = next_xofs - xofs - bar_gap;
224
225 var h_i = Math.round( b_i * graph_height / total_max );
226 var h_o = Math.round( b_o * graph_height / total_max );
227
228 var label = b_p+": "+
229 thousands(b_i)+" bytes in, "+
230 thousands(b_o)+" bytes out | "+
231 kbps(b_i/bar_secs)+" KB/s in, "+
232 kbps(b_o/bar_secs)+" KB/s out";
233
234 addBar(igraph, label, "bar_in", curr_w, h_i, xofs, 0);
235 addBar(igraph, label, "bar_out", curr_w, h_o, xofs, h_i);
236 }
237
238 function legendRow(dir_str, minb, avgb, maxb) {
239 function makeTD(c, str) {
240 var r = makeElemClass("td", c);
241 r.appendChild(document.createTextNode(str));
242 return r;
243 }
244 function addToRow(row, type_str, bytes, trail) {
245 row.appendChild( makeTD("type", type_str) );
246 row.appendChild( makeTD("rate", fkbps(bytes/bar_secs)+" KB/s"+trail) );
247 }
248 var row = document.createElement("tr");
249 row.appendChild( makeTD("dir", dir_str) );
250 var cell = makeElemClass("td", "swatch");
251 var swatch = makeElemClass("div", "bar_"+dir_str);
252 setStyle(swatch, "width:6px; height:6px;");
253 cell.appendChild(swatch);
254 row.appendChild(cell);
255 addToRow(row, "min:", minb, ",");
256 addToRow(row, "avg:", avgb, ",");
257 addToRow(row, "max:", maxb, "");
258 return row;
259 }
260
261 var glegend = makeElemClass("div", "legend");
262 var avg_i = tot_i / nbars,
263 avg_o = tot_o / nbars;
264 var tbl = document.createElement("table");
265 var tb = document.createElement("tbody"); /* for MSIE */
266 tb.appendChild( legendRow("in", min_i, avg_i, max_i) );
267 tb.appendChild( legendRow("out", min_o, avg_o, max_o) );
268 tbl.appendChild(tb);
269 glegend.appendChild(tbl);
270 setStyle(glegend, "width:"+graph_width+"px;");
271
272 var gtitle = makeElemClass("div", "graphtitle");
273 setStyle(gtitle, "width:"+graph_width+"px;");
274 gtitle.appendChild(document.createTextNode(title));
275
276 killChildren(graph);
277 graph.appendChild(igraph);
278 graph.appendChild(glegend);
279 graph.appendChild(gtitle);
280 }