Beginning of JavaScript-only routing UI
[rails.git] / app / assets / javascripts / routing.js.erb
1 /*
2         osm.org routing interface
3         
4         See also:
5         https://github.com/apmon/openstreetmap-website/tree/routing2
6         https://github.com/apmon/openstreetmap-website/compare/routing2
7         https://github.com/apmon/openstreetmap-website/blob/9755c3ae0a8d0684d43760f91dc864ff42d8477a/app/views/routing/start.js.erb
8
9         *** draggable start/end markers
10         
11 */
12
13 var TURN_INSTRUCTIONS=["",
14         "Continue on ",                         // 1
15         "Slight right onto ",           // 2
16         "Turn right onto ",                     // 3
17         "Sharp right onto ",            // 4
18         "U-turn along ",                        // 5
19         "Sharp left onto ",                     // 6
20         "Turn left onto ",                      // 7
21         "Slight left onto ",            // 8
22         "(via point) ",                         // 9
23         "Follow ",                                      // 10
24         "At roundabout take ",          // 11
25         "Leave roundabout - ",          // 12
26         "Stay on roundabout - ",        // 13
27         "Start at end of ",                     // 14
28         "Reach destination",            // 15
29         "Go against one-way on ",       // 16
30         "End of one-way on "]           // 17
31
32 var ROUTING_POLYLINE={
33         color: '#03f',
34         opacity: 0.3,
35         weight: 10
36 };
37
38
39 OSM.Routing=function(map,name,jqSearch) {
40         var r={};
41         r.map=map;                              // Leaflet map
42         r.name=name;                    // global variable name of this instance (needed for JSONP)
43         r.jqSearch=jqSearch;    // JQuery object for search panel
44
45         r.route_from=null;
46         r.route_to=null;
47         r.viaPoints=[];
48         r.polyline=null;
49
50         // Geocoding
51
52         r.geocode=function(id,event) { var _this=this;
53                 var field=event.target;
54                 var v=event.target.value;
55                 // *** do something if v==''
56                 var querystring = '<%= NOMINATIM_URL %>search?q=' + encodeURIComponent(v) + '&format=json';
57                 // *** &accept-language=<%#= request.user_preferred_languages.join(',') %>
58                 // *** prefer current viewport
59                 $.getJSON(querystring, function(json) { _this._gotGeocode(json,field); });
60         };
61         
62         r._gotGeocode=function(json,field) {
63                 if (json.length==0) {
64                         alert("Sorry, couldn't find that place.");      // *** internationalise
65                         r[field.id]=null;
66                         return;
67                 }
68                 field.value=json[0].display_name;
69                 var lat=Number(json[0].lat), lon=Number(json[0].lon);
70                 r[field.id]=[lat,lon];
71                 // ** update markers
72         };
73         
74         // Route-fetching UI
75
76         r.requestRoute=function() {
77                 if (r.route_from && r.route_to) {
78                         var chosen=jqSearch.find('select.routing_engines :selected').val();
79                         r.engines[chosen].getRoute(true,[r.route_from,r.route_to]);
80                         // then, when the route has been fetched, it'll call the engine's gotRoute function
81                 }
82         };
83
84         // Take an array of Leaflet LatLngs and draw it as a polyline
85         r.setPolyline=function(line) {
86                 if (r.polyline) map.removeLayer(r.polyline);
87                 r.polyline=L.polyline(line, ROUTING_POLYLINE).addTo(r.map);
88                 // *** zoom to fit
89         };
90
91         // Take an array of directions and write it out
92         // (we use OSRM's route_instructions format)
93         r.setItinerary=function(steps) {
94                 $("#content").removeClass("overlay-sidebar");
95                 $('#sidebar_content').empty();
96                 var html="";
97                 for (var i=0; i<steps.length; i++) {
98                         var s=steps[i];
99                         html+="<div class='route_step'>";
100                         html+=TURN_INSTRUCTIONS[s[0]] || s[0];
101                         html+=s[1];
102                         html+="</div>";
103                 }
104         $('#sidebar_content').html(html);
105         };
106
107
108         // Add engines
109         
110         r.engines=[];
111         r.addEngine=function(engine) {
112                 // Save engine
113                 var i=r.engines.length;
114                 engine.subscript=i;
115                 r['engine'+i]=engine;
116                 r.engines.push(engine);
117
118                 // Add generic JSONP function
119                 engine.requestJSONP=function(url) {
120                         var script = document.createElement('script');
121                         script.src = url+"&jsonp="+r.name+".engine"+this.subscript+".gotRoute";
122                         // OSRM doesn't like non-alphanumeric, otherwise we could just do OSM.routing.engines["+engine.subscript+"].gotRoute
123                         document.body.appendChild(script); 
124                 };
125
126                 // Populate dropdown
127                 var select=jqSearch.find('select.routing_engines');
128                 select.append("<option value='"+i+"'>"+engine.name+"</option>");
129         };
130
131         // OSRM car engine
132         // *** this should all be shared from an OSRM library somewhere
133         // *** need to clear hints at some point
134
135         r.addEngine({
136                 name: 'Car (OSRM)',
137                 draggable: true,
138                 _hints: {},
139                 getRoute: function(final,points) {
140                         var url="http://router.project-osrm.org/viaroute?z=14&output=json";
141                         for (var i=0; i<points.length; i++) {
142                                 var pair=points[i].join(',');
143                                 url+="&loc="+pair;
144                                 if (this._hints[pair]) url+= "&hint="+this._hints[pair];
145                         }
146                         if (final) url+="&instructions=true";
147                         this.requestJSONP(url);
148                 },
149                 gotRoute: function(data) {
150                         // *** save hints
151                         var line=L.PolylineUtil.decode(data.route_geometry);
152                         for (i=0; i<line.length; i++) { line[i].lat/=10; line[i].lng/=10; }
153                         r.setPolyline(line);
154                         r.setItinerary(data.route_instructions);
155                 }
156         });
157
158         return r;
159 };