2 * copyright (c) 2006-2008 Emil Mikulic.
4 * graph.js: graph renderer
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
9 * At some point, this script worked correctly in:
10 * - Firefox 1.5.0.4, 2.0.0.1, 3.0
13 * - Konqueror 3.5.9, 4.0.80, 4.0.83
15 * Consumer needs to supply the following variables:
20 * - graphs [ {id, name, title, bar_secs} ]
23 * - window.onload = graphs_init
26 function killChildren(elem
) {
27 while (elem
.childNodes
.length
> 0)
28 elem
.removeChild( elem
.childNodes
.item(0) );
31 function setClass(elem
, c
) {
32 elem
.setAttribute("class", c
);
33 elem
.setAttribute("className", c
); /* for MSIE */
36 function setStyle(elem
, s
) {
37 elem
.setAttribute("style", s
);
38 elem
.style
.cssText
= s
; /* for MSIE */
41 function makeElemClass(e
, c
) {
42 var r
= document
.createElement(e
);
47 function makeClear() {
48 var r
= document
.createElement("div");
49 setStyle(r
, "clear:both");
53 function thousands(n
) {
56 while (s
.length
> 3) {
57 out
= "," + s
.substr(s
.length
- 3, 3) + out
;
58 s
= s
.substr(0, s
.length
- 3);
65 return bps
.toFixed(1);
70 if (bps
< 1) return bps
.toPrecision(2);
71 else return bps
.toFixed(1);
74 function min(a
,b
) { return (a
<b
)?a
:b
; }
75 function max(a
,b
) { return (a
>b
)?a
:b
; }
77 var xh
, autoreload
=false;
79 function graphs_init() {
80 var gr
= document
.getElementById("graphs");
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"));
91 for (var i
=0; i
<graphs
.length
; i
++) {
92 var g
= makeElemClass("div", "outergraph");
95 if (i
% 2 == 1) gr
.appendChild(makeClear());
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"));
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"));
109 var b
= document
.createElement("div");
110 b
.appendChild(b_reload
);
111 b
.appendChild(document
.createTextNode(" - automatic reload is: "));
112 b
.appendChild(b_autoreload
);
118 function graph_reload() {
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
;
132 function graph_autoreload() {
134 autoreload
= !autoreload
;
135 document
.getElementById("graph_autoreload").innerHTML
=
136 autoreload
? "on" : "off";
137 if (autoreload
) reload_loop();
140 function reload_loop() {
143 setTimeout("reload_loop()", 1000);
148 var STATE_COMPLETE
= 4;
149 if (xh
&& xh
.readyState
== STATE_COMPLETE
) {
150 for (var i
=0; i
<graphs
.length
; i
++)
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"));
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");
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
);
170 "width:"+width
+"px; "+
171 "height:"+height
+"px; "+
172 "position: absolute; "+
174 "bottom:"+bottom
+"px;");
175 graph
.appendChild(bar
);
178 function buildGraph(graph
, title
, bar_secs
, elems
) {
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
)
190 data
.push( [b_pos
, b_in
, b_out
] );
193 var igraph
= makeElemClass("div", "graph"); // inner graph
195 "width:"+graph_width
+"px; "+
196 "height:"+graph_height
+"px; "+
197 "position:relative;");
199 var nbars
= data
.length
;
200 var b_width
= (graph_width
- bar_gap
* (nbars
-1)) / nbars
;
203 var min_i
= 0, min_o
= 0,
204 max_i
= 0, max_o
= 0,
205 tot_i
= 0, tot_o
= 0;
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];
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
);
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
);
220 var xofs
= next_xofs
;
222 next_xofs
= Math
.round((b_width
+ bar_gap
) * (i
+1));
223 var curr_w
= next_xofs
- xofs
- bar_gap
;
225 var h_i
= Math
.round( b_i
* graph_height
/ total_max
);
226 var h_o
= Math
.round( b_o
* graph_height
/ total_max
);
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
";
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);
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));
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) );
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, "");
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) );
269 glegend.appendChild(tbl);
270 setStyle(glegend, "width
:"+graph_width+"px
;");
272 var gtitle = makeElemClass("div
", "graphtitle
");
273 setStyle(gtitle, "width
:"+graph_width+"px
;");
274 gtitle.appendChild(document.createTextNode(title));
277 graph.appendChild(igraph);
278 graph.appendChild(glegend);
279 graph.appendChild(gtitle);