From 1c2b42bbfa6d7f87853937bae50ea054c61c095c Mon Sep 17 00:00:00 2001 From: Anton Sarukhanov <code@ant.sr> Date: Fri, 15 Apr 2016 23:16:02 -0400 Subject: [PATCH] Embed Predictions works now. --- app.py | 9 ++- static/css/map.css | 20 ++---- static/css/predictions.css | 28 ++++++-- static/js/map.js | 6 +- static/js/predictions.js | 128 ++++++++++++++++++++++--------------- templates/modal-embed.html | 7 +- templates/predictions.html | 5 +- 7 files changed, 126 insertions(+), 77 deletions(-) diff --git a/app.py b/app.py index e52923e..85dbbbc 100644 --- a/app.py +++ b/app.py @@ -38,7 +38,7 @@ def map_embed(mode): if not mode or mode == "m": return render_template('map.html', agency=agency, config=app.config, embed=True) elif mode == "p": - return render_template('predictions.html', agency=agency, config=app.config) + return render_template('predictions.html', agency=agency, config=app.config, embed=True) @app.route('/ajax') def ajax(): @@ -106,6 +106,7 @@ def ajax(): def predictions(): """ Serve arrival predictions only. """ from models import Prediction + stops = request.args.get('stops') now = datetime.now() p_inner = db.session.query(Prediction.vehicle, Prediction.stop_id, db.func.max(Prediction.api_call_id).label("api_call_id"))\ @@ -117,7 +118,11 @@ def ajax(): p_inner.c.stop_id == Prediction.stop_id )).filter( Agency.tag==agency_tag, - Prediction.prediction >= now)\ + Prediction.prediction >= now) + if stops: + predictions = predictions.filter( + Prediction.stop_id.in_(stops.split(','))) + predictions = predictions\ .group_by(Prediction.id, Prediction.vehicle, Prediction.stop_id)\ .all() return { diff --git a/static/css/map.css b/static/css/map.css index 1f72df1..53904d4 100644 --- a/static/css/map.css +++ b/static/css/map.css @@ -160,11 +160,13 @@ fieldset legend ~ label { box-sizing: border-box; border: 2px solid #888; position: absolute; - width: 80%; + top: 50%; left: 10%; - top: 7.5%; + width: 80%; + transform: translateY(-50%); padding: 1em; - max-height: 80%; + max-height: 100%; + margin: 0 auto; overflow: auto; z-index: 2000; } @@ -221,20 +223,8 @@ body.embed .embed-only { .modal { width: 100%; left: 0; - top: 10%; border-radius: 0; border-left: none; border-right: none; } } - -@media all and (max-height: 400px) { - .modal { - max-height: 100%; - height: 100%; - top: 0; - border-radius: 0; - border-top: none; - border-bottom: none; - } -} diff --git a/static/css/predictions.css b/static/css/predictions.css index 5c9174a..82724f4 100644 --- a/static/css/predictions.css +++ b/static/css/predictions.css @@ -1,5 +1,25 @@ -#predictions { - width: 100%; - height: 1em; - background-color: #f00; +body { + margin: 0; + padding: .4em; + background-color: #444; + color: #fff; + font-family: sans-serif; } +#predictions header { + text-align: center; + font-weight: bold; + text-align: center; +} +#predictions p { + +} +#predictions .prediction.lt1min { + color: #f00; +} +#predictions .prediction.lt2mins { + color: #f80; +} +#predictions .prediction.lt5mins { + color: #ff0; +} + diff --git a/static/js/map.js b/static/js/map.js index 607a20d..8fb1205 100644 --- a/static/js/map.js +++ b/static/js/map.js @@ -409,10 +409,12 @@ BusMap.Map = function(opts) { function zoomShowHide() { var zoom = that.leaflet.getZoom(); if (that.vehicleMarkersGroup) { - if (zoom >= that.zoomShowVehicles && !(that.leaflet.hasLayer(that.vehicleMarkersGroup))) { + if (zoom >= that.zoomShowVehicles + && !(that.leaflet.hasLayer(that.vehicleMarkersGroup))) { that.leaflet.addLayer(that.vehicleMarkersGroup); if (!that.opts.embed) $('#msg-zoomForVehicles').hide(); - } else if (zoom < that.zoomShowVehicles && that.leaflet.hasLayer(that.vehicleMarkersGroup)) { + } else if (zoom < that.zoomShowVehicles + && that.leaflet.hasLayer(that.vehicleMarkersGroup)) { that.leaflet.removeLayer(that.vehicleMarkersGroup); if (!that.opts.embed) $('#msg-zoomForVehicles').show(); } diff --git a/static/js/predictions.js b/static/js/predictions.js index 5998757..4830860 100644 --- a/static/js/predictions.js +++ b/static/js/predictions.js @@ -14,10 +14,16 @@ BusMap.Predictions = function(opts) { if (that.opts.refresh.routes) { setInterval(updateRoutes, that.opts.refresh.routes * 1000); } - if (that.opts.refresh.vehicles) { - setInterval(updateVehicles, that.opts.refresh.vehicles * 1000); + if (that.opts.refresh.predictions) { + setInterval(updatePredictions, that.opts.refresh.predictions * 1000); } + // Listen for hash change + window.onhashchange = function() { + console.log('foo'); + setViewFromUrl(); + }; + }; /* Get Routes (and Stops, and Directions) */ @@ -33,14 +39,18 @@ BusMap.Predictions = function(opts) { that.routes = data.routes; updateStopsUI(that.stops); }); - return that; }; /* Get Vehicles (and Predictions) */ function updatePredictions() { + if (!that.stops) { + updateRoutes(); + return setTimeout(function() { updatePredictions() }, 500); + } var url = "ajax"; var params = { query: "predictions", + stops: that.stop, agency: that.opts.agency, }; $.getJSON(url, params) @@ -58,68 +68,84 @@ BusMap.Predictions = function(opts) { } that.stops[pr.stop_id].predictions[pr.route].push(pr); } - if (that.vehicles && pr.vehicle in that.vehicles) { - // Store this prediction with the relevant vehicle - that.vehicles[pr.vehicle].predictions.push(pr); - } } updatePredictionsUI(that.stops); }); - return that; }; + function applyViewString(view) { + if (!view || view == "") return false; + if (!that.stops) { + updateRoutes(); + return setTimeout(function() { applyViewString(view) }, 500); + } + if (view.charAt(0).toLowerCase() == "s") return _avsStop(view); + function _avsStop(view) { + var stop = that.stops[view.substring(1)]; + if (stop) { + that.stop = stop.id; + // Show this stop + $(that.opts.predictionsElement).html( + "<header>" + stop.title + "</header>" + + "<p></p>"); + updatePredictions(); + } else console.log('Unknown stop in view string: ' + view.substring(1)); + } + } + + function setViewFromUrl() { + var hash = window.location.hash.substring(1); + applyViewString(hash); + } + /* Refresh (and/or create) UI elements for Stops */ function updateStopsUI(stops) { - // TODO: this. usually this would be for a single stop but maybe multiple. - // identified via some option. that.opts.stops = ["foo", "bar", "baz"]? - // or...get it from the URL hash (like the map does)? + var hash = window.location.hash.substring(1); + if (hash == "") return false; + applyViewString(hash); } /* Refresh (and/or create) UI elements for Predictions */ function updatePredictionsUI(stops) { - // TODO: Generate predictions ui view - for (var s in stops) { - var text = '<header>' + stops[s].title + '</header>'; - if (stops[s].predictions) { - var predictions = []; - /* - var now = new Date(); - var offset_mins = now.getTimezoneOffset(); - for (r in stops[s].predictions) { - if (!(r in that.routes)) { - console.log("Unknown route " + r + " for stop " + stops[s].title); - } - var p_line = "<strong>" + that.routes[r].title + "</strong>: "; - var times = []; - // Sort by estimated time to arrival - psorted = stops[s].predictions[r].sort(function(a,b){ - return new Date(a.prediction).getTime() - new Date(b.prediction).getTime(); - }); - for (p in psorted) { - pr = psorted[p]; - var pdate = new Date(pr.prediction); - var diff_sec = (pdate.getTime() - now.getTime()) / 1000; - var diff_min = Math.ceil(diff_sec / 60) + offset_mins; - // CSS classes for predictions - var pclass = ""; - if (diff_min <= 1) { pclass = "lt1min"; } - else if (diff_min <= 2 ) { pclass = "lt2mins"; } - else if (diff_min <= 5 ) { pclass = "lt5mins"; } - times.push("<span class='prediction " + pclass - + "' title='" + pr.vehicle + "'>" - + diff_min + "</span>"); - } - p_line += times.join(", "); - predictions.push("<span class='route'" + p_line + "</span>"); + if (!that.stop) return false; + var s = that.stop; + if (stops[s].predictions) { + var predictions = []; + var now = new Date(); + var offset_mins = now.getTimezoneOffset(); + for (r in stops[s].predictions) { + if (!(r in that.routes)) { + console.log("Unknown route " + r + " for stop " + stops[s].title); } - */ - if (predictions.length == 0) { - predictions = ['<span class="none">No arrival predictions.</span>']; + var p_line = "<strong>" + that.routes[r].title + "</strong>: "; + var times = []; + // Sort by estimated time to arrival + psorted = stops[s].predictions[r].sort(function(a,b){ + return new Date(a.prediction).getTime() - new Date(b.prediction).getTime(); + }); + for (p in psorted) { + pr = psorted[p]; + var pdate = new Date(pr.prediction); + var diff_sec = (pdate.getTime() - now.getTime()) / 1000; + var diff_min = Math.ceil(diff_sec / 60) + offset_mins; + // CSS classes for predictions + var pclass = ""; + if (diff_min <= 1) { pclass = "lt1min"; } + else if (diff_min <= 2 ) { pclass = "lt2mins"; } + else if (diff_min <= 5 ) { pclass = "lt5mins"; } + times.push("<span class='prediction " + pclass + + "' title='" + pr.vehicle + "'>" + + diff_min + "</span>"); } - text += '<section class="predictions stop-predictions">' - + predictions.sort().join("<br>") + '</section>'; - // TODO: put output somewhere... + p_line += times.join(", "); + predictions.push("<span class='route'" + p_line + "</span>"); + } + if (predictions.length == 0) { + predictions = ['<span class="none">No arrival predictions.</span>']; } + text = '<section class="predictions stop-predictions">' + + predictions.sort().join("<br>") + '</section>'; + $(that.opts.predictionsElement).find('p').html(text); } } diff --git a/templates/modal-embed.html b/templates/modal-embed.html index 312a8c6..5165b13 100644 --- a/templates/modal-embed.html +++ b/templates/modal-embed.html @@ -1,6 +1,9 @@ -<h2>Embed This Map</h2> +<h2>Embed + {% if agency.short_title %}{{ agency.short_title -}} + {% elif agency.title %}{{ agency.title }}{% endif %} Bus Map +</h2> <p> - This map can be used in websites, displays, or digital signage solutions. To embed a list of predictions instead, change the <strong>Mode</strong> selector. + Use maps and/or stop predictions in your website or digital signage. </p> <h3>Embed Code</h3> <textarea id="embed-code" cols=100 rows=3 readonly=true></textarea> diff --git a/templates/predictions.html b/templates/predictions.html index ad582e3..e8de515 100644 --- a/templates/predictions.html +++ b/templates/predictions.html @@ -16,7 +16,10 @@ var predictions = BusMap.Predictions({ agency: {{ agency.tag|tojson|safe }}, predictionsElement: $("#predictions").get(0), - refresh: 60, + refresh: { + routes: 60, + predictions: 10, + } }); </script> {% endblock %} -- GitLab