]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/directions/fossgis.js
Replace deprecated String.prototype.substr()
[rails.git] / app / assets / javascripts / index / directions / fossgis.js
1 // FOSSGIS engine (OSRM based)
2 // Doesn't yet support hints
3
4 function FOSSGISEngine(id, vehicleType) {
5   var cachedHints = [];
6
7   return {
8     id: id,
9     creditline: "<a href=\"https://routing.openstreetmap.de/about.html\" target=\"_blank\">FOSSGIS Routing Service</a>",
10     draggable: true,
11
12     _transformSteps: function (input_steps, line) {
13       var INSTRUCTION_TEMPLATE = {
14         "continue": "javascripts.directions.instructions.continue",
15         "merge right": "javascripts.directions.instructions.merge_right",
16         "merge left": "javascripts.directions.instructions.merge_left",
17         "off ramp right": "javascripts.directions.instructions.offramp_right",
18         "off ramp left": "javascripts.directions.instructions.offramp_left",
19         "on ramp right": "javascripts.directions.instructions.onramp_right",
20         "on ramp left": "javascripts.directions.instructions.onramp_left",
21         "fork right": "javascripts.directions.instructions.fork_right",
22         "fork left": "javascripts.directions.instructions.fork_left",
23         "end of road right": "javascripts.directions.instructions.endofroad_right",
24         "end of road left": "javascripts.directions.instructions.endofroad_left",
25         "turn straight": "javascripts.directions.instructions.continue",
26         "turn slight right": "javascripts.directions.instructions.slight_right",
27         "turn right": "javascripts.directions.instructions.turn_right",
28         "turn sharp right": "javascripts.directions.instructions.sharp_right",
29         "turn uturn": "javascripts.directions.instructions.uturn",
30         "turn sharp left": "javascripts.directions.instructions.sharp_left",
31         "turn left": "javascripts.directions.instructions.turn_left",
32         "turn slight left": "javascripts.directions.instructions.slight_left",
33         "roundabout": "javascripts.directions.instructions.roundabout",
34         "rotary": "javascripts.directions.instructions.roundabout",
35         "exit roundabout": "javascripts.directions.instructions.exit_roundabout",
36         "exit rotary": "javascripts.directions.instructions.exit_roundabout",
37         "depart": "javascripts.directions.instructions.start",
38         "arrive": "javascripts.directions.instructions.destination"
39       };
40       var ICON_MAP = {
41         "continue": 0,
42         "merge right": 21,
43         "merge left": 20,
44         "off ramp right": 24,
45         "off ramp left": 25,
46         "on ramp right": 2,
47         "on ramp left": 6,
48         "fork right": 18,
49         "fork left": 19,
50         "end of road right": 22,
51         "end of road left": 23,
52         "turn straight": 0,
53         "turn slight right": 1,
54         "turn right": 2,
55         "turn sharp right": 3,
56         "turn uturn": 4,
57         "turn slight left": 5,
58         "turn left": 6,
59         "turn sharp left": 7,
60         "roundabout": 10,
61         "rotary": 10,
62         "exit roundabout": 10,
63         "exit rotary": 10,
64         "depart": 8,
65         "arrive": 14
66       };
67       var numToWord = function (num) {
68         return ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"][num - 1];
69       };
70       var transformed_steps = input_steps.map(function (step, idx) {
71         var maneuver_id;
72
73         // special case handling
74         switch (step.maneuver.type) {
75           case "on ramp":
76           case "off ramp":
77           case "merge":
78           case "end of road":
79           case "fork":
80             maneuver_id = step.maneuver.type + " " + (step.maneuver.modifier.indexOf("left") >= 0 ? "left" : "right");
81             break;
82           case "depart":
83           case "arrive":
84           case "roundabout":
85           case "rotary":
86           case "exit roundabout":
87           case "exit rotary":
88             maneuver_id = step.maneuver.type;
89             break;
90           case "roundabout turn":
91           case "turn":
92             maneuver_id = "turn " + step.maneuver.modifier;
93             break;
94           // for unknown types the fallback is turn
95           default:
96             maneuver_id = "turn " + step.maneuver.modifier;
97             break;
98         }
99         var template = INSTRUCTION_TEMPLATE[maneuver_id];
100
101         // convert lat,lng pairs to LatLng objects
102         var step_geometry = L.PolylineUtil.decode(step.geometry, { precision: 5 }).map(function (a) { return L.latLng(a); });
103         // append step_geometry on line
104         Array.prototype.push.apply(line, step_geometry);
105
106         var instText = "<b>" + (idx + 1) + ".</b> ";
107         var destinations = "<b>" + step.destinations + "</b>";
108         var namedRoad = true;
109         var name;
110
111         if (step.name && step.ref) {
112           name = "<b>" + step.name + " (" + step.ref + ")</b>";
113         } else if (step.name) {
114           name = "<b>" + step.name + "</b>";
115         } else if (step.ref) {
116           name = "<b>" + step.ref + "</b>";
117         } else {
118           name = I18n.t("javascripts.directions.instructions.unnamed");
119           namedRoad = false;
120         }
121
122         if (step.maneuver.type.match(/^exit (rotary|roundabout)$/)) {
123           instText += I18n.t(template, { name: name });
124         } else if (step.maneuver.type.match(/^(rotary|roundabout)$/)) {
125           if (step.maneuver.exit) {
126             if (step.maneuver.exit <= 10) {
127               instText += I18n.t(template + "_with_exit_ordinal", { exit: I18n.t("javascripts.directions.instructions.exit_counts." + numToWord(step.maneuver.exit)), name: name });
128             } else {
129               instText += I18n.t(template + "_with_exit", { exit: step.maneuver.exit, name: name });
130             }
131           } else {
132             instText += I18n.t(template + "_without_exit", { name: name });
133           }
134         } else if (step.maneuver.type.match(/^(on ramp|off ramp)$/)) {
135           var params = {};
136           if (step.exits && step.maneuver.type.match(/^(off ramp)$/)) params.exit = step.exits;
137           if (step.destinations) params.directions = destinations;
138           if (namedRoad) params.directions = name;
139           if (Object.keys(params).length > 0) {
140             template = template + "_with_" + Object.keys(params).join("_");
141           }
142           instText += I18n.t(template, params);
143         } else {
144           instText += I18n.t(template + "_without_exit", { name: name });
145         }
146         return [[step.maneuver.location[1], step.maneuver.location[0]], ICON_MAP[maneuver_id], instText, step.distance, step_geometry];
147       });
148
149       return transformed_steps;
150     },
151
152     getRoute: function (points, callback) {
153       var params = [
154         { name: "overview", value: "false" },
155         { name: "geometries", value: "polyline" },
156         { name: "steps", value: true }
157       ];
158
159
160       if (cachedHints.length === points.length) {
161         params.push({ name: "hints", value: cachedHints.join(";") });
162       } else {
163         // invalidate cache
164         cachedHints = [];
165       }
166
167       var encoded_coords = points.map(function (p) {
168         return p.lng + "," + p.lat;
169       }).join(";");
170
171       var req_url = OSM.FOSSGIS_OSRM_URL + "routed-" + vehicleType + "/route/v1/driving/" + encoded_coords;
172
173       var onResponse = function (data) {
174         if (data.code !== "Ok") {
175           return callback(true);
176         }
177
178         cachedHints = data.waypoints.map(function (wp) {
179           return wp.hint;
180         });
181
182         var line = [];
183         var transformLeg = function (leg) {
184           return this._transformSteps(leg.steps, line);
185         };
186
187         var steps = [].concat.apply([], data.routes[0].legs.map(transformLeg.bind(this)));
188
189         callback(false, {
190           line: line,
191           steps: steps,
192           distance: data.routes[0].distance,
193           time: data.routes[0].duration
194         });
195       };
196
197       return $.ajax({
198         url: req_url,
199         data: params,
200         dataType: "json",
201         success: onResponse.bind(this),
202         error: function () {
203           callback(true);
204         }
205       });
206     }
207   };
208 }
209
210 OSM.Directions.addEngine(new FOSSGISEngine("fossgis_osrm_car", "car"), true);
211 OSM.Directions.addEngine(new FOSSGISEngine("fossgis_osrm_bike", "bike"), true);
212 OSM.Directions.addEngine(new FOSSGISEngine("fossgis_osrm_foot", "foot"), true);
213