diff --git a/web/skins/classic/views/js/montagereview.js b/web/skins/classic/views/js/montagereview.js new file mode 100644 index 000000000..5a7c73ede --- /dev/null +++ b/web/skins/classic/views/js/montagereview.js @@ -0,0 +1,720 @@ +function evaluateLoadTimes() { + // Only consider it a completed event if we load ALL monitors, then zero all and start again + var start=0; + var end=0; + if ( liveMode != 1 && currentSpeed == 0 ) return; // don't evaluate when we are not moving as we can do nothing really fast. + for ( var i = 0; i < monitorIndex.length; i++ ) { + if ( monitorName[i] > "" ) { + if ( monitorLoadEndTimems[i] ==0 ) return; // if we have a monitor with no time yet just wait + if ( start == 0 || start > monitorLoadStartTimems[i] ) start = monitorLoadStartTimems[i]; + if ( end == 0 || end < monitorLoadEndTimems[i] ) end = monitorLoadEndTimems[i]; + } + } + if ( start == 0 || end == 0 ) return; // we really should not get here + for ( var i=0; i < numMonitors; i++ ) { + var monId = monitorPtr[i]; + monitorLoadStartTimems[monId] = 0; + monitorLoadEndTimems[monId] = 0; + } + freeTimeLastIntervals[imageLoadTimesEvaluated++] = 1 - ((end - start)/currentDisplayInterval); + if( imageLoadTimesEvaluated < imageLoadTimesNeeded ) return; + var avgFrac=0; + for ( var i=0; i < imageLoadTimesEvaluated; i++ ) + avgFrac += freeTimeLastIntervals[i]; + avgFrac = avgFrac / imageLoadTimesEvaluated; + // The larger this is(positive) the faster we can go + if (avgFrac >= 0.9) currentDisplayInterval = (currentDisplayInterval * 0.50).toFixed(1); // we can go much faster + else if (avgFrac >= 0.8) currentDisplayInterval = (currentDisplayInterval * 0.55).toFixed(1); + else if (avgFrac >= 0.7) currentDisplayInterval = (currentDisplayInterval * 0.60).toFixed(1); + else if (avgFrac >= 0.6) currentDisplayInterval = (currentDisplayInterval * 0.65).toFixed(1); + else if (avgFrac >= 0.5) currentDisplayInterval = (currentDisplayInterval * 0.70).toFixed(1); + else if (avgFrac >= 0.4) currentDisplayInterval = (currentDisplayInterval * 0.80).toFixed(1); + else if (avgFrac >= 0.35) currentDisplayInterval = (currentDisplayInterval * 0.90).toFixed(1); + else if (avgFrac >= 0.3) currentDisplayInterval = (currentDisplayInterval * 1.00).toFixed(1); + else if (avgFrac >= 0.25) currentDisplayInterval = (currentDisplayInterval * 1.20).toFixed(1); + else if (avgFrac >= 0.2) currentDisplayInterval = (currentDisplayInterval * 1.50).toFixed(1); + else if (avgFrac >= 0.1) currentDisplayInterval = (currentDisplayInterval * 2.00).toFixed(1); + else currentDisplayInterval = (currentDisplayInterval * 2.50).toFixed(1); + currentDisplayInterval=Math.min(Math.max(currentDisplayInterval, 30),10000); // limit this from about 30fps to .1 fps + imageLoadTimesEvaluated=0; + setSpeed(speedIndex); + $('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + "."; +} + +function SetImageSource( monId, val ) { + if ( liveMode == 1 ) { + return monitorImageObject[monId].src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) )); + + } else { + for ( var i=0, eIdlength = eId.length; i < eIdlength; i++ ) { + // Search for a match + if ( eMonId[i] == monId && val >= eStartSecs[i] && val <= eEndSecs[i] ) { + var frame = parseInt((val - eStartSecs[i])/(eEndSecs[i]-eStartSecs[i])*eventFrames[i])+1; + return "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height; + } + } // end for + return "no data"; + } +} + +// callback when loading an image. Will load itself to the canvas, or draw no data +function imagedone( obj, monId, success ) { + if ( success ) { + var canvasCtx = monitorCanvasCtx[monId]; + var canvasObj = monitorCanvasObj[monId]; + + canvasCtx.drawImage( monitorImageObject[monId], 0, 0, canvasObj.width, canvasObj.height ); + var iconSize=(Math.max(canvasObj.width, canvasObj.height) * 0.10); + canvasCtx.font = "600 " + iconSize.toString() + "px Arial"; + canvasCtx.fillStyle = "white"; + canvasCtx.globalCompositeOperation = "difference"; + canvasCtx.fillText( "+", iconSize*0.2, iconSize*1.2 ); + canvasCtx.fillText( "-", canvasObj.width - iconSize*1.2, iconSize*1.2 ); + canvasCtx.globalCompositeOperation = "source-over"; + monitorLoadEndTimems[monId] = new Date().getTime(); // elapsed time to load + evaluateLoadTimes(); + } + monitorLoading[monId] = false; + if ( ! success ) { + // if we had a failrue queue up the no-data image + //loadImage2Monitor(monId,"no data"); // leave the staged URL if there is one, just ignore it here. + loadNoData( monId ); + } else { + if ( monitorLoadingStageURL[monId] == "" ) { + console.log("Not showing image for " + monId ); + // This means that there wasn't a loading image placeholder. + // So we weren't actually loading an image... which seems weird. + return; + } + //loadImage2Monitor(monId,monitorLoadingStageURL[monId] ); + //monitorLoadingStageURL[monId]=""; + } + 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 Data"; + 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"); + } +} + +// Either draws the +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 { + if ( monitorImageObject[monId].src == url ) return; // do nothing if it's the same + if ( url == 'no data' ) { + loadNoData( monId ); + } else { + monitorLoading[monId] = true; + monitorLoadStartTimems[monId] = new Date().getTime(); + monitorImageObject[monId].src = url; // starts a load but doesn't refresh yet, wait until ready + } + } +} +function timerFire() { + // See if we need to reschedule + if(currentDisplayInterval != timerInterval || currentSpeed == 0) { + // zero just turn off interrupts + clearInterval(timerObj); + timerInterval=currentDisplayInterval; + if(currentSpeed>0 || liveMode!=0) 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 + { + setSpeed(0); + outputUpdate(currentTimeSecs); + } + else outputUpdate(currentTimeSecs + playSecsperInterval); + return; +} + +function drawSliderOnGraph(val) { + var sliderWidth=10; + var sliderLineWidth=1; + var sliderHeight=cHeight; + + if(liveMode==1) { + val=Math.floor( Date.now() / 1000); + } + // 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 Georgia"; // 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 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='black'; + // 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 = $('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="blue"; + } + 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 = $('scrubleft'); + o.innerHTML=secs2dbstr(minTimeSecs); + o.style.position="absolute"; + o.style.bottom=labbottom; + o.style.font=labfont; + o.style.left="5px"; + if(numMonitors==0) // we need a len calculation if we skipped the slider + len = o.offsetWidth; + // If the slider will overlay part of this suppress (this is the left side) + if(len + 10 > sliderX || cWidth < len * 4 ) // that last check is for very narrow browsers + o.style.display="none"; + else + { + o.style.display="inline"; + o.style.display="inline-flex"; // safari won't take this but will just ignore + } + + var o = $('scrubright'); + o.innerHTML=secs2dbstr(maxTimeSecs); + o.style.position="absolute"; + o.style.bottom=labbottom; + o.style.font=labfont; + // If the slider will overlay part of this suppress (this is the right side) + o.style.left=(cWidth - len - 15).toString() + "px"; + if(sliderX > cWidth - len - 20 || cWidth < len * 4 ) + o.style.display="none"; + else + { + o.style.display="inline"; + o.style.display="inline-flex"; + } +} + +function drawGraph() +{ + var divWidth=$('timelinediv').clientWidth + canvas.width = cWidth = divWidth; // Let it float and determine width (it should be sized a bit smaller percentage of window) + canvas.height=cHeight = parseInt(window.innerHeight * 0.10); + if(eId.length==0) + { + ctx.font="40px Georgia"; + ctx.fillStyle="Black"; + ctx.globalAlpha=1; + var t="No data found in range - choose differently"; + var l=ctx.measureText(t).width; + ctx.fillText(t,(cWidth - l)/2, cHeight-10); + underSlider=undefined; + return; + } + var 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 i=0; i0); i++) // Now put in scored frames (if any) + { + var x1=parseInt( (fTimeFromSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth) ; // round low end down + var x2=parseInt( (fTimeToSecs[i] - 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[fMonId[i]]; + ctx.globalAlpha = 0.4 + 0.6 * (1 - fScore[i]/maxScore); // Background is scaled but even lowest is twice as dark as the background + ctx.fillRect(x1,monitorIndex[fMonId[i]]*rowHeight,x2-x1,rowHeight); + } + for(var i=0; i 0 ) { + if(maxSecs > now) + maxSecs = parseInt(now); + maxStr="&maxTime=" + secs2dbstr(maxSecs); + } + if ( maxSecs > 0 ) + minStr="&minTime=" + secs2dbstr(minSecs); + if ( maxSecs == 0 && minSecs == 0 ) { + minStr="&minTime=01/01/1950 12:00:00"; + maxStr="&maxTime=12/31/2035 12:00:00"; + } + var intervalStr="&displayinterval=" + currentDisplayInterval.toString(); + if ( minSecs && maxSecs ) { + if ( currentTimeSecs > minSecs && currentTimeSecs < maxSecs ) // make sure time is in the new range + currentStr="¤t=" + secs2dbstr(currentTimeSecs); + } + + var liveStr="&live=0"; + if ( live == 1 ) + liveStr="&live=1"; + + var fitStr="&fit=0"; + if ( fitMode == 1 ) + fitStr="&fit=1"; + + var zoomStr=""; + for ( var i=0; i < numMonitors; i++ ) + if ( monitorZoomScale[monitorPtr[i]] < 0.99 || monitorZoomScale[monitorPtr[i]] > 1.01 ) // allow for some up/down changes and just treat as 1 of almost 1 + zoomStr += "&z" + monitorPtr[i].toString() + "=" + monitorZoomScale[monitorPtr[i]].toFixed(2); + + var uri = "?view=" + currentView + fitStr + groupStr + minStr + maxStr + currentStr + intervalStr + liveStr + zoomStr + "&scale=" + document.getElementById("scaleslider").value + "&speed=" + speeds[$j("#speedslider").value]; + window.location = uri; +} + +function lastHour() { + var now = new Date() / 1000; + clicknav(now - 3600 + 1, now,1,0); +} +function lastEight() { + var now = new Date() / 1000; + clicknav(now - 3600*8 + 1, now,1,0); +} +function zoomin() { + rangeTimeSecs = parseInt(rangeTimeSecs / 2); + minTimeSecs = parseInt(currentTimeSecs - rangeTimeSecs/2); // this is the slider current time, we center on that + maxTimeSecs = parseInt(currentTimeSecs + rangeTimeSecs/2); + clicknav(minTimeSecs,maxTimeSecs,1,0); +} + +function zoomout() { + rangeTimeSecs = parseInt(rangeTimeSecs * 2); + minTimeSecs = parseInt(currentTimeSecs - rangeTimeSecs/2); // this is the slider current time, we center on that + maxTimeSecs = parseInt(currentTimeSecs + rangeTimeSecs/2); + clicknav(minTimeSecs,maxTimeSecs,1,0); +} +function panleft() { + minTimeSecs = parseInt(minTimeSecs - rangeTimeSecs/2); + maxTimeSecs = minTimeSecs + rangeTimeSecs - 1; + clicknav(minTimeSecs,maxTimeSecs,1,0); +} +function panright() { + minTimeSecs = parseInt(minTimeSecs + rangeTimeSecs/2); + maxTimeSecs = minTimeSecs + rangeTimeSecs - 1; + clicknav(minTimeSecs,maxTimeSecs,1,0); +} +function allof() { + clicknav(0,0,1,0); +} +function allnon() { + clicknav(0,0,0,0); +} +/// >>>>>>>>>>>>>>>>> handles packing different size/aspect monitors on screen <<<<<<<<<<<<<<<<<<<<<<<< + +function compSize(a, b) { // sort array by some size parameter - height seems to work best. A semi-greedy algorithm + var a_value = monitorHeight[a] * monitorWidth[a] * monitorNormalizeScale[a] * monitorZoomScale[a] * monitorNormalizeScale[a] * monitorZoomScale[a]; + var b_value = monitorHeight[b] * monitorWidth[b] * monitorNormalizeScale[b] * monitorZoomScale[b] * monitorNormalizeScale[b] * monitorZoomScale[b]; + + if ( a_value > b_value ) return -1; + else if ( a_value == b_value ) return 0; + else return 1; +} + + +function maxfit2(divW, divH) { + var bestFitX=[]; // how we arranged the so-far best match + var bestFitX2=[]; + var bestFitY=[]; + var bestFitY2=[]; + var bestFitScale; + + var minScale=0.05; + var maxScale=5.00; + var bestFitArea=0; + + var borders=-1; + + monitorPtr.sort(compSize); + + while(1) { + if( maxScale - minScale < 0.01 ) break; + var thisScale = (maxScale + minScale) / 2; + var allFit=1; + var thisArea=0; + var thisX=[]; // top left + var thisY=[]; + var thisX2=[]; // bottom right + var thisY2=[]; + + for ( var m = 0; m < numMonitors; m++ ) { + // this loop places each monitor (if it can) + var monId = monitorPtr[m]; + + function doesItFit(x,y,w,h,d) { // does block (w,h) fit at position (x,y) relative to edge and other nodes already done (0..d) + if(x+w>=divW) return 0; + if(y+h>=divH) return 0; + for(var i=0; i<=d; i++) + if( !( thisX[i]>x+w-1 || thisX2[i] < x || thisY[i] > y+h-1 || thisY2[i] < y ) ) return 0; + return 1; // it's OK + } + + if ( borders <= 0 ) + borders=$("Monitor"+monId).getStyle("border").toInt() * 2; // assume fixed size border, and added to both sides and top/bottom + // try fitting over first, then down. Each new one must land at either upper right or lower left corner of last (try in that order) + // Pick the one with the smallest Y, then smallest X if Y equal + var fitX = 999999999; + var fitY = 999999999; + for ( adjacent = 0; adjacent < m; adjacent ++ ) { + // try top right of adjacent + if ( doesItFit(thisX2[adjacent]+1, thisY[adjacent], monitorWidth[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, monitorHeight[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, m-1) == 1 ) { + if ( thisY[adjacent] 0 ) { // only rearrange if we could fit -- otherwise just do nothing, let them start coming out, whatever + for ( m = 0; m < numMonitors; m++ ) { + c = $("Monitor" + monitorPtr[m]); + c.style.position="absolute"; + c.style.left=bestFitX[m].toString() + "px"; + c.style.top=bestFitY[m].toString() + "px"; + c.width = bestFitX2[m] - bestFitX[m] + 1 - borders; + c.height= bestFitY2[m] - bestFitY[m] + 1 - borders; + } + return 1; + } else { + return 0; + } +} + +// >>>>>>>>>>>>>>>> Handles individual monitor clicks and navigation to the standard event/watch display + +function showOneMonitor(monId) { + // link out to the normal view of one event's data + // We know the monitor, need to determine the event based on current time + var url; + if ( liveMode != 0 ) + url="?view=watch&mid=" + monId.toString(); + else + for ( var i=0, len=eId.length; i= eStartSecs[i] && currentTimeSecs <= eEndSecs[i] ) + url="?view=event&eid=" + eId[i] + '&fid=' + parseInt(Math.max(1, Math.min(eventFrames[i], eventFrames[i] * (currentTimeSecs - eStartSecs[i]) / (eEndSecs[i] - eStartSecs[i] + 1) ) )); + break; + } + createPopup(url, 'zmEvent', 'event', monitorWidth[eMonId[i]], monitorHeight[eMonId[i]]); +} + +function zoom(monId,scale) { + var lastZoomMonPriorScale = monitorZoomScale[monId]; + monitorZoomScale[monId] *= scale; + if ( redrawScreen() == 0 ) {// failure here is probably because we zoomed too far + monitorZoomScale[monId] = lastZoomMonPriorScale; + alert("You can't zoom that far -- rolling back"); + redrawScreen(); // put things back and hope it works + } +} + +function clickMonitor(event,monId) { + var monitor_element = $("Monitor"+monId.toString()); + var pos_x = event.offsetX ? (event.offsetX) : event.pageX - monitor_element.offsetLeft; + var pos_y = event.offsetY ? (event.offsetY) : event.pageY - monitor_element.offsetTop; + if ( pos_x < monitor_element.width/4 && pos_y < monitor_element.height/4 ) + zoom(monId,1.15); + else if ( pos_x > monitor_element.width * 3/4 && pos_y < monitor_element.height/4 ) + zoom(monId,1/1.15); + else + showOneMonitor(monId); + return; +} + +// >>>>>>>>> Initialization that runs on window load by being at the bottom + +function initPage() { + canvas = $("timeline"); + ctx = canvas.getContext('2d'); + for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) { + var monId = monitorPtr[i]; + if ( ! monId ) continue; + monitorCanvasObj[monId] = $('Monitor'+monId ); + if ( ! monitorCanvasObj[monId] ) { + alert("Couldn't find DOM element for Monitor"+monId + "monitorPtr.length="+len); + } else { + monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d'); + var 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] ); + } + } + drawGraph(); + setSpeed(speedIndex); + setFit(fitMode); // will redraw + setLive(liveMode); // will redraw +} +window.addEventListener("resize",redrawScreen); +// Kick everything off +window.addEvent( 'domready', initPage ); diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php new file mode 100644 index 000000000..512c670d3 --- /dev/null +++ b/web/skins/classic/views/js/montagereview.js.php @@ -0,0 +1,194 @@ + +var currentScale=; +var liveMode=; +console.log("Live mode?"+liveMode); +var fitMode=; +var currentSpeed=; // slider scale, which is only for replay and relative to real time +var speedIndex=; +var currentDisplayInterval=; // will be set based on performance, this is the display interval in milliseconds for history, and fps for live, and dynamically determined (in ms) +var playSecsperInterval=1; // How many seconds of recorded image we play per refresh determined by speed (replay rate) and display interval; (default=1 if coming from live) +var timerInterval; // milliseconds between interrupts +var timerObj; // object to hold timer interval; +var freeTimeLastIntervals=[]; // Percentage of current interval used in loading most recent image +var imageLoadTimesEvaluated=0; // running count +var imageLoadTimesNeeded=15; // and how many we need +var timeLabelsFractOfRow = 0.9; +var eMonId = []; +var eId = []; +var eStartSecs = []; +var eEndSecs = []; +var eventFrames = []; // this is going to presume all frames equal durationlength +var groupStr=; + + $event['StartTimeSecs'] ) $minTimeSecs = $event['StartTimeSecs']; + if ( $maxTimeSecs < $event['CalcEndTimeSecs'] ) $maxTimeSecs = $event['CalcEndTimeSecs']; + echo " +eMonId[$index]=" . $event['MonitorId'] . "; +eId[$index]=" . $event['Id'] . "; +eStartSecs[$index]=" . $event['StartTimeSecs'] . "; +eEndSecs[$index]=" . $event['CalcEndTimeSecs'] . "; +eventFrames[$index]=" . $event['Frames'] . "; + +"; + + $index = $index + 1; + if ( $event['MaxScore'] > 0 ) + $anyAlarms = true; +} + +// if there is no data set the min/max to the passed in values +if ( $index == 0 ) { + if ( isset($minTime) && isset($maxTime) ) { + $minTimeSecs = strtotime($minTime); + $maxTimeSecs = strtotime($maxTime); + } else { + // this is the case of no passed in times AND no data -- just set something arbitrary + $minTimeSecs = strtotime('1950-06-01 01:01:01'); // random time so there's something to display + $maxTimeSecs = time() + 86400; + } +} + +// We only reset the calling time if there was no calling time +if ( !isset($minTime) || !isset($maxTime) ) { + $maxTime = strftime($maxTimeSecs); + $minTime = strftime($minTimeSecs); +} else { + $minTimeSecs = strtotime($minTime); + $maxTimeSecs = strtotime($maxTime); +} + +// If we had any alarms in those events, this builds the list of all alarm frames, but consolidated down to (nearly) contiguous segments +// comparison in else governs how aggressively it consolidates + +echo "var fMonId = [];\n"; +echo "var fTimeFromSecs = [];\n"; +echo "var fTimeToSecs = [];\n"; +echo "var fScore = [];\n"; +$maxScore=0; +$index=0; +$mId=-1; +$fromSecs=-1; +$toSecs=-1; +$maxScore=-1; + +if ( $anyAlarms ) { + foreach( dbFetchAll ($frameSql) as $frame ) { + if ( $mId < 0 ) { + $mId = $frame['MonitorId']; + $fromSecs = $frame['TimeStampSecs']; + $toSecs = $frame['TimeStampSecs']; + $maxScore = $frame['Score']; + } else if ( $mId != $frame['MonitorId'] || $frame['TimeStampSecs'] - $toSecs > 10 ) { + // dump this one start a new + $index++; + echo " + fMonId[$index]= $mId; + fTimeFromSecs[$index]= $fromSecs; + fTimeToSecs[$index]= $toSecs; + fScore[$index]= $maxScore; +"; + $mId = $frame['MonitorId']; + $fromSecs = $frame['TimeStampSecs']; + $toSecs = $frame['TimeStampSecs']; + $maxScore = $frame['Score']; + } else { + // just add this one on + $toSecs = $frame['TimeStampSecs']; + if ( $maxScore < $frame['Score'] ) $maxScore = $frame['Score']; + } + } +} +if ( $mId > 0 ) { + echo " + fMonId[$index]= $mId; + fTimeFromSecs[$index]= $fromSecs; + fTimeToSecs[$index]= $toSecs; + fScore[$index]= $maxScore; +"; +} + +echo "var maxScore=$maxScore;\n"; // used to skip frame load if we find no alarms. +echo "var monitorName = [];\n"; +echo "var monitorLoading = [];\n"; +echo "var monitorImageObject = [];\n"; +echo "var monitorImageURL = [];\n"; +echo "var monitorLoadingStageURL = [];\n"; +echo "var monitorLoadStartTimems = [];\n"; +echo "var monitorLoadEndTimems = [];\n"; +echo "var monitorColour = [];\n"; +echo "var monitorWidth = [];\n"; +echo "var monitorHeight = [];\n"; +echo "var monitorIndex = [];\n"; +echo "var monitorNormalizeScale = [];\n"; +echo "var monitorZoomScale = [];\n"; +echo "var monitorCanvasObj = [];\n"; // stash location of these here so we don't have to search +echo "var monitorCanvasCtx = [];\n"; +echo "var monitorPtr = []; // monitorName[monitorPtr[0]] is first monitor\n"; + + +$numMonitors=0; // this array is indexed by the monitor ID for faster access later, so it may be sparse +$avgArea=floatval(0); // Calculations the normalizing scale + +foreach ( $monitors as $m ) { + $avgArea = $avgArea + floatval($m->Width() * $m->Height()); + $numMonitors++; +} + +if ( $numMonitors > 0 ) $avgArea = $avgArea / $numMonitors; + +$numMonitors = 0; +foreach ( $monitors as $m ) { + echo " monitorLoading[" . $m->Id() . "]=false;\n"; + echo " monitorImageURL[" . $m->Id() . "]='".$m->getStreamSrc( array('mode'=>'single','scale'=>$defaultScale*100), '&' )."';\n"; + echo " monitorLoadingStageURL[" . $m->Id() . "] = '';\n"; + echo " monitorColour[" . $m->Id() . "]=\"" . $m->WebColour() . "\";\n"; + echo " monitorWidth[" . $m->Id() . "]=" . $m->Width() . ";\n"; + echo " monitorHeight[" . $m->Id() . "]=" . $m->Height() . ";\n"; + echo " monitorIndex[" . $m->Id() . "]=" . $numMonitors . ";\n"; + echo " monitorName[" . $m->Id() . "]=\"" . $m->Name() . "\";\n"; + echo " monitorLoadStartTimems[" . $m->Id() . "]=0;\n"; + echo " monitorLoadEndTimems[" . $m->Id() . "]=0;\n"; + echo " monitorNormalizeScale[" . $m->Id() . "]=" . sqrt($avgArea / ($m->Width() * $m->Height() )) . ";\n"; + $zoomScale=1.0; + if(isset($_REQUEST[ 'z' . $m->Id() ]) ) + $zoomScale = floatval( validHtmlStr($_REQUEST[ 'z' . $m->Id() ]) ); + echo " monitorZoomScale[" . $m->Id() . "]=" . $zoomScale . ";\n"; + echo " monitorPtr[" . $numMonitors . "]=" . $m->Id() . ";\n"; + $numMonitors += 1; +} +echo "var numMonitors = $numMonitors;\n"; +echo "var minTimeSecs=" . $minTimeSecs . ";\n"; +echo "var maxTimeSecs=" . $maxTimeSecs . ";\n"; +echo "var rangeTimeSecs=" . ( $maxTimeSecs - $minTimeSecs + 1) . ";\n"; +if(isset($defaultCurrentTime)) + echo "var currentTimeSecs=" . strtotime($defaultCurrentTime) . ";\n"; +else + echo "var currentTimeSecs=" . ($minTimeSecs + $maxTimeSecs)/2 . ";\n"; + +echo 'var speeds=['; +for ($i=0; $i0)?', ':'') . $speeds[$i]; +echo "];\n"; +?> + +var scrubAsObject=$('scrub'); +var cWidth; // save canvas width +var cHeight; // save canvas height +var canvas; // global canvas definition so we don't have to keep looking it up +var ctx; +var underSlider; // use this to hold what is hidden by the slider +var underSliderX; // Where the above was taken from (left side, Y is zero) + diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 5a153dd9e..0c4342e8e 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -95,20 +95,20 @@ // if ( !canView( 'Events' ) ) { - $view = 'error'; - return; + $view = 'error'; + return; } require_once( 'includes/Monitor.php' ); # FIXME THere is no way to select group at this time. if ( !empty($_REQUEST['group']) ) { - $group = $_REQUEST['group']; - $row = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array($_REQUEST['group']) ); - $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None' AND find_in_set( Id, '".$row['MonitorIds']."' ) "; + $group = $_REQUEST['group']; + $row = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array($_REQUEST['group']) ); + $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None' AND find_in_set( Id, '".$row['MonitorIds']."' ) "; } else { - $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None'"; - $group = ''; + $monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None'"; + $group = ''; } // Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame @@ -222,7 +222,7 @@ $monitors = array(); $monitorsSql .= ' ORDER BY Sequence ASC'; $index=0; foreach( dbFetchAll( $monitorsSql ) as $row ) { - $monitors[$index] = $row; + $monitors[$index] = new Monitor( $row ); $index = $index + 1; } @@ -270,921 +270,15 @@ input[type=range]::-ms-tooltip { +
'; foreach ($monitors as $m) { - echo 'No Canvas Support!!'; + echo 'No Canvas Support!!'; } -echo "
\n"; -echo "

evaluating fps

\n"; -echo " + +

evaluating fps