Close open InfoBubble when open a new (gMap v3) - google-maps

I do not know what to do... I just want to close all opened infoBubbles if I'm going to open a new one. I am using the following code. Ideas? I tried a lot and googled a lot but it shouldn't be so complicated, should it? I thought to create an array and save id for the open one, but I think that there must be another, quite easier way to fix this.
$(document).ready(function(){
createmap();
function createmap(lat,lng){
var latlng = new google.maps.LatLng(50, 10);
var myOptions = {
zoom: 12,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
bounds = new google.maps.LatLngBounds();
createMarker();
}
function createMarker(){
var markers = [];
var cm = window.cm = new ClusterManager(
map,
{
objClusterIcon: new google.maps.MarkerImage('images/map/flag_cluster.png', false, false, false, new google.maps.Size(20,20)),
objClusterImageSize: new google.maps.Size(20,20)
}
);
var json = [];
var x1 = -85;
var x2 = 85;
var y1 = -180;
var y2 = 180;
for (var i=0; i<20; ++i) {
json.push(
'{'+
'"longitude":'+(x1+(Math.random()*(x2-x1)))+','+
'"latitude":'+(y1+(Math.random()*(y2-y1)))+','+
'"title":"test"'+
'}'
);
}
json = '['+json.join()+']';
// eval is ok here.
eval('json = eval(json);');
infos = [];
$.each(json, function(i,item){
var contentString = '<div id="content"><a onclick="createdetailpage('+i+');">'+item.title+'<br /></a></div>';
console.log(item.latitude);
var myLatlng = new google.maps.LatLng(item.latitude,item.longitude);
var marker = new google.maps.Marker({
position: myLatlng,
//map: map,
flat: true,
title:item.title,
//animation: google.maps.Animation.DROP,
//icon: myIcon
});
var infoBubble = new InfoBubble({
content: '<div class="phoneytext">'+contentString+'</div>'
});
google.maps.event.addListener(marker, 'click', function() {
if (!infoBubble.isOpen()) {
infoBubble.open(map, marker);
}
});
cm.addMarker(marker, new google.maps.Size(50, 50));
});
map.fitBounds(bounds);
}
});

The simplest approach to only have one infoBubble open is to only have one infoBubble and open it with different contents depending on the marker that is clicked.
InfoWindow example with custom markers (same concept applies to InfoBubble)

The InfoBubble is an OverlayView. As far as I can see, an overlaycomplete event is emitted when an overlay is added. Maybe all your InfoBubbles could listen to that event and close if the added overlay is a different one than "this".
It's just a thought, though, I haven't tried it myself. Feedback appreciated if you try it out!

Related

Show User location on google maps

First thing is I will tell you I am new to google maps and some of it is very confusing to me. What I need to do is show a users location and have the appropriate markers show up. I have the database all ready and somewhat of the Google map.
What I am working with is an example from here. What I can either get is the markers if I use a static LatLng or just the users dynamic location with no markers.
Need help please. And if you downvote this post please let me know why.
Code I am using can be found at https://jsfiddle.net/8q1apmdy/9/ and show where in the blow code is where I am missing something, most likely small or in the wrong position.
function initMap() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
var pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
});
var map = new google.maps.Map(document.getElementById('map'), {
center: pos,
zoom: 12
});
}
a) While running your code locally, I was getting 'pos' undefined, so I moved the following code 'var map = new google.maps.Map(..' inside the getCurrentPosition(){...
b) Then I got another error ' InvalidValueError: setMap: not an instance of Map;' so created a 'var map' globally.
Loaded the map successfully, but still markers were not loaded. while debugging your code at this point 'var marker = new google.maps.Marker({...' it is iterating for all markers from xml but somehow markers are not adding to the map..dont know the reason yet?
So I have tried in a different way. Please see all markers from xml displayed on map. Here I am just getting the 'name' in marker, you might need to add other parameters like id, address etc.
JSFiddle added for reference
var infowindow;
var map;
//var downloadUrl;
function initialize() {
var mapOptions = {
zoom: 12,
center: new google.maps.LatLng(-33.868820, 151.209290),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById('map'), mapOptions);
downloadUrl("https://storage.googleapis.com/mapsdevsite/json/mapmarkers2.xml", function(data) {
var bounds = new google.maps.LatLngBounds();
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName('marker');
for (var i = 0; i < markers.length; i++) {
var id = markers[i].getAttribute('id');
var address = markers[i].getAttribute('address');
var type = markers[i].getAttribute('type');
var latlng = new google.maps.LatLng(parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
bounds.extend(latlng);
var marker = createMarker(id, markers[i].getAttribute("name"), address, latlng, type);
}//finish loop
//map.fitBounds(bounds);
}); //end downloadurl
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
}
function createMarker(id, name, address, latlng, type) {
var marker = new google.maps.Marker({
position: latlng,
map: map
});
google.maps.event.addListener(marker, "click", function() {
if (infowindow) infowindow.close();
infowindow = new google.maps.InfoWindow({content: name});
infowindow.open(map, marker);
});
return marker;
}
JSFiddle

How to define dynamic variables in JSP loop?

I have written the following code to display markers and have respective info windows displaying name of the policestation.
The policestation class has name, latitude and longitude.
<script>
function initialize()
{
var iconBase = 'https://maps.google.com/mapfiles/kml/shapes/';
var myCenter = new google.maps.LatLng(28.6523605,77.0910645);
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var mapProp = {
center: myCenter,
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scaleControl: true
};
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var marker = [];
var info= [];
<%
ArrayList<PoliceStation> stationList = new PoliceStation().loadclass();
for (int i=0 ; i < stationList.size() ; i++) {
%>
var pos = new google.maps.LatLng(
<%= stationList.get(i).getLatitude()%>,
<%= stationList.get(i).getLongitude()%>
);
marker = new google.maps.Marker({
position: pos,
map: map
});
marker.setMap(map);
var MarkerContent = "<div class=\"marker\">" +
"<h2>"+ "<%=stationList.get(i).getstationName()%>"
+"</h2>"+
"</div>";
info=new google.maps.InfoWindow();
info.setOptions({
content: MarkerContent,
size: new google.maps.Size(50, 50),
position: pos
});
google.maps.event.addListener(marker, 'click', function () {
info.setOptions({
content: MarkerContent
});
info.open(map, marker);
});
<%
}
%>
All the markers are set as expected. However clicking any marker results in opening the infowindow of only the last marker drawn.
I get that this is because all the marker, infoWindow names are redundant and in the end only the last infoWindow gets saved to the last marker.
I have come across solutions that encapsulate the content inside the for loop with
(function() {var marker = ...; google.maps.event.addListener...;})();
However, I'm looking for a solution to dynamically distinctly define each variable name.
like for example append the value of a counter incremented at each iteration to each marker and info variable.
Kindly do not provide JSTP solution. looking for a specific JSP solution
Surprisingly it was really easy...
JSP is basically used to print HTML dynamically.
so, instead of using marker variable as
var marker = new google.maps.Marker({
position: pos,
map: map
});
use -
var <%out.print("marker"+i);%> = new google.maps.Marker({
position: pos,
map: map
});
It is to be noted that-
var <%out.print("marker["+i+"]");%> = new google.maps.Marker({
position: pos,
map: map
});
did not work for me.
The correct code above creates new variables with values marker1, marker2... etc
also the content update function inside the event listener-
info.setOptions({
content: MarkerContent
});
is not required.

Google maps infowindow

I am trying to create listeners for some map markers. I can create the markers and they are on the map but, no matter which marker I click on it tells me "Uncaught TypeError: Cannot call method 'open' of undefined" . When I break at the open code it is showing markers[46] which is one more that the highest index. And it doesnt matter which marker I click on its always the same index.
EDIT: I edited the code and pasted all of it. No errors, but nothing happens when I click a marker. I am looking in Chrome and it looks like there isnt a event handler registered
<script>
var map;
var nav = [];
$(document).ready(function () {
//initialise a map
init();
var infowindow = new google.maps.InfoWindow({});
$.get("xxxxxx.kml", function (data) {
html = "";
//loop through placemarks tags
i = 1;
$(data).find("Placemark").each(function (index, value) {
//get coordinates and place name
coords = $(this).find("coordinates").text();
contentString = $(this).find("description").text();
var partsOfStr = coords.split(',');
var lat = parseFloat(partsOfStr[0]);
var lng = parseFloat(partsOfStr[1]);
var myLatLng = new google.maps.LatLng(lng, lat);
place = $(this).find("name").text();
createMarker(myLatLng, place, contentString, i)
//store as JSON
c = coords.split(",")
nav.push({
"place": place,
"lat": c[0],
"lng": c[1]
})
//output as a navigation
html += "<li>" + place + "</li>";
i++;
});
//output as a navigation
$(".navigation").append(html);
//bind clicks on your navigation to scroll to a placemark
$(".navigation li").bind("click", function () {
panToPoint = new google.maps.LatLng(nav[$(this).index()].lng, nav[$(this).index()].lat)
map.panTo(panToPoint);
})
});
markers = [];
function createMarker(myLatLng, title, contentString, i) {
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: title
});
google.maps.event.addListener(markers, 'click', function () {
infoWindow.setContent(contentString);
infowindow.open(map, markers[i]);
});
markers[i] = marker;
return marker
}
function init() {
//google.maps.event.addDomListener(window, 'init', Initialize);
var latlng = new google.maps.LatLng(39.047050, -77.131409);
var myOptions = {
zoom: 4,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
}
})
This is almost a FAQ. When your loop ends, the value of i is 46 (based on your statement). There is no marker 46, so all the click listeners fail. It can be solved with function closure (a createMarker function which holds the association between the marker and the infowindow contents).
Something like this in your example (not tested), call it from inside your marker creation loop, requires a global markers array, but doesn't require the global infowindow array:
//global markers array
markers = [];
// global infowindow
var infowindow = new google.maps.InfoWindow({});
// createMarker function
function createMarker(myLatLng, title, contentString, i)
{
var marker = new google.maps.Marker({
position: myLatlng ,
map: map,
title:title
});
google.maps.event.addListener(markers, 'click', function() {
infoWindow.setContent(contentString);
infowindow.open(map,markers[i]);
});
markers[i] = marker;
return marker
}

Change Google maps to re-use single infowindow rather than creating multiple

I have an increasingly complex Google map which plots thousands of points and clusters them. I have an infowindow opening when the user clicks one of the map markers and it all works great. However, one improvement I'd like to make is to force all other infowindows to close when a new one is opened so that only 1 infowindow can be open at once.
I've tried adding some code (if (infowindow) infowindow.close();) into the listener function to do this, but I think the issue is wider in that I'm currently creating an infowindow for each marker, and there is no access to other infowindows on the event which opens a new one. So, from reading around this it would seem to be a better idea to have just one infowindow which gets reused rather than many.
Trouble is, the code is at the edge of what I can really understand, and my experiments in doing this so far have just broken everything.
The code I currently have is as follows:
var _iconCenter = new google.maps.MarkerImage('/css/img/map-marker.png',
new google.maps.Size(38, 48),
new google.maps.Point(0,0),
new google.maps.Point(19, 44));
var shadow = new google.maps.MarkerImage('/css/img/map-marker-shadow.png',
new google.maps.Size(57, 49),
new google.maps.Point(0,0),
new google.maps.Point(7, 44));
var _icon = '/css/img/map-marker-purple.png';
var infowindow;
var markersArray = [];
var map;
var currentPosition = 0;
var currentmarker;
var firstload = true;
var maploaded = false;
var interval = 5000;
var geocoder;
var stylez = [];
function initialize(items,loop,zoom) {
geocoder = new google.maps.Geocoder();
if (items.length > 0) {
var latlng = new google.maps.LatLng(items[0].Lat, items[0].Lng);
var myOptions = {
zoom: zoom,
center: latlng,
//mapTypeControl: false,
streetViewControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
map.setOptions({styles: stylez});
for (var i = 0; i < items.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(items[i].Lat, items[i].Lng),
title: items[i].Title,
icon: _icon,
shadow: shadow,
infocontent: items[i].Description
});
marker.setMap(map);
attachListener(marker,'marker:'+i);
markersArray.push(marker);
}
//set style options for marker clusters (these are the default styles)
mcOptions = {
gridSize: 44
}
var markerCluster = new MarkerClusterer(map, markersArray, mcOptions);
google.maps.event.addListener(map, "tilesloaded", function () {
if(loop == true){
SetLoop();
}
});
function attachListener(marker,content){
google.maps.event.addListener(marker, "click", function () {
var infowindow = new google.maps.InfoWindow();
map.setCenter(new google.maps.LatLng(marker.getPosition().lat(), marker.getPosition().lng()));
infowindow.setContent(content);
infowindow.open(map,this);
});
}
}
}
function SetLoop() {
//This will fire everytime map loads or recenteres
maploaded = true;
if (firstload) {
firstload = false;
Recenter();
}
}
function Recenter() {
//If previous iteration is not loaded completely, wait to avoid errors
//It could happen for slow internet connection
if (maploaded) {
maploaded = false;
} else {
//keep adding 1 second to interval for slow connection till page loads
interval = interval + 1;
setTimeout("Recenter()", interval);
return;
}
if (infowindow != null && currentmarker != null) {
//currentmarker.icon = _icon;
currentmarker.icon = _iconCenter;
currentmarker.setMap(map);
infowindow.close(map, currentmarker);
}
markersArray[currentPosition].icon = _iconCenter;
markersArray[currentPosition].setMap(map);
map.setCenter(new google.maps.LatLng(markersArray[currentPosition].getPosition().lat(), markersArray[currentPosition].getPosition().lng()));
infowindow = new google.maps.InfoWindow({
content: markersArray[currentPosition].infocontent,
size: new google.maps.Size(50, 50)
});
infowindow.open(map, markersArray[currentPosition]);
currentmarker = markersArray[currentPosition];
if (currentPosition >= markersArray.length - 1) {
currentPosition = 0;
} else {
currentPosition++;
}
if (markersArray.length > 1) {
setTimeout("Recenter()", interval);
}
}
Is the best way to re-use the infowindow or is it okay to do this another way? Any help in pointing me in the right direction here would be much appreciated, thanks folks!
Remove the 'var infowindow' declaration from function attachListener(). If you declare it inside the function it becomes local to the function and you create a new instance each time you execute the function. so:
function attachListener(marker,content){
google.maps.event.addListener(marker, "click", function () {
// marker.getPosition() already returns a google.maps.LatLng() object
map.setCenter(marker.getPosition());
infowindow.close();
infowindow.setContent(content);
infowindow.open(map,this);
});
}
and instead, declare it as a global variable:
var _icon = '/css/img/map-marker-purple.png';
var infowindow = new google.maps.InfoWindow();
//...etc
so that you have only one infowindow object in the whole application

InfoWindow on Marker using MarkerClusterer

This is my html code. I've try anything to add an infowindow on the markers but it don't wanna work. My data is loading from the "Alle_Ortswahlen.page1.xml" file.
Do anyone have an idea how can I add infoWindow to each marker?
<script type="text/javascript">
google.load('maps', '3', {
other_params: 'sensor=false'
});
google.setOnLoadCallback(initialize);
function initialize() {
var stack = [];
var center = new google.maps.LatLng(48.136, 11.586);
var options = {
'zoom': 5,
'center': center,
'mapTypeId': google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), options);
GDownloadUrl("Alle_Ortswahlen.page1.xml", function(doc) {
var xmlDoc = GXml.parse(doc);
var markers = xmlDoc.documentElement.getElementsByTagName("ROW");
for (var i = 0; i < markers.length; i++) {
// obtain the attribues of each marker
var lat = parseFloat(markers[i].getAttribute("Field4"));
var lng = parseFloat(markers[i].getAttribute("Field6"));
var marker = new google.maps.Marker({
position : new google.maps.LatLng(lat, lng),
map: map,
title:"This is a marker"
});
stack.push(marker);
}
var mc = new MarkerClusterer(map,stack);
});
}
</script>
Before the for cycle, make an empty infowindow object.
var infowindow = new google.maps.InfoWindow();
Than in the for cycle, after the marker, add an event listener, like this:
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent("You might put some content here from your XML");
infowindow.open(map, marker);
}
})(marker, i));
There is some closure magic happening when passing the callback argument to the addListener method. If you are not familiar with it, take a look at here:
Mozilla Dev Center: Working with Closures
So, your code should look something like this:
google.load('maps', '3', {
other_params: 'sensor=false'
});
google.setOnLoadCallback(initialize);
function initialize() {
var stack = [];
var center = new google.maps.LatLng(48.136, 11.586);
var options = {
'zoom': 5,
'center': center,
'mapTypeId': google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), options);
var infowindow = new google.maps.InfoWindow();
GDownloadUrl("Alle_Ortswahlen.page1.xml", function(doc) {
var xmlDoc = GXml.parse(doc);
var markers = xmlDoc.documentElement.getElementsByTagName("ROW");
for (var i = 0; i < markers.length; i++) {
// obtain the attribues of each marker
var lat = parseFloat(markers[i].getAttribute("Field4"));
var lng = parseFloat(markers[i].getAttribute("Field6"));
var marker = new google.maps.Marker({
position : new google.maps.LatLng(lat, lng),
map: map,
title:"This is a marker"
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent("You might put some content here from your XML");
infowindow.open(map, marker);
}
})(marker, i));
stack.push(marker);
}
var mc = new MarkerClusterer(map,stack);
});
}
So what you need to do is add some code, inside your for-loop, associating an infowindow onclick event handler with each marker. I'm assuming you only want to have 1 infowindow showing at a time, i.e. you click on a marker, the infowindow appears with relevant content. If you then click on another marker, the first infowindow disappears, and a new one reappears attached to the other marker. Rather than having multiple infowindows all visible at the same time.
GDownloadUrl("Alle_Ortswahlen.page1.xml", function(doc) {
var xmlDoc = GXml.parse(doc);
var markers = xmlDoc.documentElement.getElementsByTagName("ROW");
// just create one infowindow without any content in it
var infowindow = new google.maps.InfoWindow({
content: ''
});
for (var i = 0; i < markers.length; i++) {
// obtain the attribues of each marker
var lat = parseFloat(markers[i].getAttribute("Field4"));
var lng = parseFloat(markers[i].getAttribute("Field6"));
var marker = new google.maps.Marker({
position : new google.maps.LatLng(lat, lng),
map: map,
title:"This is a marker"
});
// add an event listener for this marker
google.maps.event.addListener(marker , 'click', function() {
// assuming you have some content in a field called Field123
infowindow.setContent(markers[i].getAttribute("Field123"));
infowindow.open(map, this);
});
stack.push(marker);
}
var mc = new MarkerClusterer(map,stack);
});