2024-08-16 04:52:46 +00:00
|
|
|
enum SequenceStatus {
|
|
|
|
IDLE,
|
|
|
|
RUNNING,
|
|
|
|
PAUSED
|
|
|
|
}
|
|
|
|
|
|
|
|
class Display {
|
|
|
|
private parentElement : HTMLUListElement;
|
|
|
|
private canvas : HTMLCanvasElement;
|
|
|
|
private ctx : CanvasRenderingContext2D;
|
|
|
|
private screen : any;
|
2024-08-18 01:22:17 +00:00
|
|
|
private sequence : boolean = false;
|
|
|
|
|
|
|
|
private offsetX : number = 0;
|
|
|
|
private offsetY : number = 0;
|
|
|
|
private width : number = 0;
|
|
|
|
private height : number = 0;
|
|
|
|
|
|
|
|
private canvasScale : number = 0;
|
|
|
|
private canvasWidth : number = 0;
|
|
|
|
private canvasHeight : number = 0;
|
|
|
|
private canvasOffsetX : number = 0;
|
|
|
|
private canvasOffsetY : number = 0;
|
|
|
|
|
|
|
|
private screenWidth : number = 0;
|
|
|
|
private screenHeight : number = 0;
|
|
|
|
private screenOffsetX : number = 0;
|
|
|
|
private screenOffsetY : number = 0;
|
|
|
|
|
|
|
|
private displayWidth : number = 0;
|
|
|
|
private displayHeight : number = 0;
|
|
|
|
private displayOffsetX : number = 0;
|
|
|
|
private displayOffsetY : number = 0;
|
|
|
|
|
2024-08-16 04:52:46 +00:00
|
|
|
constructor () {
|
|
|
|
this.parentElement = document.getElementById('display') as HTMLUListElement;
|
|
|
|
this.create();
|
2024-08-18 01:22:17 +00:00
|
|
|
window.onresize = this.onResize.bind(this);
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
|
|
|
private create () {
|
|
|
|
this.canvas = this.parentElement.getElementsByTagName('canvas')[0];
|
|
|
|
this.ctx = this.canvas.getContext('2d');
|
|
|
|
this.screen = {
|
|
|
|
width : parseInt((document.getElementById('width') as HTMLInputElement).value),
|
|
|
|
height : parseInt((document.getElementById('height') as HTMLInputElement).value)
|
|
|
|
}
|
|
|
|
this.updateSize();
|
2024-08-18 01:22:17 +00:00
|
|
|
this.clear();
|
|
|
|
this.updateScreen();
|
|
|
|
this.updateDisplay();
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
2024-08-18 01:22:17 +00:00
|
|
|
|
2024-08-16 04:52:46 +00:00
|
|
|
private updateSize () {
|
2024-08-18 01:22:17 +00:00
|
|
|
this.canvasScale = window.devicePixelRatio;
|
|
|
|
this.canvasWidth = this.parentElement.clientWidth - 12;
|
|
|
|
this.canvasHeight = this.parentElement.clientHeight - 12;
|
|
|
|
console.log(`${this.canvasWidth},${this.canvasHeight}`);
|
|
|
|
this.canvas.width = this.canvasWidth;
|
|
|
|
this.canvas.height = this.canvasHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
private clear () {
|
|
|
|
this.ctx.fillStyle = 'rgb(0, 0, 0)';
|
|
|
|
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
private updateScreen () {
|
|
|
|
const clientRatio : number = this.canvasWidth / this.canvasHeight;
|
2024-08-16 04:52:46 +00:00
|
|
|
const screenRatio : number = this.screen.width / this.screen.height;
|
2024-08-18 01:22:17 +00:00
|
|
|
|
2024-08-16 04:52:46 +00:00
|
|
|
if (screenRatio > clientRatio) {
|
2024-08-18 01:22:17 +00:00
|
|
|
this.screenWidth = this.canvasWidth - 2;
|
|
|
|
this.screenHeight = Math.floor(this.canvasWidth / screenRatio);
|
|
|
|
this.screenOffsetX = 1;
|
|
|
|
this.screenOffsetY = Math.round((this.canvasHeight - this.screenHeight) / 2);
|
2024-08-16 04:52:46 +00:00
|
|
|
} else {
|
2024-08-18 01:22:17 +00:00
|
|
|
this.screenWidth = Math.round(this.canvasHeight * screenRatio);
|
|
|
|
this.screenHeight = this.canvasHeight - 2;
|
|
|
|
this.screenOffsetY = 1;
|
|
|
|
this.screenOffsetX = Math.round((this.canvasWidth - this.screenWidth) / 2);
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
2024-08-18 01:22:17 +00:00
|
|
|
this.ctx.strokeStyle = 'rgb(0, 0, 255)';
|
|
|
|
this.ctx.rect(this.screenOffsetX, this.screenOffsetY, this.screenWidth, this.screenHeight);
|
2024-08-16 04:52:46 +00:00
|
|
|
this.ctx.stroke();
|
|
|
|
}
|
2024-08-18 01:22:17 +00:00
|
|
|
|
|
|
|
private updateDisplay () {
|
|
|
|
if (!this.sequence) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
console.log(this.sequence)
|
|
|
|
const screenScaleX : number = this.screenWidth / this.screen.width;
|
|
|
|
const screenScaleY : number = this.screenHeight / this.screen.height;
|
|
|
|
this.displayWidth = Math.round(this.width * screenScaleX);
|
|
|
|
this.displayHeight = Math.round(this.height * screenScaleY);
|
|
|
|
this.displayOffsetX = this.screenOffsetX + Math.round(this.offsetX * screenScaleX);
|
|
|
|
this.displayOffsetY = this.screenOffsetY + Math.round(this.offsetY * screenScaleY);
|
|
|
|
|
|
|
|
this.ctx.fillStyle = 'rgb(125, 125, 125)';
|
|
|
|
this.ctx.fillRect(this.displayOffsetX, this.displayOffsetY, this.displayWidth, this.displayHeight);
|
|
|
|
console.log(`${this.displayOffsetX}, ${this.displayOffsetY}, ${this.displayWidth}, ${this.displayHeight}`);
|
|
|
|
this.updateImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
private updateImage() {
|
|
|
|
const img : any = new Image;
|
|
|
|
img.onload = function () {
|
|
|
|
this.ctx.drawImage(img, this.displayOffsetX, this.displayOffsetY, this.displayWidth, this.displayHeight);
|
|
|
|
}.bind(this);
|
|
|
|
img.src = `/${this.displayWidth}/${this.displayHeight}/image.jpg`;
|
|
|
|
}
|
|
|
|
|
2024-08-16 04:52:46 +00:00
|
|
|
public update (msg : Message) {
|
|
|
|
|
|
|
|
}
|
2024-08-18 01:22:17 +00:00
|
|
|
|
|
|
|
public set (state : State) {
|
|
|
|
this.sequence = true;
|
|
|
|
this.offsetX = state.offset.x;
|
|
|
|
this.offsetY = state.offset.y;
|
|
|
|
this.width = state.display.width;
|
|
|
|
this.height = state.display.height;
|
|
|
|
this.updateDisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
private onResize (event : any) {
|
|
|
|
this.updateSize();
|
|
|
|
this.clear();
|
|
|
|
this.updateScreen();
|
|
|
|
this.updateDisplay();
|
|
|
|
}
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
|
|
|
|
2024-05-15 21:29:59 +00:00
|
|
|
class Client {
|
2024-08-16 04:52:46 +00:00
|
|
|
private display : Display;
|
2024-05-15 21:29:59 +00:00
|
|
|
private client : WebSocket;
|
|
|
|
private connected : boolean = false;
|
2024-07-12 13:51:39 +00:00
|
|
|
private progress : HTMLProgressElement;
|
|
|
|
|
2024-05-15 21:29:59 +00:00
|
|
|
constructor () {
|
|
|
|
let uri : string = 'ws://localhost:8082';
|
2024-07-12 13:51:39 +00:00
|
|
|
this.progress = document.getElementById('progress') as HTMLProgressElement;
|
2024-05-15 21:29:59 +00:00
|
|
|
this.client = new WebSocket(uri);
|
2024-08-16 04:52:46 +00:00
|
|
|
this.display = new Display();
|
2024-05-15 21:29:59 +00:00
|
|
|
this.client.onopen = this.onOpen.bind(this);
|
2024-08-15 02:43:02 +00:00
|
|
|
this.client.onclose = this.onClose.bind(this);
|
2024-05-15 21:29:59 +00:00
|
|
|
this.client.onmessage = this.onMessage.bind(this);
|
2024-08-16 04:52:46 +00:00
|
|
|
(document.getElementById('sequenceForm') as HTMLFormElement ).reset();
|
|
|
|
(document.getElementById('sequenceCtrlForm') as HTMLFormElement ).reset();
|
|
|
|
(document.getElementById('manualCtrlForm') as HTMLFormElement ).reset();
|
|
|
|
this.disableClass('sequenceCtrl');
|
|
|
|
this.disableClass('manualCtrl');
|
2024-05-15 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private onMessage (event : any) {
|
2024-07-13 13:23:58 +00:00
|
|
|
const msg : Message = JSON.parse(event.data) as Message;
|
2024-08-16 04:52:46 +00:00
|
|
|
if (typeof msg.cmd !== 'undefined' && msg.cmd !== null) {
|
2024-08-02 14:29:12 +00:00
|
|
|
this.cmd(msg);
|
2024-07-12 13:51:39 +00:00
|
|
|
}
|
2024-05-15 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private onOpen (event : any) {
|
|
|
|
console.log('Connected');
|
|
|
|
this.connected = true;
|
2024-08-15 02:43:02 +00:00
|
|
|
this.active();
|
2024-08-16 04:52:46 +00:00
|
|
|
this.enableClass('manualCtrl');
|
2024-08-15 02:43:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private onClose (event : any) {
|
|
|
|
console.log('Disconnected');
|
|
|
|
this.connected = false;
|
|
|
|
this.inactive();
|
2024-05-15 21:29:59 +00:00
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
|
2024-08-16 04:52:46 +00:00
|
|
|
private setSequence(state : State) {
|
|
|
|
this.setProgress(state.sequence);
|
|
|
|
this.setStatus(state.sequence);
|
|
|
|
this.setDisplay(state);
|
|
|
|
(document.getElementById('sequence') as HTMLSelectElement ).value = state.sequence.hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
private setStatus (sequence : SequenceState) {
|
|
|
|
let status : string;
|
|
|
|
switch (sequence.status) {
|
|
|
|
case SequenceStatus.IDLE :
|
|
|
|
status = 'Idle';
|
|
|
|
break;
|
|
|
|
case SequenceStatus.RUNNING :
|
|
|
|
status = 'Running';
|
|
|
|
break;
|
|
|
|
case SequenceStatus.PAUSED :
|
|
|
|
status = 'Paused';
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
status = 'Unknown State';
|
|
|
|
}
|
|
|
|
document.getElementById('sequenceStatus').innerText = status;
|
|
|
|
document.getElementById('sequenceName').innerText = sequence.name;
|
|
|
|
document.getElementById('sequenceLength').innerText = `Sequence Length: ${sequence.frames}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
private setProgress (sequence : SequenceState) {
|
2024-07-12 13:51:39 +00:00
|
|
|
const percent : number = sequence.progress * 100.0;
|
2024-08-16 04:52:46 +00:00
|
|
|
if (this.progress !== null) {
|
|
|
|
this.progress.value = percent;
|
|
|
|
this.progress.innerText = `${Math.floor(percent)}%`;
|
|
|
|
}
|
|
|
|
document.getElementById('sequenceProgress').innerText = `Progress: ${Math.round(sequence.progress)}%`;
|
|
|
|
}
|
|
|
|
|
|
|
|
private setDisplay (state : State) {
|
2024-08-18 13:10:37 +00:00
|
|
|
const widthEl : HTMLInputElement = document.getElementById('displayWidth') as HTMLInputElement;
|
|
|
|
const heightEl : HTMLInputElement = document.getElementById('displayHeight') as HTMLInputElement;
|
|
|
|
|
|
|
|
widthEl.value = state.display.width as any;
|
|
|
|
heightEl.value = state.display.height as any;
|
|
|
|
|
|
|
|
widthEl.readOnly = false;
|
|
|
|
heightEl.readOnly = false;
|
|
|
|
//console.dir(state);
|
2024-08-18 01:22:17 +00:00
|
|
|
this.display.set(state);
|
2024-08-18 13:10:37 +00:00
|
|
|
|
2024-07-12 13:51:39 +00:00
|
|
|
}
|
2024-07-13 02:00:24 +00:00
|
|
|
|
2024-08-02 14:29:12 +00:00
|
|
|
private cmd (msg : Message) {
|
|
|
|
switch (msg.cmd) {
|
2024-07-13 13:23:58 +00:00
|
|
|
case 'open' :
|
|
|
|
this.receiveCameraOpen();
|
|
|
|
break;
|
2024-08-01 15:57:49 +00:00
|
|
|
case 'close' :
|
|
|
|
this.receiveCameraClose();
|
|
|
|
break;
|
2024-08-02 14:29:12 +00:00
|
|
|
case 'select' :
|
|
|
|
this.receiveSelect(msg);
|
2024-08-09 20:20:07 +00:00
|
|
|
break;
|
2024-07-13 13:23:58 +00:00
|
|
|
default:
|
2024-08-09 20:20:07 +00:00
|
|
|
console.warn(`No command "${msg.cmd}"`);
|
2024-07-13 13:23:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-09 20:20:07 +00:00
|
|
|
public disableClass (className : string) {
|
2024-08-15 22:55:37 +00:00
|
|
|
console.log(`Disabling class: ${className}`);
|
2024-08-09 20:20:07 +00:00
|
|
|
document.querySelectorAll(`.${className}`).forEach((el : HTMLButtonElement) => {
|
|
|
|
el.disabled = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public enableClass (className : string) {
|
2024-08-15 22:55:37 +00:00
|
|
|
console.log(`Enabling class: ${className}`);
|
2024-08-09 20:20:07 +00:00
|
|
|
document.querySelectorAll(`.${className}`).forEach((el : HTMLButtonElement) => {
|
|
|
|
el.disabled = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-07-13 13:23:58 +00:00
|
|
|
public sendCameraOpen () {
|
|
|
|
console.log('send camera open');
|
2024-08-09 20:20:07 +00:00
|
|
|
this.disableClass('manualCtrl');
|
2024-07-13 02:00:24 +00:00
|
|
|
this.client.send(JSON.stringify({ cmd : 'open' }));
|
|
|
|
}
|
2024-07-13 13:23:58 +00:00
|
|
|
|
|
|
|
private receiveCameraOpen () {
|
|
|
|
console.log('got camera open');
|
2024-08-09 20:20:07 +00:00
|
|
|
this.enableClass('manualCtrl');
|
2024-07-13 13:23:58 +00:00
|
|
|
}
|
2024-08-01 15:57:49 +00:00
|
|
|
|
|
|
|
public sendCameraClose () {
|
|
|
|
console.log('send camera close');
|
2024-08-09 20:20:07 +00:00
|
|
|
this.disableClass('manualCtrl');
|
2024-08-01 15:57:49 +00:00
|
|
|
this.client.send(JSON.stringify({ cmd : 'close' }));
|
|
|
|
}
|
|
|
|
|
|
|
|
private receiveCameraClose () {
|
|
|
|
console.log('got camera close');
|
2024-08-09 20:20:07 +00:00
|
|
|
this.enableClass('manualCtrl');
|
2024-08-01 15:57:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public sendSelect () {
|
2024-08-16 04:52:46 +00:00
|
|
|
const hash : string = (document.getElementById('sequence') as HTMLSelectElement ).value;
|
2024-08-01 15:57:49 +00:00
|
|
|
let msg : Message;
|
2024-08-16 04:52:46 +00:00
|
|
|
if (hash === '- Select Image Sequence -') {
|
2024-08-01 15:57:49 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-08-16 04:52:46 +00:00
|
|
|
msg = { cmd : 'select', state : { sequence : { hash } } };
|
2024-08-01 15:57:49 +00:00
|
|
|
console.log('send select');
|
2024-08-16 04:52:46 +00:00
|
|
|
console.log(hash)
|
2024-08-01 15:57:49 +00:00
|
|
|
this.client.send(JSON.stringify(msg));
|
|
|
|
}
|
|
|
|
|
2024-08-02 14:29:12 +00:00
|
|
|
private receiveSelect (msg : Message) {
|
2024-08-09 20:20:07 +00:00
|
|
|
console.log('got select');
|
2024-08-15 02:43:02 +00:00
|
|
|
console.dir(msg);
|
2024-08-16 04:52:46 +00:00
|
|
|
this.enableClass('sequenceCtrl');
|
|
|
|
this.setSequence(msg.state);
|
|
|
|
}
|
|
|
|
|
|
|
|
private receiveUpdate (msg : Message) {
|
|
|
|
|
2024-08-02 14:29:12 +00:00
|
|
|
}
|
|
|
|
|
2024-08-01 15:57:49 +00:00
|
|
|
public fullscreen () {
|
|
|
|
if (!document.fullscreenElement) {
|
|
|
|
document.documentElement.requestFullscreen();
|
|
|
|
} else {
|
|
|
|
this.exitFullscreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public exitFullscreen () {
|
|
|
|
if (document.fullscreenElement) {
|
|
|
|
document.exitFullscreen()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-15 02:43:02 +00:00
|
|
|
private active () {
|
|
|
|
document.getElementById('overlay').classList.add('active');
|
|
|
|
}
|
|
|
|
private inactive () {
|
|
|
|
document.getElementById('overlay').classList.remove('active');
|
|
|
|
}
|
2024-05-15 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
2024-07-13 02:00:24 +00:00
|
|
|
const client : Client = new Client();
|