]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/directions-route-output.js
Merge remote-tracking branch 'upstream/pull/5923'
[rails.git] / app / assets / javascripts / index / directions-route-output.js
1 OSM.DirectionsRouteOutput = function (map) {
2   const popup = L.popup({ autoPanPadding: [100, 100] });
3
4   const polyline = L.polyline([], {
5     color: "#03f",
6     opacity: 0.3,
7     weight: 10
8   });
9
10   const highlight = L.polyline([], {
11     color: "#ff0",
12     opacity: 0.5,
13     weight: 12
14   });
15
16   let downloadURL = null;
17
18   function formatTotalDistance(m) {
19     if (m < 1000) {
20       return OSM.i18n.t("javascripts.directions.distance_m", { distance: Math.round(m) });
21     } else if (m < 10000) {
22       return OSM.i18n.t("javascripts.directions.distance_km", { distance: (m / 1000.0).toFixed(1) });
23     } else {
24       return OSM.i18n.t("javascripts.directions.distance_km", { distance: Math.round(m / 1000) });
25     }
26   }
27
28   function formatStepDistance(m) {
29     if (m < 5) {
30       return "";
31     } else if (m < 200) {
32       return OSM.i18n.t("javascripts.directions.distance_m", { distance: String(Math.round(m / 10) * 10) });
33     } else if (m < 1500) {
34       return OSM.i18n.t("javascripts.directions.distance_m", { distance: String(Math.round(m / 100) * 100) });
35     } else if (m < 5000) {
36       return OSM.i18n.t("javascripts.directions.distance_km", { distance: String(Math.round(m / 100) / 10) });
37     } else {
38       return OSM.i18n.t("javascripts.directions.distance_km", { distance: String(Math.round(m / 1000)) });
39     }
40   }
41
42   function formatHeight(m) {
43     return OSM.i18n.t("javascripts.directions.distance_m", { distance: Math.round(m) });
44   }
45
46   function formatTime(s) {
47     let m = Math.round(s / 60);
48     const h = Math.floor(m / 60);
49     m -= h * 60;
50     return h + ":" + (m < 10 ? "0" : "") + m;
51   }
52
53   const routeOutput = {};
54
55   routeOutput.write = function (content, route) {
56     polyline
57       .setLatLngs(route.line)
58       .addTo(map);
59
60     const distanceText = $("<p>").append(
61       OSM.i18n.t("javascripts.directions.distance") + ": " + formatTotalDistance(route.distance) + ". " +
62       OSM.i18n.t("javascripts.directions.time") + ": " + formatTime(route.time) + ".");
63     if (typeof route.ascend !== "undefined" && typeof route.descend !== "undefined") {
64       distanceText.append(
65         $("<br>"),
66         OSM.i18n.t("javascripts.directions.ascend") + ": " + formatHeight(route.ascend) + ". " +
67         OSM.i18n.t("javascripts.directions.descend") + ": " + formatHeight(route.descend) + ".");
68     }
69
70     const turnByTurnTable = $("<table class='table table-hover table-sm mb-3'>")
71       .append($("<tbody>"));
72
73     content
74       .empty()
75       .append(
76         distanceText,
77         turnByTurnTable
78       );
79
80     for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) {
81       const row = $("<tr class='turn'/>").appendTo(turnByTurnTable);
82
83       if (direction) {
84         row.append("<td class='border-0'><svg width='20' height='20' class='d-block'><use href='#routing-sprite-" + direction + "' /></svg></td>");
85       } else {
86         row.append("<td class='border-0'>");
87       }
88       row.append(`<td><b>${i + 1}.</b> ${instruction}`);
89       row.append("<td class='distance text-body-secondary text-end'>" + formatStepDistance(dist));
90
91       row.on("click", function () {
92         popup
93           .setLatLng(lineseg[0])
94           .setContent(`<p><b>${i + 1}.</b> ${instruction}</p>`)
95           .openOn(map);
96       });
97
98       row
99         .on("mouseenter", function () {
100           highlight
101             .setLatLngs(lineseg)
102             .addTo(map);
103         })
104         .on("mouseleave", function () {
105           map.removeLayer(highlight);
106         });
107     }
108
109     const blob = new Blob([JSON.stringify(polyline.toGeoJSON())], { type: "application/json" });
110     URL.revokeObjectURL(downloadURL);
111     downloadURL = URL.createObjectURL(blob);
112
113     content.append(`<p class="text-center"><a href="${downloadURL}" download="${
114       OSM.i18n.t("javascripts.directions.filename")
115     }">${
116       OSM.i18n.t("javascripts.directions.download")
117     }</a></p>`);
118
119     content.append("<p class=\"text-center\">" +
120       OSM.i18n.t("javascripts.directions.instructions.courtesy", {
121         link: `<a href="${route.creditlink}" target="_blank">${route.credit}</a>`
122       }) +
123       "</p>");
124   };
125
126   routeOutput.fit = function () {
127     map.fitBounds(polyline.getBounds().pad(0.05));
128   };
129
130   routeOutput.isVisible = function () {
131     return map.hasLayer(polyline);
132   };
133
134   routeOutput.remove = function (content) {
135     content.empty();
136     map
137       .removeLayer(popup)
138       .removeLayer(polyline);
139   };
140
141   return routeOutput;
142 };