HTML5 Canvas - sample gauge for smart home monitoring systems
Wrapper over HTML5 canvas for polar drawing (coordinates origin are in the centre of the canvas, the angle coordinate goes anti-clockwise, and the unitary magniture is the minimum of width and height of canvas) is attached.
Instantiation is:
var canvas=document.getElementById(dialName+"_z");
var drawing=new Drawing(canvas);
.
Sample usage (partial code) is in
Sample.js.
Result is:
:for(var sensorIdx=0;sensorIdx<sensors.length;sensorIdx++){
var dialName=sensors[sensorIdx];
var canvas=document.getElementById(dialName+"_z");
var drawing=new Drawing(canvas);
drawing.clear();
drawing.circle({w:0.5,r:1,fg:'#000',bg:'#448'});
drawing.circle({r:0.85,fg:'#111',bg:'#eee'});
drawing.line({w:4,fg:'#f00',from:{a:Math.PI/2,m:0},to:{a:Math.PI/2,m:0.98}});
drawing.line({w:2,fg:'#ff0',from:{a:Math.PI/2,m:0},to:{a:Math.PI/2,m:0.97}});
for(var hour=1;hour<=12;hour++){
drawing.line({w:0.25,fg:'#777',from:{x:0,y:0},to:{a:offsetA-Math.PI*2*(hour)/(12),m:0.85}});
drawing.text({a:offsetA-Math.PI*2*(hour)/(12),m:0.925,text:hour,size:0.125,fg:'#bbb'});
}
:
if(MOUSE_OVER){
if(dialName==MOUSE_OVER.sensor){
MOUSE_OVER.at=Math.atan2(-MOUSE_OVER.y+canvas.height/2,MOUSE_OVER.x-canvas.width/2);
while(MOUSE_OVER.at<0)
MOUSE_OVER.at+=2*Math.PI;
while(MOUSE_OVER.at>=2*Math.PI)
MOUSE_OVER.at-=2*Math.PI;
drawing.line({from:{a:0,m:0},to:{a:MOUSE_OVER.at,m:0.85},w:2,fg:'#f70'});
}
}
:
drawing.circle({w:0.5,r:0.4,fg:'#000',bg:'#dde'});
var params={};
drawing.text({x:0,y:1.2,text:allSensors[sensorProperties.name].label,size:0.2,align:'center',bg:'#000',fg:'#ff0'});
var lastPoint=null;
var tooltips=[];
for(var dataIdx=0;dataIdx<data.length;dataIdx++){
var x=data[dataIdx][0];
if(lastTS-x>1000000)continue;
if(!minTSIdx)minTSIdx=dataIdx;
if(data[minTSIdx][0]>x)
minTSIdx=dataIdx;
var y=data[dataIdx][1+json.sensor2column[sensorProperties.name]];
if(!data[dataIdx][1+json.sensor2column[sensorProperties.name]])continue;
if((x==null)||(y==null))continue;
x/=100;
var min=x%100;
var hour=((x-min)/100)%100;
var params={};
params.w=0.5+3*dataIdx/data.length*dataIdx/data.length;
params.from=lastPoint;
var chan=2.5+2.5*Math.sin(Math.PI*2*((12+6+hour-1)/24));
chan=Math.round(chan);
params.fg='rgba('+chan*255/5+',0,'+(5-chan)*255/5+','+(1)+')';
params.to={};
params.to.a=offsetA-2*Math.PI*(hour/12+min/12/60);
while(params.to.a<0)
params.to.a+=2*Math.PI;
while(params.to.a>=2*Math.PI)
params.to.a-=2*Math.PI;
params.to.m=(y-minVal)/(maxVal-minVal)*0.4+0.4;
params.y=y;
if(lastPoint){
drawing.line(params);
if(MOUSE_OVER)
if(dialName==MOUSE_OVER.sensor){
if(between(params.from.a,MOUSE_OVER.at,params.to.a)){
if(tooltips.length==2)
alert([params.from.a,MOUSE_OVER.at,params.to.a]);
tooltips.push(dataIdx);
}
}
}
lastPoint=params.to;
}
var rezolutie=allSensors[sensorProperties.name].resolution;
var actualValue=Math.round(params.y/rezolutie)*rezolutie;
var yesterdaysValue=Math.round(data[minTSIdx][colIdx]/rezolutie)*rezolutie;
actualValue=1*actualValue.toFixed(6);
yesterdaysValue=1*yesterdaysValue.toFixed(6);
var delta=actualValue-yesterdaysValue;
delta=1*delta.toFixed(6);
if(delta>0)
delta='+'+delta;
delta=delta+' ';
drawing.text({x:0,y:-0.34,text:minVal,size:0.1,bg:"#bbb"});
drawing.text({x:0,y:+0.34,text:maxVal,size:0.1,bg:"#bbb"});
if(actualValue>yesterdaysValue){
drawing.text({x:0,y:0.2,text:actualValue,size:0.25,align:'center',fg:params.fg,bg:params.fg});
drawing.text({x:0,y:0,text:delta+"↗",size:0.1,bg:"#f00",align:"center"});
drawing.text({x:0,y:-0.15,text:allSensors[sensorProperties.name].um,size:0.2,align:'center',fg:params.fg,bg:params.fg});
}else if(actualValue<yesterdaysValue){
drawing.text({x:0,y:0.2,text:actualValue,size:0.25,align:'center',fg:params.fg,bg:params.fg});
drawing.text({x:0,y:0,text:delta+"↘",size:0.1,bg:"#00f",align:"center"});
drawing.text({x:0,y:-0.15,text:allSensors[sensorProperties.name].um,size:0.2,align:'center',fg:params.fg,bg:params.fg});
}else{
drawing.text({x:0,y:0,text:actualValue+allSensors[sensorProperties.name].um,size:0.2,align:'center',fg:params.fg,bg:params.fg});
}