Fix use of onclick and onchange. Fix bulk frame lookup. Make scanning events more efficient
This commit is contained in:
parent
265e49fe45
commit
1eadb814e2
|
@ -45,51 +45,81 @@ function evaluateLoadTimes() {
|
|||
$('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + ".";
|
||||
} // end evaluateLoadTimes()
|
||||
|
||||
function getFrame( monId, time ) {
|
||||
function getFrame(monId, time, last_Frame=null) {
|
||||
if ( last_Frame ) {
|
||||
if (
|
||||
(last_Frame.TimeStampSecs <= time)
|
||||
&&
|
||||
(last_Frame.EndTimeStampSecs >= time)
|
||||
) {
|
||||
return last_Frame;
|
||||
}
|
||||
}
|
||||
|
||||
var events_for_monitor = events_by_monitor_id[monId];
|
||||
if ( ! events_for_monitor ) {
|
||||
console.log("No events for monitor " + monId);
|
||||
return;
|
||||
}
|
||||
|
||||
var Frame = null;
|
||||
for ( var event_id in events ) {
|
||||
for ( var i = 0; i < events_for_monitor.length; i++ ) {
|
||||
//for ( var event_id_idx in events_for_monitor ) {
|
||||
var event_id = events_for_monitor[i];
|
||||
// Search for the event matching this time. Would be more efficient if we had events indexed by monitor
|
||||
Event = events[event_id];
|
||||
if ( Event.MonitorId != monId || Event.StartTimeSecs > time || Event.EndTimeSecs < time ) {
|
||||
e = events[event_id];
|
||||
if ( !e ) {
|
||||
console.log("No event found for " + event_id);
|
||||
break;
|
||||
}
|
||||
if ( e.MonitorId != monId || e.StartTimeSecs > time || e.EndTimeSecs < time ) {
|
||||
//console.log("Event not for " + time);
|
||||
continue;
|
||||
}
|
||||
|
||||
var duration = Event.EndTimeSecs - Event.StartTimeSecs;
|
||||
if ( ! Event.FramesById ) {
|
||||
if ( !e.FramesById ) {
|
||||
console.log("No FramesById for event " + event_id);
|
||||
return;
|
||||
}
|
||||
var frame = parseInt((time - Event.StartTimeSecs)/(duration)*Object.keys(Event.FramesById).length)+1;
|
||||
// Need to get frame by time, not some fun calc that assumes frames have the same mlength.
|
||||
// Frames are not sorted.
|
||||
for ( var frame_id in Event.FramesById ) {
|
||||
var duration = e.EndTimeSecs - e.StartTimeSecs;
|
||||
|
||||
// I think this is an estimate to jump near the desired frame.
|
||||
var frame = parseInt((time - e.StartTimeSecs)/(duration)*Object.keys(e.FramesById).length)+1;
|
||||
//console.log("frame_id for " + time + " is " + frame);
|
||||
|
||||
// Need to get frame by time, not some fun calc that assumes frames have the same length.
|
||||
// Frames are sorted in descreasing order (or not sorted).
|
||||
// This is likely not efficient. Would be better to start at the last frame viewed, see if it is still relevant
|
||||
// Then move forward or backwards as appropriate
|
||||
|
||||
for ( var frame_id in e.FramesById ) {
|
||||
if ( 0 ) {
|
||||
if ( frame == 0 ) {
|
||||
console.log("Found frame for time " + time );
|
||||
console.log("Found frame for time " + time);
|
||||
console.log(Frame);
|
||||
Frame = Event.FramesById[frame_id];
|
||||
Frame = e.FramesById[frame_id];
|
||||
break;
|
||||
}
|
||||
frame --;
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
Event.FramesById[frame_id].TimeStampSecs == time
|
||||
e.FramesById[frame_id].TimeStampSecs == time
|
||||
|| (
|
||||
Event.FramesById[frame_id].TimeStampSecs < time
|
||||
e.FramesById[frame_id].TimeStampSecs < time
|
||||
&& (
|
||||
(!Event.FramesById[frame_id].NextTimeStampSecs)
|
||||
(!e.FramesById[frame_id].NextTimeStampSecs) // only if event.EndTime is null
|
||||
||
|
||||
(Event.FramesById[frame_id].NextTimeStampSecs > time)
|
||||
(e.FramesById[frame_id].NextTimeStampSecs > time)
|
||||
)
|
||||
)
|
||||
) {
|
||||
Frame = Event.FramesById[frame_id];
|
||||
Frame = e.FramesById[frame_id];
|
||||
break;
|
||||
}
|
||||
} // end foreach frame in the event.
|
||||
if ( ! Frame ) {
|
||||
console.log("Didn't find frame for " + time );
|
||||
if ( !Frame ) {
|
||||
console.log("Didn't find frame for " + time);
|
||||
return null;
|
||||
}
|
||||
} // end foreach event
|
||||
|
@ -97,11 +127,11 @@ function getFrame( monId, time ) {
|
|||
}
|
||||
|
||||
// time is seconds since epoch
|
||||
function getImageSource( monId, time ) {
|
||||
function getImageSource(monId, time) {
|
||||
if ( liveMode == 1 ) {
|
||||
var new_url = monitorImageObject[monId].src.replace(
|
||||
/rand=\d+/i,
|
||||
'rand='+Math.floor((Math.random() * 1000000) )
|
||||
'rand='+Math.floor(Math.random() * 1000000)
|
||||
);
|
||||
if ( auth_hash ) {
|
||||
// update auth hash
|
||||
|
@ -109,20 +139,31 @@ function getImageSource( monId, time ) {
|
|||
}
|
||||
return new_url;
|
||||
}
|
||||
var frame_id;
|
||||
|
||||
var Frame = getFrame(monId, time);
|
||||
if ( Frame ) {
|
||||
// Adjust for bulk frames
|
||||
if ( Frame.NextFrameId ) {
|
||||
var e = events[Frame.EventId];
|
||||
var NextFrame = e.FramesById[Frame.NextFrameId];
|
||||
if ( !NextFrame ) {
|
||||
console.log("No next frame for " + Frame.NextFrameId);
|
||||
} else if ( NextFrame.Type == 'Bulk' ) {
|
||||
// There is time between this frame and a bulk frame
|
||||
var duration = Frame.NextTimeStampSecs - Frame.TimeStampSecs;
|
||||
frame_id = Frame.FrameId + parseInt( (Frame.NextFrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration );
|
||||
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + Frame.NextFrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) );
|
||||
//} else {
|
||||
//console.log("No NextFrame");
|
||||
frame_id = Frame.FrameId + parseInt( (NextFrame.FrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration );
|
||||
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + NextFrame.FrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) );
|
||||
}
|
||||
|
||||
} else {
|
||||
frame_id = Frame['Id'];
|
||||
console.log("No NextFrame");
|
||||
}
|
||||
Event = events[Frame.EventId];
|
||||
|
||||
var storage = Storage[Event.StorageId];
|
||||
if ( ! storage ) {
|
||||
if ( !storage ) {
|
||||
// Storage[0] is guaranteed to exist as we make sure it is there in montagereview.js.php
|
||||
console.log("No storage area for id " + Event.StorageId);
|
||||
storage = Storage[0];
|
||||
|
@ -130,7 +171,7 @@ function getImageSource( monId, time ) {
|
|||
// monitorServerId may be 0, which gives us the default Server entry
|
||||
var server = storage.ServerId ? Servers[storage.ServerId] : Servers[monitorServerId[monId]];
|
||||
return server.PathToIndex +
|
||||
'?view=image&eid=' + Frame.EventId + '&fid='+Frame.FrameId +
|
||||
'?view=image&eid=' + Frame.EventId + '&fid='+frame_id +
|
||||
"&width=" + monitorCanvasObj[monId].width +
|
||||
"&height=" + monitorCanvasObj[monId].height;
|
||||
} // end found Frame
|
||||
|
@ -818,16 +859,16 @@ function showOneMonitor(monId) {
|
|||
// We know the monitor, need to determine the event based on current time
|
||||
var url;
|
||||
if ( liveMode != 0 ) {
|
||||
url="?view=watch&mid=" + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] );
|
||||
url = '?view=watch&mid=' + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId]);
|
||||
} else {
|
||||
var Frame = getFrame( monId, currentTimeSecs );
|
||||
if ( Frame ) {
|
||||
url="?view=event&eid=" + Frame.EventId + '&fid=' +Frame.FrameId;
|
||||
url = '?view=event&eid=' + Frame.EventId + '&fid=' + Frame.FrameId;
|
||||
createPopup(url, 'zmEvent', 'event', monitorWidth[monId], monitorHeight[monId]);
|
||||
} else {
|
||||
url="?view=watch&mid=" + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] );
|
||||
url = '?view=watch&mid=' + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId]);
|
||||
}
|
||||
} // end if live/events
|
||||
}
|
||||
|
@ -960,11 +1001,19 @@ function initPage() {
|
|||
maxDate: +0,
|
||||
constrainInput: false,
|
||||
onClose: function(newDate, oldData) {
|
||||
if (newDate !== oldData.lastVal) {
|
||||
if ( newDate !== oldData.lastVal ) {
|
||||
changeDateTime();
|
||||
}
|
||||
}
|
||||
});
|
||||
$j('#scaleslider').bind('change', function() { setScale(this.value); });
|
||||
$j('#scaleslider').bind('input', function() { showScale(this.value); });
|
||||
$j('#speedslider').bind('change', function() { setSpeed(this.value); });
|
||||
$j('#speedslider').bind('input', function() { showSpeed(this.value); });
|
||||
|
||||
$j('#liveButton').bind('click', function() { setLive(1-liveMode); });
|
||||
$j('#fit').bind('click', function() { setFit(1-fitMode); });
|
||||
$j('#archive_status').bind('change', function() { console.log('submitting'); this.form.submit(); });
|
||||
}
|
||||
window.addEventListener("resize", redrawScreen, {passive: true});
|
||||
// Kick everything off
|
||||
|
|
|
@ -55,23 +55,26 @@ if ( !$liveMode ) {
|
|||
|
||||
if ( $result = dbQuery($framesSql) ) {
|
||||
$next_frame = null;
|
||||
while( $frame = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||
while ( $frame = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||
$event_id = $frame['EventId'];
|
||||
$event = &$EventsById[$event_id];
|
||||
|
||||
$frame['TimeStampSecs'] = $event['StartTimeSecs'] + $frame['Delta'];
|
||||
if ( !isset($event['FramesById']) ) {
|
||||
// Please note that this is the last frame as we sort DESC
|
||||
$event['FramesById'] = array();
|
||||
$frame['NextTimeStampSecs'] = 0;
|
||||
$frame['NextTimeStampSecs'] = $event['EndTime'];
|
||||
} else {
|
||||
$frame['NextTimeStampSecs'] = $next_frames[$frame['EventId']]['TimeStampSecs'];
|
||||
$frame['NextFrameId'] = $next_frames[$frame['EventId']]['FrameId'];
|
||||
$frame['NextFrameId'] = $next_frames[$frame['EventId']]['Id'];
|
||||
}
|
||||
$event['FramesById'] += array( $frame['Id']=>$frame );
|
||||
$event['FramesById'] += array($frame['Id']=>$frame);
|
||||
$next_frames[$frame['EventId']] = $frame;
|
||||
}
|
||||
}
|
||||
|
||||
$events_by_monitor_id = array();
|
||||
|
||||
echo "var events = {\n";
|
||||
foreach ( $EventsById as $event_id=>$event ) {
|
||||
|
||||
|
@ -82,7 +85,7 @@ if ( !$liveMode ) {
|
|||
if ( !$minTimeSecs or $minTimeSecs > $StartTimeSecs ) $minTimeSecs = $StartTimeSecs;
|
||||
if ( !$maxTimeSecs or $maxTimeSecs < $EndTimeSecs ) $maxTimeSecs = $EndTimeSecs;
|
||||
|
||||
$event_json = json_encode($event, JSON_PRETTY_PRINT);
|
||||
$event_json = json_encode($event, JSON_PRETTY_PRINT|JSON_NUMERIC_CHECK);
|
||||
echo " $event_id : $event_json,\n";
|
||||
|
||||
$index = $index + 1;
|
||||
|
@ -91,8 +94,19 @@ if ( !$liveMode ) {
|
|||
$maxScore = $event['MaxScore'];
|
||||
$anyAlarms = true;
|
||||
}
|
||||
if ( !isset($events_by_monitor_id[$event['MonitorId']]) )
|
||||
$events_by_monitor_id[$event['MonitorId']] = array();
|
||||
array_push($events_by_monitor_id[$event['MonitorId']], $event_id);
|
||||
|
||||
} # end foreach Event
|
||||
echo " };
|
||||
var events_by_monitor_id = {
|
||||
\n";
|
||||
|
||||
foreach ( $events_by_monitor_id as $monitor_id=>$event_ids ) {
|
||||
echo "$monitor_id : ".json_encode($event_ids, JSON_NUMERIC_CHECK) . "\n";
|
||||
}
|
||||
echo " };\n";
|
||||
echo " };\n";
|
||||
|
||||
// if there is no data set the min/max to the passed in values
|
||||
if ( $index == 0 ) {
|
||||
|
|
|
@ -64,7 +64,7 @@ if ( isset($_REQUEST['filter']) ) {
|
|||
$filter = $_REQUEST['filter'];
|
||||
} else {
|
||||
|
||||
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) {
|
||||
if ( isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && (count($displayMonitors) != 0) ) {
|
||||
$filter = array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
|
@ -77,10 +77,10 @@ if ( isset($_REQUEST['filter']) ) {
|
|||
$filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and'));
|
||||
} else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) {
|
||||
# this should be redundant
|
||||
for ($i=0; $i < count($displayMonitors); $i++) {
|
||||
if ($i == '0') {
|
||||
for ( $i = 0; $i < count($displayMonitors); $i++ ) {
|
||||
if ( $i == '0' ) {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1');
|
||||
} else if ($i == (count($displayMonitors)-1)) {
|
||||
} else if ( $i == (count($displayMonitors)-1) ) {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1');
|
||||
} else {
|
||||
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or');
|
||||
|
@ -118,7 +118,7 @@ $eventsSql = 'SELECT
|
|||
|
||||
// Note that the delta value seems more accurate than the time stamp for some reason.
|
||||
$framesSql = '
|
||||
SELECT Id, FrameId, EventId, TimeStamp, UNIX_TIMESTAMP(TimeStamp) AS TimeStampSecs, Score, Delta
|
||||
SELECT Id, FrameId, EventId, TimeStamp, UNIX_TIMESTAMP(TimeStamp) AS TimeStampSecs, Score, Delta, Type
|
||||
FROM Frames
|
||||
WHERE EventId IN (SELECT E.Id FROM Events AS E WHERE 1>0
|
||||
';
|
||||
|
@ -126,7 +126,7 @@ $framesSql = '
|
|||
// This program only calls itself with the time range involved -- it does all monitors (the user can see, in the called group) all the time
|
||||
|
||||
$monitor_ids_sql = '';
|
||||
if ( ! empty($user['MonitorIds']) ) {
|
||||
if ( !empty($user['MonitorIds']) ) {
|
||||
$eventsSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
|
||||
$framesSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ if ( (strtotime($maxTime) - strtotime($minTime))/(365*24*3600) > 30 ) {
|
|||
}
|
||||
|
||||
$fitMode = 1;
|
||||
if (isset($_REQUEST['fit']) && $_REQUEST['fit']=='0' )
|
||||
if ( isset($_REQUEST['fit']) && ($_REQUEST['fit'] == '0') )
|
||||
$fitMode = 0;
|
||||
|
||||
if ( isset($_REQUEST['scale']) )
|
||||
|
@ -200,7 +200,7 @@ if ( isset($_REQUEST['current']) )
|
|||
$defaultCurrentTime = validHtmlStr($_REQUEST['current']);
|
||||
|
||||
$liveMode = 1; // default to live
|
||||
if ( isset($_REQUEST['live']) && $_REQUEST['live']=='0' )
|
||||
if ( isset($_REQUEST['live']) && ($_REQUEST['live'] == '0') )
|
||||
$liveMode = 0;
|
||||
|
||||
$initialDisplayInterval = 1000;
|
||||
|
@ -236,28 +236,28 @@ foreach( $displayMonitors as $row ) {
|
|||
// These are zoom ranges per visible monitor
|
||||
|
||||
xhtmlHeaders(__FILE__, translate('MontageReview') );
|
||||
getBodyTopHTML();
|
||||
?>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="page">
|
||||
<?php echo getNavBarHTML() ?>
|
||||
<form id="montagereview_form" action="?" method="get">
|
||||
<input type="hidden" name="view" value="montagereview"/>
|
||||
<div id="header">
|
||||
<a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right"></span></a>
|
||||
<div id="flipMontageHeader">
|
||||
<?php echo $filter_bar ?>
|
||||
<?php echo $filter_bar ?>
|
||||
<div id="DateTimeDiv">
|
||||
<input type="text" name="minTime" id="minTime" value="<?php echo preg_replace('/T/', ' ', $minTime ) ?>"/> to
|
||||
<input type="text" name="maxTime" id="maxTime" value="<?php echo preg_replace('/T/', ' ', $maxTime ) ?>"/>
|
||||
</div>
|
||||
<div id="ScaleDiv">
|
||||
<label for="scaleslider"><?php echo translate('Scale')?></label>
|
||||
<input id="scaleslider" type="range" min="0.1" max="1.0" value="<?php echo $defaultScale ?>" step="0.10" onchange="setScale(this.value);" oninput="showScale(this.value);"/>
|
||||
<input id="scaleslider" type="range" min="0.1" max="1.0" value="<?php echo $defaultScale ?>" step="0.10"/>
|
||||
<span id="scaleslideroutput"><?php echo number_format((float)$defaultScale,2,'.','')?> x</span>
|
||||
</div>
|
||||
<div id="SpeedDiv">
|
||||
<label for="speedslider"><?php echo translate('Speed') ?></label>
|
||||
<input id="speedslider" type="range" min="0" max="<?php echo count($speeds)-1?>" value="<?php echo $speedIndex ?>" step="1" onchange="setSpeed(this.value);" oninput="showSpeed(this.value);"/>
|
||||
<input id="speedslider" type="range" min="0" max="<?php echo count($speeds)-1?>" value="<?php echo $speedIndex ?>" step="1"/>
|
||||
<span id="speedslideroutput"><?php echo $speeds[$speedIndex] ?> fps</span>
|
||||
</div>
|
||||
<div id="ButtonsDiv">
|
||||
|
@ -267,31 +267,29 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
|
|||
<button type="button" id="lasteight" data-on-click="click_lastEight" ><?php echo translate('8 Hour') ?></button>
|
||||
<button type="button" id="lasthour" data-on-click="click_lastHour" ><?php echo translate('1 Hour') ?></button>
|
||||
<button type="button" id="allof" data-on-click="click_all_events" ><?php echo translate('All Events') ?></button>
|
||||
<button type="button" id="liveButton" onclick="setLive(1-liveMode); console.log('live');return false;"><?php echo translate('Live') ?></button>
|
||||
<button type="button" id="fit" onclick="setFit(1-fitMode);" ><?php echo translate('Fit') ?></button>
|
||||
<button type="button" id="liveButton"><?php echo translate('Live') ?></button>
|
||||
<button type="button" id="fit" ><?php echo translate('Fit') ?></button>
|
||||
<button type="button" id="panright" data-on-click="click_panright" ><?php echo translate('Pan') ?> ></button>
|
||||
<?php
|
||||
if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
|
||||
if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
|
||||
?>
|
||||
<button type="button" id="downloadVideo" data-on-click="click_download"><?php echo translate('Download Video') ?></button>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php if ( !$liveMode ) { ?>
|
||||
<div id="eventfilterdiv" class="input-group">
|
||||
<label>Archive Status
|
||||
<?php echo htmlSelect(
|
||||
<?php echo htmlSelect(
|
||||
'archive_status',
|
||||
array(
|
||||
'' => translate('All'),
|
||||
'Archived' => translate('Archived'),
|
||||
'Unarchived' => translate('UnArchived'),
|
||||
),
|
||||
( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : ''),
|
||||
array('onchange'=>'this.form.submit();')
|
||||
);
|
||||
?>
|
||||
( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : '')
|
||||
); ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php } // end if !live ?>
|
||||
|
@ -301,17 +299,17 @@ if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
|
|||
<span id="scrubright"></span>
|
||||
<span id="scruboutput"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--flipMontageHeader-->
|
||||
<input type="hidden" name="fit" value="<?php echo $fitMode ?>"/>
|
||||
<input type="hidden" name="live" value="<?php echo $liveMode ?>"/>
|
||||
</div>
|
||||
</form>
|
||||
</div><!--header-->
|
||||
</form>
|
||||
<div id="monitors">
|
||||
<?php
|
||||
// Monitor images - these had to be loaded after the monitors used were determined (after loading events)
|
||||
foreach ( $monitors as $m ) {
|
||||
echo '<canvas title="'.$m->Id().' ' .$m->Name().'" width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" monitor_id="'.$m->Id().'">No Canvas Support!!</canvas>';
|
||||
echo '<canvas title="'.$m->Id().' ' .$m->Name().'" width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" monitor_id="'.$m->Id().'">No Canvas Support!!</canvas>
|
||||
';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue