From 57c00dfceb3547e7fbc9fffd8e85d7942d557bb5 Mon Sep 17 00:00:00 2001 From: Anton Sarukhanov <code@ant.sr> Date: Tue, 14 Jul 2015 13:30:22 -0400 Subject: [PATCH] Moved agency-specific stuff out of code and into config. --- ajax.php | 229 +++++++++--------- css/style.css | 29 +-- functions.php | 8 +- index.php | 105 ++++---- js/script.js | 650 +++++++++++++++++++++++--------------------------- 5 files changed, 482 insertions(+), 539 deletions(-) diff --git a/ajax.php b/ajax.php index 718b89b..0540de8 100644 --- a/ajax.php +++ b/ajax.php @@ -1,134 +1,127 @@ <?php /* - This file serves up data for asynchronous requests (usually as JSON). + This file serves up data for asynchronous requests (usually as JSON). */ +require_once('config.php'); +require_once('functions.php'); + if (!isset($_GET['command'])) die(); $agency = "rutgers"; if ($_GET['command'] == "vehicleLocations") { - // return a JSON array of vehicles and their locations. - - require_once('config.php'); - require_once('functions.php'); - - $db = dbc(); - - // MAX age of a bus location to return - $maxAge = 120; - - $time = 0; - if (isset($_GET['t'])) $time = $db->real_escape_string((int)$_GET['t']); - if ($time < $maxAge) $time = time() - $maxAge; - $sql = <<< V_LOC - SELECT - `id`, `title` AS `route`, `routeTag`, `dirTag`, `lat`, `lon`, `heading`, `speedKmHr` - FROM `vehicleLocations` - LEFT JOIN `routes` ON `vehicleLocations`.`routeTag` = `routes`.`tag` - WHERE `time` > '{$time}' + // return a JSON array of vehicles and their locations. + + $db = dbc(); + + // MAX age of a bus location to return + $maxAge = 120; + + $time = 0; + if (isset($_GET['t'])) $time = $db->real_escape_string((int)$_GET['t']); + if ($time < $maxAge) $time = time() - $maxAge; + $sql = <<< V_LOC + SELECT + `id`, `title` AS `route`, `routeTag`, `dirTag`, `lat`, `lon`, `heading`, `speedKmHr` + FROM `vehicleLocations` + LEFT JOIN `routes` ON `vehicleLocations`.`routeTag` = `routes`.`tag` + WHERE `time` > '{$time}' V_LOC; - $result = dbq($db, $sql); - - $locations = array(); - while($row = $result->fetch_assoc()) $locations[$row['id']] = $row; - - // predictions - $sql = <<< V_LOC - SELECT - `predictions`.`vehicle`, `stops`.`title`, `predictions`.`epochTime` - FROM `predictions` - LEFT JOIN `stops` ON `predictions`.`stopTag` = `stops`.`tag` - ORDER BY `epochTime` ASC + $result = dbq($db, $sql); + + $locations = array(); + while($row = $result->fetch_assoc()) $locations[$row['id']] = $row; + + // predictions + $sql = <<< V_LOC + SELECT + `predictions`.`vehicle`, `stops`.`title`, `predictions`.`epochTime` + FROM `predictions` + LEFT JOIN `stops` ON `predictions`.`stopTag` = `stops`.`tag` + ORDER BY `epochTime` ASC V_LOC; - $result = dbq($db, $sql); - - while($row = $result->fetch_assoc()) if (isset($locations[$row['vehicle']])) $locations[$row['vehicle']]['stops'][] = $row; - - foreach ($locations as $key => $location) { - $locations[$key]['route'] = cleanRouteName($location['route']); - $locations[$key]['stops'] = array_slice($location['stops'], 0, 8); - } - - $lastFetched = 0; - $result = dbq($db, "SELECT `time` FROM `lastChecked` WHERE `selector` = 'vehicleLocations' LIMIT 1", true); - if ($result->num_rows == 1) { - $arr = $result->fetch_array(); - $lastFetched = $arr[0]; - } - - // also return lastTime! - header("Content-type: application/json"); - echo json_encode(array( - "vehicles" => $locations, - "lastTime" => $lastFetched, - )); - + $result = dbq($db, $sql); + + while($row = $result->fetch_assoc()) if (isset($locations[$row['vehicle']])) $locations[$row['vehicle']]['stops'][] = $row; + + foreach ($locations as $key => $location) { + $locations[$key]['route'] = cleanRouteName($location['route']); + $locations[$key]['stops'] = array_slice($location['stops'], 0, 8); + } + + $lastFetched = 0; + $result = dbq($db, "SELECT `time` FROM `lastChecked` WHERE `selector` = 'vehicleLocations' LIMIT 1", true); + if ($result->num_rows == 1) { + $arr = $result->fetch_array(); + $lastFetched = $arr[0]; + } + + // also return lastTime! + header("Content-type: application/json"); + echo json_encode(array( + "vehicles" => $locations, + "lastTime" => $lastFetched, + )); + } elseif ($_GET['command'] == "routeConfig") { - // return a JSON array of routes and stops. - require_once('config.php'); - require_once('functions.php'); - - $db = dbc(); - - $sql = "SELECT `tag`, `title` FROM `routes`"; - $result = dbq($db, $sql); - $routes = array(); - while($row = $result->fetch_assoc()) $routes[$row['tag']] = $row; - - $sql = "SELECT `tag`, `title`, `lat`, `lon`, `stopId` FROM `stops`"; - $result = dbq($db, $sql); - $stops = array(); - while($row = $result->fetch_assoc()) { - $stops[$row['tag']] = $row; - $stops[$row['tag']]['routes'] = array(); - } - - $sql = "SELECT `route`, `stop` FROM `route_stops`"; - $result = dbq($db, $sql); - while($row = $result->fetch_assoc()) $stops[$row['stop']]['routes'][$row['route']] = array(); - - $sql = "SELECT `routes`.`tag`, `routes`.`title`, `stopTag`, `epochTime`, `vehicle` FROM `predictions` LEFT JOIN `routes` ON `predictions`.`routeTag` = `routes`.`tag` WHERE `routes`.`agency` = '{$agency}'"; - $result = dbq($db, $sql); - while($row = $result->fetch_assoc()) $stops[$row['stopTag']]['routes'][$row['tag']][] = array("epochTime" => $row['epochTime'], "vehicle" => $row['vehicle']); - - // post proc - foreach ($routes as $key => $route) { - $routes[$key]['title'] = cleanRouteName($route['title']); - } - $unset = array(); - foreach ($stops as $key => $stop) { - if (!in_array($key, $unset)) { - foreach ($stops as $key2 => $stop2) { - if ($key !== $key2 && $stop['title'] == $stop2['title']) { - $stops[$key]['routes'] = array_merge($stop['routes'], $stop2['routes']); - $unset[] = $key2; - } - } - } - } - foreach ($unset as $un) unset($stops[$un]); - - $lastFetched = 0; - $result = dbq($db, "SELECT `time` FROM `lastChecked` WHERE `selector` = 'routeConfig' LIMIT 1", true); - if ($result->num_rows == 1) { - $arr = $result->fetch_array(); - $lastFetched = $arr[0]; - } - - // also return lastTime! - header("Content-type: application/json"); - echo json_encode(array( - "routes" => $routes, - "stops" => $stops, - "lastTime" => $lastFetched, - )); -} + // return a JSON array of routes and stops. + + $db = dbc(); + + $sql = "SELECT `tag`, `title` FROM `routes`"; + $result = dbq($db, $sql); + $routes = array(); + while($row = $result->fetch_assoc()) $routes[$row['tag']] = $row; + + $sql = "SELECT `tag`, `title`, `lat`, `lon`, `stopId` FROM `stops`"; + $result = dbq($db, $sql); + $stops = array(); + while($row = $result->fetch_assoc()) { + $stops[$row['tag']] = $row; + $stops[$row['tag']]['routes'] = array(); + } -function cleanRouteName($name) { - if ($name == "New Brunsquick 1 Shuttle") $name = "NB 1"; - else if ($name == "New Brunsquick 2 Shuttle") $name = "NB 2"; - return $name; + $sql = "SELECT `route`, `stop` FROM `route_stops`"; + $result = dbq($db, $sql); + while($row = $result->fetch_assoc()) $stops[$row['stop']]['routes'][$row['route']] = array(); + + $sql = "SELECT `routes`.`tag`, `routes`.`title`, `stopTag`, `epochTime`, `vehicle` FROM `predictions` LEFT JOIN `routes` ON `predictions`.`routeTag` = `routes`.`tag` WHERE `routes`.`agency` = '{$agency}'"; + $result = dbq($db, $sql); + while($row = $result->fetch_assoc()) $stops[$row['stopTag']]['routes'][$row['tag']][] = array("epochTime" => $row['epochTime'], "vehicle" => $row['vehicle']); + + // post proc + foreach ($routes as $key => $route) { + $routes[$key]['title'] = cleanRouteName($route['title']); + } + $unset = array(); + foreach ($stops as $key => $stop) { + if (!in_array($key, $unset)) { + foreach ($stops as $key2 => $stop2) { + if ($key !== $key2 && $stop['title'] == $stop2['title']) { + $stops[$key]['routes'] = array_merge($stop['routes'], $stop2['routes']); + $unset[] = $key2; + } + } + } + } + foreach ($unset as $un) unset($stops[$un]); + + $lastFetched = 0; + $result = dbq($db, "SELECT `time` FROM `lastChecked` WHERE `selector` = 'routeConfig' LIMIT 1", true); + if ($result->num_rows == 1) { + $arr = $result->fetch_array(); + $lastFetched = $arr[0]; + } + + // also return lastTime! + header("Content-type: application/json"); + echo json_encode(array( + "routes" => $routes, + "stops" => $stops, + "lastTime" => $lastFetched, + )); } + ?> diff --git a/css/style.css b/css/style.css index de51d53..c47f4db 100644 --- a/css/style.css +++ b/css/style.css @@ -17,8 +17,6 @@ div#topBar { display: table; width: 100%; z-index: 1; - - background-color: #222; border-top: 2px solid #555; border-bottom: 2px solid #555; @@ -240,14 +238,15 @@ a.tooltip { screen and (-webkit-min-device-pixel-ratio: 1.5), screen and (-moz-min-device-pixel-ratio: 1.5), screen and (min-device-pixel-ratio: 1.5) { + html { + font-size: 0.5em; + line-height: 0.5em; + } div#routeselector { width: 100%; - min-height: 56px; - line-height:56px; } - + div#routeselector .bar { - font-size: 20px; /* 1em */ width: 10em; height: 1em; position: relative; @@ -255,22 +254,12 @@ screen and (min-device-pixel-ratio: 1.5) { } div#routeselector .routeBtn { - font-size: 1.5em; margin-bottom: 0px; } - + div#lastUpdate { display:none !important; } - - div#locationButton { - width: 64px; - height: 64px; - background-size: 64px 64px; - } - - .leaflet-popup-content { - font-size: 2em; - } - -} \ No newline at end of file + + +} diff --git a/functions.php b/functions.php index 3c8ec2a..cc4ae5e 100644 --- a/functions.php +++ b/functions.php @@ -25,9 +25,15 @@ function dbq($db, $query, $dieOnError = false) { } else return $result; } +function cleanRouteName($name) { + if ($name == "New Brunsquick 1 Shuttle") $name = "NB 1"; + else if ($name == "New Brunsquick 2 Shuttle") $name = "NB 2"; + return $name; +} + function sanitize($string) { $pattern = "/[^\w.-\s]/"; return preg_replace($pattern,"",$string); } -?> \ No newline at end of file +?> diff --git a/index.php b/index.php index b7fa9bb..742f4a8 100644 --- a/index.php +++ b/index.php @@ -1,56 +1,63 @@ +<?php +require_once('config.php'); +?> <!doctype html> <html lang="en"> <head> - <title>RU Bus Map</title> - <meta name="description" content="Real-time animated map of the bus system at Rutgers University New Brunswick."> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width; initial-scale=0.5; maximum-scale=0.5; user-scalable=no;" /> - <meta name="apple-mobile-web-app-capable" content="yes" /> - <meta name="apple-mobile-web-app-status-bar-style" content="black" /> - <link href="css/leaflet.css" rel="stylesheet" /> - <link href="css/leaflet.label.css" rel="stylesheet" /> - <link href="css/style.css" rel="stylesheet" /> - <?php if (isset($_GET['embed'])) { ?> - <link href="css/embed.css" rel="stylesheet" /> - <?php } ?> - <script src="js/fastclick.js"></script> - <script src="js/jquery.min.js"></script> - <script src="js/leaflet.js"></script> - <script src="js/leaflet.marker.rotate.js"></script> - <script src="js/leaflet.label.js"></script> - <script src="js/jquery.raptorize.js"></script> - <script src="js/script.js"></script> - <?php - if (isset($_GET['centerLat']) && isset($_GET['centerLon'])) { - $lat = doubleval($_GET['centerLat']); - $lon = doubleval($_GET['centerLon']); - if (isset($_GET['zoom'])) $zoom = intval($_GET['zoom']); - else $zoom = 'undefined'; - echo '<script>$(document).ready(function(){ window.map.setView(['.$lat.','.$lon.'], '.$zoom.'); });</script>'; - } - ?> - + <title><?php echo $cfg['agency']['name']; ?></title> + <meta name="description" content=<?php echo json_encode($cfg['agency']['description']); ?>> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; user-scalable=no;" /> + <meta name="apple-mobile-web-app-capable" content="yes" /> + <meta name="apple-mobile-web-app-status-bar-style" content="black" /> + <link href="css/leaflet.css" rel="stylesheet" /> + <link href="css/leaflet.label.css" rel="stylesheet" /> + <link href="css/style.css" rel="stylesheet" /> +<?php if (isset($_GET['embed'])): ?> + <link href="css/embed.css" rel="stylesheet" /> +<?php endif; ?> + <script> + window.agency = <?php echo json_encode($cfg['agency']['name']); ?>; + window.busIconUrl = <?php echo json_encode($cfg['agency']['busIconUrl'], JSON_UNESCAPED_SLASHES); ?>; + </script> + <script src="js/fastclick.js"></script> + <script src="js/jquery.min.js"></script> + <script src="js/leaflet.js"></script> + <script src="js/leaflet.marker.rotate.js"></script> + <script src="js/leaflet.label.js"></script> + <script src="js/jquery.raptorize.js"></script> + <script src="js/script.js"></script> + <script> + $(document).ready(function() { + // setup and create tile layer on map + L.tileLayer(<?php echo json_encode($cfg['agency']['tileUrl'], JSON_UNESCAPED_SLASHES); ?>, { + subdomains: <?php echo json_encode($cfg['agency']['tileSubdomains']); ?>, + tileset: <?php echo json_encode($cfg['agency']['tileset']); ?>, + errorTileUrl: <?php echo json_encode($cfg['agency']['errorTileUrl'], JSON_UNESCAPED_SLASHES); ?>, + attribution: <?php echo json_encode($cfg['agency']['attribution'], JSON_UNESCAPED_SLASHES); ?>, + detectRetina: true, + }).addTo(window.map); + }); + </script> + <?php + // Set initial lat/lon if requested. + if (isset($_GET['centerLat']) && isset($_GET['centerLon'])) { + // sanitize user inputs by converting them to doubles/ints. + $lat = doubleval($_GET['centerLat']); + $lon = doubleval($_GET['centerLon']); + if (isset($_GET['zoom'])) $zoom = intval($_GET['zoom']); + else $zoom = 'undefined'; + echo '<script>$(document).ready(function(){ window.map.setView(['.$lat.','.$lon.'], '.$zoom.'); });</script>'; + } + ?> </head> <body> - <div id="container"> - <div id="topBar"> - <div id="routeselector">Please enable Javascript to use this map.</div> - </div> - <div id="map"></div> - <div id="locationButton"></div> - </div> - <script> - var _paq = _paq || []; - _paq.push(["trackPageView"]); - _paq.push(["enableLinkTracking"]); - - (function() { - var u=(("https:" == document.location.protocol) ? "https" : "http") + "://analytics.ant.sr/"; - _paq.push(["setTrackerUrl", u+"piwik.php"]); - _paq.push(["setSiteId", "3"]); - var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript"; - g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s); - })(); - </script> + <div id="container"> + <div id="topBar"> + <div id="routeselector">Please enable Javascript to use this map.</div> + </div> + <div id="map"></div> + <div id="locationButton"></div> + </div> </body> </html> diff --git a/js/script.js b/js/script.js index 67d4989..5121120 100644 --- a/js/script.js +++ b/js/script.js @@ -1,390 +1,338 @@ $(document).ready(function() { - - // loading animation - $("#routeselector").html('<div class="loading bar"><i class="sphere"></i></div>'); - $("#routeselector .loading.bar").attr("data-text","Loading map"); - // options - var updateDelay = 10776; - - // setup map - var zoom = 14; - var center = [40.5, -74.45]; - var bounds = [ - [40.400, -74.65], // sw - [40.600, -74.25], // ne - ]; - var mapDivID = "map"; - var mapOptions = { - minZoom: 14, - maxZoom: 18, - zoomControl: false, - }; - var boundsOptions = { - 'animate': false, - 'reset': true, - }; - - // fastclick - $(function() { - FastClick.attach(document.body); - }); - - // create map - window.map = L.map(mapDivID, mapOptions).setView(center, zoom).setMaxBounds(bounds, boundsOptions); + // loading animation + $("#routeselector").html('<div class="loading bar"><i class="sphere"></i></div>'); + $("#routeselector .loading.bar").attr("data-text","Loading map"); - // setup and create tile layer on map - var text = '<a href="https://ant.sr">ant.sr</a> | <div id="raptor"></div><br>' - + '<strong>Not affiliated with <a href="http://www.rutgers.edu">Rutgers</a>.</strong><br>' - + 'Bus data © <a href="http://www.rutgers.edu/">Rutgers University</a><br>' - + 'Map data © <a href="http://osm.org/copyright">OSM contributors</a>'; - - L.tileLayer('http://{s}.tiles.antsar-static.com/{tileset}/{z}/{x}/{y}.png', { - subdomains: ['a', 'b', 'c', 'd', 'e'], - tileset: 'rutgers-black', - errorTileUrl: 'http://tiles.antsar-static.com/generic/tile-blank-black.png', - attribution: text, - }).addTo(window.map); + // options + var updateDelay = 10776; - // init UI elements - window.busMarkers = {}; - window.stopMarkers = {}; - window.polylines = []; - - // init data storage vars - window.userLocation = false; - - // event listener for successful gps geolocation - window.map.on('locationfound', function(e){ - var dotsize = 20; - if (window.devicePixelRatio > 1) dotsize = 35; // retina - showBlueDot(e.latlng, e.accuracy / 2, dotsize); - }); - - // event listener for gps geolocation failure - window.map.on('locationerror', function(e){ - alert("Access to your current location was refused. To use the Current Location feature in the future, you may need to reset your browser's location warnings."); - }); - - // event listener for beginning of dragging. - window.map.on('dragstart', function(e){ - // cancel geolocation on drag. - if (window.userLocation == true) stopUserLocation(); - }); - - // event listener for opening popup./ - /* - window.map.on('popupopen', function(e){ - window.popup = e.popup.options; - var zoom = window.map.getZoom; - if (zoom < 16) zoom = 16 - //window.map.setView(e.popup._latlng, zoom); - }); - */ - - - // Bind user location getting to the user location getting button - $("#locationButton").click(function() { - if (window.userLocation == false) { - startUserLocation(); - } else { - stopUserLocation(); - } - }); - - $("#routeselector .loading.bar").attr("data-text","Loading routes"); - - // get routes and initialize route buttons. this is awkward; should refactor. - getRouteConfig(function(routes, stops) { - makeRouteButtons(routes); - }); - - // main app loop - function mainLoop() { - getRouteConfig(function(routes, stops) { - updateMapBusStops(routes,stops); - getVehicles(function(vehicles) { - updateMapVehicles(routes, vehicles); - removeStaleMarkers(); - updateRouteButtons(vehicles); - }); - }); - } - mainLoop(); - window.setInterval(mainLoop, updateDelay); - - $('#raptor').raptorize(); + // setup map + var zoom = 14; + var center = [40.5, -74.45]; + var bounds = [ + [40.400, -74.65], // sw + [40.600, -74.25], // ne + ]; + var mapDivID = "map"; + var mapOptions = { + minZoom: 14, + maxZoom: 18, + zoomControl: false, + }; + var boundsOptions = { + 'animate': false, + 'reset': true, + }; + + // fastclick + $(function() { + FastClick.attach(document.body); + }); + + // create map + window.map = L.map(mapDivID, mapOptions).setView(center, zoom).setMaxBounds(bounds, boundsOptions); + + // init UI elements + window.busMarkers = {}; + window.stopMarkers = {}; + window.polylines = []; + + // init data storage vars + window.userLocation = false; + + // event listener for successful gps geolocation + window.map.on('locationfound', function(e){ + var dotsize = 20; + if (window.devicePixelRatio > 1) dotsize = 35; // retina + showBlueDot(e.latlng, e.accuracy / 2, dotsize); + }); + + // event listener for gps geolocation failure + window.map.on('locationerror', function(e){ + alert("Access to your current location was refused by your browser. Please reset your location warnings to use this feature."); + }); + + // event listener for beginning of dragging. + window.map.on('dragstart', function(e){ + // cancel geolocation on drag. + if (window.userLocation == true) stopUserLocation(); + }); + + // Bind user location getting to the user location getting button + $("#locationButton").click(function() { + if (window.userLocation == false) { + startUserLocation(); + } else { + stopUserLocation(); + } + }); + + $("#routeselector .loading.bar").attr("data-text","Loading routes"); + + // get routes and initialize route buttons. this is awkward; should refactor. + getRouteConfig(window.agency, function(routes, stops) { + makeRouteButtons(routes); + }); + + // main app loop + function mainLoop() { + getRouteConfig(window.agency, function(routes, stops) { + updateMapBusStops(routes,stops); + getVehicles(window.agency, function(vehicles) { + updateMapVehicles(routes, vehicles, window.busIconUrl); + removeStaleMarkers(); + updateRouteButtons(vehicles); + }); + }); + } + mainLoop(); + window.setInterval(mainLoop, updateDelay); + + $('#raptor').raptorize(); }); function startUserLocation() { - $("#locationButton").css("background-image", "url(img/crosshair-blue.png)"); - window.map.locate({ - watch: true, - setView: true, - maxZoom: 18, - }); - window.userLocation = true; + $("#locationButton").css("background-image", "url(img/crosshair-blue.png)"); + window.map.locate({ + watch: true, + setView: true, + maxZoom: 18, + }); + window.userLocation = true; } function stopUserLocation() { - var blueDotFadeTimeSeconds = 15; - window.map.stopLocate(); - window.userLocation = false; - hideBlueDot(15); - $("#locationButton").css("background-image", "url(img/crosshair.png)"); + var blueDotFadeTimeSeconds = 15; + window.map.stopLocate(); + window.userLocation = false; + hideBlueDot(15); + $("#locationButton").css("background-image", "url(img/crosshair.png)"); } function showBlueDot(latlng, radius, size) { - var markerIcon = L.icon({ - iconUrl: 'img/bluedot.png', - iconSize: [size,size], - }); - if (window.userLocationMarker == undefined) { - window.userLocationMarker = L.marker(latlng, {icon: markerIcon}).addTo(map); - } else { - window.userLocationMarker.setLatLng(latlng); - } + var markerIcon = L.icon({ + iconUrl: 'img/bluedot.png', + iconSize: [size,size], + }); + if (window.userLocationMarker == undefined) { + window.userLocationMarker = L.marker(latlng, {icon: markerIcon}).addTo(map); + } else { + window.userLocationMarker.setLatLng(latlng); + } - if (radius < 25) radius = 1; // no tiny circles + if (radius < 25) radius = 1; // no tiny circles - if (window.userLocationCircle == undefined) { - window.userLocationCircle = L.circle(latlng, radius).addTo(map); - } else { - window.userLocationCircle.setLatLng(latlng).setRadius(radius); - } + if (window.userLocationCircle == undefined) { + window.userLocationCircle = L.circle(latlng, radius).addTo(map); + } else { + window.userLocationCircle.setLatLng(latlng).setRadius(radius); + } } function hideBlueDot(userLocationFadeTime) { - var fps = 30; - var hideBlueDotFrames = userLocationFadeTime * fps; - var delay = Math.round(1000 / fps); - window.hideBlueDotTimers = []; - var frame = 0; - function drawFrames( frame, delay, totalFrames ) { - var opacity = 1 - frame/totalFrames; - window.userLocationMarker.setOpacity(opacity); - if (totalFrames > frame) { - window.hideBlueDotTimers.push(setTimeout(function() { - drawFrames(frame+1, delay, totalFrames); - }, delay)); - } else { - if (window.userLocationMarker != undefined) { - window.map.removeLayer(window.userLocationMarker); - delete window.userLocationMarker; - } - } - } - if (window.userLocationCircle != undefined) window.map.removeLayer(window.userLocationCircle); - delete window.userLocationCircle; - if (userLocationMarker) drawFrames(frame, delay, hideBlueDotFrames); + var fps = 60; + var hideBlueDotFrames = userLocationFadeTime * fps; + var delay = Math.round(1000 / fps); + window.hideBlueDotTimers = []; + var frame = 0; + function drawFrames( frame, delay, totalFrames ) { + var opacity = 1 - frame/totalFrames; + window.userLocationMarker.setOpacity(opacity); + if (totalFrames > frame) { + window.hideBlueDotTimers.push(setTimeout(function() { + drawFrames(frame+1, delay, totalFrames); + }, delay)); + } else { + if (window.userLocationMarker != undefined) { + window.map.removeLayer(window.userLocationMarker); + delete window.userLocationMarker; + } + } + } + if (window.userLocationCircle != undefined) window.map.removeLayer(window.userLocationCircle); + delete window.userLocationCircle; + if (userLocationMarker) drawFrames(frame, delay, hideBlueDotFrames); } -function getRouteConfig(grc_callback) { - $.ajax({ - url: "ajax.php?command=routeConfig&a=rutgers", - type: 'GET', - success: function(data) { - if (grc_callback != undefined) grc_callback(data['routes'], data['stops']); - }, - fail: function() { - alert("Could not get routes from NextBus. Please try again later."); - } - }); +function getRouteConfig(agency, grc_callback) { + $.ajax({ + url: "ajax.php?command=routeConfig&a=" + agency, + type: 'GET', + success: function(data) { + if (grc_callback != undefined) grc_callback(data['routes'], data['stops']); + }, + fail: function() { + alert("Could not get routes. Please try again later."); + } + }); } -function getVehicles(gv_callback) { - var time = 0; - if (window.getVehicles_lastTime != undefined) time = window.getVehicles_lastTime; - $.ajax({ - url: "ajax.php?command=vehicleLocations&a=rutgers&t=" + time, - type: 'GET', - success: function(data) { - window.getVehicles_lastTime = data['lastTime']; - // window.vehicles = data['vehicles']; - if (gv_callback != undefined) gv_callback(data['vehicles']); - }, - fail: function() { - alert("Could not get vehicle locations from NextBus. Please try again later."); - } - }); +function getVehicles(agency, gv_callback) { + var time = 0; + if (window.getVehicles_lastTime != undefined) time = window.getVehicles_lastTime; + $.ajax({ + url: "ajax.php?command=vehicleLocations&a=" + agency + "&t=" + time, + type: 'GET', + success: function(data) { + window.getVehicles_lastTime = data['lastTime']; + // window.vehicles = data['vehicles']; + if (gv_callback != undefined) gv_callback(data['vehicles']); + }, + fail: function() { + alert("Could not get vehicle locations. Please try again later."); + } + }); } -function updateMapBusStops(routesIn,stops,maxPredictions) { - if (window.map != undefined && stops != undefined) { - for (i in stops) { - if (stops[i]['lat'] != undefined && stops[i]['lon'] != undefined) { - var markerIcon = L.icon({ - iconUrl: 'img/star.png', - iconSize: [25,24], - }); - var routes = []; - for (j in stops[i]['routes']) { - var string = "<strong>"+routesIn[j]['title']+"</strong>" + ": "; - for (k in stops[i]['routes'][j]) { - var sec = Math.floor((stops[i]['routes'][j][k]['epochTime'] - (new Date).getTime()) / 1000); - var min = Math.floor(sec / 60); - var sec = sec % 60; - string += '<a class="tooltip prediction" title="Bus #'+stops[i]['routes'][j][k]['vehicle']+'">' + min + "</a>, "; - } - if (string != "<strong>"+routesIn[j]['title']+"</strong>" + ": ") { - string = string.substring(0, string.length-2); - routes.push(string); - } - } - if (routes.length == 0) var routeList = "<div class='centered em'>no predictions</div>"; - else var routeList = routes.sort().join("<br>") - var popup = '<div class="title">'+stops[i]['title']+'</div>' + routeList; - if (window.stopMarkers[stops[i]['tag']] == undefined) { - var markerOpts = { - icon: markerIcon, - title: stops[i]['title'], - opacity: 1, - riseOnHover: true, - zIndexOffset: -1000, - riseOffset: 1500, - }; - var popupOpts = { - closeButton: false, - keepInView: true, - }; - window.stopMarkers[stops[i]['tag']] = L.marker([stops[i]['lat'], stops[i]['lon']], markerOpts).addTo(window.map).bindPopup(popup, popupOpts); - } else { - window.stopMarkers[stops[i]['tag']].setLatLng([stops[i]['lat'], stops[i]['lon']]).setPopupContent(popup); - } - } - } - } +function updateMapBusStops(routesIn,stops,maxPredictions) { + if (window.map != undefined && stops != undefined) { + for (i in stops) { + if (stops[i]['lat'] != undefined && stops[i]['lon'] != undefined) { + var markerIcon = L.icon({ + iconUrl: 'img/star.png', + iconRetinaUrl: 'img/star@2x.png', + iconSize: [25,24], + }); + var routes = []; + for (j in stops[i]['routes']) { + var string = "<strong>"+routesIn[j]['title']+"</strong>" + ": "; + for (k in stops[i]['routes'][j]) { + var sec = Math.floor((stops[i]['routes'][j][k]['epochTime'] - (new Date).getTime()) / 1000); + var min = Math.floor(sec / 60); + var sec = sec % 60; + string += '<a class="tooltip prediction" title="Bus #'+stops[i]['routes'][j][k]['vehicle']+'">' + min + "</a>, "; + } + if (string != "<strong>"+routesIn[j]['title']+"</strong>" + ": ") { + string = string.substring(0, string.length-2); + routes.push(string); + } + } + if (routes.length == 0) var routeList = "<div class='centered em'>no predictions</div>"; + else var routeList = routes.sort().join("<br>") + var popup = '<div class="title">'+stops[i]['title']+'</div>' + routeList; + if (window.stopMarkers[stops[i]['tag']] == undefined) { + var markerOpts = { + icon: markerIcon, + title: stops[i]['title'], + opacity: 1, + riseOnHover: true, + zIndexOffset: -1000, + riseOffset: 1500, + }; + var popupOpts = { + closeButton: false, + keepInView: true, + }; + window.stopMarkers[stops[i]['tag']] = L.marker([stops[i]['lat'], stops[i]['lon']], markerOpts).addTo(window.map).bindPopup(popup, popupOpts); + } else { + window.stopMarkers[stops[i]['tag']].setLatLng([stops[i]['lat'], stops[i]['lon']]).setPopupContent(popup); + } + } + } + } } function makeRouteButtons(routes) { - if (window.map != undefined && routes != undefined) { - $("#routeselector").append('<button class="routeBtn routeBtn-=allRoutes" data-selected="false" data-route="allroutes">All</button>'); - for (i in routes) { - $("#routeselector").append('<button class="routeBtn" data-selected="true" data-route="'+i+'">'+routes[i]['title']+'</button>'); - } - $("#routeselector .routeBtn").hide(); - $('#routeselector').on("click", ".routeBtn", function(e) { - if ($(this).attr('data-route') == "allroutes") { - $(this).siblings().click(); - } else { - if ($(this).attr('data-selected') == 'true') { - // hide this route - for (i in window.busMarkers[$(this).attr('data-route')]) { - window.busMarkers[$(this).attr('data-route')][i].setOpacity(0); - } - $(this).attr('data-selected', 'false'); - } else { - // show this route - for (i in window.busMarkers[$(this).attr('data-route')]) { - window.busMarkers[$(this).attr('data-route')][i].setOpacity(1); - } - $(this).attr('data-selected', 'true'); - } - } - }); - } + if (window.map != undefined && routes != undefined) { + $("#routeselector").append('<button class="routeBtn routeBtn-=allRoutes" data-selected="false" data-route="allroutes">All</button>'); + for (i in routes) { + $("#routeselector").append('<button class="routeBtn" data-selected="true" data-route="'+i+'">'+routes[i]['title']+'</button>'); + } + $("#routeselector .routeBtn").hide(); + $('#routeselector').on("click", ".routeBtn", function(e) { + if ($(this).attr('data-route') == "allroutes") { + $(this).siblings().click(); + } else { + if ($(this).attr('data-selected') == 'true') { + // hide this route + for (i in window.busMarkers[$(this).attr('data-route')]) { + window.busMarkers[$(this).attr('data-route')][i].setOpacity(0); + } + $(this).attr('data-selected', 'false'); + } else { + // show this route + for (i in window.busMarkers[$(this).attr('data-route')]) { + window.busMarkers[$(this).attr('data-route')][i].setOpacity(1); + } + $(this).attr('data-selected', 'true'); + } + } + }); + } } function updateRouteButtons(vehicles) { - if (window.map != undefined) { - visibleRoutes = {}; - for (i in window.busMarkers) { - for (j in window.busMarkers[i]) { - visibleRoutes[i] = true; - } - } - if ($("#routeselector .loading").length > 0) $("#routeselector .loading").remove(); - $("#routeselector .routeBtn").not("[data-route='allroutes']").each(function() { - if (visibleRoutes[$(this).attr('data-route')] == undefined && $(this).is(":visible") == true) $(this).hide(); - else if (visibleRoutes[$(this).attr('data-route')] == true && $(this).is(":visible") == false) $(this).show(); - }); - if ($("#routeselector .routeBtn:visible").length > 0 && $("#routeselector .routeBtn[data-route='allroutes']").is(":visible") == false) { - $("#routeselector .routeBtn[data-route='allroutes']").show(); - } - } + if (window.map != undefined) { + visibleRoutes = {}; + for (i in window.busMarkers) { + for (j in window.busMarkers[i]) { + visibleRoutes[i] = true; + } + } + if ($("#routeselector .loading").length > 0) $("#routeselector .loading").remove(); + $("#routeselector .routeBtn").not("[data-route='allroutes']").each(function() { + if (visibleRoutes[$(this).attr('data-route')] == undefined && $(this).is(":visible") == true) $(this).hide(); + else if (visibleRoutes[$(this).attr('data-route')] == true && $(this).is(":visible") == false) $(this).show(); + }); + if ($("#routeselector .routeBtn:visible").length > 0 && $("#routeselector .routeBtn[data-route='allroutes']").is(":visible") == false) { + $("#routeselector .routeBtn[data-route='allroutes']").show(); + } + } } -function updateMapVehicles(routes,vehicles) { - if (window.map != undefined) { - for (i in vehicles) { - - if (window.busMarkers[vehicles[i]['routeTag']] == undefined) { - window.busMarkers[vehicles[i]['routeTag']] = {}; - } +function updateMapVehicles(routes, vehicles, busIconUrl) { + if (window.map != undefined) { + for (i in vehicles) { + if (window.busMarkers[vehicles[i]['routeTag']] == undefined) { + window.busMarkers[vehicles[i]['routeTag']] = {}; + } - var stops = []; - for (j in vehicles[i]['stops']) { - var sec = Math.floor((vehicles[i]['stops'][j]['epochTime'] - (new Date).getTime()) / 1000); - var min = Math.floor(sec / 60); - var sec = sec % 60; - stops.push("<span class='prediction'>" + min + '</span> ' + vehicles[i]['stops'][j]['title'] ); - } - var stopList = stops.join("<br>") - label = vehicles[i]['route']; - popup = ""; - popup += "<div class='title'>" + label + "</div>"; - popup += stopList; - popup += "<div class='footer'>Bus #" + vehicles[i]['id'] + "</div>"; - popup += ""; - if (window.busMarkers[vehicles[i]['routeTag']][i] == undefined) { + var stops = []; + for (j in vehicles[i]['stops']) { + var sec = Math.floor((vehicles[i]['stops'][j]['epochTime'] - (new Date).getTime()) / 1000); + var min = Math.floor(sec / 60); + var sec = sec % 60; + stops.push("<span class='prediction'>" + min + '</span> ' + vehicles[i]['stops'][j]['title'] ); + } + var stopList = stops.join("<br>") + label = vehicles[i]['route']; + popup = ""; + popup += "<div class='title'>" + label + "</div>"; + popup += stopList; + popup += "<div class='footer'>Bus #" + vehicles[i]['id'] + "</div>"; + popup += ""; + if (window.busMarkers[vehicles[i]['routeTag']][i] == undefined) { - window.busMarkers[vehicles[i]['routeTag']][i] = L.marker([vehicles[i]['lat'], vehicles[i]['lon']], { - icon: L.icon({ - iconUrl: 'https://rutgers.antsar-static.com/img/bus.png', - iconSize: [21,25], - iconAnchor: [10,12], - }), - iconAngle: vehicles[i]['heading'], - }).bindLabel(label, { - noHide: true, - direction: 'right', - className: 'busLabel', - }).bindPopup(popup).addTo(window.map); - } else { - window.busMarkers[vehicles[i]['routeTag']][i].setLatLng([vehicles[i]['lat'], vehicles[i]['lon']]).setPopupContent(popup).setIconAngle(vehicles[i]['heading']); - } - window.busMarkers[vehicles[i]['routeTag']][i].lastUpdated = (new Date).getTime(); - - } - } + window.busMarkers[vehicles[i]['routeTag']][i] = L.marker([vehicles[i]['lat'], vehicles[i]['lon']], { + icon: L.icon({ + iconUrl: busIconUrl, + iconSize: [21,25], + iconAnchor: [10,12], + }), + iconAngle: vehicles[i]['heading'], + }).bindLabel(label, { + noHide: true, + direction: 'right', + className: 'busLabel', + }).bindPopup(popup).addTo(window.map); + } else { + window.busMarkers[vehicles[i]['routeTag']][i].setLatLng([vehicles[i]['lat'], vehicles[i]['lon']]).setPopupContent(popup).setIconAngle(vehicles[i]['heading']); + } + window.busMarkers[vehicles[i]['routeTag']][i].lastUpdated = (new Date).getTime(); + } + } } function removeStaleMarkers(staleTime) { - if (staleTime == undefined) staleTime = 60 * 1000; // 60 seconds = dead bus - for (i in window.busMarkers) { - for (j in window.busMarkers[i]) { - if (window.busMarkers[i][j].lastUpdated < (new Date).getTime() - staleTime) { - window.map.removeLayer(window.busMarkers[i][j]); - delete window.busMarkers[i][j]; - } - } - } -} - -function cleanRouteName(route) { - if (route == "New Brunsquick 1 Shuttle") route = "NB 1"; - else if (route == "New Brunsquick 2 Shuttle") route = "NB 2"; - return route; -} - - -function closeEnough(arg1, arg2, decimalPlacesAccuracy) { - var x = Math.pow(10,decimalPlacesAccuracy); - return (Math.floor(arg1 * x) / x == Math.floor(arg2 * x) / x); -} - -function sameBusStop(pos1, pos2) { - var acc = 3; // up to 110 meters - if (closeEnough(pos1['lat'], pos2['lat'], acc) && closeEnough(pos1['lon'], pos2['lon'], acc)) return true; - return false; -} - -function ol( object ) { - var length = 0; - for( var key in object ) { - if( object.hasOwnProperty(key) ) { - ++length; + if (staleTime == undefined) staleTime = 60 * 1000; // 60 seconds = dead bus + for (i in window.busMarkers) { + for (j in window.busMarkers[i]) { + if (window.busMarkers[i][j].lastUpdated < (new Date).getTime() - staleTime) { + window.map.removeLayer(window.busMarkers[i][j]); + delete window.busMarkers[i][j]; + } } } - return length; -}; +} + -- GitLab