const PT_LEFT=10;
const PT_TOP=25;
const PT_WIDTH=140;
const PT_HEIGHT=140;
const Z_LEFT=160;
const Z_TOP=25;
const Z_WIDTH=24;
const Z_HEIGHT=140;
const PTZ_KNOB_SIZE=20
const kPtzLeft=1;
const kPtzRight=2;
const kPtzUp=3;
const kPtzDown=4;
const kPtzZoomIn=5;
const kPtzZoomOut=6;
const kPtzHome=7;
const kPtzUpLeft=8;
const kPtzUpRight=9;
const kPtzDownLeft=10;
const kPtzDownRight=11;
const kPtzPreset0=12;
const kPtzStopMoving=99;
const kPtzPresetSet0=112;
class PtzPicker{
constructor(){
this.div=document.getElementById('ptzDiv');
if(!this.div)return;
this.lastCmd={code:0,speed:0};
this.ptInProgress=false;
this.zInProgress=false;
this.div.onmousedown=(e)=>this.mouseDown(e);
this.div.onmousemove=(e)=>this.mouseMove(e);
this.title=AddElement(this.div,'span');
this.ptImg=AddElement(this.div,'img','left:'+PT_LEFT+'px;top:'+PT_TOP+'px;width:'+PT_WIDTH+'+px;height:'+PT_HEIGHT+'px;margin:0;');
this.ptImg.src='../img/ptz-pt.png';
this.ptImg.draggable=false;
this.zImg=AddElement(this.div,'img','left:'+Z_LEFT+'px;top:'+Z_TOP+'px;width:'+Z_WIDTH+'px;height:'+Z_HEIGHT+'px;margin:0;');
this.zImg.src='../img/ptz-z.png';
this.zImg.draggable=false;
this.ptKnob=AddElement(this.div,'img','width:'+PTZ_KNOB_SIZE+'px;height:'+PTZ_KNOB_SIZE+'px;margin:0;');
this.ptKnob.src='../img/ptz-knob.png';
this.ptKnob.draggable=false;
this.zKnob=AddElement(this.div,'img','width:'+PTZ_KNOB_SIZE+'px;height:'+PTZ_KNOB_SIZE+'px;margin:0;');
this.zKnob.src='../img/ptz-knob.png';
this.zKnob.draggable=false;
for(let i=0;i<5;i++){
let b=AddElement(this.div,'button','bottom:19px;left:'+(10+28*i)+'px;');
b.type='button';
b.id='preset'+i;
b.textContent=i+1;
b.onclick=(e)=>this.presetClick(e,kPtzPreset0+i);
}
for(let i=0;i<5;i++){
let b=AddElement(this.div,'button','bottom:4px;left:'+(10+28*i)+'px;');
b.type='button';
b.id='preset'+(i+5);
b.textContent=i+6;
b.onclick=(e)=>this.presetClick(e,kPtzPreset0+i+5);
}
let b=AddElement(this.div,'button','bottom:4px;width:23px;height:31px;left:160px;');
b.type='button';
b.innerHTML='<img src="../img/ptz-home.png" class="invertableImg">';
b.onclick=(e)=>this.presetClick(e,kPtzHome);
document.addEventListener('mouseup',()=>{
let cmd={code:kPtzStopMoving,speed:0};
if(this.ptInProgress || this.zInProgress)this.sendCommand(cmd);
if(this.ptInProgress){this.ptInProgress=false;this.setPtKnobPos(cmd);}
if(this.zInProgress){this.zInProgress=false;this.setZKnobPos(cmd);}
this.setButtonsEvents(false);
});
this.setCam(null);
this.setPtKnobPos(this.lastCmd);
this.setZKnobPos(this.lastCmd);
}
setCam(cam){
if(cam && cam.name)this.title.textContent=cam.name;
else this.title.textContent=Loc('(No Camera Selected)');
if(cam && cam.ptz && cam.perm&PERM_CAMCONTROL){
this.ptImg.style.opacity='';
this.zImg.style.opacity='';
this.ptKnob.style.display='';
this.zKnob.style.display='';
this.setButtonsState(false);
for(let i=0;i<10;i++)document.getElementById('preset'+i).title=cam.pnames[i];
this.cam=cam;
}else{
this.ptImg.style.opacity='60%';
this.zImg.style.opacity='60%';
this.ptKnob.style.display='none';
this.zKnob.style.display='none';
this.setButtonsState(true);
this.cam=null;
}
}
mouseDown(e){
this.ptInProgress=false;
this.zInProgress=false;
if(e.offsetX>=PT_LEFT && e.offsetX<PT_LEFT+PT_WIDTH && e.offsetY>PT_TOP && e.offsetY<PT_TOP+PT_HEIGHT){
this.ptInProgress=true;
this.setButtonsEvents(true);
this.mouseMove(e);
}else if(e.offsetX>=Z_LEFT && e.offsetX<Z_LEFT+Z_WIDTH && e.offsetY>Z_TOP && e.offsetY<Z_TOP+Z_HEIGHT){
this.zInProgress=true;
this.setButtonsEvents(true);
this.mouseMove(e);
}
}
mouseMove(e){
let cmd={code:0,speed:0};
if(this.ptInProgress){
let r_max=PT_WIDTH/2-2;
let x=Math.round(e.offsetX-PT_LEFT-PT_WIDTH/2);
let y=Math.round(e.offsetY-PT_TOP-PT_HEIGHT/2);
let r=Math.sqrt(x*x+y*y);
if(r>r_max)r=r_max;
cmd.speed=Math.round(100*r/r_max);
if(cmd.speed==0){
cmd.code=kPtzStopMoving;
}else if(x==0){
cmd.code=(y>0)?kPtzDown:kPtzUp;
}else{
let t=Math.atan(y/x);
if(t<-3*Math.PI/8)cmd.code=(x>0)?kPtzUp:kPtzDown;
else if(t<-1*Math.PI/8)cmd.code=(x>0)?kPtzUpRight:kPtzDownLeft;
else if(t< 1*Math.PI/8)cmd.code=(x>0)?kPtzRight:kPtzLeft;
else if(t< 3*Math.PI/8)cmd.code=(x>0)?kPtzDownRight:kPtzUpLeft;
else cmd.code=(x>0)?kPtzDown:kPtzUp;
}
this.sendCommand(cmd);
this.setPtKnobPos(cmd);
}else if(this.zInProgress){
let r=e.offsetY-Z_TOP-Z_HEIGHT/2;
cmd.code=(r<0)?kPtzZoomIn:kPtzZoomOut;
cmd.speed=Math.round(((r<0)?-1:1)*100*r/(Z_HEIGHT/2-PTZ_KNOB_SIZE/2-2));
if(cmd.speed==0)cmd.code=kPtzStopMoving;
else if(cmd.speed>100)cmd.speed=100;
this.sendCommand(cmd);
this.setZKnobPos(cmd);
}
}
setPtKnobPos(cmd){
let x=PT_LEFT+PT_WIDTH/2;
let y=PT_TOP+PT_HEIGHT/2;
let r=(PT_WIDTH/2-PTZ_KNOB_SIZE/2-2)*cmd.speed/100.0;
let r_sqrt2=r/Math.SQRT2;
switch(cmd.code)
{
case kPtzLeft:x-=r;break;
case kPtzRight:x+=r;break;
case kPtzUp:y-=r;break;
case kPtzDown:y+=r;break;
case kPtzUpRight:x+=r_sqrt2;y-=r_sqrt2;break;
case kPtzDownRight:x+=r_sqrt2;y+=r_sqrt2;break;
case kPtzUpLeft:x-=r_sqrt2;y-=r_sqrt2;break;
case kPtzDownLeft:x-=r_sqrt2;y+=r_sqrt2;break;
}
this.ptKnob.style.left=(x-PTZ_KNOB_SIZE/2)+'px';
this.ptKnob.style.top=(y-PTZ_KNOB_SIZE/2)+'px';
}
setZKnobPos(cmd){
let x=Z_LEFT+Z_WIDTH/2;
let y=Z_TOP+Z_HEIGHT/2;
let r=(Z_HEIGHT/2-PTZ_KNOB_SIZE/2-2)*cmd.speed/100.0;
switch(cmd.code)
{
case kPtzZoomIn:y-=r;break;
case kPtzZoomOut:y+=r;break;
}
this.zKnob.style.left=(x-PTZ_KNOB_SIZE/2)+'px';
this.zKnob.style.top=(y-PTZ_KNOB_SIZE/2)+'px';
}
setButtonsEvents(disabled){
for(let b of this.div.querySelectorAll('button'))b.style.pointerEvents=disabled?'none':'';
}
setButtonsState(disabled){
for(let b of this.div.querySelectorAll('button'))b.disabled=disabled;
}
presetClick(e,code){
if(this.cam){
if(code!=kPtzHome && e.altKey && this.cam.perm&PERM_PTZSET)code+=kPtzPresetSet0-kPtzPreset0;
this.sendCommand({code:code,speed:100,preset:1});
}
}
sendCommand(cmd){
if(this.cam && cmd.code &&(cmd.preset || cmd.code!=this.lastCmd.code || cmd.speed!=this.lastCmd.speed)){
fetch('ptzcommand?cameraNum='+this.cam.num+'&code='+cmd.code+'&speed='+cmd.speed,{credentials:'same-origin'});
this.lastCmd.code=cmd.code;
this.lastCmd.speed=cmd.speed;
}
}
}
