I am getting an Uncaught InvalidValueError: in property origin: not a string; and not a LatLng or LatLngLiteral: not an Object error when I call the Google maps directions service - even so, the directions seem to be added to the map?
Here is the function that calls the directions service between the current location (currentPos) and a location not too far away (LatLng(52.705151, -2.741861))
function calcRoute() {
var start = currentPos;
var end = new google.maps.LatLng(52.705151, -2.741861);
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
Here is the code that initializes the map and calls the calcRoute() function:
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var currentPos;
var destinationPos;
var map;
function initialize() {
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
zoom: 14
};
map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
directionsDisplay.setMap(map);
var infoWindow = new google.maps.InfoWindow();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
currentPos = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var marker = new google.maps.Marker({
position: currentPos,
map: map,
title: "You are here"
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png')
map.setCenter(currentPos);
$.ajax({
type: 'GET',
url: $('#AddMarkersToMap').val(),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
addMarkers(data, infoWindow);
},
error: function () {
alert("Error");
}
});
}, function () {
handleNoGeolocation(true);
});
} else {
handleNoGeolocation(false);
}
calcRoute();
}
Some Googling suggested the exception might be caused because the map hadn't loaded so I tried putting the calcRoute call like this which didn't help:
$(function () {
calcRoute()
});
Your currentPos variable is undefined when you call calcRoute.
getCurrentPosition is asynchronous and will not have executed before calcRoute and therefore not set currentPos.
If you need to use currentPos in calcRoute you should call it in the callback to getCurrentPosition to ensure that it is defined.
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
currentPos = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var marker = new google.maps.Marker({
position: currentPos,
map: map,
title: "You are here"
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png')
map.setCenter(currentPos);
$.ajax({
type: 'GET',
url: $('#AddMarkersToMap').val(),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
addMarkers(data, infoWindow);
},
error: function () {
alert("Error");
}
});
calcRoute();
//\\//\\//\\
}, function () {
handleNoGeolocation(true);
});
Related
Each time my code invokes the function search() I would like the google map markers that were placed on the map from the previous search call cleared off the map and the NEW markers placed on the map.
I need help clearing out the markers.
function search() {
//loading the map with markers
$('.map').addClass('.map-with-searching');
$.ajax({
url: 'https://' + getApiURL(),
data: data,
contentType: 'application/json',
type: 'POST',
success: function (result) {
$('#universitiesList').html('');
for (const row of result.payload) {
locations.push({ lat: row.location.latitude, lng:
row.location.longitude, university: row.campusName, id:row.campusID});
}
//marker.setVisible(false);
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: { lat: locations[i].lat, lng: locations[i].lng },
map: map,
data: {
university: locations[i].university,
id: locations[i].id,
name: locations[i].name,
address: locations[i].address,
image: locations[i].image,
}
});
map.setCenter(new google.maps.LatLng(locations[i].lat, locations[i].lng));
marker.addListener('click', function () {
if (!this.infoWindow) {
this.infoWindow = new google.maps.InfoWindow({
content: '<div class="flex marker-pop-up"><div class="image-container"><img id="building" src="'
+ this.data.image + '"onerror="imgError(this)"; alt="Smiley face" height="110" width="120" /></div></div></div></div>'
});
}
this.infoWindow.open(map, this);
})
};
},
error: function (jqXhr, textStatus, errorThrown) {
//console.log(errorThrown);
}
})
}
Here's an untested example - store references to the markers and then call .setMap(null) to remove them from the map.
// an array of the markers on the map
let markers = [];
function search() {
// clear the markers
for( const marker of markers ) {
marker.setMap(null);
}
markers = [];
//loading the map with markers
$('.map').addClass('.map-with-searching');
$.ajax({
url: 'https://' + getApiURL(),
data: data,
contentType: 'application/json',
type: 'POST',
success: function (result) {
$('#universitiesList').html('');
for (const row of result.payload) {
locations.push({ lat: row.location.latitude, lng: row.location.longitude, university: row.campusName, id:row.campusID});
}
//marker.setVisible(false);
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: { lat: locations[i].lat, lng: locations[i].lng },
map: map,
data: {
university: locations[i].university,
id: locations[i].id,
name: locations[i].name,
address: locations[i].address,
image: locations[i].image,
}
});
// Store a reference so you can remove markers later
markers.push( marker );
map.setCenter(new google.maps.LatLng(locations[i].lat, locations[i].lng));
marker.addListener('click', function () {
if (!this.infoWindow) {
this.infoWindow = new google.maps.InfoWindow({
content: '<div class="flex marker-pop-up"><div class="image-container"><img id="building" src="' + this.data.image + '"onerror="imgError(this)"; alt="Smiley face" height="110" width="120" /></div></div></div></div>'
});
}
this.infoWindow.open(map, this);
});
};
},
error: function (jqXhr, textStatus, errorThrown) {
//console.log(errorThrown);
}
});
}
I have to put markes on google maps, but the array with lat, long is made by an Ajax request.
Map is loaded before the initialization of the array and I don't see the markers.
I think that this is the problem but I'm not so sure. hope you can help me
<script>
$(document).ready(function() {
setVariable('<?php echo $_SESSION["token"]?>');
});
</script>
<script defer
src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXX&callback=initMap">
</script>
coord = new Array();
function setVariable(token) {
format="text/plain";
$.ajax({
url: BASE_URL + "reports",
type: "GET",
contentType: "application/json; charset=utf-8",
headers: {'x-access-token': token},
cache: false,
success: function(data){
if (data.success){
$.each(data.data.reports, function (i, item) {
coord[i] = [ data.data.reports[i].lat , data.data.reports[i].lng ] ;
});
console.log(coord)
}else{
alert(data.error.message);
}
},
error: function(data){
console.log(data);
}
});
}
function initMap() {
var myLatLng = {lat: 43.1107168, lng: 12.3908279};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 2,
center: myLatLng
});
var marker, i;
for (i = 0; i < coord.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(coord[i][0], coord[i][1]),
map: map,
title: 'Hello World!'
});
}
}
How can i resolve this?
thank you very much.
You will need to restructure the code in order to make this work. We need to add markers on the map only after we have fetched the lat/long data successfully by making an AJAX request. We could do this in the following manner.
<script defer
src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXX&callback=initMap">
/*
We will keep a global variable that would contain a reference to the google map object.
It would be initialized as soon as the script for google maps is loaded and initMap function is called subsequently.
*/
var GoogleMap;
coord = new Array();
function setVariable(token) {
format="text/plain";
$.ajax({
url: BASE_URL + "reports",
type: "GET",
contentType: "application/json; charset=utf-8",
headers: {'x-access-token': token},
cache: false,
success: function(data){
if (data.success){
$.each(data.data.reports, function (i, item) {
coord[i] = [ data.data.reports[i].lat , data.data.reports[i].lng ] ;
});
console.log(coord)
var marker, i;
for (i = 0; i < coord.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(coord[i][0], coord[i][1]),
map: GoogleMap,
title: 'Hello World!'
});
}
}else{
alert(data.error.message);
}
},
error: function(data){
console.log(data);
}
});
}
function initMap() {
var myLatLng = {lat: 43.1107168, lng: 12.3908279};
GoogleMap = new google.maps.Map(document.getElementById('map'), {
zoom: 2,
center: myLatLng
});
}
Hopefully, this should work!
I'm using google map api for web...
Also I'm calling search nearby api directly from jquery to search places,
this is error in console
this is response in network
I've already added to use api from all referrer in google api console.
var param = {
key: "My_Key",
location: pos.lat+','+pos.lng,
radius: 3000,
type: "church"
};
$.ajax({
url: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?" + jQuery.param(param),
method: "GET",
async: false,
success: function(resp) {
console.log(resp);
},
error: function(error) {
console.log(error);
}
});
Don't use the Places API web service from javascript on the client, use the Google Maps Javascript API v3 Places Library.
example in documentation
proof of concept fiddle (using the posted request parameters)
code snippet:
var map;
var service;
var infowindow;
function initialize() {
var pyrmont = new google.maps.LatLng(-33.8665433, 151.1956316);
map = new google.maps.Map(document.getElementById('map'), {
center: pyrmont,
zoom: 15
});
var request = {
location: pyrmont,
radius: '3000',
type: ['church']
};
service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, callback);
}
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
});
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<div id="map"></div>
Try adding dataType : 'jsonp' in your $.ajax call as,
$.ajax({
url: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?" + jQuery.param(param),
method: "GET",
dataType : 'jsonp',
async: false,
success: function(resp) {
console.log(resp);
},
error: function(error) {
console.log(error);
}
});
Hope this helps!
Sorry in advance if this isn't the proper way to ask this, please let me know how I can improve my questions :)
Essentially I have a json file which I want to pull data from (name, address, etc) in order to use a Google Maps API function to plot them as markers. This is the current ajax function I'm using:
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false',
success: function(data) {
$(data.group).each(function(index, person) {
if (typeof person.Address != "undefined") {
geocodeAddress(geocoder, map, person);
}
});
}
});
However, this is calling the geocodeAddress function for all 800+ of my directory entries all at once, which is far above my Maps API query limit. I'd like to space these out ~100ms apart to prevent this. I tried using setInterval like to accomplish this, but it seems that the geocodeAddress line is run for all entries at once, so this would only delay all of the functions, not the length between each.
Is there another way I could pull this json data instead of using ajax, or just a way to delay each API request individually?
geocodeAddress function for reference (it both geocodes and plots markers)
function geocodeAddress(geocoder, resultsMap, person) {
//geocoding address
geocoder.geocode({'address': person.Address[0].text}, function(results, status) {
if (status === 'OK') {
//plotting coordinate as marker
var marker = new google.maps.Marker({
map: resultsMap,
position: results[0].geometry.location,
icon: {
url: person.Image[0].src,
size: new google.maps.Size(120, 150),
scaledSize: new google.maps.Size(30, 38),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(15, 19)
}
});
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
});
}
You can loop the geocodeAddress calling with a 100ms spaced out time like below,
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false',
success: function(data) {
var i = 0;
var loop = function(){
if(i < data.group.length){
if (typeof data.group[i].Address != "undefined")
geocodeAddress(geocoder, map, data.group[i]);
i++;
setTimeout(loop, 100);
}
}
loop();
}
});
hope it helps.
With a little mod to your geocodeAddress function, to add an optional callback
function geocodeAddress(geocoder, resultsMap, person, callback) {
//geocoding address
geocoder.geocode({
'address': person.Address[0].text
}, function(results, status) {
if (status === 'OK') {
//plotting coordinate as marker
var marker = new google.maps.Marker({
map: resultsMap,
position: results[0].geometry.location,
icon: {
url: person.Image[0].src,
size: new google.maps.Size(120, 150),
scaledSize: new google.maps.Size(30, 38),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(15, 19)
}
});
} else {
console.log("Geocode was not successful for the following reason: " + status);
}
if (typeof callback == 'function') {
callback();
}
});
}
and, for the sake of minimal changes, adding a wrapper function for geocodeAddress that returns a Promise
function geocodeAddressPromise(geocoder, resultsMap, person) {
return new Promise(function(resolve) {
geocodeAddress(geocoder, resultsMap, person, resolve);
};
}
Your main code can be written as:
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false'
}).then(function(data) {
return data.group.filter(function(person) {
return typeof person.Address != "undefined";
}).reduce(function(promise, person) {
return promise.then(function() {
return geocodeAddressPromise(geocoder, map, person);
}).then(function() {
return new Promise(function(resolve) {
setTimeout(resolve, 100);
});
});
}, Promise.resolve());
});
it uses .filter to include only persons with an address
and a fairly common .reduce pattern to chain Promises in sequence, with the addition of the 100ms timeout between resolution of one address to the start of the next geocode call
You can add delays to your array iteration using setTimeout inside an IIFE:
$.ajax({
url: 'directory.json',
dataType: 'json',
type: 'get',
cache: 'false',
success: function(data) {
//Invoke delayLoop with initial params - i = 0, delay = 100ms
(delayLoop)(0, data.group, 100, geocodePerson);
}
});
//Function to perform delayed iteration function on array elements
function delayLoop (i, list, interval, itemFunc) {
setTimeout(function() {
itemFunc(list[i]);
if (++i < list.length) {
delayLoop(i, list, interval, itemFunc);
}
}, interval)
}
//function to perform on array elements
function geocodePerson(person) {
if (typeof person.Address != "undefined") {
geocodeAddress(geocoder, map, person);
}
}
I've written the below code and all is working grand from the point of view of data, the data is returned from the ajax call in JSON format like the snippet below.
The problem seems to be with the addMarker function, the data is passed into the function ok, I've verified this with an alert() from within the addMarker function but no markers are being plotted on the map and no errors are being thrown in the browser or console.
Do I need to call setMapOnAll after each marker is added to display it on the map? I've tried adding setMapOnAll to the end of the addMarker function but nothing changed.
JSON:
{id:278, title:"", lat:"52.50474200", lng:"-8.71032700"}
Javascript:
$(document).ready(function () {
var map;
var markers = [];
function loadMap()
{
map = new google.maps.Map(document.getElementById('map_canvas'), {
minZoom: 2,
maxZoom: 12,
zoom: 6,
disableDefaultUI: true,
zoomControl: true
});
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
map.setCenter(initialLocation);
});
} else {
map.setCenter({lat: -34.397, lng: 150.644});
}
loadMarkerData(-1);
}
function addMarker(lat, lng) {
var marker = new google.maps.Marker({
position: {lat: lat, lng: lng},
map: map
});
markers.push(marker);
}
function setMapOnAll(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
function loadMarkerData(selectedKeys, year, source)
{
var data = {id: 1};
if (selectedKeys != '' && year != '' && source != '') {
data = {id: 1, selectedKeys:selectedKeys, year:year, source:source};
}
$.ajax(
{
url: "ajaxcall.php",
type: "POST",
data: data,
success: function (data, textStatus, jqXHR)
{
if (data != '') {
markerObj = eval(data);
$.each(markerObj, function(index, element) {
addMarker(element.lat, element.lng)
});
}
},
error: function (jqXHR, textStatus, errorThrown)
{
console.log(textStatus);
}
});
}
});
With your original code, I get a javascript error: Assertion failed: InvalidValueError: setPosition: not a LatLng or LatLngLiteral: in property lat: not a number, because those values are strings. You can fix that by changing this:
function addMarker(lat, lng) {
var marker = new google.maps.Marker({
position: {
lat: lat,
lng: lng
},
map: map
});
markers.push(marker);
}
To:
function addMarker(lat, lng) {
var marker = new google.maps.Marker({
position: {
lat: parseFloat(lat),
lng: parseFloat(lng)
},
map: map
});
markers.push(marker);
}