Error when add multiple waypoints to Leaflet - javascript

The code works fine for two waypoints on an ionic v1 app, but if I add more than two, I get the following error:
Uncaught TypeError: Cannot read property 'lat' of undefined
at o.LatLng.distanceTo (file:///android_asset/www/lib/leaflet/leaflet.js:6:14158)
at e._extendToWaypoints (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:3751:18)
at e.initialize (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:3699:10)
at new e (file:///android_asset/www/lib/leaflet/leaflet.js:6:2539)
at Object.line (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:3329:16)
at e.<anonymous> (file:///android_asset/www/js/services/Maps.js:461:35)
at e.fireEvent (file:///android_asset/www/lib/leaflet/leaflet.js:6:4952)
at e.<anonymous> (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:2907:13)
at e._routeDone (file:///android_asset/www/lib/lrm-mapbox/lrm-mapbox.js:289:20)
at e.<anonymous> (file:///android_asset/www/lib/lrm-mapbox/lrm-mapbox.js:248:22)
The strange thing is that this code where working well a few months ago, but suddenly it started to fail. The problematic code is this:
function getRoute() {
var r = L.Routing.control({
waypoints: waypoints,
router: new L.Routing.Mapbox(Config.mapBoxApiKey,
{
serviceUrl: 'https://api.tiles.mapbox.com/v4/directions/',
timeout: 30 * 1000,
profile: 'mapbox.' + tipo
}
),
lineOptions: {
styles: styles
},
fitSelectedRoutes: false,
routeWhileDragging: false,
createMarker: function () {
return null;
}
});
return r;
}
var control = getRoute();
var routeLayer = L.layerGroup([control]); <---- HERE I GET THE ERROR
Any ideas?

In Leaflet, Controls are different from Layers.
In particular, you cannot make them children of a Layer Group.
As shown in Leaflet Routing Machine plugin home page, you just need to use the addTo() method to add your Control to the map:
L.Routing.control({
waypoints: waypoints
}).addTo(map);
In your precise case:
getRoute().addTo(map);

Related

Ionic 5 Leaflet - Map container not found

I'm trying to integrate a leaflet map into my application.
I've written the following code in my .ts file:
ionViewDidEnter() {
this.leafletMap();
}
leafletMap() {
this.map = Leaflet.map('map').setView([49.992863, 8.247253], 5);
Leaflet.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© XY',
}).addTo(this.map);
}
In the template file I've added the div container: <div id="map" style="width: 100%; height: 200px">
When I'm running it, everything works fine. But now I would like to add some markers with data, which is loaded from an api. Therefore, I have to modify the code so, that the map (and the markers) are added after the data has loaded. So, my new code is the following:
ionViewDidEnter() {
this.dataService.getLocation(this.locationID).then(data => {
this.location = data;
this.leafletMap();
});
}
So now I'm receiving the location data, but I'm also getting an error message: Error: Uncaught (in promise): Error: Map container not found.
I've tried different things from other questions here, but nothing works. Do you have an idea, how I can solve this problem?
can you try this:
leafletMap() {
setTimeout( () => {
this.map = Leaflet.map('map').setView([49.992863, 8.247253], 5);
Leaflet.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© XY',
}).addTo(this.map);
}, 2000);
}
I had the same problem with here maps. This was working for me

Accessing Mapbox Geocoder Object

I have created a MapboxGeocoder object in my code and I'm curious if I can access/use it to reverse geocode elsewhere in the code. This, in an effort to get a formatted address from coords.
I created an object like so:
const address = new MapboxGeocoder({
accessToken: mbat,
mapboxgl: mapboxgl,
container: 'geocoder',
countries: "us",
bbox: [-83.726807, 31.784217, -78.013916, 35.415915],
reverseGeocode: true,
}).on("result", function (result) {
console.log(result);
});
I also have the GeolocateControl object in my code and I'm creating it like so:
map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
// When active the map will receive updates to the device's location as it changes.
trackUserLocation: true,
// Draw an arrow next to the location dot to indicate which direction the device is heading.
showUserHeading: true
}).on('geolocate', (e) => {
console.log(e)
})
)
My question is, is there a way to access the address object within the GeolocateControl event handler to reverse geocode? I am imagining something to this effect:
.on('geolocate', (e) => { console.log(address(e)) })
As long as your geocoder instance is in scope, you should be able to use it in the event handler from GeolocateControl
I am not 100% sure about the data object in the geolocate callback, so inspect it to see how to pull out the lng/lat coordinates.
const geocoder = new MapboxGeocoder(...)
map.addControl(
new mapboxgl.GeolocateControl({
...
}).on('geolocate', (data) => {
const geocoder.query(`${data.coords[0},${data.coords[1]}`)
})
)

Error in Angular: earthquake_GeoJSONP.js:1 Uncaught ReferenceError: eqfeed_callback is not defined at earthquake_GeoJSONP.js:1:1

I'm trying to replicate the Importing Data into Maps (Importing Data into Maps) example to my angular project but I get the following error in console:
earthquake_GeoJSONP.js:1 Uncaught ReferenceError: eqfeed_callback is not defined
at earthquake_GeoJSONP.js:1:1
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Loader } from "#googlemaps/js-api-loader"
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'map';
ngOnInit() {
let map: google.maps.Map;
const loader = new Loader({
apiKey: "YOUR_API_KEY"
});
loader.load().then(() => {
const map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
zoom: 2,
center: new google.maps.LatLng(2.8, -187.3),
mapTypeId: "terrain",
});
// map.data.loadGeoJson('data.json');
// Create a <script> tag and set the USGS URL as the source.
const script = document.createElement("script");
// This example uses a local copy of the GeoJSON stored at
// http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojsonp
script.src =
"https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js";
document.getElementsByTagName("head")[0].appendChild(script);
const eqfeed_callback = function (results: any) {
for (let i = 0; i < results.features.length; i++) {
const coords = results.features[i].geometry.coordinates;
const latLng = new google.maps.LatLng(coords[1], coords[0]);
let marker = new google.maps.Marker({
position: latLng,
map: map,
});
// place marker in map
marker.setMap(map)
}
};
});
}
}
app.component.html
<div id="map"></div>
app.component.css
#map {
height: 500px;
width: 100%;
}
Installed Packages
This is the googlemaps package that I installed in my project.
npm install #googlemaps/js-api-loader
npm i -D #types/google.maps
My Angular version
Angular CLI: 13.3.7
Node: 16.14.2
Package Manager: npm 8.5.0
OS: win32 x64
What my code shows
Just appear the map but without markers.
What I hope will appear
According to the Google Maps documentation at the following link: Importing Data into Maps
Thanks for your time and support!
I confirmed that your map appears but the markers don't.
Just like you said, what you want to happen is for the markers to show.
What I did is I tried to replicate your code in codesandbox and found out two main errors:
'map' is defined but never used. (#typescript-eslint/no-unused-vars)
'eqfeed_callback' is assigned a value but never used. (#typescript-eslint/no-unused-vars)
Solutions:
Error #1: app.component.ts had an unused variable of map and it looks like this in your code:
ngOnInit() {
let map: google.maps.Map;
const loader = new Loader({
apiKey: "YOUR_API_KEY"
});
loader.load().then(() => {
const map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
zoom: 2,
center: new google.maps.LatLng(2.8, -187.3),
mapTypeId: "terrain",
});
the map variable inside the loader.load().then is the one you used and the one on top is the unused which caused error #1. I just removed it and it removed the error on the console.
Error #2: your code had a variable eqfeed_callback that stored a function but was not called. I compared your code to the sample you gave here and confirmed that there was a callback on the code there.
As I am not very familiar to typescript and angular I tried experimenting on the code and made it work by making the end part of your code look like this:
const eqfeed_callback = function (results: any) {
for (let i = 0; i < results.features.length; i++) {
const coords = results.features[i].geometry.coordinates;
const latLng = new google.maps.LatLng(coords[1], coords[0]);
let marker = new google.maps.Marker({
position: latLng,
map: map
});
// place marker in map
marker.setMap(map);
}
};
window.eqfeed_callback = eqfeed_callback;
});
}
}
I just inserted window.eqfeed_callback = eqfeed_callback and it made the error disappear and at the same time show the markers on the map.
Here's the sandbox link: https://codesandbox.io/s/holy-sound-p8qtrc
Just use your own API key.
I hope this helps.

What is the meaning of this (undefined getCameraForLocationToPoint) error and how to fix?

This is error which I don't understand TypeError: Cannot read properties of undefined (reading 'getCameraForLocationToPoint')
I got this error when I try to create a Bingmap for my angular project
.TS
let loc = new Microsoft.Maps.Location(Latitude,Longitude);
this.map.setView({ center: { latitude: loc.latitude, longitude: loc.longitude }});
this.map.setView({ mapTypeId: Microsoft.Maps.MapTypeId.streetside });
Microsoft.Maps.Events.addHandler(this.map, 'viewchangeend', () => { this.updateView(this.map); });
this.updateView(this.map);
Microsoft.Maps.Events.addHandler(this.map, 'click', this.Clicked.bind(this.map));
streetViewMapPromise(promise: Promise<any>) {
promise.then(x => {
this.map = x;
})
}
Clicked(e){ //click event
console.log(e)
}
.Html
<app-rs-bingmap (MapPromise)="streetViewMapPromise($event)" [options]="_mapOptions"></app-rs-bingmap>
above section is my Bingmap v8 component import section. As well as my click event is not working too. when I click on the map I want to show and alert.
Here is the stackblitz : getCameraForLocationToPoint error here

How can I test google.maps.Geocoder?

Hi! I'm attempting to write a "simple" test to check for a react class component state change. Specifically, I'm testing if the lat(latitude) and lng(longitude) states change if Google successfully geocodes some string(address) that I send it. Here is an example of what I want to test (i.e. the lat and lng states being set to results[0].geometry.location.lat()):
getLatLong = (address) => {
const that = this;
var geo = new google.maps.Geocoder;
geo.geocode({'address':address},(results, status) => {
if (status == google.maps.GeocoderStatus.OK) {
that.setState(
{
center: {
lat: results[0].geometry.location.lat(),
lng: results[0].geometry.location.lng(),
},
});
}
});
}
In my jest suite, I'm having issues writing my test and spying/mocking out the google.maps.Geocoder because the google library is never imported. It is attached via a script, like so:
<script async defer
src=<%="https://maps.googleapis.com/maps/api/js?key=#{Rails.application.config.google_api_key}&callback=initMap"%>>
</script>
Just so its confirmed, the code works as intended after manual testing, but I receive errors inside my testing suite when attempting to spy like so:
let geocoderSpy = jest.spyOn(google.maps, 'Geocoder');
I receive an error like this:
● EventMap › getLatLong works as intended by getting coordinates of valid locations › calls the geocoder function
ReferenceError: google is not defined
34 | let geocoder;
35 | beforeEach(() => {
> 36 | let geocoderSpy = jest.spyOn(google.maps, 'Geocoder');
| ^
37 | geocoder = jest.createSpy('Geocoder', ['geocode']);
38 | geocoderSpy.and.returnValue(geocoder);
39 | });
at Object.google (app/javascript/__tests__/EventPage/EventMap.test.jsx:36:42)
So then, I followed up this problem and found this stackoverflow post and this answer that claimed to solve it by adding something like this to jest in the package.json file...
"globals": { "google": { } }
This also failed to solve my problem. I think the solution is to somehow find out how to import google, but not quite sure how to do that.... If anyone can help me out that would be greatly appreciated. I would love to learn how to test something like this. In advance, many thanks. Austin
It seems that you are not the only one having suffered through the terrors of testing Google maps with Jest. I found a lot of projects and conversations around. But they all seem to recommend mocking the Google maps library, by doing something similar to this :
const setupGoogleMock = () => {
/*** Mock Google Maps JavaScript API ***/
const google = {
maps: {
places: {
AutocompleteService: () => {},
PlacesServiceStatus: {
INVALID_REQUEST: 'INVALID_REQUEST',
NOT_FOUND: 'NOT_FOUND',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
},
Geocoder: () => {},
GeocoderStatus: {
ERROR: 'ERROR',
INVALID_REQUEST: 'INVALID_REQUEST',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
},
};
global.window.google = google;
};
// in test file.
beforeAll(() => {
setupGoogleMock();
});
(source : https://github.com/hibiken/react-places-autocomplete/issues/189#issuecomment-377770674)
There is even an npm package for it! https://github.com/hupe1980/jest-google-maps-mock
Not sure if it will solve your problem, though, because this will only allow you to check if you have correctly called the right method from the API, not to check if you get the correct response from the API.
However, I don't know if it is advisable to actually do real API calls when testing such a functionality.
Inspired by the answer from Mathieu. I had to make a little change to adapt this solution for my project (Nuxt.js/Vue.JS).
I've replaced the Geocoder function with a mock of the Geocoder class.
const setupGoogleMock = () => {
/** * Mock Google Maps JavaScript API ***/
const google = {
maps: {
places: {
AutocompleteService: () => {},
PlacesServiceStatus: {
INVALID_REQUEST: 'INVALID_REQUEST',
NOT_FOUND: 'NOT_FOUND',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
},
Geocoder: class {
public async geocode() {
return Promise.resolve()
}
},
GeocoderStatus: {
ERROR: 'ERROR',
INVALID_REQUEST: 'INVALID_REQUEST',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
},
}
// #ts-ignore
global.window.google = google
}
setupGoogleMock()

Categories