diff --git a/compass/app/Http/Controllers/Api.php b/compass/app/Http/Controllers/Api.php index 20702c5..72e2aa8 100644 --- a/compass/app/Http/Controllers/Api.php +++ b/compass/app/Http/Controllers/Api.php @@ -7,13 +7,60 @@ use Illuminate\Http\Request; use DB; use Quartz; use Log; -use DateTime; +use DateTime, DateTimeZone; class Api extends BaseController { public function query(Request $request) { + $token = $request->input('token'); + if(!$token) + return response(json_encode(['error' => 'no token provided']))->header('Content-Type', 'application/json'); + + $db = DB::table('databases')->where('read_token','=',$token)->first(); + if(!$db) + return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json'); + + $qz = new Quartz\DB(env('STORAGE_DIR').$db->name, 'r'); + + if($date=$request->input('date')) { + if($request->input('tz')) { + $tz = $request->input('tz'); + } else { + $tz = 'America/Los_Angeles'; + } + $start = DateTime::createFromFormat('Y-m-d H:i:s', $date.' 00:00:00', new DateTimeZone($tz)); + $end = DateTime::createFromFormat('Y-m-d H:i:s', $date.' 23:59:59', new DateTimeZone($tz)); + } else { + return response(json_encode(['error' => 'no date provided']))->header('Content-Type', 'application/json'); + } + + $results = $qz->queryRange($start, $end); + + $locations = []; + + foreach($results as $id=>$record) { + $record->date->format('U.u'); + $locations[] = $record->data; + } + + if($request->input('format') == 'linestring') { + + $response = array( + 'type' => 'LineString', + 'coordinates' => array() + ); + foreach($locations as $loc) { + $response['coordinates'][] = $loc->geometry->coordinates; + } + + } else { + $response = [ + 'locations' => $locations + ]; + } + return response(json_encode($response))->header('Content-Type', 'application/json'); } public function input(Request $request) { @@ -26,13 +73,15 @@ class Api extends BaseController return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json'); if(!is_array($request->input('locations'))) - return response(json_encode(['error' => 'invalid input', 'error_description' => 'parameter "locations" must be an array of location data with a "timestamp" property']))->header('Content-Type', 'application/json'); + return response(json_encode(['error' => 'invalid input', 'error_description' => 'parameter "locations" must be an array of GeoJSON data with a "timestamp" property']))->header('Content-Type', 'application/json'); $qz = new Quartz\DB(env('STORAGE_DIR').$db->name, 'w'); foreach($request->input('locations') as $loc) { - $date = DateTime::createFromFormat('U', $loc['timestamp']); - $line = $qz->add($date, $loc); + if(array_key_exists('properties', $loc) && array_key_exists('timestamp', $loc['properties'])) { + $date = DateTime::createFromFormat('U', $loc['properties']['timestamp']); + $line = $qz->add($date, $loc); + } } return response(json_encode(['result' => 'ok']))->header('Content-Type', 'application/json'); diff --git a/compass/public/assets/map.css b/compass/public/assets/map.css index 3e3d826..837a1b1 100644 --- a/compass/public/assets/map.css +++ b/compass/public/assets/map.css @@ -7,8 +7,32 @@ html, body, #map { margin-left: 26px; } +#calendar { + z-index: 100; + width: 200px; + height: calc(100% - 40px); + position: absolute; + top: 10px; + right: 10px; + border: 3px #888 solid; + background: white; + font-size: 14px; + line-height: 20px; +} +#calendar #controls { + position: absolute; + top: 0; + padding: 3px; + background: white; +} +#calendar .scroll { + overflow: scroll; + height: calc(100%); +} + table.calendar { width: 100%; + margin-bottom: 10px; } .calendar th, .calendar td { text-align: center; diff --git a/compass/public/assets/map.js b/compass/public/assets/map.js index 1c9b93a..754ed19 100644 --- a/compass/public/assets/map.js +++ b/compass/public/assets/map.js @@ -51,32 +51,33 @@ jQuery(function($){ var db_name = $("#database").data("name"); var db_token = $("#database").data("token"); - $.get("/api/query?date="+$(this).data('date')+"&tz=America/Los_Angeles&token="+db_token, function(data){ - visible_data.push(data); - visible_layers.push(L.geoJson(data, { - style: geojsonLineOptions - }).addTo(map)); - - // If the new layer is completely outside the current view, zoom the map to fit all layers - var layer = visible_layers[visible_layers.length - 1]; - var is_outside = false; - if(!map.getBounds().intersects(layer.getBounds())) { - is_outside = true; - } + $.get("/api/query?format=linestring&date="+$(this).data('date')+"&tz=America/Los_Angeles&token="+db_token, function(data){ + if(data.coordinates && data.coordinates.length > 0) { + visible_data.push(data); + visible_layers.push(L.geoJson(data, { + style: geojsonLineOptions + }).addTo(map)); + + // If the new layer is completely outside the current view, zoom the map to fit all layers + var layer = visible_layers[visible_layers.length - 1]; + var is_outside = false; + if(!map.getBounds().intersects(layer.getBounds())) { + is_outside = true; + } - if(is_outside) { - var full_bounds; - for(var i in visible_layers) { - layer = visible_layers[i]; - if(full_bounds) { - full_bounds.extend(layer.getBounds()); - } else { - full_bounds = layer.getBounds(); + if(is_outside) { + var full_bounds; + for(var i in visible_layers) { + layer = visible_layers[i]; + if(full_bounds) { + full_bounds.extend(layer.getBounds()); + } else { + full_bounds = layer.getBounds(); + } } + map.fitBounds(full_bounds); } - map.fitBounds(full_bounds); } - }); return false; diff --git a/compass/resources/views/map.blade.php b/compass/resources/views/map.blade.php index 11bb0e3..06f01b0 100644 --- a/compass/resources/views/map.blade.php +++ b/compass/resources/views/map.blade.php @@ -4,8 +4,39 @@ +
+
+ setTimeZone(new DateTimeZone('America/Los_Angeles')); + $i = clone $start; + while((int)$i->format('Y') <= (int)$end->format('Y') && (int)$i->format('M') <= (int)$end->format('M')) { + ?> + @include('partials/calendar', [ + 'year' => $i->format('Y'), + 'month' => $i->format('m'), + 'days' => $days, + 'day_name_length' => 3, + 'month_href' => null, + 'first_day' => 1, + 'pn' => [] + ]) + add(new DateInterval('P1M')); + } + ?> +
+
+
+ @endsection diff --git a/compass/resources/views/partials/calendar.blade.php b/compass/resources/views/partials/calendar.blade.php new file mode 100644 index 0000000..77f05ff --- /dev/null +++ b/compass/resources/views/partials/calendar.blade.php @@ -0,0 +1,52 @@ + +. See http://diveintomark.org/archives/2002/07/03 + @list($p, $pl) = each($pn); @list($n, $nl) = each($pn); #previous and next links, if applicable + if($p) $p = ''.($pl ? ''.$p.'' : $p).' '; + if($n) $n = ' '.($nl ? ''.$n.'' : $n).''; + $calendar = ''."\n". + '\n"; + + if($day_name_length){ #if the day names should be shown ($day_name_length > 0) + #if day_name_length is >3, the full name of the day will be printed + foreach($day_names as $d) + $calendar .= ''; + $calendar .= "\n"; + } + + if($weekday > 0) $calendar .= ''; #initial 'empty' days + for($day=1,$days_in_month=gmdate('t',$first_of_month); $day<=$days_in_month; $day++,$weekday++){ + if($weekday == 7){ + $weekday = 0; #start a new week + $calendar .= "\n"; + } + if(isset($days[$day]) and is_array($days[$day])){ + @list($link, $classes, $content) = $days[$day]; + if(is_null($content)) $content = $day; + $calendar .= '' : '>'). + ($link ? ''.$content.'' : $content).''; + } + else $calendar .= ""; + } + if($weekday != 7) $calendar .= ''; #remaining "empty" days + + echo $calendar."\n
'.$p.($month_href ? ''.$title.'' : $title).$n."
'.htmlentities($day_name_length < 4 ? substr($d,0,$day_name_length) : $d).'
 
$day 
\n";