//= require leaflet.key
//= require leaflet.note
//= require leaflet.share
+//= require leaflet.polyline
//= require index/search
//= require index/browse
//= require index/export
//= require index/note
//= require index/new_note
//= require router
+//= require routing
+//= require_tree ./routing_engines
(function() {
var loaderTimeout;
$(".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(true, true);
} 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));
+ }
}
});
map.getCenter().lat.toFixed(precision) + "," +
map.getCenter().lng.toFixed(precision)));
});
+
+ OSM.routing = OSM.Routing(map,'OSM.routing',$('.query_wrapper.routing'));
+ OSM.routing.chooseEngine('javascripts.directions.engines.osrm_car');
+
+ $(".get_directions").on("click",function(e) {
+ e.preventDefault();
+ $(".search").hide();
+ $(".routing").show();
+ $(".query_wrapper.routing [name=route_from]").focus();
+ $("#map").on('dragend dragover',function(e) { e.preventDefault(); });
+ $("#map").on('drop',function(e) { OSM.routing.handleDrop(e); e.preventDefault(); });
+ $(".routing_marker").on('dragstart',function(e) {
+ e.originalEvent.dataTransfer.effectAllowed = 'move';
+ e.originalEvent.dataTransfer.setData('id', this.id);
+ e.originalEvent.dataTransfer.setData('offsetX', e.originalEvent.target.width/2 - (e.originalEvent.x-e.target.x));
+ e.originalEvent.dataTransfer.setData('offsetY', e.originalEvent.target.height - (e.originalEvent.y-e.target.y));
+ });
+ });
+
+ $(".close_directions").on("click",function(e) {
+ e.preventDefault();
+ $(".search").show();
+ $(".routing").hide();
+ OSM.routing.close();
+ $("#map").off('dragend drop dragover');
+ $(".routing_marker").off('dragstart');
+ $(".query_wrapper.search [name=query]").focus();
+ });
+
});
--- /dev/null
+/*
+ osm.org routing interface
+*/
+
+var TURN_INSTRUCTIONS=[]
+
+var ROUTING_POLYLINE={
+ color: '#03f',
+ opacity: 0.3,
+ weight: 10
+};
+
+
+OSM.RoutingEngines={
+ list: []
+};
+
+OSM.Routing=function(map,name,jqSearch) {
+ var r={};
+
+ TURN_INSTRUCTIONS=["",
+ I18n.t('javascripts.directions.instructions.continue_on'), // 1
+ I18n.t('javascripts.directions.instructions.slight_right'), // 2
+ I18n.t('javascripts.directions.instructions.turn_right'), // 3
+ I18n.t('javascripts.directions.instructions.sharp_right'), // 4
+ I18n.t('javascripts.directions.instructions.uturn'), // 5
+ I18n.t('javascripts.directions.instructions.sharp_left'), // 6
+ I18n.t('javascripts.directions.instructions.turn_left'), // 7
+ I18n.t('javascripts.directions.instructions.slight_left'), // 8
+ I18n.t('javascripts.directions.instructions.via_point'), // 9
+ I18n.t('javascripts.directions.instructions.follow'), // 10
+ I18n.t('javascripts.directions.instructions.roundabout'), // 11
+ I18n.t('javascripts.directions.instructions.leave_roundabout'), // 12
+ I18n.t('javascripts.directions.instructions.stay_roundabout'), // 13
+ I18n.t('javascripts.directions.instructions.start'), // 14
+ I18n.t('javascripts.directions.instructions.destination'), // 15
+ I18n.t('javascripts.directions.instructions.against_oneway'), // 16
+ I18n.t('javascripts.directions.instructions.end_oneway')] // 17
+
+ 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; // null=unset, false=awaiting response, [lat,lon]=geocoded
+ r.route_to=null; // |
+ r.awaitingGeocode=false;// true if the user has requested a route, but we're waiting on a geocode result
+ r.awaitingRoute=false; // true if we've asked the engine for a route and are waiting to hear back
+ r.dragging=false; // true if the user is dragging a start/end point
+ r.viaPoints=[]; // not yet used
+
+ r.polyline=null; // Leaflet polyline object
+ r.popup=null; // Leaflet popup object
+ r.marker_from=null; // Leaflet from marker
+ r.marker_to=null; // Leaflet to marker
+
+ r.chosenEngine=null; // currently selected routing engine
+
+ var icon_from = L.icon({
+ iconUrl: <%= asset_path('marker-green.png').to_json %>,
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ popupAnchor: [1, -34],
+ shadowUrl: <%= asset_path('images/marker-shadow.png').to_json %>,
+ shadowSize: [41, 41]
+ });
+ var icon_to = L.icon({
+ iconUrl: <%= asset_path('marker-red.png').to_json %>,
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ popupAnchor: [1, -34],
+ shadowUrl: <%= asset_path('images/marker-shadow.png').to_json %>,
+ shadowSize: [41, 41]
+ });
+
+ // Geocoding
+
+ r.geocode=function(id,event) { var _this=this;
+ var field=event.target;
+ var v=event.target.value;
+ var querystring = '<%= NOMINATIM_URL %>search?q=' + encodeURIComponent(v) + '&format=json';
+ // *** &accept-language=<%#= request.user_preferred_languages.join(',') %>
+ r[field.id]=false;
+ $.getJSON(querystring, function(json) { _this._gotGeocode(json,field); });
+ };
+
+ r._gotGeocode=function(json,field) {
+ if (json.length==0) {
+ alert(I18n.t('javascripts.directions.errors.no_place'));
+ 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];
+ r.updateMarker(field.id);
+ if (r.awaitingGeocode) {
+ r.awaitingGeocode=false;
+ r.requestRoute(true, true);
+ }
+ };
+
+ // Drag and drop markers
+
+ r.handleDrop=function(e) {
+ var oe=e.originalEvent;
+ var id=oe.dataTransfer.getData('id');
+ var pt=L.DomEvent.getMousePosition(oe,map.getContainer()); // co-ordinates of the mouse pointer at present
+ pt.x+=Number(oe.dataTransfer.getData('offsetX'));
+ pt.y+=Number(oe.dataTransfer.getData('offsetY'));
+ var ll=map.containerPointToLatLng(pt);
+ r.createMarker(ll,id);
+ r.setNumericInput(ll,id);
+ r.requestRoute(true, false);
+ // update to/from field
+ };
+ r.createMarker=function(latlng,id) {
+ if (r[id]) r.map.removeLayer(r[id]);
+ r[id]=L.marker(latlng, {
+ icon: id=='marker_from' ? icon_from : icon_to,
+ draggable: true,
+ name: id
+ }).addTo(r.map);
+ r[id].on('drag',r.markerDragged);
+ r[id].on('dragend',r.markerDragged);
+ };
+ // Update marker from geocoded route input
+ r.updateMarker=function(id) {
+ var m=id.replace('route','marker');
+ if (!r[m]) { r.createMarker(r[id],m); return; }
+ var ll=r[m].getLatLng();
+ if (ll.lat!=r[id][0] || ll.lng!=r[id][1]) {
+ r.createMarker(r[id],m);
+ }
+ };
+ // Marker has been dragged
+ r.markerDragged=function(e) {
+ r.dragging=(e.type=='drag'); // true for drag, false for dragend
+ if (r.dragging && !r.chosenEngine.draggable) return;
+ if (r.dragging && r.awaitingRoute) return;
+ r.setNumericInput(e.target.getLatLng(), e.target.options.name);
+ r.requestRoute(!r.dragging, false);
+ };
+ // Set a route input field to a numeric value
+ r.setNumericInput=function(ll,id) {
+ var routeid=id.replace('marker','route');
+ r[routeid]=[ll.lat,ll.lng];
+ $("[name="+routeid+"]:visible").val(Math.round(ll.lat*10000)/10000+" "+Math.round(ll.lng*10000)/10000);
+ }
+
+ // Route-fetching UI
+
+ r.requestRoute=function(isFinal, updateZoom) {
+ if (r.route_from && r.route_to) {
+ $(".query_wrapper.routing .spinner").show();
+ r.awaitingRoute=true;
+ r.chosenEngine.getRoute(isFinal,[r.route_from,r.route_to]);
+ if(updateZoom){
+ r.map.fitBounds(L.latLngBounds([r.route_from, r.route_to]).pad(0.05));
+ }
+ // then, when the route has been fetched, it'll call the engine's gotRoute function
+ } else if (r.route_from==false || r.route_to==false) {
+ // we're waiting for a Nominatim response before we can request a route
+ r.awaitingGeocode=true;
+ }
+ };
+
+ // 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);
+ };
+
+ // Take directions and write them out
+ // data = { steps: array of [latlng, sprite number, instruction text, distance in metres] }
+ // sprite numbers equate to OSRM's route_instructions turn values
+ r.setItinerary=function(data) {
+ // Create base table
+ $("#content").removeClass("overlay-sidebar");
+ $('#sidebar_content').empty();
+ var html=('<h2><a class="geolink" href="#" onclick="$(~.close_directions~).click();return false;">' +
+ '<span class="icon close"></span></a>' + I18n.t('javascripts.directions.directions') +
+ '</h2><p id="routing_summary">' +
+ I18n.t('javascripts.directions.distance') + ': ' + r.formatDistance(data.distance)+ '. ' +
+ I18n.t('javascripts.directions.time' ) + ': ' + r.formatTime(data.time) + '.</p>' +
+ '<table id="turnbyturn" />').replace(/~/g,"'");
+ $('#sidebar_content').html(html);
+ // Add each row
+ var cumulative=0;
+ for (var i=0; i<data.steps.length; i++) {
+ var step=data.steps[i];
+ // Distance
+ var dist=step[3];
+ if (dist<5) { dist=""; }
+ else if (dist<200) { dist=Math.round(dist/10)*10+"m"; }
+ else if (dist<1500) { dist=Math.round(dist/100)*100+"m"; }
+ else if (dist<5000) { dist=Math.round(dist/100)/10+"km"; }
+ else { dist=Math.round(dist/1000)+"km"; }
+ // Add to table
+ var row=$("<tr class='turn'/>");
+ row.append("<td class='direction i"+step[1]+"'> ");
+ row.append("<td class='instruction'>"+step[2]);
+ row.append("<td class='distance'>"+dist);
+ with ({ num: i, ll: step[0] }) {
+ row.on('click',function(e) { r.clickTurn(num, ll); });
+ };
+ $('#turnbyturn').append(row);
+ cumulative+=step[3];
+ }
+ $('#sidebar_content').append('<p id="routing_credit">' + r.chosenEngine.creditline + '</p>');
+
+ };
+ r.clickTurn=function(num,latlng) {
+ r.popup=L.popup().setLatLng(latlng).setContent("<p>"+(num+1)+"</p>").openOn(r.map);
+ };
+ r.formatDistance=function(m) {
+ if (m < 1000 ) { return Math.round(m) + "m"; }
+ else if (m < 10000) { return (m/1000.0).toFixed(1) + "km"; }
+ else { return Math.round(m / 1000) + "km"; }
+ };
+ r.formatTime=function(s) {
+ var d=new Date(s*1000); var h=d.getHours(); var m=d.getMinutes();
+ return h+":"+(m<10 ? '0' : '')+m;
+ };
+
+ // Close all routing UI
+
+ r.close=function() {
+ $("#content").addClass("overlay-sidebar");
+ r.route_from=r.route_to=null;
+ $(".query_wrapper.routing input").val("");
+ var remove=['polyline','popup','marker_from','marker_to'];
+ for (var i=0; i<remove.length; i++) {
+ if (r[remove[i]]) { map.removeLayer(r[remove[i]]); r[remove[i]]=null; }
+ }
+ };
+
+ // Routing engine handling
+
+ // Add all engines
+ var list=OSM.RoutingEngines.list;
+ list.sort(function(a,b) { return I18n.t(a.name)>I18n.t(b.name); });
+ var select=r.jqSearch.find('select.routing_engines');
+ for (var i=0; i<list.length; i++) {
+ // Set up JSONP callback
+ with ({num: i}) {
+ list[num].requestJSONP=function(url) {
+ var script = document.createElement('script');
+ script.src = url+r.name+".gotRoute"+num;
+ document.body.appendChild(script);
+ };
+ list[num].requestCORS=function(url) {
+ $.ajax({ url: url, method: "GET", data: {}, dataType: 'json', success: r['gotRoute'+num] });
+ };
+ r['gotRoute'+num]=function(data) {
+ r.awaitingRoute=false;
+ $(".query_wrapper.routing .spinner").hide();
+ if (!list[num].gotRoute(r,data)) {
+ // No route found
+ if (r.polyline) {
+ map.removeLayer(r.polyline);
+ r.polyline=null;
+ }
+ if (!r.dragging) { alert(I18n.t('javascripts.directions.errors.no_route')); }
+ }
+ };
+ }
+ select.append("<option value='"+i+"'>"+I18n.t(list[i].name)+"</option>");
+ }
+ r.engines=list;
+ r.chosenEngine=list[0]; // default to first engine
+
+ // Choose an engine on dropdown change
+ r.selectEngine=function(e) {
+ r.chosenEngine=r.engines[e.target.selectedIndex];
+ if (r.polyline){ // and if a route is currently showing, must also refresh, else confusion
+ r.requestRoute(true, false);
+ }
+ };
+ // Choose an engine by name
+ r.chooseEngine=function(name) {
+ for (var i=0; i<r.engines.length; i++) {
+ if (r.engines[i].name==name) {
+ r.chosenEngine=r.engines[i];
+ r.jqSearch.find('select.routing_engines').val(i);
+ }
+ }
+ };
+
+ return r;
+};
--- /dev/null
+GraphHopperEngine = function(vehicleName, vehicleParam, locale) {
+ this.vehicleName = vehicleName;
+ this.vehicleParam = vehicleParam;
+ this.locale = locale;
+ if (!locale)
+ this.locale = "en";
+};
+
+GraphHopperEngine.prototype.createConfig = function() {
+ var that = this;
+ return {
+ name: "javascripts.directions.engines.graphhopper_"+this.vehicleName.toLowerCase(),
+ draggable: false,
+ _hints: {},
+ getRoute: function(isFinal, points) {
+ var url = "http://graphhopper.com/routing/api/route?"
+ + that.vehicleParam
+ + "&locale=" + that.locale;
+ for (var i = 0; i < points.length; i++) {
+ var pair = points[i].join(',');
+ url += "&point=" + pair;
+ }
+ if (isFinal)
+ url += "&instructions=true";
+ // GraphHopper supports json too
+ this.requestJSONP(url + "&type=jsonp&callback=");
+ },
+ gotRoute: function(router, data) {
+ if (!data.info.routeFound) {
+ return false;
+ }
+ // Draw polyline
+ var line = L.PolylineUtil.decode(data.route.coordinates);
+ router.setPolyline(line);
+ // Assemble instructions
+ var steps = [];
+ var instr = data.route.instructions;
+ for (i = 0; i < instr.descriptions.length; i++) {
+ var indi = instr.indications[i];
+ var instrCode = (i == instr.descriptions.length - 1) ? 15 : this.GH_INSTR_MAP[indi];
+ var instrText = "<b>" + (i + 1) + ".</b> ";
+ instrText += instr.descriptions[i];
+ var latlng = instr.latLngs[i];
+ var distInMeter = instr.distances[i];
+ steps.push([{lat: latlng[0], lng: latlng[1]}, instrCode, instrText, distInMeter]);
+ }
+ router.setItinerary({ steps: steps, distance: data.route.distance, time: data.route['time']/1000 });
+ return true;
+ },
+ GH_INSTR_MAP: {
+ "-3": 6, // sharp left
+ "-2": 7, // left
+ "-1": 8, // slight left
+ 0: 0, // straight
+ 1: 1, // slight right
+ 2: 2, // right
+ 3: 3 // sharp right
+ }
+ };
+};
+
+OSM.RoutingEngines.list.push(new GraphHopperEngine("Bicycle", "vehicle=bike").createConfig());
+OSM.RoutingEngines.list.push(new GraphHopperEngine("Foot", "vehicle=foot").createConfig());
--- /dev/null
+// For docs, see:
+// http://developer.mapquest.com/web/products/open/directions-service
+// http://open.mapquestapi.com/directions/
+// https://github.com/apmon/openstreetmap-website/blob/21edc353a4558006f0ce23f5ec3930be6a7d4c8b/app/controllers/routing_controller.rb#L153
+
+MapQuestEngine = function(vehicleName, vehicleParam, locale) {
+ this.vehicleName = vehicleName;
+ this.vehicleParam = vehicleParam;
+ this.locale = locale;
+ if (!locale)
+ this.locale = "en";
+};
+
+MapQuestEngine.prototype.createConfig = function() {
+ var that = this;
+ return {
+ name: "javascripts.directions.engines.mapquest_"+this.vehicleName.toLowerCase(),
+ creditline: 'Directions courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> <img src="http://developer.mapquest.com/content/osm/mq_logo.png">',
+ draggable: false,
+ _hints: {},
+ MQ_SPRITE_MAP: {
+ 0: 1, // straight
+ 1: 2, // slight right
+ 2: 3, // right
+ 3: 4, // sharp right
+ 4: 5, // reverse
+ 5: 6, // sharp left
+ 6: 7, // left
+ 7: 8, // slight left
+ 8: 5, // right U-turn
+ 9: 5, // left U-turn
+ 10: 2, // right merge
+ 11: 8, // left merge
+ 12: 2, // right on-ramp
+ 13: 8, // left on-ramp
+ 14: 2, // right off-ramp
+ 15: 8, // left off-ramp
+ 16: 2, // right fork
+ 17: 8, // left fork
+ 18: 1 // straight fork
+ },
+ getRoute: function(isFinal,points) {
+ var url="http://open.mapquestapi.com/directions/v2/route?key=Fmjtd%7Cluur290anu%2Crl%3Do5-908a0y";
+ var from=points[0]; var to=points[points.length-1];
+ url+="&from="+from.join(',');
+ url+="&to="+to.join(',');
+ url+="&"+that.vehicleParam;
+ //url+="&locale=" + I18n.currentLocale(); //Doesn't actually work. MapQuest requires full locale e.g. "de_DE", but I18n only provides language, e.g. "de"
+ url+="&manMaps=false";
+ url+="&shapeFormat=raw&generalize=0&unit=k";
+ this.requestCORS(url);
+ },
+ gotRoute: function(router,data) {
+ if (data.info.statuscode!=0) return false;
+
+ var poly=[];
+ var shape=data.route.shape.shapePoints;
+ for (var i=0; i<shape.length; i+=2) {
+ poly.push(L.latLng(shape[i],shape[i+1]));
+ }
+ router.setPolyline(poly);
+
+ // data.shape.maneuverIndexes links turns to polyline positions
+ // data.legs[0].maneuvers is list of turns
+ var steps=[];
+ var mq=data.route.legs[0].maneuvers;
+ for (var i=0; i<mq.length; i++) {
+ var s=mq[i];
+ var d=(i==mq.length-1) ? 15: this.MQ_SPRITE_MAP[s.turnType];
+ steps.push([L.latLng(s.startPoint.lat, s.startPoint.lng), d, s.narrative, s.distance*1000]);
+ }
+ router.setItinerary( { steps: steps, distance: data.route.distance*1000, time: data.route['time'] });
+ return true;
+ }
+ };
+};
+
+OSM.RoutingEngines.list.push(new MapQuestEngine("Bicycle", "routeType=bicycle").createConfig());
+OSM.RoutingEngines.list.push(new MapQuestEngine("Foot", "routeType=pedestrian").createConfig());
+OSM.RoutingEngines.list.push(new MapQuestEngine("Car", "routeType=fastest").createConfig());
+// can be: routeType=fastest|shortest|pedestrian|multimodal|bicycle
--- /dev/null
+// OSRM car engine
+// Doesn't yet support hints
+
+OSRMEngine = function(vehicleName, baseURL, locale) {
+ this.vehicleName = vehicleName;
+ this.baseURL = baseURL;
+ this.locale = locale;
+ if (!locale)
+ this.locale = "en";
+};
+
+OSRMEngine.prototype.createConfig = function() {
+ var that = this;
+ return {
+ name: "javascripts.directions.engines.osrm_"+this.vehicleName.toLowerCase(),
+ creditline: 'Directions courtesy of <a href="http://project-osrm.org/" target="_blank">OSRM</a>',
+ draggable: true,
+ _hints: {},
+ getRoute: function(isFinal,points) {
+ var url=that.baseURL+"?z=14&output=json";
+ for (var i=0; i<points.length; i++) {
+ var pair=points[i].join(',');
+ url+="&loc="+pair;
+ if (this._hints[pair]) url+= "&hint="+this._hints[pair];
+ }
+ if (isFinal) url+="&instructions=true";
+ this.requestCORS(url);
+ },
+ gotRoute: function(router,data) {
+ if (data.status==207) {
+ return false;
+ }
+ // Draw polyline
+ var line=L.PolylineUtil.decode(data.route_geometry);
+ for (i=0; i<line.length; i++) { line[i].lat/=10; line[i].lng/=10; }
+ router.setPolyline(line);
+ // Assemble instructions
+ var steps=[];
+ for (i=0; i<data.route_instructions.length; i++) {
+ var s=data.route_instructions[i];
+ var instCodes=s[0].split('-');
+ var instText="<b>"+(i+1)+".</b> ";
+ instText+=TURN_INSTRUCTIONS[instCodes[0]];
+ if (instCodes[1]) { instText+="exit "+instCodes[1]+" "; }
+ if (instCodes[0]!=15) { instText+=s[1] ? "<b>"+s[1]+"</b>" : I18n.t('javascripts.directions.instructions.unnamed'); }
+ steps.push([line[s[3]], s[0].split('-')[0], instText, s[2]]);
+ }
+ if (steps.length) router.setItinerary({ steps: steps, distance: data.route_summary.total_distance, time: data.route_summary.total_time });
+ return true;
+ }
+ };
+};
+
+OSM.RoutingEngines.list.push(new OSRMEngine("Car", "http://router.project-osrm.org/viaroute").createConfig());
font-size: 13px;
}
+ p {
+ padding: 0 $lineheight $lineheight/4;
+ }
+
.icon.close {
float: right;
cursor: pointer;
.search_form {
position: relative;
padding: $lineheight/2;
+ padding-top: 1px;
background-color: $lightgrey;
.query_wrapper {
border-radius: 0 2px 2px 0;
}
- .describe_location {
- position: absolute;
- top: 6px;
- right: 6px;
+ .query_options {
+ text-align: right;
font-size: 10px;
color: $blue;
}
+
+ .routing {
+ display: none;
+ }
}
/* Rules for the map key which appears in the popout sidebar */
color: #f00;
}
+/* Rules for routing */
+
+#sidebar_content>table {
+ padding: 5px 20px 10px 15px;
+ width: 100%;
+ border-collapse: separate;
+}
+
+td.direction {
+ background-image: image-url('routing-sprite.png');
+ width: 20px; height: 20px;
+ background-repeat: no-repeat;
+}
+@for $i from 1 through 17 {
+td.direction.i#{$i} { background-position: #{($i)*-20+20}px 0px; }
+}
+
+td.instruction, td.distance {
+ padding-top: 0;
+ border-bottom: 1px solid #DDD;
+}
+td.distance {
+ color: #BBB;
+ text-align: right;
+ font-size: x-small;
+}
+tr.turn {
+ cursor: pointer;
+}
+tr.turn:hover {
+ background: lighten($green, 30%);
+}
+.routing_engines, #route_from, #route_to { margin-left: 25px; }
+.routing_marker { width: 15px; position: absolute; }
+
/* Rules for entity history */
#sidebar_content {
}
}
+/* Rules for the routing sidebar */
+
+#sidebar_content {
+ #routing_credit {
+ text-align: center;
+ padding: 0.5em;
+ }
+}
+
/* Rules for edit pages */
.site-edit {
<form method="GET" action="<%= search_path %>" class="search_form">
+
+ <div class='query_options search'>
+ <%= link_to t('site.search.where_am_i'), '#', { :class => "describe_location", :title => t('site.search.where_am_i_title') } %>
+ ·
+ <%= link_to t('site.search.get_directions'), '#', { :class => "get_directions", :title => t('site.search.get_directions_title') } %>
+ </div>
+
+ <div class='query_options routing'>
+ <%= link_to t('site.search.close_directions'), '#', { :class => "close_directions", :title => t('site.search.close_directions_title') } %>
+ </div>
+
<%= submit_tag t('site.search.submit_text') %>
- <div class='query_wrapper'>
+
+ <div class='query_wrapper search'>
<%= text_field_tag "query", params[:query], :placeholder => t("site.search.search"), :autofocus => autofocus %>
- <%= link_to t('site.search.where_am_i'), '#', { :class => "describe_location", :title => t('site.search.where_am_i_title') } %>
</div>
+
+ <div class='query_wrapper routing'>
+ <%= image_tag "marker-green.png", :class => 'routing_marker', :id => 'marker_from', :draggable => 'true' %>
+ <%= text_field_tag "route_from", params[:from], :placeholder => t('site.search.from'), :onchange=>"OSM.routing.geocode('route_from',event)" %>
+ <%= image_tag "marker-red.png" , :class => 'routing_marker', :id => 'marker_to' , :draggable => 'true' %>
+ <%= text_field_tag "route_to" , params[:to] , :placeholder => t('site.search.to') , :onchange=>"OSM.routing.geocode('route_to' ,event)" %>
+ <select class='routing_engines' name='routing_engines' onchange="OSM.routing.selectEngine(event)"></select>
+ <%= image_tag "searching-small.gif", :class => 'spinner', :style => "vertical-align: middle; display: none;" %>
+ </div>
+
</form>
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
- config.assets.precompile += %w( index.js browse.js welcome.js fixthemap.js )
+ config.assets.precompile += %w( index.js browse.js welcome.js fixthemap.js routing.js )
config.assets.precompile += %w( user.js diary_entry.js swfobject.js )
config.assets.precompile += %w( large-ltr.css small-ltr.css print-ltr.css )
config.assets.precompile += %w( large-rtl.css small-rtl.css print-rtl.css )
javascripts:
close: Schließen
edit_help: Wähle eine höhere Zoomstufe und verschiebe die Karte an einen Ort, den du bearbeiten möchtest, und klicke hier.
+ directions:
+ directions: "Fahranweisungen: "
+ engines:
+ graphhopper_bike: "Fahrrad (GraphHopper)"
+ mapquest_bike: "Fahrrad (MapQuest)"
+ osrm_car: "Auto (OSRM)"
+ cloudmade_foot: "Fuss (Cloudmade)"
+ instructions:
+ continue_on: "Weiter auf "
+ slight_right: "Rechts halten auf "
+ turn_right: "Rechts abbiegen auf "
+ sharp_right: "Hart rechts auf "
+ uturn: "U-turn along "
+ sharp_left: "Hart links auf "
+ turn_left: "Links abbiegen auf "
+ slight_left: "Links halten auf "
+ via_point: "(via point) "
+ follow: "Folge "
+ roundabout: "Im Kreisverkehr nehme "
+ leave_roundabout: "Verlasse den Kreisverkehr - "
+ stay_roundabout: "Stay on roundabout - "
+ start: "Start at end of "
+ destination: "Ziel erreicht"
+ against_oneway: "Go against one-way on "
+ end_oneway: "Ende der Einbahnstrasse "
+ unnamed: "(unbekannt)"
key:
title: Legende
tooltip: Legende
preview: Vorschau
search:
search: Suchen
+ get_directions: "Route berechnen"
+ get_directions_title: "Routenberechnung zwischen zwei Orten"
+ close_directions: "Schliessen der Route"
+ close_directions_title: "Schliessen des Routenmenus"
+ from: "Von"
+ to: "Nach"
submit_text: Los
where_am_i: Wo bin ich?
where_am_i_title: Die momentane Position mit der Suchmaschine anzeigen
close: Close
search:
search: Search
+ get_directions: "Get directions"
+ get_directions_title: "Find directions between two points"
+ close_directions: "Close directions"
+ close_directions_title: "Close the directions panel"
+ from: "From"
+ to: "To"
where_am_i: "Where am I?"
where_am_i_title: Describe the current location using the search engine
submit_text: "Go"
comment_and_resolve: Comment & Resolve
comment: Comment
edit_help: Move the map and zoom in on a location you want to edit, then click here.
+ directions:
+ engines:
+ graphhopper_bicycle: "Bicycle (GraphHopper)"
+ graphhopper_foot: "Foot (GraphHopper)"
+ mapquest_bicycle: "Bicycle (MapQuest)"
+ mapquest_car: "Car (MapQuest)"
+ mapquest_foot: "Foot (MapQuest)"
+ osrm_car: "Car (OSRM)"
+ directions: "Directions"
+ distance: "Distance"
+ errors:
+ no_route: "Couldn't find a route between those two places."
+ no_place: "Sorry - couldn't find that place."
+ instructions:
+ continue_on: "Continue on "
+ slight_right: "Slight right onto "
+ turn_right: "Turn right onto "
+ sharp_right: "Sharp right onto "
+ uturn: "U-turn along "
+ sharp_left: "Sharp left onto "
+ turn_left: "Turn left onto "
+ slight_left: "Slight left onto "
+ via_point: "(via point) "
+ follow: "Follow "
+ roundabout: "At roundabout take "
+ leave_roundabout: "Leave roundabout - "
+ stay_roundabout: "Stay on roundabout - "
+ start: "Start at end of "
+ destination: "Reach destination"
+ against_oneway: "Go against one-way on "
+ end_oneway: "End of one-way on "
+ unnamed: "(unnamed)"
+ time: "Time"
redaction:
edit:
description: "Description"
--- /dev/null
+/*
+ * 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