From 558d8b3d0f9ea2862f242fdfc1d8b81147f7c7c3 Mon Sep 17 00:00:00 2001 From: Amaury Zarzelli Date: Wed, 4 Sep 2024 15:50:30 +0200 Subject: [PATCH] feat(routes-draw)(directions): pedestrian travel time uses elevation (#123) --- src/js/directions/directions-results-dom.js | 45 +++++++++++++++------ src/js/directions/directions-results.js | 14 +++++++ src/js/directions/directions.js | 8 +++- src/js/globals.js | 9 +++++ src/js/route-draw/route-draw.js | 3 ++ src/js/utils/gis-utils.js | 9 ++++- 6 files changed, 73 insertions(+), 15 deletions(-) diff --git a/src/js/directions/directions-results-dom.js b/src/js/directions/directions-results-dom.js index af3c58d6..1abec542 100644 --- a/src/js/directions/directions-results-dom.js +++ b/src/js/directions/directions-results-dom.js @@ -46,7 +46,12 @@ let DirectionsResultsDOM = { noDetailsDiv.appendChild(this.__addResultsDetailsContainerDOMElement()); container.appendChild(noDetailsDiv); // ajout des détails - container.appendChild(this.__addResultsListDetailsContainerDOMElement(data.instructions, data.transport)); + try { + + container.appendChild(this.__addResultsListDetailsContainerDOMElement(data.instructions, data.transport)); + } catch (err) { + console.error(err); + } return container; }, @@ -155,7 +160,28 @@ let DirectionsResultsDOM = { divList.id = "directionsListDetails"; divList.className = ""; + divList.appendChild(this.__addInstructionListDOMElement(instructions)); + // FIXME comment fusionner les points intermediaires ? + if (transport !== "Voiture") { + var profileHeader = document.createElement("p"); + profileHeader.className = "elevationLineHeader"; + profileHeader.textContent = "Profil altimétrique"; + divList.appendChild(profileHeader); + + var canvasProfile = document.createElement("canvas"); + canvasProfile.id = "directions-elevationline"; + canvasProfile.className = "elevationLineCanvas"; + canvasProfile.style.width = "100%"; + divList.appendChild(canvasProfile); + } + + return divList; + }, + + __addInstructionListDOMElement(instructions) { + var divList = document.createElement("div"); + divList.id = "directionsInstructionsList"; var first = instructions[0].steps[0]; var last = instructions.slice(-1)[0].steps.slice(-1)[0]; @@ -203,18 +229,6 @@ let DirectionsResultsDOM = { } }); } - if (transport !== "Voiture") { - var profileHeader = document.createElement("p"); - profileHeader.className = "elevationLineHeader"; - profileHeader.textContent = "Profil altimétrique"; - divList.appendChild(profileHeader); - - var canvasProfile = document.createElement("canvas"); - canvasProfile.id = "directions-elevationline"; - canvasProfile.className = "elevationLineCanvas"; - canvasProfile.style.width = "100%"; - divList.appendChild(canvasProfile); - } return divList; }, @@ -281,6 +295,11 @@ let DirectionsResultsDOM = { return divContainer; + }, + + __updateDurationDom() { + this.dom.container.querySelector("#directionsSummaryDuration").textContent = utils.convertSecondsToTime(this.options.duration); + this.dom.container.querySelector("#directionsInstructionsList").replaceWith(this.__addInstructionListDOMElement(this.options.instructions)); } }; diff --git a/src/js/directions/directions-results.js b/src/js/directions/directions-results.js index 981819c5..c33ab233 100644 --- a/src/js/directions/directions-results.js +++ b/src/js/directions/directions-results.js @@ -98,6 +98,20 @@ class DirectionsResults { } } + updateDuration(newDuration) { + const oldDuration = this.options.duration; + this.options.duration = newDuration; + + const ratio = newDuration / oldDuration; + this.options.instructions.forEach( (instruction) => { + instruction.steps.forEach( (step) => { + step.duration *= ratio; + }); + }); + + this.__updateDurationDom(); + } + } // mixins diff --git a/src/js/directions/directions.js b/src/js/directions/directions.js index 99d94b85..f9bb3a49 100644 --- a/src/js/directions/directions.js +++ b/src/js/directions/directions.js @@ -11,6 +11,9 @@ import DirectionsDOM from "./directions-dom"; import DirectionsResults from "./directions-results"; import DirectionsLayers from "./directions-styles"; import directionsSortableCallback from "./directions-sortable-callback"; +import Globals from "../globals"; + +import GisUtils from "../utils/gis-utils"; // dependance : abonnement au event du module import Geocode from "../services/geocode"; @@ -360,7 +363,10 @@ class Directions { this.elevation.target = document.getElementById("directions-elevationline"); this.elevation.loadingDomInDocument = false; this.elevation.setCoordinates(routeCoordinates); - this.elevation.compute(e.data.routes[0].distance); + this.elevation.compute(e.data.routes[0].distance).then( () => { + const newDuration = GisUtils.getHikeTimeScarfsRule(this.results.options.distance, this.elevation.dplus, Globals.walkingSpeed); + this.results.updateDuration(newDuration); + }); } } }); diff --git a/src/js/globals.js b/src/js/globals.js index 93759391..23b7ee49 100644 --- a/src/js/globals.js +++ b/src/js/globals.js @@ -104,6 +104,14 @@ let currentScrollIndex = 0; let mapLoaded = false; +// Walking speed for time calculation +let walkingSpeed; +if (!localStorage.getItem("walkingSpeed")) { + walkingSpeed = 4 / 3.6; +} else { + walkingSpeed = parseFloat(localStorage.getItem("walkingSpeed")) / 3.6; +} + export default { map, mapRLT1, @@ -139,5 +147,6 @@ export default { signalementOSM, online, mapLoaded, + walkingSpeed, osmPoiAccessibility, }; diff --git a/src/js/route-draw/route-draw.js b/src/js/route-draw/route-draw.js index 7d742413..2c5ae4db 100644 --- a/src/js/route-draw/route-draw.js +++ b/src/js/route-draw/route-draw.js @@ -12,6 +12,8 @@ import DOM from "../dom"; import RouteDrawLayers from "./route-draw-styles"; import Reverse from "../services/reverse"; +import GisUtils from "../utils/gis-utils"; + import MapLibreGL from "maplibre-gl"; import { Toast } from "@capacitor/toast"; @@ -890,6 +892,7 @@ class RouteDraw { if (this.dataHistory[this.currentHistoryPosition]) { this.dataHistory[this.currentHistoryPosition].elevationData = JSON.parse(JSON.stringify(this.data.elevationData)); } + this.data.duration = GisUtils.getHikeTimeScarfsRule(this.data.distance, this.data.elevationData.dplus, Globals.walkingSpeed); this.__updateRouteInfo(this.data); // Si mode lecture seule mais que l'alti est recalculée (non sauvegardé de base), on la rajoute dans les données enregistrées if (this.readonly) { diff --git a/src/js/utils/gis-utils.js b/src/js/utils/gis-utils.js index cfa46367..ff128756 100644 --- a/src/js/utils/gis-utils.js +++ b/src/js/utils/gis-utils.js @@ -46,7 +46,14 @@ let gisUtils = { } return dissolvedCoords; - } + }, + + // https://en.wikipedia.org/wiki/Naismith's_rule#Scarf's_equivalence_between_distance_and_climb + // all parameters in standard units (meters and m/s, result in seconds) + getHikeTimeScarfsRule(horizontalDistance, verticalDistance, speed) { + const equivalentDistance = horizontalDistance + 7.92 * verticalDistance; + return equivalentDistance / speed; + }, }; export default gisUtils;