1 OSM.DirectionsRouteOutput = function (map) {
 
   2   const popup = L.popup({ autoPanPadding: [100, 100] });
 
   4   const polyline = L.polyline([], {
 
  10   const highlight = L.polyline([], {
 
  16   let distanceUnits = "km_m";
 
  17   let downloadURL = null;
 
  19   function translateDistanceUnits(m) {
 
  20     if (distanceUnits === "mi_ft") {
 
  21       return [m / 0.3048, "ft", m / 1609.344, "mi"];
 
  22     } else if (distanceUnits === "mi_yd") {
 
  23       return [m / 0.9144, "yd", m / 1609.344, "mi"];
 
  25       return [m, "m", m / 1000, "km"];
 
  29   function formatTotalDistance(minorValue, minorName, majorValue, majorName) {
 
  30     const scope = "javascripts.directions.distance_in_units";
 
  32     if (minorValue < 1000 || majorValue < 0.25) {
 
  33       return OSM.i18n.t(minorName, { scope, distance: Math.round(minorValue) });
 
  34     } else if (majorValue < 10) {
 
  35       return OSM.i18n.t(majorName, { scope, distance: majorValue.toFixed(1) });
 
  37       return OSM.i18n.t(majorName, { scope, distance: Math.round(majorValue) });
 
  41   function formatStepDistance(minorValue, minorName, majorValue, majorName) {
 
  42     const scope = "javascripts.directions.distance_in_units";
 
  46     } else if (minorValue < 200) {
 
  47       return OSM.i18n.t(minorName, { scope, distance: Math.round(minorValue / 10) * 10 });
 
  48     } else if (minorValue < 1500 || majorValue < 0.25) {
 
  49       return OSM.i18n.t(minorName, { scope, distance: Math.round(minorValue / 100) * 100 });
 
  50     } else if (majorValue < 5) {
 
  51       return OSM.i18n.t(majorName, { scope, distance: majorValue.toFixed(1) });
 
  53       return OSM.i18n.t(majorName, { scope, distance: Math.round(majorValue) });
 
  57   function formatHeight(minorValue, minorName) {
 
  58     const scope = "javascripts.directions.distance_in_units";
 
  60     return OSM.i18n.t(minorName, { scope, distance: Math.round(minorValue) });
 
  63   function formatTime(s) {
 
  64     let m = Math.round(s / 60);
 
  65     const h = Math.floor(m / 60);
 
  67     return h + ":" + (m < 10 ? "0" : "") + m;
 
  70   function writeSummary(route) {
 
  71     $("#directions_route_distance").val(formatTotalDistance(...translateDistanceUnits(route.distance)));
 
  72     $("#directions_route_time").val(formatTime(route.time));
 
  73     if (typeof route.ascend !== "undefined" && typeof route.descend !== "undefined") {
 
  74       $("#directions_route_ascend_descend").prop("hidden", false);
 
  75       $("#directions_route_ascend").val(formatHeight(...translateDistanceUnits(route.ascend)));
 
  76       $("#directions_route_descend").val(formatHeight(...translateDistanceUnits(route.descend)));
 
  78       $("#directions_route_ascend_descend").prop("hidden", true);
 
  79       $("#directions_route_ascend").val("");
 
  80       $("#directions_route_descend").val("");
 
  84   function writeSteps(route) {
 
  85     $("#directions_route_steps").empty();
 
  87     for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) {
 
  88       const row = $("<tr class='turn'/>").appendTo($("#directions_route_steps"));
 
  91         row.append("<td class='ps-3'><svg width='20' height='20' class='d-block'><use href='#routing-sprite-" + direction + "' /></svg></td>");
 
  93         row.append("<td class='ps-3'>");
 
  95       row.append(`<td><b>${i + 1}.</b> ${instruction}`);
 
  96       row.append("<td class='pe-3 distance text-body-secondary text-end'>" + formatStepDistance(...translateDistanceUnits(dist)));
 
  98       row.on("click", function () {
 
 100           .setLatLng(lineseg[0])
 
 101           .setContent(`<p><b>${i + 1}.</b> ${instruction}</p>`)
 
 106         .on("mouseenter", function () {
 
 111         .on("mouseleave", function () {
 
 112           map.removeLayer(highlight);
 
 117   const routeOutput = {};
 
 119   routeOutput.write = function (route) {
 
 121       .setLatLngs(route.line)
 
 127     $("#directions_distance_units_settings input").off().on("change", function () {
 
 128       distanceUnits = this.value;
 
 133     const blob = new Blob([JSON.stringify(polyline.toGeoJSON())], { type: "application/json" });
 
 134     URL.revokeObjectURL(downloadURL);
 
 135     downloadURL = URL.createObjectURL(blob);
 
 136     $("#directions_route_download").prop("href", downloadURL);
 
 138     $("#directions_route_credit")
 
 140       .prop("href", route.creditlink);
 
 143   routeOutput.fit = function () {
 
 144     map.fitBounds(polyline.getBounds().pad(0.05));
 
 147   routeOutput.isVisible = function () {
 
 148     return map.hasLayer(polyline);
 
 151   routeOutput.remove = function () {
 
 154       .removeLayer(polyline);
 
 156     $("#directions_distance_units_settings input").off();
 
 158     $("#directions_route_steps").empty();
 
 160     URL.revokeObjectURL(downloadURL);
 
 161     $("#directions_route_download").prop("href", "");