Asynchronous execution of a function passed as an argument - javascript

I'm facing the following problem. I want to use Google's geocoding service to draw some markers on the map. However, the marker is instantiated before geocoding even finished it's job. drawMarker function will return a Marker with location undefined.
I tried passing the geocoding function as an argument to drawMarker function, and executing it there. I thought that this way I'd achieve synchronous behaviour, which is not the case. Simplified code follows:
drawMarker(i, map, codeAddress, locationsToConvert[i]);
function drawMarker(i, map, func, arg) {
var location = func.apply(this, [arg]);
return new google.maps.Marker({
position: {lat: location.lat, lng: location.lng},
map: map,
html: locations[i][0],
id: i
});
}
function codeAddress(address) {
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
return results[0].geometry.location
}
});
}
What are my solutions, which one's best, perhaps:
using the Promise interface?
doing everything in one function and instantiating Marker in the callback of the geocode service?
other?

You could try getting the address first and calling drawMarker from the callback once you have it. Edited drawMarker to something close to how it would look, I do not have full code so might not be 100% correct.
codeAddress(locationsToConvert[i]);
function drawMarker(i, map, location) {
return new google.maps.Marker({
position: {lat: location.lat, lng: location.lng},
map: map,
html: locations[i][0],
id: i
});
}
function codeAddress(address) {
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
drawMarker(i, map, results[0].geometry.location);
}
});
}

You have to put the drawMarker inside the geocoder callback
function codeAddress(address) {
geocoder.geocode({ 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
drawMarker(map,results[0].geometry.location);
}
});
}
take a look at this -> fiddle for the example

Why not convert the location then call the draw function once it returns?
Something similar to the below example (will change depending on the promise lib you are using) -- also can't promise there aren't any syntax errors in the example.
function geocodeAsync(addressToConvert) {
return new Promise((resolve, reject) => {
geocoder.geocode( {'address': addressToConvert }, (results, status) => {
if (status == google.maps.GeocoderStatus.OK) {
resolve(results[0].geometry.location);
}
else {
reject(status);
}
});
});
}
let loc = locationsToConvert[i];
var promise = geocodeAsync(loc)
promise.then(result => {
let marker = new google.maps.Marker({
position: {lat: result.lat, lng: result.lng},
map: map,
html: loc[0],
id: i
});
// add marker to google maps
})
.catch(err => console.error(err));

Related

Map: Expected mapDiv of type Element but was passed undefined - google maps

I have a map inside a div with a reference #mapa
When i want to trace a route in the map the map refreshes. I want to not refresh the map i have the following code:
<div style="height: 500px; width: auto;" #mapa>
<google-map height="500px" width="100%" [zoom]="zoom" [center]="center" [options]="options" (mapClick)="click($event)">
<map-marker #markerElem *ngFor="let marker of markers" [position]="marker.position" [label]="marker.label" [title]="marker.title" [options]="marker.options" (mapClick)="openInfo(markerElem, marker.info)" (mapDragend)="moveMap($event)">
</map-marker>
<map-info-window>{{ infoContent }}</map-info-window>
</google-map>
</div>
If i remove the div with the reference #mapa and i put it the reference into the <google-map> tag i got the title error and show the map without routes.
trazarRutaMapa() {
const directionsService = new google.maps.DirectionsService;
const directionsDisplay = new google.maps.DirectionsRenderer;
const map = new google.maps.Map(this.mapa.nativeElement, {
zoom: 7,
center: {
lat: this.markers[0].position.lat,
lng: this.markers[0].position.lng
}
});
directionsDisplay.setMap(map);
directionsDisplay.setOptions({
suppressMarkers: false,
draggable: true,
markerOptions: {
icon: 'https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png'
}
});
directionsService.route({
origin: {
lat: this.markers[0].position.lat,
lng: this.markers[0].position.lng
},
destination: {
lat: this.markers[1].position.lat,
lng: this.markers[1].position.lng
},
travelMode: google.maps.TravelMode.DRIVING,
}, (response, status) => {
if (status === google.maps.DirectionsStatus.OK) {
console.log('ESTATUS OKEY');
directionsDisplay.setDirections(response);
} else {
window.alert("Fallo el estatus" + status);
}
});
}
As far as I can see you can accomplish your goal just using the #angular/google-maps official module.
Your HTML will become something like this
<google-map [options]="options">
<map-marker *ngFor="let some of somearray" [icon]="...", [label]="...", [position]="..."></map-marker>
<map-directions-renderer [directions]="..." [options]="..."></map-directions-renderer>
</google-map>
and your trazarRoutaMapa() method will become something like this:
trazarRoutaMapa(): void {
const directionsService = new google.maps.DirectionsService; // better if injected from constructor
const request: google.maps.DirectionsRequest = {
destination: {
lat: this.markers[0].position.lat,
lng: this.markers[0].position.lng
},
origin: {
lat: this.markers[1].position.lat,
lng: this.markers[1].position.lng
},
travelMode: google.maps.TravelMode.DRIVING
};
return directionsService.route(
request,
(response, status) => {
if (status === google.maps.DirectionsStatus.OK) {
console.log('ESTATUS OKEY');
directionsDisplay.setDirections(response);
} else {
window.alert("Fallo el estatus" + status);
}
});
}
Disclaimer: I didn't test the code, just created on notepad copy/pasting :)

Google maps - directions service api ZERO_RESULTS

I have a question regarding directions service API. Is there a hybrid travel mode setting which would allow me to draw a route for a bike, even if there isn't a bike track on that particular street or it's against street rules (is it even possible).
I would like to draw a segment which will go from A to B exactly through selected road, and not around if that road
doesn't actually allow driving in that direction. It doesn't have to be correct in regard to driving rules, it must be just drawn over the street. I tried bicycle mode instead of driving mode, but there isn't any difference.
I hope my post makes any sense
Example of call:
function loadRoute0() {
var request0 = {
origin: new google.maps.LatLng(46.56300788, 15.62779705),
destination: new google.maps.LatLng(46.55953332, 15.62616729),
travelMode: google.maps.TravelMode.BICYCLING
};
directionsService.route(request0, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
var renderer = new google.maps.DirectionsRenderer({
polylineOptions: {
strokeColor: "#00FF00"
},
suppressMarkers: true,
map: map
});
renderer.setDirections(result);
}
});
}
You could use TravelMode.WALKING, that tends to give results for one way roads and other routes that won't work for TravelMode.DRIVING.
The code in your question doesn't reproduce the picture you posted, but using TravelMode.WALKING returns a route (where TravelMode.BICYCLING gives ZERO_RESULTS for the posted code)
function loadRoute0() {
var request0 = {
origin: new google.maps.LatLng(46.56300788, 15.62779705),
destination: new google.maps.LatLng(46.55953332, 15.62616729),
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request0, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
var renderer = new google.maps.DirectionsRenderer({
polylineOptions: {
strokeColor: "#00FF00"
},
suppressMarkers: true,
map: map
});
renderer.setDirections(result);
} else
console.log("status=" + status);
});
}
proof of concept fiddle (for the posted code)
proof of concept fiddle (for the picture)
code snippet:
var map;
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"));
directionsService = new google.maps.DirectionsService();
loadRoute0();
function loadRoute0() {
var request0 = {
origin: new google.maps.LatLng(46.56300788, 15.62779705),
destination: new google.maps.LatLng(46.55953332, 15.62616729),
travelMode: google.maps.TravelMode.WALKING
};
var markerS = new google.maps.Marker({
position: request0.origin,
map: map,
label: "S"
});
var markerE = new google.maps.Marker({
position: request0.destination,
map: map,
label: "E"
});
directionsService.route(request0, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
var renderer = new google.maps.DirectionsRenderer({
polylineOptions: {
strokeColor: "#00FF00"
},
suppressMarkers: true,
map: map
});
renderer.setDirections(result);
} else
console.log("status=" + status);
});
}
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas"></div>

Uncaught TypeError: Cannot read property 'apply' of undefined Google Maps

I am using Google Maps to make markers on a map and I am trying to convert addresses to geocodes using the following code:
<script src="https://maps.googleapis.com/maps/api/js?key=&callback=initialize" async defer></script>
<script type="text/javascript">
var map;
function initialize() {
var chamberLocation = {lat: 43, lng: -82};
var geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 42.9745, lng: -82.4066},
zoom: 14,
styles: [{"featureType":"road","elementType":"geometry","stylers":[{"visibility":"simplified"}]},{"featureType":"road.arterial","stylers":[{"hue":149},{"saturation":-78},{"lightness":0}]},{"featureType":"road.highway","stylers":[{"hue":-31},{"saturation":-40},{"lightness":2.8}]},{"featureType":"poi","elementType":"label","stylers":[{"visibility":"off"}]},{"featureType":"landscape","stylers":[{"hue":163},{"saturation":-26},{"lightness":-1.1}]},{"featureType":"transit","stylers":[{"visibility":"off"}]},{"featureType":"water","stylers":[{"hue":3},{"saturation":-24.24},{"lightness":-38.57}]}],
zoomControl: false,
scaleControl: false,
mapTypeControl: false,
disableDefaultUI: false,
streetViewControl: false,
rotateControl: false,
scrollwheel: false,
draggable: false
});
codeAddress(geocoder, map);
}
function codeAddress(geocoder, map) {
var address = 'place';
geocoder.geocode({ 'address' : address }), function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
console.log('This didnt work' + status);
}
};
}
</script>
Whenever I do this I get an error saying Uncaught TypeError: Cannot read property 'apply' of undefined
What is causing this error? I am unsure as to how to fix this. Do I have to import another google maps api?
The error is a typo. I put the code below and commented //change in places where the typo was at. geocoder.geocode({}, callback) is a function that takes an object and a callback, but you have geocoder.geocode({ 'address' : address }), the typo is the ) it should be geocoder.geocode({ 'address' : address }, function(results, status) { ...
<div id="map" style="width: 320px; height: 480px;"></div>
<script type="text/javascript">
var map;
function initialize() {
// your code
// etc ...
codeAddress(geocoder, map);
}
function codeAddress(geocoder, map) {
var address = 'place';
geocoder.geocode({
'address': address
}, // change
function(results, status) {
if (status == 'OK') { // change
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
// some debug output
console.log("status is: " + status)
console.log("results is: " + JSON.stringify(results[0].geometry.location))
} else {
console.log('This didnt work' + status);
}
});
};
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=initialize"></script>
Today i have also faced the same error while using distance matrix library, what we need to do is simply use the callback function mentioned here https://developers.google.com/maps/documentation/javascript/distancematrix
According to this doc https://developers.google.com/maps/documentation/javascript/examples/distance-matrix#maps_distance_matrix-typescript i was using promises thats when i encounterd the above error
var origin1 = new google.maps.LatLng(55.930385, -3.118425);
var origin2 = 'Greenwich, England';
var destinationA = 'Stockholm, Sweden';
var destinationB = new google.maps.LatLng(50.087692, 14.421150);
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [origin1, origin2],
destinations: [destinationA, destinationB],
travelMode: 'DRIVING',
transitOptions: TransitOptions,
drivingOptions: DrivingOptions,
unitSystem: UnitSystem,
avoidHighways: Boolean,
avoidTolls: Boolean,
}, callback);
function callback(response, status) {
// See Parsing the Results for
// the basics of a callback function.
console.log(status);
console.log(response);
}

angularJS find the location/place name using angular google map

I want to find the location name which user select on map.
Currently I am getting latitude and longitude both.
But unable to get the location name.
I am using angularJS and angular-google-maps 2.1.5.
Here is the html.
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true" options="options" events="map.events">
</ui-gmap-google-map>
JS :
$scope.map = {
center: {
latitude: 21.0000,
longitude: 78.0000
},
zoom: 4,
events: {
click: function(mapModel, eventName, originalEventArgs,ok) {
var e = originalEventArgs[0];
objOneDevice.dev_latitude = e.latLng.lat();
objOneDevice.dev_longitude = e.latLng.lng();
$scope.templatedInfoWindow.show = true;
}
}
};
$scope.options = {
scrollwheel: true
};
Anything is appreciated.
Here what I have done using Reverse geocoding.
$scope.map = {
center: {
latitude: 21.0000,
longitude: 78.0000
},
zoom: 4,
events: {
click: function(mapModel, eventName, originalEventArgs,ok) {
var e = originalEventArgs[0];
var geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(e.latLng.lat(), e.latLng.lng());
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
console.log(results[1].formatted_address); // details address
} else {
console.log('Location not found');
}
} else {
console.log('Geocoder failed due to: ' + status);
}
});
}
}
};
Given Latitude/Longitude object you can map location to approximate address using Google Map API.
You can use the Geocoding API for mapping locations to addresses and addresses to locations.
Geocoder.geocode( { 'latLng': latLngObject }, callbackFn);
Here is the link for Google Map API for Geocoding.
Try these links
https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse?csw=1
Use the Geocoding API for mapping locations to addresses and addresses to locations. http://code.google.com/apis/maps/documentation/javascript/services.html#Geocoding
Geocoder.geocode( { 'latLng': latLngObject }, callback);
http://wbyoko.co/angularjs/angularjs-google-maps-components.html
Hope it helps!!!

Mapping route history

I need to display a route, that consists of 1,000-2,000 (lat/lon) points.
I tried to do this, but I do not think it is a good solution to show route for so many points; please advise on best way to do it.
function calcRoute() {
var request = {
origin:new google.maps.LatLng(37, -97),
waypoints: [
{
location:new google.maps.LatLng(39, -97),
stopover:false
},{
location:new google.maps.LatLng(32, -95),
stopover:false
}],
destination:new google.maps.LatLng(37, -97),
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
Instead of passing the entire result to the DirectionsRenderer you can use the overview_path, (which is simplified), of the google.maps.DirectionsRoute object and add the polylines directly to the map, for example:
directionsService.route(request,plot);
function plot(result,status){
if (status == google.maps.DirectionsStatus.OK) {
for (var n = 0 ;n < result.routes.length ; n++ ){
addLine(result.routes[n].overview_path);
}
}
}
function addLine(path){
var line = new google.maps.Polyline ({
path: path,
map: map
});
}

Categories

Resources