Hi there guys, i’m having some problems using tomtom’s api for geocoding location using addresses, mos of the times it just gives me wrong addresses, im not sure why honestly, i don’t know if it’s the geocoding or if it is the map itself that it’s wrong, ill leave the entire react component for anyone to check out, iv’e been on this for hours and can’t find what might be the problem.
import { useEffect, useState, useRef } from "react";
import * as tt from '@tomtom-international/web-sdk-maps'
import * as ttapi from '@tomtom-international/web-sdk-services'
import '@tomtom-international/web-sdk-maps/dist/maps.css'
import {Row} from 'react-bootstrap'
import './DeliveriesMap.css'
export default function DeliveriesMap({sells}) {
const geocodes = [];
const [map, setMap] = useState({});
const [address, setAddress] = useState('');
const [municipality, setMunicipality] = useState('');
const mapElement = useRef();
//circcloHQ long and lat
const circcloLong = -65.267403;
const circcloLat = -26.798281;
//get geocode from addresses
async function getGeocodesFromAddresses() {
const addresses = sells.map(sell => [sell.address, sell.municipality]);
const promises = addresses.map((address) => {
return ttapi.services.geocode({
key: process.env.REACT_APP_TOMTOM_KEY,
query: address[0] + ", " + address[1] + ", Argentina",
limit: 1,
countrySet: 'ARG',
center: [circcloLong, circcloLat],
radius: 30000,
})
})
//consume all promises
const results = await Promise.all(promises);
results.forEach(result => {
if (result.results.length > 0) {
const item = {...result.results[0].position, address: result.results[0].address}
console.log("item: ", item)
geocodes.push(item);
}
})
}
const convertToPoints = (geocode) => {
return {
point: {
latitude: geocode.lat,
longitude: geocode.lng
}
}
}
const sortDestinations = async (locations) => {
const pointsForDestinations = await locations.map((dest) => convertToPoints(dest));
const callParams = {
key: process.env.REACT_APP_TOMTOM_KEY,
destinations: pointsForDestinations,
origins: [convertToPoints({lat: circcloLat, lng: circcloLong})],
}
return new Promise((resolve, reject) => {
ttapi.services
.matrixRouting(callParams)
.then((matrixResults) => {
console.log("mresult: ", matrixResults)
const results = matrixResults.matrix[0];
console.log("results", results)
const resultsArray = results.map((result, index) => {
return {
location: locations[index],
drivingTime: result.response.routeSummary.travelTimeInSeconds,
}
})
resultsArray.sort((a, b) => a.drivingTime - b.drivingTime);
const sortedLocations = resultsArray.map((result) => result.location);
resolve(sortedLocations);
})
.catch((error) => {
console.log(error);
reject(error);
})
})
}
function drawRoute(geoJson, map) {
if(map.getLayer('route')){
map.removeLayer('route');
map.removeSource('route');
}
map.addLayer({
id: "route",
type: "line",
source: {
type: 'geojson',
data: geoJson
},
paint: {
"line-width": 5,
"line-color": "#007cbf"
}
});
}
function recalculateRoutes(map) {
sortDestinations(geocodes).then((sorted) => {
const markers = [];
let index = 0;
sorted.forEach((geocode) => {
console.log("geocode adress", geocode.address)
//make sure markers are not duplicated
if(!markers.includes(geocode.address.freeformAddress)) {
index ++;
markers.push(geocode.address.freeformAddress);
addMarker(geocode.lng, geocode.lat, map, `${geocode.address.streetName + " " + (geocode.address.streetNumber || "")}`, index);
}
})
sorted.unshift({lat: circcloLat, lng: circcloLong});
ttapi.services
.calculateRoute({
key: process.env.REACT_APP_TOMTOM_KEY,
locations: sorted,
})
.then((routeData) => {
//add markers
const geoJSON = routeData.toGeoJson()
drawRoute(geoJSON, map);
})
.catch((error) => {
console.log(error);
})
})
}
const addMarker = (longitude, latitude, map, popupMsg, markerMsg) => {
const popup = new tt.Popup({
offset: [0, -15]
}).setHTML(popupMsg);
const element = document.createElement('div');
element.className = 'marker';
element.innerHTML = markerMsg;
const marker = new tt.Marker({
element: element,
anchor: 'bottom',
})
.setLngLat([longitude, latitude])
.addTo(map);
marker.setPopup(popup).togglePopup();
}
async function handleRoute(map) {
await getGeocodesFromAddresses();
recalculateRoutes(map);
}
const handleClick = async (e) => {
e.preventDefault();
const sell = {
address: address,
municipality: municipality,
}
sells.push(sell);
}
useEffect(() => {
console.log("key: ", process.env.REACT_APP_TOMTOM_KEY);
const map = tt.map({
key: process.env.REACT_APP_TOMTOM_KEY,
container: mapElement.current,
stylesVisibility: {
trafficIncidents: true,
trafficFlow: true,
},
center: [circcloLong, circcloLat],
zoom: 16,
});
setMap(map);
addMarker(circcloLong, circcloLat, map, "Circclo HQ", "HQ");
handleRoute(map);
return () => map.remove();
}, [sells])
return(
<Row className="p-3 map-height text-center align-items-center justify-content-center">
<h2 className="text-center"> Ruta de entregas </h2>
<Row className="p-3">
<input type="text" className="" placeholder="Ingrese dirección" onChange={(e) => setAddress(e.target.value)}/>
<input type="text" className="" placeholder="Ingrese municipio" onChange={(e) => setMunicipality(e.target.value)}/>
<button className="btn btn-primary" onClick={(e) => handleClick(e)}> Calcular ruta </button>
</Row>
{map && <div ref={mapElement} className="map"></div>}
</Row>
)
}
just for some context the addresses fed to the API have this format “street name street number” (avenida independencia 2000 for example) and then “municipality” (yerba buena for example) so the query ends up being “avenida independencia 2000, yerba buena, Argentina”.
The most common error y get is that i get back from the api the street but without the number, as if the API found the street but the number dosen’t exist or something like that? Im really confused. That ends up meaning that the location marked on the map latter is wrong. Any help would be greatly apreciated. Thanks in advance!