async function nearestEntryPoint(mapDir, originMarker) {
let routeLine = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
coordinates: nextbillion.utils.polyline
.decode(mutable globalRoute.geometry, 6)
.map((c) => c.reverse()),
type: "LineString"
}
}
]
};
const pointFeature = {
type: "Feature",
properties: {},
geometry: {
type: "Point",
coordinates: [originMarker.getLngLat().lng, originMarker.getLngLat().lat]
}
};
console.log("Origin :", originMarker);
const closestPoint = turf.nearestPointOnLine(routeLine, pointFeature);
const index = findPointIndexInLineStringWithThreshold(
routeLine,
closestPoint,
0.001
);
console.log("ClosestPoint:", closestPoint);
//build a DM 1 x (max200) from the nearest point
const maxPoints = routeLine.features[0].geometry.coordinates.length;
const startPoint = index - 100 < 0 ? 0 : index - 100;
const nbrPoints = maxPoints < 200 ? maxPoints : 200;
const coordsOfInterest = routeLine.features[0].geometry.coordinates.slice(
startPoint,
startPoint + nbrPoints
);
// route to the closest result returned in the DM
let destString = coordsOfInterest
.map((coord) => `${coord[1]},${coord[0]}`)
.join("|");
let origString = `${originMarker.getLngLat().lat},${
originMarker.getLngLat().lng
}`;
const dmResponse = await requestDistanceMatrix(origString, destString);
let nearestIndex = -1;
let nearestValue = Number.MAX_SAFE_INTEGER;
dmResponse.rows[0].forEach((el, idx) => {
if (el[0] < nearestValue) {
nearestValue = el[0];
nearestIndex = idx;
}
});
// Now we do a directions service request and render the polyline to nearest entry point
const directionsService = new nextbillion.maps.DirectionsService();
let resp = null;
resp = await directionsService.route({
destination: {
lat: coordsOfInterest[nearestIndex][1],
lng: coordsOfInterest[nearestIndex][0]
},
origin: {
lat: originMarker.getLngLat().lat,
lng: originMarker.getLngLat().lng
}
});
const popupOffsets = {
top: [0, 0],
"top-left": [0, 0]
};
const popupIdx = (
nextbillion.utils.polyline.decode(resp.routes[0], 6).length / 2
).toFixed(0);
// pops.forEach((popup) => popup.remove());
let popup = new nextbillion.maps.Popup({
offset: 25
})
.setLngLat({
lat: nextbillion.utils.polyline.decode(resp.routes[0].geometry, 6)[
popupIdx
][0],
lng: nextbillion.utils.polyline.decode(resp.routes[0].geometry, 6)[
popupIdx
][1]
})
.setHTML(
`${(resp.routes[0].distance / 1000).toFixed(1)}km<br>${(
resp.routes[0].duration / 60
).toFixed(1)}min<br>${originMarker.code}`
)
.addTo(mapDir.map);
mutable pops.push(popup);
let geojson = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
coordinates: nextbillion.utils.polyline
.decode(resp.routes[0].geometry, 6)
.map((c) => c.reverse()),
type: "LineString"
}
}
]
};
if (!mapDir.map.getSource("route-entry")) {
mapDir.map.addSource("route-entry", {
type: "geojson",
data: null
});
}
mapDir.map.getSource("route-entry").setData(geojson);
if (mapDir.map.getLayer("route-entry")) {
mapDir.map.removeLayer("route-entry");
}
mapDir.map.addLayer({
id: "route-entry",
type: "line",
source: "route-entry",
layout: {
"line-join": "round",
"line-cap": "round"
},
paint: {
"line-color": "#FF00EE",
"line-width": 6
}
});
}