Google maps - reuse single infoWindow for multiple markers - javascript

I have multiple markers and currently when more than one infoWindow is clicked, the other already-opened infoWindows stay open, cluttering the map. I would prefer it if I could simply reuse a single infoWindow, move it and update it's content. This is what I am attempting to do below:
var info = new SnazzyInfoWindow ();
/*
* Loop through each item in the 'features' array, including info windows, and display the marker
*/
features.forEach(function (feature) {
var marker = new google.maps.Marker({
position: feature.position,
icon: icons[feature.type].icon,
map: map
});
var infoContent = feature.contentImage + feature.content;
marker.addListener('click', function() {
infoCallback(infoContent, marker);
});
});
function infoCallback(infoContent, marker) {
return function() {
info.close();
info.setContent(infoContent)
info.open(map, marker);
};
};
However I am receiving the error Cannot read property 'placement' of undefined and can't seem to figure out what's wrong here.
Note that I am using the "Snazzy Info Window" plugin, but I think the same would apply to the stock infoWindow.

Yes. Inside the onClick function, when marker.addListener('click' is being executed, you don't have feature/marker. The variables are not what they were when the foreach was executed.
One trick I mostly use, is to make an array of the marker objects. Inside the onClick you search for the 'this' marker inside the array.
Something like this:
var markers = []; // store the markers in this array
features.forEach(function (feature) {
var marker = new google.maps.Marker({
position: feature.position,
icon: icons[feature.type].icon,
map: map
});
markers.push(marker);
marker.addListener('click', function() {
// first find out which marker was clicked on
var index = markers.indexOf(this); // this represents the marker that was clicked on
// index should be the same index as the index for features.
var feature = features[index];
var marker = markers[index];
var infoContent = feature.contentImage + feature.content;
// now we can call infoCallback.
infoCallback(infoContent, marker);
});
});

Related

Google Map Markers With Url

I really cant understand javascript, i know it should be a very easy question but i stucked..
I have a google map with multiple markers and i added every marker and work perfect but i wanted to give them links. My locations array is like;
['http://website.com',36.598900,35.202094,'1']
i use [1] and [2] as lat long but i wanted to use [0] as link. My loop works perfect but every marker's link going to last item's link
Here is my loop
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
icon: image,
url: locations[i][0],
});
google.maps.event.addListener(marker, 'click', function() {
window.location.href = marker.url;
});
}
Where did i make the mistake?
1/ You need to add var before marker = new google.maps.Marker({ ,
Because , you use now marker as Global variable which is overridden for each iteration.
2/ Anyway, best practices are to save all markers as object attributes . Let's call this Object: mk , then your markers will be mk.marker0,mk.marker1,...so on.
var mk={}; // this is nameSpace to save all markers
locations.map((loc,i)=>{
mk['marker'+i] = new google.maps.Marker({
position: new google.maps.LatLng(loc[1], loc[2]),
map: map,
icon: image,
url: loc[0],
});
return mk['marker'+i];
}).forEach((marker)=>{
google.maps.event.addListener(marker, 'click', function() {
window.location.href = marker.url;
});
})

Google Maps with multiple markers in Bootstrap Modal

I'm trying to display a Google map in a Bootstrap modal with multiple markers. I have found several posts where people were having problems displaying the map on the modal with just one marker, but none with multiple markers. This is what I currently have, but my map is just showing up gray.
var locations = [...]
var complexMap = new google.maps.Map(document.getElementById('complexes-modal-map-canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP
});
//create empty LatLngBounds object
var bounds = new google.maps.LatLngBounds();
var infowindow = new google.maps.InfoWindow();
for (i = 0; i < locations.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
icon: locations[i][3],
map: complexMap
});
//extend the bounds to include each marker's position
bounds.extend(marker.position);
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infowindow.setContent(locations[i][0]);
infowindow.open(complexMap, marker);
}
})(marker, i));
}
$("#complexes-modal-map-canvas").on("shown.bs.modal", function () {
var currentCenter = complexMap.getCenter();
google.maps.event.trigger(complexMap, "resize");
complexMap.setCenter(currentCenter);
complexMap.fitBounds(bounds);
});
There are 2 things I had to do to make this work. The first thing was an obvious mistake - I was selecting the incorrect element on the "shown.bs.modal" method. I needed to select my Bootstrap modal, not the Google Map. The second thing was to call the "fitBounds" method before calling the "resize" event and setting the center.
$("#complexes-modal").on("shown.bs.modal", function () {
complexMap.fitBounds(bounds);
var currentCenter = complexMap.getCenter();
google.maps.event.trigger(complexMap, "resize");
complexMap.setCenter(currentCenter);
});

Google Map markers - add a custom icon with a unique label for each marker

I have implemented a google map with multiple markers but what i am failing to do is how to add a unique label for each marker i.e. Each marker needs have a letter:e.g.
Marker 1 needs to display 'A'
Marker 2 needs to display 'B'
Marker 3 needs to display 'C'
Marker 4 needs to display 'D'
...
an example of what i am trying to achieve is: http://www.athenos.com/locator/ --- enter 11205 in the zip search
here is a portion of my map code - my init and add_marker methods:
init : function() {
var self = this;
// set map property
var map = new google.maps.Map(self.dom_element, self.options);
self.map = map;
// set some other shit
new google.maps.Size(95, 77),
new google.maps.Point(0,0),
new google.maps.Point(47, 76);
// creating new bounds
var bounds = new google.maps.LatLngBounds();
// for loop to iterate through locations
for (var i = 0; i < self.locations.length; i++) {
// extend the bounds
bounds.extend(self.locations[i].latlng);
// add the marker
self.add_marker(self.locations[i].latlng, i);
}
// centers the map based on the existing map markers
self.map.fitBounds(bounds);
},
add_marker : function(latlng, marker_index) {
var self = this;
var marker = new google.maps.Marker({
position: latlng,
map: self.map,
icon: self.map_icon,
zIndex: 998,
id: marker_index // give the marker an ID e.g. 0, 1, 2, 3 - use this for indexing the listed venues
});
google.maps.event.addListener(marker, 'mouseover', function(event) {
var this_marker = this;
// executes handler and passes the marker as 'this' and event data as an argument
self.handle_marker_mouseover.call(self, this, event);
this_marker.setZIndex(999);
});
google.maps.event.addListener(marker, 'mouseout', function(event) {
// executes handler and passes the marker as 'this' and event data as an argument
self.handle_marker_mouseout.call(self, this, event);
});
google.maps.event.addListener(marker, 'click', function(event) {
// executes handler and passes the marker as 'this' and event data as an argument
self.handle_marker_click.call(self, this, event);
});
},
...
Please help.
Thanks in advance
just try to locate your icon, in marker's prop, at this url:
http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=7|00FF00|000000
So iterate with letters over the first part of the chld querystring parameter, and don't forget to choose your marker's color (latest two part, pipe separated)
Take a look at the article below. It's very simple. Use a marker with numeric labels or a marker with alphabet label (A,B..)
Multiple marker with labels in google map
for (i = 1; i <= markers.length; i++) {
var letter = String.fromCharCode("A".charCodeAt(0) + i - 1);
var data = markers[i - 1]
var myLatlng = new google.maps.LatLng(data.lat, data.lng);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: data.title,
icon: "http://maps.google.com/mapfiles/marker" + letter + ".png"
});
(function (marker, data) {
google.maps.event.addListener(marker, "click", function (e) {
infoWindow.setContent(data.description);
infoWindow.open(map, marker);
});
})(marker, data);
}
Go to this article for more details
Multiple marker with labels in google map

Setting infoWindow for a list of markers created inside a callback function (directionsService)

I'm trying to set infoWindows for markers that are created in the callback function of a directionsService (Google Maps API V3). I tried many different ways to do that without any luck..
Here is a skeleton of how my code looks like:
for(i=0;i<markersList.length;i++){
map = someMap
var request = myRequestObject;
var directionsService = new google.maps.DirectionsService();
var directionsDisplay = new google.maps.DirectionsRenderer();
directionsDisplay.setMap(map);
directionsService.route(request, (function (address) {
return function(response, status) {
//Use the directions service to do some stuff
//..Then create markers
var marker = new google.maps.Marker({
map: map,
title: address['title']
});
//push the marker to a list of markers attached to the map
//this can be useful to delete all markers in a later step
map.markers.push(marker);
//Creating multiple instances of infoWindows works fine though..
//However, Creating 1 info window for the whole map doesn't work from here
//If I try that, I'd set the same content for all info windows
//which is not what I want.
}
}
)(markersList[i])
);
}
I tried doing this, which didn't work either:
//add setInfo as a custom function to my map
//then call it to iterate over all markers and add info windows
google.maps.Map.prototype.setInfo = function() {
for(var i=0; i < this.markers.length; i++){
infowindow.setContent(this.markers[i].getTitle());
google.maps.event.addListener(this.markers[i], 'click', function(){
infowindow.close();
infowindow.open(map,this.markers[i]);
});
}
};
Then I'd call this function after I'm done with directionsService.route (check the first code block), outside my main for-loop. However, it never finds any markers attached to the map for some reason..
Any thoughts on how to assign the right infoWindows to the map markers?
I want to have 1 infoWindow instance so that I could close it when a new infoWindow is clicked (infoWindow.close()).
Thanks!
Here is how I do it within a geocoder callback function (a little different than the directionService, but still using a callback function, so the methodology should be the same) using only one infowindow. I would use this in a loop when geocoding a bunch of addresses.
var infowindow = new google.maps.InfoWindow();
geocoder.geocode( { 'address': value}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//create and add marker to map based off geocode result
var marker = new google.maps.Marker({
map: map,
title: results[0].formatted_address,
position: results[0].geometry.location
});
//add marker to array so we can clear it later
markersArray.push(marker);
//create listener for marker infowindow and set content
google.maps.event.addListener(marker, 'click', function() {
infowindow.close();
infowindow.setContent(results[0].formatted_address);
infowindow.open(map,marker);
});
}
});
One way to do this is have an external function that sets the content on the infowindow, and as you add your markers, you call that function instead of having the event listener declared inline within your loop. The problem is that after all the markers are created, when you click one, it will just use whatever the value of results[0].formatted_address is, which is whatever it was last set to at the end of the loop.
var marker = new google.maps.Marker({
map: map,
title: address['title']
});
//push the marker to a list of markers attached to the map
//this can be useful to delete all markers in a later step
map.markers.push(marker);
// add an event listener for this marker
bindInfoWindow(marker, map, infowindow, address['title']);
And that function is simply:
function bindInfoWindow(marker, map, infowindow, html) {
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(html);
infowindow.open(map, marker);
});
}
PS: You shouldn't need to call infowindow.close() prior to calling infowindow.open(). As there's only one infowindow, the API will automatically close it before reopening it at the new location.

google maps infoWindow in javascript (creating multiple infoWindows through a loop)

I am pulling my latlng object from a database and when I loop through the query in the javascript the markers all populate just fine, but when ever I click on one they all open the same infoWindow object on a different marker. I assume this is some sort of naming issue, but I am having trouble finding out why because it all looks right to me. the following code is in a cfoutput tag creating the loop.
var latlng_#get_latlng.recordcount# = new google.maps.LatLng(#get_latlng.mlat#,#get_latlng.mlong#);
var marker_#get_latlng.recordcount# = new google.maps.Marker({
position: latlng_#get_latlng.recordcount#,
map: map,
title: "test"
});
var contentString_#get_latlng.recordcount# = "test" + #get_latlng.recordcount#;
var infowindow_#get_latlng.recordcount# = new google.maps.InfoWindow({
content: contentString_#get_latlng.recordcount#
});
google.maps.event.addListener(marker_#get_latlng.recordcount#, 'click', function() {
infowindow_#get_latlng.recordcount#.open(map,marker_#get_latlng.recordcount#);
});
Rather than producing so much redundant JS, I'd create a function that adds the markers.
function addMarker(lat, lng, title, content) {
var latlng = new google.maps.LatLng(lat, lng);
var marker = new google.maps.Marker({
position: latlng,
map: map,
title: title
});
var infowindow = new google.maps.InfoWindow({ content: content });
google.maps.event.addListener(marker, "click", function() {
infowindow.open(map, marker);
});
}
Then in your loop:
addMarker(#get_latlng.mlat#,#get_latlng.mlong#,"#get_latlng.title#","#get_latlng.content#");
Doesn't 'recordcount' return the number of values in your result set? In which case, all your variable names will be the same. Therefore they will all be rendered correctly, but will continually overwrite the JavaScript variable reference: and will all create an infoWindow based on the last one you did.
You need a more unique name: I presume you wanted an index based on the resultset index, but a simple count would be fine.

Categories

Resources