Established several improvments: disabled buttons work more like expected. Started a display UI feature for showing the screen vs the image.

This commit is contained in:
Matt McWilliams 2024-08-16 00:52:46 -04:00
parent 3291201e34
commit 9d27d59e29
25 changed files with 545 additions and 87 deletions

29
browser/globals.d.ts vendored
View File

@ -1,18 +1,33 @@
interface StateDimensions {
width? : number,
height? : number
}
interface StateOffset {
x? : number,
y? : number
}
interface SequenceState { interface SequenceState {
hash : string, hash : string,
name : string, name? : string,
progress : number, progress? : number,
current? : number current? : number,
frames? : number,
status? : any
} }
interface State { interface State {
width? : number, display? : StateDimensions,
height? : number, offset? : StateOffset,
sequence? : SequenceState source? : StateDimensions,
screen? : StateDimensions,
sequence? : SequenceState,
exposure? : number
} }
interface Message { interface Message {
cmd? : string; cmd? : string;
state? : State; state? : State;
sequence? : string;
} }

View File

@ -1,4 +1,58 @@
enum SequenceStatus {
IDLE,
RUNNING,
PAUSED
}
class Display {
private parentElement : HTMLUListElement;
private canvas : HTMLCanvasElement;
private ctx : CanvasRenderingContext2D;
private screen : any;
constructor () {
this.parentElement = document.getElementById('display') as HTMLUListElement;
this.create();
}
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();
}
private updateSize () {
const w : number = this.parentElement.clientWidth - 12;
const h : number = this.parentElement.clientHeight - 12;
const clientRatio : number = w / h;
const screenRatio : number = this.screen.width / this.screen.height;
let val : number;
let offset : number;
console.log(`${w},${h}`);
this.canvas.width = w;
this.canvas.height = h;
this.ctx.strokeStyle = "rgb(0, 0, 255)";
if (screenRatio > clientRatio) {
val = Math.floor(w / screenRatio);
offset = Math.round((h - val) / 2);
this.ctx.rect(0, offset + 1, w, val);
} else {
val = Math.round(h * screenRatio);
offset = Math.round((w - val) / 2);
this.ctx.rect(offset, 1, val, h - 1);
}
this.ctx.stroke();
}
public update (msg : Message) {
}
}
class Client { class Client {
private display : Display;
private client : WebSocket; private client : WebSocket;
private connected : boolean = false; private connected : boolean = false;
private progress : HTMLProgressElement; private progress : HTMLProgressElement;
@ -7,16 +61,20 @@ class Client {
let uri : string = 'ws://localhost:8082'; let uri : string = 'ws://localhost:8082';
this.progress = document.getElementById('progress') as HTMLProgressElement; this.progress = document.getElementById('progress') as HTMLProgressElement;
this.client = new WebSocket(uri); this.client = new WebSocket(uri);
this.display = new Display();
this.client.onopen = this.onOpen.bind(this); this.client.onopen = this.onOpen.bind(this);
this.client.onclose = this.onClose.bind(this); this.client.onclose = this.onClose.bind(this);
this.client.onmessage = this.onMessage.bind(this); this.client.onmessage = this.onMessage.bind(this);
(document.getElementById('sequenceForm') as HTMLFormElement ).reset();
(document.getElementById('sequenceCtrlForm') as HTMLFormElement ).reset();
(document.getElementById('manualCtrlForm') as HTMLFormElement ).reset();
this.disableClass('sequenceCtrl');
this.disableClass('manualCtrl');
} }
private onMessage (event : any) { private onMessage (event : any) {
const msg : Message = JSON.parse(event.data) as Message; const msg : Message = JSON.parse(event.data) as Message;
if (typeof msg.state !== 'undefined' && msg.state.sequence !== null) { if (typeof msg.cmd !== 'undefined' && msg.cmd !== null) {
this.setSequence(msg.state.sequence);
} else if (typeof msg.cmd !== 'undefined' && msg.cmd !== null) {
this.cmd(msg); this.cmd(msg);
} }
} }
@ -25,6 +83,7 @@ class Client {
console.log('Connected'); console.log('Connected');
this.connected = true; this.connected = true;
this.active(); this.active();
this.enableClass('manualCtrl');
} }
private onClose (event : any) { private onClose (event : any) {
@ -33,10 +92,44 @@ class Client {
this.inactive(); this.inactive();
} }
private setSequence(sequence : SequenceState) { 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) {
const percent : number = sequence.progress * 100.0; const percent : number = sequence.progress * 100.0;
this.progress.value = percent; if (this.progress !== null) {
this.progress.innerText = `${Math.floor(percent)}%`; this.progress.value = percent;
this.progress.innerText = `${Math.floor(percent)}%`;
}
document.getElementById('sequenceProgress').innerText = `Progress: ${Math.round(sequence.progress)}%`;
}
private setDisplay (state : State) {
console.dir(state);
} }
private cmd (msg : Message) { private cmd (msg : Message) {
@ -93,22 +186,26 @@ class Client {
} }
public sendSelect () { public sendSelect () {
const sequence : string = (document.getElementById('sequence') as HTMLSelectElement ).value; const hash : string = (document.getElementById('sequence') as HTMLSelectElement ).value;
let msg : Message; let msg : Message;
if (sequence === '- Select Image Sequence -') { if (hash === '- Select Image Sequence -') {
return; return;
} }
msg = { cmd : 'select', sequence }; msg = { cmd : 'select', state : { sequence : { hash } } };
console.log('send select'); console.log('send select');
console.log(sequence) console.log(hash)
this.client.send(JSON.stringify(msg)); this.client.send(JSON.stringify(msg));
} }
private receiveSelect (msg : Message) { private receiveSelect (msg : Message) {
console.log('got select'); console.log('got select');
console.dir(msg); console.dir(msg);
(document.getElementById('sequence') as HTMLSelectElement ).value = msg.sequence; this.enableClass('sequenceCtrl');
//this.enableClass('sequenceCtrl'); this.setSequence(msg.state);
}
private receiveUpdate (msg : Message) {
} }
public fullscreen () { public fullscreen () {

View File

@ -16,5 +16,6 @@ export declare class Display {
setSource(width: number, height: number): void; setSource(width: number, height: number): void;
getDimensions(): fdOutgoingPosition; getDimensions(): fdOutgoingPosition;
getScreen(): Dimensions; getScreen(): Dimensions;
getSource(): Dimensions;
} }
export type { Dimensions }; export type { Dimensions };

View File

@ -46,6 +46,9 @@ class Display {
getScreen() { getScreen() {
return this.screen; return this.screen;
} }
getSource() {
return this.source;
}
} }
exports.Display = Display; exports.Display = Display;
module.exports = { Display }; module.exports = { Display };

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/display/index.ts"],"names":[],"mappings":";;;AAEA,MAAM,UAAU;IAIf,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;CACD;AAOD,MAAa,OAAO;IAQnB,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAG,CAAC,EAAE,CAAA;IAC9B,CAAC;IAEM,UAAU,CAAE,CAAU;QAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAEM,UAAU,CAAE,CAAU;QAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAEM,SAAS,CAAE,KAAc,EAAE,MAAe;QAChD,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;YACrD,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACzG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YAClD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAG,CAAC,EAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QACrD,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3G,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YAChD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAG,CAAC,EAAG,CAAC,EAAE,CAAC;QACrD,CAAC;IACF,CAAC;IAEM,aAAa;QACnB,OAAO;YACN,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,KAAK;YACtB,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,MAAM;YACvB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YACjB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;SACjB,CAAA;IACF,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;CACD;AA/CD,0BA+CC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/display/index.ts"],"names":[],"mappings":";;;AAEA,MAAM,UAAU;IAIf,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;CACD;AAOD,MAAa,OAAO;IAQnB,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAG,CAAC,EAAE,CAAA;IAC9B,CAAC;IAEM,UAAU,CAAE,CAAU;QAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAEM,UAAU,CAAE,CAAU;QAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAEM,SAAS,CAAE,KAAc,EAAE,MAAe;QAChD,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;YACrD,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACzG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YAClD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAG,CAAC,EAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QACrD,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3G,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;YAChD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAG,CAAC,EAAG,CAAC,EAAE,CAAC;QACrD,CAAC;IACF,CAAC;IAEM,aAAa;QACnB,OAAO;YACN,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,KAAK;YACtB,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,MAAM;YACvB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YACjB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;SACjB,CAAA;IACF,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;CACD;AAnDD,0BAmDC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}

6
dist/globals.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare enum SequenceStatus {
IDLE = 0,
RUNNING = 1,
PAUSED = 2
}
export type { SequenceStatus };

9
dist/globals.js vendored Normal file
View File

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var SequenceStatus;
(function (SequenceStatus) {
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
})(SequenceStatus || (SequenceStatus = {}));
//# sourceMappingURL=globals.js.map

1
dist/globals.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"globals.js","sourceRoot":"","sources":["../src/globals.ts"],"names":[],"mappings":";;AAAA,IAAK,cAIJ;AAJD,WAAK,cAAc;IACjB,mDAAI,CAAA;IACJ,yDAAO,CAAA;IACP,uDAAM,CAAA;AACR,CAAC,EAJI,cAAc,KAAd,cAAc,QAIlB"}

5
dist/index.js vendored
View File

@ -173,6 +173,7 @@ function onWssConnection(ws, req) {
ws.ip = ip; ws.ip = ip;
ws.session = (0, uuid_1.v4)(); ws.session = (0, uuid_1.v4)();
ws.on('message', function (data) { onClientMessage(data, ws); }); ws.on('message', function (data) { onClientMessage(data, ws); });
sequence.updateClients();
} }
async function onClientMessage(data, ws) { async function onClientMessage(data, ws) {
let msg = null; let msg = null;
@ -196,7 +197,7 @@ async function cmd(msg) {
await cameraClose(); await cameraClose();
break; break;
case 'select': case 'select':
await select(msg.sequence); await select(msg.state.sequence.hash);
break; break;
default: default:
log.warn(`No matching command: ${msg.cmd}`); log.warn(`No matching command: ${msg.cmd}`);
@ -232,6 +233,8 @@ app.get('/', async (req, res, next) => {
const html = index({ sequences: sequencesArr, width, height }); const html = index({ sequences: sequencesArr, width, height });
res.send(html); res.send(html);
}); });
app.get('/image.jpg', async (req, res, next) => {
});
async function main() { async function main() {
await settings(); await settings();
index = await createTemplate('./views/index.hbs'); index = await createTemplate('./views/index.hbs');

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -3,6 +3,11 @@ import type { FD } from '../fd';
import type { Camera } from '../camera'; import type { Camera } from '../camera';
import type { Display } from '../display'; import type { Display } from '../display';
import type { FFPROBE } from '../ffprobe'; import type { FFPROBE } from '../ffprobe';
declare enum SequenceStatus {
IDLE = 0,
RUNNING = 1,
PAUSED = 2
}
export declare class Sequence { export declare class Sequence {
private log; private log;
private current; private current;
@ -12,16 +17,25 @@ export declare class Sequence {
private display; private display;
private ffprobe; private ffprobe;
private fd; private fd;
private running;
private progress;
private frames;
private send; private send;
private running;
private paused;
private progress;
private frame;
private frames;
private exposure;
constructor(camera: Camera, fd: FD, display: Display, ffprobe: FFPROBE, send: Function); constructor(camera: Camera, fd: FD, display: Display, ffprobe: FFPROBE, send: Function);
start(): void; start(): void;
stop(): void; stop(): void;
isRunning(): boolean; isRunning(): boolean;
load(seq: SequenceObject): void; load(seq: SequenceObject): Promise<void>;
updateClients(): void;
private enumerate; private enumerate;
unload(): void; unload(): void;
getState(): SequenceState; getState(): State;
getSequenceState(): SequenceState;
setExposure(ms: number): void;
getStatus(): SequenceStatus;
getCurrent(): string;
} }
export {};

View File

@ -3,11 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.Sequence = void 0; exports.Sequence = void 0;
const files_1 = require("../files"); const files_1 = require("../files");
const log_1 = require("../log"); const log_1 = require("../log");
var SequenceStatus;
(function (SequenceStatus) {
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
})(SequenceStatus || (SequenceStatus = {}));
class Sequence { class Sequence {
constructor(camera, fd, display, ffprobe, send) { constructor(camera, fd, display, ffprobe, send) {
this.current = null; this.current = null;
this.info = null; this.info = null;
this.images = []; this.images = [];
this.running = false;
this.paused = false;
this.progress = 0;
this.frame = 0;
this.frames = 0;
this.exposure = 1000;
this.log = (0, log_1.createLog)('seq'); this.log = (0, log_1.createLog)('seq');
this.camera = camera; this.camera = camera;
this.fd = fd; this.fd = fd;
@ -24,10 +36,17 @@ class Sequence {
isRunning() { isRunning() {
return this.running; return this.running;
} }
load(seq) { async load(seq) {
this.current = seq; this.current = seq;
this.enumerate(); this.frame = 0;
this.send({ cmd: 'select', sequence: seq.hash }); this.progress = 0;
await this.enumerate();
this.updateClients();
}
updateClients() {
if (this.current !== null) {
this.send({ cmd: 'select', state: this.getState() });
}
} }
async enumerate() { async enumerate() {
let screen; let screen;
@ -42,8 +61,9 @@ class Sequence {
this.log.error(`Error enumerating images in sequence: ${this.current.name}`, err); this.log.error(`Error enumerating images in sequence: ${this.current.name}`, err);
return; return;
} }
this.frames = this.images.length;
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`); this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
if (this.images.length > 0) { if (this.frames > 0) {
this.info = await this.ffprobe.info(this.images[0].path); this.info = await this.ffprobe.info(this.images[0].path);
} }
if (this.info !== null) { if (this.info !== null) {
@ -60,12 +80,56 @@ class Sequence {
this.images = []; this.images = [];
} }
getState() { getState() {
const dimensions = this.display.getDimensions();
const source = this.display.getSource();
const screen = this.display.getScreen();
return {
display: {
width: dimensions.w,
height: dimensions.h
},
offset: {
x: dimensions.x,
y: dimensions.y
},
screen,
source,
sequence: {
hash: this.current.hash,
name: this.current.name,
progress: this.progress,
current: this.frame,
frames: this.frames,
status: this.getStatus()
},
exposure: this.exposure
};
}
getSequenceState() {
return { return {
hash: this.current.hash, hash: this.current.hash,
name: this.current.name, name: this.current.name,
progress: this.progress progress: this.progress
}; };
} }
setExposure(ms) {
this.exposure = ms;
}
getStatus() {
if (this.running && this.paused) {
return SequenceStatus.PAUSED;
}
else if (this.running && !this.paused) {
return SequenceStatus.RUNNING;
}
return SequenceStatus.IDLE;
}
getCurrent() {
if (this.current !== null && this.images.length > 0 && typeof this.images[this.frame] !== 'undefined') {
this.images[this.frame];
}
return null;
}
} }
exports.Sequence = Sequence; exports.Sequence = Sequence;
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":";;;AAAA,oCAAiC;AACjC,gCAAkC;AAQlC,MAAa,QAAQ;IAcpB,YAAa,MAAe,EAAE,EAAO,EAAE,OAAgB,EAAE,OAAiB,EAAE,IAAe;QAZnF,YAAO,GAAoB,IAAI,CAAC;QAChC,SAAI,GAAe,IAAI,CAAC;QACxB,WAAM,GAAmB,EAAE,CAAC;QAWnC,IAAI,CAAC,GAAG,GAAG,IAAA,eAAS,EAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAEM,IAAI,CAAE,GAAoB;QAChC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAG,QAAQ,EAAE,QAAQ,EAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAEO,KAAK,CAAC,SAAS;QACtB,IAAI,MAAmB,CAAC;QACxB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAG,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,CAAC,MAAM,GAAG,MAAM,aAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,yCAAyC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAClF,OAAO;QACR,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,MAAM,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAE1H,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,CAAA;QAC5E,CAAC;IACF,CAAC;IAEM,MAAM;QACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IAClB,CAAC;IAEM,QAAQ;QACd,OAAO;YACN,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,QAAQ,EAAG,IAAI,CAAC,QAAQ;SACxB,CAAA;IACF,CAAC;CACD;AAlFD,4BAkFC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":"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"}

View File

@ -66,6 +66,10 @@ export class Display {
public getScreen () : Dimensions { public getScreen () : Dimensions {
return this.screen; return this.screen;
} }
public getSource () : Dimensions {
return this.source;
}
} }
module.exports = { Display }; module.exports = { Display };

29
src/globals.d.ts vendored
View File

@ -1,18 +1,33 @@
interface StateDimensions {
width? : number,
height? : number
}
interface StateOffset {
x? : number,
y? : number
}
interface SequenceState { interface SequenceState {
hash : string, hash : string,
name : string, name? : string,
progress : number, progress? : number,
current? : number current? : number,
frames? : number,
status? : any
} }
interface State { interface State {
width? : number, display? : StateDimensions,
height? : number, offset? : StateOffset,
sequence? : SequenceState source? : StateDimensions,
screen? : StateDimensions,
sequence? : SequenceState,
exposure? : number
} }
interface Message { interface Message {
cmd? : string; cmd? : string;
state? : State; state? : State;
sequence? : string;
} }

View File

@ -162,6 +162,7 @@ function onWssConnection (ws : WebSocketExtended, req : Request) {
ws.ip = ip; ws.ip = ip;
ws.session = uuid(); ws.session = uuid();
ws.on('message', function (data) { onClientMessage(data, ws) }); ws.on('message', function (data) { onClientMessage(data, ws) });
sequence.updateClients();
} }
async function onClientMessage (data : any, ws : WebSocket) { async function onClientMessage (data : any, ws : WebSocket) {
@ -186,7 +187,7 @@ async function cmd (msg : Message) {
await cameraClose(); await cameraClose();
break; break;
case 'select' : case 'select' :
await select(msg.sequence); await select(msg.state.sequence.hash);
break; break;
default : default :
log.warn(`No matching command: ${msg.cmd}`); log.warn(`No matching command: ${msg.cmd}`);
@ -228,6 +229,10 @@ app.get('/', async (req : Request, res : Response, next : NextFunction) => {
res.send(html); res.send(html);
}); });
app.get('/image.jpg', async (req : Request, res : Response, next : NextFunction) => {
});
async function main () { async function main () {
await settings(); await settings();
index = await createTemplate('./views/index.hbs'); index = await createTemplate('./views/index.hbs');

View File

@ -2,11 +2,17 @@ import { Files } from '../files';
import { createLog } from '../log' import { createLog } from '../log'
import type { Logger } from 'winston'; import type { Logger } from 'winston';
import type { SequenceObject, ImageObject } from '../files'; import type { SequenceObject, ImageObject } from '../files';
import type { FD } from '../fd'; import type { FD, fdOutgoingPosition } from '../fd';
import type { Camera } from '../camera'; import type { Camera } from '../camera';
import type { Display, Dimensions } from '../display'; import type { Display, Dimensions } from '../display';
import type { FFPROBE, VideoInfo } from '../ffprobe'; import type { FFPROBE, VideoInfo } from '../ffprobe';
enum SequenceStatus {
IDLE,
RUNNING,
PAUSED
}
export class Sequence { export class Sequence {
private log : Logger; private log : Logger;
private current : SequenceObject = null; private current : SequenceObject = null;
@ -16,10 +22,15 @@ export class Sequence {
private display : Display; private display : Display;
private ffprobe : FFPROBE; private ffprobe : FFPROBE;
private fd : FD; private fd : FD;
private running : boolean;
private progress : number;
private frames : number;
private send : Function; private send : Function;
private running : boolean = false;
private paused : boolean = false;
private progress : number = 0;
private frame : number = 0;
private frames : number = 0;
private exposure : number = 1000;
constructor (camera : Camera, fd : FD, display: Display, ffprobe : FFPROBE, send : Function) { constructor (camera : Camera, fd : FD, display: Display, ffprobe : FFPROBE, send : Function) {
this.log = createLog('seq'); this.log = createLog('seq');
@ -42,14 +53,23 @@ export class Sequence {
return this.running; return this.running;
} }
public load (seq : SequenceObject) { public async load (seq : SequenceObject) {
this.current = seq; this.current = seq;
this.enumerate(); this.frame = 0;
this.send({ cmd : 'select', sequence : seq.hash }); this.progress = 0;
await this.enumerate();
this.updateClients();
}
public updateClients () {
if (this.current !== null) {
this.send({ cmd : 'select', state : this.getState() });
}
} }
private async enumerate () { private async enumerate () {
let screen : Dimensions; let screen : Dimensions;
if (this.current === null) { if (this.current === null) {
this.log.error('Cannot enumerate sequence because it is not set'); this.log.error('Cannot enumerate sequence because it is not set');
return; return;
@ -62,9 +82,11 @@ export class Sequence {
return; return;
} }
this.frames = this.images.length;
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`); this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
if (this.images.length > 0) { if (this.frames > 0) {
this.info = await this.ffprobe.info(this.images[0].path); this.info = await this.ffprobe.info(this.images[0].path);
} }
if (this.info !== null) { if (this.info !== null) {
@ -82,11 +104,58 @@ export class Sequence {
this.images = []; this.images = [];
} }
public getState () : SequenceState { public getState () : State {
const dimensions : fdOutgoingPosition = this.display.getDimensions();
const source : Dimensions = this.display.getSource();
const screen : Dimensions = this.display.getScreen();
return {
display : {
width : dimensions.w,
height : dimensions.h
},
offset : {
x : dimensions.x,
y : dimensions.y
},
screen,
source,
sequence : {
hash : this.current.hash,
name : this.current.name,
progress : this.progress,
current : this.frame,
frames : this.frames,
status : this.getStatus() as SequenceStatus
},
exposure : this.exposure
}
}
public getSequenceState () : SequenceState {
return { return {
hash : this.current.hash, hash : this.current.hash,
name : this.current.name, name : this.current.name,
progress : this.progress progress : this.progress
} }
} }
public setExposure (ms : number) {
this.exposure = ms;
}
public getStatus () : SequenceStatus {
if (this.running && this.paused) {
return SequenceStatus.PAUSED;
} else if (this.running && !this.paused) {
return SequenceStatus.RUNNING;
}
return SequenceStatus.IDLE;
}
public getCurrent () : string {
if (this.current !== null && this.images.length > 0 && typeof this.images[this.frame] !== 'undefined') {
this.images[this.frame]
}
return null;
}
} }

View File

@ -27,4 +27,18 @@ html, body{
#overlay.active{ #overlay.active{
display: none; display: none;
}
#display{
background: black;
min-height: 50vh;
}
#screen .field-row{
display: inline-block;
margin-left: 20px;
}
#screen .field-row input {
max-width: 50px;
} }

6
static/js/globals.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare enum SequenceStatus {
IDLE = 0,
RUNNING = 1,
PAUSED = 2
}
export type { SequenceStatus };

11
static/js/globals.js Normal file
View File

@ -0,0 +1,11 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var SequenceStatus;
(function (SequenceStatus) {
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
})(SequenceStatus || (SequenceStatus = {}));
});
//# sourceMappingURL=globals.js.map

1
static/js/globals.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"globals.js","sourceRoot":"","sources":["../../browser/globals.ts"],"names":[],"mappings":";;;IAAA,IAAK,cAIJ;IAJD,WAAK,cAAc;QACjB,mDAAI,CAAA;QACJ,yDAAO,CAAA;QACP,uDAAM,CAAA;IACR,CAAC,EAJI,cAAc,KAAd,cAAc,QAIlB"}

20
static/js/index.d.ts vendored
View File

@ -1,4 +1,20 @@
declare enum SequenceStatus {
IDLE = 0,
RUNNING = 1,
PAUSED = 2
}
declare class Display {
private parentElement;
private canvas;
private ctx;
private screen;
constructor();
private create;
private updateSize;
update(msg: Message): void;
}
declare class Client { declare class Client {
private display;
private client; private client;
private connected; private connected;
private progress; private progress;
@ -7,6 +23,9 @@ declare class Client {
private onOpen; private onOpen;
private onClose; private onClose;
private setSequence; private setSequence;
private setStatus;
private setProgress;
private setDisplay;
private cmd; private cmd;
disableClass(className: string): void; disableClass(className: string): void;
enableClass(className: string): void; enableClass(className: string): void;
@ -16,6 +35,7 @@ declare class Client {
private receiveCameraClose; private receiveCameraClose;
sendSelect(): void; sendSelect(): void;
private receiveSelect; private receiveSelect;
private receiveUpdate;
fullscreen(): void; fullscreen(): void;
exitFullscreen(): void; exitFullscreen(): void;
private active; private active;

View File

@ -1,19 +1,68 @@
var SequenceStatus;
(function (SequenceStatus) {
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
})(SequenceStatus || (SequenceStatus = {}));
class Display {
constructor() {
this.parentElement = document.getElementById('display');
this.create();
}
create() {
this.canvas = this.parentElement.getElementsByTagName('canvas')[0];
this.ctx = this.canvas.getContext('2d');
this.screen = {
width: parseInt(document.getElementById('width').value),
height: parseInt(document.getElementById('height').value)
};
this.updateSize();
}
updateSize() {
const w = this.parentElement.clientWidth - 12;
const h = this.parentElement.clientHeight - 12;
const clientRatio = w / h;
const screenRatio = this.screen.width / this.screen.height;
let val;
let offset;
console.log(`${w},${h}`);
this.canvas.width = w;
this.canvas.height = h;
this.ctx.strokeStyle = "rgb(0, 0, 255)";
if (screenRatio > clientRatio) {
val = Math.floor(w / screenRatio);
offset = Math.round((h - val) / 2);
this.ctx.rect(0, offset + 1, w, val);
}
else {
val = Math.round(h * screenRatio);
offset = Math.round((w - val) / 2);
this.ctx.rect(offset, 1, val, h - 1);
}
this.ctx.stroke();
}
update(msg) {
}
}
class Client { class Client {
constructor() { constructor() {
this.connected = false; this.connected = false;
let uri = 'ws://localhost:8082'; let uri = 'ws://localhost:8082';
this.progress = document.getElementById('progress'); this.progress = document.getElementById('progress');
this.client = new WebSocket(uri); this.client = new WebSocket(uri);
this.display = new Display();
this.client.onopen = this.onOpen.bind(this); this.client.onopen = this.onOpen.bind(this);
this.client.onclose = this.onClose.bind(this); this.client.onclose = this.onClose.bind(this);
this.client.onmessage = this.onMessage.bind(this); this.client.onmessage = this.onMessage.bind(this);
document.getElementById('sequenceForm').reset();
document.getElementById('sequenceCtrlForm').reset();
document.getElementById('manualCtrlForm').reset();
this.disableClass('sequenceCtrl');
this.disableClass('manualCtrl');
} }
onMessage(event) { onMessage(event) {
const msg = JSON.parse(event.data); const msg = JSON.parse(event.data);
if (typeof msg.state !== 'undefined' && msg.state.sequence !== null) { if (typeof msg.cmd !== 'undefined' && msg.cmd !== null) {
this.setSequence(msg.state.sequence);
}
else if (typeof msg.cmd !== 'undefined' && msg.cmd !== null) {
this.cmd(msg); this.cmd(msg);
} }
} }
@ -21,16 +70,48 @@ class Client {
console.log('Connected'); console.log('Connected');
this.connected = true; this.connected = true;
this.active(); this.active();
this.enableClass('manualCtrl');
} }
onClose(event) { onClose(event) {
console.log('Disconnected'); console.log('Disconnected');
this.connected = false; this.connected = false;
this.inactive(); this.inactive();
} }
setSequence(sequence) { setSequence(state) {
this.setProgress(state.sequence);
this.setStatus(state.sequence);
this.setDisplay(state);
document.getElementById('sequence').value = state.sequence.hash;
}
setStatus(sequence) {
let status;
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}`;
}
setProgress(sequence) {
const percent = sequence.progress * 100.0; const percent = sequence.progress * 100.0;
this.progress.value = percent; if (this.progress !== null) {
this.progress.innerText = `${Math.floor(percent)}%`; this.progress.value = percent;
this.progress.innerText = `${Math.floor(percent)}%`;
}
document.getElementById('sequenceProgress').innerText = `Progress: ${Math.round(sequence.progress)}%`;
}
setDisplay(state) {
console.dir(state);
} }
cmd(msg) { cmd(msg) {
switch (msg.cmd) { switch (msg.cmd) {
@ -79,20 +160,23 @@ class Client {
this.enableClass('manualCtrl'); this.enableClass('manualCtrl');
} }
sendSelect() { sendSelect() {
const sequence = document.getElementById('sequence').value; const hash = document.getElementById('sequence').value;
let msg; let msg;
if (sequence === '- Select Image Sequence -') { if (hash === '- Select Image Sequence -') {
return; return;
} }
msg = { cmd: 'select', sequence }; msg = { cmd: 'select', state: { sequence: { hash } } };
console.log('send select'); console.log('send select');
console.log(sequence); console.log(hash);
this.client.send(JSON.stringify(msg)); this.client.send(JSON.stringify(msg));
} }
receiveSelect(msg) { receiveSelect(msg) {
console.log('got select'); console.log('got select');
console.dir(msg); console.dir(msg);
document.getElementById('sequence').value = msg.sequence; this.enableClass('sequenceCtrl');
this.setSequence(msg.state);
}
receiveUpdate(msg) {
} }
fullscreen() { fullscreen() {
if (!document.fullscreenElement) { if (!document.fullscreenElement) {

File diff suppressed because one or more lines are too long

View File

@ -18,14 +18,17 @@
</div> </div>
</div> </div>
<div class="window-body"> <div class="window-body">
<div>Screen Resolution : <div>
<div class="field-row"> <ul class="tree-view" id="display"><canvas></canvas></ul>
<label for="width">Width</label> <div id="screen">Screen Resolution :
<input id="width" type="text" value="{{width}}" readonly /> <span class="field-row">
</div> <label for="width">Width</label>
<div class="field-row"> <input id="width" type="text" value="{{width}}" readonly />
<label for="height">Height</label> </span>
<input id="height" type="text" value="{{height}}" readonly /> <span class="field-row">
<label for="height">Height</label>
<input id="height" type="text" value="{{height}}" readonly />
</span>
</div> </div>
</div> </div>
<!-- <!--
@ -37,29 +40,42 @@
</select> </select>
--> -->
<div> <div>
<select name="sequence" id="sequence"> <form id="sequenceForm" onsubmit="return false;">
<option> - Select Image Sequence - </option> <select name="sequence" id="sequence">
{{#each sequences}} <option> - Select Image Sequence - </option>
<option value="{{this.hash}}">{{this.name}}</option> {{#each sequences}}
{{/each}} <option value="{{this.hash}}">{{this.name}}</option>
</select> {{/each}}
<button id="select" onclick="client.sendSelect();">Select</button> </select>
<button id="select" onclick="client.sendSelect();">Select</button>
</form>
</div> </div>
<div> <div>
<button id="start" class="sequenceCtrl" disabled>Start</button> <form id="sequenceCtrlForm" onsubmit="return false;">
<button id="stop" class="sequenceCtrl" disabled>Stop</button> <button id="start" class="sequenceCtrl" disabled>Start</button>
<button id="pause" class="sequenceCtrl" disabled>Pause</button> <button id="stop" class="sequenceCtrl" disabled>Stop</button>
<button id="pause" class="sequenceCtrl" disabled>Pause</button>
<button id="rewind" class="sequenceCtrl" disabled><< Frame</button>
<input id="frame" value="0" class="sequenceCtrl" readonly />
<button id="forward" class="sequenceCtrl" disabled>Frame >></button>
</form>
</div> </div>
<div> <div>
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open Gate</button> <form id="manualCtrlForm" onsubmit="return false;" >
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close Gate</button> <button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open Gate</button>
<button id="focus" class="manualCtrl" onclick="">Focus</button> <button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close Gate</button>
<button id="framing" class="manualCtrl" onclick="">Framing</button> <button id="focus" class="manualCtrl" onclick="">Focus</button>
<button id="framing" class="manualCtrl" onclick="">Framing</button>
</form>
</div>
<div>
<progress id="progress"></progress>
</div> </div>
<div class="status-bar" id="status"> <div class="status-bar" id="status">
<p class="status-bar-field">Idle</p> <p class="status-bar-field" id="sequenceStatus">Idle</p>
<p class="status-bar-field">Progress: 0%</p> <p class="status-bar-field" id="sequenceName">Not Set</p>
<p class="status-bar-field">Sequence Length: 0</p> <p class="status-bar-field" id="sequenceProgress">Progress: 0%</p>
<p class="status-bar-field" id="sequenceLength">Sequence Length: 0</p>
</div> </div>
</div> </div>
</div> </div>