Backported LuCI Livestats

This commit is contained in:
Steven Barth 2008-12-07 19:50:02 +00:00
parent 973771c9d3
commit 338391eacb
15 changed files with 7853 additions and 2 deletions

View File

@ -0,0 +1,2 @@
include ../../build/config.mk
include ../../build/module.mk

View File

@ -0,0 +1,19 @@
if(!window.CanvasRenderingContext2D){(function(){var I=Math,i=I.round,L=I.sin,M=I.cos,m=10,A=m/2,Q={init:function(a){var b=a||document;if(/MSIE/.test(navigator.userAgent)&&!window.opera){var c=this;b.attachEvent("onreadystatechange",function(){c.r(b)})}},r:function(a){if(a.readyState=="complete"){if(!a.namespaces["s"]){a.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml")}var b=a.createStyleSheet();b.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}";
var c=a.getElementsByTagName("canvas");for(var d=0;d<c.length;d++){if(!c[d].getContext){this.initElement(c[d])}}}},q:function(a){var b=a.outerHTML,c=a.ownerDocument.createElement(b);if(b.slice(-2)!="/>"){var d="/"+a.tagName,e;while((e=a.nextSibling)&&e.tagName!=d){e.removeNode()}if(e){e.removeNode()}}a.parentNode.replaceChild(c,a);return c},initElement:function(a){a=this.q(a);a.getContext=function(){if(this.l){return this.l}return this.l=new K(this)};a.attachEvent("onpropertychange",V);a.attachEvent("onresize",
W);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+"px"}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+"px"}else{a.height=a.clientHeight}return a}};function V(a){var b=a.srcElement;switch(a.propertyName){case "width":b.style.width=b.attributes.width.nodeValue+"px";b.getContext().clearRect();break;case "height":b.style.height=b.attributes.height.nodeValue+"px";b.getContext().clearRect();break}}function W(a){var b=a.srcElement;
if(b.firstChild){b.firstChild.style.width=b.clientWidth+"px";b.firstChild.style.height=b.clientHeight+"px"}}Q.init();var R=[];for(var E=0;E<16;E++){for(var F=0;F<16;F++){R[E*16+F]=E.toString(16)+F.toString(16)}}function J(){return[[1,0,0],[0,1,0],[0,0,1]]}function G(a,b){var c=J();for(var d=0;d<3;d++){for(var e=0;e<3;e++){var g=0;for(var h=0;h<3;h++){g+=a[d][h]*b[h][e]}c[d][e]=g}}return c}function N(a,b){b.fillStyle=a.fillStyle;b.lineCap=a.lineCap;b.lineJoin=a.lineJoin;b.lineWidth=a.lineWidth;b.miterLimit=
a.miterLimit;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.shadowOffsetX=a.shadowOffsetX;b.shadowOffsetY=a.shadowOffsetY;b.strokeStyle=a.strokeStyle;b.d=a.d;b.e=a.e}function O(a){var b,c=1;a=String(a);if(a.substring(0,3)=="rgb"){var d=a.indexOf("(",3),e=a.indexOf(")",d+1),g=a.substring(d+1,e).split(",");b="#";for(var h=0;h<3;h++){b+=R[Number(g[h])]}if(g.length==4&&a.substr(3,1)=="a"){c=g[3]}}else{b=a}return[b,c]}function S(a){switch(a){case "butt":return"flat";case "round":return"round";
case "square":default:return"square"}}function K(a){this.a=J();this.m=[];this.k=[];this.c=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=m*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement("div");b.style.width=a.clientWidth+"px";b.style.height=a.clientHeight+"px";b.style.overflow="hidden";b.style.position="absolute";a.appendChild(b);this.j=b;this.d=1;this.e=1}var j=K.prototype;j.clearRect=function(){this.j.innerHTML=
"";this.c=[]};j.beginPath=function(){this.c=[]};j.moveTo=function(a,b){this.c.push({type:"moveTo",x:a,y:b});this.f=a;this.g=b};j.lineTo=function(a,b){this.c.push({type:"lineTo",x:a,y:b});this.f=a;this.g=b};j.bezierCurveTo=function(a,b,c,d,e,g){this.c.push({type:"bezierCurveTo",cp1x:a,cp1y:b,cp2x:c,cp2y:d,x:e,y:g});this.f=e;this.g=g};j.quadraticCurveTo=function(a,b,c,d){var e=this.f+0.6666666666666666*(a-this.f),g=this.g+0.6666666666666666*(b-this.g),h=e+(c-this.f)/3,l=g+(d-this.g)/3;this.bezierCurveTo(e,
g,h,l,c,d)};j.arc=function(a,b,c,d,e,g){c*=m;var h=g?"at":"wa",l=a+M(d)*c-A,n=b+L(d)*c-A,o=a+M(e)*c-A,f=b+L(e)*c-A;if(l==o&&!g){l+=0.125}this.c.push({type:h,x:a,y:b,radius:c,xStart:l,yStart:n,xEnd:o,yEnd:f})};j.rect=function(a,b,c,d){this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath()};j.strokeRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.stroke()};j.fillRect=function(a,
b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill()};j.createLinearGradient=function(a,b,c,d){var e=new H("gradient");return e};j.createRadialGradient=function(a,b,c,d,e,g){var h=new H("gradientradial");h.n=c;h.o=g;h.i.x=a;h.i.y=b;return h};j.drawImage=function(a,b){var c,d,e,g,h,l,n,o,f=a.runtimeStyle.width,k=a.runtimeStyle.height;a.runtimeStyle.width="auto";a.runtimeStyle.height="auto";var q=a.width,r=a.height;a.runtimeStyle.width=
f;a.runtimeStyle.height=k;if(arguments.length==3){c=arguments[1];d=arguments[2];h=(l=0);n=(e=q);o=(g=r)}else if(arguments.length==5){c=arguments[1];d=arguments[2];e=arguments[3];g=arguments[4];h=(l=0);n=q;o=r}else if(arguments.length==9){h=arguments[1];l=arguments[2];n=arguments[3];o=arguments[4];c=arguments[5];d=arguments[6];e=arguments[7];g=arguments[8]}else{throw"Invalid number of arguments";}var s=this.b(c,d),t=[],v=10,w=10;t.push(" <g_vml_:group",' coordsize="',m*v,",",m*w,'"',' coordorigin="0,0"',
' style="width:',v,";height:",w,";position:absolute;");if(this.a[0][0]!=1||this.a[0][1]){var x=[];x.push("M11='",this.a[0][0],"',","M12='",this.a[1][0],"',","M21='",this.a[0][1],"',","M22='",this.a[1][1],"',","Dx='",i(s.x/m),"',","Dy='",i(s.y/m),"'");var p=s,y=this.b(c+e,d),z=this.b(c,d+g),B=this.b(c+e,d+g);p.x=Math.max(p.x,y.x,z.x,B.x);p.y=Math.max(p.y,y.y,z.y,B.y);t.push("padding:0 ",i(p.x/m),"px ",i(p.y/m),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",x.join(""),", sizingmethod='clip');")}else{t.push("top:",
i(s.y/m),"px;left:",i(s.x/m),"px;")}t.push(' ">','<g_vml_:image src="',a.src,'"',' style="width:',m*e,";"," height:",m*g,';"',' cropleft="',h/q,'"',' croptop="',l/r,'"',' cropright="',(q-h-n)/q,'"',' cropbottom="',(r-l-o)/r,'"'," />","</g_vml_:group>");this.j.insertAdjacentHTML("BeforeEnd",t.join(""))};j.stroke=function(a){var b=[],c=O(a?this.fillStyle:this.strokeStyle),d=c[0],e=c[1]*this.globalAlpha,g=10,h=10;b.push("<g_vml_:shape",' fillcolor="',d,'"',' filled="',Boolean(a),'"',' style="position:absolute;width:',
g,";height:",h,';"',' coordorigin="0 0" coordsize="',m*g," ",m*h,'"',' stroked="',!a,'"',' strokeweight="',this.lineWidth,'"',' strokecolor="',d,'"',' path="');var l={x:null,y:null},n={x:null,y:null};for(var o=0;o<this.c.length;o++){var f=this.c[o];if(f.type=="moveTo"){b.push(" m ");var k=this.b(f.x,f.y);b.push(i(k.x),",",i(k.y))}else if(f.type=="lineTo"){b.push(" l ");var k=this.b(f.x,f.y);b.push(i(k.x),",",i(k.y))}else if(f.type=="close"){b.push(" x ")}else if(f.type=="bezierCurveTo"){b.push(" c ");
var k=this.b(f.x,f.y),q=this.b(f.cp1x,f.cp1y),r=this.b(f.cp2x,f.cp2y);b.push(i(q.x),",",i(q.y),",",i(r.x),",",i(r.y),",",i(k.x),",",i(k.y))}else if(f.type=="at"||f.type=="wa"){b.push(" ",f.type," ");var k=this.b(f.x,f.y),s=this.b(f.xStart,f.yStart),t=this.b(f.xEnd,f.yEnd);b.push(i(k.x-this.d*f.radius),",",i(k.y-this.e*f.radius)," ",i(k.x+this.d*f.radius),",",i(k.y+this.e*f.radius)," ",i(s.x),",",i(s.y)," ",i(t.x),",",i(t.y))}if(k){if(l.x==null||k.x<l.x){l.x=k.x}if(n.x==null||k.x>n.x){n.x=k.x}if(l.y==
null||k.y<l.y){l.y=k.y}if(n.y==null||k.y>n.y){n.y=k.y}}}b.push(' ">');if(typeof this.fillStyle=="object"){var v={x:"50%",y:"50%"},w=n.x-l.x,x=n.y-l.y,p=w>x?w:x;v.x=i(this.fillStyle.i.x/w*100+50)+"%";v.y=i(this.fillStyle.i.y/x*100+50)+"%";var y=[];if(this.fillStyle.p=="gradientradial"){var z=this.fillStyle.n/p*100,B=this.fillStyle.o/p*100-z}else{var z=0,B=100}var C={offset:null,color:null},D={offset:null,color:null};this.fillStyle.h.sort(function(T,U){return T.offset-U.offset});for(var o=0;o<this.fillStyle.h.length;o++){var u=
this.fillStyle.h[o];y.push(u.offset*B+z,"% ",u.color,",");if(u.offset>C.offset||C.offset==null){C.offset=u.offset;C.color=u.color}if(u.offset<D.offset||D.offset==null){D.offset=u.offset;D.color=u.color}}y.pop();b.push("<g_vml_:fill",' color="',D.color,'"',' color2="',C.color,'"',' type="',this.fillStyle.p,'"',' focusposition="',v.x,", ",v.y,'"',' colors="',y.join(""),'"',' opacity="',e,'" />')}else if(a){b.push('<g_vml_:fill color="',d,'" opacity="',e,'" />')}else{b.push("<g_vml_:stroke",' opacity="',
e,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',S(this.lineCap),'"',' weight="',this.lineWidth,'px"',' color="',d,'" />')}b.push("</g_vml_:shape>");this.j.insertAdjacentHTML("beforeEnd",b.join(""));this.c=[]};j.fill=function(){this.stroke(true)};j.closePath=function(){this.c.push({type:"close"})};j.b=function(a,b){return{x:m*(a*this.a[0][0]+b*this.a[1][0]+this.a[2][0])-A,y:m*(a*this.a[0][1]+b*this.a[1][1]+this.a[2][1])-A}};j.save=function(){var a={};N(this,a);
this.k.push(a);this.m.push(this.a);this.a=G(J(),this.a)};j.restore=function(){N(this.k.pop(),this);this.a=this.m.pop()};j.translate=function(a,b){var c=[[1,0,0],[0,1,0],[a,b,1]];this.a=G(c,this.a)};j.rotate=function(a){var b=M(a),c=L(a),d=[[b,c,0],[-c,b,0],[0,0,1]];this.a=G(d,this.a)};j.scale=function(a,b){this.d*=a;this.e*=b;var c=[[a,0,0],[0,b,0],[0,0,1]];this.a=G(c,this.a)};j.clip=function(){};j.arcTo=function(){};j.createPattern=function(){return new P};function H(a){this.p=a;this.n=0;this.o=
0;this.h=[];this.i={x:0,y:0}}H.prototype.addColorStop=function(a,b){b=O(b);this.h.push({offset:1-a,color:b})};function P(){}G_vmlCanvasManager=Q;CanvasRenderingContext2D=K;CanvasGradient=H;CanvasPattern=P})()};

View File

@ -0,0 +1,204 @@
function Graph(container, id, options, transform, legend) {
if( !options ) options = { };
this.id = id;
this.cols = 100;
this.type = "line";
this.options = options;
this.transform = transform;
this.dataset = {};
this.legend = legend;
this.lastvalue = {};
var name = (options.instanceNames && options.instanceNames[id])
? options.instanceNames[id] : id;
var graph = document.createElement('div');
var label = document.createElement('h2');
label.innerHTML = options.title
? options.title.replace("%s", name) : name;
container.appendChild( label );
container.appendChild( graph );
this.canvas = document.createElement('canvas');
graph.appendChild( this.canvas );
this.canvas.id = id;
this.canvas.width = ( options.width || graph.offsetWidth - 20 );
this.canvas.height = ( options.height || 300 );
}
Graph.prototype.addDataset = function(name, ds) {
if( !this.layout ) {
this.layout = new PlotKit.Layout( this.type, this.options );
}
if( !ds ) {
ds = new Array();
for( var i = 0; i < this.cols; i++ )
ds[i] = new Array( i, 0 );
}
this.dataset[name] = ds;
this.layout.addDataset(name, ds);
}
Graph.prototype.updateDataset = function(name, value) {
if( this.dataset[name] ) {
var ds = this.dataset[name];
for( var i = 1; i < this.cols; i++ )
ds[i-1][1] = ds[i][1];
value = Math.abs( parseFloat(value) || 0 );
if( this.transform ) {
var orgvalue = value;
value = (this.lastvalue[name]) ? this.transform(value, this.lastvalue[name]) : 0;
this.lastvalue[name] = orgvalue;
}
ds[this.cols-1][1] = value;
this.layout.addDataset(name, ds);
}
}
Graph.prototype.draw = function( options ) {
if( this.layout ) {
this.plotter = new PlotKit.CanvasRenderer(
this.canvas, this.layout, this.options || options || {}
);
this.layout.evaluate();
this.plotter.render();
legend_opt = {
"legendStyle": 'li'
};
legend = new LegendRenderer(this.legend, this.layout, legend_opt);
legend.render();
}
}
Graph.prototype.redraw = function() {
if( this.layout && this.plotter ) {
this.layout.evaluate();
this.plotter.clear();
this.plotter.render();
}
}
function GraphRPC(container, uri, action, interval, datasources, options, transform, legend) {
this.ds = datasources;
this.uri = uri
this.action = action;
this.options = options || { };
this.container = container;
this.transform = transform;
this.proxy = new MochiKit.JsonRpc.JsonRpcProxy(uri, [action]);
this.graphs = new Object();
this.legend = legend;
this.requestData();
if( interval ) {
var self = this;
window.setInterval(function(){self.requestData()}, interval);
}
}
GraphRPC.prototype.requestData = function() {
var r = this.proxy[this.action](); var self = this;
r.addCallback(function(r){ self.dispatchResponse(r) });
r.addErrback(function(e){ throw('Error: ' + e) });
}
GraphRPC.prototype.dispatchResponse = function(response) {
var instances;
if( this.options.instances ) {
instances = this.options.instances;
}
else {
instances = new Array();
for( var instance in response ) {
instances[instances.length] = instance;
}
}
for( var j = 0; j < instances.length; j++ ) {
var instance = instances[j];
if( this.options.separateDS ) {
for( var i = 0; i < this.ds.length; i += 2 ) {
var name = this.ds[i+1] || this.ds[i];
var gid = instance + '-' + name;
var otle = this.options.title || instance;
if( !this.graphs[gid] ) {
this.options.title = otle.replace('%s', instance) + ': ' + name;
this.graphs[gid] = new Graph(
this.container, gid, this.options, this.transform, this.legend
);
this.graphs[gid].addDataset(name);
this.graphs[gid].draw();
this.options.title = otle;
}
else
{
var datum = null;
if (typeof (this.ds[i]) == "function") {
datum = this.ds[i](
instance ? response[instance] : response
);
} else {
datum = instance
? response[instance][this.ds[i]]
: response[this.ds[i]]
}
this.graphs[gid].updateDataset(
name, datum
);
this.graphs[gid].redraw();
}
}
}
else {
var gid = instance || 'livegraph';
if( !this.graphs[gid] ) {
this.graphs[gid] = new Graph(
this.container, gid, this.options, this.transform, this.legend
);
for( var i = 0; i < this.ds.length; i += 2 ) {
var name = this.ds[i+1] || this.ds[i];
this.graphs[gid].addDataset(name);
}
this.graphs[gid].draw();
}
else {
for( var i = 0; i < this.ds.length; i += 2 ) {
var name = this.ds[i+1] || this.ds[i];
var datum = null;
if (typeof (this.ds[i]) == "function") {
datum = this.ds[i](
instance ? response[instance] : response
);
} else {
datum = instance
? response[instance][this.ds[i]]
: response[this.ds[i]]
}
this.graphs[gid].updateDataset(
name, datum
);
}
this.graphs[gid].redraw();
}
}
}
}

View File

@ -0,0 +1,220 @@
/* MochiKit.JsonRpc */
if (typeof(dojo) != 'undefined') {
dojo.provide("MochiKit.JsonRpc");
dojo.require("MochiKit.Base");
dojo.require("MochiKit.DOM");
dojo.require("MochiKit.Async");
}
if (typeof(JSAN) != 'undefined') {
JSAN.use("MochiKit.Base", []);
JSAN.use("MochiKit.DOM", []);
JSAN.use("MochiKit.Async", []);
}
try {
if (typeof(MochiKit.Base) == 'undefined' ||
typeof(MochiKit.DOM) == 'undefined' ||
typeof(MochiKit.Async) == 'undefined') {
throw "";
}
} catch (e) {
throw "MochiKit.JsonRpc depends on MochiKit.Base, MochiKit.DOM and MochiKit.Async";
}
if (typeof(MochiKit.JsonRpc) == 'undefined') {
MochiKit.JsonRpc = {};
}
MochiKit.JsonRpc.NAME = "MochiKit.JsonRpc";
MochiKit.JsonRpc.VERSION = "0.90";
MochiKit.JsonRpc.__repr__ = function () {
return "[" + this.NAME + " " + this.VERSION + "]";
}
MochiKit.JsonRpc.toString = function () {
return this.__repr__();
}
MochiKit.JsonRpc.JsonRpcError = function (message) {
this.message = message;
this.name = 'JsonRpcError';
}
MochiKit.JsonRpc.JsonRpcError.prototype = new Error();
MochiKit.JsonRpc.JsonRpcError.prototype.repr = function () {
return 'JsonRpcError(' + this.message + ')';
}
MochiKit.JsonRpc.JsonRpcError.prototype.toString = function () {
return this.repr();
}
MochiKit.JsonRpc.jsonObject = function (o) {
var attrs=[];
for(attr in o){
if(typeof o[attr] != "function"){
attrs.push('"' + attr + '": ' + json(o[attr]));
}
}
return "{" + attrs.join(", ") + "}";
}
MochiKit.JsonRpc.isObject = function (o) {
return true;
}
MochiKit.JsonRpc.jsonArray = function (o) {
return "[" + MochiKit.Base.map(json, o).join(", ") + "]";
}
var MB = MochiKit.Base
MochiKit.JsonRpc.jsonRegistry = new MochiKit.Base.AdapterRegistry();
MochiKit.JsonRpc.jsonRegistry.register('arrayLike',MB.isArrayLike,MochiKit.JsonRpc.jsonArray);
MochiKit.JsonRpc.jsonRegistry.register("string", MB.typeMatcher("string"), MB.reprString);
MochiKit.JsonRpc.jsonRegistry.register("numbers", MB.typeMatcher("number", "boolean"), MB.reprNumber);
MochiKit.JsonRpc.jsonRegistry.register("undefined", MB.isUndefined, MB.reprUndefined);
MochiKit.JsonRpc.jsonRegistry.register("null", MB.isNull, MB.reprNull);
MochiKit.JsonRpc.jsonRegistry.register("objectLike", MochiKit.JsonRpc.isObject, MochiKit.JsonRpc.jsonObject);
MochiKit.JsonRpc.json = function (o) {
try {
if (typeof(o.__json__) == 'function') {
return o.__json__();
} else if (typeof(o.json) == 'function' && o.json != arguments.callee) {
return o.json();
}
return jsonRegistry.match(o);
} catch (e) {
if (typeof(o.NAME) == 'string' && (
o.toString == Function.prototype.toString ||
o.toString == Object.prototype.toString
)) {
return o.NAME;
}
return o;
}
}
MochiKit.JsonRpc.JsonRpcCall = function (method,params) {
this.method = method;
this.params = params;
this.id = '0';
}
MochiKit.JsonRpc.JsonRpcProxy = function (url,methNames) {
MochiKit.Base.bindMethods(this);
this.url = url;
if (methNames) {
MochiKit.Base.map(this._proxyMethod,methNames);
}
}
update(MochiKit.JsonRpc.JsonRpcProxy.prototype, {
'call': function () {
var arglist = MochiKit.Base.map(null,arguments)
var methname = arglist.shift()
log(arglist);
var callobj = new MochiKit.JsonRpc.JsonRpcCall(methname,arglist);
var callstr = json(callobj);
var req = MochiKit.Async.getXMLHttpRequest();
req.open("POST",this.url,true);
req.setRequestHeader("Content-Type","text/plain");
req.setRequestHeader("Content-Length",callstr.length);
var d = MochiKit.Async.sendXMLHttpRequest(req,callstr);
d.addCallback(MochiKit.Async.evalJSONRequest);
d.addCallback(this._extractResult);
return d
},
'addSingleMethod': function (methName) {
if (methName) {
this._proxyMethod(methName);
}
},
'addMethods': function (methNames) {
if (methNames) {
MochiKit.Base.map(this._proxyMethod,methNames);
}
},
'_extractResult': function (resp) {
if (!resp.error){
return resp.result;
} else {
throw new MochiKit.JsonRpc.JsonRpcError(resp.error);
}
},
'_proxyMethod': function (methname) {
this[methname] = MochiKit.Base.partial(this.call,methname);
}
});
MochiKit.JsonRpc.DomObjectFromJson = function (){
var retval = false;
if (arguments.length == 1) {
var arg = arguments[0];
if (typeof(arg) == 'string'){
retval = MochiKit.DOM.SPAN(null,arg);
} else {
var objrepr = arguments[0];
var elem = document.createElement(objrepr[0]);
var attrs = objrepr[1];
if (attrs) {
MochiKit.DOM.updateNodeAttributes(elem, attrs);
}
if (objrepr.length >= 3){
var extraobj = objrepr[2]
for (var i=0;i<extraobj.length;i++) {
var value = MochiKit.JsonRpc.DomObjectFromJson(extraobj[i]);
if (value) {
elem.appendChild(value);
}
}
}
retval = elem;
}
}
return retval;
};
MochiKit.JsonRpc.EXPORT = [
"JsonRpcError",
"JsonRpcProxy",
];
MochiKit.JsonRpc.EXPORT_OK = [
"jsonObject",
"jsonArray",
"jsonRegistry",
"json",
"JsonRpcCall",
"DomObjectFromJson",
];
MochiKit.JsonRpc.__new__ = function () {
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
};
MochiKit.Base.nameFunctions(this);
};
MochiKit.JsonRpc.__new__();
if ((typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
|| (typeof(MochiKit.__compat__) == 'boolean' && MochiKit.__compat__)) {
(function (self) {
var all = self.EXPORT_TAGS[":all"];
for (var i = 0; i < all.length; i++) {
this[all[i]] = self[all[i]];
}
})(MochiKit.JsonRpc);
}

View File

@ -0,0 +1,228 @@
/*
PlotKit Legend
==============
Handles laying out legend into a DIV element.
Design taken from comments of Julien Wajsberg (http://
groups.google.com/group/plotkit/browse_thread/thread/2494bd88e6e9956d)
and Niel Domingo (http://nieldomingo.blogspot.com/2007/03/legend-
for-plotkit-bar-charts.html).
Copyright
---------
Copyright 2007 (c) Ashley Martens <ashleym_72^yahoo.com>
For use under the BSD license. <http://www.liquidx.net/plotkit>
*/
try {
if (typeof(MochiKit.Base) == 'undefined' ||
typeof(MochiKit.DOM) == 'undefined' ||
typeof(MochiKit.Color) == 'undefined' ||
typeof(MochiKit.Format) == 'undefined' ||
typeof(PlotKit.Layout) == 'undefined' ||
typeof(PlotKit.Base) == 'undefined')
{
throw "";
}
}
catch (e) {
throw "PlotKit depends on MochiKit.{Base,Color,DOM,Format}"
}
if (typeof(PlotKit.LegendRenderer) == 'undefined') {
PlotKit.LegendRenderer = {};
}
PlotKit.LegendRenderer = function(element, layout, options) {
if (arguments.length > 0)
this.__init__(element, layout, options);
};
PlotKit.LegendRenderer.NAME = "PlotKit.LegendRenderer";
PlotKit.LegendRenderer.VERSION = PlotKit.VERSION;
PlotKit.LegendRenderer.__repr__ = function() {
return "[" + this.NAME + " " + this.VERSION + "]";
};
PlotKit.LegendRenderer.toString = function() {
return this.__repr__();
}
PlotKit.LegendRenderer.prototype.__init__ = function(element, layout,
options) {
var isNil = MochiKit.Base.isUndefinedOrNull;
var Color = MochiKit.Color.Color;
this.options = {
"colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()
[0]),
"legendStyle": "table",
"tableColumns": 1
};
MochiKit.Base.update(this.options, options ? options : {});
this.layout = layout;
this.element = MochiKit.DOM.getElement(element);
// --- check whether everything is ok before we return
if (isNil(this.element))
throw "CRILegend() - passed legend is not found";
};
PlotKit.LegendRenderer.prototype.render = function() {
var colorScheme = this.options.colorScheme;
var setNames = PlotKit.Base.keys(this.layout.datasets);
MochiKit.DOM.updateNodeAttributes(this.element,
{"style":
{"margin":"0"
,"padding":"0"
}
});
var ul = null;
if (this.options.legendStyle == "table")
ul = this._renderListTable(colorScheme, setNames);
else
ul = this._renderList(colorScheme, setNames);
MochiKit.DOM.appendChildNodes(this.element, ul);
};
PlotKit.LegendRenderer.prototype._renderList = function(colorScheme,
setNames) {
var ul = document.createElement("ul");
ul.style.listStyle="none";
ul.style.margin="0";
ul.style.padding="0";
var colorCount = colorScheme.length;
var setCount = setNames.length;
for (var i = 0; i < setCount; i++) {
var setName = setNames[i];
var color = colorScheme[i%colorCount];
var le = this._renderElement(setName, color.toRGBString());
ul.appendChild(le);
}
return ul;
};
PlotKit.LegendRenderer.prototype._renderElement = function(title,
color) {
var le = MochiKit.DOM.createDOM("li");
le.style.listStyle="none";
le.style.margin="0 0 5px 0";
le.style.padding="0";
var box = MochiKit.DOM.createDOM("div");
box.style.backgroundColor=color;
box.style.width="2em";
box.style.height=".9em";
box.style.border="1px solid black";
box.style.margin="0 5px 0 0";
box.style.padding="0";
box.style.float="left";
box.style.cssFloat="left";
box.style.clear="left";
box.style.cssClear="left";
var span = MochiKit.DOM.createDOM("span");
MochiKit.DOM.appendChildNodes(span,
document.createTextNode(title));
MochiKit.DOM.appendChildNodes(le, box, span);
return le;
};
PlotKit.LegendRenderer.prototype._renderListTable =
function(colorScheme, setNames) {
var tabhead = THEAD(null);
var tabfoot = TFOOT(null);
var tabbody = partial(TBODY, null);
var i = 0;
var colorcount = colorScheme.length;
var tabrow;
var columns = this.options.tableColumns;
for (var label in setNames)
{
var legendcolor = colorScheme[i%colorcount];
var legendbox = DIV({'class': 'legendbox', 'className':
'legendbox'});
legendbox.style.width = "10px";
legendbox.style.height = "10px";
legendbox.style.backgroundColor = legendcolor.toHexString();
legendbox.style.borderWidth = "1px";
legendbox.style.borderStyle = "solid";
legendbox.style.borderColor = "#000000";
var boxcell = TD(null, legendbox);
var labelcell = TD({'class': 'legendlabel', 'className':
'legendlabel'}, setNames[i]);
labelcell.style.font = 'normal 10pt arial';
if (!(i % columns))
{
tabrow = partial(TR, null);
}
tabrow = partial(tabrow, boxcell, labelcell);
if (i % columns)
{
tabrow = tabrow(null);
tabbody = partial(tabbody, tabrow);
}
i++;
}
if ((setNames % columns))
{
tabrow = tabrow(TD(null), TD(null));
tabbody = partial(tabbody, tabrow);
}
tabbody = tabbody(null);
tab = TABLE({'class': 'legendcontainer', 'className':
'legendcontainer'}, tabhead, tabfoot, tabbody);
tab.style.marginTop = '1em';
tab.style.marginLeft = '1.5em';
tab.style.marginBottom = '1em';
tab.style.borderWidth = '1px';
tab.style.borderStyle = 'solid';
tab.style.borderColor = '#000000';
return tab;
};
// Namespace Iniitialisation
PlotKit.Legend = {}
PlotKit.Legend.LegendRenderer = PlotKit.LegendRenderer;
PlotKit.Legend.EXPORT = [
"LegendRenderer"
];
PlotKit.Legend.EXPORT_OK = [
"LegendRenderer"
];
PlotKit.Legend.__new__ = function() {
var m = MochiKit.Base;
m.nameFunctions(this);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
};
PlotKit.Legend.__new__();
MochiKit.Base._exportSymbols(this, PlotKit.Legend);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
module("luci.controller.livestats", package.seeall)
function index()
require("luci.i18n")
luci.i18n.loadc("livestats")
entry( {"admin", "status", "wifistat"}, template("livestats/wireless"), luci.i18n.translate("livestats_stat_wireless"), 90 ).i18n = "livestats"
entry( {"admin", "status", "trafstat"}, template("livestats/traffic"), luci.i18n.translate("livestats_stat_traffic"), 91 ).i18n = "livestats"
entry( {"admin", "status", "loadavg"}, template("livestats/loadavg"), luci.i18n.translate("livestats_stat_loadavg"), 92 ).i18n = "livestats"
entry( {"mini", "network", "wifistat"}, template("livestats/wireless"), luci.i18n.translate("livestats_stat_wireless"), 90 ).i18n = "livestats"
entry( {"mini", "network", "trafstat"}, template("livestats/traffic"), luci.i18n.translate("livestats_stat_traffic"), 91 ).i18n = "livestats"
entry( {"mini", "system", "loadavg"}, template("livestats/loadavg"), luci.i18n.translate("livestats_stat_loadavg"), 92 ).i18n = "livestats"
end

View File

@ -0,0 +1,8 @@
livestats_incoming = "eingehend"
livestats_outgoing = "ausgehend"
livestats_traffic = "Netzverkehr auf"
livestats_wifi = "Signal-Rauschabstand für"
livestats_loadavg = "Durchschnittliche Systemlast"
livestats_stat_wireless = "Echtzeit-Drahtlosstatus"
livestats_stat_traffic = "Echtzeit-Netzwerkverkehr"
livestats_stat_loadavg = "Echtzeit-Systemlast"

View File

@ -0,0 +1,8 @@
livestats_incoming = "incoming"
livestats_outgoing = "outgoing"
livestats_traffic = "traffic on"
livestats_wifi = "signal-to-noise ratio for"
livestats_loadavg = "load average"
livestats_stat_wireless = "Realtime Wireless Status"
livestats_stat_traffic = "Realtime Network Traffic"
livestats_stat_loadavg = "Realtime System Load"

View File

@ -0,0 +1,33 @@
<%+header%>
<!--[if IE]><script type="text/javascript" src="<%=resource%>/livestats/ExCanvas.js"></script><![endif]-->
<script type="text/javascript" src="<%=resource%>/livestats/MochiKit.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/JsonRpc.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/PlotKit.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/GraphRPC.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/Legend.js"></script>
<script type="text/javascript">
function initGraphs() {
var rpc = new GraphRPC(
document.getElementById('live_graphs'),
'<%=luci.dispatcher.build_url('rpc', 'sys')%>', 'loadavg',
2000,
// Data sources
[ 0, "1 min", 1, "5 min", 2, "15 min" ],
// Graph layout options
{ title: '<%:livestats_loadavg%>', strokeWidth: 2.5, shouldFill: false, strokeColor: null,
padding: { left: 70, right: 10, top: 10, bottom: 20 },
instances: [ false ], yAxis: [ 0, 2 ], drawBackground: false },
null,
'live_graphs'
);
}
MochiKit.DOM.addLoadEvent(initGraphs);
</script>
<div id="live_graphs"></div>
<%+footer%>

View File

@ -0,0 +1,66 @@
<%+header%>
<!--[if IE]><script type="text/javascript" src="<%=resource%>/livestats/ExCanvas.js"></script><![endif]-->
<script type="text/javascript" src="<%=resource%>/livestats/MochiKit.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/JsonRpc.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/PlotKit.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/GraphRPC.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/Legend.js"></script>
<%
local interfaces = { }
local ifnames = {}
local uci = luci.model.uci.cursor_state()
uci:foreach("network", "interface",
function(s)
if s.ifname ~= "lo" then
table.insert( interfaces,
"'" .. ( s.ifname or s['.name'] ) .. "'"
)
ifnames[s.ifname or s['.name']] = s['.name']
end
end
)
-%>
<script type="text/javascript">
function initGraphs() {
var rpc = new GraphRPC(
document.getElementById('live_graphs'),
'<%=luci.dispatcher.build_url('rpc', 'sys')%>', 'net.deviceinfo',
2000,
// Data sources
[ "0", "<%:livestats_incoming%> (kiB/s)", "8", "<%:livestats_outgoing%> (kiB/s)" ],
// Graph layout options
{
shouldFill: false,
drawBackground: false,
strokeColor: null,
title: '<%:livestats_traffic%> %s',
strokeWidth: 2.5, height: 140,
padding: { left: 70, right: 10, top: 10, bottom: 20 },
instances: [ <%=table.concat(interfaces, ", ") %> ],
instanceNames: {
<%- for iface, network in pairs(ifnames) do %>
<%-="%q:%q," % {iface, network}-%>
<% end %>
"0": ""
}},
// transform function
function (cur, last) {
return (cur - last) / 2048;
},
'live_graphs'
);
}
MochiKit.DOM.addLoadEvent(initGraphs);
</script>
<div id="live_graphs"></div>
<%+footer%>

View File

@ -0,0 +1,43 @@
<%+header%>
<!--[if IE]><script type="text/javascript" src="<%=resource%>/livestats/ExCanvas.js"></script><![endif]-->
<script type="text/javascript" src="<%=resource%>/livestats/MochiKit.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/JsonRpc.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/PlotKit.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/GraphRPC.js"></script>
<script type="text/javascript" src="<%=resource%>/livestats/Legend.js"></script>
<script type="text/javascript">
function initGraphs() {
var rpc = new GraphRPC(
document.getElementById('live_graphs'),
'<%=luci.dispatcher.build_url('rpc', 'sys')%>', 'wifi.getiwconfig',
1500,
// Data sources
[ function(data) {
return parseFloat(data["Signal level"])
- parseFloat(data["Noise level"]);
}, "S/N (dBm)"],
// Graph layout options
{ drawBackground: false, yAxis: [ 0, 50 ],
title: '<%:livestats_wifi%> %s',
padding: { left: 40, right: 10, top: 10, bottom: 20 },
instanceNames: {
<%- for k,v in pairs(luci.sys.wifi.getiwconfig()) do %>
<%-="%q:%q," % {k, "%s (%s)" % {k, tostring(v.ESSID)}}-%>
<% end %>
"0": ""
}},
null,
'live_graphs'
);
}
MochiKit.DOM.addLoadEvent(initGraphs);
</script>
<div id="live_graphs"></div>
<%+footer%>

View File

@ -428,6 +428,16 @@ define Package/luci-app-initmgr/install
$(call Package/luci/install/template,$(1),applications/luci-initmgr) $(call Package/luci/install/template,$(1),applications/luci-initmgr)
endef endef
define Package/luci-app-livestats
$(call Package/luci/webtemplate)
DEPENDS+=+luci-admin-core +luci-admin-rpc
TITLE:=LuCI Realtime Statistics
endef
define Package/luci-app-livestats/install
$(call Package/luci/install/template,$(1),applications/luci-livestats)
endef
#define Package/luci-app-polipo #define Package/luci-app-polipo
# $(call Package/luci/webtemplate) # $(call Package/luci/webtemplate)
# TITLE:=LuCI Support for the Polipo Proxy # TITLE:=LuCI Support for the Polipo Proxy
@ -622,6 +632,9 @@ endif
ifneq ($(CONFIG_PACKAGE_luci-app-initmgr),) ifneq ($(CONFIG_PACKAGE_luci-app-initmgr),)
PKG_SELECTED_MODULES+=applications/luci-initmgr PKG_SELECTED_MODULES+=applications/luci-initmgr
endif endif
ifneq ($(CONFIG_PACKAGE_luci-app-livestats),)
PKG_SELECTED_MODULES+=applications/luci-livestats
endif
#ifneq ($(CONFIG_PACKAGE_luci-app-polipo),) #ifneq ($(CONFIG_PACKAGE_luci-app-polipo),)
# PKG_SELECTED_MODULES+=applications/luci-polipo # PKG_SELECTED_MODULES+=applications/luci-polipo
#endif #endif
@ -698,6 +711,7 @@ $(eval $(call BuildPackage,luci-app-ushare))
$(eval $(call BuildPackage,luci-app-hd_idle)) $(eval $(call BuildPackage,luci-app-hd_idle))
$(eval $(call BuildPackage,luci-app-tinyproxy)) $(eval $(call BuildPackage,luci-app-tinyproxy))
$(eval $(call BuildPackage,luci-app-initmgr)) $(eval $(call BuildPackage,luci-app-initmgr))
$(eval $(call BuildPackage,luci-app-livestats))
#$(eval $(call BuildPackage,luci-app-polipo)) #$(eval $(call BuildPackage,luci-app-polipo))
$(eval $(call BuildPackage,luci-sgi-cgi)) $(eval $(call BuildPackage,luci-sgi-cgi))

View File

@ -15,7 +15,7 @@ config interface loopback
#### LAN configuration #### LAN configuration
config interface lan config interface lan
option type bridge option type bridge
option ifname "eth0.0" option ifname "eth0"
option proto static option proto static
option ipaddr 192.168.1.1 option ipaddr 192.168.1.1
option netmask 255.255.255.0 option netmask 255.255.255.0
@ -23,5 +23,5 @@ config interface lan
#### WAN configuration #### WAN configuration
config interface wan config interface wan
option ifname "eth0.1" option ifname "wlan0"
option proto dhcp option proto dhcp