Add all work on statistics. Still need to add work on display manipulation but the ground is laid.
This commit is contained in:
parent
a4d964ef20
commit
1be3c8308d
|
@ -18,12 +18,39 @@ interface SequenceState {
|
||||||
status? : any
|
status? : any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SequenceStatistics {
|
||||||
|
totalFrameLast? : number,
|
||||||
|
totalFrameAvg? : number,
|
||||||
|
totalFrameMargin? : number,
|
||||||
|
fps? : number,
|
||||||
|
|
||||||
|
loadAvg? : number,
|
||||||
|
loadLast? : number,
|
||||||
|
loadMargin? : number,
|
||||||
|
|
||||||
|
openLast? : number,
|
||||||
|
openAvg? : number,
|
||||||
|
openMargin? : number,
|
||||||
|
|
||||||
|
closeLast? : number,
|
||||||
|
closeAvg? : number,
|
||||||
|
closeMargin? : number,
|
||||||
|
|
||||||
|
exposureLast? : number,
|
||||||
|
exposureAvg? : number,
|
||||||
|
exposureMargin? : number,
|
||||||
|
|
||||||
|
elapsed? : number,
|
||||||
|
estimate? : number
|
||||||
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
display? : StateDimensions,
|
display? : StateDimensions,
|
||||||
offset? : StateOffset,
|
offset? : StateOffset,
|
||||||
source? : StateDimensions,
|
source? : StateDimensions,
|
||||||
screen? : StateDimensions,
|
screen? : StateDimensions,
|
||||||
sequence? : SequenceState,
|
sequence? : SequenceState,
|
||||||
|
statistics? : SequenceStatistics,
|
||||||
exposure? : number
|
exposure? : number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
let client : Client;
|
||||||
|
|
||||||
enum SequenceStatus {
|
enum SequenceStatus {
|
||||||
IDLE,
|
IDLE,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
|
@ -152,6 +154,7 @@ class Client {
|
||||||
(document.getElementById('sequenceCtrlForm') as HTMLFormElement ).reset();
|
(document.getElementById('sequenceCtrlForm') as HTMLFormElement ).reset();
|
||||||
(document.getElementById('manualCtrlForm') as HTMLFormElement ).reset();
|
(document.getElementById('manualCtrlForm') as HTMLFormElement ).reset();
|
||||||
(document.getElementById('exposureCtrlForm') as HTMLFormElement ).reset();
|
(document.getElementById('exposureCtrlForm') as HTMLFormElement ).reset();
|
||||||
|
(document.getElementById('statisticsForm') as HTMLFormElement).reset();
|
||||||
this.disableClass('sequenceCtrl');
|
this.disableClass('sequenceCtrl');
|
||||||
this.disableClass('manualCtrl');
|
this.disableClass('manualCtrl');
|
||||||
this.disableClass('exposureCtrl');
|
this.disableClass('exposureCtrl');
|
||||||
|
@ -191,7 +194,8 @@ class Client {
|
||||||
this.setStatus(state.sequence);
|
this.setStatus(state.sequence);
|
||||||
this.setExposure(state);
|
this.setExposure(state);
|
||||||
this.setDisplay(state);
|
this.setDisplay(state);
|
||||||
(document.getElementById('sequence') as HTMLSelectElement ).value = state.sequence.hash;
|
this.set('sequence', state.sequence.hash);
|
||||||
|
this.removeClass('sequence', 'edited');
|
||||||
}
|
}
|
||||||
|
|
||||||
private setUpdate(state : State) {
|
private setUpdate(state : State) {
|
||||||
|
@ -199,6 +203,7 @@ class Client {
|
||||||
this.setFrame(state.sequence);
|
this.setFrame(state.sequence);
|
||||||
this.setStatus(state.sequence);
|
this.setStatus(state.sequence);
|
||||||
this.setExposure(state);
|
this.setExposure(state);
|
||||||
|
this.setStatistics(state.statistics);
|
||||||
this.display.updateImage();
|
this.display.updateImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,45 +230,72 @@ class Client {
|
||||||
|
|
||||||
private setProgress (sequence : SequenceState) {
|
private setProgress (sequence : SequenceState) {
|
||||||
const percent : number = sequence.progress * 100.0;
|
const percent : number = sequence.progress * 100.0;
|
||||||
if (this.progress !== null) {
|
|
||||||
this.progress.value = sequence.progress;
|
this.progress.value = sequence.progress;
|
||||||
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setFrame (sequence : SequenceState) {
|
private setFrame (sequence : SequenceState) {
|
||||||
if (typeof sequence.current !== 'undefined') {
|
if (typeof sequence.current !== 'undefined') {
|
||||||
(document.getElementById('frame') as HTMLInputElement).value = `${sequence.current}`.padStart(5, '0');
|
this.set('frame', `${sequence.current}`.padStart(5, '0'));
|
||||||
|
this.removeClass('frame', 'edited');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private setExposure (state : State) {
|
private setExposure (state : State) {
|
||||||
if (typeof state.exposure !== 'undefined') {
|
if (typeof state.exposure !== 'undefined') {
|
||||||
|
const el : HTMLInputElement = document.getElementById('exposure') as HTMLInputElement;
|
||||||
this.enableClass('exposureCtrl');
|
this.enableClass('exposureCtrl');
|
||||||
(document.getElementById('exposure') as HTMLInputElement).value = `${state.exposure}`;
|
this.set('exposure', `${state.exposure}`);
|
||||||
|
this.removeClass('exposure', 'edited');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private setDisplay (state : State) {
|
private setDisplay (state : State) {
|
||||||
const widthEl : HTMLInputElement = document.getElementById('displayWidth') as HTMLInputElement;
|
|
||||||
const heightEl : HTMLInputElement = document.getElementById('displayHeight') as HTMLInputElement;
|
|
||||||
const srcWidthEl : HTMLInputElement = document.getElementById('sourceWidth') as HTMLInputElement;
|
|
||||||
const srcHeightEl : HTMLInputElement = document.getElementById('sourceHeight') as HTMLInputElement;
|
|
||||||
|
|
||||||
if (typeof state.display !== 'undefined') {
|
if (typeof state.display !== 'undefined') {
|
||||||
widthEl.value = state.display.width as any;
|
this.set('displayWidth', state.display.width.toString());
|
||||||
heightEl.value = state.display.height as any;
|
this.set('displayHeight', state.display.height.toString());
|
||||||
|
this.set('sourceWidth', state.source.width.toString());
|
||||||
|
this.set('sourceHeight', state.source.height.toString());
|
||||||
|
|
||||||
srcWidthEl.value = state.source.width as any;
|
//widthEl.readOnly = false;
|
||||||
srcHeightEl.value = state.source.height as any;
|
//heightEl.readOnly = false;
|
||||||
|
|
||||||
widthEl.readOnly = false;
|
|
||||||
heightEl.readOnly = false;
|
|
||||||
//console.dir(state);
|
//console.dir(state);
|
||||||
this.display.set(state);
|
this.display.set(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public edited (el : HTMLElement) {
|
||||||
|
el.classList.add('edited');
|
||||||
|
}
|
||||||
|
|
||||||
|
private setStatistics (stats : SequenceStatistics) {
|
||||||
|
if (stats !== null) {
|
||||||
|
this.set('statsFrameTotalAvg', stats.totalFrameAvg.toString());
|
||||||
|
this.set('statsFrameTotalLast', stats.totalFrameLast.toString());
|
||||||
|
this.set('statsFrameTotalMargin', stats.totalFrameMargin.toString());
|
||||||
|
|
||||||
|
this.set('statsFPS', stats.fps.toString());
|
||||||
|
|
||||||
|
this.set('statsFrameLoadAvg', stats.loadAvg.toString());
|
||||||
|
this.set('statsFrameLoadMargin', stats.loadMargin.toString());
|
||||||
|
|
||||||
|
this.set('statsFrameOpenLast', stats.openLast.toString());
|
||||||
|
this.set('statsFrameOpenAvg', stats.openAvg.toString());
|
||||||
|
this.set('statsFrameOpenMargin', stats.openMargin.toString());
|
||||||
|
|
||||||
|
this.set('statsFrameCloseLast', stats.closeLast.toString());
|
||||||
|
this.set('statsFrameCloseAvg', stats.closeAvg.toString());
|
||||||
|
this.set('statsFrameCloseMargin', stats.closeMargin.toString());
|
||||||
|
|
||||||
|
this.set('statsExposureLast', stats.exposureLast.toString());
|
||||||
|
this.set('statsExposureAvg', stats.exposureAvg.toString());
|
||||||
|
this.set('statsExposureMargin', stats.exposureMargin.toString());
|
||||||
|
|
||||||
|
//this.set('statsFrameTotalAvg', stats.elapsed.toString());
|
||||||
|
//this.set('statsFrameTotalAvg', stats.estimate.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private cmd (msg : Message) {
|
private cmd (msg : Message) {
|
||||||
switch (msg.cmd) {
|
switch (msg.cmd) {
|
||||||
case 'ping' :
|
case 'ping' :
|
||||||
|
@ -374,14 +406,11 @@ class Client {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
msg = { cmd : 'select', state : { sequence : { hash } } };
|
msg = { cmd : 'select', state : { sequence : { hash } } };
|
||||||
console.log('send select');
|
console.log(`send select ${hash}`);
|
||||||
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.dir(msg);
|
|
||||||
this.enableClass('sequenceCtrl');
|
this.enableClass('sequenceCtrl');
|
||||||
this.setSequence(msg.state);
|
this.setSequence(msg.state);
|
||||||
}
|
}
|
||||||
|
@ -395,7 +424,7 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendExposure () {
|
public sendExposure () {
|
||||||
const exposure : number = parseInt((document.getElementById('exposure') as HTMLSelectElement ).value);
|
const exposure : number = parseInt(this.get('exposure'));
|
||||||
this.client.send(JSON.stringify({ cmd : 'exposure', state : { exposure }}));
|
this.client.send(JSON.stringify({ cmd : 'exposure', state : { exposure }}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,11 +447,30 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
private active () {
|
private active () {
|
||||||
document.getElementById('overlay').classList.add('active');
|
this.addClass('overlay', 'active');
|
||||||
}
|
}
|
||||||
private inactive () {
|
private inactive () {
|
||||||
document.getElementById('overlay').classList.remove('active');
|
this.removeClass('overlay', 'active');
|
||||||
|
}
|
||||||
|
|
||||||
|
public addClass (id : string, className : string) {
|
||||||
|
document.getElementById(id).classList.add(className);
|
||||||
|
}
|
||||||
|
public removeClass (id : string, className : string) {
|
||||||
|
document.getElementById(id).classList.remove(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set (id : string, value : string) {
|
||||||
|
try {
|
||||||
|
(document.getElementById(id) as HTMLInputElement).value = value;
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Element ${id} does not exist or cannot be set`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get (id : string) {
|
||||||
|
return (document.getElementById(id) as HTMLInputElement).value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const client : Client = new Client();
|
client = new Client();
|
|
@ -221,35 +221,35 @@ class Camera {
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
async frame() {
|
async frame() {
|
||||||
const start = +new Date();
|
const start = Date.now();
|
||||||
let ms;
|
let ms;
|
||||||
await this.confirm(Commands.CAMERA, Commands.CAMERA);
|
await this.confirm(Commands.CAMERA, Commands.CAMERA);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `frame() - ${ms}ms`);
|
this.log.info(this.prefix + `frame() - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
async open() {
|
async open() {
|
||||||
const start = +new Date();
|
const start = Date.now();
|
||||||
let ms;
|
let ms;
|
||||||
await this.confirm(Commands.CAMERA_OPEN, Commands.CAMERA_OPEN);
|
await this.confirm(Commands.CAMERA_OPEN, Commands.CAMERA_OPEN);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `open() - ${ms}ms`);
|
this.log.info(this.prefix + `open() - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
async close() {
|
async close() {
|
||||||
const start = +new Date();
|
const start = Date.now();
|
||||||
let ms;
|
let ms;
|
||||||
await this.confirm(Commands.CAMERA_CLOSE, Commands.CAMERA_CLOSE);
|
await this.confirm(Commands.CAMERA_CLOSE, Commands.CAMERA_CLOSE);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `close() - ${ms}ms`);
|
this.log.info(this.prefix + `close() - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
async direction(dir) {
|
async direction(dir) {
|
||||||
const start = +new Date();
|
const start = Date.now();
|
||||||
let ms;
|
let ms;
|
||||||
const cmd = dir ? Commands.CAMERA_FORWARD : Commands.CAMERA_BACKWARD;
|
const cmd = dir ? Commands.CAMERA_FORWARD : Commands.CAMERA_BACKWARD;
|
||||||
await this.confirm(cmd, cmd);
|
await this.confirm(cmd, cmd);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `direction(${dir}) - ${ms}ms`);
|
this.log.info(this.prefix + `direction(${dir}) - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -27,13 +27,15 @@ interface fdOutgoingMessage {
|
||||||
}
|
}
|
||||||
interface fdIncomingMessage {
|
interface fdIncomingMessage {
|
||||||
action: Action;
|
action: Action;
|
||||||
|
data?: number;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
interface fdResult {
|
interface fdResult {
|
||||||
action: Action;
|
action: Action;
|
||||||
image: string;
|
image: string;
|
||||||
time: number;
|
reported?: number;
|
||||||
|
elapsed?: number;
|
||||||
}
|
}
|
||||||
export declare class FD {
|
export declare class FD {
|
||||||
private bin;
|
private bin;
|
||||||
|
|
|
@ -126,12 +126,13 @@ class FD {
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const startTime = +new Date();
|
const startTime = Date.now();
|
||||||
if (this.mock) {
|
if (this.mock) {
|
||||||
return {
|
return {
|
||||||
action: Action.LOAD,
|
action: Action.LOAD,
|
||||||
image,
|
image,
|
||||||
time: (+new Date()) - startTime
|
reported: (Date.now()) - startTime,
|
||||||
|
elapsed: (Date.now()) - startTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const promise = new Promise(function (resolve, reject) {
|
const promise = new Promise(function (resolve, reject) {
|
||||||
|
@ -140,7 +141,8 @@ class FD {
|
||||||
return resolve({
|
return resolve({
|
||||||
action: Action.LOAD,
|
action: Action.LOAD,
|
||||||
image,
|
image,
|
||||||
time: (+new Date()) - startTime
|
reported: msg.data,
|
||||||
|
elapsed: (Date.now()) - startTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (typeof msg.error !== 'undefined') {
|
else if (typeof msg.error !== 'undefined') {
|
||||||
|
@ -158,7 +160,7 @@ class FD {
|
||||||
image,
|
image,
|
||||||
exposure
|
exposure
|
||||||
};
|
};
|
||||||
const startTime = +new Date();
|
const startTime = Date.now();
|
||||||
if (this.mock) {
|
if (this.mock) {
|
||||||
for (let exp of exposure) {
|
for (let exp of exposure) {
|
||||||
await (0, delay_1.delay)(exp);
|
await (0, delay_1.delay)(exp);
|
||||||
|
@ -166,7 +168,8 @@ class FD {
|
||||||
return {
|
return {
|
||||||
action: Action.DISPLAY,
|
action: Action.DISPLAY,
|
||||||
image,
|
image,
|
||||||
time: (+new Date()) - startTime
|
reported: (Date.now()) - startTime,
|
||||||
|
elapsed: (Date.now()) - startTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const promise = new Promise(function (resolve, reject) {
|
const promise = new Promise(function (resolve, reject) {
|
||||||
|
@ -175,7 +178,8 @@ class FD {
|
||||||
return resolve({
|
return resolve({
|
||||||
action: Action.DISPLAY,
|
action: Action.DISPLAY,
|
||||||
image,
|
image,
|
||||||
time: (+new Date()) - startTime
|
reported: msg.data,
|
||||||
|
elapsed: (Date.now()) - startTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (typeof msg.error !== 'undefined') {
|
else if (typeof msg.error !== 'undefined') {
|
||||||
|
@ -192,21 +196,24 @@ class FD {
|
||||||
action: Action.STOP,
|
action: Action.STOP,
|
||||||
image
|
image
|
||||||
};
|
};
|
||||||
const startTime = +new Date();
|
const startTime = Date.now();
|
||||||
if (this.mock) {
|
if (this.mock) {
|
||||||
return {
|
return {
|
||||||
action: Action.STOP,
|
action: Action.STOP,
|
||||||
image,
|
image,
|
||||||
time: (+new Date()) - startTime
|
reported: (Date.now()) - startTime,
|
||||||
|
elapsed: (Date.now()) - startTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const promise = new Promise(function (resolve, reject) {
|
const promise = new Promise(function (resolve, reject) {
|
||||||
this.waiting = function (msg) {
|
this.waiting = function (msg) {
|
||||||
if (msg.action == Action.STOP && msg.success) {
|
if (msg.action == Action.STOP && msg.success) {
|
||||||
|
this.log.info(msg.data);
|
||||||
return resolve({
|
return resolve({
|
||||||
action: Action.STOP,
|
action: Action.STOP,
|
||||||
image,
|
image,
|
||||||
time: (+new Date()) - startTime
|
reported: msg.data,
|
||||||
|
elapsed: (Date.now()) - startTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (typeof msg.error !== 'undefined') {
|
else if (typeof msg.error !== 'undefined') {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -18,6 +18,7 @@ export declare class Sequence {
|
||||||
private ffprobe;
|
private ffprobe;
|
||||||
private fd;
|
private fd;
|
||||||
private send;
|
private send;
|
||||||
|
private stats;
|
||||||
private running;
|
private running;
|
||||||
private paused;
|
private paused;
|
||||||
private progress;
|
private progress;
|
||||||
|
|
|
@ -9,11 +9,78 @@ var SequenceStatus;
|
||||||
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
|
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
|
||||||
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
|
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
|
||||||
})(SequenceStatus || (SequenceStatus = {}));
|
})(SequenceStatus || (SequenceStatus = {}));
|
||||||
|
class Statistics {
|
||||||
|
constructor(exposure, frames) {
|
||||||
|
this.exposure = exposure;
|
||||||
|
this.frames = frames;
|
||||||
|
this.frameLoad = [];
|
||||||
|
this.frameOpen = [];
|
||||||
|
this.frameExposureElapsed = [];
|
||||||
|
this.frameExposureReported = [];
|
||||||
|
this.frameClose = [];
|
||||||
|
this.frameTotal = [];
|
||||||
|
}
|
||||||
|
add(load, open, exposureElapsed, exposureReported, close, total) {
|
||||||
|
this.frameLoad.push(load);
|
||||||
|
this.frameOpen.push(open);
|
||||||
|
this.frameExposureElapsed.push(exposureElapsed);
|
||||||
|
this.frameExposureReported.push(exposureReported);
|
||||||
|
this.frameClose.push(close);
|
||||||
|
this.frameTotal.push(total);
|
||||||
|
}
|
||||||
|
average(arr) {
|
||||||
|
return arr.reduce((a, b) => a + b) / arr.length;
|
||||||
|
}
|
||||||
|
elapsed() {
|
||||||
|
return this.frameTotal.reduce((a, b) => a + b);
|
||||||
|
}
|
||||||
|
estimate(frame, avg) {
|
||||||
|
const frames = this.frames - frame;
|
||||||
|
return frames * avg;
|
||||||
|
}
|
||||||
|
margin(target, arr) {
|
||||||
|
const min = Math.min(...arr);
|
||||||
|
const max = Math.max(...arr);
|
||||||
|
const diff = Math.abs(max - min);
|
||||||
|
return (diff / target) / 2;
|
||||||
|
}
|
||||||
|
calculate(frame) {
|
||||||
|
if (this.frameTotal.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const totalFrameAvg = this.average(this.frameTotal);
|
||||||
|
const openAvg = this.average(this.frameOpen);
|
||||||
|
const closeAvg = this.average(this.frameClose);
|
||||||
|
const exposureAvg = this.average(this.frameExposureReported);
|
||||||
|
const loadAvg = this.average(this.frameLoad);
|
||||||
|
return {
|
||||||
|
totalFrameLast: this.frameTotal[this.frameTotal.length - 1],
|
||||||
|
totalFrameAvg,
|
||||||
|
totalFrameMargin: this.margin(totalFrameAvg, this.frameTotal) * 100.0,
|
||||||
|
fps: 1000.0 / totalFrameAvg,
|
||||||
|
loadLast: this.frameLoad[this.frameLoad.length - 1],
|
||||||
|
loadAvg,
|
||||||
|
loadMargin: this.margin(loadAvg, this.frameLoad),
|
||||||
|
openLast: this.frameOpen[this.frameOpen.length - 1],
|
||||||
|
openAvg,
|
||||||
|
openMargin: this.margin(openAvg, this.frameOpen) * 100.0,
|
||||||
|
closeLast: this.frameClose[this.frameClose.length - 1],
|
||||||
|
closeAvg,
|
||||||
|
closeMargin: this.margin(closeAvg, this.frameClose) * 100.0,
|
||||||
|
exposureLast: this.frameExposureReported[this.frameExposureReported.length - 1],
|
||||||
|
exposureAvg,
|
||||||
|
exposureMargin: this.margin(exposureAvg, this.frameExposureReported) * 100.0,
|
||||||
|
elapsed: this.elapsed(),
|
||||||
|
estimate: this.estimate(frame, totalFrameAvg)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
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.stats = null;
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
|
@ -31,6 +98,7 @@ class Sequence {
|
||||||
if (this.current !== null) {
|
if (this.current !== null) {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
this.log.info(`Started sequence: ${this.current.name}`);
|
this.log.info(`Started sequence: ${this.current.name}`);
|
||||||
|
this.stats = new Statistics(this.exposure, this.frames);
|
||||||
this.run();
|
this.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +127,7 @@ class Sequence {
|
||||||
}
|
}
|
||||||
//complete running
|
//complete running
|
||||||
this.updateClientsOnState();
|
this.updateClientsOnState();
|
||||||
|
this.stats = null;
|
||||||
}
|
}
|
||||||
async load(seq) {
|
async load(seq) {
|
||||||
this.current = seq;
|
this.current = seq;
|
||||||
|
@ -131,7 +200,8 @@ class Sequence {
|
||||||
frames: this.frames,
|
frames: this.frames,
|
||||||
status: this.getStatus()
|
status: this.getStatus()
|
||||||
},
|
},
|
||||||
exposure: this.exposure
|
exposure: this.exposure,
|
||||||
|
statistics: this.stats !== null ? this.stats.calculate(this.frame) : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
getUpdateState() {
|
getUpdateState() {
|
||||||
|
@ -209,13 +279,28 @@ class Sequence {
|
||||||
this.updateClientsOnState();
|
this.updateClientsOnState();
|
||||||
}
|
}
|
||||||
async frameRecord() {
|
async frameRecord() {
|
||||||
|
const start = Date.now();
|
||||||
|
let load;
|
||||||
|
let open;
|
||||||
|
let exposureElapsed;
|
||||||
|
let exposureReported;
|
||||||
|
let close;
|
||||||
|
let total;
|
||||||
|
let result;
|
||||||
const img = this.images[this.frame];
|
const img = this.images[this.frame];
|
||||||
const dimensions = this.display.getDimensions();
|
const dimensions = this.display.getDimensions();
|
||||||
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
||||||
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
||||||
|
load = Date.now() - start;
|
||||||
await this.camera.open();
|
await this.camera.open();
|
||||||
await this.fd.display(img.path, [this.exposure]);
|
open = Date.now() - start - load;
|
||||||
|
result = await this.fd.display(img.path, [this.exposure]);
|
||||||
|
exposureReported = result.reported;
|
||||||
|
exposureElapsed = Date.now() - start - load - open;
|
||||||
await this.camera.close();
|
await this.camera.close();
|
||||||
|
close = Date.now() - start - load - open - exposureElapsed;
|
||||||
|
total = Date.now() - start;
|
||||||
|
this.stats.add(load, open, exposureElapsed, exposureReported, close, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.Sequence = Sequence;
|
exports.Sequence = Sequence;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -239,38 +239,38 @@ export class Camera {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async frame () : Promise<number> {
|
public async frame () : Promise<number> {
|
||||||
const start : number = +new Date();
|
const start : number = Date.now();
|
||||||
let ms : number;
|
let ms : number;
|
||||||
await this.confirm(Commands.CAMERA, Commands.CAMERA);
|
await this.confirm(Commands.CAMERA, Commands.CAMERA);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `frame() - ${ms}ms`);
|
this.log.info(this.prefix + `frame() - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async open () : Promise<number> {
|
public async open () : Promise<number> {
|
||||||
const start : number = +new Date();
|
const start : number = Date.now();
|
||||||
let ms : number;
|
let ms : number;
|
||||||
await this.confirm(Commands.CAMERA_OPEN, Commands.CAMERA_OPEN);
|
await this.confirm(Commands.CAMERA_OPEN, Commands.CAMERA_OPEN);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `open() - ${ms}ms`);
|
this.log.info(this.prefix + `open() - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async close () : Promise<number> {
|
public async close () : Promise<number> {
|
||||||
const start : number = +new Date();
|
const start : number = Date.now();
|
||||||
let ms : number;
|
let ms : number;
|
||||||
await this.confirm(Commands.CAMERA_CLOSE, Commands.CAMERA_CLOSE);
|
await this.confirm(Commands.CAMERA_CLOSE, Commands.CAMERA_CLOSE);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `close() - ${ms}ms`);
|
this.log.info(this.prefix + `close() - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async direction (dir : boolean) : Promise<number> {
|
public async direction (dir : boolean) : Promise<number> {
|
||||||
const start : number = +new Date();
|
const start : number = Date.now();
|
||||||
let ms : number;
|
let ms : number;
|
||||||
const cmd : string = dir ? Commands.CAMERA_FORWARD : Commands.CAMERA_BACKWARD;
|
const cmd : string = dir ? Commands.CAMERA_FORWARD : Commands.CAMERA_BACKWARD;
|
||||||
await this.confirm(cmd, cmd);
|
await this.confirm(cmd, cmd);
|
||||||
ms = (+new Date()) - start;
|
ms = (Date.now()) - start;
|
||||||
this.log.info(this.prefix + `direction(${dir}) - ${ms}ms`);
|
this.log.info(this.prefix + `direction(${dir}) - ${ms}ms`);
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ interface fdOutgoingMessage {
|
||||||
|
|
||||||
interface fdIncomingMessage {
|
interface fdIncomingMessage {
|
||||||
action : Action,
|
action : Action,
|
||||||
|
data? : number,
|
||||||
success : boolean,
|
success : boolean,
|
||||||
error? : string
|
error? : string
|
||||||
}
|
}
|
||||||
|
@ -45,7 +46,8 @@ interface fdIncomingMessage {
|
||||||
interface fdResult {
|
interface fdResult {
|
||||||
action : Action,
|
action : Action,
|
||||||
image : string,
|
image : string,
|
||||||
time : number
|
reported? :number,
|
||||||
|
elapsed? : number
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FD {
|
export class FD {
|
||||||
|
@ -166,12 +168,13 @@ export class FD {
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const startTime : number = +new Date();
|
const startTime : number = Date.now();
|
||||||
if (this.mock) {
|
if (this.mock) {
|
||||||
return {
|
return {
|
||||||
action : Action.LOAD,
|
action : Action.LOAD,
|
||||||
image,
|
image,
|
||||||
time : (+new Date()) - startTime
|
reported : (Date.now()) - startTime,
|
||||||
|
elapsed : (Date.now()) - startTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
||||||
|
@ -180,7 +183,8 @@ export class FD {
|
||||||
return resolve({
|
return resolve({
|
||||||
action : Action.LOAD,
|
action : Action.LOAD,
|
||||||
image,
|
image,
|
||||||
time : (+new Date()) - startTime
|
reported : msg.data,
|
||||||
|
elapsed : (Date.now()) - startTime
|
||||||
});
|
});
|
||||||
} else if (typeof msg.error !== 'undefined') {
|
} else if (typeof msg.error !== 'undefined') {
|
||||||
return reject(new Error(msg.error));
|
return reject(new Error(msg.error));
|
||||||
|
@ -198,7 +202,7 @@ export class FD {
|
||||||
image,
|
image,
|
||||||
exposure
|
exposure
|
||||||
};
|
};
|
||||||
const startTime : number = +new Date();
|
const startTime : number = Date.now();
|
||||||
if (this.mock) {
|
if (this.mock) {
|
||||||
for (let exp of exposure) {
|
for (let exp of exposure) {
|
||||||
await delay(exp);
|
await delay(exp);
|
||||||
|
@ -206,7 +210,8 @@ export class FD {
|
||||||
return {
|
return {
|
||||||
action : Action.DISPLAY,
|
action : Action.DISPLAY,
|
||||||
image,
|
image,
|
||||||
time : (+new Date()) - startTime
|
reported : (Date.now()) - startTime,
|
||||||
|
elapsed : (Date.now()) - startTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
||||||
|
@ -215,7 +220,8 @@ export class FD {
|
||||||
return resolve({
|
return resolve({
|
||||||
action : Action.DISPLAY,
|
action : Action.DISPLAY,
|
||||||
image,
|
image,
|
||||||
time : (+new Date()) - startTime
|
reported : msg.data,
|
||||||
|
elapsed : (Date.now()) - startTime
|
||||||
});
|
});
|
||||||
} else if (typeof msg.error !== 'undefined') {
|
} else if (typeof msg.error !== 'undefined') {
|
||||||
return reject(new Error(msg.error));
|
return reject(new Error(msg.error));
|
||||||
|
@ -232,21 +238,24 @@ export class FD {
|
||||||
action : Action.STOP,
|
action : Action.STOP,
|
||||||
image
|
image
|
||||||
};
|
};
|
||||||
const startTime : number = +new Date();
|
const startTime : number = Date.now();
|
||||||
if (this.mock) {
|
if (this.mock) {
|
||||||
return {
|
return {
|
||||||
action : Action.STOP,
|
action : Action.STOP,
|
||||||
image,
|
image,
|
||||||
time : (+new Date()) - startTime
|
reported : (Date.now()) - startTime,
|
||||||
|
elapsed : (Date.now()) - startTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
||||||
this.waiting = function (msg : fdIncomingMessage) {
|
this.waiting = function (msg : fdIncomingMessage) {
|
||||||
if (msg.action == Action.STOP && msg.success) {
|
if (msg.action == Action.STOP && msg.success) {
|
||||||
|
this.log.info(msg.data);
|
||||||
return resolve({
|
return resolve({
|
||||||
action : Action.STOP,
|
action : Action.STOP,
|
||||||
image,
|
image,
|
||||||
time : (+new Date()) - startTime
|
reported : msg.data,
|
||||||
|
elapsed : (Date.now()) - startTime
|
||||||
});
|
});
|
||||||
} else if (typeof msg.error !== 'undefined') {
|
} else if (typeof msg.error !== 'undefined') {
|
||||||
return reject(new Error(msg.error));
|
return reject(new Error(msg.error));
|
||||||
|
|
|
@ -19,7 +19,29 @@ interface SequenceState {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SequenceStatistics {
|
interface SequenceStatistics {
|
||||||
|
totalFrameLast? : number,
|
||||||
|
totalFrameAvg? : number,
|
||||||
|
totalFrameMargin? : number,
|
||||||
|
fps? : number,
|
||||||
|
|
||||||
|
loadAvg? : number,
|
||||||
|
loadLast? : number,
|
||||||
|
loadMargin? : number,
|
||||||
|
|
||||||
|
openLast? : number,
|
||||||
|
openAvg? : number,
|
||||||
|
openMargin? : number,
|
||||||
|
|
||||||
|
closeLast? : number,
|
||||||
|
closeAvg? : number,
|
||||||
|
closeMargin? : number,
|
||||||
|
|
||||||
|
exposureLast? : number,
|
||||||
|
exposureAvg? : number,
|
||||||
|
exposureMargin? : number,
|
||||||
|
|
||||||
|
elapsed? : number,
|
||||||
|
estimate? : number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { createLog } from '../log';
|
||||||
import { delay } from '../delay';
|
import { delay } from '../delay';
|
||||||
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, fdOutgoingPosition } from '../fd';
|
import type { FD, fdOutgoingPosition, fdResult } 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';
|
||||||
|
@ -14,6 +14,97 @@ enum SequenceStatus {
|
||||||
PAUSED
|
PAUSED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Statistics {
|
||||||
|
private frameLoad : number[];
|
||||||
|
private frameOpen : number[];
|
||||||
|
private frameExposureElapsed : number[];
|
||||||
|
private frameExposureReported : number[];
|
||||||
|
private frameClose : number[];
|
||||||
|
private frameTotal : number[];
|
||||||
|
|
||||||
|
private exposure : number;
|
||||||
|
private frames : number;
|
||||||
|
|
||||||
|
constructor (exposure : number, frames : number) {
|
||||||
|
this.exposure = exposure;
|
||||||
|
this.frames = frames;
|
||||||
|
|
||||||
|
this.frameLoad = [];
|
||||||
|
this.frameOpen = [];
|
||||||
|
this.frameExposureElapsed = [];
|
||||||
|
this.frameExposureReported = [];
|
||||||
|
this.frameClose = [];
|
||||||
|
this.frameTotal = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public add (load : number, open : number, exposureElapsed : number, exposureReported : number, close : number, total : number) {
|
||||||
|
this.frameLoad.push(load);
|
||||||
|
this.frameOpen.push(open);
|
||||||
|
this.frameExposureElapsed.push(exposureElapsed);
|
||||||
|
this.frameExposureReported.push(exposureReported);
|
||||||
|
this.frameClose.push(close);
|
||||||
|
this.frameTotal.push(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
private average (arr : number[]) : number {
|
||||||
|
return arr.reduce((a, b) => a + b) / arr.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private elapsed () : number {
|
||||||
|
return this.frameTotal.reduce((a, b) => a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private estimate (frame : number, avg : number) : number {
|
||||||
|
const frames : number = this.frames - frame;
|
||||||
|
return frames * avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private margin (target : number, arr : number[]) : number {
|
||||||
|
const min : number = Math.min(...arr);
|
||||||
|
const max : number = Math.max(...arr);
|
||||||
|
const diff : number = Math.abs(max - min);
|
||||||
|
return (diff / target) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public calculate (frame : number) : SequenceStatistics {
|
||||||
|
if (this.frameTotal.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalFrameAvg : number = this.average(this.frameTotal);
|
||||||
|
const openAvg : number = this.average(this.frameOpen);
|
||||||
|
const closeAvg : number = this.average(this.frameClose);
|
||||||
|
const exposureAvg : number = this.average(this.frameExposureReported);
|
||||||
|
const loadAvg : number = this.average(this.frameLoad);
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalFrameLast : this.frameTotal[this.frameTotal.length - 1],
|
||||||
|
totalFrameAvg,
|
||||||
|
totalFrameMargin : this.margin(totalFrameAvg, this.frameTotal) * 100.0,
|
||||||
|
fps : 1000.0 / totalFrameAvg,
|
||||||
|
|
||||||
|
loadLast : this.frameLoad[this.frameLoad.length - 1],
|
||||||
|
loadAvg,
|
||||||
|
loadMargin : this.margin(loadAvg, this.frameLoad),
|
||||||
|
|
||||||
|
openLast : this.frameOpen[this.frameOpen.length - 1],
|
||||||
|
openAvg,
|
||||||
|
openMargin : this.margin(openAvg, this.frameOpen) * 100.0,
|
||||||
|
|
||||||
|
closeLast : this.frameClose[this.frameClose.length - 1],
|
||||||
|
closeAvg,
|
||||||
|
closeMargin : this.margin(closeAvg, this.frameClose) * 100.0,
|
||||||
|
|
||||||
|
exposureLast : this.frameExposureReported[this.frameExposureReported.length - 1],
|
||||||
|
exposureAvg,
|
||||||
|
exposureMargin : this.margin(exposureAvg, this.frameExposureReported) * 100.0,
|
||||||
|
|
||||||
|
elapsed : this.elapsed(),
|
||||||
|
estimate : this.estimate(frame, totalFrameAvg)
|
||||||
|
} as SequenceStatistics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Sequence {
|
export class Sequence {
|
||||||
private log : Logger;
|
private log : Logger;
|
||||||
private current : SequenceObject = null;
|
private current : SequenceObject = null;
|
||||||
|
@ -24,9 +115,11 @@ export class Sequence {
|
||||||
private ffprobe : FFPROBE;
|
private ffprobe : FFPROBE;
|
||||||
private fd : FD;
|
private fd : FD;
|
||||||
private send : Function;
|
private send : Function;
|
||||||
|
private stats : Statistics = null;
|
||||||
private running : boolean = false;
|
private running : boolean = false;
|
||||||
private paused : boolean = false;
|
private paused : boolean = false;
|
||||||
|
|
||||||
|
|
||||||
private progress : number = 0;
|
private progress : number = 0;
|
||||||
private frame : number = 0;
|
private frame : number = 0;
|
||||||
private frames : number = 0;
|
private frames : number = 0;
|
||||||
|
@ -46,6 +139,7 @@ export class Sequence {
|
||||||
if (this.current !== null) {
|
if (this.current !== null) {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
this.log.info(`Started sequence: ${this.current.name}`);
|
this.log.info(`Started sequence: ${this.current.name}`);
|
||||||
|
this.stats = new Statistics(this.exposure, this.frames);
|
||||||
this.run();
|
this.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +170,7 @@ export class Sequence {
|
||||||
}
|
}
|
||||||
//complete running
|
//complete running
|
||||||
this.updateClientsOnState();
|
this.updateClientsOnState();
|
||||||
|
this.stats = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async load (seq : SequenceObject) {
|
public async load (seq : SequenceObject) {
|
||||||
|
@ -158,7 +253,8 @@ export class Sequence {
|
||||||
frames : this.frames,
|
frames : this.frames,
|
||||||
status : this.getStatus() as SequenceStatus
|
status : this.getStatus() as SequenceStatus
|
||||||
},
|
},
|
||||||
exposure : this.exposure
|
exposure : this.exposure,
|
||||||
|
statistics : this.stats !== null ? this.stats.calculate(this.frame) : null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,12 +339,27 @@ export class Sequence {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async frameRecord () {
|
private async frameRecord () {
|
||||||
|
const start : number = Date.now();
|
||||||
|
let load : number;
|
||||||
|
let open : number;
|
||||||
|
let exposureElapsed : number;
|
||||||
|
let exposureReported : number;
|
||||||
|
let close : number;
|
||||||
|
let total : number;
|
||||||
|
let result : fdResult;
|
||||||
const img : ImageObject = this.images[this.frame];
|
const img : ImageObject = this.images[this.frame];
|
||||||
const dimensions : fdOutgoingPosition = this.display.getDimensions();
|
const dimensions : fdOutgoingPosition = this.display.getDimensions();
|
||||||
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
||||||
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
||||||
|
load = Date.now() - start;
|
||||||
await this.camera.open();
|
await this.camera.open();
|
||||||
await this.fd.display(img.path, [ this.exposure ] );
|
open = Date.now() - start - load;
|
||||||
|
result = await this.fd.display(img.path, [ this.exposure ] );
|
||||||
|
exposureReported = result.reported;
|
||||||
|
exposureElapsed = Date.now() - start - load - open;
|
||||||
await this.camera.close();
|
await this.camera.close();
|
||||||
|
close = Date.now() - start - load - open - exposureElapsed;
|
||||||
|
total = Date.now() - start;
|
||||||
|
this.stats.add(load, open, exposureElapsed, exposureReported, close, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -55,10 +55,20 @@ html, body{
|
||||||
flex: 0 0 33.33333%;
|
flex: 0 0 33.33333%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quarter{
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 0 0 25%;
|
||||||
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edited {
|
||||||
|
background-color: yellow !important;
|
||||||
|
color: rgb(0, 0, 0) !important;
|
||||||
|
}
|
||||||
|
|
||||||
fieldset.inline .field-row {
|
fieldset.inline .field-row {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
@ -71,6 +81,14 @@ fieldset.inline input.medium {
|
||||||
max-width: 70px;
|
max-width: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
width: 80px;
|
||||||
|
text-align: right;
|
||||||
|
display: inline-block;
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
progress {
|
progress {
|
||||||
width: 97vw;
|
width: 97vw;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -78,16 +96,26 @@ progress {
|
||||||
left: 0.5vw;
|
left: 0.5vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.small{
|
button.small,
|
||||||
|
input.small {
|
||||||
width: 35px;
|
width: 35px;
|
||||||
max-width: 35px;
|
max-width: 35px;
|
||||||
min-width: 35px;
|
min-width: 35px;
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.medium{
|
button.medium,
|
||||||
|
input.medium {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
max-width: 50px;
|
max-width: 50px;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.large,
|
||||||
|
input.large {
|
||||||
|
width: 75px;
|
||||||
|
min-width: 75px;
|
||||||
|
max-width: 75px;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
declare let client: Client;
|
||||||
declare enum SequenceStatus {
|
declare enum SequenceStatus {
|
||||||
IDLE = 0,
|
IDLE = 0,
|
||||||
RUNNING = 1,
|
RUNNING = 1,
|
||||||
|
@ -56,6 +57,8 @@ declare class Client {
|
||||||
private setFrame;
|
private setFrame;
|
||||||
private setExposure;
|
private setExposure;
|
||||||
private setDisplay;
|
private setDisplay;
|
||||||
|
edited(el: HTMLElement): void;
|
||||||
|
private setStatistics;
|
||||||
private cmd;
|
private cmd;
|
||||||
disableClass(className: string): void;
|
disableClass(className: string): void;
|
||||||
enableClass(className: string): void;
|
enableClass(className: string): void;
|
||||||
|
@ -80,5 +83,8 @@ declare class Client {
|
||||||
exitFullscreen(): void;
|
exitFullscreen(): void;
|
||||||
private active;
|
private active;
|
||||||
private inactive;
|
private inactive;
|
||||||
|
addClass(id: string, className: string): void;
|
||||||
|
removeClass(id: string, className: string): void;
|
||||||
|
set(id: string, value: string): void;
|
||||||
|
get(id: string): string;
|
||||||
}
|
}
|
||||||
declare const client: Client;
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
let client;
|
||||||
var SequenceStatus;
|
var SequenceStatus;
|
||||||
(function (SequenceStatus) {
|
(function (SequenceStatus) {
|
||||||
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
|
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
|
||||||
|
@ -127,6 +128,7 @@ class Client {
|
||||||
document.getElementById('sequenceCtrlForm').reset();
|
document.getElementById('sequenceCtrlForm').reset();
|
||||||
document.getElementById('manualCtrlForm').reset();
|
document.getElementById('manualCtrlForm').reset();
|
||||||
document.getElementById('exposureCtrlForm').reset();
|
document.getElementById('exposureCtrlForm').reset();
|
||||||
|
document.getElementById('statisticsForm').reset();
|
||||||
this.disableClass('sequenceCtrl');
|
this.disableClass('sequenceCtrl');
|
||||||
this.disableClass('manualCtrl');
|
this.disableClass('manualCtrl');
|
||||||
this.disableClass('exposureCtrl');
|
this.disableClass('exposureCtrl');
|
||||||
|
@ -159,13 +161,15 @@ class Client {
|
||||||
this.setStatus(state.sequence);
|
this.setStatus(state.sequence);
|
||||||
this.setExposure(state);
|
this.setExposure(state);
|
||||||
this.setDisplay(state);
|
this.setDisplay(state);
|
||||||
document.getElementById('sequence').value = state.sequence.hash;
|
this.set('sequence', state.sequence.hash);
|
||||||
|
this.removeClass('sequence', 'edited');
|
||||||
}
|
}
|
||||||
setUpdate(state) {
|
setUpdate(state) {
|
||||||
this.setProgress(state.sequence);
|
this.setProgress(state.sequence);
|
||||||
this.setFrame(state.sequence);
|
this.setFrame(state.sequence);
|
||||||
this.setStatus(state.sequence);
|
this.setStatus(state.sequence);
|
||||||
this.setExposure(state);
|
this.setExposure(state);
|
||||||
|
this.setStatistics(state.statistics);
|
||||||
this.display.updateImage();
|
this.display.updateImage();
|
||||||
}
|
}
|
||||||
setStatus(sequence) {
|
setStatus(sequence) {
|
||||||
|
@ -190,37 +194,54 @@ class Client {
|
||||||
}
|
}
|
||||||
setProgress(sequence) {
|
setProgress(sequence) {
|
||||||
const percent = sequence.progress * 100.0;
|
const percent = sequence.progress * 100.0;
|
||||||
if (this.progress !== null) {
|
this.progress.value = sequence.progress;
|
||||||
this.progress.value = sequence.progress;
|
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
||||||
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setFrame(sequence) {
|
setFrame(sequence) {
|
||||||
if (typeof sequence.current !== 'undefined') {
|
if (typeof sequence.current !== 'undefined') {
|
||||||
document.getElementById('frame').value = `${sequence.current}`.padStart(5, '0');
|
this.set('frame', `${sequence.current}`.padStart(5, '0'));
|
||||||
|
this.removeClass('frame', 'edited');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setExposure(state) {
|
setExposure(state) {
|
||||||
if (typeof state.exposure !== 'undefined') {
|
if (typeof state.exposure !== 'undefined') {
|
||||||
|
const el = document.getElementById('exposure');
|
||||||
this.enableClass('exposureCtrl');
|
this.enableClass('exposureCtrl');
|
||||||
document.getElementById('exposure').value = `${state.exposure}`;
|
this.set('exposure', `${state.exposure}`);
|
||||||
|
this.removeClass('exposure', 'edited');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setDisplay(state) {
|
setDisplay(state) {
|
||||||
const widthEl = document.getElementById('displayWidth');
|
|
||||||
const heightEl = document.getElementById('displayHeight');
|
|
||||||
const srcWidthEl = document.getElementById('sourceWidth');
|
|
||||||
const srcHeightEl = document.getElementById('sourceHeight');
|
|
||||||
if (typeof state.display !== 'undefined') {
|
if (typeof state.display !== 'undefined') {
|
||||||
widthEl.value = state.display.width;
|
this.set('displayWidth', state.display.width.toString());
|
||||||
heightEl.value = state.display.height;
|
this.set('displayHeight', state.display.height.toString());
|
||||||
srcWidthEl.value = state.source.width;
|
this.set('sourceWidth', state.source.width.toString());
|
||||||
srcHeightEl.value = state.source.height;
|
this.set('sourceHeight', state.source.height.toString());
|
||||||
widthEl.readOnly = false;
|
|
||||||
heightEl.readOnly = false;
|
|
||||||
this.display.set(state);
|
this.display.set(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
edited(el) {
|
||||||
|
el.classList.add('edited');
|
||||||
|
}
|
||||||
|
setStatistics(stats) {
|
||||||
|
if (stats !== null) {
|
||||||
|
this.set('statsFrameTotalAvg', stats.totalFrameAvg.toString());
|
||||||
|
this.set('statsFrameTotalLast', stats.totalFrameLast.toString());
|
||||||
|
this.set('statsFrameTotalMargin', stats.totalFrameMargin.toString());
|
||||||
|
this.set('statsFPS', stats.fps.toString());
|
||||||
|
this.set('statsFrameLoadAvg', stats.loadAvg.toString());
|
||||||
|
this.set('statsFrameLoadMargin', stats.loadMargin.toString());
|
||||||
|
this.set('statsFrameOpenLast', stats.openLast.toString());
|
||||||
|
this.set('statsFrameOpenAvg', stats.openAvg.toString());
|
||||||
|
this.set('statsFrameOpenMargin', stats.openMargin.toString());
|
||||||
|
this.set('statsFrameCloseLast', stats.closeLast.toString());
|
||||||
|
this.set('statsFrameCloseAvg', stats.closeAvg.toString());
|
||||||
|
this.set('statsFrameCloseMargin', stats.closeMargin.toString());
|
||||||
|
this.set('statsExposureLast', stats.exposureLast.toString());
|
||||||
|
this.set('statsExposureAvg', stats.exposureAvg.toString());
|
||||||
|
this.set('statsExposureMargin', stats.exposureMargin.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
cmd(msg) {
|
cmd(msg) {
|
||||||
switch (msg.cmd) {
|
switch (msg.cmd) {
|
||||||
case 'ping':
|
case 'ping':
|
||||||
|
@ -318,12 +339,10 @@ class Client {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
msg = { cmd: 'select', state: { sequence: { hash } } };
|
msg = { cmd: 'select', state: { sequence: { hash } } };
|
||||||
console.log('send select');
|
console.log(`send select ${hash}`);
|
||||||
console.log(hash);
|
|
||||||
this.client.send(JSON.stringify(msg));
|
this.client.send(JSON.stringify(msg));
|
||||||
}
|
}
|
||||||
receiveSelect(msg) {
|
receiveSelect(msg) {
|
||||||
console.log('got select');
|
|
||||||
this.enableClass('sequenceCtrl');
|
this.enableClass('sequenceCtrl');
|
||||||
this.setSequence(msg.state);
|
this.setSequence(msg.state);
|
||||||
}
|
}
|
||||||
|
@ -334,7 +353,7 @@ class Client {
|
||||||
this.client.send(JSON.stringify({ cmd: 'stop' }));
|
this.client.send(JSON.stringify({ cmd: 'stop' }));
|
||||||
}
|
}
|
||||||
sendExposure() {
|
sendExposure() {
|
||||||
const exposure = parseInt(document.getElementById('exposure').value);
|
const exposure = parseInt(this.get('exposure'));
|
||||||
this.client.send(JSON.stringify({ cmd: 'exposure', state: { exposure } }));
|
this.client.send(JSON.stringify({ cmd: 'exposure', state: { exposure } }));
|
||||||
}
|
}
|
||||||
receiveUpdate(msg) {
|
receiveUpdate(msg) {
|
||||||
|
@ -354,11 +373,28 @@ class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
active() {
|
active() {
|
||||||
document.getElementById('overlay').classList.add('active');
|
this.addClass('overlay', 'active');
|
||||||
}
|
}
|
||||||
inactive() {
|
inactive() {
|
||||||
document.getElementById('overlay').classList.remove('active');
|
this.removeClass('overlay', 'active');
|
||||||
|
}
|
||||||
|
addClass(id, className) {
|
||||||
|
document.getElementById(id).classList.add(className);
|
||||||
|
}
|
||||||
|
removeClass(id, className) {
|
||||||
|
document.getElementById(id).classList.remove(className);
|
||||||
|
}
|
||||||
|
set(id, value) {
|
||||||
|
try {
|
||||||
|
document.getElementById(id).value = value;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.warn(`Element ${id} does not exist or cannot be set`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get(id) {
|
||||||
|
return document.getElementById(id).value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const client = new Client();
|
client = new Client();
|
||||||
//# sourceMappingURL=index.js.map
|
//# sourceMappingURL=index.js.map
|
File diff suppressed because one or more lines are too long
128
views/index.hbs
128
views/index.hbs
|
@ -68,7 +68,7 @@
|
||||||
<fieldset id="sequenceSelect" class="inline half">
|
<fieldset id="sequenceSelect" class="inline half">
|
||||||
<legend>Sequence</legend>
|
<legend>Sequence</legend>
|
||||||
<form id="sequenceSelectForm" onsubmit="return false;">
|
<form id="sequenceSelectForm" onsubmit="return false;">
|
||||||
<select name="sequence" id="sequence">
|
<select name="sequence" id="sequence" oninput="client.edited(this);">
|
||||||
<option> - Select Image Sequence - </option>
|
<option> - Select Image Sequence - </option>
|
||||||
{{#each sequences}}
|
{{#each sequences}}
|
||||||
<option value="{{this.hash}}">{{this.name}}</option>
|
<option value="{{this.hash}}">{{this.name}}</option>
|
||||||
|
@ -80,47 +80,107 @@
|
||||||
<fieldset id="exposureCtrl" class="inline half">
|
<fieldset id="exposureCtrl" class="inline half">
|
||||||
<legend>Exposure</legend>
|
<legend>Exposure</legend>
|
||||||
<form id="exposureCtrlForm" onsubmit="return false;">
|
<form id="exposureCtrlForm" onsubmit="return false;">
|
||||||
<input id="exposure" class="medium exposureCtrl" type="number" value="0" disabled />
|
<input id="exposure" class="large exposureCtrl" type="number" value="0" oninput="client.edited(this);" disabled />
|
||||||
<span>ms </span>
|
<span>ms </span>
|
||||||
<button id="exposureUpdate" class="exposureCtrl" onclick="client.sendExposure();">Update</button>
|
<button id="exposureUpdate" class="exposureCtrl" onclick="client.sendExposure();">Update</button>
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<fieldset class="inline half" id="sequenceCtrl">
|
<div class="half">
|
||||||
<legend>Sequence Controls</legend>
|
<div>
|
||||||
<form id="sequenceCtrlForm" onsubmit="return false;">
|
<fieldset id="sequenceCtrl">
|
||||||
<button id="start" class="medium sequenceCtrl" onclick="client.sendStart();" disabled>Start</button>
|
<legend>Sequence Controls</legend>
|
||||||
<button id="stop" class="medium sequenceCtrl" onclick="client.sendStop();" disabled>Stop</button>
|
<form id="sequenceCtrlForm" onsubmit="return false;">
|
||||||
<button id="rewind" class="small sequenceCtrl" onclick="client.sendToStart();" disabled><<</button>
|
<button id="start" class="medium sequenceCtrl" onclick="client.sendStart();" disabled>Start</button>
|
||||||
<button id="rewind" class="small sequenceCtrl" onclick="client.sendRewind();" disabled><</button>
|
<button id="stop" class="medium sequenceCtrl" onclick="client.sendStop();" disabled>Stop</button>
|
||||||
<input id="frame" type="number" value="00000" class="sequenceCtrl medium" onchange="client.sendFrameSet();" disabled />
|
<button id="rewind" class="small sequenceCtrl" onclick="client.sendToStart();" disabled><<</button>
|
||||||
<button id="advance" class="small sequenceCtrl" onclick="client.sendAdvance()" disabled>></button>
|
<button id="rewind" class="small sequenceCtrl" onclick="client.sendRewind();" disabled><</button>
|
||||||
<button id="advance" class="small sequenceCtrl" onclick="client.sendToEnd()" disabled>>></button>
|
<input id="frame" type="number" value="00000" class="sequenceCtrl large" oninput="client.edited(this);" onchange="client.sendFrameSet();" disabled />
|
||||||
</form>
|
<button id="advance" class="small sequenceCtrl" onclick="client.sendAdvance()" disabled>></button>
|
||||||
</fieldset>
|
<button id="advance" class="small sequenceCtrl" onclick="client.sendToEnd()" disabled>>></button>
|
||||||
<fieldset id="displayAdjust" class="inline half">
|
</form>
|
||||||
<legend>Display Adjust</legend>
|
</fieldset>
|
||||||
<form id="displayAdjustForm" onsubmit="return false;">
|
</div>
|
||||||
<button class="small" id="offsetXPlus" disabled>X +</button>
|
<div>
|
||||||
<button class="small" id="offsetXMinus" disabled>X -</button>
|
<fieldset id="manualCtrl">
|
||||||
<button class="small" id="offsetYPlus" disabled>Y +</button>
|
<legend>Manual Controls</legend>
|
||||||
<button class="small" id="offsetYMinus" disabled>Y -</button>
|
<form id="manualCtrlForm" onsubmit="return false;" >
|
||||||
<button class="small" id="widthPlus" disabled>W +</button>
|
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open</button>
|
||||||
<button class="small" id="widthMinus" disabled>W -</button>
|
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
|
||||||
<button class="small" id="heightPlus" disabled>H +</button>
|
<button id="focus" class="manualCtrl" onclick="">Focus</button>
|
||||||
<button class="small" id="heightMinus" disabled>H -</button>
|
<button id="framing" class="manualCtrl" onclick="">Framing</button>
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="half">
|
||||||
|
<fieldset id="displayAdjust" class="inline half">
|
||||||
|
<legend>Display Adjust</legend>
|
||||||
|
<form id="displayAdjustForm" onsubmit="return false;">
|
||||||
|
<button class="small manualCtrl" id="offsetXPlus" disabled>X +</button>
|
||||||
|
<button class="small manualCtrl" id="offsetXMinus" disabled>X -</button>
|
||||||
|
<button class="small manualCtrl" id="offsetYPlus" disabled>Y +</button>
|
||||||
|
<button class="small manualCtrl" id="offsetYMinus" disabled>Y -</button>
|
||||||
|
<button class="small manualCtrl" id="widthPlus" disabled>W +</button>
|
||||||
|
<button class="small manualCtrl" id="widthMinus" disabled>W -</button>
|
||||||
|
<button class="small manualCtrl" id="heightPlus" disabled>H +</button>
|
||||||
|
<button class="small manualCtrl" id="heightMinus" disabled>H -</button>
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<fieldset id="manualCtrl" class="inline half">
|
<fieldset id="statistics" class="inline">
|
||||||
<legend>Manual Controls</legend>
|
<legend>Statistics</legend>
|
||||||
<form id="manualCtrlForm" onsubmit="return false;" >
|
<form id="statisticsForm" onsubmit="return false;" class="flex">
|
||||||
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open</button>
|
<div id="statisticsFrame" class="quarter">
|
||||||
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
|
<div>
|
||||||
<button id="focus" class="manualCtrl" onclick="">Focus</button>
|
<label for="statsFrameTotalAvg">Frame Total Avg</label><input id="statsFrameTotalAvg" class="large" type="text" readonly value="0" /><span> ms +/-</span>
|
||||||
<button id="framing" class="manualCtrl" onclick="">Framing</button>
|
<input id="statsFrameTotalMargin" class="small" type="text" readonly value="0"/><span>%</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsFrameTotalLast">Frame Total Last</label><input id="statsFrameTotalLast" class="large" type="text" readonly value="0" /><span> ms</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsFPS">FPS</label><input id="statsFPS" class="large" type="text" readonly value="0" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsFrameLoadAvg">Frame Load Avg</label><input id="statsFrameLoadAvg" class="large" type="text" readonly value="0" /><span> ms +/-</span>
|
||||||
|
<input id="statsFrameLoadMargin" class="small" type="text" readonly value="0"/><span>%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="statisticsOpenClose" class="quarter">
|
||||||
|
<div>
|
||||||
|
<label for="statsFrameOpenAvg">Cam Open Avg</label><input id="statsFrameOpenAvg" class="large" type="text" readonly value="0" /><span> ms +/-</span>
|
||||||
|
<input id="statsFrameOpenMargin" class="small" type="text" readonly value="0"/><span>%</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsFrameOpenLast">Frame Open Last</label><input id="statsFrameOpenLast" class="large" type="text" readonly value="0" /><span> ms</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsFrameCloseAvg">Cam Close Avg</label><input id="statsFrameCloseAvg" class="large" type="text" readonly value="0" /><span> ms +/-</span>
|
||||||
|
<input id="statsFrameCloseMargin" class="small" type="text" readonly value="0"/><span>%</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsFrameCloseLast">Frame Close Last</label><input id="statsFrameCloseLast" class="large" type="text" readonly value="0" /><span> ms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="statisticsExposure" class="quarter">
|
||||||
|
<div>
|
||||||
|
<label for="statsExposureAvg">Exposure Avg</label><input id="statsExposureAvg" class="large" type="text" readonly value="0" /><span> ms +/-</span>
|
||||||
|
<input id="statsExposureMargin" class="small" type="text" readonly value="0"/><span>%</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsExposureLast">Exposure Last</label><input id="statsExposureLast" class="large" type="text" readonly value="0" /><span> ms</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="statsExposureLast">Equivalent</label><input id="statsExposureEquivalent" class="large" type="text" readonly value="1s" /><span> ms</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="statisticsTiming" class="quarter">
|
||||||
|
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue