Related
I'm hitting an issue that is WELL discussed in these forums, but none of the recommendations seem to be working for me so I'm looking for some full javascript that works when saved as an html file.
The issue is I keep hitting the OVER_QUERY_LIMIT error when trying to geocode > 11 locations on a Google Map using the V3 APIs called by Javascript. I understand that there is a limit to the rate at which you can call the geocoder (as well as the daily limit on total volume), so I need to introduce a pause in between each result in the array.
Any help very much appreciated.
Here is my code:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var geocoder;
var map;
var wait = false;
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(51.32, 0.5);
var myOptions = {
zoom: 8,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
codeAddress('KT16 8LA' + ', UK');
codeAddress('LS8 2LQ' + ', UK');
codeAddress('NE13 8AF' + ', UK');
codeAddress('KT12 2BE' + ', UK');
codeAddress('W1W 8AN' + ', UK');
codeAddress('EC3N 2LS' + ', UK');
codeAddress('BS9 3BH' + ', UK');
codeAddress('KA10 6LZ' + ', UK');
codeAddress('EC1V 9BW' + ', UK');
codeAddress('WD18 8YN' + ', UK');
codeAddress('HA3 6DQ' + ', UK');
codeAddress('W1U 3PL' + ', UK');
codeAddress('W1T 7QL' + ', UK');
codeAddress('W1S 1TD' + ', UK');
codeAddress('SW1X 8NX' + ', UK');
codeAddress('LE2 8ET' + ', UK');
codeAddress('BA3 4BH' + ', UK');
codeAddress('AL3 8JP' + ', UK');
codeAddress('DE55 4QJ' + ', UK');
codeAddress('W6 0QT' + ', UK');
codeAddress('LA1 1PP' + ', UK');
codeAddress('SW16 4DH' + ', UK');
codeAddress('WC2N 6DF' + ', UK');
codeAddress('RM6 6LS' + ', UK');
codeAddress('S25 3QZ' + ', UK');
codeAddress('WC2H 7LR' + ', UK');
codeAddress('BH24 1DW' + ', UK');
codeAddress('EC2N 6AR' + ', UK');
codeAddress('W1U 2FA' + ', UK');
codeAddress('B60 3DX' + ', UK');
}
function codeAddress(vPostCode) {
if (geocoder) {
geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
}
</script>
<body style="margin:0px; padding:0px;" onload="initialize()">
<div id="map_canvas" style="width:100%; height:90%"></div>
</body>
EDIT: This is what I've tried to do to get it to pause/wait in the relevant section, but it doesn't do anything:
function codeAddress(vPostCode) {
if (geocoder) {
while (wait) { /* Just wait. */ };
geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
/* When geocoding "fails", see if it was because of over quota error: */
} else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
wait = true;
setTimeout("wait = true", 2000);
//alert("OQL: " + status);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
}
Nothing like these two lines appears in Mike Williams' tutorial:
wait = true;
setTimeout("wait = true", 2000);
Here's a Version 3 port:
http://acleach.me.uk/gmaps/v3/plotaddresses.htm
The relevant bit of code is
// ====== Geocoding ======
function getAddress(search, next) {
geo.geocode({address:search}, function (results,status)
{
// If that was successful
if (status == google.maps.GeocoderStatus.OK) {
// Lets assume that the first marker is the one we want
var p = results[0].geometry.location;
var lat=p.lat();
var lng=p.lng();
// Output the data
var msg = 'address="' + search + '" lat=' +lat+ ' lng=' +lng+ '(delay='+delay+'ms)<br>';
document.getElementById("messages").innerHTML += msg;
// Create a marker
createMarker(search,lat,lng);
}
// ====== Decode the error status ======
else {
// === if we were sending the requests to fast, try this one again and increase the delay
if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
nextAddress--;
delay++;
} else {
var reason="Code "+status;
var msg = 'address="' + search + '" error=' +reason+ '(delay='+delay+'ms)<br>';
document.getElementById("messages").innerHTML += msg;
}
}
next();
}
);
}
The general answer to this question is:
Don't geocode known locations every time you load your page. Geocode them off-line and use the resulting coordinates to display the markers on your page.
The limits exist for a reason.
If you can't geocode the locations off-line, see this page (Part 17 Geocoding multiple addresses) from Mike Williams' v2 tutorial which describes an approach, port that to the v3 API.
Here I have loaded 2200 markers. It takes around 1 min to add 2200 locations.
https://jsfiddle.net/suchg/qm1pqunz/11/
//function to get random element from an array
(function($) {
$.rand = function(arg) {
if ($.isArray(arg)) {
return arg[$.rand(arg.length)];
} else if (typeof arg === "number") {
return Math.floor(Math.random() * arg);
} else {
return 4; // chosen by fair dice roll
}
};
})(jQuery);
//start code on document ready
$(document).ready(function () {
var map;
var elevator;
var myOptions = {
zoom: 0,
center: new google.maps.LatLng(35.392738, -100.019531),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map($('#map_canvas')[0], myOptions);
//get place from inputfile.js
var placesObject = place;
errorArray = [];
//will fire 20 ajax request at a time and other will keep in queue
var queuCounter = 0, setLimit = 20;
//keep count of added markers and update at top
totalAddedMarkers = 0;
//make an array of geocode keys to avoid the overlimit error
var geoCodKeys = [
'AIzaSyCF82XXUtT0vzMTcEPpTXvKQPr1keMNr_4',
'AIzaSyAYPw6oFHktAMhQqp34PptnkDEdmXwC3s0',
'AIzaSyAwd0OLvubYtKkEWwMe4Fe0DQpauX0pzlk',
'AIzaSyDF3F09RkYcibDuTFaINrWFBOG7ilCsVL0',
'AIzaSyC1dyD2kzPmZPmM4-oGYnIH_0x--0hVSY8'
];
//funciton to add marker
var addMarkers = function(address, queKey){
var key = jQuery.rand(geoCodKeys);
var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false';
var qyName = '';
if( queKey ) {
qyName = queKey;
} else {
qyName = 'MyQueue'+queuCounter;
}
$.ajaxq (qyName, {
url: url,
dataType: 'json'
}).done(function( data ) {
var address = getParameterByName('address', this.url);
var index = errorArray.indexOf(address);
try{
var p = data.results[0].geometry.location;
var latlng = new google.maps.LatLng(p.lat, p.lng);
new google.maps.Marker({
position: latlng,
map: map
});
totalAddedMarkers ++;
//update adde marker count
$("#totalAddedMarker").text(totalAddedMarkers);
if (index > -1) {
errorArray.splice(index, 1);
}
}catch(e){
if(data.status = 'ZERO_RESULTS')
return false;
//on error call add marker function for same address
//and keep in Error ajax queue
addMarkers( address, 'Errror' );
if (index == -1) {
errorArray.push( address );
}
}
});
//mentain ajax queue set
queuCounter++;
if( queuCounter == setLimit ){
queuCounter = 0;
}
}
//function get url parameter from url string
getParameterByName = function ( name,href )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( href );
if( results == null )
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
//call add marker function for each address mention in inputfile.js
for (var x = 0; x < placesObject.length; x++) {
var address = placesObject[x]['City'] + ', ' + placesObject[x]['State'];
addMarkers(address);
}
});
Using "setInterval" & "clearInterval" fixes the problem:
function drawMarkers(map, markers) {
var _this = this,
geocoder = new google.maps.Geocoder(),
geocode_filetrs;
_this.key = 0;
_this.interval = setInterval(function() {
_this.markerData = markers[_this.key];
geocoder.geocode({ address: _this.markerData.address }, yourCallback(_this.markerData));
_this.key++;
if ( ! markers[_this.key]) {
clearInterval(_this.interval);
}
}, 300);
}
this post was made a while ago, but it provides an answer that did not solve the problem regarding reaching the limit of requests in an iteration for me, so I publish this, to help who else has not served.
My environment happened in Ionic 3.
Instead of making a "pause" in the iteration, I ocurred the idea of iterating with a timer, this timer has the particularity of executing the code that would go in the iteration, but will run every so often until it is reached the maximum count of the "Array" in which we want to iterate.
In other words, we will consult the Google API in a certain time so that it does not exceed the limit allowed in milliseconds.
// Code to start the timer
this.count= 0;
let loading = this.loadingCtrl.create({
content: 'Buscando los mejores servicios...'
});
loading.present();
this.interval = setInterval(() => this.getDistancias(loading), 40);
// Function that runs the timer, that is, query Google API
getDistancias(loading){
if(this.count>= this.datos.length){
clearInterval(this.interval);
} else {
var sucursal = this.datos[this.count];
this.calcularDistancia(this.posicion, new LatLng(parseFloat(sucursal.position.latitude),parseFloat(sucursal.position.longitude)),sucursal.codigo).then(distancia => {
}).catch(error => {
console.log('error');
console.log(error);
});
}
this.count += 1;
}
calcularDistancia(miPosicion, markerPosicion, codigo){
return new Promise(async (resolve,reject) => {
var service = new google.maps.DistanceMatrixService;
var distance;
var duration;
service.getDistanceMatrix({
origins: [miPosicion, 'salida'],
destinations: [markerPosicion, 'llegada'],
travelMode: 'DRIVING',
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, function(response, status){
if (status == 'OK') {
var originList = response.originAddresses;
var destinationList = response.destinationAddresses;
try{
if(response != null && response != undefined){
distance = response.rows[0].elements[0].distance.value;
duration = response.rows[0].elements[0].duration.text;
resolve(distance);
}
}catch(error){
console.log("ERROR GOOGLE");
console.log(status);
}
}
});
});
}
I hope this helps!
I'm sorry for my English, I hope it's not an inconvenience, I had to use the Google translator.
Regards, Leandro.
You are using setTimeout wrong way. The (one of) function signature is setTimeout(callback, delay). So you can easily specify what code should be run after what delay.
var codeAddress = (function() {
var index = 0;
var delay = 100;
function GeocodeCallback(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
new google.maps.Marker({ map: map, position: results[0].geometry.location, animation: google.maps.Animation.DROP });
console.log(results);
}
else alert("Geocode was not successful for the following reason: " + status);
};
return function(vPostCode) {
if (geocoder) setTimeout(geocoder.geocode.bind(geocoder, { 'address': "'" + vPostCode + "'"}, GeocodeCallback), index*delay);
index++;
};
})();
This way, every codeAddress() call will result in geocoder.geocode() being called 100ms later after previous call.
I also added animation to marker so you will have a nice animation effect with markers being added to map one after another. I'm not sure what is the current google limit, so you may need to increase the value of delay variable.
Also, if you are each time geocoding the same addresses, you should instead save the results of geocode to your db and next time just use those (so you will save some traffic and your application will be a little bit quicker)
I am working on a google maps project where I am populating the google maps with markers being read from a database (drawMarkers function). Along with that the google maps finds your current location and keeps refreshing it every couple of seconds to keep track of you on the map. My issue is that have a var closest which is also a function i am using the too find the closest marker then create directions to current locations from there. I did not know how to actually find the closest marker so i borrowed the code from another question from stack overflow and tried to adapt it to this project. I need help to get my closest function to find the closest marker and then to make it the destination in the direction service
$ionicSideMenuDelegate.canDragContent(false);
$scope.getTourMarkers = function () {
tourmarkers.getTourMarkers().success(function (data) {
$scope.tourmarkers = data;
console.log($scope.tourmarkers);
drawMarkers();
});
};
var drawMarkers = function () {
var markers;
var content;
var infoWindow;
for (var i = 0; i < $scope.tourmarkers.length; i++) {
content = '<h2>' + $scope.tourmarkers[i].title + '</h2>' +
'<br />' +
'<p>' +
'</p>';
infoWindow = new google.maps.InfoWindow({
content: content
});
var point = new google.maps.LatLng($scope.tourmarkers[i].lat, $scope.tourmarkers[i].lon);
markers = new google.maps.Marker({
label: "S",
animation: google.maps.Animation.DROP,
position: point,
map: map,
info: content
});
//SCOPE: 'this' refers to the current 'markers' object, we pass in the info and marker
google.maps.event.addListener(markers, 'click', function () {
infoWindow.setContent(this.info);
infoWindow.open(map, this);
});
}
};
var myLatlng = new google.maps.LatLng(38.5602, -121.4241);
var NAPA_HALL_LAT_LNG = new google.maps.LatLng(38.553801, -121.4212745); // just created this marker for testing purposes
var mapOptions = {
center: myLatlng,
zoom: 18,
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoomControl: true,
disableDefaultUI: true
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'SAC STATE'
});
var dest = new google.maps.Marker({
position: NAPA_HALL_LAT_LNG,
map: map,
title: 'NAPA HALL'
});
///////////////////Directions Display//////////////////////
var directionsDisplay = new google.maps.DirectionsRenderer;
var directionsService = new google.maps.DirectionsService;
//////////////////////////////////////////////////////////////////////////////////////////
//Goal of this function is to find closest marker to current location
//then to create directions to that marker.
//should be refreshed everytime in the onSuccess function
var closest = function (directionsService, directionsDisplay, marker, dest) {
var event;
function rad(x) {return x*Math.PI/180;}
function find_closest_marker( event ) {
var lat = event.latLng.lat();
var lng = event.latLng.lng();
var R = 6371; // radius of earth in km
var distances = [];
var shortest = -1;
for( i=0;i < $scope.tourmarkers.length; i++) {
content = '<h2>' + $scope.tourmarkers[i].title + '</h2>' +
'<br />' +
'<p>' +
'</p>';
infoWindow = new google.maps.InfoWindow({
var mlat = $scope.tourmarkers[i].position.lat();
var mlng = $scope.tourmarkers[i].position.lng();
var dLat = rad(mlat - lat);
var dLong = rad(mlng - lng);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(rad(lat)) * Math.cos(rad(lat)) * Math.sin(dLong/2) * Math.sin(dLong/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
distances[i] = d;
if ( shortest == -1 || d < distances[shortest] ) {
shortest = i;
}
}
alert(map.markers[shortest].title);
}
/////**directions feature should have the closest marker be the desitination//
directionsService.route({
origin: marker.position,
destination: dest.position, // i think the marker that should in here is shortest.
travelMode: google.maps.TravelMode.WALKING
}, function(response,status) {
if(status==google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
};
//////////////////////////////////////////////////////////////////////////////////////////
var onSuccess = function (position) {
marker.setPosition(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
directionsDisplay.setMap(map);
dest.setPosition(new google.maps.LatLng(38.553801, -121.4212745));
//dest.setPosition((closest(marker, $scope.tourmarkers)).position); // if you can get this line to work without commenting it out then you're set
closest(directionsService,directionsDisplay, marker,dest);
$scope.map = map;
//$scope.map.panTo(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
};
function onError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
}
navigator.geolocation.watchPosition(onSuccess, onError, {
maximumAge: 3000,
timeout: 5000,
enableHighAccuracy: true
});
Everything in this project is working properly except that closest function. but even then i have already tested the directionservice and even that is working too. I just need help making the destination in the direction service to be the closest marker to current location.
i think this code is helpful for you i used this code in my project such that your requirement same as my requirement
in the below function 'data' means list of lat lng's from server
function initialize(data) {
size = 0;
counts = 0;
stops = data;
size = stops.length;
if (stops.length > 0) {
var map = new window.google.maps.Map(document
.getElementById("map"));
// new up complex objects before passing them around
var directionsDisplay = new window.google.maps.DirectionsRenderer(
{
suppressMarkers : true,
polylineOptions : {
strokeColor : "black"
}
});
var directionsService = new window.google.maps.DirectionsService();
Tour_startUp(stops);
window.tour.loadMap(map, directionsDisplay);
window.tour.fitBounds(map,stops);
/* if (stops.length > 1) */
window.tour.calcRoute(stops,directionsService,
directionsDisplay,size);
}
}
function Tour_startUp(stops) {
var stops=stops;
var counts=0;
if (!window.tour) window.tour = {
// map: google map object
// directionsDisplay: google directionsDisplay object (comes in empty)
loadMap: function (map, directionsDisplay) {
var myOptions = {
zoom:10,
center: new window.google.maps.LatLng(17.379818, 78.478542), // default to Hyderabad
mapTypeId: window.google.maps.MapTypeId.ROADMAP
};
map.setOptions(myOptions);
directionsDisplay.setMap(map);
},
fitBounds: function (map,stops) {
var bounds = new window.google.maps.LatLngBounds();
// extend bounds for each record
jQuery.each(stops, function (key, val) {
var myLatlng = new window.google.maps.LatLng(val.latitude, val.longitude);
bounds.extend(myLatlng);
});
map.fitBounds(bounds);
},
calcRoute: function (stops,directionsService, directionsDisplay,size) {
size=size;
var batches = [];
var itemsPerBatch = 10; // google API max = 10 - 1 start, 1 stop, and 8 waypoints
var itemsCounter = 0;
var wayptsExist = stops.length > 0;
var tempp=0;
while (wayptsExist) {
var subBatch = [];
var subitemsCounter = 0;
for (var j = itemsCounter; j < stops.length; j++) {
subitemsCounter++;
tempp++;
subBatch.push({
location: new window.google.maps.LatLng(stops[j].latitude, stops[j].longitude),
stopover: true
});
if (subitemsCounter == itemsPerBatch)
break;
}
itemsCounter += subitemsCounter;
batches.push(subBatch);
wayptsExist = itemsCounter < stops.length;
// If it runs again there are still points. Minus 1 before continuing to
// start up with end of previous tour leg
itemsCounter--;
}
// now we should have a 2 dimensional array with a list of a list of waypoints
var combinedResults;
var unsortedResults = [{}]; // to hold the counter and the results themselves as they come back, to later sort
var directionsResultsReturned = 0;
for (var k = 0; k < batches.length; k++) {
var lastIndex = batches[k].length - 1;
var start = batches[k][0].location;
//delay(600);
var end = batches[k][lastIndex].location;
// trim first and last entry from array
var waypts = [];
waypts = batches[k];
waypts.splice(0, 1);
waypts.splice(waypts.length - 1, 1);
var request = {
origin: start,
destination: end,
waypoints: waypts,
travelMode: window.google.maps.TravelMode.WALKING
};
(function (kk) {
directionsService.route(request, function (result, status) {
if (status == window.google.maps.DirectionsStatus.OK) {
var unsortedResult = { order: kk, result: result };
unsortedResults.push(unsortedResult);
//alert("count test");
directionsResultsReturned++;
if (directionsResultsReturned == batches.length) // we've received all the results. put to map
{
// sort the returned values into their correct order
unsortedResults.sort(function (a, b) { return parseFloat(a.order) - parseFloat(b.order); });
var count = 0;
for (var key in unsortedResults) {
if (unsortedResults[key].result != null) {
if (unsortedResults.hasOwnProperty(key)) {
if (count == 0) // first results. new up the combinedResults object
combinedResults = unsortedResults[key].result;
else {
// only building up legs, overview_path, and bounds in my consolidated object. This is not a complete
// directionResults object, but enough to draw a path on the map, which is all I need
combinedResults.routes[0].legs = combinedResults.routes[0].legs.concat(unsortedResults[key].result.routes[0].legs);
combinedResults.routes[0].overview_path = combinedResults.routes[0].overview_path.concat(unsortedResults[key].result.routes[0].overview_path);
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getNorthEast());
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getSouthWest());
}
count++;
}
}
}
directionsDisplay.setDirections(combinedResults);
var legs = combinedResults.routes[0].legs;
var summaryPanel = document.getElementById('directions_panel');
summaryPanel.innerHTML = '';
var totdist=0;
for (var i=0; i < legs.length;i++){
var markerletter = "A".charCodeAt(0);
var markerletter2= "B".charCodeAt(0)
markerletter += i;
markerletter2 += i;
markerletter = String.fromCharCode(markerletter);
markerletter2 = String.fromCharCode(markerletter2);
createMarker(directionsDisplay.getMap(),legs[i].start_location,legs[i].start_address,markerletter,size);//To display location address on the marker
var routeSegment = i + 1;
var point=+routeSegment+1;
summaryPanel.innerHTML += '<b>Route Segment: ' + routeSegment + '</b><br>';
summaryPanel.innerHTML += '<b>Point '+ routeSegment +' :</b>'+ ' ' +legs[i].start_address + ' <br> ';
summaryPanel.innerHTML += '<b>Point '+ point +' :</b>'+ ' '+legs[i].end_address + '<br>';
summaryPanel.innerHTML += '<b>Distance Covered '+' :</b>'+legs[i].distance.text + '<br><br>';
var test=legs[i].distance.text.split(' ');
var one=parseFloat(test[0]);
if(test[1]=="m"){
var one=parseFloat(test[0]/1000);
}
totdist=parseFloat(totdist)+parseFloat(one);
}
summaryPanel.innerHTML += '<b> Total Distance :'+totdist + 'km'+ '</b><br><br>';
var i=legs.length;
var markerletter = "A".charCodeAt(0);
markerletter += i;
markerletter = String.fromCharCode(markerletter);
createMarker(directionsDisplay.getMap(),legs[legs.length-1].end_location,legs[legs.length-1].end_address,markerletter,size);
}
}
});
})(k);
function delay(ms) {
ms += new Date().getTime();
while (new Date() < ms){}
}
}
}//calculate route end
};
}
//to show information on clicking marker
var infowindow = new google.maps.InfoWindow(
{
size: new google.maps.Size(150,50)
});
var icons = new Array();
icons["red"] = new google.maps.MarkerImage("mapIcons/marker_red.png",
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(20, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 9,34.
new google.maps.Point(9, 34));
function getMarkerImage(iconStr,size) {
counts++;
if(counts==size){
var markerimageLoc = "http://www.maps.google.com/mapfiles/ms/icons/blue.png";
counts = 0;
}else{
if (iconStr=="undefined") {
iconStr = "red";
var markerimageLoc = "http://www.maps.google.com/mapfiles/ms/icons/red.png";
}
else{
var markerimageLoc="http://www.google.com/mapfiles/marker"+ iconStr +".png";
// var markerimageLoc = "http://www.maps.google.com/mapfiles/ms/icons/red.png";
}
}
icons[iconStr] = new google.maps.MarkerImage(markerimageLoc,
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(25, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 6,20.
new google.maps.Point(9, 34));
return icons[iconStr];
}
// Marker sizes are expressed as a Size of X,Y
// where the origin of the image (0,0) is located
// in the top left of the image.
// Origins, anchor positions and coordinates of the marker
// increase in the X direction to the right and in
// the Y direction down.
var iconShadow = new google.maps.MarkerImage('http://www.google.com/mapfiles/shadow50.png',
// The shadow image is larger in the horizontal dimension
// while the position and offset are the same as for the main image.
new google.maps.Size(37, 34),
new google.maps.Point(0,0),
new google.maps.Point(9, 34));
// Shapes define the clickable region of the icon.
// The type defines an HTML <area> element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var iconShape = {
coord: [9,0,6,1,4,2,2,4,0,8,0,12,1,14,2,16,5,19,7,23,8,26,9,30,9,34,11,34,11,30,12,26,13,24,14,21,16,18,18,16,20,12,20,8,18,4,16,2,15,1,13,0],
type: 'poly'
};
function createMarker(map, latlng, label, character,size) {
var markerletter = character;
var size=size;
if (/[^a-zA-Z]/.test(character)) {
var markerletter = "undefined";
}
var contentString = '<b>' + label + '</b><br>';
var marker = new google.maps.Marker({
position : latlng,
map : map,
shadow : iconShadow,
icon : getMarkerImage(markerletter,size),
shape : iconShape,
title : label,
zIndex : Math.round(latlng.lat() * -100000) << 5
});
marker.myname = label;
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map, marker);
});
return marker;
}
I must say this is the weirdest error that I've ever caught during my programming adventures. I really have no idea why this is happening.
Basically, my application must receive some data from a Mysql Database and when the user clicks in a country, a infowindow must appear with some information (from the DB). The DB communication is working fine, the problem is: when I pass the mouse over a country, sometimes, the mouseover event isn't called, same thing with mouseout.
But sometimes? With what frequency? Here is the weirdest part: During specific times of the day. I'm brazilian, I work with UTC -3 here, if I acces my application at 18:00, it doesn't work, however if I access it during the morning, like 7 am, IT DOES WORK.
I really have no idea why this is happening, tryed to search online but found nothing...
Can someone help me? This is the code I'm using (no erros appears in the js console, the error happens in chrome, firefox, IE...):
<script type="text/javascript" >
var colors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00'];
var map
var infowindow;
function initialize() {
var myOptions = {
zoom: 2,
center: new google.maps.LatLng(10, 0),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'),
myOptions);
geocoder = new google.maps.Geocoder();
// Initialize JSONP request
var script = document.createElement('script');
var url = ['https://www.googleapis.com/fusiontables/v1/query?'];
url.push('sql=');
var query = 'SELECT name, kml_4326 FROM ' +
'1foc3xO9DyfSIF6ofvN0kp2bxSfSeKog5FbdWdQ';
var encodedQuery = encodeURIComponent(query);
url.push(encodedQuery);
url.push('&callback=drawMap');
url.push('&key=AIzaSyAm9yWCV7JPCTHCJut8whOjARd7pwROFDQ');
script.src = url.join('');
var body = document.getElementsByTagName('body')[0];
body.appendChild(script);
}
function drawMap(data) {
var rows = data['rows'];
for (var i in rows) {
if (rows[i][0] != 'Antarctica') {
var newCoordinates = [];
var geometries = rows[i][1]['geometries'];
if (geometries) {
for (var j in geometries) {
newCoordinates.push(constructNewCoordinates(geometries[j]));
}
} else {
newCoordinates = constructNewCoordinates(rows[i][1]['geometry']);
}
//var randomnumber = Math.floor(Math.random() * 4);
var country = new google.maps.Polygon({
paths: newCoordinates,
//strokeColor: colors[randomnumber],
strokeOpacity: 0,
strokeWeight: 1,
//fillColor: colors[randomnumber],
fillOpacity: 0
});
infowindow = new google.maps.InfoWindow({
content: ''
});
google.maps.event.addListener(country, 'mouseover', function() {
alert("HIIIIII JOW");
this.setOptions({fillOpacity: 0.3});
});
google.maps.event.addListener(country, 'mouseout', function() {
this.setOptions({fillOpacity: 0});
});
google.maps.event.addListener(country, 'click', function(event) {
var lat = event.latLng.lat();
var lng = event.latLng.lng();
initialize2(lat,lng);
});
country.setMap(map);
}
}
}
function constructNewCoordinates(polygon) {
var newCoordinates = [];
var coordinates = polygon['coordinates'][0];
for (var i in coordinates) {
newCoordinates.push(
new google.maps.LatLng(coordinates[i][1], coordinates[i][0]));
}
return newCoordinates;
}
function initialize2(lat,lng){
var url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + lat + "," + lng+ "&sensor=true&language=en";
jQuery.getJSON(url, function (data) {
for (var i = 0; i < data.results[0].address_components.length; i++){
//var formatted = results[0].formatted_address;//.short_name
var countryName
var shortname = data.results[0].address_components[i].short_name;
var longname = data.results[0].address_components[i].long_name;
var type = data.results[0].address_components[i].types;
if (type.indexOf("country") != -1){
if (isNullOrWhitespace(shortname)){
countryName = shortname;
}
else{
countryName = longname;
}
}
}
var lat2;
var lng2
geocoder.geocode( {'address' : countryName}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
lat2 = results[0].geometry.location.lat();
lng2 = results[0].geometry.location.lng();
//alert(results[0].geometry.location);//map.setCenter(results[0].geometry.location);
//alert(lat2+','+lng2);
var array = <?php echo json_encode($arr); ?>;
var str = 'Nenhuma exchange cadastrada neste país!';
for(var i = 0;i<array.length;i++){
if(countryName==array[i][0]){
var string = 'country_volume.php?country=' + countryName;
str = '<center><strong>'+array[i][0]+'</strong></center>' +
'<strong>Número de Exchanges: </strong>' + array[i][1] + '</br>' +
'<strong>Volume: </strong>' + array[i][2] + '</br>' +
'<strong>Ranking Mundial: </strong> ' + array[i][3] + 'º' + '</br>' +
'<strong>Porcentagem Mundial (%): </strong> ' + array[i][4] + '%' + '</br>' +
'<a href='+string+'>' + 'Mais Informações' + '</a>';
}
}
if (infowindow) infowindow.close();
infowindow = new google.maps.InfoWindow({
content: str,
map: map,
position: new google.maps.LatLng(lat2,lng2)
});
}
});
});
}
function isNullOrWhitespace(text) {
if (text == null) {
return true;
}
return text.replace(/\s/gi, '').length < 1;
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
You may exceeded the daily quota of Fusion Tables API:
The default request quota limits are the following:
25,000 requests per day per API project, where reads count as one request and writes count as five requests.
30 write requests per minute per table
You may request more quota at the Google APIs Console under the "Quotas" tab.
The storage quota limits are:
100 MB per table
250 MB total among all your tables
For more details, please refer to here.
First, I'm using the library from : http://www.pittss.lv/jquery/gomap/examples/marker.php,
and I'm using a webservice to get data.
I would like to locate these informations on the map, but i can't know before, how many elements I will have to create.
To get data I have this code :
$('#default-search').submit(function () {
var gomap_marker = [];
var search_where = $('#search-where').val();
if ($('#search-where').val() == "")
search_where = "-1";
$.ajax({
url: "http://my_url.com/",
contentType: "json",
data: {
city: search_where
},
success: function (data) {
//List received data
$.each(data, function (index, item) {
//create an array with data
gomap_marker.push({
id: item.Id,
address: item.Street + ', ' + item.ZipCode + ' ' + item.City,
icon: 'images/marker.png',
group: 'toshow',
html: '' + item.Street + ', ' + item.ZipCode + ' ' + item.City + ''
});
}); // END - $.ajax success each
// valid test
for (var i = 0; i < gomap_marker.length; i++) {
alert('1 - ' + gomap_marker[i].id + gomap_marker[i].address + gomap_marker[i].html);
}
// reset the map for each request
$("#map").removeData();
alert('Test');
// map init + markers
jQuery('#map').goMap({
maptype: 'ROADMAP',
zoom: 13,
scaleControl: true,
scrollwheel: false,
markers: gomap_marker
});
}, // END - $.ajax success
error: function () { alert("simple request goes wrong"); }
}); // END - $.ajax
return false;
}); // END - default-search
Only the first row of my array create a marker on the map. I don't understand how to set the others.
I would like to use $.goMap.createMarker instead of creating an array and reset the map, but I had the same problem : only the first row created a marker on the map.
Regards,
emm First create an array of lat,long
var data = new Array();
data[0] = new Array();
data[0][0] = 'FOOD'; //name
data[0][1] = '23,23';//coordinates(lat,lng)
function HTMLMarker( place ) {
this.name = place[0];
var latLngStrings = place[1].split(',');
var lat = +latLngStrings[0];
var lng = +latLngStrings[1];
this.pos = new google.maps.LatLng( lat, lng );
}
HTMLMarker.prototype = new google.maps.OverlayView();
HTMLMarker.prototype.onRemove = function () {};
HTMLMarker.prototype.onAdd = function () {
var div = this.div = document.createElement('DIV');
div.className = "htmlMarker";
div.innerHTML = ''+this.name+'';
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
};
HTMLMarker.prototype.draw = function () {
var overlayProjection = this.getProjection();
var position = overlayProjection.fromLatLngToDivPixel(this.pos);
var panes = this.getPanes();
this.div.style.left = position.x - 30 + 'px';
this.div.style.top = position.y - 48 + 'px';
};
function initialize() {
var myLatLng = new google.maps.LatLng(23,23);
var mapOptions = {
zoom: 15,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var gmap = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
for (var i = 0; i < data.length; i++) {
addMarker( data[i] );
}
function addMarker( place ) {
var htmlMarker = new HTMLMarker( place );
htmlMarker.setMap(gmap);
}
}
google.maps.event.addDomListener( window, 'load', initialize );
This should work!!
I am creating the array with php:
<script>
<?php $i = 0;
foreach($places as $place) {
$pins = $place['pins']; //coordinates
$name = $place['name'];
echo "data[$i] = new Array();\n";
echo "data[$i][0] = '" .$name. "';\n";
echo "data[$i][1] = '" .$pins. "';\n";
$i++;
} ?>
</script>
ALSO In css add this
.htmlMarker {
position: absolute;
}
I've got the following problem with Googlemaps.
I've created a createMarker function which returns a marker which I publish with addOverlay(). This works perfect, the marker get shown but the only problem is the click event voor the marker, I want a infowindow which is populated with the 'I want this text to be published' text, instead it gets populated with a var called html which I set in the beginning of my code (var html = 'test';), I received earlier a message with 'html is not defined', this is why is set the html var. Every infowindow has the text 'test' in it. I've tried using updateInfoWindow() but that doesn't work, anyone familiar with this problem? I can supply you with the full source but I think the createMarker function should be enough.
function GM_load() {
map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.enableScrollWheelZoom();
map.setMapType(G_HYBRID_MAP);
geocoder = new GClientGeocoder();
GM_showItems();
}
function GM_showItems() {
GDownloadUrl("modules/Googlemaps/ajax/getItems.php", function(data, responseCode) {
var xml = GXml.parse(data);
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
//start
var itemid = markers[i].getAttribute('id');
var title = markers[i].getAttribute('name');
var address = markers[i].getAttribute('address');
var city = markers[i].getAttribute('city');
var x = 0;
if (geocoder) {
geocoder.getLatLng(address + ' ' + city,
function(point) {
if (!point) {
alert(address + ' ' + city + " not found");
} else {
x = x+1;
Marker = createMarker(point, x);
map.addOverlay(Marker);
}
}
);
}
}
});
}
function createMarker(latlng, number) {
var marker = new GMarker(latlng);
marker.value = number;
GEvent.addListener(marker,"click", function() {
map.openInfoWindowHtml(latlng,'i want this text to be published');
});
return marker;
}
Solved.
I overwrite var html. not perfect but it works.