1
<?xml version="1.0" encoding="iso-8859-1"?>
5
OpenWRT port of this file based originally on the following:
8
$Id: graph_if.svg,v 1.1 2007/01/07 23:46:54 deri Exp $
9
part of m0n0wall (http://m0n0.ch/wall)
11
Copyright (C) 2004-2005 T. Lechat <dev@lechat.org>, Manuel Kasper <mk@neon1.net>
12
and Jonathan Watt <jwatt@jwatt.org>.
15
Redistribution and use in source and binary forms, with or without
16
modification, are permitted provided that the following conditions are met:
18
1. Redistributions of source code must retain the above copyright notice,
19
this list of conditions and the following disclaimer.
21
2. Redistributionss in binary form must reproduce the above copyright
22
notice, this list of conditions and the following disclaimer in the
23
documentation and/or other materials provided with the distribution.
25
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26
BINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
POSSIBILITY OF SUCH DAMAGE.
36
<svg xml:space='preserve' xmlns='http://www.w3.org/2000/svg'
37
xmlns:xlink='http://www.w3.org/1999/xlink'
38
width='100%' height='100%'
40
preserveAspectRatio='none'
44
<rect id='bg' x1='0' y1='0' width='600' height='300' fill='white' />
46
<text id='graph_ip_lbl' x='50' y='15' fill='#435370' text-anchor='end'>IP</text>
47
<text id='graph_non_ip_lbl' x='50' y='35' fill='#8092B3' text-anchor='end'>Non IP</text>
49
<text id='graph_ip_txt' x='54' y='15' fill='#435370'>--</text>
50
<text id='graph_non_ip_txt' x='54' y='35' fill='#8092B3'>--</text>
52
<text id='switch_unit' x='200' y='15' fill='#435370' cursor='pointer'>Switch to bytes/s</text>
53
<text id='switch_scale' x='200' y='35' fill='#435370' cursor='pointer'>Autoscale (follow)</text>
55
<text id='error' x='300' y='125' text-anchor='middle' visibility='hidden' fill='blue'>Cannot get data about interface</text>
56
<text id='collect_initial' x='300' y='125' text-anchor='middle' visibility='hidden' fill='gray'>Collecting initial data, please wait...</text>
58
<path id='grid' d='M 2 75 L 600 75 M 2 150 L 600 150 M 2 225 L 600 225' stroke='gray' stroke-opacity='0.5' />
59
<text id='grid_txt3' x='600' y='223' fill='gray' text-anchor='end'>--</text>
60
<text id='grid_txt2' x='600' y='148' fill='gray' text-anchor='end'>--</text>
61
<text id='grid_txt1' x='600' y='73' fill='gray' text-anchor='end'>--</text>
63
<path id='graph_non_ip' d='' fill='none' stroke='#8092B3' stroke-width='2' stroke-opacity='0.8' />
64
<path id='graph_ip' d='' fill='none' stroke='#435370' stroke-width='2' stroke-opacity='0.8' />
66
<line id='axis_x' x1='2' y1='299' x2='600' y2='299' stroke='black' />
67
<line id='axis_y' x1='1' y1='300' x2='1' y2='0' stroke='black' />
69
<script type="text/ecmascript">
71
if (typeof getURL == 'undefined') {
72
getURL = function(url, callback) {
73
if (!url) throw 'No URL for getURL';
76
if (typeof callback.operationComplete == 'function') {
77
callback = callback.operationComplete;
81
if (typeof callback != 'function') {
82
throw 'No callback function for getURL';
85
var http_request = null;
86
if (typeof XMLHttpRequest != 'undefined') {
87
http_request = new XMLHttpRequest();
88
} else if (typeof ActiveXObject != 'undefined') {
90
http_request = new ActiveXObject('Msxml2.XMLHTTP');
93
http_request = new ActiveXObject('Microsoft.XMLHTTP');
98
throw 'Both getURL and XMLHttpRequest are undefined';
101
http_request.onreadystatechange = function() {
102
if (http_request.readyState == 4) {
106
content : http_request.responseText,
107
contentType : http_request.getResponseHeader("Content-Type")
112
http_request.open('GET', url, true);
113
http_request.send(null);
122
var plot_in = new Array();
123
var plot_out = new Array();
125
var max_num_points = 120; // maximum number of plot data points
126
var step = 600 / max_num_points ;
128
var scale_type = 'follow';
133
/* hacked in fix for all browsers by spectra
134
* he says is 'ugly', and someone may want to redo the 'right' way */
135
fetch_url=location.search.split('?');
136
fetch_url='/ifStats.html';
137
/* end hacked in fix */
138
SVGDoc = evt.target.ownerDocument;
139
SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
140
SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
143
setInterval('fetch_data()', 1000);
146
function switch_unit(event) {
147
SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
148
unit = (unit == 'bits') ? 'bytes' : 'bits';
151
function switch_scale(event) {
152
scale_type = (scale_type == 'up') ? 'follow' : 'up';
153
SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
156
function fetch_data() {
158
getURL(fetch_url, plot_data);
164
function plot_data(obj) {
165
if (!obj.success) return handle_error(); // getURL failed to get data
167
// parse incoming data
168
// (format: "date" output, newline, proper line of /proc/net/dev)
169
var data=obj.content.split("\n");
171
//fake timezone cause the real value might confuse JS
172
dateStr=dateStr.replace(/ [A-Z]+ /, ' GMT ');
173
var ugmt=(Date.parse(dateStr))/1000;
175
data=data[1].split(/\s+|:/);
176
while (data[0]!=parseInt(data[0])) {
179
if (0==data.length) return;
181
var ifin=parseInt(data[0]);
182
var ifout=parseInt(data[1]);
184
if (!isNumber(ifin) || !isNumber(ifout)) {
185
return handle_error();
188
var diff_ugmt = ugmt - last_ugmt;
189
var diff_ifin = ifin - last_ifin;
190
var diff_ifout = ifout - last_ifout;
192
if (diff_ugmt == 0) diff_ugmt = 1; // avoid division by zero
198
switch (plot_in.length) {
200
SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
201
plot_in[0] = diff_ifin / diff_ugmt;
202
plot_out[0] = diff_ifout / diff_ugmt;
205
SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
208
// shift plot to left if the maximum number of plot points has been reached
210
while (i < max_num_points) {
211
plot_in[i] = plot_in[i+1];
212
plot_out[i] = plot_out[++i];
218
plot_in[plot_in.length] = diff_ifin / diff_ugmt;
219
plot_out[plot_out.length]= diff_ifout / diff_ugmt;
220
var index_plot = plot_in.length - 1;
222
SVGDoc.getElementById('graph_ip_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
223
SVGDoc.getElementById('graph_non_ip_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
225
// determine peak for sensible scaling
226
if (scale_type == 'up') {
227
if (plot_in[index_plot] > max) max = plot_in[index_plot];
228
if (plot_out[index_plot] > max) max = plot_out[index_plot];
229
} else if (scale_type == 'follow') {
232
while (i < plot_in.length) {
233
if (plot_in[i] > max) max = plot_in[i];
234
if (plot_out[i] > max) max = plot_out[i];
239
var rmax=makeRoundMax(max);
241
var scale = 298 / rmax;
243
// change labels accordingly
244
SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4, unit);
245
SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4, unit);
246
SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4, unit);
248
var path_in = "M 0 " + (298 - (plot_in[0] * scale));
249
var path_out = "M 0 " + (298 - (plot_out[0] * scale));
250
for (i = 1; i < plot_in.length; i++) {
252
var y_in = 298 - (plot_in[i] * scale);
253
var y_out = 298 - (plot_out[i] * scale);
254
path_in += " L" + x + " " + y_in;
255
path_out += " L" + x + " " + y_out;
258
SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
259
SVGDoc.getElementById('graph_ip').setAttributeNS(null, 'd', path_in);
260
SVGDoc.getElementById('graph_non_ip').setAttributeNS(null, 'd', path_out);
263
function makeRoundMax(max) {
264
if (unit == 'bits') {
270
if (i && (i % 4 == 0)) {
281
if (i && (i % 4 == 0)) {
287
if (i == 8) rmax *= 1.024;
293
function handle_error() {
294
SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
297
function isNumber(a) {
298
return typeof a == 'number' && isFinite(a);
301
function formatSpeed(speed, unit) {
302
if (unit == 'bits') return formatSpeedBits(speed);
303
if (unit == 'bytes') return formatSpeedBytes(speed);
306
function formatSpeedBits(speed) {
307
// format speed in bits/sec, input: bytes/sec
308
if (speed < 125000) return Math.round(speed / 125) + " Kbps";
309
if (speed < 125000000) return Math.round(speed / 1250)/100 + " Mbps";
311
return Math.round(speed / 1250000)/100 + " Gbps"; // wow!
314
function formatSpeedBytes(speed) {
315
// format speed in bytes/sec, input: bytes/sec
316
if (speed < 1048576) return Math.round(speed / 10.24)/100 + " KB/s";
317
if (speed < 1073741824) return Math.round(speed / 10485.76)/100 + " MB/s";
319
return Math.round(speed / 10737418.24)/100 + " GB/s"; // wow!