Google Maps markers not incrementing array - javascript

I have looked all over but can't find an answer to this. I have a map that when I click on it adds markers to where I clicked. I am pushing those markers into an array but when I do one marker just seems to override the one that was in the array before instead of adding another index to the array. The array just always looks like this [me] no matter how many markers are on the map. Here is the code
addLatLng: function(event) {
var path = this.poly.getPath();
var markers = [];
path.push(event.latLng);
this.calcDistance(path);
var marker = new google.maps.Marker({
position: event.latLng,
title: '#' + path.getLength(),
map: this.map
});
markers.push(marker);
console.log(markers);
console.log(marker);
// debugger;
function removeMarkers(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
markers = [];
}
$('#btn-clear-map').on('click', function(event) {
event.preventDefault();
removeMarkers(null);
});
$('#btn-clear-point').on('click', function(event) {
event.preventDefault();
markers[markers.length -1].setMap(null);
});
},
this is part of a backbone view if that makes any difference. I just have no idea why when I push a marker in it seems to override the one that was already in there.
Edit: Ok I just figured out why, every time I click to make a new marker, it is resetting the marker array. Any clever ways to get around this?

The problem is that you are re-declaring the markers array on each call to addLatLng method (Also you're new event handlers and creating removeMarkers function and a closure each time)
Instead, you should keep the markers array as a property of the view as shown below:
Backbone.View.extend({
initialize: function() {
this.markers = [];
},
events: {
'click #btn-clear-map': 'removeMarkers',
'click #btn-clear-point': 'clearPoint',
},
render: function() {},
addLatLng: function(event) {
var path = this.poly.getPath();
path.push(event.latLng);
this.calcDistance(path);
var marker = new google.maps.Marker({
position: event.latLng,
title: '#' + path.getLength(),
map: this.map
});
this.markers.push(marker);
},
removeMarkers: function(event) {
event.preventDefault();
for (var i = 0; i < this.markers.length; i++) {
this.markers[i].setMap(null);
}
this.markers = [];
},
clearPoint: function(event) {
event.preventDefault();
this.markers[this.markers.length - 1].setMap(null);
}
});

Related

Google InfoWindow not loading inside for loop

I have add the following code to a Google Map on a site of mine. The map contains many points pulling from coordinates set in the WordPress backend.
I also want to include some static points which will always stay on the map and am hardcoding their coordinates.
The following is the code I am using and what happens is that the code displays the first marker but not the infobox. Because of this, the code stops and does not continue through the for loop. The issue is at the return function() bit, but I am not sure how to get it working.
var infowindow = new google.maps.InfoWindow({maxWidth: 185});
var setMarker;
var setMarkers = new Array();
var setLocations = [
['<h4>Location1</h4>', 53.4264,-6.2499, '/wp-content/themes/path/to/airport_icon.png'],
['<h4>Location2</h4>', 53.3461,-6.2969, '/wp-content/themes/path/to/train_icon.png'],
['<h4>Location3</h4>', 53.3532,-6.2468, '/wp-content/themes/path/to/train_icon.png'],
['<h4>Location4</h4>', 53.4264,-6.2499, '/wp-content/themes/path/to/dvc_icon.png'],
['<h4>Location5</h4>', 53.4264,-6.2499, '/wp-content/themes/path/to/dvc_icon.png'],
];
for (var i = 0; i < setLocations.length; i++) {
marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(setLocations[i][1], setLocations[i][2]),
icon : setLocations[i][3],
});
setMarkers.push(setMarker);
google.maps.event.addListener(setMarker, 'click', (function(setMarker, i) {
return function() {
infowindow.setContent(setLocations[i][0]);
infowindow.open(map, setMarker);
}
})(setMarker, i));
}
Define your setMarker variable inside the for loop and push it to your markers array:
for (var i = 0; i < setLocations.length; i++) {
var setMarker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(setLocations[i][1], setLocations[i][2])
});
google.maps.event.addListener(setMarker, 'click', (function (setMarker, i) {
return function () {
infowindow.setContent(setLocations[i][0]);
infowindow.open(map, setMarker);
}
})(setMarker, i));
setMarkers.push(setMarker);
}
JSFiddle demo

Declaring google map markers in a loop

I have a weird issue with event listeners on google map markers. Basically I want to declare a bunch of markers in a loop, and have each marker have an associated infowindow. The relevant code is:
var markers=[];
var contents = [];
var infowindows = [];
for (i = 0; i < 10; i++) {
markers[i] = new google.maps.Marker({
position: new google.maps.LatLng(40+Math.random()*5, 4+Math.random()*5),
map: map,
title: 'samplemarker'
});
contents[i] = '<div class="popup_container">' +
'</div>';
infowindows[i] = new google.maps.InfoWindow({
content: contents[i],
maxWidth: 300
});
google.maps.event.addListener(markers[i], 'click', function() {
infowindows[i].open(map,markers[i]);
map.panTo(markers[i].getPosition());
});
}
The markers are created correctly, and the infowindows too, since if I do manually infowindows[i].open(map,markers[i]); they are opened correctly. However the listener does not work.
Even weirder: I have another marker, "marker_1" declared outside of the for loop, exactly the same way. If I write:
google.maps.event.addListener(marker_1, 'click', function() {
infowindows[0].open(map,markers[0]);
map.panTo(markers[0].getPosition());
});
The infowindow 0 is opened and the map is panned to marker 0 when marker_1 is clicked. However when writing, at the exact same position, the same lines except for marker_1 replaced with markers[0], a click on the marker 0 has no effect at all.
Thanks for any help and sorry if it's something stupid!
Inside your onclick handler, you don't already have that i value, in your case it would always take last value of i after the end of the loop, i.e 10, and markers[10] doesn't exist as you only have 10 markers.
To make it work you can e.g. add additional property to your markers in array, that would store marker index and use it inside your onlick handler
var markers=[];
var contents = [];
var infowindows = [];
for (i = 0; i < 10; i++) {
markers[i] = new google.maps.Marker({
position: new google.maps.LatLng(40+Math.random()*5, 4+Math.random()*5),
map: map,
title: 'samplemarker'
});
markers[i].index = i; //add index property
contents[i] = '<div class="popup_container"></div>';
infowindows[i] = new google.maps.InfoWindow({
content: contents[i],
maxWidth: 300
});
google.maps.event.addListener(markers[i], 'click', function() {
console.log(this.index); // this will give correct index
console.log(i); //this will always give 10 for you
infowindows[this.index].open(map,markers[this.index]);
map.panTo(markers[this.index].getPosition());
});
}
see corrected example

Listener event always triggers with last element's info

I'm trying to make a map-based application, but I'm having bit of difficulty. The original code I had been working with added a separate InfoWindow for each marker, but I'd like to get it using a single InfoWindow for which I can set the content on the fly.
However, I still seem to be a little fuzzy on how JavaScript behaves, because each time any marker is clicked the InfoWindow pops up over the last marker and the alert indicates the ID of the last entry in locations.
Short snippet, problem highlighted:
function plotLocations(my_locations) {
locations = my_locations;
for(var i=0; i<locations.length; i++) {
var pos = new google.maps.LatLng(locations[i].loc_lat, locations[i].loc_lng);
var icon = new google.maps.MarkerImage(
"http://goo.gl/TQpwU",
new google.maps.Size(20,32),
new google.maps.Point(0,0),
new google.maps.Point(0,32)
);
var marker = new google.maps.Marker({
map: map,
position: pos,
animation: google.maps.Animation.DROP,
icon: icon
});
// ! -- trouble right here -- ! //
google.maps.event.addListener(marker, 'click', function() {
setPopInfo(pos, i);
});
// ! -- ------------------ -- ! //
}
}
function setPopInfo(pos, index) {
pop_info.setPosition(pos);
pop_info.open(map);
window.alert(pos+"::"+index);
}
Most of the rest of my code:
var map;
var mapBounds;
var locations;
var pop_info;
$(document).ready(init);
function init() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
pop_info = new google.maps.InfoWindow({
content: "I'm not populated!",
size: new google.maps.Size(100,25)
});
google.maps.event.addListener(map, 'bounds_changed', function() {
queryLocations(map.getBounds());
});
prepareGeolocation();
doGeolocation();
}
function queryLocations(bounds) {
jQuery.ajax({
url: 'http://mydomain.com/myapp/test2.php',
data: bounds.toString(),
dataType: 'json',
success: addLocations
});
}
function addLocations(new_locations) {
document.getElementById('footer').innerHTML = new_locations;
plotLocations(new_locations);
}
My reasoning for the single InfoWindow is that once a few hundred Markers and InfoWindows have been created the performance might take a nosedive. Is what I'm trying to do feasible/advisable?
The problem occurs because you're defining your event listener callback function inside the loop. Closures refer to their context dynamically rather than binding to a copy of the data at the time of definition, so you have effectively created locations.length number of functions that are all bound to the same values of marker, pos and i, which are whatever they happened to be when the loop terminated.
To work round this, you could create a function that calls addListener outside the body of the loop, like so:
function plotLocations (my_locations) {
locations = my_locations;
for(var i=0; i<locations.length; i++) {
var pos = new google.maps.LatLng(locations[i].loc_lat, locations[i].loc_lng);
var icon = new google.maps.MarkerImage(
"http://goo.gl/TQpwU",
new google.maps.Size(20,32),
new google.maps.Point(0,0),
new google.maps.Point(0,32)
);
var marker = new google.maps.Marker({
map: map,
position: pos,
animation: google.maps.Animation.DROP,
icon: icon
});
bindEvent(marker, pos, i);
}
}
function bindEvent (marker, pos, i) {
google.maps.event.addListener(marker, 'click', function() {
setPopInfo(pos, i);
});
}

Bing Map adding infoBox from array of pins

Trying to add an infobox to each pin, each pin is loaded from a separate function and attaches the corresponding title, description, lat/lon, etc from an xml file. (source if needed)
In the function that receives the array of pins I'm trying to loop through each item and add infoboxes accordingly. Any ideas as to what I'm missing here?
function GeoRSSImportedCallback(items, bounds) {
map.entities.push(items);
for (var i = 0; i<items.length; i++) {
items.Title = items.title;
items.Description = items.description;
Microsoft.Maps.Events.addHandler(itmes, 'click', displayInfoBox);
}
map.entities.push(infoboxLayer);
map.setView({ bounds: bounds });
}
function displayInfoBox(e) {
pinInfoBox.setOptions({title: e.target.Title, description: e.target.Description, visible:true, offset: new Microsoft.Maps.Point(0,25)});
pinInfoBox.setLocation(e.target.getLocation());
}
I do initialize the following in the GetMap() function
pinInfoBox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
infoboxLayer.push(pinInfoBox);
Your code uses properties that are not part of the various Bing Maps objects, so I am going to assume that is your intent. There are also errors with your for loop, the following should be more correct:
function GeoRSSImportedCallback(items, bounds) {
map.entities.push(items);
for (var i = 0; i<items.length; i++) {
items[i].Title = items[i].title; // Assumes .title is defined
items[i].Description = items[i].description; // Assumes .description is defined
Microsoft.Maps.Events.addHandler(items[i], 'click', displayInfoBox);
}
map.entities.push(infoboxLayer);
map.setView({ bounds: bounds });
}

google maps v3 event trigger on markers created by json

We have a dynamic json feed that is parsed into markers on our google map.
the parsing function looks something like this:
function parse_json(json) {
// alert('start parse: '+json.length);
if (json.length > 0) {
var markers = [];
for (i=0; i<json.length; i++) {
var report = json[i];
//alert(report.longitude +','+report.latitude);
// addLocation(report);
markers[i] = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(report.latitude, report.longitude),
pop_title: report.area1.name,
pop_body: '<b>'+ report.spot.name +'</b>'+
'<br>'+ report.report_description,
draggable: false,
title: 'title',
zIndex: i,
icon: '/images/map_icon.png'
});
markers[i].metadata = {type: "point", id: report.id};
google.maps.event.addListener(markers[i], 'click', onMarkerClick);
}
};
i have added metadata info to the markers created so their id is the report.id - but i want to use the google.maps.event.trigger(SOMETHING_HERE, 'click'); construct to trigger a click event on a given marker when a button outside of the map is pressed. how do i get the object name, or is there a way to do this using the object's id?
thanks!
If you declare your markers array at a higher scope than your parse_json function, then you will be able to refer to it later, something like this:
var markers = new Array();
function parse_json(json) {
//code removed for brevity
}
Then later, when you need to find the marker you want to fire a click event against, you could use the id like this:
for ( var i = 0; i < markers.length; i++ ) {
var mkr = markers[i];
if ( mkr.metadata.id === idYouAreSearchingFor ) {
//do whatever is needed here and fire your event
}
}

Categories