From: Richard Fairhurst Date: Tue, 21 Jan 2014 13:29:05 +0000 (+0000) Subject: Beginning of JavaScript-only routing UI X-Git-Tag: live~4217^2~67 X-Git-Url: https://git.openstreetmap.org/rails.git/commitdiff_plain/2198b6ebbf46cdad39b75a461b9a72e5cde93c3a?ds=sidebyside Beginning of JavaScript-only routing UI --- diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 55e612f17..4645a3e2e 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -5,6 +5,7 @@ //= require leaflet.key //= require leaflet.note //= require leaflet.share +//= require leaflet.polyline //= require index/search //= require index/browse //= require index/export @@ -13,6 +14,7 @@ //= require index/note //= require index/new_note //= require router +//= require routing (function() { var loaderTimeout; @@ -322,12 +324,18 @@ $(document).ready(function () { $(".search_form").on("submit", function(e) { e.preventDefault(); - $("header").addClass("closed"); - var query = $(this).find("input[name=query]").val(); - if (query) { - OSM.router.route("/search?query=" + encodeURIComponent(query) + OSM.formatHash(map)); + if ($(".query_wrapper.routing").is(":visible")) { + // Routing + OSM.routing.requestRoute(); } else { - OSM.router.route("/" + OSM.formatHash(map)); + // Search + $("header").addClass("closed"); + var query = $(this).find("input[name=query]").val(); + if (query) { + OSM.router.route("/search?query=" + encodeURIComponent(query) + OSM.formatHash(map)); + } else { + OSM.router.route("/" + OSM.formatHash(map)); + } } }); @@ -338,4 +346,19 @@ $(document).ready(function () { map.getCenter().lat.toFixed(precision) + "," + map.getCenter().lng.toFixed(precision))); }); + + $(".get_directions").on("click",function(e) { + e.preventDefault(); + $(".query_wrapper.search").hide(); + $(".query_wrapper.routing").show(); + }); + + $(".close_directions").on("click",function(e) { + e.preventDefault(); + $(".query_wrapper.search").show(); + $(".query_wrapper.routing").hide(); + }); + + OSM.routing = OSM.Routing(map,'OSM.routing',$('.query_wrapper.routing')); + }); diff --git a/app/assets/javascripts/routing.js.erb b/app/assets/javascripts/routing.js.erb new file mode 100644 index 000000000..30846479d --- /dev/null +++ b/app/assets/javascripts/routing.js.erb @@ -0,0 +1,159 @@ +/* + osm.org routing interface + + See also: + https://github.com/apmon/openstreetmap-website/tree/routing2 + https://github.com/apmon/openstreetmap-website/compare/routing2 + https://github.com/apmon/openstreetmap-website/blob/9755c3ae0a8d0684d43760f91dc864ff42d8477a/app/views/routing/start.js.erb + + *** draggable start/end markers + +*/ + +var TURN_INSTRUCTIONS=["", + "Continue on ", // 1 + "Slight right onto ", // 2 + "Turn right onto ", // 3 + "Sharp right onto ", // 4 + "U-turn along ", // 5 + "Sharp left onto ", // 6 + "Turn left onto ", // 7 + "Slight left onto ", // 8 + "(via point) ", // 9 + "Follow ", // 10 + "At roundabout take ", // 11 + "Leave roundabout - ", // 12 + "Stay on roundabout - ", // 13 + "Start at end of ", // 14 + "Reach destination", // 15 + "Go against one-way on ", // 16 + "End of one-way on "] // 17 + +var ROUTING_POLYLINE={ + color: '#03f', + opacity: 0.3, + weight: 10 +}; + + +OSM.Routing=function(map,name,jqSearch) { + var r={}; + r.map=map; // Leaflet map + r.name=name; // global variable name of this instance (needed for JSONP) + r.jqSearch=jqSearch; // JQuery object for search panel + + r.route_from=null; + r.route_to=null; + r.viaPoints=[]; + r.polyline=null; + + // Geocoding + + r.geocode=function(id,event) { var _this=this; + var field=event.target; + var v=event.target.value; + // *** do something if v=='' + var querystring = '<%= NOMINATIM_URL %>search?q=' + encodeURIComponent(v) + '&format=json'; + // *** &accept-language=<%#= request.user_preferred_languages.join(',') %> + // *** prefer current viewport + $.getJSON(querystring, function(json) { _this._gotGeocode(json,field); }); + }; + + r._gotGeocode=function(json,field) { + if (json.length==0) { + alert("Sorry, couldn't find that place."); // *** internationalise + r[field.id]=null; + return; + } + field.value=json[0].display_name; + var lat=Number(json[0].lat), lon=Number(json[0].lon); + r[field.id]=[lat,lon]; + // ** update markers + }; + + // Route-fetching UI + + r.requestRoute=function() { + if (r.route_from && r.route_to) { + var chosen=jqSearch.find('select.routing_engines :selected').val(); + r.engines[chosen].getRoute(true,[r.route_from,r.route_to]); + // then, when the route has been fetched, it'll call the engine's gotRoute function + } + }; + + // Take an array of Leaflet LatLngs and draw it as a polyline + r.setPolyline=function(line) { + if (r.polyline) map.removeLayer(r.polyline); + r.polyline=L.polyline(line, ROUTING_POLYLINE).addTo(r.map); + // *** zoom to fit + }; + + // Take an array of directions and write it out + // (we use OSRM's route_instructions format) + r.setItinerary=function(steps) { + $("#content").removeClass("overlay-sidebar"); + $('#sidebar_content').empty(); + var html=""; + for (var i=0; i"+engine.name+""); + }; + + // OSRM car engine + // *** this should all be shared from an OSRM library somewhere + // *** need to clear hints at some point + + r.addEngine({ + name: 'Car (OSRM)', + draggable: true, + _hints: {}, + getRoute: function(final,points) { + var url="http://router.project-osrm.org/viaroute?z=14&output=json"; + for (var i=0; i "search_form" do %> <%= submit_tag t('site.search.submit_text') %> -
+ + + +
+ <%= text_field_tag "route_from", params[:from], :placeholder => "From", :onchange=>"OSM.routing.geocode('route_from',event)" %> + <%= text_field_tag "route_to" , params[:to] , :placeholder => "To" , :onchange=>"OSM.routing.geocode('route_to' ,event)" %> +
+ + <%= link_to t('site.search.close_directions'), '#', { :class => "close_directions", :title => t('site.search.close_directions_title') } %> +
+
+ <% end %> diff --git a/vendor/assets/leaflet/leaflet.polyline.js b/vendor/assets/leaflet/leaflet.polyline.js new file mode 100755 index 000000000..b7e85d6c5 --- /dev/null +++ b/vendor/assets/leaflet/leaflet.polyline.js @@ -0,0 +1,127 @@ +/* + * L.PolylineUtil contains utilify functions for polylines, two methods + * are added to the L.Polyline object to support creation of polylines + * from an encoded string and converting existing polylines to an + * encoded string. + * + * - L.Polyline.fromEncoded(encoded [, options]) returns a L.Polyline + * - L.Polyline.encodePath() returns a string + * + * Actual code from: + * http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/\ + */ + +/*jshint browser:true, debug: true, strict:false, globalstrict:false, indent:4, white:true, smarttabs:true*/ +/*global L:true, console:true*/ + + +// Inject functionality into Leaflet +(function (L) { + if (!(L.Polyline.prototype.fromEncoded)) { + L.Polyline.fromEncoded = function (encoded, options) { + return new L.Polyline(L.PolylineUtil.decode(encoded), options); + }; + } + if (!(L.Polygon.prototype.fromEncoded)) { + L.Polygon.fromEncoded = function (encoded, options) { + return new L.Polygon(L.PolylineUtil.decode(encoded), options); + }; + } + + var encodeMixin = { + encodePath: function () { + return L.PolylineUtil.encode(this.getLatLngs()); + } + }; + + if (!L.Polyline.prototype.encodePath) { + L.Polyline.include(encodeMixin); + } + if (!L.Polygon.prototype.encodePath) { + L.Polygon.include(encodeMixin); + } +})(L); + +// Utility functions. +L.PolylineUtil = {}; + +L.PolylineUtil.encode = function (latlngs) { + var i, dlat, dlng; + var plat = 0; + var plng = 0; + var encoded_points = ""; + + for (i = 0; i < latlngs.length; i++) { + var lat = latlngs[i].lat; + var lng = latlngs[i].lng; + var late5 = Math.floor(lat * 1e5); + var lnge5 = Math.floor(lng * 1e5); + dlat = late5 - plat; + dlng = lnge5 - plng; + plat = late5; + plng = lnge5; + encoded_points += + L.PolylineUtil.encodeSignedNumber(dlat) + + L.PolylineUtil.encodeSignedNumber(dlng); + } + return encoded_points; +}; + +// This function is very similar to Google's, but I added +// some stuff to deal with the double slash issue. +L.PolylineUtil.encodeNumber = function (num) { + var encodeString = ""; + var nextValue, finalValue; + while (num >= 0x20) { + nextValue = (0x20 | (num & 0x1f)) + 63; + encodeString += (String.fromCharCode(nextValue)); + num >>= 5; + } + finalValue = num + 63; + encodeString += (String.fromCharCode(finalValue)); + return encodeString; +}; + +// This one is Google's verbatim. +L.PolylineUtil.encodeSignedNumber = function (num) { + var sgn_num = num << 1; + if (num < 0) { + sgn_num = ~(sgn_num); + } + return (L.PolylineUtil.encodeNumber(sgn_num)); +}; + +L.PolylineUtil.decode = function (encoded) { + var len = encoded.length; + var index = 0; + var latlngs = []; + var lat = 0; + var lng = 0; + + while (index < len) { + var b; + var shift = 0; + var result = 0; + do { + b = encoded.charCodeAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1)); + lat += dlat; + + shift = 0; + result = 0; + do { + b = encoded.charCodeAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1)); + lng += dlng; + + latlngs.push(new L.LatLng(lat * 1e-5, lng * 1e-5)); + } + + return latlngs; +}; \ No newline at end of file