2 //= require_tree ./directions_engines
4 OSM.Directions = function (map) {
5 $(".directions_form a.directions_close").on("click", function(e) {
7 var route_from = $(e.target).parent().parent().parent().find("input[name=route_from]").val();
9 OSM.router.route("/?query=" + encodeURIComponent(route_from) + OSM.formatHash(map));
11 OSM.router.route("/" + OSM.formatHash(map));
15 var awaitingGeocode; // true if the user has requested a route, but we're waiting on a geocode result
16 var awaitingRoute; // true if we've asked the engine for a route and are waiting to hear back
17 var dragging; // true if the user is dragging a start/end point
20 var popup = L.popup();
22 var polyline = L.polyline([], {
28 var highlight = L.polyline([], {
35 Endpoint($("input[name='route_from']"), <%= asset_path('marker-green.png').to_json %>),
36 Endpoint($("input[name='route_to']"), <%= asset_path('marker-red.png').to_json %>)
39 function Endpoint(input, iconUrl) {
42 endpoint.marker = L.marker([0, 0], {
47 popupAnchor: [1, -34],
48 shadowUrl: <%= asset_path('images/marker-shadow.png').to_json %>,
54 endpoint.marker.on('drag dragend', function (e) {
55 dragging = (e.type == 'drag');
56 if (dragging && !chosenEngine.draggable) return;
57 if (dragging && awaitingRoute) return;
58 endpoint.setLatLng(e.target.getLatLng());
59 if (map.hasLayer(polyline)) {
64 input.on("change", function (e) {
65 endpoint.awaitingGeocode = true;
67 $.getJSON('<%= NOMINATIM_URL %>search?q=' + encodeURIComponent(e.target.value) + '&format=json', function (json) {
68 endpoint.awaitingGeocode = false;
70 if (json.length == 0) {
71 alert(I18n.t('javascripts.directions.errors.no_place'));
75 input.val(json[0].display_name);
77 endpoint.latlng = L.latLng(json[0]);
79 .setLatLng(endpoint.latlng)
82 if (awaitingGeocode) {
83 awaitingGeocode = false;
89 endpoint.setLatLng = function (ll) {
90 var precision = OSM.zoomPrecision(map.getZoom());
91 input.val(ll.lat.toFixed(precision) + ", " + ll.lng.toFixed(precision));
101 function formatDistance(m) {
103 return Math.round(m) + "m";
104 } else if (m < 10000) {
105 return (m / 1000.0).toFixed(1) + "km";
107 return Math.round(m / 1000) + "km";
111 function formatTime(s) {
112 var m = Math.round(s / 60);
113 var h = Math.floor(m / 60);
115 return h + ":" + (m < 10 ? '0' : '') + m;
118 function setEngine(id) {
119 engines.forEach(function(engine, i) {
120 if (engine.id == id) {
121 chosenEngine = engine;
127 function getRoute() {
128 if (endpoints[0].awaitingGeocode || endpoints[1].awaitingGeocode) {
129 awaitingGeocode = true;
133 var o = endpoints[0].latlng,
134 d = endpoints[1].latlng;
136 if (!o || !d) return;
138 var precision = OSM.zoomPrecision(map.getZoom());
140 OSM.router.replace("/directions?" + querystring.stringify({
141 engine: chosenEngine.id,
142 route: o.lat.toFixed(precision) + ',' + o.lng.toFixed(precision) + ';' +
143 d.lat.toFixed(precision) + ',' + d.lng.toFixed(precision)
146 $(".directions_form .spinner").show();
147 awaitingRoute = true;
149 chosenEngine.getRoute([o, d], function (err, route) {
150 awaitingRoute = false;
152 $(".directions_form .spinner").hide();
155 map.removeLayer(polyline);
158 alert(I18n.t('javascripts.directions.errors.no_route'));
165 .setLatLngs(route.line)
168 map.setSidebarOverlaid(false);
171 map.fitBounds(polyline.getBounds().pad(0.05));
174 var html = '<h2><a class="geolink" href="#">' +
175 '<span class="icon close"></span></a>' + I18n.t('javascripts.directions.directions') +
176 '</h2><p id="routing_summary">' +
177 I18n.t('javascripts.directions.distance') + ': ' + formatDistance(route.distance) + '. ' +
178 I18n.t('javascripts.directions.time') + ': ' + formatTime(route.time) + '.</p>' +
179 '<table id="turnbyturn" />';
181 $('#sidebar_content')
186 route.steps.forEach(function (step) {
189 instruction = step[2],
197 } else if (dist < 200) {
198 dist = Math.round(dist / 10) * 10 + "m";
199 } else if (dist < 1500) {
200 dist = Math.round(dist / 100) * 100 + "m";
201 } else if (dist < 5000) {
202 dist = Math.round(dist / 100) / 10 + "km";
204 dist = Math.round(dist / 1000) + "km";
207 var row = $("<tr class='turn'/>");
208 row.append("<td><div class='direction i" + direction + "'/></td> ");
209 row.append("<td class='instruction'>" + instruction);
210 row.append("<td class='distance'>" + dist);
212 row.on('click', function () {
215 .setContent("<p>" + instruction + "</p>")
219 row.hover(function () {
224 map.removeLayer(highlight);
227 $('#turnbyturn').append(row);
230 $('#sidebar_content').append('<p id="routing_credit">' +
231 I18n.t('javascripts.directions.instructions.courtesy', {link: chosenEngine.creditline}) +
236 var engines = OSM.Directions.engines;
238 engines.sort(function (a, b) {
239 a = I18n.t('javascripts.directions.engines.' + a.id);
240 b = I18n.t('javascripts.directions.engines.' + b.id);
241 return a.localeCompare(b);
244 var select = $('select.routing_engines');
246 engines.forEach(function(engine, i) {
247 select.append("<option value='" + i + "'>" + I18n.t('javascripts.directions.engines.' + engine.id) + "</option>");
250 setEngine('osrm_car');
252 select.on("change", function (e) {
253 chosenEngine = engines[e.target.selectedIndex];
254 if (map.hasLayer(polyline)) {
259 $(".directions_form").on("submit", function(e) {
261 $("header").addClass("closed");
265 $(".routing_marker").on('dragstart', function (e) {
266 e.originalEvent.dataTransfer.effectAllowed = 'move';
267 e.originalEvent.dataTransfer.setData('id', this.id);
268 var xo = e.originalEvent.clientX - $(e.target).offset().left;
269 var yo = e.originalEvent.clientY - $(e.target).offset().top;
270 e.originalEvent.dataTransfer.setData('offsetX', e.originalEvent.target.width / 2 - xo);
271 e.originalEvent.dataTransfer.setData('offsetY', e.originalEvent.target.height - yo);
276 page.pushstate = page.popstate = function() {
277 $(".search_form").hide();
278 $(".directions_form").show();
280 $("#map").on('dragend dragover', function (e) {
284 $("#map").on('drop', function (e) {
286 var oe = e.originalEvent;
287 var id = oe.dataTransfer.getData('id');
288 var pt = L.DomEvent.getMousePosition(oe, map.getContainer()); // co-ordinates of the mouse pointer at present
289 pt.x += Number(oe.dataTransfer.getData('offsetX'));
290 pt.y += Number(oe.dataTransfer.getData('offsetY'));
291 var ll = map.containerPointToLatLng(pt);
292 endpoints[id === 'marker_from' ? 0 : 1].setLatLng(ll);
296 var params = querystring.parse(location.search.substring(1)),
297 route = (params.route || '').split(';');
300 setEngine(params.engine);
304 $(".directions_form input[name='route_from']").val(params.from);
307 var o = route[0] && L.latLng(route[0].split(',')),
308 d = route[1] && L.latLng(route[1].split(','));
310 if (o) endpoints[0].setLatLng(o);
311 if (d) endpoints[1].setLatLng(d);
313 map.setSidebarOverlaid(!o || !d);
318 page.load = function() {
322 page.unload = function() {
323 $(".search_form").show();
324 $(".directions_form").hide();
325 $("#map").off('dragend dragover drop');
329 .removeLayer(polyline)
330 .removeLayer(endpoints[0].marker)
331 .removeLayer(endpoints[1].marker);
337 OSM.Directions.engines = [];
339 OSM.Directions.addEngine = function (engine, supportsHTTPS) {
340 if (document.location.protocol == "http:" || supportsHTTPS) {
341 OSM.Directions.engines.push(engine);