]> git.openstreetmap.org Git - rails.git/commitdiff
Move directions route output to its own module
authorAnton Khorev <tony29@yandex.ru>
Wed, 9 Apr 2025 15:31:58 +0000 (18:31 +0300)
committerAnton Khorev <tony29@yandex.ru>
Wed, 9 Apr 2025 18:49:33 +0000 (21:49 +0300)
app/assets/javascripts/index/directions-route-output.js [new file with mode: 0644]
app/assets/javascripts/index/directions.js

diff --git a/app/assets/javascripts/index/directions-route-output.js b/app/assets/javascripts/index/directions-route-output.js
new file mode 100644 (file)
index 0000000..1f1ff4d
--- /dev/null
@@ -0,0 +1,138 @@
+OSM.DirectionsRouteOutput = function (map) {
+  const popup = L.popup({ autoPanPadding: [100, 100] });
+
+  const polyline = L.polyline([], {
+    color: "#03f",
+    opacity: 0.3,
+    weight: 10
+  });
+
+  const highlight = L.polyline([], {
+    color: "#ff0",
+    opacity: 0.5,
+    weight: 12
+  });
+
+  let downloadURL = null;
+
+  function formatTotalDistance(m) {
+    if (m < 1000) {
+      return OSM.i18n.t("javascripts.directions.distance_m", { distance: Math.round(m) });
+    } else if (m < 10000) {
+      return OSM.i18n.t("javascripts.directions.distance_km", { distance: (m / 1000.0).toFixed(1) });
+    } else {
+      return OSM.i18n.t("javascripts.directions.distance_km", { distance: Math.round(m / 1000) });
+    }
+  }
+
+  function formatStepDistance(m) {
+    if (m < 5) {
+      return "";
+    } else if (m < 200) {
+      return OSM.i18n.t("javascripts.directions.distance_m", { distance: String(Math.round(m / 10) * 10) });
+    } else if (m < 1500) {
+      return OSM.i18n.t("javascripts.directions.distance_m", { distance: String(Math.round(m / 100) * 100) });
+    } else if (m < 5000) {
+      return OSM.i18n.t("javascripts.directions.distance_km", { distance: String(Math.round(m / 100) / 10) });
+    } else {
+      return OSM.i18n.t("javascripts.directions.distance_km", { distance: String(Math.round(m / 1000)) });
+    }
+  }
+
+  function formatHeight(m) {
+    return OSM.i18n.t("javascripts.directions.distance_m", { distance: Math.round(m) });
+  }
+
+  function formatTime(s) {
+    let m = Math.round(s / 60);
+    const h = Math.floor(m / 60);
+    m -= h * 60;
+    return h + ":" + (m < 10 ? "0" : "") + m;
+  }
+
+  const routeOutput = {};
+
+  routeOutput.write = function (content, engine, route) {
+    polyline
+      .setLatLngs(route.line)
+      .addTo(map);
+
+    const distanceText = $("<p>").append(
+      OSM.i18n.t("javascripts.directions.distance") + ": " + formatTotalDistance(route.distance) + ". " +
+      OSM.i18n.t("javascripts.directions.time") + ": " + formatTime(route.time) + ".");
+    if (typeof route.ascend !== "undefined" && typeof route.descend !== "undefined") {
+      distanceText.append(
+        $("<br>"),
+        OSM.i18n.t("javascripts.directions.ascend") + ": " + formatHeight(route.ascend) + ". " +
+        OSM.i18n.t("javascripts.directions.descend") + ": " + formatHeight(route.descend) + ".");
+    }
+
+    const turnByTurnTable = $("<table class='table table-hover table-sm mb-3'>")
+      .append($("<tbody>"));
+
+    content
+      .empty()
+      .append(
+        distanceText,
+        turnByTurnTable
+      );
+
+    for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) {
+      const row = $("<tr class='turn'/>").appendTo(turnByTurnTable);
+
+      if (direction) {
+        row.append("<td class='border-0'><svg width='20' height='20' class='d-block'><use href='#routing-sprite-" + direction + "' /></svg></td>");
+      } else {
+        row.append("<td class='border-0'>");
+      }
+      row.append(`<td><b>${i + 1}.</b> ${instruction}`);
+      row.append("<td class='distance text-body-secondary text-end'>" + formatStepDistance(dist));
+
+      row.on("click", function () {
+        popup
+          .setLatLng(lineseg[0])
+          .setContent(`<p><b>${i + 1}.</b> ${instruction}</p>`)
+          .openOn(map);
+      });
+
+      row.hover(function () {
+        highlight
+          .setLatLngs(lineseg)
+          .addTo(map);
+      }, function () {
+        map.removeLayer(highlight);
+      });
+    }
+
+    const blob = new Blob([JSON.stringify(polyline.toGeoJSON())], { type: "application/json" });
+    URL.revokeObjectURL(downloadURL);
+    downloadURL = URL.createObjectURL(blob);
+
+    content.append(`<p class="text-center"><a href="${downloadURL}" download="${
+      OSM.i18n.t("javascripts.directions.filename")
+    }">${
+      OSM.i18n.t("javascripts.directions.download")
+    }</a></p>`);
+
+    content.append("<p class=\"text-center\">" +
+      OSM.i18n.t("javascripts.directions.instructions.courtesy", { link: engine.creditline }) +
+      "</p>");
+  };
+
+  routeOutput.fit = function () {
+    map.fitBounds(polyline.getBounds().pad(0.05));
+  };
+
+  routeOutput.isVisible = function () {
+    return map.hasLayer(polyline);
+  };
+
+  routeOutput.remove = function (content) {
+    content.empty();
+    map
+      .removeLayer(popup)
+      .removeLayer(polyline);
+  };
+
+  return routeOutput;
+};
index d2d23c5452565f8497008d2a505d68ffbee7f530..b97151989070ad10f783fcfd66f1e919d68d035a 100644 (file)
@@ -1,4 +1,5 @@
 //= require ./directions-endpoint
+//= require ./directions-route-output
 //= require_self
 //= require_tree ./directions
 
@@ -7,22 +8,10 @@ OSM.Directions = function (map) {
   let lastLocation = [];
   let chosenEngine;
 
-  const popup = L.popup({ autoPanPadding: [100, 100] });
-
-  const polyline = L.polyline([], {
-    color: "#03f",
-    opacity: 0.3,
-    weight: 10
-  });
-
-  const highlight = L.polyline([], {
-    color: "#ff0",
-    opacity: 0.5,
-    weight: 12
-  });
+  const routeOutput = OSM.DirectionsRouteOutput(map);
 
   const endpointDragCallback = function (dragging) {
-    if (!map.hasLayer(polyline)) return;
+    if (!routeOutput.isVisible()) return;
     if (dragging && !chosenEngine.draggable) return;
     if (dragging && controller) return;
 
@@ -37,8 +26,6 @@ OSM.Directions = function (map) {
     OSM.DirectionsEndpoint(map, $("input[name='route_to']"), { icon: "MARKER_RED" }, endpointDragCallback, endpointChangeCallback)
   ];
 
-  let downloadURL = null;
-
   const expiry = new Date();
   expiry.setYear(expiry.getFullYear() + 10);
 
@@ -70,41 +57,6 @@ OSM.Directions = function (map) {
     OSM.router.route("/" + OSM.formatHash(map));
   });
 
-  function formatTotalDistance(m) {
-    if (m < 1000) {
-      return OSM.i18n.t("javascripts.directions.distance_m", { distance: Math.round(m) });
-    } else if (m < 10000) {
-      return OSM.i18n.t("javascripts.directions.distance_km", { distance: (m / 1000.0).toFixed(1) });
-    } else {
-      return OSM.i18n.t("javascripts.directions.distance_km", { distance: Math.round(m / 1000) });
-    }
-  }
-
-  function formatStepDistance(m) {
-    if (m < 5) {
-      return "";
-    } else if (m < 200) {
-      return OSM.i18n.t("javascripts.directions.distance_m", { distance: String(Math.round(m / 10) * 10) });
-    } else if (m < 1500) {
-      return OSM.i18n.t("javascripts.directions.distance_m", { distance: String(Math.round(m / 100) * 100) });
-    } else if (m < 5000) {
-      return OSM.i18n.t("javascripts.directions.distance_km", { distance: String(Math.round(m / 100) / 10) });
-    } else {
-      return OSM.i18n.t("javascripts.directions.distance_km", { distance: String(Math.round(m / 1000)) });
-    }
-  }
-
-  function formatHeight(m) {
-    return OSM.i18n.t("javascripts.directions.distance_m", { distance: Math.round(m) });
-  }
-
-  function formatTime(s) {
-    let m = Math.round(s / 60);
-    const h = Math.floor(m / 60);
-    m -= h * 60;
-    return h + ":" + (m < 10 ? "0" : "") + m;
-  }
-
   function setEngine(id) {
     const engines = OSM.Directions.engines;
     const desired = engines.find(engine => engine.id === id);
@@ -155,77 +107,12 @@ OSM.Directions = function (map) {
     map.setSidebarOverlaid(false);
     controller = new AbortController();
     chosenEngine.getRoute(points, controller.signal).then(function (route) {
-      polyline
-        .setLatLngs(route.line)
-        .addTo(map);
-
+      routeOutput.write($("#directions_content"), chosenEngine, route);
       if (fitRoute) {
-        map.fitBounds(polyline.getBounds().pad(0.05));
-      }
-
-      const distanceText = $("<p>").append(
-        OSM.i18n.t("javascripts.directions.distance") + ": " + formatTotalDistance(route.distance) + ". " +
-        OSM.i18n.t("javascripts.directions.time") + ": " + formatTime(route.time) + ".");
-      if (typeof route.ascend !== "undefined" && typeof route.descend !== "undefined") {
-        distanceText.append(
-          $("<br>"),
-          OSM.i18n.t("javascripts.directions.ascend") + ": " + formatHeight(route.ascend) + ". " +
-          OSM.i18n.t("javascripts.directions.descend") + ": " + formatHeight(route.descend) + ".");
-      }
-
-      const turnByTurnTable = $("<table class='table table-hover table-sm mb-3'>")
-        .append($("<tbody>"));
-
-      $("#directions_content")
-        .empty()
-        .append(
-          distanceText,
-          turnByTurnTable
-        );
-
-      // Add each row
-      for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) {
-        const row = $("<tr class='turn'/>").appendTo(turnByTurnTable);
-
-        if (direction) {
-          row.append("<td class='border-0'><svg width='20' height='20' class='d-block'><use href='#routing-sprite-" + direction + "' /></svg></td>");
-        } else {
-          row.append("<td class='border-0'>");
-        }
-        row.append(`<td><b>${i + 1}.</b> ${instruction}`);
-        row.append("<td class='distance text-body-secondary text-end'>" + formatStepDistance(dist));
-
-        row.on("click", function () {
-          popup
-            .setLatLng(lineseg[0])
-            .setContent(`<p><b>${i + 1}.</b> ${instruction}</p>`)
-            .openOn(map);
-        });
-
-        row.hover(function () {
-          highlight
-            .setLatLngs(lineseg)
-            .addTo(map);
-        }, function () {
-          map.removeLayer(highlight);
-        });
+        routeOutput.fit();
       }
-
-      const blob = new Blob([JSON.stringify(polyline.toGeoJSON())], { type: "application/json" });
-      URL.revokeObjectURL(downloadURL);
-      downloadURL = URL.createObjectURL(blob);
-
-      $("#directions_content").append(`<p class="text-center"><a href="${downloadURL}" download="${
-        OSM.i18n.t("javascripts.directions.filename")
-      }">${
-        OSM.i18n.t("javascripts.directions.download")
-      }</a></p>`);
-
-      $("#directions_content").append("<p class=\"text-center\">" +
-        OSM.i18n.t("javascripts.directions.instructions.courtesy", { link: chosenEngine.creditline }) +
-        "</p>");
     }).catch(function () {
-      map.removeLayer(polyline);
+      routeOutput.remove($("#directions_content"));
       if (reportErrors) {
         $("#directions_content").html("<div class=\"alert alert-danger\">" + OSM.i18n.t("javascripts.directions.errors.no_route") + "</div>");
       }
@@ -236,9 +123,7 @@ OSM.Directions = function (map) {
 
   function hideRoute(e) {
     e.stopPropagation();
-    map.removeLayer(polyline);
-    $("#directions_content").html("");
-    popup.close();
+    routeOutput.remove($("#directions_content"));
     map.setSidebarOverlaid(true);
     // TODO: collapse width of sidebar back to previous
   }
@@ -366,9 +251,7 @@ OSM.Directions = function (map) {
     endpoints[0].clearValue();
     endpoints[1].clearValue();
 
-    map
-      .removeLayer(popup)
-      .removeLayer(polyline);
+    routeOutput.remove($("#directions_content"));
   };
 
   return page;