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
|
||||
}
|
||||
|
||||
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 {
|
||||
display? : StateDimensions,
|
||||
offset? : StateOffset,
|
||||
source? : StateDimensions,
|
||||
screen? : StateDimensions,
|
||||
sequence? : SequenceState,
|
||||
statistics? : SequenceStatistics,
|
||||
exposure? : number
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
let client : Client;
|
||||
|
||||
enum SequenceStatus {
|
||||
IDLE,
|
||||
RUNNING,
|
||||
|
@ -152,6 +154,7 @@ class Client {
|
|||
(document.getElementById('sequenceCtrlForm') as HTMLFormElement ).reset();
|
||||
(document.getElementById('manualCtrlForm') as HTMLFormElement ).reset();
|
||||
(document.getElementById('exposureCtrlForm') as HTMLFormElement ).reset();
|
||||
(document.getElementById('statisticsForm') as HTMLFormElement).reset();
|
||||
this.disableClass('sequenceCtrl');
|
||||
this.disableClass('manualCtrl');
|
||||
this.disableClass('exposureCtrl');
|
||||
|
@ -191,7 +194,8 @@ class Client {
|
|||
this.setStatus(state.sequence);
|
||||
this.setExposure(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) {
|
||||
|
@ -199,6 +203,7 @@ class Client {
|
|||
this.setFrame(state.sequence);
|
||||
this.setStatus(state.sequence);
|
||||
this.setExposure(state);
|
||||
this.setStatistics(state.statistics);
|
||||
this.display.updateImage();
|
||||
}
|
||||
|
||||
|
@ -225,45 +230,72 @@ class Client {
|
|||
|
||||
private setProgress (sequence : SequenceState) {
|
||||
const percent : number = sequence.progress * 100.0;
|
||||
if (this.progress !== null) {
|
||||
this.progress.value = sequence.progress;
|
||||
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
||||
}
|
||||
}
|
||||
|
||||
private setFrame (sequence : SequenceState) {
|
||||
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) {
|
||||
if (typeof state.exposure !== 'undefined') {
|
||||
const el : HTMLInputElement = document.getElementById('exposure') as HTMLInputElement;
|
||||
this.enableClass('exposureCtrl');
|
||||
(document.getElementById('exposure') as HTMLInputElement).value = `${state.exposure}`;
|
||||
this.set('exposure', `${state.exposure}`);
|
||||
this.removeClass('exposure', 'edited');
|
||||
}
|
||||
}
|
||||
|
||||
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') {
|
||||
widthEl.value = state.display.width as any;
|
||||
heightEl.value = state.display.height as any;
|
||||
this.set('displayWidth', state.display.width.toString());
|
||||
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;
|
||||
srcHeightEl.value = state.source.height as any;
|
||||
|
||||
widthEl.readOnly = false;
|
||||
heightEl.readOnly = false;
|
||||
//widthEl.readOnly = false;
|
||||
//heightEl.readOnly = false;
|
||||
//console.dir(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) {
|
||||
switch (msg.cmd) {
|
||||
case 'ping' :
|
||||
|
@ -374,14 +406,11 @@ class Client {
|
|||
return;
|
||||
}
|
||||
msg = { cmd : 'select', state : { sequence : { hash } } };
|
||||
console.log('send select');
|
||||
console.log(hash)
|
||||
console.log(`send select ${hash}`);
|
||||
this.client.send(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
private receiveSelect (msg : Message) {
|
||||
console.log('got select');
|
||||
//console.dir(msg);
|
||||
this.enableClass('sequenceCtrl');
|
||||
this.setSequence(msg.state);
|
||||
}
|
||||
|
@ -395,7 +424,7 @@ class Client {
|
|||
}
|
||||
|
||||
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 }}));
|
||||
}
|
||||
|
||||
|
@ -418,11 +447,30 @@ class Client {
|
|||
}
|
||||
|
||||
private active () {
|
||||
document.getElementById('overlay').classList.add('active');
|
||||
this.addClass('overlay', 'active');
|
||||
}
|
||||
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));
|
||||
}
|
||||
async frame() {
|
||||
const start = +new Date();
|
||||
const start = Date.now();
|
||||
let ms;
|
||||
await this.confirm(Commands.CAMERA, Commands.CAMERA);
|
||||
ms = (+new Date()) - start;
|
||||
ms = (Date.now()) - start;
|
||||
this.log.info(this.prefix + `frame() - ${ms}ms`);
|
||||
return ms;
|
||||
}
|
||||
async open() {
|
||||
const start = +new Date();
|
||||
const start = Date.now();
|
||||
let ms;
|
||||
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`);
|
||||
return ms;
|
||||
}
|
||||
async close() {
|
||||
const start = +new Date();
|
||||
const start = Date.now();
|
||||
let ms;
|
||||
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`);
|
||||
return ms;
|
||||
}
|
||||
async direction(dir) {
|
||||
const start = +new Date();
|
||||
const start = Date.now();
|
||||
let ms;
|
||||
const cmd = dir ? Commands.CAMERA_FORWARD : Commands.CAMERA_BACKWARD;
|
||||
await this.confirm(cmd, cmd);
|
||||
ms = (+new Date()) - start;
|
||||
ms = (Date.now()) - start;
|
||||
this.log.info(this.prefix + `direction(${dir}) - ${ms}ms`);
|
||||
return ms;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -27,13 +27,15 @@ interface fdOutgoingMessage {
|
|||
}
|
||||
interface fdIncomingMessage {
|
||||
action: Action;
|
||||
data?: number;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
interface fdResult {
|
||||
action: Action;
|
||||
image: string;
|
||||
time: number;
|
||||
reported?: number;
|
||||
elapsed?: number;
|
||||
}
|
||||
export declare class FD {
|
||||
private bin;
|
||||
|
|
|
@ -126,12 +126,13 @@ class FD {
|
|||
h
|
||||
}
|
||||
};
|
||||
const startTime = +new Date();
|
||||
const startTime = Date.now();
|
||||
if (this.mock) {
|
||||
return {
|
||||
action: Action.LOAD,
|
||||
image,
|
||||
time: (+new Date()) - startTime
|
||||
reported: (Date.now()) - startTime,
|
||||
elapsed: (Date.now()) - startTime
|
||||
};
|
||||
}
|
||||
const promise = new Promise(function (resolve, reject) {
|
||||
|
@ -140,7 +141,8 @@ class FD {
|
|||
return resolve({
|
||||
action: Action.LOAD,
|
||||
image,
|
||||
time: (+new Date()) - startTime
|
||||
reported: msg.data,
|
||||
elapsed: (Date.now()) - startTime
|
||||
});
|
||||
}
|
||||
else if (typeof msg.error !== 'undefined') {
|
||||
|
@ -158,7 +160,7 @@ class FD {
|
|||
image,
|
||||
exposure
|
||||
};
|
||||
const startTime = +new Date();
|
||||
const startTime = Date.now();
|
||||
if (this.mock) {
|
||||
for (let exp of exposure) {
|
||||
await (0, delay_1.delay)(exp);
|
||||
|
@ -166,7 +168,8 @@ class FD {
|
|||
return {
|
||||
action: Action.DISPLAY,
|
||||
image,
|
||||
time: (+new Date()) - startTime
|
||||
reported: (Date.now()) - startTime,
|
||||
elapsed: (Date.now()) - startTime
|
||||
};
|
||||
}
|
||||
const promise = new Promise(function (resolve, reject) {
|
||||
|
@ -175,7 +178,8 @@ class FD {
|
|||
return resolve({
|
||||
action: Action.DISPLAY,
|
||||
image,
|
||||
time: (+new Date()) - startTime
|
||||
reported: msg.data,
|
||||
elapsed: (Date.now()) - startTime
|
||||
});
|
||||
}
|
||||
else if (typeof msg.error !== 'undefined') {
|
||||
|
@ -192,21 +196,24 @@ class FD {
|
|||
action: Action.STOP,
|
||||
image
|
||||
};
|
||||
const startTime = +new Date();
|
||||
const startTime = Date.now();
|
||||
if (this.mock) {
|
||||
return {
|
||||
action: Action.STOP,
|
||||
image,
|
||||
time: (+new Date()) - startTime
|
||||
reported: (Date.now()) - startTime,
|
||||
elapsed: (Date.now()) - startTime
|
||||
};
|
||||
}
|
||||
const promise = new Promise(function (resolve, reject) {
|
||||
this.waiting = function (msg) {
|
||||
if (msg.action == Action.STOP && msg.success) {
|
||||
this.log.info(msg.data);
|
||||
return resolve({
|
||||
action: Action.STOP,
|
||||
image,
|
||||
time: (+new Date()) - startTime
|
||||
reported: msg.data,
|
||||
elapsed: (Date.now()) - startTime
|
||||
});
|
||||
}
|
||||
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 fd;
|
||||
private send;
|
||||
private stats;
|
||||
private running;
|
||||
private paused;
|
||||
private progress;
|
||||
|
|
|
@ -9,11 +9,78 @@ var SequenceStatus;
|
|||
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
|
||||
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
|
||||
})(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 {
|
||||
constructor(camera, fd, display, ffprobe, send) {
|
||||
this.current = null;
|
||||
this.info = null;
|
||||
this.images = [];
|
||||
this.stats = null;
|
||||
this.running = false;
|
||||
this.paused = false;
|
||||
this.progress = 0;
|
||||
|
@ -31,6 +98,7 @@ class Sequence {
|
|||
if (this.current !== null) {
|
||||
this.running = true;
|
||||
this.log.info(`Started sequence: ${this.current.name}`);
|
||||
this.stats = new Statistics(this.exposure, this.frames);
|
||||
this.run();
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +127,7 @@ class Sequence {
|
|||
}
|
||||
//complete running
|
||||
this.updateClientsOnState();
|
||||
this.stats = null;
|
||||
}
|
||||
async load(seq) {
|
||||
this.current = seq;
|
||||
|
@ -131,7 +200,8 @@ class Sequence {
|
|||
frames: this.frames,
|
||||
status: this.getStatus()
|
||||
},
|
||||
exposure: this.exposure
|
||||
exposure: this.exposure,
|
||||
statistics: this.stats !== null ? this.stats.calculate(this.frame) : null
|
||||
};
|
||||
}
|
||||
getUpdateState() {
|
||||
|
@ -209,13 +279,28 @@ class Sequence {
|
|||
this.updateClientsOnState();
|
||||
}
|
||||
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 dimensions = this.display.getDimensions();
|
||||
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
||||
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
||||
load = Date.now() - start;
|
||||
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();
|
||||
close = Date.now() - start - load - open - exposureElapsed;
|
||||
total = Date.now() - start;
|
||||
this.stats.add(load, open, exposureElapsed, exposureReported, close, total);
|
||||
}
|
||||
}
|
||||
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> {
|
||||
const start : number = +new Date();
|
||||
const start : number = Date.now();
|
||||
let ms : number;
|
||||
await this.confirm(Commands.CAMERA, Commands.CAMERA);
|
||||
ms = (+new Date()) - start;
|
||||
ms = (Date.now()) - start;
|
||||
this.log.info(this.prefix + `frame() - ${ms}ms`);
|
||||
return ms;
|
||||
}
|
||||
|
||||
public async open () : Promise<number> {
|
||||
const start : number = +new Date();
|
||||
const start : number = Date.now();
|
||||
let ms : number;
|
||||
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`);
|
||||
return ms;
|
||||
}
|
||||
|
||||
public async close () : Promise<number> {
|
||||
const start : number = +new Date();
|
||||
const start : number = Date.now();
|
||||
let ms : number;
|
||||
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`);
|
||||
return ms;
|
||||
}
|
||||
|
||||
public async direction (dir : boolean) : Promise<number> {
|
||||
const start : number = +new Date();
|
||||
const start : number = Date.now();
|
||||
let ms : number;
|
||||
const cmd : string = dir ? Commands.CAMERA_FORWARD : Commands.CAMERA_BACKWARD;
|
||||
await this.confirm(cmd, cmd);
|
||||
ms = (+new Date()) - start;
|
||||
ms = (Date.now()) - start;
|
||||
this.log.info(this.prefix + `direction(${dir}) - ${ms}ms`);
|
||||
return ms;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ interface fdOutgoingMessage {
|
|||
|
||||
interface fdIncomingMessage {
|
||||
action : Action,
|
||||
data? : number,
|
||||
success : boolean,
|
||||
error? : string
|
||||
}
|
||||
|
@ -45,7 +46,8 @@ interface fdIncomingMessage {
|
|||
interface fdResult {
|
||||
action : Action,
|
||||
image : string,
|
||||
time : number
|
||||
reported? :number,
|
||||
elapsed? : number
|
||||
}
|
||||
|
||||
export class FD {
|
||||
|
@ -166,12 +168,13 @@ export class FD {
|
|||
h
|
||||
}
|
||||
};
|
||||
const startTime : number = +new Date();
|
||||
const startTime : number = Date.now();
|
||||
if (this.mock) {
|
||||
return {
|
||||
action : Action.LOAD,
|
||||
image,
|
||||
time : (+new Date()) - startTime
|
||||
reported : (Date.now()) - startTime,
|
||||
elapsed : (Date.now()) - startTime
|
||||
};
|
||||
}
|
||||
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
||||
|
@ -180,7 +183,8 @@ export class FD {
|
|||
return resolve({
|
||||
action : Action.LOAD,
|
||||
image,
|
||||
time : (+new Date()) - startTime
|
||||
reported : msg.data,
|
||||
elapsed : (Date.now()) - startTime
|
||||
});
|
||||
} else if (typeof msg.error !== 'undefined') {
|
||||
return reject(new Error(msg.error));
|
||||
|
@ -198,7 +202,7 @@ export class FD {
|
|||
image,
|
||||
exposure
|
||||
};
|
||||
const startTime : number = +new Date();
|
||||
const startTime : number = Date.now();
|
||||
if (this.mock) {
|
||||
for (let exp of exposure) {
|
||||
await delay(exp);
|
||||
|
@ -206,7 +210,8 @@ export class FD {
|
|||
return {
|
||||
action : Action.DISPLAY,
|
||||
image,
|
||||
time : (+new Date()) - startTime
|
||||
reported : (Date.now()) - startTime,
|
||||
elapsed : (Date.now()) - startTime
|
||||
};
|
||||
}
|
||||
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
||||
|
@ -215,7 +220,8 @@ export class FD {
|
|||
return resolve({
|
||||
action : Action.DISPLAY,
|
||||
image,
|
||||
time : (+new Date()) - startTime
|
||||
reported : msg.data,
|
||||
elapsed : (Date.now()) - startTime
|
||||
});
|
||||
} else if (typeof msg.error !== 'undefined') {
|
||||
return reject(new Error(msg.error));
|
||||
|
@ -232,21 +238,24 @@ export class FD {
|
|||
action : Action.STOP,
|
||||
image
|
||||
};
|
||||
const startTime : number = +new Date();
|
||||
const startTime : number = Date.now();
|
||||
if (this.mock) {
|
||||
return {
|
||||
action : Action.STOP,
|
||||
image,
|
||||
time : (+new Date()) - startTime
|
||||
reported : (Date.now()) - startTime,
|
||||
elapsed : (Date.now()) - startTime
|
||||
};
|
||||
}
|
||||
const promise : Promise<fdResult> = new Promise(function (resolve : Function, reject : Function) {
|
||||
this.waiting = function (msg : fdIncomingMessage) {
|
||||
if (msg.action == Action.STOP && msg.success) {
|
||||
this.log.info(msg.data);
|
||||
return resolve({
|
||||
action : Action.STOP,
|
||||
image,
|
||||
time : (+new Date()) - startTime
|
||||
reported : msg.data,
|
||||
elapsed : (Date.now()) - startTime
|
||||
});
|
||||
} else if (typeof msg.error !== 'undefined') {
|
||||
return reject(new Error(msg.error));
|
||||
|
|
|
@ -19,7 +19,29 @@ interface SequenceState {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { createLog } from '../log';
|
|||
import { delay } from '../delay';
|
||||
import type { Logger } from 'winston';
|
||||
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 { Display, Dimensions } from '../display';
|
||||
import type { FFPROBE, VideoInfo } from '../ffprobe';
|
||||
|
@ -14,6 +14,97 @@ enum SequenceStatus {
|
|||
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 {
|
||||
private log : Logger;
|
||||
private current : SequenceObject = null;
|
||||
|
@ -24,9 +115,11 @@ export class Sequence {
|
|||
private ffprobe : FFPROBE;
|
||||
private fd : FD;
|
||||
private send : Function;
|
||||
private stats : Statistics = null;
|
||||
private running : boolean = false;
|
||||
private paused : boolean = false;
|
||||
|
||||
|
||||
private progress : number = 0;
|
||||
private frame : number = 0;
|
||||
private frames : number = 0;
|
||||
|
@ -46,6 +139,7 @@ export class Sequence {
|
|||
if (this.current !== null) {
|
||||
this.running = true;
|
||||
this.log.info(`Started sequence: ${this.current.name}`);
|
||||
this.stats = new Statistics(this.exposure, this.frames);
|
||||
this.run();
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +170,7 @@ export class Sequence {
|
|||
}
|
||||
//complete running
|
||||
this.updateClientsOnState();
|
||||
this.stats = null;
|
||||
}
|
||||
|
||||
public async load (seq : SequenceObject) {
|
||||
|
@ -158,7 +253,8 @@ export class Sequence {
|
|||
frames : this.frames,
|
||||
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 () {
|
||||
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 dimensions : fdOutgoingPosition = this.display.getDimensions();
|
||||
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
||||
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
||||
load = Date.now() - start;
|
||||
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();
|
||||
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%;
|
||||
}
|
||||
|
||||
.quarter{
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 25%;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.edited {
|
||||
background-color: yellow !important;
|
||||
color: rgb(0, 0, 0) !important;
|
||||
}
|
||||
|
||||
fieldset.inline .field-row {
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -71,6 +81,14 @@ fieldset.inline input.medium {
|
|||
max-width: 70px;
|
||||
}
|
||||
|
||||
label {
|
||||
width: 80px;
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
progress {
|
||||
width: 97vw;
|
||||
position: absolute;
|
||||
|
@ -78,16 +96,26 @@ progress {
|
|||
left: 0.5vw;
|
||||
}
|
||||
|
||||
button.small{
|
||||
button.small,
|
||||
input.small {
|
||||
width: 35px;
|
||||
max-width: 35px;
|
||||
min-width: 35px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
button.medium{
|
||||
button.medium,
|
||||
input.medium {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
min-width: 50px;
|
||||
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 {
|
||||
IDLE = 0,
|
||||
RUNNING = 1,
|
||||
|
@ -56,6 +57,8 @@ declare class Client {
|
|||
private setFrame;
|
||||
private setExposure;
|
||||
private setDisplay;
|
||||
edited(el: HTMLElement): void;
|
||||
private setStatistics;
|
||||
private cmd;
|
||||
disableClass(className: string): void;
|
||||
enableClass(className: string): void;
|
||||
|
@ -80,5 +83,8 @@ declare class Client {
|
|||
exitFullscreen(): void;
|
||||
private active;
|
||||
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;
|
||||
(function (SequenceStatus) {
|
||||
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
|
||||
|
@ -127,6 +128,7 @@ class Client {
|
|||
document.getElementById('sequenceCtrlForm').reset();
|
||||
document.getElementById('manualCtrlForm').reset();
|
||||
document.getElementById('exposureCtrlForm').reset();
|
||||
document.getElementById('statisticsForm').reset();
|
||||
this.disableClass('sequenceCtrl');
|
||||
this.disableClass('manualCtrl');
|
||||
this.disableClass('exposureCtrl');
|
||||
|
@ -159,13 +161,15 @@ class Client {
|
|||
this.setStatus(state.sequence);
|
||||
this.setExposure(state);
|
||||
this.setDisplay(state);
|
||||
document.getElementById('sequence').value = state.sequence.hash;
|
||||
this.set('sequence', state.sequence.hash);
|
||||
this.removeClass('sequence', 'edited');
|
||||
}
|
||||
setUpdate(state) {
|
||||
this.setProgress(state.sequence);
|
||||
this.setFrame(state.sequence);
|
||||
this.setStatus(state.sequence);
|
||||
this.setExposure(state);
|
||||
this.setStatistics(state.statistics);
|
||||
this.display.updateImage();
|
||||
}
|
||||
setStatus(sequence) {
|
||||
|
@ -190,37 +194,54 @@ class Client {
|
|||
}
|
||||
setProgress(sequence) {
|
||||
const percent = sequence.progress * 100.0;
|
||||
if (this.progress !== null) {
|
||||
this.progress.value = sequence.progress;
|
||||
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
||||
}
|
||||
this.progress.value = sequence.progress;
|
||||
this.progressText.innerText = `Progress: ${Math.floor(percent)}%`;
|
||||
}
|
||||
setFrame(sequence) {
|
||||
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) {
|
||||
if (typeof state.exposure !== 'undefined') {
|
||||
const el = document.getElementById('exposure');
|
||||
this.enableClass('exposureCtrl');
|
||||
document.getElementById('exposure').value = `${state.exposure}`;
|
||||
this.set('exposure', `${state.exposure}`);
|
||||
this.removeClass('exposure', 'edited');
|
||||
}
|
||||
}
|
||||
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') {
|
||||
widthEl.value = state.display.width;
|
||||
heightEl.value = state.display.height;
|
||||
srcWidthEl.value = state.source.width;
|
||||
srcHeightEl.value = state.source.height;
|
||||
widthEl.readOnly = false;
|
||||
heightEl.readOnly = false;
|
||||
this.set('displayWidth', state.display.width.toString());
|
||||
this.set('displayHeight', state.display.height.toString());
|
||||
this.set('sourceWidth', state.source.width.toString());
|
||||
this.set('sourceHeight', state.source.height.toString());
|
||||
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) {
|
||||
switch (msg.cmd) {
|
||||
case 'ping':
|
||||
|
@ -318,12 +339,10 @@ class Client {
|
|||
return;
|
||||
}
|
||||
msg = { cmd: 'select', state: { sequence: { hash } } };
|
||||
console.log('send select');
|
||||
console.log(hash);
|
||||
console.log(`send select ${hash}`);
|
||||
this.client.send(JSON.stringify(msg));
|
||||
}
|
||||
receiveSelect(msg) {
|
||||
console.log('got select');
|
||||
this.enableClass('sequenceCtrl');
|
||||
this.setSequence(msg.state);
|
||||
}
|
||||
|
@ -334,7 +353,7 @@ class Client {
|
|||
this.client.send(JSON.stringify({ cmd: 'stop' }));
|
||||
}
|
||||
sendExposure() {
|
||||
const exposure = parseInt(document.getElementById('exposure').value);
|
||||
const exposure = parseInt(this.get('exposure'));
|
||||
this.client.send(JSON.stringify({ cmd: 'exposure', state: { exposure } }));
|
||||
}
|
||||
receiveUpdate(msg) {
|
||||
|
@ -354,11 +373,28 @@ class Client {
|
|||
}
|
||||
}
|
||||
active() {
|
||||
document.getElementById('overlay').classList.add('active');
|
||||
this.addClass('overlay', 'active');
|
||||
}
|
||||
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
|
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">
|
||||
<legend>Sequence</legend>
|
||||
<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>
|
||||
{{#each sequences}}
|
||||
<option value="{{this.hash}}">{{this.name}}</option>
|
||||
|
@ -80,47 +80,107 @@
|
|||
<fieldset id="exposureCtrl" class="inline half">
|
||||
<legend>Exposure</legend>
|
||||
<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>
|
||||
<button id="exposureUpdate" class="exposureCtrl" onclick="client.sendExposure();">Update</button>
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<fieldset class="inline half" id="sequenceCtrl">
|
||||
<legend>Sequence Controls</legend>
|
||||
<form id="sequenceCtrlForm" onsubmit="return false;">
|
||||
<button id="start" class="medium sequenceCtrl" onclick="client.sendStart();" disabled>Start</button>
|
||||
<button id="stop" class="medium sequenceCtrl" onclick="client.sendStop();" disabled>Stop</button>
|
||||
<button id="rewind" class="small sequenceCtrl" onclick="client.sendToStart();" disabled><<</button>
|
||||
<button id="rewind" class="small sequenceCtrl" onclick="client.sendRewind();" disabled><</button>
|
||||
<input id="frame" type="number" value="00000" class="sequenceCtrl medium" onchange="client.sendFrameSet();" disabled />
|
||||
<button id="advance" class="small sequenceCtrl" onclick="client.sendAdvance()" disabled>></button>
|
||||
<button id="advance" class="small sequenceCtrl" onclick="client.sendToEnd()" disabled>>></button>
|
||||
</form>
|
||||
</fieldset>
|
||||
<fieldset id="displayAdjust" class="inline half">
|
||||
<legend>Display Adjust</legend>
|
||||
<form id="displayAdjustForm" onsubmit="return false;">
|
||||
<button class="small" id="offsetXPlus" disabled>X +</button>
|
||||
<button class="small" id="offsetXMinus" disabled>X -</button>
|
||||
<button class="small" id="offsetYPlus" disabled>Y +</button>
|
||||
<button class="small" id="offsetYMinus" disabled>Y -</button>
|
||||
<button class="small" id="widthPlus" disabled>W +</button>
|
||||
<button class="small" id="widthMinus" disabled>W -</button>
|
||||
<button class="small" id="heightPlus" disabled>H +</button>
|
||||
<button class="small" id="heightMinus" disabled>H -</button>
|
||||
</form>
|
||||
</fieldset>
|
||||
<div class="half">
|
||||
<div>
|
||||
<fieldset id="sequenceCtrl">
|
||||
<legend>Sequence Controls</legend>
|
||||
<form id="sequenceCtrlForm" onsubmit="return false;">
|
||||
<button id="start" class="medium sequenceCtrl" onclick="client.sendStart();" disabled>Start</button>
|
||||
<button id="stop" class="medium sequenceCtrl" onclick="client.sendStop();" disabled>Stop</button>
|
||||
<button id="rewind" class="small sequenceCtrl" onclick="client.sendToStart();" disabled><<</button>
|
||||
<button id="rewind" class="small sequenceCtrl" onclick="client.sendRewind();" disabled><</button>
|
||||
<input id="frame" type="number" value="00000" class="sequenceCtrl large" oninput="client.edited(this);" onchange="client.sendFrameSet();" disabled />
|
||||
<button id="advance" class="small sequenceCtrl" onclick="client.sendAdvance()" disabled>></button>
|
||||
<button id="advance" class="small sequenceCtrl" onclick="client.sendToEnd()" disabled>>></button>
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<fieldset id="manualCtrl">
|
||||
<legend>Manual Controls</legend>
|
||||
<form id="manualCtrlForm" onsubmit="return false;" >
|
||||
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open</button>
|
||||
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
|
||||
<button id="focus" class="manualCtrl" onclick="">Focus</button>
|
||||
<button id="framing" class="manualCtrl" onclick="">Framing</button>
|
||||
</form>
|
||||
</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>
|
||||
<fieldset id="manualCtrl" class="inline half">
|
||||
<legend>Manual Controls</legend>
|
||||
<form id="manualCtrlForm" onsubmit="return false;" >
|
||||
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open</button>
|
||||
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
|
||||
<button id="focus" class="manualCtrl" onclick="">Focus</button>
|
||||
<button id="framing" class="manualCtrl" onclick="">Framing</button>
|
||||
<fieldset id="statistics" class="inline">
|
||||
<legend>Statistics</legend>
|
||||
<form id="statisticsForm" onsubmit="return false;" class="flex">
|
||||
<div id="statisticsFrame" class="quarter">
|
||||
<div>
|
||||
<label for="statsFrameTotalAvg">Frame Total Avg</label><input id="statsFrameTotalAvg" class="large" type="text" readonly value="0" /><span> ms +/-</span>
|
||||
<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>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue