diff --git a/web/zm_html_view_timeline.php b/web/zm_html_view_timeline.php
index 95f4250f5..a21cd5943 100644
--- a/web/zm_html_view_timeline.php
+++ b/web/zm_html_view_timeline.php
@@ -1,6 +1,6 @@
700,
+ "height"=>460,
+ "image" => array(
+ "width"=>200,
+ "height"=>200,
+ "top_offset"=>20,
+ ),
+ "image_text" => array(
+ "width"=>400,
+ "height"=>30,
+ "top_offset"=>20,
+ ),
+ "graph" => array(
+ "width"=>600,
+ "height"=>160,
+ "top_offset"=>30,
+ ),
+ "title" => array(
+ "top_offset"=>50
+ ),
+ "key" => array(
+ "top_offset"=>50
+ ),
+ "axes" => array(
+ "x" => array(
+ "height" => 20,
+ ),
+ "y" => array(
+ "width" => 30,
+ ),
+ ),
+ "grid" => array(
+ "x" => array(
+ "major" => array(
+ "max" => 12,
+ "min" => 4,
+ ),
+ "minor" => array(
+ "max" => 48,
+ "min" => 12,
+ ),
+ ),
+ "y" => array(
+ "major" => array(
+ "max" => 8,
+ "min" => 1,
+ ),
+ "minor" => array(
+ "max" => 0,
+ "min" => 0,
+ ),
+ ),
+ ),
+);
+
+$monitors = array();
+$monitors_sql = "select * from Monitors order by Id asc";
+if ( !($result = mysql_query( $monitors_sql )) )
+ die( mysql_error() );
+srand( 97981 );
+while ( $row = mysql_fetch_assoc( $result ) )
+{
+ if ( empty($row['WebColour']) )
+ {
+ $row['WebColour'] = sprintf( "#%02x%02x%02x", rand( 0, 255 ), rand( 0, 255), rand( 0, 255 ) );
+ }
+ $monitors[$row['Id']] = $row;
+}
+
+$range_sql = "select min(E.StartTime) as MinTime, max(E.EndTime) as MaxTime from Events as E inner join Monitors as M on (E.MonitorId = M.Id) where not isnull(E.StartTime) and not isnull(E.EndTime)";
+$events_sql = "select E.Id,E.Name,E.StartTime,E.EndTime,E.Length,E.Frames,E.MaxScore,E.MonitorId from Events as E inner join Monitors as M on (E.MonitorId = M.Id) where not isnull(StartTime)";
+
if ( $user['MonitorIds'] )
{
- $count_sql .= " M.Id in (".join( ",", preg_split( '/["\'\s]*,["\'\s]*/', $user['MonitorIds'] ) ).")";
- $events_sql .= " M.Id in (".join( ",", preg_split( '/["\'\s]*,["\'\s]*/', $user['MonitorIds'] ) ).")";
-}
-else
-{
- $count_sql .= " 1";
- $events_sql .= " 1";
+ $mon_filter_sql = " and M.Id in (".join( ",", preg_split( '/["\'\s]*,["\'\s]*/', $user['MonitorIds'] ) ).")";
+
+ $range_sql .= $mon_filter_sql;
+ $events_sql .= $mon_filter_sql;
}
-parseSort();
-parseFilter();
-
-if ( $filter_sql )
+if ( isset($range) )
{
- $count_sql .= $filter_sql;
- $events_sql .= $filter_sql;
-}
-$events_sql .= " order by $sort_column $sort_order";
-if ( $page )
-{
- $limit_start = (($page-1)*ZM_WEB_EVENTS_PER_PAGE);
- if ( empty( $limit ) )
+ $half_range = (int)($range/2);
+ if ( isset($mid_time) )
{
- $limit_amount = ZM_WEB_EVENTS_PER_PAGE;
+ $mid_time_t = strtotime($mid_time);
+ $min_time_t = $mid_time_t-$half_range;
+ $max_time_t = $mid_time_t+$half_range;
+ if ( !($range%1) )
+ {
+ $max_time_t--;
+ }
+ $min_time = date( "Y-m-d H:i:s", $min_time_t );
+ $max_time = date( "Y-m-d H:i:s", $max_time_t );
+ }
+ elseif ( isset($min_time) )
+ {
+ $min_time_t = strtotime($min_time);
+ $max_time_t = $min_time_t + $range;
+ $mid_time_t = $min_time_t + $half_range;
+ $mid_time = date( "Y-m-d H:i:s", $mid_time_t );
+ $max_time = date( "Y-m-d H:i:s", $max_time_t );
+ }
+ elseif ( isset($max_time) )
+ {
+ $max_time_t = strtotime($max_time);
+ $min_time_t = $max_time_t - $range;
+ $mid_time_t = $min_time_t + $half_range;
+ $min_time = date( "Y-m-d H:i:s", $min_time_t );
+ $mid_time = date( "Y-m-d H:i:s", $mid_time_t );
+ }
+}
+elseif ( isset($min_time) && isset($max_time) )
+{
+ $min_time_t = strtotime($min_time);
+ $max_time_t = strtotime($max_time);
+ $range = ($max_time_t - $min_time_t) + 1;
+ $half_range = (int)($range/2);
+ $mid_time_t = $min_time_t + $half_range;
+ $mid_time = date( "Y-m-d H:i:s", $mid_time_t );
+}
+
+if ( !isset($min_time) || !isset($max_time) )
+{
+ parseFilter();
+ if ( $filter_sql )
+ {
+ $range_sql .= $filter_sql;
+ $events_sql .= $filter_sql;
+ }
+
+ // Dynamically determine range
+ if ( !($result = mysql_query( $range_sql )) )
+ die( mysql_error() );
+ $row = mysql_fetch_assoc( $result );
+
+ if ( !isset($min_time) )
+ $min_time = $row['MinTime'];
+ if ( !isset($max_time) )
+ $max_time = $row['MaxTime'];
+ $min_time_t = strtotime($min_time);
+ $max_time_t = strtotime($max_time);
+ $range = ($max_time_t - $min_time_t) + 1;
+ $half_range = (int)($range/2);
+ $mid_time_t = $min_time_t + $half_range;
+ $mid_time = date( "Y-m-d H:i:s", $mid_time_t );
+}
+
+$scales = array(
+ array( "name"=>"year", "factor"=>60*60*24*365, "align"=>1, "zoomout"=>2, "label"=>"Y" ),
+ array( "name"=>"month", "factor"=>60*60*24*30, "align"=>1, "zoomout"=>12, "label"=>"M" ),
+ array( "name"=>"week", "factor"=>60*60*24*7, "align"=>1, "zoomout"=>4.25, "label"=>"j/n", "label_check"=>"W" ),
+ array( "name"=>"day", "factor"=>60*60*24, "align"=>1, "zoomout"=>7, "label"=>"j" ),
+ array( "name"=>"hour", "factor"=>60*60, "align"=>1, "zoomout"=>24, "label"=>"H:00", "label_check"=>"H" ),
+ array( "name"=>"minute10", "factor"=>60, "align"=>10, "zoomout"=>6, "label"=>"H:i", "label_check"=>"i" ),
+ array( "name"=>"minute", "factor"=>60, "align"=>1, "zoomout"=>10, "label"=>"H:i", "label_check"=>"i" ),
+ array( "name"=>"second10", "factor"=>1, "align"=>10, "zoomout"=>6, "label"=>"s" ),
+ array( "name"=>"second", "factor"=>1, "align"=>1, "zoomout"=>10, "label"=>"s" ),
+);
+
+$maj_x_scale = getDateScale( $scales, $range, $chart['grid']['x']['major']['min'], $chart['grid']['x']['major']['max'] );
+//$min_x_scale = getDateScale( $scales, $range, $chart['grid']['x']['minor']['min'], $chart['grid']['x']['minor']['max'] );
+//print_r( $maj_x_scale );
+//print_r( $min_x_scale );
+
+// Adjust the range etc for scale
+$min_time_t -= $min_time_t%($maj_x_scale['factor']*$maj_x_scale['align']);
+$min_time = date( "Y-m-d H:i:s", $min_time_t );
+$max_time_t += (($maj_x_scale['factor']*$maj_x_scale['align'])-$max_time_t%($maj_x_scale['factor']*$maj_x_scale['align']))-1;
+if ( $max_time_t > time() )
+ $max_time_t = time();
+$max_time = date( "Y-m-d H:i:s", $max_time_t );
+$range = ($max_time_t - $min_time_t) + 1;
+$half_range = (int)($range/2);
+$mid_time_t = $min_time_t + $half_range;
+$mid_time = date( "Y-m-d H:i:s", $mid_time_t );
+
+//echo "R:$range
";
+//echo "MnT:$min_time
";
+//echo "MnTt:$min_time_t
";
+//echo "MdT:$mid_time
";
+//echo "MdTt:$mid_time_t
";
+//echo "MxT:$max_time
";
+//echo "MxTt:$max_time_t
";
+
+if ( isset($min_time) && isset($max_time) )
+{
+ $range_sql .= " and E.EndTime >= '$min_time' and E.StartTime <= '$max_time'";
+ $events_sql .= " and E.EndTime >= '$min_time' and E.StartTime <= '$max_time'";
+}
+$events_sql .= " order by Id asc";
+//echo "ESQL: $events_sql
";
+
+$chart['data'] = array(
+ "x" => array(
+ "lo" => strtotime( $min_time ),
+ "hi" => strtotime( $max_time ),
+ ),
+ "y" => array(
+ "lo" => 0,
+ "hi" => 0,
+ )
+);
+
+$chart['data']['x']['range'] = ($chart['data']['x']['hi'] - $chart['data']['x']['lo']) + 1;
+$chart['data']['x']['density'] = $chart['data']['x']['range']/$chart['graph']['width'];
+
+$mon_event_slots = array();
+$mon_frame_slots = array();
+if ( !($event_result = mysql_query( $events_sql )) )
+ die( mysql_error() );
+$monitor_ids = array();
+//echo "YYY:".date( "r" )."
"; flush();
+while( $event = mysql_fetch_assoc( $event_result ) )
+{
+ if ( !isset($monitor_ids[$event['MonitorId']]) )
+ $monitor_ids[$event['MonitorId']] = true;
+
+ if ( !isset($mon_event_slots[$event['MonitorId']]) )
+ $mon_event_slots[$event['MonitorId']] = array();
+ if ( !isset($mon_frame_slots[$event['MonitorId']]) )
+ $mon_frame_slots[$event['MonitorId']] = array();
+
+ $curr_event_slots = &$mon_event_slots[$event['MonitorId']];
+ $curr_frame_slots = &$mon_frame_slots[$event['MonitorId']];
+
+ $start_time_t = strtotime($event['StartTime']);
+ $start_index = $raw_start_index = (int)(($start_time_t - $chart['data']['x']['lo']) / $chart['data']['x']['density']);
+ if ( $start_index < 0 )
+ $start_index = 0;
+
+ if ( isset($event['EndTime']) )
+ {
+ $end_time_t = strtotime($event['EndTime']);
}
else
{
- $limit_left = $limit - $limit_start;
- $limit_amount = ($limit_left>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limit_left;
+ $end_time_t = time();
+ }
+ $end_index = $raw_end_index = (int)(($end_time_t - $chart['data']['x']['lo']) / $chart['data']['x']['density']);
+ if ( $end_index >= $chart['graph']['width'] )
+ $end_index = $chart['graph']['width'] - 1;
+
+ for ( $i = $start_index; $i <= $end_index; $i++ )
+ {
+ if ( !isset($curr_event_slots[$i]) )
+ {
+ if ( $raw_start_index == $raw_end_index )
+ {
+ $offset = 1;
+ }
+ else
+ {
+ $offset = 1+ ($event['Frames']?((int)($event['Frames']*(($i-$raw_start_index)/($raw_end_index-$raw_start_index)))):0);
+ }
+ $curr_event_slots[$i] = array( "count"=>0, "width"=>1, "offset"=>$offset, "event"=>$event );
+ }
+ else
+ {
+ $curr_event_slots[$i]['count']++;
+ }
+ }
+ if ( $event['MaxScore'] > 0 )
+ {
+ if ( $start_index == $end_index )
+ {
+ $i = $start_index;
+ if ( !isset($curr_frame_slots[$i]) )
+ {
+ $curr_frame_slots[$i] = array( "count"=>1, "value"=>$event['MaxScore'], "event"=>$event );
+ }
+ else
+ {
+ $curr_frame_slots[$i]['count']++;
+ if ( $event['MaxScore'] > $curr_frame_slots[$i]['value'] )
+ {
+ $curr_frame_slots[$i]['value'] = $event['MaxScore'];
+ $curr_frame_slots[$i]['event'] = $event;
+ }
+ }
+ if ( $event['MaxScore'] > $chart['data']['y']['hi'] )
+ {
+ $chart['data']['y']['hi'] = $event['MaxScore'];
+ }
+ }
+ else
+ {
+ $frames_sql = "select F.FrameId,F.Delta,unix_timestamp(F.TimeStamp) as TimeT,F.Score from Frames as F where F.EventId = '".$event['Id']."' and F.Score > 0";
+ if ( !($frame_result = mysql_query( $frames_sql )) )
+ die( mysql_error() );
+ while( $frame = mysql_fetch_assoc( $frame_result ) )
+ {
+ $frame_time_t = $frame['TimeT'];
+ $frame_time_t = $start_time_t + $frame['Delta'];
+ $frame_index = (int)(($frame_time_t - $chart['data']['x']['lo']) / $chart['data']['x']['density']);
+ if ( $frame_index < 0 )
+ continue;
+ if ( $frame_index >= $chart['graph']['width'] )
+ continue;
+
+ if ( !isset($curr_frame_slots[$frame_index]) )
+ {
+ $curr_frame_slots[$frame_index] = array( "count"=>1, "value"=>$frame['Score'], "event"=>$event, "frame"=>$frame );
+ }
+ else
+ {
+ $curr_frame_slots[$frame_index]['count']++;
+ if ( $frame['Score'] > $curr_frame_slots[$frame_index]['value'] )
+ {
+ $curr_frame_slots[$frame_index]['value'] = $frame['Score'];
+ $curr_frame_slots[$frame_index]['event'] = $event;
+ $curr_frame_slots[$frame_index]['frame'] = $frame;
+ }
+ }
+ if ( $frame['Score'] > $chart['data']['y']['hi'] )
+ {
+ $chart['data']['y']['hi'] = $frame['Score'];
+ }
+ }
+ }
}
- $events_sql .= " limit $limit_start, $limit_amount";
}
-elseif ( !empty( $limit ) )
+
+ksort($monitor_ids,SORT_NUMERIC);
+ksort($mon_event_slots,SORT_NUMERIC);
+ksort($mon_frame_slots,SORT_NUMERIC);
+
+//echo "AAA:".date( "r" )."
"; flush();
+// Add on missing frames
+$xcount = 0;
+foreach( array_keys($mon_frame_slots) as $monitor_id )
{
- $events_sql .= " limit 0, $limit";
+ unset( $curr_frame_slots );
+ $curr_frame_slots = &$mon_frame_slots[$monitor_id];
+ for ( $i = 0; $i < $chart['graph']['width']; $i++ )
+ {
+ if ( isset($curr_frame_slots[$i]) )
+ {
+ if ( !isset($curr_frame_slots[$i]['frame']) )
+ {
+ $xcount++;
+ $frames_sql = "select F.FrameId,F.Score from Frames as F where F.EventId = '".$curr_frame_slots[$i]['event']['Id']."' and F.Score > 0 order by F.FrameId limit 0,1";
+ if ( !($frame_result = mysql_query( $frames_sql )) )
+ die( mysql_error() );
+ $curr_frame_slots[$i]['frame'] = mysql_fetch_assoc( $frame_result );
+ }
+ }
+ }
+}
+//echo "Fetched $xcount frames
";
+//echo "BBB:".date( "r" )."
"; flush();
+
+$chart['data']['y']['range'] = ($chart['data']['y']['hi'] - $chart['data']['y']['lo']) + 1;
+$chart['data']['y']['density'] = $chart['data']['y']['range']/$chart['graph']['height'];
+
+$maj_y_scale = getYScale( $chart['data']['y']['range'], $chart['grid']['y']['major']['min'], $chart['grid']['y']['major']['max'] );
+//print_r( $maj_y_scale );
+
+$max_width = 0;
+$max_height = 0;
+
+foreach ( array_keys($monitor_ids) as $monitor_id )
+{
+ if ( $max_width < $monitors[$monitor_id]['Width'] )
+ $max_width = $monitors[$monitor_id]['Width'];
+ if ( $max_height < $monitors[$monitor_id]['Height'] )
+ $max_height = $monitors[$monitor_id]['Height'];
+}
+
+//echo "ZZZ:".date( "r" )."
"; flush();
+// Optimise boxes
+foreach( array_keys($mon_event_slots) as $monitor_id )
+{
+ unset( $curr_event_slots );
+ $curr_event_slots = &$mon_event_slots[$monitor_id];
+ for ( $i = 0; $i < $chart['graph']['width']; $i++ )
+ {
+ if ( isset($curr_event_slots[$i]) )
+ {
+ //if ( isset($curr_slot) && (($curr_slot['width'] < $min_event_width) || (($curr_slot['event']['Id'] == $curr_event_slots[$i]['event']['Id']) && ($curr_slot['frame']['FrameId'] == $curr_event_slots[$i]['frame']['FrameId'])) ) )
+ //if ( isset($curr_slot) && ($curr_slot['event']['Id'] == $curr_event_slots[$i]['event']['Id']) )
+ if ( isset($curr_slot) )
+ {
+ if ( $curr_slot['event']['Id'] == $curr_event_slots[$i]['event']['Id'] )
+ {
+ if ( $curr_slot['width'] < $max_event_width )
+ {
+ // Merge slots for the same long event
+ $curr_slot['width']++;
+ unset( $curr_event_slots[$i] );
+ continue;
+ }
+ elseif ( $curr_slot['offset'] < $curr_event_slots[$i]['offset'] )
+ {
+ // Split very long events
+ $curr_event_slots[$i]['frame'] = array( 'FrameId'=>$curr_event_slots[$i]['offset'] );
+ }
+ }
+ elseif ( $curr_slot['width'] < $min_event_width )
+ {
+ // Merge multiple small events
+ $curr_slot['width']++;
+ unset( $curr_event_slots[$i] );
+ continue;
+ }
+ }
+ $curr_slot = &$curr_event_slots[$i];
+
+ //if ( isset($curr_slot) && ($curr_slot['width'] < $min_event_width || ($curr_slot['event']['Id'] == $curr_event_slots[$i]['event']['Id']) ) )
+ //{
+ //$curr_slot['width']++;
+ //unset( $curr_event_slots[$i] );
+ //}
+ //else
+ //{
+ //$curr_slot = &$curr_event_slots[$i];
+ //}
+ }
+ else
+ {
+ unset( $curr_slot );
+ }
+ }
+ if ( isset( $curr_slot ) )
+ unset( $curr_slot );
+}
+
+// Stack events
+//echo "XXX:".date( "r" )."
"; flush();
+$frame_slots = array();
+$frame_monitor_ids = array_keys($mon_frame_slots);
+for ( $i = 0; $i < $chart['graph']['width']; $i++ )
+{
+ foreach ( $frame_monitor_ids as $frame_monitor_id )
+ {
+ unset( $curr_frame_slots );
+ $curr_frame_slots = &$mon_frame_slots[$frame_monitor_id];
+ if ( isset($curr_frame_slots[$i]) )
+ {
+ if ( !isset($frame_slots[$i]) )
+ {
+ $frame_slots[$i] = array();
+ $frame_slots[$i][] = &$curr_frame_slots[$i];
+ }
+ else
+ {
+ $slot_count = count($frame_slots[$i]);
+ for ( $j = 0; $j < $slot_count; $j++ )
+ {
+ if ( $curr_frame_slots[$i]['value'] > $frame_slots[$i][$j]['value'] )
+ {
+ for ( $k = $slot_count; $k > $j; $k-- )
+ {
+ $frame_slots[$i][$k] = $frame_slots[$i][$k-1];
+ }
+ $frame_slots[$i][$j] = &$curr_frame_slots[$i];
+ break 2;
+ }
+ }
+ $frame_slots[$i][] = &$curr_frame_slots[$i];
+ }
+ }
+ }
+}
+//echo "YYY:".date( "r" )."
"; flush();
+
+//print_r( $mon_event_slots );
+//print_r( $mon_frame_slots );
+//print_r( $chart );
+
+preg_match( '/^(\d+)-(\d+)-(\d+) (\d+):(\d+)/', $min_time, $start_matches );
+preg_match( '/^(\d+)-(\d+)-(\d+) (\d+):(\d+)/', $max_time, $end_matches );
+
+if ( $start_matches[1] != $end_matches[1] )
+{
+ // Different years
+ $title = date( "M Y", $chart['data']['x']['lo'] )." - ".date( "M Y", $chart['data']['x']['hi'] );
+}
+elseif ( $start_matches[2] != $end_matches[2] )
+{
+ // Different months
+ $title = date( "M", $chart['data']['x']['lo'] )." - ".date( "M Y", $chart['data']['x']['hi'] );
+}
+elseif ( $start_matches[3] != $end_matches[3] )
+{
+ // Different dates
+ $title = date( "j", $chart['data']['x']['lo'] )." - ".date( "j M Y", $chart['data']['x']['hi'] );
+}
+else
+{
+ // Different times
+ $title = date( "H:i", $chart['data']['x']['lo'] )." - ".date( "H:i, j M Y", $chart['data']['x']['hi'] );
+}
+
+function getDateScale( $scales, $range, $min_lines, $max_lines )
+{
+ foreach ( $scales as $scale )
+ {
+ $align = isset($scale['align'])?$scale['align']:1;
+ $scale_range = (int)($range/($scale['factor']*$align));
+ //echo "S:".$scale['name'].", A:$align, SR:$scale_range
";
+ if ( $scale_range >= $min_lines )
+ {
+ $scale['range'] = $scale_range;
+ break;
+ }
+ }
+ if ( !isset($scale['range']) )
+ {
+ $scale['range'] = (int)($range/($scale['factor']*$align));
+ }
+ $scale['divisor'] = 1;
+ while ( ($scale['range']/$scale['divisor']) > $max_lines )
+ {
+ $scale['divisor']++;
+ }
+ $scale['lines'] = (int)($scale['range']/$scale['divisor']);
+ return( $scale );
+}
+
+function getYScale( $range, $min_lines, $max_lines )
+{
+ $scale['range'] = $range;
+ $scale['divisor'] = 1;
+ while ( $scale['range']/$scale['divisor'] > $max_lines )
+ {
+ $scale['divisor']++;
+ }
+ $scale['lines'] = (int)(($scale['range']-1)/$scale['divisor'])+1;
+
+ return( $scale );
+}
+
+function drawXGrid( $chart, $scale, $label_class, $tick_class, $grid_class, $zoom_class=0 )
+{
+ global $PHP_SELF, $view;
+
+ ob_start();
+ $label_count = 0;
+ $last_tick = 0;
+ unset( $last_label );
+ $label_check = isset($scale['label_check'])?$scale['label_check']:$scale['label'];
+ for ( $i = 0; $i < $chart['graph']['width']; $i++ )
+ {
+ $x = $i - 1;
+ $time_offset = (int)($chart['data']['x']['lo'] + ($i * $chart['data']['x']['density']));
+ if ( $scale['align'] > 1 )
+ {
+ $label = (int)(date( $label_check, $time_offset )/$scale['align']);
+ }
+ else
+ {
+ $label = date( $label_check, $time_offset );
+ }
+ if ( !isset($last_label) || ($last_label != $label) )
+ {
+ $label_count++;
+ }
+ if ( $label_count >= $scale['divisor'] )
+ {
+ $label_count = 0;
+ if ( isset($last_label) )
+ {
+ if ( $label_class )
+ {
+?>
+