/** * Gets latest datasource coverage and return as JSON */ public function getDataCoverageEvents($events, $resolution, $startDate, $endDate, $currentDate) { require_once HV_ROOT_DIR . '/../src/Helper/DateTimeConversions.php'; $distance = $endDate->getTimestamp() - $startDate->getTimestamp(); $interval = new DateInterval('PT' . $distance . 'S'); $visibleStartTimestamp = $startDate->getTimestamp(); $visibleEndTimestamp = $endDate->getTimestamp(); $startDate->modify('-' . $distance . ' seconds'); $endDate->modify('+' . $distance . ' seconds'); $dateStart = toMySQLDateString($startDate); $dateEnd = toMySQLDateString($endDate); $startTimestamp = $startDate->getTimestamp(); $endTimestamp = $endDate->getTimestamp(); $currentTimestamp = $currentDate->getTimestamp(); $dateStartISO = str_replace("Z", "", toISOString($startDate)); $dateEndISO = str_replace("Z", "", toISOString($endDate)); $sources = array(); if (!$events) { return json_encode(array()); } $eventsKeys = array('AR' => 0, 'CC' => 1, 'CD' => 2, 'CH' => 3, 'CJ' => 4, 'CE' => 5, 'CR' => 6, 'CW' => 7, 'EF' => 8, 'ER' => 9, 'FI' => 10, 'FA' => 11, 'FE' => 12, 'FL' => 13, 'LP' => 14, 'OS' => 15, 'PG' => 16, 'SG' => 17, 'SP' => 18, 'SS' => 19, 'OT' => 20, 'NR' => 21, 'TO' => 22, 'HY' => 23, 'BO' => 24, 'EE' => 25, 'PB' => 26, 'PT' => 27, 'UNK' => 28); $eventsColors = array('AR' => '#ff8f97', 'CE' => '#ffb294', 'CME' => '#ffb294', 'CD' => '#ffd391', 'CH' => '#fef38e', 'CW' => '#ebff8c', 'FI' => '#c8ff8d', 'FE' => '#a3ff8d', 'FA' => '#7bff8e', 'FL' => '#7affae', 'LP' => '#7cffc9', 'OS' => '#81fffc', 'SS' => '#8ce6ff', 'EF' => '#95c6ff', 'CJ' => '#9da4ff', 'PG' => '#ab8cff', 'OT' => '#d4d4d4', 'NR' => '#d4d4d4', 'SG' => '#e986ff', 'SP' => '#ff82ff', 'CR' => '#ff85ff', 'CC' => '#ff8acc', 'ER' => '#ff8dad', 'TO' => '#ca89ff', 'HY' => '#00ffff', 'BO' => '#a7e417', 'EE' => '#fec00a', 'PB' => '#b3d5e4', 'PT' => '#494a37', 'UNK' => '#d4d4d4'); $eventTypes = array(); $dbData = array(); $dbVisibleData = array(); $layersString = ''; foreach ($events->toArray() as $layer) { if (!empty($layer['frm_name']) && $layer['frm_name'] != 'all') { $frms = explode(';', $layer['frm_name']); foreach ($frms as $frm_name) { if (!empty($layersString)) { $layersString .= ' OR '; } $frm_name = str_replace('_', ' ', $frm_name); $layersString .= '(event_type = "' . $layer['event_type'] . '" AND frm_name = "' . $frm_name . '")'; } } else { if (!empty($layersString)) { $layersString .= ' OR '; } $layersString .= 'event_type = "' . $layer['event_type'] . '"'; } $eventKey = $eventsKeys[$layer['event_type']]; $dbData[$eventKey] = array(); $dbVisibleData[$eventKey] = false; $sources[$eventKey] = array('data' => array(), 'event_type' => $layer['event_type'], 'res' => $resolution, 'showInLegend' => false); } switch ($resolution) { case 'm': $sql = 'SELECT * FROM events WHERE (' . $layersString . ') AND (event_endtime >= "' . $dateStart . '" AND event_starttime <= "' . $dateEnd . '") ORDER BY event_starttime;'; $beginInterval = new DateTime(); $endInterval = new DateTime(); $beginInterval->setTimestamp($startTimestamp); $endInterval->setTimestamp($endTimestamp); break; case '5m': $sql = 'SELECT * FROM events WHERE (' . $layersString . ') AND (event_endtime >= "' . $dateStart . '" AND event_starttime <= "' . $dateEnd . '") ORDER BY event_starttime;'; $beginInterval = new DateTime(); $endInterval = new DateTime(); $beginInterval->setTimestamp(floor($startTimestamp / 300) * 300); $endInterval->setTimestamp(floor($endTimestamp / 300) * 300); $interval = DateInterval::createFromDateString('5 minutes'); $period = new DatePeriod($beginInterval, $interval, $endInterval); $periodSeconds = 300000; break; case '15m': $sql = 'SELECT * FROM events WHERE (' . $layersString . ') AND (event_endtime >= "' . $dateStart . '" AND event_starttime <= "' . $dateEnd . '") ORDER BY event_starttime;'; $beginInterval = new DateTime(); $endInterval = new DateTime(); $beginInterval->setTimestamp(floor($startTimestamp / 900) * 900); $endInterval->setTimestamp(floor($endTimestamp / 900) * 900); $interval = DateInterval::createFromDateString('15 minutes'); $period = new DatePeriod($beginInterval, $interval, $endInterval); $periodSeconds = 900000; break; case '30m': $sql = 'SELECT date, event_type, SUM(count) as count FROM events_coverage WHERE period = "30m" AND (' . $layersString . ') AND `date` BETWEEN "' . $dateStart . '" AND "' . $dateEnd . '" GROUP BY date, event_type ORDER BY date;'; $beginInterval = new DateTime(); $endInterval = new DateTime(); $beginInterval->setTimestamp(floor($startTimestamp / 1800) * 1800); $endInterval->setTimestamp(floor($endTimestamp / 1800) * 1800); $interval = DateInterval::createFromDateString('30 minutes'); $period = new DatePeriod($beginInterval, $interval, $endInterval); $periodSeconds = 1800000; break; case 'h': $sql = 'SELECT date, event_type, SUM(count) as count FROM events_coverage WHERE period = "1H" AND (' . $layersString . ') AND `date` BETWEEN "' . $dateStart . '" AND "' . $dateEnd . '" GROUP BY date, event_type ORDER BY date;'; $beginInterval = new DateTime(date('Y-m-d H:00:00', $startTimestamp)); $endInterval = new DateTime(date('Y-m-d H:00:00', $endTimestamp)); $interval = DateInterval::createFromDateString('1 hour'); $period = new DatePeriod($beginInterval, $interval, $endInterval); $periodSeconds = 3600000; break; case 'D': $sql = 'SELECT date, event_type, SUM(count) as count FROM events_coverage WHERE period = "1D" AND (' . $layersString . ') AND `date` BETWEEN "' . $dateStart . '" AND "' . $dateEnd . '" GROUP BY date, event_type ORDER BY date;'; $beginInterval = new DateTime(date('Y-m-d 00:00:00', $startTimestamp)); $endInterval = new DateTime(date('Y-m-d 00:00:00', $endTimestamp)); $interval = DateInterval::createFromDateString('1 day'); $period = new DatePeriod($beginInterval, $interval, $endInterval); break; case 'W': $sql = 'SELECT date, event_type, SUM(count) as count FROM events_coverage WHERE period = "1W" AND (' . $layersString . ') AND `date` BETWEEN "' . $dateStart . '" AND "' . $dateEnd . '" GROUP BY date, event_type ORDER BY date;'; $beginInterval = new DateTime(date('Y-m-d 00:00:00', strtotime('Last Monday', $startTimestamp))); $endInterval = new DateTime(date('Y-m-d 00:00:00', $endTimestamp)); $interval = DateInterval::createFromDateString('1 week'); $period = new DatePeriod($beginInterval, $interval, $endInterval); break; case 'M': $sql = 'SELECT date, event_type, SUM(count) as count FROM events_coverage WHERE period = "1M" AND (' . $layersString . ') AND `date` BETWEEN "' . $dateStart . '" AND "' . $dateEnd . '" GROUP BY date, event_type ORDER BY date;'; $beginInterval = new DateTime(date('Y-m-01 00:00:00', $startTimestamp)); $endInterval = new DateTime(date('Y-m-01 00:00:00', $endTimestamp)); $interval = DateInterval::createFromDateString('1 month'); $period = new DatePeriod($beginInterval, $interval, $endInterval); break; case 'Y': $sql = 'SELECT date, event_type, SUM(count) as count FROM events_coverage WHERE period = "1Y" AND (' . $layersString . ') AND `date` BETWEEN "' . $dateStart . '" AND "' . $dateEnd . '" GROUP BY date, event_type ORDER BY date;'; $beginInterval = new DateTime(date('Y-01-01 00:00:00', $startTimestamp)); $endInterval = new DateTime(date('Y-01-01 00:00:00', $endTimestamp)); $interval = DateInterval::createFromDateString('1 year'); $period = new DatePeriod($beginInterval, $interval, $endInterval); break; default: $msg = 'Invalid resolution specified. Valid options include: ' . implode(', ', $validRes); throw new Exception($msg, 25); } //build 0 data array if ($resolution != 'm') { $emptyData = array(); foreach ($period as $dt) { $emptyData[$dt->getTimestamp() * 1000] = 0; } } //Procceed SQL Data $result = $this->_dbConnection->query($sql); $i = 1; $uniqueIds = array(); $j = 0; while ($row = $result->fetch_array(MYSQLI_ASSOC)) { //Event Name $key = $row['event_type']; $eventKey = $eventsKeys[$key]; //Build data array if ($resolution == 'm') { $timeStart = strtotime($row['event_starttime']) * 1000; $timeEnd = strtotime($row['event_endtime']) * 1000; if ($startTimestamp * 1000 > $timeStart) { $timeStart = $beginInterval->getTimestamp() * 1000; } if ($endTimestamp * 1000 < $timeEnd) { $timeEnd = $endInterval->getTimestamp() * 1000; } $modifier = 0; if ($timeStart == $timeEnd) { $modifier = round(($endTimestamp - $startTimestamp) / (3 * 60)) * 100; $startTimeToDisplay = $timeStart - $modifier; $timeEndToDisplay = $timeEnd + $modifier; } else { $startTimeToDisplay = $timeStart; $timeEndToDisplay = $timeEnd; } $sources[$eventKey]['data'][$j] = array('x' => $startTimeToDisplay, 'x2' => $timeEndToDisplay, 'y' => $j, 'kb_archivid' => $row['kb_archivid'], 'hv_labels_formatted' => json_decode($row['hv_labels_formatted']), 'event_type' => $row['event_type'], 'frm_name' => $row['frm_name'], 'frm_specificid' => $row['frm_specificid'], 'event_peaktime' => $row['event_peaktime'], 'event_starttime' => $row['event_starttime'], 'event_endtime' => $row['event_endtime'], 'modifier' => $modifier); if ($timeStart == $timeEnd) { $sources[$eventKey]['data'][$j]['zeroSeconds'] = true; } if ($currentTimestamp >= $timeStart && $currentTimestamp <= $timeEnd) { $sources[$eventKey]['data'][$j]['borderColor'] = '#ffffff'; } else { $sources[$eventKey]['data'][$j]['color'] = $this->colourBrightness($eventsColors[$row['event_type']], -0.9); } if ($visibleEndTimestamp >= strtotime($row['event_starttime']) && $visibleStartTimestamp <= strtotime($row['event_endtime'])) { $dbVisibleData[$eventKey] = true; } $uniqueIds[$row['frm_specificid']] = $j; $j++; } else { $timestamp = strtotime($row['date']) * 1000; $dbData[$eventKey][$timestamp] = (int) $row['count']; if ($visibleEndTimestamp >= strtotime($row['date']) && $visibleStartTimestamp <= strtotime($row['date'])) { $dbVisibleData[$eventKey] = true; } } $i++; } //Fill 0 values rows if ($resolution != 'm') { foreach ($dbData as $key => $row) { foreach ($emptyData as $timestamp => $count) { if (isset($dbData[$key]) && isset($dbData[$key][$timestamp])) { $count = $dbData[$key][$timestamp]; } $sources[$key]['data'][] = array($timestamp, (int) $count); } } } else { ksort($sources); $i = 1; $levels = array(); foreach ($sources as $k => $series) { //loop over all the events //$i = count($levels); //$levels = array(); $data = array(); foreach ($series['data'] as $dk => $event) { //was this event placed in a level already? $placed = false; //loop through each level checking only the last event foreach ($levels as $row => $events) { //we only need to check the last event if they are already sorted $last = end($events); //does the current event start after the end time of the last event in this level if ($event['x'] >= $last['x2']) { //add to this level and break out of the inner loop $event['y'] = $row; $levels[$row][] = $event; $data[] = $event; $placed = true; break; } } //if not placed in another level, add a new level if (!$placed) { $levels[$i] = array($event); $event['y'] = $i; $data[] = $event; $i++; } } $sources[$k]['data'] = $data; } } //Remove not visible events foreach ($dbVisibleData as $k => $isVisible) { if ($isVisible) { $sources[$k]['showInLegend'] = true; } } ksort($sources); $sources = array_values($sources); return json_encode($sources); }
/** * Retrieve filepaths and timestamps for images at a specified cadence of * a given type between the specified start and end dates. * * @param object $imgIndex An ImgIndex object with access to the database * @param int $numFrames The number of frames to go into the JPX movie * * @return array List of filepaths to images to use during JPX generation * as well as a list of times for each image in the series. */ private function _queryJPXImageFramesByCadence($imgIndex, $numFrames) { $images = array(); $dates = array(); // Timer $time = toUnixTimestamp($this->_endTime); // Get nearest JP2 images to each time-step for ($i = 0; $i < $numFrames; $i++) { // Get next image $isoDate = toISOString(parseUnixTimestamp($time)); $img = $imgIndex->getDataFromDatabase($isoDate, $this->_sourceId); $filepath = HV_JP2_DIR . $img['filepath'] . '/' . $img['filename']; // Ignore redundant images if (!$images || $images[0] != $filepath) { array_unshift($images, $filepath); array_unshift($dates, toUnixTimestamp($img['date'])); } $time -= $this->_cadence; } // Add entry for start time if it isn't already included $img = $imgIndex->getDataFromDatabase($this->_startTime, $this->_sourceId); $jp2 = HV_JP2_DIR . $img['filepath'] . '/' . $img['filename']; if ($images && $images[0] != $jp2) { array_unshift($images, $jp2); array_unshift($dates, toUnixTimestamp($img['date'])); } return array($images, $dates); }
/** * Returns status information (i.e. time of most recent available data) * based on either observatory, instrument, detector or measurement. * * There are two types of queries that can be made: * * (1) instrument * * If key is set to instrument, then the time of the data source associated * with that instrument that is lagging the furthest behind is returned. * * (2) nickname * * If the key is set to nickname, then the most recent image times * are returned for all datasources, sorted by instrument. */ public function getStatus() { // Connect to database include_once HV_ROOT_DIR . '/../src/Database/ImgIndex.php'; include_once HV_ROOT_DIR . '/../src/Helper/DateTimeConversions.php'; $imgIndex = new Database_ImgIndex(); // Default to instrument-level status information if (!isset($this->_options['key'])) { $this->_options['key'] = 'instrument'; } $statuses = array(); // Case 1: instrument $instruments = $imgIndex->getDataSourcesByInstrument(); // Date format $format = 'Y-m-d H:i:s'; // Current time $now = new DateTime(); // Iterate through instruments foreach ($instruments as $inst => $dataSources) { $oldest = new DateTime('2035-01-01'); // Keep track of which datasource is the furthest behind foreach ($dataSources as $dataSource) { // Get date string for most recent image $dateStr = $imgIndex->getNewestData($dataSource['id']); // Skip data source if no images are found if (is_null($dateStr)) { continue; } // Convert to DateTime $date = DateTime::createFromFormat($format, $dateStr); // Store if older if ($date < $oldest) { $oldest = $date; } } // Get elapsed time $delta = $now->getTimestamp() - $oldest->getTimestamp(); // Add to result array if ($delta > 0) { $statuses[$inst] = array('time' => toISOString($oldest), 'level' => $this->_computeStatusLevel($delta, $inst), 'secondsBehind' => $delta); } } // Get a list of the datasources grouped by instrument $this->_printJSON(json_encode($statuses)); }