From: Anton Khorev Date: Wed, 9 Apr 2025 15:31:58 +0000 (+0300) Subject: Move directions route output to its own module X-Git-Tag: live~61^2~2 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/7196368d6a27f4c3313e60c82ed06c959d60e90b?ds=sidebyside;hp=--cc Move directions route output to its own module --- 7196368d6a27f4c3313e60c82ed06c959d60e90b diff --git a/app/assets/javascripts/index/directions-route-output.js b/app/assets/javascripts/index/directions-route-output.js new file mode 100644 index 000000000..1f1ff4df6 --- /dev/null +++ b/app/assets/javascripts/index/directions-route-output.js @@ -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 = $("

").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( + $("
"), + OSM.i18n.t("javascripts.directions.ascend") + ": " + formatHeight(route.ascend) + ". " + + OSM.i18n.t("javascripts.directions.descend") + ": " + formatHeight(route.descend) + "."); + } + + const turnByTurnTable = $("") + .append($("")); + + content + .empty() + .append( + distanceText, + turnByTurnTable + ); + + for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) { + const row = $("").appendTo(turnByTurnTable); + + if (direction) { + row.append(""); + } else { + row.append("
"); + } + row.append(`${i + 1}. ${instruction}`); + row.append("" + formatStepDistance(dist)); + + row.on("click", function () { + popup + .setLatLng(lineseg[0]) + .setContent(`

${i + 1}. ${instruction}

`) + .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(`

${ + OSM.i18n.t("javascripts.directions.download") + }

`); + + content.append("

" + + OSM.i18n.t("javascripts.directions.instructions.courtesy", { link: engine.creditline }) + + "

"); + }; + + 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; +}; diff --git a/app/assets/javascripts/index/directions.js b/app/assets/javascripts/index/directions.js index d2d23c545..b97151989 100644 --- a/app/assets/javascripts/index/directions.js +++ b/app/assets/javascripts/index/directions.js @@ -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 = $("

").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( - $("
"), - OSM.i18n.t("javascripts.directions.ascend") + ": " + formatHeight(route.ascend) + ". " + - OSM.i18n.t("javascripts.directions.descend") + ": " + formatHeight(route.descend) + "."); - } - - const turnByTurnTable = $("") - .append($("")); - - $("#directions_content") - .empty() - .append( - distanceText, - turnByTurnTable - ); - - // Add each row - for (const [i, [direction, instruction, dist, lineseg]] of route.steps.entries()) { - const row = $("").appendTo(turnByTurnTable); - - if (direction) { - row.append(""); - } else { - row.append("
"); - } - row.append(`${i + 1}. ${instruction}`); - row.append("" + formatStepDistance(dist)); - - row.on("click", function () { - popup - .setLatLng(lineseg[0]) - .setContent(`

${i + 1}. ${instruction}

`) - .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(`

${ - OSM.i18n.t("javascripts.directions.download") - }

`); - - $("#directions_content").append("

" + - OSM.i18n.t("javascripts.directions.instructions.courtesy", { link: chosenEngine.creditline }) + - "

"); }).catch(function () { - map.removeLayer(polyline); + routeOutput.remove($("#directions_content")); if (reportErrors) { $("#directions_content").html("
" + OSM.i18n.t("javascripts.directions.errors.no_route") + "
"); } @@ -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;