]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/directions-route-output.js
Remove unnecessary string conversions in distance formatting
[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     const scope = "javascripts.directions.distance_in_units";
20
21     if (m < 1000) {
22       return OSM.i18n.t("m", { scope, distance: Math.round(m) });
23     } else if (m < 10000) {
24       return OSM.i18n.t("km", { scope, distance: (m / 1000.0).toFixed(1) });
25     } else {
26       return OSM.i18n.t("km", { scope, distance: Math.round(m / 1000) });
27     }
28   }
29
30   function formatStepDistance(m) {
31     const scope = "javascripts.directions.distance_in_units";
32
33     if (m < 5) {
34       return "";
35     } else if (m < 200) {
36       return OSM.i18n.t("m", { scope, distance: Math.round(m / 10) * 10 });
37     } else if (m < 1500) {
38       return OSM.i18n.t("m", { scope, distance: Math.round(m / 100) * 100 });
39     } else if (m < 5000) {
40       return OSM.i18n.t("km", { scope, distance: Math.round(m / 100) / 10 });
41     } else {
42       return OSM.i18n.t("km", { scope, distance: Math.round(m / 1000) });
43     }
44   }
45
46   function formatHeight(m) {
47     const scope = "javascripts.directions.distance_in_units";
48
49     return OSM.i18n.t("m", { scope, distance: Math.round(m) });
50   }
51
52   function formatTime(s) {
53     let m = Math.round(s / 60);
54     const h = Math.floor(m / 60);
55     m -= h * 60;
56     return h + ":" + (m < 10 ? "0" : "") + m;
57   }
58
59   function writeSummary(route) {
60     $("#directions_route_distance").val(formatTotalDistance(route.distance));
61     $("#directions_route_time").val(formatTime(route.time));
62     if (typeof route.ascend !== "undefined" && typeof route.descend !== "undefined") {
63       $("#directions_route_ascend_descend").prop("hidden", false);
64       $("#directions_route_ascend").val(formatHeight(route.ascend));
65       $("#directions_route_descend").val(formatHeight(route.descend));
66     } else {
67       $("#directions_route_ascend_descend").prop("hidden", true);
68       $("#directions_route_ascend").val("");
69       $("#directions_route_descend").val("");
70     }
71   }
72
73   function writeSteps(route) {
74     $("#directions_route_steps").empty();
75
76     for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) {
77       const row = $("<tr class='turn'/>").appendTo($("#directions_route_steps"));
78
79       if (direction) {
80         row.append("<td class='border-0'><svg width='20' height='20' class='d-block'><use href='#routing-sprite-" + direction + "' /></svg></td>");
81       } else {
82         row.append("<td class='border-0'>");
83       }
84       row.append(`<td><b>${i + 1}.</b> ${instruction}`);
85       row.append("<td class='distance text-body-secondary text-end'>" + formatStepDistance(dist));
86
87       row.on("click", function () {
88         popup
89           .setLatLng(lineseg[0])
90           .setContent(`<p><b>${i + 1}.</b> ${instruction}</p>`)
91           .openOn(map);
92       });
93
94       row
95         .on("mouseenter", function () {
96           highlight
97             .setLatLngs(lineseg)
98             .addTo(map);
99         })
100         .on("mouseleave", function () {
101           map.removeLayer(highlight);
102         });
103     }
104   }
105
106   const routeOutput = {};
107
108   routeOutput.write = function (route) {
109     polyline
110       .setLatLngs(route.line)
111       .addTo(map);
112
113     writeSummary(route);
114     writeSteps(route);
115
116     const blob = new Blob([JSON.stringify(polyline.toGeoJSON())], { type: "application/json" });
117     URL.revokeObjectURL(downloadURL);
118     downloadURL = URL.createObjectURL(blob);
119     $("#directions_route_download").prop("href", downloadURL);
120
121     $("#directions_route_credit")
122       .text(route.credit)
123       .prop("href", route.creditlink);
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 () {
135     map
136       .removeLayer(popup)
137       .removeLayer(polyline);
138
139     $("#directions_route_steps").empty();
140
141     URL.revokeObjectURL(downloadURL);
142     $("#directions_route_download").prop("href", "");
143   };
144
145   return routeOutput;
146 };