|
|
|
@ -1,3 +1,12 @@
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var LOADING = 1;
|
|
|
|
|
|
|
|
|
|
var ajax = null;
|
|
|
|
|
var wait_for_events_interval = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function evaluateLoadTimes() {
|
|
|
|
|
if (liveMode != 1 && currentSpeed == 0) return; // don't evaluate when we are not moving as we can do nothing really fast.
|
|
|
|
|
|
|
|
|
@ -45,26 +54,33 @@ function evaluateLoadTimes() {
|
|
|
|
|
$j('#fps').text("Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + ".");
|
|
|
|
|
} // end evaluateLoadTimes()
|
|
|
|
|
|
|
|
|
|
function findEventByTime(arr, time, debug) {
|
|
|
|
|
function findEventByTime(arr, time, debug=false) {
|
|
|
|
|
let start = 0;
|
|
|
|
|
let end = arr.length-1; // -1 because 0 based indexing
|
|
|
|
|
|
|
|
|
|
//console.log("looking for "+time+" Start: " + arr[start].StartTimeSecs + ' End: ' + arr[end].EndTimeSecs);
|
|
|
|
|
if (debug) {
|
|
|
|
|
if ( arr.length ) {
|
|
|
|
|
console.log("looking for "+time+" Start: " + arr[start].StartTimeSecs + ' End: ' + arr[end].EndTimeSecs);
|
|
|
|
|
} else {
|
|
|
|
|
console.log("looking for "+time+" but nothing in arr");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Iterate while start not meets end
|
|
|
|
|
while ((start <= end) && (arr[start].StartTimeSecs <= time) && (!arr[end].EndTimeSecs || (arr[end].EndTimeSecs >= time))) {
|
|
|
|
|
//console.log("looking for "+time+" Start: " + arr[start].StartTimeSecs + ' End: ' + arr[end].EndTimeSecs);
|
|
|
|
|
if (debug)
|
|
|
|
|
console.log("looking for "+time+" Start: " + arr[start].StartTimeSecs + ' End: ' + arr[end].EndTimeSecs);
|
|
|
|
|
// Find the middle index
|
|
|
|
|
const middle = Math.floor((start + end)/2);
|
|
|
|
|
const zm_event = arr[middle];
|
|
|
|
|
|
|
|
|
|
// If element is present at mid, return True
|
|
|
|
|
//console.log(middle, zm_event, time);
|
|
|
|
|
if (debug) console.log(middle, zm_event, time);
|
|
|
|
|
if ((zm_event.StartTimeSecs <= time) && (!zm_event.EndTimeSecs || (zm_event.EndTimeSecs >= time))) {
|
|
|
|
|
//console.log("Found it at ", zm_event);
|
|
|
|
|
if (debug) console.log("Found it at ", zm_event);
|
|
|
|
|
return zm_event;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//console.log("Didn't find it looking for "+time+" Start: " + zm_event.StartTimeSecs + ' End: ' + zm_event.EndTimeSecs);
|
|
|
|
|
if (debug) console.log("Didn't find it looking for "+time+" Start: " + zm_event.StartTimeSecs + ' End: ' + zm_event.EndTimeSecs);
|
|
|
|
|
// Else look in left or right half accordingly
|
|
|
|
|
if (zm_event.StartTimeSecs < time) {
|
|
|
|
|
start = middle + 1;
|
|
|
|
@ -77,7 +93,7 @@ function findEventByTime(arr, time, debug) {
|
|
|
|
|
return false;
|
|
|
|
|
} // end function findEventByTime
|
|
|
|
|
|
|
|
|
|
function findFrameByTime(arr, time, debug) {
|
|
|
|
|
function findFrameByTime(arr, time, debug=false) {
|
|
|
|
|
if (!arr) {
|
|
|
|
|
console.log("No array in findFrameByTime");
|
|
|
|
|
return false;
|
|
|
|
@ -149,7 +165,7 @@ function findFrameByTime(arr, time, debug) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} // end while
|
|
|
|
|
if (debug) console.log("Didn't find it");
|
|
|
|
|
if (debug) console.log("Didn't find frame it");
|
|
|
|
|
return false;
|
|
|
|
|
} // end function findFrameByTime(arr, time, debug=false)
|
|
|
|
|
|
|
|
|
@ -180,7 +196,6 @@ function getFrame(monId, time, last_Frame) {
|
|
|
|
|
|
|
|
|
|
let Event = findEventByTime(events_for_monitor[monId], time, false);
|
|
|
|
|
if (Event === false) {
|
|
|
|
|
// This might be better with a binary search
|
|
|
|
|
for (let i=0, len=events_for_monitor[monId].length; i<len; i++) {
|
|
|
|
|
const event_id = events_for_monitor[monId][i].Id;
|
|
|
|
|
const e = events[event_id];
|
|
|
|
@ -207,19 +222,28 @@ function getFrame(monId, time, last_Frame) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!Event) return;
|
|
|
|
|
if (!Event) {
|
|
|
|
|
console.log('No event found for ' + time + ' ' + secs2inputstr(time) + ' on monitor ' + monId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Event.FramesById) {
|
|
|
|
|
// It is assumed at this time that every event has frames
|
|
|
|
|
console.log('No FramesById for event ', Event.Id);
|
|
|
|
|
load_Frames({event_id: Event}).then(function() {
|
|
|
|
|
var event_list = {};
|
|
|
|
|
event_list[Event.Id] = Event;
|
|
|
|
|
loadFrames(event_list).then(function() {
|
|
|
|
|
if (!Event.FramesById) {
|
|
|
|
|
console.log("No FramesById after load_Frames!", Event);
|
|
|
|
|
console.log("No FramesById after loadFrames!", Event);
|
|
|
|
|
}
|
|
|
|
|
return findFrameByTime(Event.FramesById, time);
|
|
|
|
|
}, function(Error) {
|
|
|
|
|
console.log(Error);
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
} else if (!Event.FramesById.length) {
|
|
|
|
|
console.log("frames loading for event " + Event.Id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Need to get frame by time, not some fun calc that assumes frames have the same length.
|
|
|
|
@ -302,37 +326,32 @@ function getImageSource(monId, time) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let scale = parseInt(100*monitorCanvasObj[monId].width / monitorWidth[monId]);
|
|
|
|
|
let scale = parseInt(100 * monitorCanvasObj[monId].width / monitorWidth[monId]);
|
|
|
|
|
if (scale > 100) {
|
|
|
|
|
scale = 100;
|
|
|
|
|
} else {
|
|
|
|
|
scale = 10 * parseInt(scale/10);
|
|
|
|
|
scale = 10 * parseInt(scale/10); // Round to nearest 10
|
|
|
|
|
// May need to limit how small we can go to maintain fidelity
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Storage[0] is guaranteed to exist as we make sure it is there in montagereview.js.php
|
|
|
|
|
const storage = Storage[e.StorageId] ? Storage[e.StorageId] : Storage[0];
|
|
|
|
|
// monitorServerId may be 0, which gives us the default Server entry
|
|
|
|
|
const server = storage.ServerId ? Servers[storage.ServerId] : Servers[monitorServerId[monId]];
|
|
|
|
|
return server.PathToZMS + '?mode=jpeg&frames=1&event=' + Frame.EventId + '&frame='+frame_id +
|
|
|
|
|
return server.PathToZMS + '?mode=jpeg&event=' + Frame.EventId + '&frame='+frame_id +
|
|
|
|
|
//"&width=" + monitorCanvasObj[monId].width +
|
|
|
|
|
//"&height=" + monitorCanvasObj[monId].height +
|
|
|
|
|
"&scale=" + scale +
|
|
|
|
|
"&frames=1" +
|
|
|
|
|
"&rate=" + 100*speeds[speedIndex] +
|
|
|
|
|
'&' + auth_relay;
|
|
|
|
|
|
|
|
|
|
return server.PathToIndex +
|
|
|
|
|
'?view=image&eid=' + Frame.EventId + '&fid='+frame_id +
|
|
|
|
|
"&width=" + monitorCanvasObj[monId].width +
|
|
|
|
|
"&height=" + monitorCanvasObj[monId].height;
|
|
|
|
|
} // end found Frame
|
|
|
|
|
return '';
|
|
|
|
|
} // end function getImageSource
|
|
|
|
|
|
|
|
|
|
// callback when loading an image. Will load itself to the canvas, or draw no data
|
|
|
|
|
function imagedone( obj, monId, success ) {
|
|
|
|
|
if ( success ) {
|
|
|
|
|
if (success) {
|
|
|
|
|
const canvasCtx = monitorCanvasCtx[monId];
|
|
|
|
|
const canvasObj = monitorCanvasObj[monId];
|
|
|
|
|
|
|
|
|
@ -369,42 +388,25 @@ function imagedone( obj, monId, success ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNoData( monId ) {
|
|
|
|
|
if ( monId ) {
|
|
|
|
|
var canvasCtx = monitorCanvasCtx[monId];
|
|
|
|
|
var canvasObj = monitorCanvasObj[monId];
|
|
|
|
|
canvasCtx.fillStyle="white";
|
|
|
|
|
canvasCtx.fillRect(0, 0, canvasObj.width, canvasObj.height);
|
|
|
|
|
var textSize=canvasObj.width * 0.15;
|
|
|
|
|
var text="No Event";
|
|
|
|
|
canvasCtx.font = "600 " + textSize.toString() + "px Arial";
|
|
|
|
|
canvasCtx.fillStyle="black";
|
|
|
|
|
var textWidth = canvasCtx.measureText(text).width;
|
|
|
|
|
canvasCtx.fillText(text, canvasObj.width/2 - textWidth/2, canvasObj.height/2);
|
|
|
|
|
} else {
|
|
|
|
|
console.log("No monId in loadNoData");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function writeText( monId, text ) {
|
|
|
|
|
if ( monId ) {
|
|
|
|
|
var canvasCtx = monitorCanvasCtx[monId];
|
|
|
|
|
var canvasObj = monitorCanvasObj[monId];
|
|
|
|
|
function writeText(monId, text) {
|
|
|
|
|
if (monId) {
|
|
|
|
|
const canvasCtx = monitorCanvasCtx[monId];
|
|
|
|
|
const canvasObj = monitorCanvasObj[monId];
|
|
|
|
|
//canvasCtx.fillStyle="white";
|
|
|
|
|
//canvasCtx.fillRect(0, 0, canvasObj.width, canvasObj.height);
|
|
|
|
|
var textSize=canvasObj.width * 0.15;
|
|
|
|
|
canvasCtx.font = "600 " + textSize.toString() + "px Arial";
|
|
|
|
|
canvasCtx.fillStyle="white";
|
|
|
|
|
var textSize = canvasObj.width * 0.15;
|
|
|
|
|
canvasCtx.font = '600 ' + textSize.toString() + "px Arial";
|
|
|
|
|
canvasCtx.fillStyle = 'white';
|
|
|
|
|
var textWidth = canvasCtx.measureText(text).width;
|
|
|
|
|
canvasCtx.fillText(text, canvasObj.width/2 - textWidth/2, canvasObj.height/2);
|
|
|
|
|
} else {
|
|
|
|
|
console.log("No monId in loadNoData");
|
|
|
|
|
console.log('No monId in writeText');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Either draws the
|
|
|
|
|
function loadImage2Monitor( monId, url ) {
|
|
|
|
|
if ( monitorLoading[monId] && monitorImageObject[monId].src != url ) {
|
|
|
|
|
function loadImage2Monitor(monId, url) {
|
|
|
|
|
if ( monitorLoading[monId] && (monitorImageObject[monId].src != url) ) {
|
|
|
|
|
// never queue the same image twice (if it's loading it has to be defined, right?
|
|
|
|
|
monitorLoadingStageURL[monId] = url; // we don't care if we are overriting, it means it didn't change fast enough
|
|
|
|
|
} else {
|
|
|
|
@ -430,91 +432,90 @@ function timerFire() {
|
|
|
|
|
console.log("Turn off interrupts timerInterfave" + timerInterval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( (currentSpeed > 0 || liveMode != 0) && ! timerObj ) {
|
|
|
|
|
timerObj = setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (liveMode) {
|
|
|
|
|
outputUpdate(currentTimeSecs); // In live mode we basically do nothing but redisplay
|
|
|
|
|
} else if (currentTimeSecs + playSecsPerInterval >= maxTimeSecs) {
|
|
|
|
|
// beyond the end just stop
|
|
|
|
|
console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval + " >= " + maxTimeSecs + " so stopping");
|
|
|
|
|
if (speedIndex) setSpeed(0);
|
|
|
|
|
setSpeed(0);
|
|
|
|
|
outputUpdate(currentTimeSecs);
|
|
|
|
|
} else {
|
|
|
|
|
//console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval);
|
|
|
|
|
} else if (playSecsPerInterval || (currentTimeSecs==minTimeSecs)) {
|
|
|
|
|
outputUpdate(playSecsPerInterval + currentTimeSecs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((currentSpeed > 0 || liveMode != 0) && !timerObj) {
|
|
|
|
|
timerObj = setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero
|
|
|
|
|
} else {
|
|
|
|
|
console.log("CurrentSpeed", currentSpeed, "liveMode", liveMode, timerObj);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} // end function timerFire()
|
|
|
|
|
|
|
|
|
|
// val is seconds?
|
|
|
|
|
function drawSliderOnGraph(val) {
|
|
|
|
|
var sliderWidth=10;
|
|
|
|
|
var sliderLineWidth=1;
|
|
|
|
|
var sliderHeight=cHeight;
|
|
|
|
|
if (numMonitors <= 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( liveMode == 1 ) {
|
|
|
|
|
val = Math.floor( Date.now() / 1000);
|
|
|
|
|
}
|
|
|
|
|
// Set some sizes
|
|
|
|
|
|
|
|
|
|
var sliderWidth=10;
|
|
|
|
|
var sliderLineWidth=1;
|
|
|
|
|
var sliderHeight=cHeight;
|
|
|
|
|
// Set some sizes
|
|
|
|
|
var labelpx = Math.max( 6, Math.min( 20, parseInt(cHeight * timeLabelsFractOfRow / (numMonitors+1)) ) );
|
|
|
|
|
var labbottom = parseInt(cHeight * 0.2 / (numMonitors+1)).toString() + "px"; // This is positioning same as row labels below, but from bottom so 1-position
|
|
|
|
|
var labfont = labelpx + "px"; // set this like below row labels
|
|
|
|
|
|
|
|
|
|
if ( numMonitors > 0 ) {
|
|
|
|
|
// if we have no data to display don't do the slider itself
|
|
|
|
|
var sliderX = parseInt((val - minTimeSecs) / rangeTimeSecs * cWidth - sliderWidth/2); // position left side of slider
|
|
|
|
|
if ( sliderX < 0 ) sliderX = 0;
|
|
|
|
|
if ( sliderX + sliderWidth > cWidth ) {
|
|
|
|
|
sliderX = cWidth-sliderWidth-1;
|
|
|
|
|
}
|
|
|
|
|
// if we have no data to display don't do the slider itself
|
|
|
|
|
let sliderX = parseInt((val - minTimeSecs) / rangeTimeSecs * cWidth - sliderWidth/2); // position left side of slider
|
|
|
|
|
if ( sliderX < 0 ) sliderX = 0;
|
|
|
|
|
if ( sliderX + sliderWidth > cWidth ) sliderX = cWidth-sliderWidth-1;
|
|
|
|
|
|
|
|
|
|
// If we have data already saved first restore it from LAST time
|
|
|
|
|
// If we have data already saved first restore it from LAST time
|
|
|
|
|
|
|
|
|
|
if ( typeof underSlider !== 'undefined' ) {
|
|
|
|
|
ctx.putImageData(underSlider, underSliderX, 0, 0, 0, sliderWidth, sliderHeight);
|
|
|
|
|
underSlider = undefined;
|
|
|
|
|
}
|
|
|
|
|
if ( liveMode == 0 ) {
|
|
|
|
|
// we get rid of the slider if we switch to live (since it may not be in the "right" place)
|
|
|
|
|
// Now save where we are putting it THIS time
|
|
|
|
|
underSlider = ctx.getImageData(sliderX, 0, sliderWidth, sliderHeight);
|
|
|
|
|
// And add in the slider'
|
|
|
|
|
ctx.lineWidth = sliderLineWidth;
|
|
|
|
|
ctx.strokeStyle = 'yellow';
|
|
|
|
|
// looks like strokes are on the outside (or could be) so shrink it by the line width so we replace all the pixels
|
|
|
|
|
ctx.strokeRect(sliderX+sliderLineWidth, sliderLineWidth, sliderWidth - 2*sliderLineWidth, sliderHeight - 2*sliderLineWidth);
|
|
|
|
|
underSliderX = sliderX;
|
|
|
|
|
}
|
|
|
|
|
var o = document.getElementById('scruboutput');
|
|
|
|
|
if ( liveMode == 1 ) {
|
|
|
|
|
o.innerHTML = "Live Feed @ " + (1000 / currentDisplayInterval).toFixed(1) + " fps";
|
|
|
|
|
o.style.color = "red";
|
|
|
|
|
} else {
|
|
|
|
|
o.innerHTML = secs2dbstr(val);
|
|
|
|
|
o.style.color = 'white';
|
|
|
|
|
}
|
|
|
|
|
o.style.position = "absolute";
|
|
|
|
|
o.style.bottom = labbottom;
|
|
|
|
|
o.style.font = labfont;
|
|
|
|
|
// try to get length and then when we get too close to the right switch to the left
|
|
|
|
|
var len = o.offsetWidth;
|
|
|
|
|
var x;
|
|
|
|
|
if ( sliderX > cWidth/2 ) {
|
|
|
|
|
x = sliderX - len - 10;
|
|
|
|
|
} else {
|
|
|
|
|
x = sliderX + 10;
|
|
|
|
|
}
|
|
|
|
|
o.style.left = x.toString() + "px";
|
|
|
|
|
if ( typeof underSlider !== 'undefined' ) {
|
|
|
|
|
ctx.putImageData(underSlider, underSliderX, 0, 0, 0, sliderWidth, sliderHeight);
|
|
|
|
|
underSlider = undefined;
|
|
|
|
|
}
|
|
|
|
|
if ( liveMode == 0 ) {
|
|
|
|
|
// we get rid of the slider if we switch to live (since it may not be in the "right" place)
|
|
|
|
|
// Now save where we are putting it THIS time
|
|
|
|
|
underSlider = ctx.getImageData(sliderX, 0, sliderWidth, sliderHeight);
|
|
|
|
|
// And add in the slider'
|
|
|
|
|
ctx.lineWidth = sliderLineWidth;
|
|
|
|
|
ctx.strokeStyle = 'yellow';
|
|
|
|
|
// looks like strokes are on the outside (or could be) so shrink it by the line width so we replace all the pixels
|
|
|
|
|
ctx.strokeRect(sliderX+sliderLineWidth, sliderLineWidth, sliderWidth - 2*sliderLineWidth, sliderHeight - 2*sliderLineWidth);
|
|
|
|
|
underSliderX = sliderX;
|
|
|
|
|
}
|
|
|
|
|
var o = document.getElementById('scruboutput');
|
|
|
|
|
if ( liveMode == 1 ) {
|
|
|
|
|
o.innerHTML = 'Live Feed @ ' + (1000 / currentDisplayInterval).toFixed(1) + ' fps';
|
|
|
|
|
o.style.color = 'red';
|
|
|
|
|
} else {
|
|
|
|
|
o.innerHTML = secs2dbstr(val);
|
|
|
|
|
o.style.color = 'white';
|
|
|
|
|
}
|
|
|
|
|
o.style.position = 'absolute';
|
|
|
|
|
o.style.bottom = labbottom;
|
|
|
|
|
o.style.font = labfont;
|
|
|
|
|
// try to get length and then when we get too close to the right switch to the left
|
|
|
|
|
var len = o.offsetWidth;
|
|
|
|
|
var x;
|
|
|
|
|
if ( sliderX > cWidth/2 ) {
|
|
|
|
|
x = sliderX - len - 10;
|
|
|
|
|
} else {
|
|
|
|
|
x = sliderX + 10;
|
|
|
|
|
}
|
|
|
|
|
o.style.left = x.toString() + "px";
|
|
|
|
|
|
|
|
|
|
// This displays (or not) the left/right limits depending on how close the slider is.
|
|
|
|
|
// Because these change widths if the slider is too close, use the slider width as an estimate for the left/right label length (i.e. don't recalculate len from above)
|
|
|
|
|
// If this starts to collide increase some of the extra space
|
|
|
|
|
|
|
|
|
|
var o = document.getElementById('scrubleft');
|
|
|
|
|
o = document.getElementById('scrubleft');
|
|
|
|
|
o.innerHTML = secs2dbstr(minTimeSecs);
|
|
|
|
|
o.style.position = "absolute";
|
|
|
|
|
o.style.bottom = labbottom;
|
|
|
|
@ -532,7 +533,7 @@ function drawSliderOnGraph(val) {
|
|
|
|
|
o.style.display = "inline-flex"; // safari won't take this but will just ignore
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var o = document.getElementById('scrubright');
|
|
|
|
|
o = document.getElementById('scrubright');
|
|
|
|
|
o.innerHTML = secs2dbstr(maxTimeSecs);
|
|
|
|
|
o.style.position = "absolute";
|
|
|
|
|
o.style.bottom = labbottom;
|
|
|
|
@ -547,6 +548,40 @@ function drawSliderOnGraph(val) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function drawFrameOnGraph(frame) {
|
|
|
|
|
if (!frame.Score) return;
|
|
|
|
|
// Now put in scored frames (if any)
|
|
|
|
|
var x1 = parseInt( (frame.TimeStampSecs - minTimeSecs) / rangeTimeSecs * cWidth); // round low end down
|
|
|
|
|
var x2 = parseInt( (frame.TimeStampSecs - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ); // round up
|
|
|
|
|
if (x2-x1 < 2) x2=x1+2; // So it is visible make them all at least this number of seconds wide
|
|
|
|
|
ctx.fillStyle=monitorColour[Event.MonitorId];
|
|
|
|
|
//ctx.fillStyle = '#ff0000';
|
|
|
|
|
ctx.globalAlpha = 0.4 + 0.6 * (1 - frame.Score/maxScore); // Background is scaled but even lowest is twice as dark as the background
|
|
|
|
|
const MonitorId = events[frame.EventId].MonitorId;
|
|
|
|
|
ctx.fillRect(x1, monitorIndex[MonitorId]*rowHeight, x2-x1, rowHeight-2);
|
|
|
|
|
//console.log("Drew frame from ", x1, MonitorId, monitorIndex[MonitorId]*rowHeight, x2-x1, rowHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function drawEventOnGraph(Event) {
|
|
|
|
|
// round low end down
|
|
|
|
|
const x1 = parseInt((Event.StartTimeSecs - minTimeSecs) / rangeTimeSecs * cWidth);
|
|
|
|
|
if (!Event.EndTimeSecs) Event.EndTimeSecs = maxTimeSecs;
|
|
|
|
|
// round high end up to be sure consecutive ones connect
|
|
|
|
|
const x2 = parseInt((Event.EndTimeSecs - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 );
|
|
|
|
|
if (!monitorColour[Event.MonitorId]) {
|
|
|
|
|
console.log("No colour for ", Event.MonitorId, monitorColour);
|
|
|
|
|
ctx.fillStyle = '#43bcf2';
|
|
|
|
|
} else {
|
|
|
|
|
ctx.fillStyle = monitorColour[Event.MonitorId];
|
|
|
|
|
}
|
|
|
|
|
ctx.globalAlpha = 0.2; // light color for background
|
|
|
|
|
// Erase any overlap so it doesn't look artificially darker
|
|
|
|
|
ctx.clearRect(x1, monitorIndex[Event.MonitorId]*rowHeight, x2-x1, rowHeight);
|
|
|
|
|
ctx.fillRect(x1, monitorIndex[Event.MonitorId]*rowHeight, x2-x1, rowHeight-2);
|
|
|
|
|
//outputUpdate(currentTimeSecs);
|
|
|
|
|
console.log("Drew event from ", x1, monitorIndex[Event.MonitorId]*rowHeight, x2-x1, rowHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function drawGraph() {
|
|
|
|
|
var divWidth = document.getElementById('timelinediv').clientWidth;
|
|
|
|
|
canvas.width = cWidth = divWidth; // Let it float and determine width (it should be sized a bit smaller percentage of window)
|
|
|
|
@ -567,38 +602,24 @@ function drawGraph() {
|
|
|
|
|
underSlider = undefined;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var rowHeight = parseInt(cHeight / (numMonitors + 1) ); // Leave room for a scale of some sort
|
|
|
|
|
rowHeight = parseInt(cHeight / (numMonitors + 1) ); // Leave room for a scale of some sort
|
|
|
|
|
|
|
|
|
|
// first fill in the bars for the events (not alarms)
|
|
|
|
|
|
|
|
|
|
for ( var event_id in events ) {
|
|
|
|
|
var Event = events[event_id];
|
|
|
|
|
|
|
|
|
|
// round low end down
|
|
|
|
|
var x1 = parseInt((Event.StartTimeSecs - minTimeSecs) / rangeTimeSecs * cWidth);
|
|
|
|
|
var x2 = parseInt((Event.EndTimeSecs - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ); // round high end up to be sure consecutive ones connect
|
|
|
|
|
ctx.fillStyle = monitorColour[Event.MonitorId];
|
|
|
|
|
ctx.globalAlpha = 0.2; // light color for background
|
|
|
|
|
ctx.clearRect(x1, monitorIndex[Event.MonitorId]*rowHeight, x2-x1, rowHeight); // Erase any overlap so it doesn't look artificially darker
|
|
|
|
|
ctx.fillRect(x1, monitorIndex[Event.MonitorId]*rowHeight, x2-x1, rowHeight);
|
|
|
|
|
|
|
|
|
|
for ( var frame_id in Event.FramesById ) {
|
|
|
|
|
var Frame = Event.FramesById[frame_id];
|
|
|
|
|
if ( ! Frame.Score ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now put in scored frames (if any)
|
|
|
|
|
var x1=parseInt( (Frame.TimeStampSecs - minTimeSecs) / rangeTimeSecs * cWidth); // round low end down
|
|
|
|
|
var x2=parseInt( (Frame.TimeStampSecs - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ); // round up
|
|
|
|
|
if (x2-x1 < 2) x2=x1+2; // So it is visible make them all at least this number of seconds wide
|
|
|
|
|
//ctx.fillStyle=monitorColour[Event.MonitorId];
|
|
|
|
|
ctx.globalAlpha = 0.4 + 0.6 * (1 - Frame.Score/maxScore); // Background is scaled but even lowest is twice as dark as the background
|
|
|
|
|
ctx.fillRect(x1, monitorIndex[Event.MonitorId]*rowHeight, x2-x1, rowHeight);
|
|
|
|
|
} // end foreach frame
|
|
|
|
|
console.log(events);
|
|
|
|
|
for (const event_id in events) {
|
|
|
|
|
const Event = events[event_id];
|
|
|
|
|
drawEventOnGraph(Event);
|
|
|
|
|
if (Event.FramesById) {
|
|
|
|
|
for (const frame_id in Event.FramesById ) {
|
|
|
|
|
const Frame = Event.FramesById[frame_id];
|
|
|
|
|
if (!Frame.Score) continue;
|
|
|
|
|
drawFrameOnGraph(Frame);
|
|
|
|
|
} // end foreach frame
|
|
|
|
|
}
|
|
|
|
|
} // end foreach Event
|
|
|
|
|
|
|
|
|
|
for ( var i=0; i < numMonitors; i++ ) {
|
|
|
|
|
for (let i=0; i < numMonitors; i++) {
|
|
|
|
|
// Note that this may be a sparse array
|
|
|
|
|
ctx.font = parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
|
|
|
|
|
ctx.fillStyle = "white";
|
|
|
|
@ -624,7 +645,7 @@ function redrawScreen() {
|
|
|
|
|
var scaleDiv = $j('#ScaleDiv');
|
|
|
|
|
var fit = $j('#fit');
|
|
|
|
|
|
|
|
|
|
if ( liveMode == 1 ) {
|
|
|
|
|
if (liveMode == 1) {
|
|
|
|
|
// if we are not in live view switch to history -- this has to come before fit in case we re-establish the timeline
|
|
|
|
|
dateTimeDiv.hide();
|
|
|
|
|
speedDiv.hide();
|
|
|
|
@ -646,12 +667,11 @@ function redrawScreen() {
|
|
|
|
|
panLeft.show();
|
|
|
|
|
panRight.show();
|
|
|
|
|
downloadVideo.show();
|
|
|
|
|
|
|
|
|
|
drawGraph();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var monitors = $j('#monitors');
|
|
|
|
|
if ( fitMode == 1 ) {
|
|
|
|
|
if (fitMode == 1) {
|
|
|
|
|
var fps = $j('#fps');
|
|
|
|
|
var vh = window.innerHeight;
|
|
|
|
|
var mh = (vh - monitors.position().top - fps.outerHeight());
|
|
|
|
@ -680,13 +700,14 @@ function redrawScreen() {
|
|
|
|
|
} // end function redrawScreen
|
|
|
|
|
|
|
|
|
|
function outputUpdate(time) {
|
|
|
|
|
drawSliderOnGraph(time);
|
|
|
|
|
for ( var i=0; i < numMonitors; i++ ) {
|
|
|
|
|
var src = getImageSource(monitorPtr[i], time);
|
|
|
|
|
//console.log("New image src: " + src);
|
|
|
|
|
loadImage2Monitor(monitorPtr[i], src);
|
|
|
|
|
if (Object.keys(events).length !== 0) {
|
|
|
|
|
for ( let i=0; i < numMonitors; i++ ) {
|
|
|
|
|
const src = getImageSource(monitorPtr[i], time);
|
|
|
|
|
loadImage2Monitor(monitorPtr[i], src);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
currentTimeSecs = time;
|
|
|
|
|
drawSliderOnGraph(time);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Found this here: http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element
|
|
|
|
@ -728,8 +749,9 @@ function tmove(event) {
|
|
|
|
|
function mmove(event) {
|
|
|
|
|
if ( mouseisdown ) {
|
|
|
|
|
// only do anything if the mouse is depressed while on the sheet
|
|
|
|
|
var sec = Math.floor(minTimeSecs + rangeTimeSecs / event.target.width * event.target.relMouseCoords(event).x);
|
|
|
|
|
outputUpdate(sec);
|
|
|
|
|
const relx = event.target.relMouseCoords(event).x;
|
|
|
|
|
const sec = Math.floor(minTimeSecs + rangeTimeSecs / event.target.width * relx);
|
|
|
|
|
if (parseInt(sec)) outputUpdate(sec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -748,7 +770,7 @@ function secs2inputstr(s) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function secs2dbstr(s) {
|
|
|
|
|
if ( ! parseInt(s) ) {
|
|
|
|
|
if (!parseInt(s)) {
|
|
|
|
|
console.log("Invalid value for " + s + " seconds");
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
@ -761,7 +783,7 @@ function secs2dbstr(s) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setFit(value) {
|
|
|
|
|
fitMode=value;
|
|
|
|
|
fitMode = value;
|
|
|
|
|
redrawScreen();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -896,6 +918,7 @@ function click_zoomout() {
|
|
|
|
|
function click_panleft() {
|
|
|
|
|
minTimeSecs = parseInt(minTimeSecs - rangeTimeSecs/2);
|
|
|
|
|
maxTimeSecs = minTimeSecs + rangeTimeSecs - 1;
|
|
|
|
|
currentTimeSecs -= rangeTimeSecs/2;
|
|
|
|
|
clicknav(minTimeSecs, maxTimeSecs, 0);
|
|
|
|
|
}
|
|
|
|
|
function click_panright() {
|
|
|
|
@ -941,7 +964,7 @@ function allnon() {
|
|
|
|
|
clicknav(0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// >>>>>>>>>>>>>>>> Handles individual monitor clicks and navigation to the standard event/watch display
|
|
|
|
|
// Handles individual monitor clicks and navigation to the standard event/watch display
|
|
|
|
|
|
|
|
|
|
function showOneMonitor(monId, event) {
|
|
|
|
|
// link out to the normal view of one event's data
|
|
|
|
@ -1019,19 +1042,134 @@ function changeDateTime(e) {
|
|
|
|
|
// Reloading can take a while, so stop interrupts to reduce load
|
|
|
|
|
clearInterval(timerObj);
|
|
|
|
|
timerObj = null;
|
|
|
|
|
const form = $j('#montagereview_form');
|
|
|
|
|
console.log(form.serialize());
|
|
|
|
|
|
|
|
|
|
var uri = "?" + form.serialize() + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value];
|
|
|
|
|
drawGraph();
|
|
|
|
|
|
|
|
|
|
console.log("ChangeDateTime");
|
|
|
|
|
loadEventData();
|
|
|
|
|
console.log("timerFire from changeDateTime");
|
|
|
|
|
wait_for_events();
|
|
|
|
|
|
|
|
|
|
//const form = $j('#montagereview_form');
|
|
|
|
|
//console.log(form.serialize());
|
|
|
|
|
|
|
|
|
|
//var uri = "?" + form.serialize() + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value];
|
|
|
|
|
//var uri = "?view=" + currentView + fitStr + minStr + maxStr + liveStr + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value];
|
|
|
|
|
window.location = uri;
|
|
|
|
|
//window.location = uri;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// >>>>>>>>> Initialization that runs on window load by being at the bottom
|
|
|
|
|
function loadEventData(e) {
|
|
|
|
|
LOADING = true;
|
|
|
|
|
|
|
|
|
|
var monitors = monitorData;
|
|
|
|
|
var data = {};
|
|
|
|
|
var mon_ids = [];
|
|
|
|
|
for (let monitor_i=0, monitors_len=monitors.length; monitor_i < monitors_len; monitor_i++) {
|
|
|
|
|
const monitor = monitors[monitor_i];
|
|
|
|
|
monitorLoading[monitor.Id] = false;
|
|
|
|
|
mon_ids[mon_ids.length] = monitor.Id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var url = Servers[serverId].urlToApi()+'/events/index';
|
|
|
|
|
$j('#fieldsTable input,#fieldsTable select').each(function(index) {
|
|
|
|
|
const el = $j(this);
|
|
|
|
|
const val = el.val();
|
|
|
|
|
if (val && (!Array.isArray(val) || val.length)) {
|
|
|
|
|
const name = el.attr('name');
|
|
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
|
const found = name.match(/filter\[Query\]\[terms\]\[(\d)+\]\[val\]/);
|
|
|
|
|
if (found) {
|
|
|
|
|
const attr_name = 'filter[Query][terms]['+found[1]+'][attr]';
|
|
|
|
|
const attr = this.form.elements[attr_name];
|
|
|
|
|
const op_name = 'filter[Query][terms]['+found[1]+'][op]';
|
|
|
|
|
const op = this.form.elements[op_name];
|
|
|
|
|
if (attr) {
|
|
|
|
|
url += '/'+attr.value+' '+op.value+':'+encodeURIComponent(val);
|
|
|
|
|
} else {
|
|
|
|
|
console.log('No attr for '+attr_name);
|
|
|
|
|
}
|
|
|
|
|
//} else {
|
|
|
|
|
//console.log("No match for " + name);
|
|
|
|
|
}
|
|
|
|
|
data[name] = val;
|
|
|
|
|
const cookie = el.attr('data-cookie');
|
|
|
|
|
if (cookie) setCookie(cookie, val, 3600);
|
|
|
|
|
} // end if name
|
|
|
|
|
} // end if val
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function receive_events(data) {
|
|
|
|
|
if (data.result == 'Error') {
|
|
|
|
|
alert(data.message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!data.events) {
|
|
|
|
|
console.log(data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
console.log("Event data ", data);
|
|
|
|
|
|
|
|
|
|
if (data.events.length) {
|
|
|
|
|
const event_list = {};
|
|
|
|
|
for (let i=0, len = data.events.length; i<len; i++) {
|
|
|
|
|
const ev = data.events[i].Event;
|
|
|
|
|
events[parseInt(ev.Id)] = ev;
|
|
|
|
|
if (!events_by_monitor_id[ev.MonitorId]) {
|
|
|
|
|
events_by_monitor_id[ev.MonitorId] = []; // just event ids
|
|
|
|
|
events_for_monitor[ev.MonitorId] = []; // id=>event
|
|
|
|
|
}
|
|
|
|
|
events_by_monitor_id[ev.MonitorId].push(ev.Id);
|
|
|
|
|
events_for_monitor[ev.MonitorId].push(ev);
|
|
|
|
|
drawEventOnGraph(ev);
|
|
|
|
|
event_list[ev.Id] = ev;
|
|
|
|
|
events[ev.id] = ev;
|
|
|
|
|
}
|
|
|
|
|
loadFrames(event_list);
|
|
|
|
|
}
|
|
|
|
|
} // end function receive_events
|
|
|
|
|
|
|
|
|
|
if (ajax) ajax.abort();
|
|
|
|
|
LOADING = false;
|
|
|
|
|
|
|
|
|
|
if (mon_ids.length) {
|
|
|
|
|
for (let i=0; i < mon_ids.length; i++) {
|
|
|
|
|
ajax = $j.ajax({
|
|
|
|
|
url: url+ '/MonitorId:'+mon_ids[i]+ '.json'+'?'+auth_relay,
|
|
|
|
|
method: 'GET',
|
|
|
|
|
//url: thisUrl + '?view=request&request=events&task=query&sort=Id&order=ASC',
|
|
|
|
|
//data: data,
|
|
|
|
|
timeout: 0,
|
|
|
|
|
success: receive_events,
|
|
|
|
|
error: function(jqXHR) {
|
|
|
|
|
ajax = null;
|
|
|
|
|
console.log("error", jqXHR);
|
|
|
|
|
//logAjaxFail(jqXHR);
|
|
|
|
|
//$j('#eventTable').bootstrapTable('refresh');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} // end foreach monitor
|
|
|
|
|
} else {
|
|
|
|
|
ajax = $j.ajax({
|
|
|
|
|
url: url+'.json'+'?'+auth_relay,
|
|
|
|
|
method: 'GET',
|
|
|
|
|
//url: thisUrl + '?view=request&request=events&task=query&sort=Id&order=ASC',
|
|
|
|
|
//data: data,
|
|
|
|
|
timeout: 0,
|
|
|
|
|
success: receive_events,
|
|
|
|
|
error: function(jqXHR) {
|
|
|
|
|
ajax = null;
|
|
|
|
|
console.log("error", jqXHR);
|
|
|
|
|
//logAjaxFail(jqXHR);
|
|
|
|
|
//$j('#eventTable').bootstrapTable('refresh');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
} // end function loadEventData
|
|
|
|
|
|
|
|
|
|
function initPage() {
|
|
|
|
|
if (!liveMode) {
|
|
|
|
|
load_Frames(events);
|
|
|
|
|
canvas = document.getElementById('timeline');
|
|
|
|
|
|
|
|
|
|
canvas.addEventListener('mousemove', mmove, false);
|
|
|
|
@ -1041,59 +1179,38 @@ function initPage() {
|
|
|
|
|
canvas.addEventListener('mouseout', mout, false);
|
|
|
|
|
|
|
|
|
|
ctx = canvas.getContext('2d', {willReadFrequently: true});
|
|
|
|
|
|
|
|
|
|
// draw an empty timeline
|
|
|
|
|
drawGraph();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( let i = 0, len = monitorPtr.length; i < len; i += 1 ) {
|
|
|
|
|
for (let i = 0, len = monitorPtr.length; i < len; i += 1) {
|
|
|
|
|
const monId = monitorPtr[i];
|
|
|
|
|
if (!monId) continue;
|
|
|
|
|
monitorCanvasObj[monId] = document.getElementById('Monitor'+monId);
|
|
|
|
|
if ( !monitorCanvasObj[monId] ) {
|
|
|
|
|
alert("Couldn't find DOM element for Monitor" + monId + "monitorPtr.length=" + len);
|
|
|
|
|
} else {
|
|
|
|
|
monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d');
|
|
|
|
|
const imageObject = monitorImageObject[monId] = new Image();
|
|
|
|
|
imageObject.monId = monId;
|
|
|
|
|
imageObject.onload = function() {
|
|
|
|
|
imagedone(this, this.monId, true);
|
|
|
|
|
};
|
|
|
|
|
imageObject.onerror = function() {
|
|
|
|
|
imagedone(this, this.monId, false);
|
|
|
|
|
};
|
|
|
|
|
loadImage2Monitor(monId, monitorImageURL[monId]);
|
|
|
|
|
monitorCanvasObj[monId].addEventListener('click', clickMonitor, false);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d');
|
|
|
|
|
const imageObject = monitorImageObject[monId] = new Image();
|
|
|
|
|
imageObject.monId = monId;
|
|
|
|
|
imageObject.onload = function() {
|
|
|
|
|
imagedone(this, this.monId, true);
|
|
|
|
|
};
|
|
|
|
|
imageObject.onerror = function() {
|
|
|
|
|
imagedone(this, this.monId, false);
|
|
|
|
|
};
|
|
|
|
|
if (liveMode) loadImage2Monitor(monId, monitorImageURL[monId]);
|
|
|
|
|
monitorCanvasObj[monId].addEventListener('click', clickMonitor, false);
|
|
|
|
|
} // end foreach monitor
|
|
|
|
|
|
|
|
|
|
setSpeed(speedIndex);
|
|
|
|
|
//setFit(fitMode); // will redraw
|
|
|
|
|
//setLive(liveMode); // will redraw
|
|
|
|
|
loadEventData();
|
|
|
|
|
redrawScreen();
|
|
|
|
|
/*
|
|
|
|
|
$j('#minTime').datetimepicker({
|
|
|
|
|
timeFormat: "HH:mm:ss",
|
|
|
|
|
dateFormat: "yy-mm-dd",
|
|
|
|
|
maxDate: +0,
|
|
|
|
|
constrainInput: false,
|
|
|
|
|
onClose: function(newDate, oldData) {
|
|
|
|
|
if (newDate !== oldData.lastVal) {
|
|
|
|
|
changeDateTime();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
$j('#maxTime').datetimepicker({
|
|
|
|
|
timeFormat: "HH:mm:ss",
|
|
|
|
|
dateFormat: "yy-mm-dd",
|
|
|
|
|
minDate: minTime,
|
|
|
|
|
maxDate: +0,
|
|
|
|
|
constrainInput: false,
|
|
|
|
|
onClose: function(newDate, oldData) {
|
|
|
|
|
if ( newDate !== oldData.lastVal ) {
|
|
|
|
|
changeDateTime();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
$j('#scaleslider').bind('change', function() {
|
|
|
|
|
setScale(this.value);
|
|
|
|
|
});
|
|
|
|
@ -1126,6 +1243,19 @@ function initPage() {
|
|
|
|
|
el.on('change', changeDateTime);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
wait_for_events();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function wait_for_events() {
|
|
|
|
|
if (Object.keys(events).length === 0) {
|
|
|
|
|
if (!wait_for_events_interval)
|
|
|
|
|
wait_for_events_interval = setInterval(wait_for_events, 1000);
|
|
|
|
|
} else {
|
|
|
|
|
clearInterval(wait_for_events_interval);
|
|
|
|
|
wait_for_events_interval = null;
|
|
|
|
|
timerFire();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function takeSnapshot() {
|
|
|
|
@ -1156,7 +1286,7 @@ window.addEventListener("resize", redrawScreen, {passive: true});
|
|
|
|
|
window.addEventListener('DOMContentLoaded', initPage);
|
|
|
|
|
|
|
|
|
|
/* Expects and Object, not an array, of EventId=>Event mappings. */
|
|
|
|
|
function load_Frames(zm_events) {
|
|
|
|
|
function loadFrames(zm_events) {
|
|
|
|
|
console.log("Loading frames", zm_events);
|
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
|
const url = Servers[serverId].urlToApi()+'/frames/index';
|
|
|
|
@ -1219,4 +1349,4 @@ function load_Frames(zm_events) {
|
|
|
|
|
} // end while zm_events.legtnh
|
|
|
|
|
} // end Promise
|
|
|
|
|
);
|
|
|
|
|
} // end function load_Frames(Event)
|
|
|
|
|
} // end function loadFrames(Event)
|
|
|
|
|