I'm trying to iterate through a collection of Markers and using a counter variable to wire up an event. "When someone clicks a marker, show the infobox in position 'count'"
The problem is as the script executes, the count variable is shared among each and every click event subscriber.
Meaning, a click in Marker A or B is wired to the same position, meaning the same InfoBox.
var popups = [];
var count = 0;
#foreach (var marker in Model) {
<text>
/* Create Markers */
popups[count] = {};
popups[count]["marker"] = new google.maps.Marker({
map: themap
});
popups[count]["content"] = document.createElement("div");</div>';
popups[count]["infoboxoptions"] = {
boxClass: 'infobox-custom'
};
popups[count]["infobox"]= new InfoBox(popups[count]["infoboxoptions"]);
google.maps.event.addListener(popups[count]["marker"], "click", function (e) {
popups[count]["infobox"].open(themap, this);
/* PROBLEM IS HERE! ^ */
});
count++;
</text>
}
I understand the problem but don't know how to tackle it. Javascript is using the same variable for each click event and incrementing it after every iteration is also incrementing it for each click event.
Any suggestions?
Here's one solution. I used the Razor engine to ouput a hardcoded number value.
var popups = [];
var count = 0;
#{ var i = 0; }
#foreach (var marker in Model) {
<text>
/* Create Markers */
popups[count] = {};
popups[count]["marker"] = new google.maps.Marker({
map: themap
});
popups[count]["content"] = document.createElement("div");</div>';
popups[count]["infoboxoptions"] = {
boxClass: 'infobox-custom'
};
popups[count]["infobox"]= new InfoBox(popups[count]["infoboxoptions"]);
google.maps.event.addListener(popups[count]["marker"], "click", function (e) {
popups[#i]["infobox"].open(themap, this);
});
count++;
</text>
i++;
}
Related
Guys need a bit of help with google maps, I'm creating a tracking web app using MySQL DB coordinates, the tracking works well so far except the google map markers keep repeating when refreshed, I have set the map marker refresh using a setInterval function for every 5 seconds(for testing). I've tried clearoverlays() methods and remove map markers method(from google sample) but doesn't work. Appreciate your help, thank you
<script defer
src="https://maps.googleapis.com/maps/api/js?key="KEY"8&callback=initMap">
</script>
<script type="text/javascript">
setInterval(function () {
BindMarker();
}, 5000);
var customIcons = {
blue: { icon: 'blue48.png'},
};
var marker;
var map = null;
var infoWindow = null;
function load() {
map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(1.4370993, 110.3387572),
zoom:15,
});
infoWindow = new google.maps.InfoWindow;
}
function BindMarker() {
downloadUrl('maps1.php', function (data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var icon = customIcons["blue"] || {};
marker = new google.maps.Marker({
map: map,
animation: google.maps.Animation.BOUNCE,
position: point,
icon: icon.icon,
shadow: icon.shadow
});
}
});
}
function bindInfoWindow(marker, map, infoWindow) {
google.maps.event.addListener(marker, 'click', function () {
map.setCenter(marker.getPosition());
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function () {
if (request.readyState == 4) {
request.önreadystatechange = doNothing;
callback(request, request.status); }
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() { }
</script>
The functions I tried are given below( I called the remove overlays function, remove markers and also the delete markers function before BindMarker() inside the setInterval function so that it would remove the markers before binding new markers
function setMapOnAll(map) {
for (let i = 0; i < markers.length; i++) { markers[i].setMap(map); }
}
function clearMarkers() {setMapOnAll(null); }
function deleteMarkers() {clearMarkers(); markers = [];}
function clearOverlays() {
while(markers.length) { markers.pop().setMap(null); }
markers.length = 0;
}
I believe you've confounded the examples, which your attempted code shows verbatim and what your code is actually doing.
It the sample code you're drawing from, the variable markers is an array of Google Map marker objects. So this code makes sense in that regard:
function deleteMarkers() {clearMarkers(); markers = [];}
But, your code is not creating an array of those objects. Your code does not have a variable named markers that is accessible outside of the downloadUrl() function. The variable markers does show up inside that function, but it contains an HTMLCollection element - not an array of markers.
To fix this you need to create an array named markers right after the variable name marker is created.
Then, within the for loop, just after you create the marker push that marker on to the markers array. You will also have to rename the existing markers variable to something more appropriate like markerElements.
Now, the deleteMarkers() function will work as expected.
function pushMarkers() {
locInfo = new google.maps.InfoWindow();
for (var i = 0; i < model.length; i++) {
var loc = model[i].places;
var title = model[i].title;
model[i].marker = new google.maps.Marker({
position: loc,
title: title,
animation: google.maps.Animation.DROP,
map: map,
id: i
});
console.log(model[i].title);
model[i].marker.addListener('click', function() {
console.log('InfoWindow Loop entered');
toggleBounce(this);
populateInfoWindow(this, locInfo);
});
wikiLink(model[i].marker);
}
}
Its not advisable to make functions within a loop so i want to make the function outside the loop.
You shouldn't make multiple functions at all, in point of fact, you should just make it once and then attach it as a listener in the loop. such that:
function handleMarkerClick() {
console.log('InfoWindow Loop entered');
toggleBounce(this);
populateInfoWindow(this, locInfo);
}
model[i].marker.addEventListener('click', handleMarkerClick);
Note that if you need to pass contextual information to that handleMarkerClick function that's only available inside the loop, let's say you want it to know the index (i) for some reason, you can bind it:
model[i].marker.addEventListener('click', handleMarkerClick.bind(model[i].marker, i);
and then the signature of the function would need to be function handleMarkerClick(i, event){}
I use the following script to generate this page
function initialize() {
var mapCanvas = document.getElementById('map');
var mapOptions = {center:new google.maps.LatLng(latitudeMid,longitudeMid),zoom:15,mapTypeId:google.maps.MapTypeId.ROADMAP,streetViewControl:false,mapTypeControl:true,scaleControl:true,scaleControlOptions:{position:google.maps.ControlPosition.TOP_RIGHT}};
var map = new google.maps.Map(mapCanvas, mapOptions);
var i;
var insertion;
var previousMarker;
// -------------------------------
//show locations on the map
// -------------------------------
for (i = 0; i < fotoCount; i++) {
var myLatLng=new google.maps.LatLng(Latituden[i], Longituden[i]);
var marker = new StyledMarker({styleIcon:new StyledIcon(StyledIconTypes.MARKER,{color:'00ff00',text:Letters[i]}),position:myLatLng,map:map});
marker.set('zIndex', -i);
insertion='<img src=\"http://www.pdavis.nl/Ams/'.concat(Bestanden[i],'.jpg\"></img>');
insertion=insertion.concat('<table class=width100><tr><td>Bestand: ',Bestanden[i],'</td><td class=pright>Lokatie: ',Latituden[i],' °N., ',Longituden[i],' °E. (',Letters[i],')</td>');
insertion=insertion.concat('<td class=pright>Genomen: ',Datums[i],'</td></tr><td colspan=3>Object: ',Objecten[i],'</td></table>');
google.maps.event.addListener(marker, 'click', function() {
$('#photo').html(insertion);
this.styleIcon.set('color', 'ff0000');
if(previousMarker!=null){previousMarker.styleIcon.set('color', '00ff00')};
previousMarker=this;
});
}
Clicking a marker should do two things: (i) turn the marker red (and any existing red marker green) and (ii) show the appropriate photo with information in the right-hand panel. The first does work, but the second always shows the photo corresponding to the last marker. Using
"alert(insertion);" shows that this is correct for each marker.
You can't do it this way because at the end of the loop, "i" will always be the last index. And of course when you click on a marker, "i" value inside the callback is the last index, so you should always have the last picture displayed.
Just put insertion code inside your click callback isn't enough because of the i value. You didn't bind anything to fix value in your callback so you will have the same problem.
The following solution use the marker object to bind the "i" value, like this you can use it in your callback.
Script tested on your page :).
Adapt it as you want !
function initialize() {
var mapCanvas = document.getElementById('map');
var mapOptions = {center:new google.maps.LatLng(latitudeMid,longitudeMid),zoom:15,mapTypeId:google.maps.MapTypeId.ROADMAP,streetViewControl:false,mapTypeControl:true,scaleControl:true,scaleControlOptions:{position:google.maps.ControlPosition.TOP_RIGHT}};
var map = new google.maps.Map(mapCanvas, mapOptions);
var i;
var previousMarker;
// -------------------------------
//show locations on the map
// -------------------------------
for (i = 0; i < fotoCount; i++) {
var myLatLng=new google.maps.LatLng(Latituden[i], Longituden[i]);
var marker = new StyledMarker({styleIcon:new StyledIcon(StyledIconTypes.MARKER,{color:'00ff00',text:Letters[i]}),position:myLatLng,map:map});
marker.set('zIndex', -i);
marker.myIndex = i;
google.maps.event.addListener(marker, 'click', function() {
var insertion = "";
insertion='<img src=\"http://www.pdavis.nl/Ams/'.concat(Bestanden[this.myIndex],'.jpg\"></img>');
insertion=insertion.concat('<table class=width100><tr><td>Bestand: ',Bestanden[this.myIndex],'</td><td class=pright>Lokatie: ',Latituden[this.myIndex],' °N., ',Longituden[this.myIndex],' °E. (',Letters[this.myIndex],')</td>');
insertion=insertion.concat('<td class=pright>Genomen: ',Datums[this.myIndex],'</td></tr><td colspan=3>Object: ',Objecten[this.myIndex],'</td></table>');
$('#photo').html(insertion);
this.styleIcon.set('color', 'ff0000');
if(previousMarker!=null){previousMarker.styleIcon.set('color', '00ff00')};
previousMarker=this;
});
}
}
insertion should be an array. This way when you iterate, in eacj iteration you are just overwriting the content of insertion. In the end you have last value from image array as insertion.
var insertionArr = [];
...
insertion=insertion.concat('<td class=pright>Genomen: ',Datums[i],'</td></tr><td colspan=3>Object: ',Objecten[i],'</td></table>');
insertionArr[marker] = insertion; // Add it to the array
google.maps.event.addListener(marker, 'click', function() {
$('#photo').html(insertionArr[this]);// get it from the array
...
});
This is not tested code.
I have a simple google map with multiple markers (4 in this case).
I want to add a "bubble" on click event. Markers are rendered fine, but the bubble (infowindow) show always on the last pin. I mean:
I click marker[1] - infowindow shows up on marker[3]
I click marker[[2] - infowindow shows up on marker[3]
etc.
I think that the problem is in the way I loop my array
Here is my loop, that iterates through 4 elements of array:
var key = 0;
var markers = new Array();
var infowindows = new Array();
for(key in myJson.hotels)
{
var newLatlng = new google.maps.LatLng(myJson.hotels[key].latitude,myJson.hotels[key].longitude);
markers[key] = new google.maps.Marker(
{
position: newLatlng,
map: map,
title: 'Hello World!'
});
// the code above works fine - it renders 4 pins o my map
infowindows[key] = new google.maps.InfoWindow(
{
content: contentString
});
google.maps.event.addListener(markers[key], 'click', function() {
//console.log(key); <-- this always return [3]
infowindows[key].open(map,markers[key]);
});
//console.log(key); <-- this always return the right key - 0,1,2,3
}
}
The function in addListener gets called asynchronously. When it gets called you dont know which value key has.
You can come arround this by storing the key in a closure.
google.maps.event.addListener(markers[key], 'click',
function (k) {
return function() { infowindows[k].open(map,markers[k]);
}(key)
});
I used a #phylax hint and I solved the problem this way:
I made a new function:
function addClickEventToMarker(aMap,aKey){
google.maps.event.addListener(markers[aKey], 'click', function() {
//console.log(key); <-- this always return [3]
infowindows[aKey].open(aMap,markers[aKey]);
});
}
and I call the function in my 'for' loop:
for(key in myJson.hotels)
{
var newLatlng = new google.maps.LatLng(myJson.hotels[key].latitude,myJson.hotels[key].longitude);
markers[key] = new google.maps.Marker(
{
position: newLatlng,
map: map,
title: 'Hello World!'
});
infowindows[key] = new google.maps.InfoWindow(
{
content: contentString
});
addClickEventToMarker(map, key);
}
}
I have functions that when a li element is clicked markers are added to the map. If another li is clicked then the original markers are removed and the new one appearr.
The issue I am having is that the markers are placed on the map when a li is clicked for the first time. When a second li is clicked the markers are removed but the new ones are not added. I get no error in firebug. I cant see what I am missing.
$(document).ready(function() {
$(".markerSelection").click(function() {
var selectionId = $(this).attr("id");
drop(selectionId);
});
});
var markers = {
shopping : [
new google.maps.LatLng(52.26183, -7.11339),
new google.maps.LatLng(52.26134, -7.11226),
new google.maps.LatLng(52.26067, -7.11181),
new google.maps.LatLng(52.26003, -7.11033)],
cars : [
new google.maps.LatLng(52.26183, -7.11339),
new google.maps.LatLng(52.26134, -7.11226),
new google.maps.LatLng(52.26067, -7.11181),
new google.maps.LatLng(52.26003, -7.11033)]
};
var iterator = 0;
function drop(selectionId) {
clearOverlays();
for (var i = 0; i < markers[selectionId].length; i++) {
setTimeout(function() {
addMarker(selectionId);
}, i * 200);
}
}
function addMarker(selectionId) {
marker = new google.maps.Marker({
position: markers[selectionId][iterator],
map: map,
draggable: false,
animation: google.maps.Animation.DROP
});
iterator++;
markersArray.push(marker);
}
// Removes the overlays from the map, but keeps them in the array
function clearOverlays() {
if (markersArray) {
for (i in markersArray) {
markersArray[i].setMap(null);
}
}
}
I reviewed your code one more time, and I think the problem is with iterator, which is initialized to 0 in global scope. That is why the first time it works okay, but after that, indices exceed. It seems you should set it to zero at the beginning of the drop() function.
However it makes more sense if you pass index as a second parameter of addMarker() instead of an outer variable which is handled in drop() and complicate you code.
You have defined markers as a Json variable, but I don't know what you mean by markers[selectionId]! Markers is not defined as an array and it seems it's not correct to refer to it by index!