googlemaps info window popup doesn't loading the dynamic content - google-maps

please help me with this issue. I have the following code with working address variable. I tryed to add titles to the Infowindow so when a user clicks on a marker on the map to see some content in popup. Unfortunately, for all popups I can see the same title. I tested, it is a correct js array, but shows only the first titles that comes from the array.. Please help to solve this issue.. Thank you in advance guys !
<script type="text/javascript" charset="utf-8">
var map;
var address = < ? php echo json_encode($adr); ? > ;
var titles = < ? php echo json_encode($ttl); ? > ;
var x = 0;
var nbAddresses = address.length;
var geocoder;
var mark;
var contentString = titles[x];
function init() {
var moptions = {
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map"), moptions);
geocoder = new google.maps.Geocoder();
for (var i = 0; i < nbAddresses; i++) {
geocoder.geocode({
'address': address[i]
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: titles[x]
});
map.setCenter(results[0].geometry.location);
x++;
setInfoWindow();
}
});
}
function setInfoWindow() {
google.maps.event.addListener(mark, 'click', function(event) {
var iwindow = new google.maps.InfoWindow();
iwindow.setContent(contentString);
iwindow.open(map, this);
});
}
}
window.onload = init;
</script>

changing
x++;
setInfoWindow(); to
setInfoWindow();
x++;
sets the problem !

At the start of your program you set the contentString to the first element in the title array
var contentString = titles[x];
Then you use this variable inside the setInfoWindow function unchanged.
What if you changed the setInfoWindow to accept a contentString parameter like so
function setInfoWindow(contentString) {...
When you call setInfoWindow, pass in the title.
setInfoWindow(title[x]);
Make sure you increment x after you call this function, so move x++ below setInfoWindow call.
EDIT You will also notice a strange problem from time to time where some titles may appear on the wrong markers. This is because you are doing multiple geocodes at once, and you may get a response out of order.
The following modification would fix that.
for (var i = 0; i < nbAddresses; i++) {
geocoder.geocode({
'address': address[i]
}, return function(x) { // we define a function and call it straight away. The function returns another function which is our callback.
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: titles[x]
});
map.setCenter(results[0].geometry.location);
setInfoWindow();
}
}
}(i)); // (i) after the function declaration calls the function and passes in the current value of i
}
So basically what we did here was define a function and run it straight away with the current value of 'i' passed in. The function would then return another function. This function will be run once the goecoding has finished. But now we have a reference to 'i' as it was when the function was defined. So you no longer need to keep a record of x outside this function as x will be equal to i which corresponds with the address passed into geocoder.
This is called a closure.
How do JavaScript closures work?

Related

google maps over query limit

I know that similar questions have been posted but I have not found and answer in any of them as it relates to my particular issue.
I have a javascript that uses google maps to place customer zipcodes on a map. The problem I am have is similar to what others have already posted – I get a “over query limit” error.
I have tried different setups using setTimeOut to try to send google the data within the allowable time intervals but I can’t get it to work.
Here is my action:
function initialize()
{
var rowNum = 0 ;
var rowColor = "" ;
var latlng = new google.maps.LatLng(27.91425, -82.842617);
var myOptions =
{
zoom: 7,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
geocoder = new google.maps.Geocoder();
data.forEach(function(mapData,idx)
{
window.setTimeout(function()
{
geocoder.geocode({ 'address': mapData.address}, function(results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
title: mapData.title,
icon: getIcon(mapData.type)
});
var contentHtml = "<div style='width:250px;height:90px'><strong>"+mapData.title+"</strong><br />"+mapData.address+"</div>";
var infowindow = new google.maps.InfoWindow({
content: contentHtml
});
google.maps.event.addListener(marker, 'click', function()
{
infowindow.open(map,marker);
});
marker.locid = idx+1;
marker.infowindow = infowindow;
markers[markers.length] = marker;
if (idx%2 == 0)
{
rowColor = 'style="background-color:#00FFFF;"' ;
}
else
{
rowColor = 'style="background-color:#FFFFFF;"' ;
}
var sideHtml = '<div ' + rowColor + ' class="loc" data-locid="'+marker.locid+'"><b>'+mapData.title+'</b><br/>';
sideHtml += mapData.address + '</div>';
$("#locs").append(sideHtml);
//Are we all done? Not 100% sure of this
if(markers.length == data.length) doFilter();
}
else
{
// alert("Geocode was not successful for the following reason: " + status);
}
}, 3000);
});
});
When I run my page using this action, I get back 11 markers even though I have many more than that in my JSON string. The window.setTimeout has absolutely no effect – I’m obviously doing something wrong here.
I would appreciate any help on this matter.
Thanks,
I found the answer to my question. I found the following code on the Web and modified it to my needs.
With it, you can load many markers without getting Over Query Limit from Google.
I have tested it with over 100 markers and it works beautifully. The page does not freeze up at all.
I am certain some of you guys can do something much more elegant and efficient but this is a good starting point.
<script type="text/javascript">
//<![CDATA[
// display ani gif
loadingGMap() ;
// delay between geocode requests - at the time of writing, 100 miliseconds seems to work well
var delay = 100;
// ====== Create map objects ======
var infowindow = new google.maps.InfoWindow();
var latlng = new google.maps.LatLng(27.989551,-82.462235);
var mapOptions =
{
zoom: 7,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var geo = new google.maps.Geocoder();
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var bounds = new google.maps.LatLngBounds();
// ====== 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();
}
);
}
// ======= Function to create a marker
function createMarker(add,lat,lng)
{
var contentString = add;
if (add=='EOF')
{
stopLoadingGMap() ;
}
var addArray = add.split(' ');
var zipcode = addArray.pop();
var zipcode = add.match(/\d{5}/)[0] ;
var image = 'icons/sm_02.png';
var marker = new MarkerWithLabel(
{
position: new google.maps.LatLng(lat,lng),
map: map,
icon: image,
labelContent: zipcode,
labelAnchor: new google.maps.Point(50, 0),
labelClass: "labels", // the CSS class for the label
labelStyle: {opacity: 0.75},
zIndex: Math.round(latlng.lat()*-100000)<<5
});
google.maps.event.addListener(marker, 'click', function()
{
infowindow.setContent(contentString);
infowindow.open(map,marker);
});
bounds.extend(marker.position);
}
// ======= An array of locations that we want to Geocode ========
// use static or build dynamically
// use as many markers as you need – I’ve test with over 100
var addresses = var data = [
{‘StreetAddress1 City State Zipcode’},
{‘StreetAddress2 City State Zipcode’},
{‘StreetAddress3 City State Zipcode’},
{‘StreetAddress14 City State Zipcode’},
…
{‘EOF’},
];
// ======= Global variable to remind us what to do next
var nextAddress = 0;
// ======= Function to call the next Geocode operation when the reply comes back
function theNext()
{
if (nextAddress < addresses.length)
{
setTimeout('getAddress("'+addresses[nextAddress]+'",theNext)', delay);
nextAddress++;
}
else
{
// We're done. Show map bounds
map.fitBounds(bounds);
}
}
// ======= Call that function for the first time =======
theNext();
// This Javascript is based on code provided by the
// Community Church Javascript Team
// http://www.bisphamchurch.org.uk/
// http://econym.org.uk/gmap/
//]]>
</script>

Adding Google Maps V3 User input through a searchbox

So, I found some instructions around and a few questions that seemed to answer this question, but none really worked for me or were very incomplete. I'm seeking a way to display the traditional google maps interaction of search and a pin is displayed on the map at the location. This marker, then, should be a blank option to include the data a user wants and the location saved to my database. I tried this sample by Google Dev and it worked for a custom click on the map, but the integration with a simple auto-complete search or even the google's own autocomplete search didn't quite worked.
I was wondering if there is a plugin or a technique (or a tutorial) that would suit this case (that I previously thought would be a simple matter as it is the traditional search on google maps). Thanks!
I can show you how I did this page http://www.a-zhotels.net/register, you could easily combine all the fields into one autocomplete address field. However, this should give you an idea.
First, create a function:
function getMapByGeoLocation() {
//build the address using many fields.
var postcode = $("#HotelPostcode").val();
var address = $("#HotelAddress").val();
var town = $("#HotelTown").val();
var city = $("#HotelCity").val();
var country = $("#HotelCountryId > option:selected").text();
var fulladdress = address + ', ' + town + ', ' + postcode + ', ' + city + ', ' + country;
geocoder.geocode(
{
'address': fulladdress
},
function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location = results[0].geometry.location;
console.log(location);
//map and marker should be previously created
map.setCenter(location);
map.setZoom(14);
marker.setPosition(location);
//These 2 hidden inputs will be posted to the server
$("#HotelLatitude").val(location.Ya);
$("#HotelLongitude").val(location.Za);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
This function is then called when the textbox and dropdowns change:
$("#HotelTown, #HotelAddress, #HotelPostcode").change(getMapByGeoLocation);
See below the function that creates the map:
var map;
var marker;
var geocoder;
function createMap() {
if (map) { //Map already exists
return;
}
if (!$('#mapCanvas').is(':visible')) {
return;
}
var mapCanvas = $("#mapCanvas")[0];
var averageLatitude = $("#HotelLatitude").val();
var averageLongitude = $("#HotelLongitude").val();
map = new google.maps.Map(mapCanvas, {
streetViewControl: true,
zoom: 13,
scrollwheel: false,
center: new google.maps.LatLng(averageLatitude, averageLongitude)
});
geocoder = new google.maps.Geocoder();
//Associate the styled map with the MapTypeId and set it to display.
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
marker = new google.maps.Marker({
position: new google.maps.LatLng(averageLatitude, averageLongitude),
draggable: true,
map: map
});
google.maps.event.addListener(marker, "dragend", function () {
var position = marker.getPosition();
map.panTo(position);
$("#HotelLatitude").val(position.lat());
$("#HotelLongitude").val(position.lng());
});
google.maps.event.addListener(map, "center_changed", function () {
var position = map.getCenter();
marker.setPosition(position);
$("#HotelLatitude").val(position.lat());
$("#HotelLongitude").val(position.lng());
});
}
createMap();
I am not sure what exactly you are looking for.
If you are looking for autocomplete field that adds a marker to the map after the user entered some string and opens an infowindow with a form on the map, is may be something like that: http://jsfiddle.net/XG9Qj/2/
It is important to notice, that this example only places a marker on the map if the user selected one of the suggestions from the autocomplete. To allow him to enter an arbitrary string you have to watch the input for RETURN and use the google maps geocoder on your own(1).
var geocoder = new google.maps.Geocoder();
geocoder.geocode(...)

Geocoding using Google Maps API v3 - Linking the original request to the response

I have a list of schools that I want to plot on a Google Map. I'm using Google's Geocoding Service to lookup the lng/lat for a given postcode, upon successfully retrieving this information I want to drop a marker, together with adding the appropriate event listener that opens an infobox when a given marker is clicked.
When I make a request to the geocoder it's in the context of a school, when I receive a callback I lose this context. You'll see from code below that I've come up with a clunky solution to this, although it fails occasionally when the geocoder results truncate the postcode.
Should I be using something like jQuery's Deferred Object to solve this issue?
var geocoder;
var map;
var infowindow
var iterator = 0;
geosearch = new Array();
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() { // delay added to prevent being throttled
addMarker();
iterator++;
}, i * 1000);
}
}
function addMarker() {
address = schools[iterator].addresses[0].address.zip;
geosearch[address] = schools[iterator]; // this is how I'm keeping track of initial request
geocoder.geocode( { 'address': address }, function(results, status) {
var school = geosearch[results[0].address_components[0].short_name]; // loading the school associated with the initial request, which only works if the postcode completely matches up - clunky!
if (status == google.maps.GeocoderStatus.OK) {
// each school has tags, I want to set a marker if certain tags exist
if ($.inArray('D', school.tags) > 0) {
var image = 'map_markers/brown_MarkerD.png';
} else if ($.inArray('C', school.tags) > 0) {
var image = 'map_markers/red_MarkerC.png';
} else if ($.inArray('B', school.tags) > 0) {
var image = 'map_markers/yellow_MarkerB.png';
} else if ($.inArray('A', school.tags) > 0) {
var image = 'map_markers/green_MarkerA.png';
} else {
var image = 'map_markers/blue_MarkerZ.png';
}
// add the marker to the map, using result
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
draggable: false,
icon: image,
shadow: 'http://www.google.com/mapfiles/arrowshadow.png',
animation: google.maps.Animation.DROP
});
// adds listening on marker so that popup box appears when clicked
google.maps.event.addListener(marker, 'click', (function(marker, school) {
return function() {
infowindow.setContent(
''+school.name+''
+'<address>'
+school.addresses[0].address.street+'<br />'
+school.addresses[0].address.city+'<br />'
+school.addresses[0].address.state+'<br />'
+school.addresses[0].address.zip+'<br />'
+school.addresses[0].address.country+'<br />'
+'</address>');
infowindow.open(map, marker);
}
})(marker, school));
} else {
console.log("* NOT found: " + status);
}
});
}
function initialise() {
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow();
var latlng = new google.maps.LatLng(54.82659788452641,-3.417279296874991);
var mapOptions = {
zoom: 6,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
drop(); // loops through schools to add marker
}
I would suggest geocoding the addresses offline and storing the coordinates in your database (or wherever you are storing the addresses). Then use the coordinates to display the markers.
I would also suggest reviewing this article on geocoding strategies from the documentation
To answer your question, I would suggest using javascript function closures to associate the address with the callback function.
The problem I was experiencing here was just a questions of scope, and in particular the way that I was referencing the school within the addMarker() function. Rather than referencing the school within the schools array using the global iterator variable, I instead pass in this school, this way the correct school is always referenced on the callback that is created within this scope.
var geocoder;
var map;
var infowindow
var iterator = 0;
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() {
addMarker(schools[iterator]); // pass in the school as an argument
iterator++;
$('#current_school').text(iterator); // taken this out of addMarker()
}, i * 1000);
}
}
function addMarker(school) {
geocoder.geocode( { 'address': school.addresses[0].address.zip }, function(results, status) {
... // the inners from here remain the same
});
}

Display Number on Marker for Google Maps

All,
I've got the following code to display my markers on my maps:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function'){
window.onload = func
} else {
window.onload = function() {
oldonload();
func();
}
}
}
var map,
infowin=new google.maps.InfoWindow({content:'moin'});
function loadMap()
{
map = new google.maps.Map(
document.getElementById('map'),
{
zoom: 12,
mapTypeId:google.maps.MapTypeId.ROADMAP,
center:new google.maps.LatLng(<?php echo $_SESSION['pav_event_latitude']; ?>,
<?php echo $_SESSION['pav_event_longitude']; ?>)
});
addPoints(myStores);
}
function addPoints( points )
{
var bounds=new google.maps.LatLngBounds();
for ( var p = 0; p < points.length; ++p )
{
var pointData = points[p];
if ( pointData == null ) {map.fitBounds(bounds);return; }
var point = new google.maps.LatLng( pointData.latitude, pointData.longitude );
bounds.union(new google.maps.LatLngBounds(point));
createMarker( point, pointData.html );
}
map.fitBounds(bounds);
}
function createMarker(point, popuphtml)
{
var popuphtml = "<div id=\"popup\">" + popuphtml + "<\/div>";
var marker = new google.maps.Marker(
{
position:point,
map:map
}
);
google.maps.event.addListener(marker, 'click', function() {
infowin.setContent(popuphtml)
infowin.open(map,marker);
});
}
function Store( lat, long, text )
{
this.latitude = lat;
this.longitude = long;
this.html = text;
}
var myStores = [<?php echo $jsData;?>, null];
addLoadEvent(loadMap);
</script>
This works great. However I'm trying to say add a number over the marker so that people can relate the number on my site with the marker in Google Maps. How can I go about creating the number over top of my markers (on top of the actual icon and not in an information bubble)?
Any help would be greatly appreciate! Thanks in advance!
EDIT: This API is now deprecated, and I can no longer recommend this answer.
You could use Google's Charts API to generate a pin image.
See: http://code.google.com/apis/chart/infographics/docs/dynamic_icons.html#pins
It'll make and return an image of a marker from the parameters you specify. An example usage would be: https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=2|FF776B|000000
To implement it into your Google Map, it can be added into the new Marker() code:
var number = 2; // or whatever you want to do here
var marker = new google.maps.Marker(
{
position:point,
map:map,
icon:'https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld='+number+'|FF776B|000000',
shadow:'https://chart.googleapis.com/chart?chst=d_map_pin_shadow'
}
);
EDIT:
For quite some time now, map markers have an option called label available.
var marker = new google.maps.Marker({
position:point,
map:map,
label: "Your text here."
});
Labels themselves have few options to play with. You can read more about it here.
Original answer
Here is a service similar to one described by Rick - but still active and you can upload your own marker image.
Service is no longer available.

Google fusion tables data and changing image to markers

Here is my problem. I want to set different image to standard markers given by fusion tables. I extract data from the column that contains my points "(coord,coord)" BUT when I associate this coordinates to a marker, this one is not showed! I think that the solution is soooo easy but I can't get it :(. Please read in the section "HERE IS THE PROBLEM" in the middle of this code to have a clear idea. Thanks!!!!
function initialize() {
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(46.06454, 13.23561), //the center lat and long
zoom: 9, //zoom
mapTypeId: google.maps.MapTypeId.ROADMAP //the map style
});
//make gviz request
setData();
}
/* GVIZ - get data from Fusion Tables */
function setData() {
//create a viz query to send to Fusion Tables
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + encodeURIComponent("SELECT dove FROM 781907"));
//set the callback function that will be called when the query returns
query.send(getData);
}
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
for (i = 0; i < numRows; i++) {
var row = response.getDataTable().getValue(i,0);
codeAddress(row);
}
}
var geocoder;
function codeAddress(latlng) {
// HERE IS THE PROBLEM!!!!
// Test show correctly "(lat,lng)" BUT no marker showed on the map!
document.getElementById("test").innerHTML = latlng;
geocoder.geocode( { 'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: latlng
//icon: new google.maps.MarkerImage("http://www.google.com/images/icons/product/fusion_tables-32.png")
});
}
});
}
UPDATE: Based on #Trott's answer, maybe something like this? But still not running. Any advice?
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
//create an array of row values
for (i = 0; i < numRows; i++) {
rowtext = response.getDataTable().getValue(i,0);
var strArr[] = rowtext.split(",");
document.getElementById("via").innerHTML = rowtext;
row = new google.maps.LatLng(strArr[0],strArr[1]);
codeAddress(row);
}
}
geocoder.geocode() requires a LatLng object. Your variable latlng is simply text. You'll need to find a way to convert it to a LatLng object. Most obvious way is probably to parse it with a regex or some other way and pass the lat and lng to new google.maps.LatLng(). There may be a more elegant solution, but that will work.
If it helps, here's some quick hacking I did to your code to confirm what I wrote above. I just hardcoded your first pair of coordinates. You'll still need to write something to parse the data.
function codeAddress(latlng) {
//Whoops, latlng is a string. We need it to be an object. Let's just hardcode one for demo purposes.
latlng=new google.maps.LatLng(46.0724339, 13.249490000000037);
geocoder.geocode( { 'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: latlng,
icon: new google.maps.MarkerImage("http://www.google.com/images/icons/product/fusion_tables-32.png")
});
}
});
}
UPDATE: If you (#Massimo) want to do it the way you have it in your update, then you need to remove the parentheses and possibly white space. Try something more like this:
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
//create an array of row values
for (i = 0; i < numRows; i++) {
var rowtext = response.getDataTable().getValue(i,0);
var sanitizedText = rowtext.replace(/[\(\)\s]/g, "");
var strArr = sanitizedText.split(",");
document.getElementById("via").innerHTML = rowtext;
row = new google.maps.LatLng(strArr[0],strArr[1]);
codeAddress(row);
}
}