2 //= require_tree ./directions_engines
4 OSM.Directions = function (map) {
5 var awaitingGeocode; // true if the user has requested a route, but we're waiting on a geocode result
6 var awaitingRoute; // true if we've asked the engine for a route and are waiting to hear back
7 var dragging; // true if the user is dragging a start/end point
10 var popup = L.popup();
12 var polyline = L.polyline([], {
18 var highlight = L.polyline([], {
25 Endpoint($("input[name='route_from']"), <%= asset_path('marker-green.png').to_json %>),
26 Endpoint($("input[name='route_to']"), <%= asset_path('marker-red.png').to_json %>)
29 function Endpoint(input, iconUrl) {
32 endpoint.marker = L.marker([0, 0], {
37 popupAnchor: [1, -34],
38 shadowUrl: <%= asset_path('images/marker-shadow.png').to_json %>,
44 endpoint.marker.on('drag dragend', function (e) {
45 dragging = (e.type == 'drag');
46 if (dragging && !chosenEngine.draggable) return;
47 if (dragging && awaitingRoute) return;
48 endpoint.setLatLng(e.target.getLatLng());
49 if (map.hasLayer(polyline)) {
54 input.on("change", function (e) {
55 endpoint.awaitingGeocode = true;
57 $.getJSON('<%= NOMINATIM_URL %>search?q=' + encodeURIComponent(e.target.value) + '&format=json', function (json) {
58 endpoint.awaitingGeocode = false;
60 if (json.length == 0) {
61 alert(I18n.t('javascripts.directions.errors.no_place'));
65 input.val(json[0].display_name);
67 endpoint.latlng = L.latLng(json[0]);
69 .setLatLng(endpoint.latlng)
72 if (awaitingGeocode) {
73 awaitingGeocode = false;
79 endpoint.setLatLng = function (ll) {
80 var precision = OSM.zoomPrecision(map.getZoom());
81 input.val(ll.lat.toFixed(precision) + ", " + ll.lng.toFixed(precision));
91 function formatDistance(m) {
93 return Math.round(m) + "m";
94 } else if (m < 10000) {
95 return (m / 1000.0).toFixed(1) + "km";
97 return Math.round(m / 1000) + "km";
101 function formatTime(s) {
102 var m = Math.round(s / 60);
103 var h = Math.floor(m / 60);
105 return h + ":" + (m < 10 ? '0' : '') + m;
108 function setEngine(id) {
109 engines.forEach(function(engine, i) {
110 if (engine.id == id) {
111 chosenEngine = engine;
117 function getRoute() {
118 if (endpoints[0].awaitingGeocode || endpoints[1].awaitingGeocode) {
119 awaitingGeocode = true;
123 var o = endpoints[0].latlng,
124 d = endpoints[1].latlng;
126 if (!o || !d) return;
128 var precision = OSM.zoomPrecision(map.getZoom());
130 OSM.router.replace("/directions?" + querystring.stringify({
131 engine: chosenEngine.id,
132 route: o.lat.toFixed(precision) + ',' + o.lng.toFixed(precision) + ';' +
133 d.lat.toFixed(precision) + ',' + d.lng.toFixed(precision)
136 $(".directions_form .spinner").show();
137 awaitingRoute = true;
139 chosenEngine.getRoute([o, d], function (err, route) {
140 awaitingRoute = false;
142 $(".directions_form .spinner").hide();
145 map.removeLayer(polyline);
148 alert(I18n.t('javascripts.directions.errors.no_route'));
155 .setLatLngs(route.line)
158 map.setSidebarOverlaid(false);
161 map.fitBounds(polyline.getBounds().pad(0.05));
164 var html = '<h2><a class="geolink" href="#">' +
165 '<span class="icon close"></span></a>' + I18n.t('javascripts.directions.directions') +
166 '</h2><p id="routing_summary">' +
167 I18n.t('javascripts.directions.distance') + ': ' + formatDistance(route.distance) + '. ' +
168 I18n.t('javascripts.directions.time') + ': ' + formatTime(route.time) + '.</p>' +
169 '<table id="turnbyturn" />';
171 $('#sidebar_content')
176 route.steps.forEach(function (step) {
179 instruction = step[2],
187 } else if (dist < 200) {
188 dist = Math.round(dist / 10) * 10 + "m";
189 } else if (dist < 1500) {
190 dist = Math.round(dist / 100) * 100 + "m";
191 } else if (dist < 5000) {
192 dist = Math.round(dist / 100) / 10 + "km";
194 dist = Math.round(dist / 1000) + "km";
197 var row = $("<tr class='turn'/>");
198 row.append("<td><div class='direction i" + direction + "'/></td> ");
199 row.append("<td class='instruction'>" + instruction);
200 row.append("<td class='distance'>" + dist);
202 row.on('click', function () {
205 .setContent("<p>" + instruction + "</p>")
209 row.hover(function () {
214 map.removeLayer(highlight);
217 $('#turnbyturn').append(row);
220 $('#sidebar_content').append('<p id="routing_credit">' +
221 I18n.t('javascripts.directions.instructions.courtesy', {link: chosenEngine.creditline}) +
226 var engines = OSM.Directions.engines;
228 engines.sort(function (a, b) {
229 a = I18n.t('javascripts.directions.engines.' + a.id);
230 b = I18n.t('javascripts.directions.engines.' + b.id);
231 return a.localeCompare(b);
234 var select = $('select.routing_engines');
236 engines.forEach(function(engine, i) {
237 select.append("<option value='" + i + "'>" + I18n.t('javascripts.directions.engines.' + engine.id) + "</option>");
240 setEngine('osrm_car');
242 select.on("change", function (e) {
243 chosenEngine = engines[e.target.selectedIndex];
244 if (map.hasLayer(polyline)) {
249 $(".directions_form").on("submit", function(e) {
251 $("header").addClass("closed");
255 $(".routing_marker").on('dragstart', function (e) {
256 e.originalEvent.dataTransfer.effectAllowed = 'move';
257 e.originalEvent.dataTransfer.setData('id', this.id);
258 var xo = e.originalEvent.clientX - $(e.target).offset().left;
259 var yo = e.originalEvent.clientY - $(e.target).offset().top;
260 e.originalEvent.dataTransfer.setData('offsetX', e.originalEvent.target.width / 2 - xo);
261 e.originalEvent.dataTransfer.setData('offsetY', e.originalEvent.target.height - yo);
266 page.pushstate = page.popstate = function() {
267 $(".search_form").hide();
268 $(".directions_form").show();
270 $("#map").on('dragend dragover', function (e) {
274 $("#map").on('drop', function (e) {
276 var oe = e.originalEvent;
277 var id = oe.dataTransfer.getData('id');
278 var pt = L.DomEvent.getMousePosition(oe, map.getContainer()); // co-ordinates of the mouse pointer at present
279 pt.x += Number(oe.dataTransfer.getData('offsetX'));
280 pt.y += Number(oe.dataTransfer.getData('offsetY'));
281 var ll = map.containerPointToLatLng(pt);
282 endpoints[id === 'marker_from' ? 0 : 1].setLatLng(ll);
286 var params = querystring.parse(location.search.substring(1)),
287 route = (params.route || '').split(';');
290 setEngine(params.engine);
293 var o = route[0] && L.latLng(route[0].split(',')),
294 d = route[1] && L.latLng(route[1].split(','));
296 if (o) endpoints[0].setLatLng(o);
297 if (d) endpoints[1].setLatLng(d);
299 map.setSidebarOverlaid(!o || !d);
304 page.load = function() {
308 page.unload = function() {
309 $(".search_form").show();
310 $(".directions_form").hide();
311 $("#map").off('dragend dragover drop');
315 .removeLayer(polyline)
316 .removeLayer(endpoints[0].marker)
317 .removeLayer(endpoints[1].marker);
323 OSM.Directions.engines = [];
325 OSM.Directions.addEngine = function (engine, supportsHTTPS) {
326 if (document.location.protocol == "http:" || supportsHTTPS) {
327 OSM.Directions.engines.push(engine);