Merge branch 'storageareas' of github.com:ConnorTechnology/ZoneMinder into storageareas
commit
f9be7f0fa0
|
@ -28,7 +28,7 @@ New installs
|
|||
1. Unless you are already using MariaDB server, you need to ensure that the
|
||||
server is configured to start during boot and properly secured by running:
|
||||
|
||||
sudo dnf install mariadb-server
|
||||
sudo yum install mariadb-server
|
||||
sudo systemctl enable mariadb
|
||||
sudo systemctl start mariadb.service
|
||||
mysql_secure_installation
|
||||
|
|
|
@ -18,7 +18,7 @@ Alias /zm "@ZM_WEBDIR@"
|
|||
Allow from all
|
||||
</Directory>
|
||||
|
||||
ScriptAlias /cgi-bin/zm "@ZM_CGIDIR@"
|
||||
ScriptAlias /cgi-bin-zm "@ZM_CGIDIR@"
|
||||
<Directory "@ZM_CGIDIR@">
|
||||
SSLRequireSSL
|
||||
AllowOverride All
|
||||
|
|
|
@ -4,3 +4,5 @@ var/cache/zoneminder/events
|
|||
var/cache/zoneminder/images
|
||||
var/cache/zoneminder/temp
|
||||
usr/share/zoneminder/db
|
||||
etc/zm
|
||||
etc/zm/conf.d
|
||||
|
|
|
@ -14,6 +14,8 @@ if [ "$1" = "configure" ]; then
|
|||
fi
|
||||
|
||||
# Do this every time the package is installed or upgraded
|
||||
# Ensure zoneminder is stopped
|
||||
invoke-rc.d zoneminder stop || true
|
||||
|
||||
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||
if [ -e "/etc/init.d/mysql" ]; then
|
||||
|
@ -34,12 +36,8 @@ if [ "$1" = "configure" ]; then
|
|||
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
fi
|
||||
|
||||
# Ensure zoneminder is stopped
|
||||
invoke-rc.d zoneminder stop || true
|
||||
zmupdate.pl --nointeractive
|
||||
zmupdate.pl --nointeractive -f
|
||||
echo "Done Updating, starting ZoneMinder"
|
||||
invoke-rc.d zoneminder start || true
|
||||
else
|
||||
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||
fi
|
||||
|
@ -49,6 +47,8 @@ if [ "$1" = "configure" ]; then
|
|||
else
|
||||
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
|
||||
fi
|
||||
echo "Done Updating, starting ZoneMinder"
|
||||
invoke-rc.d zoneminder start || true
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
|
|
@ -13,11 +13,11 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
|
|||
,libavutil-dev (>= 6:10~)
|
||||
,libswscale-dev (>= 6:10~)
|
||||
,libbz2-dev
|
||||
,libgcrypt-dev
|
||||
,libgcrypt-dev | libgcrypt11-dev
|
||||
,libcurl4-gnutls-dev
|
||||
,libgnutls-openssl-dev
|
||||
,libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev
|
||||
,libmysqlclient-dev
|
||||
,libmysqlclient-dev | libmariadbclient-dev
|
||||
,libpcre3-dev
|
||||
,libpolkit-gobject-1-dev
|
||||
,libv4l-dev (>= 0.8.3) [!hurd-any]
|
||||
|
|
|
@ -21,6 +21,8 @@ if [ "$1" = "configure" ]; then
|
|||
# Ensure zoneminder is stopped
|
||||
deb-systemd-invoke stop zoneminder.service || exit $?
|
||||
|
||||
# Ensure zoneminder is stopped
|
||||
deb-systemd-invoke stop zoneminder.service || exit $?
|
||||
if [ "$ZM_DB_HOST" = "localhost" ]; then
|
||||
|
||||
if [ -e "/etc/init.d/mysql" ]; then
|
||||
|
|
|
@ -297,24 +297,28 @@ sub terminate {
|
|||
sub reinitialise {
|
||||
my $this = shift;
|
||||
|
||||
# So if the logger is initialized, we just return. Since the logger is NORMALLY initialized... the rest of this function never executes.
|
||||
return unless ( $this->{initialised} );
|
||||
|
||||
# Bit of a nasty hack to reopen connections to log files and the DB
|
||||
my $syslogLevel = $this->syslogLevel();
|
||||
$this->syslogLevel( NOLOG );
|
||||
$this->syslogLevel( $syslogLevel ) if ( $syslogLevel > NOLOG );
|
||||
|
||||
my $logfileLevel = $this->fileLevel();
|
||||
$this->fileLevel( NOLOG );
|
||||
$this->fileLevel( $logfileLevel ) if ( $logfileLevel > NOLOG );
|
||||
|
||||
my $databaseLevel = $this->databaseLevel();
|
||||
$this->databaseLevel( NOLOG );
|
||||
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
|
||||
|
||||
my $screenLevel = $this->termLevel();
|
||||
$this->termLevel( NOLOG );
|
||||
|
||||
$this->syslogLevel( $syslogLevel ) if ( $syslogLevel > NOLOG );
|
||||
$this->fileLevel( $logfileLevel ) if ( $logfileLevel > NOLOG );
|
||||
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
|
||||
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
|
||||
$this->termLevel( $screenLevel ) if ( $screenLevel > NOLOG );
|
||||
}
|
||||
|
||||
# Prevents undefined logging levels
|
||||
sub limit {
|
||||
my $this = shift;
|
||||
my $level = shift;
|
||||
|
@ -375,12 +379,16 @@ sub level {
|
|||
my $level = shift;
|
||||
if ( defined($level) ) {
|
||||
$this->{level} = $this->limit( $level );
|
||||
|
||||
# effectiveLevel is the highest logging level used by any of the outputs.
|
||||
$this->{effectiveLevel} = NOLOG;
|
||||
$this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} );
|
||||
$this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} );
|
||||
$this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} );
|
||||
$this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{effectiveLevel} );
|
||||
$this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{effectiveLevel} );
|
||||
|
||||
# ICON: I am remarking this out because I don't see the point of having an effective level, if we are just going to set it to level.
|
||||
#$this->{effectiveLevel} = $this->{level} if ( $this->{level} > $this->{effectiveLevel} );
|
||||
}
|
||||
return( $this->{level} );
|
||||
}
|
||||
|
@ -400,6 +408,7 @@ sub termLevel {
|
|||
my $this = shift;
|
||||
my $termLevel = shift;
|
||||
if ( defined($termLevel) ) {
|
||||
# What is the point of this next lint if we are just going to overwrite it with the next line? I propose we move it down one line or remove it altogether
|
||||
$termLevel = NOLOG if ( !$this->{hasTerm} );
|
||||
$termLevel = $this->limit( $termLevel );
|
||||
if ( $this->{termLevel} != $termLevel ) {
|
||||
|
|
|
@ -174,7 +174,7 @@ if ( ! $server_up ) {
|
|||
$attempts++;
|
||||
Error("Waiting for zmdc.pl server process, attempt $attempts" );
|
||||
Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY);
|
||||
usleep(20000);
|
||||
usleep(200000);
|
||||
} # end while
|
||||
} elsif ( defined($cpid) ) {
|
||||
ZMServer::run();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -62,8 +63,7 @@ if ( ! defined $interval ) {
|
|||
$interval = eval($Config{ZM_TELEMETRY_INTERVAL});
|
||||
}
|
||||
|
||||
if ( $Config{ZM_TELEMETRY_DATA} or $force )
|
||||
{
|
||||
if ( $Config{ZM_TELEMETRY_DATA} or $force ) {
|
||||
print "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
|
||||
|
||||
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
|
||||
|
@ -84,17 +84,17 @@ if ( $Config{ZM_TELEMETRY_DATA} or $force )
|
|||
my %telemetry;
|
||||
$telemetry{uuid} = getUUID($dbh);
|
||||
$telemetry{ip} = getIP();
|
||||
$telemetry{timestamp} = strftime( "%Y-%m-%dT%H:%M:%S%z", localtime() );
|
||||
$telemetry{monitor_count} = countQuery($dbh,"Monitors");
|
||||
$telemetry{event_count} = countQuery($dbh,"Events");
|
||||
$telemetry{architecture} = runSysCmd("uname -p");
|
||||
$telemetry{timestamp} = strftime( '%Y-%m-%dT%H:%M:%S%z', localtime() );
|
||||
$telemetry{monitor_count} = countQuery($dbh,'Monitors');
|
||||
$telemetry{event_count} = countQuery($dbh,'Events');
|
||||
$telemetry{architecture} = runSysCmd('uname -p');
|
||||
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
|
||||
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
|
||||
$telemetry{system_memory} = totalmem();
|
||||
$telemetry{processor_count} = cpu_count();
|
||||
$telemetry{monitors} = getMonitorRef($dbh);
|
||||
|
||||
Info( "Sending data to ZoneMinder Telemetry server." );
|
||||
Info( 'Sending data to ZoneMinder Telemetry server.' );
|
||||
|
||||
my $result = jsonEncode( \%telemetry );
|
||||
|
||||
|
@ -112,7 +112,7 @@ if ( $Config{ZM_TELEMETRY_DATA} or $force )
|
|||
}
|
||||
sleep( 3600 );
|
||||
}
|
||||
print "Update agent exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
|
||||
print 'Update agent exiting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n";
|
||||
}
|
||||
|
||||
###############
|
||||
|
@ -127,13 +127,13 @@ sub runSysCmd {
|
|||
my $path = qx( which $arguments[0] );
|
||||
|
||||
my $status = $? >> 8;
|
||||
my $result = "";
|
||||
my $result = '';
|
||||
if ( !$path || $status ) {
|
||||
Warning( "Cannot find the $arguments[0] executable." );
|
||||
} else {
|
||||
chomp($path);
|
||||
$arguments[0] = $path;
|
||||
my $cmd = join(" ",@arguments);
|
||||
my $cmd = join(' ',@arguments);
|
||||
$result = qx( $cmd );
|
||||
chomp($result);
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ sub sendData {
|
|||
my $server_endpoint = $Config{ZM_TELEMETRY_SERVER_ENDPOINT};
|
||||
|
||||
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
|
||||
$ua->proxy( "https", $Config{ZM_UPDATE_CHECK_PROXY} );
|
||||
$ua->proxy( 'https', $Config{ZM_UPDATE_CHECK_PROXY} );
|
||||
}
|
||||
|
||||
Debug("Posting telemetry data to: $server_endpoint");
|
||||
|
@ -166,7 +166,7 @@ sub sendData {
|
|||
my $resp_msg = $resp->decoded_content;
|
||||
my $resp_code = $resp->code;
|
||||
if ($resp->is_success) {
|
||||
Info("Telemetry data uploaded successfully.");
|
||||
Info('Telemetry data uploaded successfully.');
|
||||
Debug("Telemetry server upload success response message: $resp_msg");
|
||||
} else {
|
||||
Warning("Telemetry server returned HTTP POST error code: $resp_code");
|
||||
|
@ -181,16 +181,16 @@ sub getUUID {
|
|||
my $uuid= "";
|
||||
|
||||
# Verify the current UUID is valid and not nil
|
||||
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne "00000000-0000-0000-0000-000000000000" )) {
|
||||
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne '00000000-0000-0000-0000-000000000000' )) {
|
||||
$uuid = $Config{ZM_TELEMETRY_UUID};
|
||||
} else {
|
||||
my $sql = "SELECT uuid()";
|
||||
my $sql = 'SELECT uuid()';
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
|
||||
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
|
||||
$sth->finish();
|
||||
|
||||
$sql = "UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'";
|
||||
$sql = q`UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`;
|
||||
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
@ -202,9 +202,9 @@ return $uuid;
|
|||
|
||||
# Retrieves the local server's external IP address
|
||||
sub getIP {
|
||||
my $ipaddr = "0.0.0.0";
|
||||
my $ipaddr = '0.0.0.0';
|
||||
my $ua = LWP::UserAgent->new;
|
||||
my $server_endpoint = "https://wiki.zoneminder.com/ip.php";
|
||||
my $server_endpoint = 'https://wiki.zoneminder.com/ip.php';
|
||||
|
||||
my $req = HTTP::Request->new(GET => $server_endpoint);
|
||||
my $resp = $ua->request($req);
|
||||
|
@ -236,7 +236,7 @@ return $count
|
|||
sub getMonitorRef {
|
||||
my $dbh = shift;
|
||||
|
||||
my $sql = "SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors";
|
||||
my $sql = 'SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors';
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
|
||||
my $arrayref = $sth->fetchall_arrayref({});
|
||||
|
@ -245,34 +245,34 @@ return $arrayref;
|
|||
}
|
||||
|
||||
sub getDistro {
|
||||
my $kernel = "";
|
||||
my $distro = "";
|
||||
my $version = "";
|
||||
my $kernel = '';
|
||||
my $distro = '';
|
||||
my $version = '';
|
||||
my @uname = uname();
|
||||
|
||||
if ( $uname[0] =~ /Linux/ ) {
|
||||
Debug("Linux distro detected.");
|
||||
Debug('Linux distro detected.');
|
||||
($kernel, $distro, $version) = linuxDistro();
|
||||
} elsif ( $uname[0] =~ /.*BSD/ ) {
|
||||
Debug("BSD distro detected.");
|
||||
Debug('BSD distro detected.');
|
||||
$kernel = $uname[3];
|
||||
$distro = $uname[0];
|
||||
$version = $uname[2];
|
||||
} elsif ( $uname[0] =~ /Darwin/ ) {
|
||||
Debug("Mac OS distro detected.");
|
||||
Debug('Mac OS distro detected.');
|
||||
$kernel = $uname[3];
|
||||
$distro = runSysCmd("sw_vers -productName");
|
||||
$version = runSysCmd("sw_vers -productVersion");
|
||||
$distro = runSysCmd('sw_vers -productName');
|
||||
$version = runSysCmd('sw_vers -productVersion');
|
||||
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
|
||||
Debug("Sun Solaris detected.");
|
||||
Debug('Sun Solaris detected.');
|
||||
$kernel = $uname[3];
|
||||
$distro = $uname[1];
|
||||
$version = $uname[2];
|
||||
} else {
|
||||
Warning("ZoneMinder was unable to determine the host system. Please report.");
|
||||
$kernel = "Unknown";
|
||||
$distro = "Unknown";
|
||||
$version = "Unknown";
|
||||
Warning('ZoneMinder was unable to determine the host system. Please report.');
|
||||
$kernel = 'Unknown';
|
||||
$distro = 'Unknown';
|
||||
$version = 'Unknown';
|
||||
}
|
||||
|
||||
return ($kernel, $distro, $version);
|
||||
|
@ -281,13 +281,13 @@ return ($kernel, $distro, $version);
|
|||
sub linuxDistro {
|
||||
my @uname = uname();
|
||||
my $kernel = $uname[2];
|
||||
my $distro = "Unknown Linux Distro";
|
||||
my $version = "Unknown Linux Version";
|
||||
my $distro = 'Unknown Linux Distro';
|
||||
my $version = 'Unknown Linux Version';
|
||||
my $found = 0;
|
||||
|
||||
# os-release is the standard for many new distros based on systemd
|
||||
if ( -f "/etc/os-release" ) {
|
||||
open(my $RELFILE,"<","/etc/os-release") or die( "Can't Open file: $!\n" );
|
||||
if ( -f '/etc/os-release' ) {
|
||||
open(my $RELFILE,'<','/etc/os-release') or die( "Can't Open file: $!\n" );
|
||||
while (<$RELFILE>) {
|
||||
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
|
||||
$distro = $2;
|
||||
|
@ -300,8 +300,8 @@ sub linuxDistro {
|
|||
}
|
||||
close $RELFILE;
|
||||
# exists on many distros but does not always contain useful information, such as redhat
|
||||
} elsif ( -f "/etc/lsb-release" ) {
|
||||
open(my $RELFILE,"<","/etc/lsb-release") or die( "Can't Open file: $!\n" );
|
||||
} elsif ( -f '/etc/lsb-release' ) {
|
||||
open(my $RELFILE,'<','/etc/lsb-release') or die( "Can't Open file: $!\n" );
|
||||
while (<$RELFILE>) {
|
||||
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
|
||||
$distro = $2;
|
||||
|
@ -317,13 +317,13 @@ sub linuxDistro {
|
|||
|
||||
# If all else fails, search through a list of known release files until we find one
|
||||
if ( !$found ) {
|
||||
my @releasefile = ("/etc/SuSE-release", "/etc/redhat-release", "/etc/redhat_version",
|
||||
"/etc/fedora-release", "/etc/slackware-release", "/etc/slackware-version",
|
||||
"/etc/debian_release", "/etc/debian_version", "/etc/mandrake-release",
|
||||
"/etc/yellowdog-release", "/etc/gentoo-release");
|
||||
my @releasefile = ('/etc/SuSE-release', '/etc/redhat-release', '/etc/redhat_version',
|
||||
'/etc/fedora-release', '/etc/slackware-release', '/etc/slackware-version',
|
||||
'/etc/debian_release', '/etc/debian_version', '/etc/mandrake-release',
|
||||
'/etc/yellowdog-release', '/etc/gentoo-release');
|
||||
foreach (@releasefile) {
|
||||
if ( -f $_ ) {
|
||||
open(my $RELFILE,"<",$_) or die( "Can't Open file: $!\n" );
|
||||
open(my $RELFILE,'<',$_) or die( "Can't Open file: $!\n" );
|
||||
while (<$RELFILE>) {
|
||||
if ( /(.*).* (\d+\.?\d*) .*/ ) {
|
||||
$distro = $1;
|
||||
|
@ -338,7 +338,7 @@ sub linuxDistro {
|
|||
}
|
||||
|
||||
if ( !$found ) {
|
||||
Warning("ZoneMinder was unable to determine Linux distro. Please report.");
|
||||
Warning('ZoneMinder was unable to determine Linux distro. Please report.');
|
||||
}
|
||||
|
||||
return ($kernel, $distro, $version);
|
||||
|
|
|
@ -195,7 +195,7 @@ void Logger::initialise( const std::string &id, const Options &options ) {
|
|||
level( tempLevel );
|
||||
|
||||
mFlush = false;
|
||||
if (envPtr = getenv( "LOG_FLUSH")) {
|
||||
if ( (envPtr = getenv("LOG_FLUSH")) ) {
|
||||
mFlush = atoi( envPtr );
|
||||
} else if ( config.log_debug ) {
|
||||
mFlush = true;
|
||||
|
|
|
@ -30,8 +30,7 @@ class Monitor;
|
|||
|
||||
#define TV_2_FLOAT( tv ) ( double((tv).tv_sec) + (double((tv).tv_usec) / 1000000.0) )
|
||||
|
||||
class StreamBase
|
||||
{
|
||||
class StreamBase {
|
||||
public:
|
||||
typedef enum { STREAM_JPEG, STREAM_RAW, STREAM_ZIP, STREAM_SINGLE, STREAM_MPEG } StreamType;
|
||||
|
||||
|
@ -110,8 +109,7 @@ protected:
|
|||
virtual void processCommand( const CmdMsg *msg )=0;
|
||||
|
||||
public:
|
||||
StreamBase()
|
||||
{
|
||||
StreamBase() {
|
||||
monitor = 0;
|
||||
|
||||
type = DEFAULT_TYPE;
|
||||
|
@ -145,32 +143,27 @@ public:
|
|||
}
|
||||
virtual ~StreamBase();
|
||||
|
||||
void setStreamType( StreamType p_type )
|
||||
{
|
||||
void setStreamType( StreamType p_type ) {
|
||||
type = p_type;
|
||||
}
|
||||
void setStreamFormat( const char *p_format )
|
||||
{
|
||||
void setStreamFormat( const char *p_format ) {
|
||||
format = p_format;
|
||||
}
|
||||
void setStreamScale( int p_scale )
|
||||
{
|
||||
void setStreamScale( int p_scale ) {
|
||||
scale = p_scale;
|
||||
if ( ! scale )
|
||||
scale = DEFAULT_SCALE;
|
||||
}
|
||||
void setStreamReplayRate( int p_rate )
|
||||
{
|
||||
void setStreamReplayRate( int p_rate ) {
|
||||
replay_rate = p_rate;
|
||||
}
|
||||
void setStreamMaxFPS( double p_maxfps )
|
||||
{
|
||||
void setStreamMaxFPS( double p_maxfps ) {
|
||||
maxfps = p_maxfps;
|
||||
}
|
||||
void setStreamBitrate( int p_bitrate )
|
||||
{
|
||||
void setStreamBitrate( int p_bitrate ) {
|
||||
bitrate = p_bitrate;
|
||||
}
|
||||
void setStreamQueue( int p_connkey )
|
||||
{
|
||||
void setStreamQueue( int p_connkey ) {
|
||||
connkey = p_connkey;
|
||||
}
|
||||
virtual void openComms();
|
||||
|
|
|
@ -155,7 +155,7 @@ int X264MP4Writer::Open() {
|
|||
}
|
||||
|
||||
/* Search SPS NAL for AVC information */
|
||||
for ( unsigned int i = 0; i < i_nals; i++ ) {
|
||||
for ( int i = 0; i < i_nals; i++ ) {
|
||||
if ( nals[i].i_type == NAL_SPS ) {
|
||||
x264_profleindication = nals[i].p_payload[5];
|
||||
x264_profilecompat = nals[i].p_payload[6];
|
||||
|
@ -467,7 +467,7 @@ void X264MP4Writer::x264encodeloop(bool bFlush) {
|
|||
/* Got a frame. Copy this new frame into the previous frame */
|
||||
if ( frame_size > 0 ) {
|
||||
/* Copy the NALs and the payloads */
|
||||
for ( unsigned int i = 0; i < i_nals; i++ ) {
|
||||
for ( int i = 0; i < i_nals; i++ ) {
|
||||
prevnals.push_back(nals[i]);
|
||||
prevpayload.append(nals[i].p_payload, nals[i].i_payload);
|
||||
}
|
||||
|
|
|
@ -718,6 +718,10 @@ Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts
|
|||
// There's nothing we can really do if the frame is rejected, just drop it and get on with the next
|
||||
Warning("%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) ", __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret));
|
||||
dumpPacket(&safepkt);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
zm_dump_codecpar( video_input_stream->codecpar );
|
||||
zm_dump_codecpar( video_output_stream->codecpar );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
44
src/zms.cpp
44
src/zms.cpp
|
@ -42,14 +42,11 @@ bool ValidateAccess( User *user, int mon_id ) {
|
|||
if ( !allowed ) {
|
||||
Error( "Error, insufficient privileges for requested action" );
|
||||
exit( -1 );
|
||||
} else {
|
||||
Debug( 1, "User allowed.");
|
||||
}
|
||||
return( allowed );
|
||||
}
|
||||
|
||||
int main( int argc, const char *argv[] )
|
||||
{
|
||||
int main( int argc, const char *argv[] ) {
|
||||
self = argv[0];
|
||||
|
||||
srand( getpid() * time( 0 ) );
|
||||
|
@ -119,37 +116,37 @@ int main( int argc, const char *argv[] )
|
|||
mode = !strcmp( value, "raw" )?ZMS_RAW:mode;
|
||||
mode = !strcmp( value, "zip" )?ZMS_ZIP:mode;
|
||||
mode = !strcmp( value, "single" )?ZMS_SINGLE:mode;
|
||||
} else if ( !strcmp( name, "format" ) )
|
||||
} else if ( !strcmp( name, "format" ) ) {
|
||||
strncpy( format, value, sizeof(format) );
|
||||
else if ( !strcmp( name, "monitor" ) )
|
||||
} else if ( !strcmp( name, "monitor" ) ) {
|
||||
monitor_id = atoi( value );
|
||||
else if ( !strcmp( name, "time" ) )
|
||||
} else if ( !strcmp( name, "time" ) ) {
|
||||
event_time = atoi( value );
|
||||
else if ( !strcmp( name, "event" ) )
|
||||
} else if ( !strcmp( name, "event" ) ) {
|
||||
event_id = strtoull( value, (char **)NULL, 10 );
|
||||
else if ( !strcmp( name, "frame" ) )
|
||||
} else if ( !strcmp( name, "frame" ) ) {
|
||||
frame_id = strtoull( value, (char **)NULL, 10 );
|
||||
else if ( !strcmp( name, "scale" ) )
|
||||
} else if ( !strcmp( name, "scale" ) ) {
|
||||
scale = atoi( value );
|
||||
else if ( !strcmp( name, "rate" ) )
|
||||
} else if ( !strcmp( name, "rate" ) ) {
|
||||
rate = atoi( value );
|
||||
else if ( !strcmp( name, "maxfps" ) )
|
||||
} else if ( !strcmp( name, "maxfps" ) ) {
|
||||
maxfps = atof( value );
|
||||
else if ( !strcmp( name, "bitrate" ) )
|
||||
} else if ( !strcmp( name, "bitrate" ) ) {
|
||||
bitrate = atoi( value );
|
||||
else if ( !strcmp( name, "ttl" ) )
|
||||
} else if ( !strcmp( name, "ttl" ) ) {
|
||||
ttl = atoi(value);
|
||||
else if ( !strcmp( name, "replay" ) ) {
|
||||
} else if ( !strcmp( name, "replay" ) ) {
|
||||
replay = !strcmp( value, "gapless" )?EventStream::MODE_ALL_GAPLESS:EventStream::MODE_SINGLE;
|
||||
replay = !strcmp( value, "all" )?EventStream::MODE_ALL:replay;
|
||||
} else if ( !strcmp( name, "connkey" ) )
|
||||
} else if ( !strcmp( name, "connkey" ) ) {
|
||||
connkey = atoi(value);
|
||||
else if ( !strcmp( name, "buffer" ) )
|
||||
} else if ( !strcmp( name, "buffer" ) ) {
|
||||
playback_buffer = atoi(value);
|
||||
else if ( config.opt_use_auth ) {
|
||||
} else if ( config.opt_use_auth ) {
|
||||
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
|
||||
if ( !strcmp( name, "user" ) ) {
|
||||
username = UriDecode( value );
|
||||
username = value;
|
||||
}
|
||||
} else {
|
||||
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
|
||||
|
@ -162,7 +159,6 @@ int main( int argc, const char *argv[] )
|
|||
{
|
||||
if ( !strcmp( name, "user" ) ) {
|
||||
username = UriDecode( value );
|
||||
Debug( 1, "Have %s for username", username.c_str() );
|
||||
}
|
||||
if ( !strcmp( name, "pass" ) ) {
|
||||
password = UriDecode( value );
|
||||
|
@ -186,19 +182,15 @@ int main( int argc, const char *argv[] )
|
|||
{
|
||||
if ( *auth ) {
|
||||
user = zmLoadAuthUser( auth, config.auth_hash_ips );
|
||||
} else {
|
||||
Debug( 1, "Need both username and password" );
|
||||
}
|
||||
}
|
||||
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
|
||||
{
|
||||
if ( username.length() && password.length() ) {
|
||||
user = zmLoadUser( username.c_str(), password.c_str() );
|
||||
} else {
|
||||
Debug( 1, "Need both username and password" );
|
||||
}
|
||||
}
|
||||
} // auth is none or something else
|
||||
}
|
||||
if ( !user ) {
|
||||
Error( "Unable to authenticate user" );
|
||||
logTerm();
|
||||
|
@ -206,7 +198,7 @@ int main( int argc, const char *argv[] )
|
|||
return( -1 );
|
||||
}
|
||||
ValidateAccess( user, monitor_id );
|
||||
} // end if use_auth
|
||||
}
|
||||
|
||||
setbuf( stdout, 0 );
|
||||
if ( nph ) {
|
||||
|
|
|
@ -263,16 +263,15 @@ if [ $TYPE == "binary" ]; then
|
|||
if [[ $REPLY == [yY] ]]; then
|
||||
sudo dpkg -i $DIRECTORY*.deb
|
||||
fi;
|
||||
|
||||
read -p "Do you want to upload this binary to zmrepo? (y/N)"
|
||||
if [[ $REPLY == [yY] ]]; then
|
||||
if [ "$RELEASE" != "" ]; then
|
||||
scp "zoneminder_${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/"
|
||||
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/"
|
||||
else
|
||||
if [ "$BRANCH" == "" ]; then
|
||||
scp "zoneminder_${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/"
|
||||
scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/"
|
||||
else
|
||||
scp "$DIRECTORY-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
|
||||
scp "$DIRECTORY-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/"
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
|
|
|
@ -42,26 +42,27 @@ switch ( $_REQUEST['task'] )
|
|||
$servers_by_Id[$server->Id()] = $server;
|
||||
}
|
||||
|
||||
$minTime = isset($_POST['minTime'])?$_POST['minTime']:NULL;
|
||||
$maxTime = isset($_POST['maxTime'])?$_POST['maxTime']:NULL;
|
||||
$minTime = isset($_REQUEST['minTime'])?$_REQUEST['minTime']:NULL;
|
||||
$maxTime = isset($_REQUEST['maxTime'])?$_REQUEST['maxTime']:NULL;
|
||||
|
||||
$limit = 100;
|
||||
if ( isset($_POST['limit']) ) {
|
||||
if ( ( !is_integer( $_POST['limit'] ) and !ctype_digit($_POST['limit']) ) ) {
|
||||
Error("Invalid value for limit " . $_POST['limit'] );
|
||||
if ( isset($_REQUEST['limit']) ) {
|
||||
if ( ( !is_integer( $_REQUEST['limit'] ) and !ctype_digit($_REQUEST['limit']) ) ) {
|
||||
Error("Invalid value for limit " . $_REQUEST['limit'] );
|
||||
} else {
|
||||
$limit = $_POST['limit'];
|
||||
$limit = $_REQUEST['limit'];
|
||||
}
|
||||
}
|
||||
$sortField = 'TimeKey';
|
||||
if ( isset($_POST['sortField']) ) {
|
||||
if ( ! in_array( $_POST['sortField'], $filterFields ) and ( $_POST['sortField'] != 'TimeKey' ) ) {
|
||||
Error("Invalid sort field " . $_POST['sortField'] );
|
||||
if ( isset($_REQUEST['sortField']) ) {
|
||||
if ( ! in_array( $_REQUEST['sortField'], $filterFields ) and ( $_REQUEST['sortField'] != 'TimeKey' ) ) {
|
||||
Error("Invalid sort field " . $_REQUEST['sortField'] );
|
||||
} else {
|
||||
$sortField = $_POST['sortField'];
|
||||
$sortField = $_REQUEST['sortField'];
|
||||
}
|
||||
}
|
||||
$sortOrder = (isset($_POST['sortOrder']) and $_POST['sortOrder']) == 'asc' ? 'asc':'desc';
|
||||
$filter = isset($_POST['filter'])?$_POST['filter']:array();
|
||||
$sortOrder = (isset($_REQUEST['sortOrder']) and $_REQUEST['sortOrder']) == 'asc' ? 'asc':'desc';
|
||||
$filter = isset($_REQUEST['filter'])?$_REQUEST['filter']:array();
|
||||
|
||||
$total = dbFetchOne( 'SELECT count(*) AS Total FROM Logs', 'Total' );
|
||||
$sql = 'SELECT * FROM Logs';
|
||||
|
@ -95,6 +96,8 @@ switch ( $_REQUEST['task'] )
|
|||
foreach ( dbFetchAll( $sql, NULL, $values ) as $log ) {
|
||||
$log['DateTime'] = preg_replace( '/^\d+/', strftime( "%Y-%m-%d %H:%M:%S", intval($log['TimeKey']) ), $log['TimeKey'] );
|
||||
$log['Server'] = ( $log['ServerId'] and isset($servers_by_Id[$log['ServerId']]) ) ? $servers_by_Id[$log['ServerId']]->Name() : '';
|
||||
#$log['Message'] = preg_replace('/[\x00-\x1F\x7F]/u', '', $log['Message'] );
|
||||
$log['Message'] = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $log['Message'] );
|
||||
$logs[] = $log;
|
||||
}
|
||||
$options = array();
|
||||
|
|
|
@ -171,14 +171,13 @@ Warning("Addterm");
|
|||
} else if ( $action == 'eventdetail' ) {
|
||||
if ( !empty($_REQUEST['eid']) ) {
|
||||
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $_REQUEST['eid'] ) );
|
||||
$refreshParent = true;
|
||||
} else {
|
||||
foreach( getAffectedIds( 'markEid' ) as $markEid ) {
|
||||
dbQuery( 'UPDATE Events SET Cause=?, Notes=? WHERE Id=?', array( $_REQUEST['newEvent']['Cause'], $_REQUEST['newEvent']['Notes'], $markEid ) );
|
||||
}
|
||||
}
|
||||
$refreshParent = true;
|
||||
}
|
||||
$refreshParent = '/index.php?view=filter&Id='.$_REQUEST['Id'];
|
||||
}
|
||||
$closePopup = true;
|
||||
} elseif ( $action == 'archive' || $action == 'unarchive' ) {
|
||||
$archiveVal = ($action == 'archive')?1:0;
|
||||
if ( !empty($_REQUEST['eid']) ) {
|
||||
|
@ -186,14 +185,14 @@ Warning("Addterm");
|
|||
} else {
|
||||
foreach( getAffectedIds( 'markEid' ) as $markEid ) {
|
||||
dbQuery( 'UPDATE Events SET Archived=? WHERE Id=?', array( $archiveVal, $markEid ) );
|
||||
$refreshParent = true;
|
||||
}
|
||||
$refreshParent = true;
|
||||
}
|
||||
} elseif ( $action == 'delete' ) {
|
||||
foreach( getAffectedIds( 'markEid' ) as $markEid ) {
|
||||
deleteEvent( $markEid );
|
||||
$refreshParent = true;
|
||||
}
|
||||
$refreshParent = true;
|
||||
}
|
||||
} // end if canEdit(Events)
|
||||
} // end if filter or something else
|
||||
|
|
|
@ -1146,24 +1146,26 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
|
||||
$StorageArea = NULL;
|
||||
|
||||
if ( isset($filter['terms']) && count($filter['terms']) ) {
|
||||
for ( $i = 0; $i < count($filter['terms']); $i++ ) {
|
||||
if ( isset($filter['terms'][$i]['cnj']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[terms][$i][cnj]").'='.urlencode($filter['terms'][$i]['cnj']);
|
||||
$filter['sql'] .= ' '.$filter['terms'][$i]['cnj'].' ';
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cnj]\" value=\"".htmlspecialchars($filter['terms'][$i]['cnj'])."\"/>\n";
|
||||
$terms = $filter['Query']['terms'];
|
||||
|
||||
if ( isset($terms) && count($terms) ) {
|
||||
for ( $i = 0; $i < count($terms); $i++ ) {
|
||||
if ( isset($terms[$i]['cnj']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cnj]").'='.urlencode($terms[$i]['cnj']);
|
||||
$filter['sql'] .= ' '.$terms[$i]['cnj'].' ';
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][cnj]\" value=\"".htmlspecialchars($terms[$i]['cnj'])."\"/>\n";
|
||||
}
|
||||
if ( isset($filter['terms'][$i]['obr']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[terms][$i][obr]").'='.urlencode($filter['terms'][$i]['obr']);
|
||||
$filter['sql'] .= ' '.str_repeat( '(', $filter['terms'][$i]['obr'] ).' ';
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][obr]\" value=\"".htmlspecialchars($filter['terms'][$i]['obr'])."\"/>\n";
|
||||
if ( isset($terms[$i]['obr']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][obr]").'='.urlencode($terms[$i]['obr']);
|
||||
$filter['sql'] .= ' '.str_repeat( '(', $terms[$i]['obr'] ).' ';
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][obr]\" value=\"".htmlspecialchars($terms[$i]['obr'])."\"/>\n";
|
||||
}
|
||||
if ( isset($filter['terms'][$i]['attr']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[terms][$i][attr]").'='.urlencode($filter['terms'][$i]['attr']);
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][attr]\" value=\"".htmlspecialchars($filter['terms'][$i]['attr'])."\"/>\n";
|
||||
switch ( $filter['terms'][$i]['attr'] ) {
|
||||
if ( isset($terms[$i]['attr']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][attr]").'='.urlencode($terms[$i]['attr']);
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][attr]\" value=\"".htmlspecialchars($terms[$i]['attr'])."\"/>\n";
|
||||
switch ( $terms[$i]['attr'] ) {
|
||||
case 'MonitorName':
|
||||
$filter['sql'] .= 'M.'.preg_replace( '/^Monitor/', '', $filter['terms'][$i]['attr'] );
|
||||
$filter['sql'] .= 'M.'.preg_replace( '/^Monitor/', '', $terms[$i]['attr'] );
|
||||
break;
|
||||
case 'ServerId':
|
||||
$filter['sql'] .= 'M.ServerId';
|
||||
|
@ -1194,14 +1196,14 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
case 'Notes':
|
||||
case 'StateId':
|
||||
case 'Archived':
|
||||
$filter['sql'] .= 'E.'.$filter['terms'][$i]['attr'];
|
||||
$filter['sql'] .= 'E.'.$terms[$i]['attr'];
|
||||
break;
|
||||
case 'DiskPercent':
|
||||
// Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH
|
||||
if ( ! $StorageArea ) {
|
||||
for ( $j = 0; $j < count($filter['terms']); $j++ ) {
|
||||
if ( isset($filter['terms'][$j]['attr']) and $filter['terms'][$j]['attr'] == 'StorageId' ) {
|
||||
$StorageArea = new Storage( $filter['terms'][$j]['val'] );
|
||||
for ( $j = 0; $j < count($terms); $j++ ) {
|
||||
if ( isset($terms[$j]['attr']) and $terms[$j]['attr'] == 'StorageId' ) {
|
||||
$StorageArea = new Storage( $terms[$j]['val'] );
|
||||
}
|
||||
} // end foreach remaining term
|
||||
if ( ! $StorageArea ) $StorageArea = new Storage();
|
||||
|
@ -1212,9 +1214,9 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
case 'DiskBlocks':
|
||||
// Need to specify a storage area, so need to look through other terms looking for a storage area, else we default to ZM_EVENTS_PATH
|
||||
if ( ! $StorageArea ) {
|
||||
for ( $j = $i; $j < count($filter['terms']); $j++ ) {
|
||||
if ( isset($filter['terms'][$i]['attr']) and $filter['terms'][$i]['attr'] == 'StorageId' ) {
|
||||
$StorageArea = new Storage( $filter['terms'][$i]['val'] );
|
||||
for ( $j = $i; $j < count($terms); $j++ ) {
|
||||
if ( isset($terms[$i]['attr']) and $terms[$i]['attr'] == 'StorageId' ) {
|
||||
$StorageArea = new Storage( $terms[$i]['val'] );
|
||||
}
|
||||
} // end foreach remaining term
|
||||
} // end no StorageArea found yet
|
||||
|
@ -1225,8 +1227,8 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
break;
|
||||
}
|
||||
$valueList = array();
|
||||
foreach ( preg_split( '/["\'\s]*?,["\'\s]*?/', preg_replace( '/^["\']+?(.+)["\']+?$/', '$1', $filter['terms'][$i]['val'] ) ) as $value ) {
|
||||
switch ( $filter['terms'][$i]['attr'] ) {
|
||||
foreach ( preg_split( '/["\'\s]*?,["\'\s]*?/', preg_replace( '/^["\']+?(.+)["\']+?$/', '$1', $terms[$i]['val'] ) ) as $value ) {
|
||||
switch ( $terms[$i]['attr'] ) {
|
||||
case 'MonitorName':
|
||||
case 'Name':
|
||||
case 'Cause':
|
||||
|
@ -1260,14 +1262,14 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
$valueList[] = $value;
|
||||
}
|
||||
|
||||
switch ( $filter['terms'][$i]['op'] ) {
|
||||
switch ( $terms[$i]['op'] ) {
|
||||
case '=' :
|
||||
case '!=' :
|
||||
case '>=' :
|
||||
case '>' :
|
||||
case '<' :
|
||||
case '<=' :
|
||||
$filter['sql'] .= ' '.$filter['terms'][$i]['op'].' '. $value;
|
||||
$filter['sql'] .= ' '.$terms[$i]['op'].' '. $value;
|
||||
break;
|
||||
case '=~' :
|
||||
$filter['sql'] .= ' regexp '.$value;
|
||||
|
@ -1283,15 +1285,15 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
break;
|
||||
}
|
||||
|
||||
$filter['query'] .= $querySep.urlencode("filter[terms][$i][op]").'='.urlencode($filter['terms'][$i]['op']);
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][op]\" value=\"".htmlspecialchars($filter['terms'][$i]['op'])."\"/>\n";
|
||||
$filter['query'] .= $querySep.urlencode("filter[terms][$i][val]").'='.urlencode($filter['terms'][$i]['val']);
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][val]\" value=\"".htmlspecialchars($filter['terms'][$i]['val'])."\"/>\n";
|
||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']);
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][op]\" value=\"".htmlspecialchars($terms[$i]['op'])."\"/>\n";
|
||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][val]").'='.urlencode($terms[$i]['val']);
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][val]\" value=\"".htmlspecialchars($terms[$i]['val'])."\"/>\n";
|
||||
}
|
||||
if ( isset($filter['terms'][$i]['cbr']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[terms][$i][cbr]").'='.urlencode($filter['terms'][$i]['cbr']);
|
||||
$filter['sql'] .= ' '.str_repeat( ')', $filter['terms'][$i]['cbr'] ).' ';
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[terms][$i][cbr]\" value=\"".htmlspecialchars($filter['terms'][$i]['cbr'])."\"/>\n";
|
||||
if ( isset($terms[$i]['cbr']) ) {
|
||||
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][cbr]").'='.urlencode($terms[$i]['cbr']);
|
||||
$filter['sql'] .= ' '.str_repeat( ')', $terms[$i]['cbr'] ).' ';
|
||||
$filter['fields'] .= "<input type=\"hidden\" name=\"filter[Query][terms][$i][cbr]\" value=\"".htmlspecialchars($terms[$i]['cbr'])."\"/>\n";
|
||||
}
|
||||
}
|
||||
if ( $filter['sql'] )
|
||||
|
|
|
@ -28,7 +28,7 @@ if ( $debug ) {
|
|||
}
|
||||
|
||||
// Use new style autoglobals where possible
|
||||
if ( version_compare( phpversion(), "4.1.0", "<") ) {
|
||||
if ( version_compare( phpversion(), '4.1.0', '<') ) {
|
||||
$_SESSION = &$HTTP_SESSION_VARS;
|
||||
$_SERVER = &$HTTP_SERVER_VARS;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ if ( version_compare( phpversion(), "4.1.0", "<") ) {
|
|||
if ( false ) {
|
||||
ob_start();
|
||||
phpinfo( INFO_VARIABLES );
|
||||
$fp = fopen( "/tmp/env.html", "w" );
|
||||
$fp = fopen( '/tmp/env.html', 'w' );
|
||||
fwrite( $fp, ob_get_contents() );
|
||||
fclose( $fp );
|
||||
ob_end_clean();
|
||||
|
@ -114,10 +114,10 @@ $skinBase[] = $skin;
|
|||
$currentCookieParams = session_get_cookie_params();
|
||||
Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
|
||||
session_set_cookie_params(
|
||||
$currentCookieParams["lifetime"],
|
||||
$currentCookieParams["path"],
|
||||
$currentCookieParams["domain"],
|
||||
$currentCookieParams["secure"],
|
||||
$currentCookieParams['lifetime'],
|
||||
$currentCookieParams['path'],
|
||||
$currentCookieParams['domain'],
|
||||
$currentCookieParams['secure'],
|
||||
true
|
||||
);
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ var popupSizes = {
|
|||
'events': { 'width': 960, 'height': 780 },
|
||||
'export': { 'width': 400, 'height': 340 },
|
||||
'filter': { 'width': 820, 'height': 700 },
|
||||
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 100 },
|
||||
'frames': { 'width': 600, 'height': 600 },
|
||||
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
|
||||
'frames': { 'width': 600, 'height': 700 },
|
||||
'function': { 'width': 300, 'height': 92 },
|
||||
'group': { 'width': 360, 'height': 180 },
|
||||
'groups': { 'width': 440, 'height': 220 },
|
||||
|
|
|
@ -38,8 +38,8 @@ var popupSizes = {
|
|||
'events': { 'width': 960, 'height': 780 },
|
||||
'export': { 'width': 400, 'height': 340 },
|
||||
'filter': { 'width': 900, 'height': 700 },
|
||||
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 100 },
|
||||
'frames': { 'width': 600, 'height': 600 },
|
||||
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
|
||||
'frames': { 'width': 600, 'height': 700 },
|
||||
'function': { 'width': 300, 'height': 160 },
|
||||
'group': { 'width': 360, 'height': 300 },
|
||||
'groups': { 'width': 540, 'height': 420 },
|
||||
|
|
|
@ -38,7 +38,7 @@ var popupSizes = {
|
|||
'events': { 'width': 1220, 'height': 780 },
|
||||
'export': { 'width': 400, 'height': 340 },
|
||||
'filter': { 'width': 900, 'height': 700 },
|
||||
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 100 },
|
||||
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
|
||||
'frames': { 'width': 600, 'height': 600 },
|
||||
'function': { 'width': 300, 'height': 160 },
|
||||
'group': { 'width': 360, 'height': 300 },
|
||||
|
|
|
@ -253,6 +253,9 @@ if ( refreshParent ) {
|
|||
if ( focusWindow ) {
|
||||
windowToFront();
|
||||
}
|
||||
if ( closePopup ) {
|
||||
closeWindow();
|
||||
}
|
||||
|
||||
window.addEvent( 'domready', checkSize );
|
||||
|
||||
|
|
|
@ -49,6 +49,13 @@ if ( ! empty($refreshParent) ) {
|
|||
echo 'false';
|
||||
}
|
||||
?>;
|
||||
var closePopup = <?php
|
||||
if ( ( ! empty($closePopup) ) and ( $closePopup == true ) ) {
|
||||
echo 'true';
|
||||
} else {
|
||||
echo 'false';
|
||||
}
|
||||
?>;
|
||||
|
||||
var focusWindow = <?php echo !empty($focusWindow)?'true':'false' ?>;
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ $eventCounts = array(
|
|||
array(
|
||||
'title' => translate('Events'),
|
||||
'filter' => array(
|
||||
'terms' => array(
|
||||
'Query' => array (
|
||||
'terms' => array()
|
||||
)
|
||||
),
|
||||
'total' => 0,
|
||||
|
@ -37,45 +38,55 @@ $eventCounts = array(
|
|||
array(
|
||||
'title' => translate('Hour'),
|
||||
'filter' => array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 hour' ),
|
||||
)
|
||||
)
|
||||
),
|
||||
'total' => 0,
|
||||
),
|
||||
array(
|
||||
'title' => translate('Day'),
|
||||
'filter' => array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 day' ),
|
||||
)
|
||||
)
|
||||
),
|
||||
'total' => 0,
|
||||
),
|
||||
array(
|
||||
'title' => translate('Week'),
|
||||
'filter' => array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-7 day' ),
|
||||
)
|
||||
)
|
||||
),
|
||||
'total' => 0,
|
||||
),
|
||||
array(
|
||||
'title' => translate('Month'),
|
||||
'filter' => array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 month' ),
|
||||
)
|
||||
)
|
||||
),
|
||||
'total' => 0,
|
||||
),
|
||||
array(
|
||||
'title' => translate('Archived'),
|
||||
'filter' => array(
|
||||
'Query' => array(
|
||||
'terms' => array(
|
||||
array( 'attr' => "Archived", 'op' => '=', 'val' => '1' ),
|
||||
)
|
||||
)
|
||||
),
|
||||
'total' => 0,
|
||||
),
|
||||
|
@ -94,7 +105,7 @@ for( $i = 0; $i < count($displayMonitors); $i += 1 ) {
|
|||
$monitor['ZoneCount'] = dbFetchOne( 'select count(Id) as ZoneCount from Zones where MonitorId = ?', 'ZoneCount', array($monitor['Id']) );
|
||||
$counts = array();
|
||||
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
|
||||
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
|
||||
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
|
||||
parseFilter( $filter );
|
||||
$counts[] = "count(if(1".$filter['sql'].",1,NULL)) as EventCount$j";
|
||||
$monitor['eventCounts'][$j]['filter'] = $filter;
|
||||
|
|
|
@ -155,7 +155,7 @@ if ( $Event->DefaultVideo() ) {
|
|||
?>
|
||||
<div id="videoFeed">
|
||||
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $Event->Width(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
|
||||
<source src="<?php echo $Event->getStreamSrc( array( "mode=mpeg&format=h264" ) ); ?>" type="video/mp4">
|
||||
<source src="<?php echo $Event->getStreamSrc( array( 'mode'=>'mpeg','format'=>'h264' ) ); ?>" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
|
@ -170,6 +170,7 @@ if ( $Event->DefaultVideo() ) {
|
|||
<?php
|
||||
} // end if DefaultVideo
|
||||
?>
|
||||
</div><!--eventVideo-->
|
||||
<div id="imageFeed"<?php if ( $Event->DefaultVideo() ) { ?> class="hidden"<?php } ?>>
|
||||
<?php
|
||||
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
||||
|
@ -184,7 +185,6 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
|||
}
|
||||
} // end if stream method
|
||||
?>
|
||||
</div>
|
||||
<p id="dvrControls">
|
||||
<input type="button" value="<+" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" onclick="streamPrev( true );"/>
|
||||
<input type="button" value="<<" id="fastRevBtn" title="<?php echo translate('Rewind') ?>" class="inactive" disabled="disabled" onclick="streamFastRev( true );"/>
|
||||
|
@ -206,8 +206,8 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
|
|||
<?php for ( $i = 0; $i < $panelSections; $i++ ) { ?>
|
||||
<div class="progressBox" id="progressBox<?php echo $i ?>" title=""></div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--progressBar-->
|
||||
</div><!--imageFeed-->
|
||||
</div>
|
||||
<?php
|
||||
if ( $Event->SaveJPEGs() & 3 ) { // frames or analysis
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
|
||||
if ( !canEdit( 'Events' ) )
|
||||
{
|
||||
$view = "error";
|
||||
if ( !canEdit( 'Events' ) ) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
if ( isset($_REQUEST['eid']) ) {
|
||||
|
@ -38,30 +37,24 @@ if ( isset($_REQUEST['eid']) ) {
|
|||
}
|
||||
unset( $eid );
|
||||
$sql .= join( " or ", $sqlWhere );
|
||||
foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row )
|
||||
{
|
||||
if ( !isset($newEvent) )
|
||||
{
|
||||
foreach( dbFetchAll( $sql, NULL, $sqlValues ) as $row ) {
|
||||
if ( !isset($newEvent) ) {
|
||||
$newEvent = $row;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if ( $newEvent['Cause'] && $newEvent['Cause'] != $row['Cause'] )
|
||||
$newEvent['Cause'] = "";
|
||||
$newEvent['Cause'] = '';
|
||||
if ( $newEvent['Notes'] && $newEvent['Notes'] != $row['Notes'] )
|
||||
$newEvent['Notes'] = "";
|
||||
$newEvent['Notes'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$mode = '';
|
||||
}
|
||||
|
||||
$focusWindow = true;
|
||||
|
||||
if ( $mode == 'single' )
|
||||
xhtmlHeaders(__FILE__, translate('Event')." - ".$eid );
|
||||
xhtmlHeaders(__FILE__, translate('Event').' - '.$eid );
|
||||
else
|
||||
xhtmlHeaders(__FILE__, translate('Events') );
|
||||
?>
|
||||
|
@ -69,14 +62,11 @@ else
|
|||
<div id="page">
|
||||
<div id="header">
|
||||
<?php
|
||||
if ( $mode == 'single' )
|
||||
{
|
||||
if ( $mode == 'single' ) {
|
||||
?>
|
||||
<h2><?php echo translate('Event') ?> <?php echo $eid ?></h2>
|
||||
<?php
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
?>
|
||||
<h2><?php echo translate('Events') ?></h2>
|
||||
<?php
|
||||
|
@ -87,22 +77,18 @@ else
|
|||
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
|
||||
<input type="hidden" name="view" value="none"/>
|
||||
<?php
|
||||
if ( $mode == 'single' )
|
||||
{
|
||||
if ( $mode == 'single' ) {
|
||||
?>
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<input type="hidden" name="action" value="eventdetail"/>
|
||||
<input type="hidden" name="eid" value="<?php echo $eid ?>"/>
|
||||
<?php
|
||||
}
|
||||
elseif ( $mode = 'multi' )
|
||||
{
|
||||
} elseif ( $mode = 'multi' ) {
|
||||
?>
|
||||
<input type="hidden" name="view" value="none"/>
|
||||
<input type="hidden" name="action" value="eventdetail"/>
|
||||
<?php
|
||||
foreach ( $_REQUEST['eids'] as $eid )
|
||||
{
|
||||
foreach ( $_REQUEST['eids'] as $eid ) {
|
||||
?>
|
||||
<input type="hidden" name="markEids[]" value="<?php echo validHtmlStr($eid) ?>"/>
|
||||
<?php
|
||||
|
@ -122,7 +108,8 @@ elseif ( $mode = 'multi' )
|
|||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/><input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
|
||||
<input type="submit" value="<?php echo translate('Save') ?>"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/>
|
||||
<input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -214,7 +214,7 @@ foreach ( $events as $event ) {
|
|||
<td class="colThumbnail">
|
||||
<?php
|
||||
$imgSrc = '?view=image&eid='.$event->Id().'&fid='.$thumbData['FrameId'].'&width='.$thumbData['Width'].'&height='.$thumbData['Height'];
|
||||
$streamSrc = getStreamSrc( array( "source=event", "mode=jpeg", "event=".$event->Id(), "scale=".$scale, "maxfps=".ZM_WEB_VIDEO_MAXFPS, "replay=single") );
|
||||
$streamSrc = $event->getStreamSrc( array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single') );
|
||||
|
||||
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt( $thumbData['Height'] ).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ var logCodes = new Object({
|
|||
'-4': 'PNC',
|
||||
});
|
||||
|
||||
var minSampleTime = 1000;
|
||||
var minSampleTime = 2000;
|
||||
var maxSampleTime = 16000;
|
||||
var minLogTime = 0;
|
||||
var maxLogTime = 0;
|
||||
|
@ -56,11 +56,12 @@ function logResponse( respObj ) {
|
|||
try {
|
||||
respObj.logs.each(
|
||||
function( log ) {
|
||||
if ( !maxLogTime || log.TimeKey > maxLogTime )
|
||||
if ( ( !maxLogTime ) || ( log.TimeKey > maxLogTime ) )
|
||||
maxLogTime = log.TimeKey;
|
||||
if ( !minLogTime || log.TimeKey < minLogTime )
|
||||
if ( ( !minLogTime ) || ( log.TimeKey < minLogTime ) )
|
||||
minLogTime = log.TimeKey;
|
||||
var row = logTable.push( [{ content: log.DateTime, properties: { style: 'white-space: nowrap' }}, log.Component, log.Server, log.Pid, log.Code, log.Message, log.File, log.Line] );
|
||||
|
||||
delete log.Message;
|
||||
row.tr.store( 'log', log );
|
||||
if ( log.Level <= -3 )
|
||||
|
@ -106,8 +107,8 @@ function logResponse( respObj ) {
|
|||
logTimeout *= 2;
|
||||
if ( logTimeout > maxSampleTime )
|
||||
logTimeout = maxSampleTime;
|
||||
}
|
||||
}
|
||||
} // end logs.length > 0
|
||||
} // end if result == Ok
|
||||
logTimer = fetchNextLogs.delay( logTimeout );
|
||||
}
|
||||
|
||||
|
|
|
@ -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; i<eId.length; i++) // Display all we loaded
|
||||
{
|
||||
var x1=parseInt( (eStartSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth) ; // round low end down
|
||||
var x2=parseInt( (eEndSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ) ; // round high end up to be sure consecutive ones connect
|
||||
ctx.fillStyle=monitorColour[eMonId[i]];
|
||||
ctx.globalAlpha = 0.2; // light color for background
|
||||
ctx.clearRect(x1,monitorIndex[eMonId[i]]*rowHeight,x2-x1,rowHeight); // Erase any overlap so it doesn't look artificially darker
|
||||
ctx.fillRect (x1,monitorIndex[eMonId[i]]*rowHeight,x2-x1,rowHeight);
|
||||
}
|
||||
for(var i=0; (i<fScore.length) && (maxScore>0); 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<numMonitors; i++) // Note that this may be a sparse array
|
||||
{
|
||||
ctx.font= parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
|
||||
ctx.fillStyle="Black";
|
||||
ctx.globalAlpha=1;
|
||||
ctx.fillText(monitorName[monitorPtr[i]], 0, (i + 1 - (1 - timeLabelsFractOfRow)/2 ) * rowHeight ); // This should roughly center font in row
|
||||
}
|
||||
underSlider=undefined; // flag we don't have a slider cached
|
||||
drawSliderOnGraph(currentTimeSecs);
|
||||
return;
|
||||
}
|
||||
|
||||
function redrawScreen()
|
||||
{
|
||||
if(fitMode==0) // if we fit, then monitors were absolutely positioned already (or will be) otherwise release them to float
|
||||
{
|
||||
for(var i=0; i<numMonitors; i++)
|
||||
monitorCanvasObj[monitorPtr[i]].style.position="";
|
||||
$('monitors').setStyle('height',"auto");
|
||||
}
|
||||
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
|
||||
{
|
||||
$('SpeedDiv').style.display="none";
|
||||
$('timelinediv').style.display="none";
|
||||
$('live').innerHTML="History";
|
||||
$('zoomin').style.display="none";
|
||||
$('zoomout').style.display="none";
|
||||
$('panleft').style.display="none";
|
||||
$('panright').style.display="none";
|
||||
|
||||
}
|
||||
else // switch out of liveview mode
|
||||
{
|
||||
$('SpeedDiv').style.display="inline";
|
||||
$('SpeedDiv').style.display="inline-flex";
|
||||
$('timelinediv').style.display=null;
|
||||
$('live').innerHTML="Live";
|
||||
$('zoomin').style.display="inline";
|
||||
$('zoomin').style.display="inline-flex";
|
||||
$('zoomout').style.display="inline";
|
||||
$('zoomout').style.display="inline-flex";
|
||||
$('panleft').style.display="inline";
|
||||
$('panleft').style.display="inline-flex";
|
||||
$('panright').style.display="inline";
|
||||
$('panright').style.display="inline-flex";
|
||||
}
|
||||
|
||||
if(fitMode==1)
|
||||
{
|
||||
$('ScaleDiv').style.display="none";
|
||||
$('fit').innerHTML="Scale";
|
||||
var vh=window.innerHeight;
|
||||
var vw=window.innerWidth;
|
||||
var pos=$('monitors').getPosition();
|
||||
var mh=(vh - pos.y - $('fps').getSize().y);
|
||||
$('monitors').setStyle('height',mh.toString() + "px"); // leave a small gap at bottom
|
||||
if(maxfit2($('monitors').getSize().x,$('monitors').getSize().y) == 0) /// if we fail to fix we back out of fit mode -- ??? This may need some better handling
|
||||
fitMode=1-fitMode;
|
||||
}
|
||||
else // switch out of fit mode
|
||||
{
|
||||
$('ScaleDiv').style.display="inline";
|
||||
$('ScaleDiv').style.display="inline-flex";
|
||||
$('fit').innerHTML="Fit";
|
||||
setScale(currentScale);
|
||||
}
|
||||
drawGraph();
|
||||
outputUpdate(currentTimeSecs);
|
||||
timerFire(); // force a fire in case it's not timing
|
||||
}
|
||||
|
||||
|
||||
function outputUpdate(val)
|
||||
{
|
||||
drawSliderOnGraph(val);
|
||||
for(var i=0; i<numMonitors; i++)
|
||||
{
|
||||
loadImage2Monitor(monitorPtr[i],SetImageSource(monitorPtr[i],val));
|
||||
}
|
||||
var currentTimeMS = new Date(val*1000);
|
||||
currentTimeSecs=val;
|
||||
}
|
||||
|
||||
|
||||
/// Found this here: http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element
|
||||
function relMouseCoords(event){
|
||||
var totalOffsetX = 0;
|
||||
var totalOffsetY = 0;
|
||||
var canvasX = 0;
|
||||
var canvasY = 0;
|
||||
var currentElement = this;
|
||||
|
||||
do{
|
||||
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
|
||||
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
|
||||
}
|
||||
while(currentElement = currentElement.offsetParent)
|
||||
|
||||
canvasX = event.pageX - totalOffsetX;
|
||||
canvasY = event.pageY - totalOffsetY;
|
||||
|
||||
return {x:canvasX, y:canvasY}
|
||||
}
|
||||
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
|
||||
|
||||
// These are the functions for mouse movement in the timeline. Note that touch is treated as a mouse move with mouse down
|
||||
|
||||
var mouseisdown=false;
|
||||
function mdown(event) {mouseisdown=true; mmove(event);}
|
||||
function mup(event) {mouseisdown=false;}
|
||||
function mout(event) {mouseisdown=false;} // if we go outside treat it as release
|
||||
function tmove(event) {mouseisdown=true; mmove(event);}
|
||||
|
||||
function mmove(event) {
|
||||
if(mouseisdown) {
|
||||
// only do anything if the mouse is depressed while on the sheet
|
||||
var sec = minTimeSecs + rangeTimeSecs / event.target.width * event.target.relMouseCoords(event).x;
|
||||
outputUpdate(sec);
|
||||
}
|
||||
}
|
||||
|
||||
function secs2dbstr (s)
|
||||
{
|
||||
var st = (new Date(s * 1000)).format("%Y-%m-%d %H:%M:%S");
|
||||
return st;
|
||||
}
|
||||
|
||||
function setFit(value)
|
||||
{
|
||||
fitMode=value;
|
||||
redrawScreen();
|
||||
}
|
||||
|
||||
function showScale(newscale) // updates slider only
|
||||
{
|
||||
$('scaleslideroutput').innerHTML = parseFloat(newscale).toFixed(2).toString() + " x";
|
||||
return;
|
||||
}
|
||||
|
||||
function setScale(newscale) // makes actual change
|
||||
{
|
||||
showScale(newscale);
|
||||
for(var i=0; i<numMonitors; i++)
|
||||
{
|
||||
monitorCanvasObj[monitorPtr[i]].width=monitorWidth[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
|
||||
monitorCanvasObj[monitorPtr[i]].height=monitorHeight[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
|
||||
}
|
||||
currentScale=newscale;
|
||||
}
|
||||
|
||||
function showSpeed(val) // updates slider only
|
||||
{
|
||||
$('speedslideroutput').innerHTML = parseFloat(speeds[val]).toFixed(2).toString() + " x";
|
||||
}
|
||||
|
||||
function setSpeed(val) // Note parameter is the index not the speed
|
||||
{
|
||||
var t;
|
||||
if(liveMode==1) return; // we shouldn't actually get here but just in case
|
||||
currentSpeed=parseFloat(speeds[val]);
|
||||
speedIndex=val;
|
||||
playSecsperInterval = currentSpeed * currentDisplayInterval / 1000;
|
||||
showSpeed(val);
|
||||
if( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
|
||||
}
|
||||
|
||||
function setLive(value)
|
||||
{
|
||||
liveMode=value;
|
||||
redrawScreen();
|
||||
}
|
||||
|
||||
|
||||
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
// The section below are to reload this program with new parameters
|
||||
|
||||
function clicknav(minSecs,maxSecs,arch,live) {// we use the current time if we can
|
||||
var now = new Date() / 1000;
|
||||
var minStr="";
|
||||
var maxStr="";
|
||||
var currentStr="";
|
||||
if ( minSecs > 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]<fitY || ( thisY[adjacent] == fitY && thisX2[adjacent]+1 < fitX ) ) {
|
||||
fitX = thisX2[adjacent] + 1;
|
||||
fitY = thisY[adjacent];
|
||||
}
|
||||
}
|
||||
// try bottom left
|
||||
if ( doesItFit(thisX[adjacent], thisY2[adjacent]+1, monitorWidth[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, monitorHeight[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, m-1) == 1 ) {
|
||||
if ( thisY2[adjacent]+1 < fitY || ( thisY2[adjacent]+1 == fitY && thisX[adjacent] < fitX ) ) {
|
||||
fitX = thisX[adjacent];
|
||||
fitY = thisY2[adjacent] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( m == 0 ) { // note for the very first one there were no adjacents so the above loop didn't run
|
||||
if ( doesItFit(0,0,monitorWidth[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, monitorHeight[monId] * thisScale * monitorNormalizeScale[monId] * monitorZoomScale[monId] + borders, -1) == 1 ) {
|
||||
fitX = 0;
|
||||
fitY = 0;
|
||||
}
|
||||
}
|
||||
if ( fitX == 999999999 ) {
|
||||
allFit = 0;
|
||||
break; // break out of monitor loop flagging we didn't fit
|
||||
}
|
||||
thisX[m] =fitX;
|
||||
thisX2[m]=fitX + monitorWidth[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders;
|
||||
thisY[m] =fitY;
|
||||
thisY2[m]=fitY + monitorHeight[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders;
|
||||
thisArea += (thisX2[m] - thisX[m])*(thisY2[m] - thisY[m]);
|
||||
}
|
||||
if ( allFit == 1 ) {
|
||||
minScale=thisScale;
|
||||
if(bestFitArea<thisArea) {
|
||||
bestFitArea=thisArea;
|
||||
bestFitX=thisX;
|
||||
bestFitY=thisY;
|
||||
bestFitX2=thisX2;
|
||||
bestFitY2=thisY2;
|
||||
bestFitScale=thisScale;
|
||||
}
|
||||
} else {
|
||||
// didn't fit
|
||||
maxScale=thisScale;
|
||||
}
|
||||
}
|
||||
if ( bestFitArea > 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<len; i++ ) {
|
||||
if ( eMonId[i] == monId && currentTimeSecs >= 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 );
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
var currentScale=<?php echo $defaultScale?>;
|
||||
var liveMode=<?php echo $initialModeIsLive?>;
|
||||
console.log("Live mode?"+liveMode);
|
||||
var fitMode=<?php echo $fitMode?>;
|
||||
var currentSpeed=<?php echo $speeds[$speedIndex]?>; // slider scale, which is only for replay and relative to real time
|
||||
var speedIndex=<?php echo $speedIndex?>;
|
||||
var currentDisplayInterval=<?php echo $initialDisplayInterval?>; // 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=<?php if($group=="") echo '""'; else echo "\"&group=$group\""; ?>;
|
||||
|
||||
<?php
|
||||
|
||||
// Because we might not have time as the criteria, figure out the min/max time when we run the query
|
||||
|
||||
$minTimeSecs = strtotime('2036-01-01 01:01:01');
|
||||
$maxTimeSecs = strtotime('1950-01-01 01:01:01');
|
||||
|
||||
// This builds the list of events that are eligible from this range
|
||||
|
||||
$index=0;
|
||||
$anyAlarms=false;
|
||||
|
||||
foreach( dbFetchAll( $eventsSql ) as $event ) {
|
||||
if ( $minTimeSecs > $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; $i<count($speeds); $i++)
|
||||
echo (($i>0)?', ':'') . $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)
|
||||
|
|
@ -31,7 +31,7 @@ function changeScale() {
|
|||
Cookie.write( 'zmWatchScale'+monitorId, scale, { duration: 10*365 } );
|
||||
|
||||
/*Stream could be an applet so can't use moo tools*/
|
||||
var streamImg = document.getElementById('liveStream'+monitorId);
|
||||
var streamImg = $('#liveStream'+monitorId);
|
||||
if ( streamImg ) {
|
||||
streamImg.style.width = newWidth + "px";
|
||||
streamImg.style.height = newHeight + "px";
|
||||
|
@ -187,14 +187,14 @@ function getStreamCmdResponse( respObj, respText ) {
|
|||
if ( streamStatus.auth ) {
|
||||
console.log("Haev a new auth hash" + streamStatus.auth);
|
||||
// Try to reload the image stream.
|
||||
var streamImg = document.getElementById('liveStream');
|
||||
var streamImg = $('liveStream');
|
||||
if ( streamImg )
|
||||
streamImg.src = streamImg.src.replace( /auth=\w+/i, 'auth='+streamStatus.auth );
|
||||
} // end if haev a new auth hash
|
||||
} else {
|
||||
checkStreamForErrors("getStreamCmdResponse",respObj);//log them
|
||||
// Try to reload the image stream.
|
||||
var streamImg = document.getElementById('liveStream'+monitorId);
|
||||
var streamImg = $('liveStream'+monitorId);
|
||||
if ( streamImg ) {
|
||||
streamImg.src = streamImg.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) ));
|
||||
console.log("Changing lviestream src to " + streamImg.src);
|
||||
|
|
|
@ -41,6 +41,7 @@ if ( isset( $_REQUEST['showZones'] ) ) {
|
|||
}
|
||||
}
|
||||
$monitors = array();
|
||||
<<<<<<< HEAD
|
||||
$widths = array(
|
||||
'' => 'auto',
|
||||
160 => 160,
|
||||
|
@ -63,8 +64,10 @@ if ( isset( $_REQUEST['scale'] ) ) {
|
|||
} else if ( isset( $_COOKIE['zmMontageScale'] ) ) {
|
||||
$scale = $_COOKIE['zmMontageScale'];
|
||||
Logger::Debug("Setting scale from cookie to $scale");
|
||||
} else {
|
||||
Logger::Debug("scale is $scale");
|
||||
}
|
||||
|
||||
if ( ! $scale )
|
||||
$scale = 100;
|
||||
}
|
||||
|
||||
foreach( dbFetchAll( $sql ) as $row ) {
|
||||
|
|
|
@ -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 {
|
|||
<span id="scrubright"></span>
|
||||
<span id="scruboutput"></span>
|
||||
</div>
|
||||
<div id="monitors">
|
||||
<?php
|
||||
// Monitor images - these had to be loaded after the monitors used were determined (after loading events)
|
||||
|
||||
echo '<div id="monitors">';
|
||||
foreach ($monitors as $m) {
|
||||
echo '<canvas width="' . $m['Width'] * $defaultScale . 'px" height="' . $m['Height'] * $defaultScale . 'px" id="Monitor' . $m['Id'] . '" style="border:3px solid ' . $m['WebColour'] . '" onclick="clickMonitor(event,' . $m['Id'] . ')">No Canvas Support!!</canvas>';
|
||||
echo '<canvas width="' . $m->Width() * $defaultScale . 'px" height="' . $m->Height() * $defaultScale . 'px" id="Monitor' . $m->Id() . '" style="border:3px solid ' . $m->WebColour() . '" onclick="clickMonitor(event,' . $m->Id() . ')">No Canvas Support!!</canvas>';
|
||||
}
|
||||
echo "</div>\n";
|
||||
echo "<p id=\"fps\">evaluating fps</p>\n";
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
?>
|
||||
|
||||
var currentScale=<?php echo $defaultScale?>;
|
||||
var liveMode=<?php echo $initialModeIsLive?>;
|
||||
var fitMode=<?php echo $fitMode?>;
|
||||
var currentSpeed=<?php echo $speeds[$speedIndex]?>; // slider scale, which is only for replay and relative to real time
|
||||
var speedIndex=<?php echo $speedIndex?>;
|
||||
var currentDisplayInterval=<?php echo $initialDisplayInterval?>; // 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 ePath = [];
|
||||
var eventFrames = []; // this is going to presume all frames equal durationlength
|
||||
|
||||
<?php
|
||||
|
||||
// Because we might not have time as the criteria, figure out the min/max time when we run the query
|
||||
|
||||
$minTimeSecs = strtotime("2036-01-01 01:01:01");
|
||||
$maxTimeSecs = strtotime("1950-01-01 01:01:01");
|
||||
|
||||
// This builds the list of events that are eligible from this range
|
||||
|
||||
$index=0;
|
||||
$anyAlarms=false;
|
||||
|
||||
foreach( dbFetchAll( $eventsSql ) as $event ) {
|
||||
if( $minTimeSecs > $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'] . "; ";
|
||||
|
||||
// NO GOOD, need to use view=image
|
||||
if ( ZM_USE_DEEP_STORAGE )
|
||||
echo "ePath[$index] = \"events/" . $event['MonitorId'] . "/" . strftime("%y/%m/%d/%H/%M/%S", $event['StartTimeSecs']) . "/\";" ;
|
||||
else
|
||||
echo "ePath[$index] = \"events/" . $event['MonitorId'] . "/" . $event['Id'] . "/\";" ;
|
||||
$index = $index + 1;
|
||||
if($event['MaxScore']>0)
|
||||
$anyAlarms = true;
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
// 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=strtotime('2020-06-02 02:02:02');
|
||||
}
|
||||
}
|
||||
|
||||
// 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 . ";";
|
||||
echo " fTimeFromSecs[$index]=" . $fromSecs . ";";
|
||||
echo " fTimeToSecs[$index]=" . $toSecs . ";";
|
||||
echo " fScore[$index]=" . $maxScore . ";\n";
|
||||
$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 . ";";
|
||||
echo " fTimeFromSecs[$index]=" . $fromSecs . ";";
|
||||
echo " fTimeToSecs[$index]=" . $toSecs . ";";
|
||||
echo " fScore[$index]=" . $maxScore . ";\n";
|
||||
}
|
||||
|
||||
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 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; ";
|
||||
echo " monitorImageObject[" . $m['Id'] . "]=null; ";
|
||||
echo " monitorLoadingStageURL[" . $m['Id'] . "] = ''; ";
|
||||
echo " monitorColour[" . $m['Id'] . "]=\"" . $m['WebColour'] . "\"; ";
|
||||
echo " monitorWidth[" . $m['Id'] . "]=" . $m['Width'] . "; ";
|
||||
echo " monitorHeight[" . $m['Id'] . "]=" . $m['Height'] . "; ";
|
||||
echo " monitorIndex[" . $m['Id'] . "]=" . $numMonitors . "; ";
|
||||
echo " monitorName[" . $m['Id'] . "]=\"" . $m['Name'] . "\"; ";
|
||||
echo " monitorLoadStartTimems[" . $m['Id'] . "]=0; ";
|
||||
echo " monitorLoadEndTimems[" . $m['Id'] . "]=0; ";
|
||||
echo " monitorCanvasObj[" . $m['Id'] . "]=document.getElementById('Monitor" . $m['Id'] . "'); ";
|
||||
echo " monitorCanvasCtx[" . $m['Id'] . "]=monitorCanvasObj[" . $m['Id'] . "].getContext('2d'); ";
|
||||
echo " monitorNormalizeScale[" . $m['Id'] . "]=" . sqrt($avgArea / ($m['Width'] * $m['Height'] )) . "; ";
|
||||
$zoomScale=1.0;
|
||||
if(isset($_REQUEST[ 'z' . $m['Id'] ]) )
|
||||
$zoomScale = floatval( validHtmlStr($_REQUEST[ 'z' . $m['Id'] ]) );
|
||||
echo " monitorZoomScale[" . $m['Id'] . "]=" . $zoomScale . ";";
|
||||
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; $i<count($speeds); $i++)
|
||||
echo (($i>0)?", ":"") . $speeds[$i];
|
||||
echo "];\n";
|
||||
?>
|
||||
|
||||
var scrubAsObject=document.getElementById('scrub');
|
||||
var cWidth; // save canvas width
|
||||
var cHeight; // save canvas height
|
||||
var canvas=document.getElementById("timeline"); // global canvas definition so we don't have to keep looking it up
|
||||
var ctx=canvas.getContext('2d');
|
||||
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)
|
||||
|
||||
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++) {
|
||||
monitorLoadStartTimems[monitorPtr[i]]=0;
|
||||
monitorLoadEndTimems[monitorPtr[i]]=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) {
|
||||
// This uses the standard php routine to set up the url and authentication, but because it is called repeatedly the built in random number is not usable, so one is appended below for two total (yuck)
|
||||
var effectiveScale = (100.0 * monitorCanvasObj[monId].width) / monitorWidth[monId];
|
||||
var $x = "<?php echo getStreamSrc( array("mode=single"),"&" )?>" + "&monitor=" + monId.toString() + "&scale=" + effectiveScale + Math.random().toString() ;
|
||||
return $x;
|
||||
} else {
|
||||
var zeropad = <?php echo sprintf("\"%0" . ZM_EVENT_IMAGE_DIGITS . "d\"",0); ?>;
|
||||
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;
|
||||
img = "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height;
|
||||
return img;
|
||||
}
|
||||
} // end for
|
||||
return "no data";
|
||||
}
|
||||
}
|
||||
|
||||
function imagedone(obj, monId, success) {
|
||||
if(success) {
|
||||
monitorCanvasCtx[monId].drawImage( monitorImageObject[monId], 0, 0, monitorCanvasObj[monId].width, monitorCanvasObj[monId].height);
|
||||
var iconSize=(Math.max(monitorCanvasObj[monId].width,monitorCanvasObj[monId].height) * 0.10);
|
||||
monitorCanvasCtx[monId].font = "600 " + iconSize.toString() + "px Arial";
|
||||
monitorCanvasCtx[monId].fillStyle="white";
|
||||
monitorCanvasCtx[monId].globalCompositeOperation="difference";
|
||||
monitorCanvasCtx[monId].fillText("+",iconSize*0.2, iconSize*1.2);
|
||||
monitorCanvasCtx[monId].fillText("-",monitorCanvasObj[monId].width - iconSize*1.2, iconSize*1.2);
|
||||
monitorCanvasCtx[monId].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.
|
||||
} else {
|
||||
if(monitorLoadingStageURL[monId]=="") return;
|
||||
loadImage2Monitor(monId,monitorLoadingStageURL[monId]);
|
||||
monitorLoadingStageURL[monId]="";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
var skipthis=0;
|
||||
if( typeof monitorImageObject[monId] !== "undefined" && monitorImageObject[monId] != null && monitorImageObject[monId].src == url ) return; // do nothing if it's the same
|
||||
if( monitorImageObject[monId] == null ) {
|
||||
monitorImageObject[monId]=new Image();
|
||||
monitorImageObject[monId].onload = function() {imagedone(this, monId,true )};
|
||||
monitorImageObject[monId].onerror = function() {imagedone(this, monId,false)};
|
||||
}
|
||||
if(url=='no data') {
|
||||
monitorCanvasCtx[monId].fillStyle="white";
|
||||
monitorCanvasCtx[monId].fillRect(0,0,monitorCanvasObj[monId].width,monitorCanvasObj[monId].height);
|
||||
var textSize=monitorCanvasObj[monId].width * 0.15;
|
||||
var text="No Data";
|
||||
monitorCanvasCtx[monId].font = "600 " + textSize.toString() + "px Arial";
|
||||
monitorCanvasCtx[monId].fillStyle="black";
|
||||
var textWidth = monitorCanvasCtx[monId].measureText(text).width;
|
||||
monitorCanvasCtx[monId].fillText(text,monitorCanvasObj[monId].width/2 - textWidth/2,monitorCanvasObj[monId].height/2);
|
||||
} 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; i<eId.length; i++) // Display all we loaded
|
||||
{
|
||||
var x1=parseInt( (eStartSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth) ; // round low end down
|
||||
var x2=parseInt( (eEndSecs[i] - minTimeSecs) / rangeTimeSecs * cWidth + 0.5 ) ; // round high end up to be sure consecutive ones connect
|
||||
ctx.fillStyle=monitorColour[eMonId[i]];
|
||||
ctx.globalAlpha = 0.2; // light color for background
|
||||
ctx.clearRect(x1,monitorIndex[eMonId[i]]*rowHeight,x2-x1,rowHeight); // Erase any overlap so it doesn't look artificially darker
|
||||
ctx.fillRect (x1,monitorIndex[eMonId[i]]*rowHeight,x2-x1,rowHeight);
|
||||
}
|
||||
for(var i=0; (i<fScore.length) && (maxScore>0); 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<numMonitors; i++) // Note that this may be a sparse array
|
||||
{
|
||||
ctx.font= parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
|
||||
ctx.fillStyle="Black";
|
||||
ctx.globalAlpha=1;
|
||||
ctx.fillText(monitorName[monitorPtr[i]], 0, (i + 1 - (1 - timeLabelsFractOfRow)/2 ) * rowHeight ); // This should roughly center font in row
|
||||
}
|
||||
underSlider=undefined; // flag we don't have a slider cached
|
||||
drawSliderOnGraph(currentTimeSecs);
|
||||
return;
|
||||
}
|
||||
|
||||
function redrawScreen()
|
||||
{
|
||||
if(fitMode==0) // if we fit, then monitors were absolutely positioned already (or will be) otherwise release them to float
|
||||
{
|
||||
for(var i=0; i<numMonitors; i++)
|
||||
monitorCanvasObj[monitorPtr[i]].style.position="";
|
||||
$('monitors').setStyle('height',"auto");
|
||||
}
|
||||
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
|
||||
{
|
||||
$('SpeedDiv').style.display="none";
|
||||
$('timelinediv').style.display="none";
|
||||
$('live').innerHTML="History";
|
||||
$('zoomin').style.display="none";
|
||||
$('zoomout').style.display="none";
|
||||
$('panleft').style.display="none";
|
||||
$('panright').style.display="none";
|
||||
|
||||
}
|
||||
else // switch out of liveview mode
|
||||
{
|
||||
$('SpeedDiv').style.display="inline";
|
||||
$('SpeedDiv').style.display="inline-flex";
|
||||
$('timelinediv').style.display=null;
|
||||
$('live').innerHTML="Live";
|
||||
$('zoomin').style.display="inline";
|
||||
$('zoomin').style.display="inline-flex";
|
||||
$('zoomout').style.display="inline";
|
||||
$('zoomout').style.display="inline-flex";
|
||||
$('panleft').style.display="inline";
|
||||
$('panleft').style.display="inline-flex";
|
||||
$('panright').style.display="inline";
|
||||
$('panright').style.display="inline-flex";
|
||||
}
|
||||
|
||||
if(fitMode==1)
|
||||
{
|
||||
$('ScaleDiv').style.display="none";
|
||||
$('fit').innerHTML="Scale";
|
||||
var vh=window.innerHeight;
|
||||
var vw=window.innerWidth;
|
||||
var pos=$('monitors').getPosition();
|
||||
var mh=(vh - pos.y - $('fps').getSize().y);
|
||||
$('monitors').setStyle('height',mh.toString() + "px"); // leave a small gap at bottom
|
||||
if(maxfit2($('monitors').getSize().x,$('monitors').getSize().y) == 0) /// if we fail to fix we back out of fit mode -- ??? This may need some better handling
|
||||
fitMode=1-fitMode;
|
||||
}
|
||||
else // switch out of fit mode
|
||||
{
|
||||
$('ScaleDiv').style.display="inline";
|
||||
$('ScaleDiv').style.display="inline-flex";
|
||||
$('fit').innerHTML="Fit";
|
||||
setScale(currentScale);
|
||||
}
|
||||
drawGraph();
|
||||
outputUpdate(currentTimeSecs);
|
||||
timerFire(); // force a fire in case it's not timing
|
||||
}
|
||||
|
||||
|
||||
function outputUpdate(val)
|
||||
{
|
||||
drawSliderOnGraph(val);
|
||||
for(var i=0; i<numMonitors; i++)
|
||||
{
|
||||
loadImage2Monitor(monitorPtr[i],SetImageSource(monitorPtr[i],val));
|
||||
}
|
||||
var currentTimeMS = new Date(val*1000);
|
||||
currentTimeSecs=val;
|
||||
}
|
||||
|
||||
|
||||
/// Found this here: http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element
|
||||
function relMouseCoords(event){
|
||||
var totalOffsetX = 0;
|
||||
var totalOffsetY = 0;
|
||||
var canvasX = 0;
|
||||
var canvasY = 0;
|
||||
var currentElement = this;
|
||||
|
||||
do{
|
||||
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
|
||||
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
|
||||
}
|
||||
while(currentElement = currentElement.offsetParent)
|
||||
|
||||
canvasX = event.pageX - totalOffsetX;
|
||||
canvasY = event.pageY - totalOffsetY;
|
||||
|
||||
return {x:canvasX, y:canvasY}
|
||||
}
|
||||
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
|
||||
|
||||
// These are the functions for mouse movement in the timeline. Note that touch is treated as a mouse move with mouse down
|
||||
|
||||
var mouseisdown=false;
|
||||
function mdown(event) {mouseisdown=true; mmove(event);}
|
||||
function mup(event) {mouseisdown=false;}
|
||||
function mout(event) {mouseisdown=false;} // if we go outside treat it as release
|
||||
function tmove(event) {mouseisdown=true; mmove(event);}
|
||||
|
||||
function mmove(event) {
|
||||
if(mouseisdown) {
|
||||
// only do anything if the mouse is depressed while on the sheet
|
||||
var sec = minTimeSecs + rangeTimeSecs / event.target.width * event.target.relMouseCoords(event).x;
|
||||
outputUpdate(sec);
|
||||
}
|
||||
}
|
||||
|
||||
function secs2dbstr (s)
|
||||
{
|
||||
var st = (new Date(s * 1000)).format("%Y-%m-%d %H:%M:%S");
|
||||
return st;
|
||||
}
|
||||
|
||||
function setFit(value)
|
||||
{
|
||||
fitMode=value;
|
||||
redrawScreen();
|
||||
}
|
||||
|
||||
function showScale(newscale) // updates slider only
|
||||
{
|
||||
$('scaleslideroutput').innerHTML = parseFloat(newscale).toFixed(2).toString() + " x";
|
||||
return;
|
||||
}
|
||||
|
||||
function setScale(newscale) // makes actual change
|
||||
{
|
||||
showScale(newscale);
|
||||
for(var i=0; i<numMonitors; i++)
|
||||
{
|
||||
monitorCanvasObj[monitorPtr[i]].width=monitorWidth[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
|
||||
monitorCanvasObj[monitorPtr[i]].height=monitorHeight[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
|
||||
}
|
||||
currentScale=newscale;
|
||||
}
|
||||
|
||||
function showSpeed(val) // updates slider only
|
||||
{
|
||||
$('speedslideroutput').innerHTML = parseFloat(speeds[val]).toFixed(2).toString() + " x";
|
||||
}
|
||||
|
||||
function setSpeed(val) // Note parameter is the index not the speed
|
||||
{
|
||||
var t;
|
||||
if(liveMode==1) return; // we shouldn't actually get here but just in case
|
||||
currentSpeed=parseFloat(speeds[val]);
|
||||
speedIndex=val;
|
||||
playSecsperInterval = currentSpeed * currentDisplayInterval / 1000;
|
||||
showSpeed(val);
|
||||
if( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
|
||||
}
|
||||
|
||||
function setLive(value)
|
||||
{
|
||||
liveMode=value;
|
||||
redrawScreen();
|
||||
}
|
||||
|
||||
|
||||
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
// The section below are to reload this program with new parameters
|
||||
|
||||
function clicknav(minSecs,maxSecs,arch,live) // we use the current time if we can
|
||||
{
|
||||
var now = new Date() / 1000;
|
||||
var minStr="";
|
||||
var maxStr="";
|
||||
var currentStr="";
|
||||
if(minSecs>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 groupStr=<?php if($group=="") echo '""'; else echo "\"&group=$group\""; ?>;
|
||||
var uri = "?view=" + currentView + fitStr + groupStr + minStr + maxStr + currentStr + intervalStr + liveStr + zoomStr + "&scale=" + document.getElementById("scaleslider").value + "&speed=" + speeds[document.getElementById("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
|
||||
{
|
||||
if ( monitorHeight[a] * monitorWidth[a] * monitorNormalizeScale[a] * monitorZoomScale[a] * monitorNormalizeScale[a] * monitorZoomScale[a] > monitorHeight[b] * monitorWidth[b] * monitorNormalizeScale[b] * monitorZoomScale[b] * monitorNormalizeScale[b] * monitorZoomScale[b]) return -1;
|
||||
else if ( monitorHeight[a] * monitorWidth[a] * monitorNormalizeScale[a] * monitorZoomScale[a] * monitorNormalizeScale[a] * monitorZoomScale[a] == monitorHeight[b] * monitorWidth[b] * monitorNormalizeScale[b] * monitorZoomScale[b] * monitorNormalizeScale[b] * monitorZoomScale[b]) 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)
|
||||
|
||||
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"+monitorPtr[m]).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[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders, monitorHeight[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders, m-1) == 1 )
|
||||
{
|
||||
if(thisY[adjacent]<fitY || ( thisY[adjacent]==fitY && thisX2[adjacent]+1 < fitX ))
|
||||
{
|
||||
fitX=thisX2[adjacent]+1;
|
||||
fitY=thisY[adjacent];
|
||||
}
|
||||
}
|
||||
// try bottom left
|
||||
if ( doesItFit(thisX[adjacent], thisY2[adjacent]+1, monitorWidth[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders, monitorHeight[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders, m-1) == 1 )
|
||||
{
|
||||
if(thisY2[adjacent]+1<fitY || ( thisY2[adjacent]+1 == fitY && thisX[adjacent]<fitX ))
|
||||
{
|
||||
fitX=thisX[adjacent];
|
||||
fitY=thisY2[adjacent]+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m==0) // note for teh very first one there were no adjacents so the above loop didn't run
|
||||
{
|
||||
if( doesItFit(0,0,monitorWidth[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders, monitorHeight[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders, -1) == 1 )
|
||||
{
|
||||
fitX=0;
|
||||
fitY=0;
|
||||
}
|
||||
}
|
||||
if(fitX==999999999)
|
||||
{
|
||||
allFit=0;
|
||||
break; // break out of monitor loop flagging we didn't fit
|
||||
}
|
||||
thisX[m] =fitX;
|
||||
thisX2[m]=fitX + monitorWidth[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders;
|
||||
thisY[m] =fitY;
|
||||
thisY2[m]=fitY + monitorHeight[monitorPtr[m]] * thisScale * monitorNormalizeScale[monitorPtr[m]] * monitorZoomScale[monitorPtr[m]] + borders;
|
||||
thisArea += (thisX2[m] - thisX[m])*(thisY2[m] - thisY[m]);
|
||||
}
|
||||
if(allFit==1)
|
||||
{
|
||||
minScale=thisScale;
|
||||
if(bestFitArea<thisArea)
|
||||
{
|
||||
bestFitArea=thisArea;
|
||||
bestFitX=thisX;
|
||||
bestFitY=thisY;
|
||||
bestFitX2=thisX2;
|
||||
bestFitY2=thisY2;
|
||||
bestFitScale=thisScale;
|
||||
}
|
||||
}
|
||||
else // didn't fit
|
||||
{
|
||||
maxScale=thisScale;
|
||||
}
|
||||
}
|
||||
if(bestFitArea>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; i<eId.length; i++)
|
||||
if(eMonId[i]==monId && currentTimeSecs >= 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) ) ));
|
||||
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 pos_x = event.offsetX ? (event.offsetX) : event.pageX - $("Monitor"+monId.toString()).offsetLeft;
|
||||
var pos_y = event.offsetY ? (event.offsetY) : event.pageY - $("Monitor"+monId.toString()).offsetTop;
|
||||
if(pos_x < $("Monitor"+monId.toString()).width/4 && pos_y < $("Monitor"+monId.toString()).height/4) zoom(monId,1.15);
|
||||
else if(pos_x > $("Monitor"+monId.toString()).width * 3/4 && pos_y < $("Monitor"+monId.toString()).height/4) zoom(monId,1/1.15);
|
||||
else showOneMonitor(monId);
|
||||
return;
|
||||
}
|
||||
|
||||
// >>>>>>>>> Initialization that runs on window load by being at the bottom
|
||||
|
||||
drawGraph();
|
||||
setSpeed(speedIndex);
|
||||
setFit(fitMode); // will redraw
|
||||
setLive(liveMode); // will redraw
|
||||
window.addEventListener("resize",redrawScreen);
|
||||
|
||||
</script>
|
||||
</div>
|
||||
<p id="fps">evaluating fps</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue