I try to make a custom infobox. If I run for one marker, it works, but if I try from an imgUr (the array has got coordinates, name and other attributes for every marker) which have more than one marker I can't make it work. It shows only the first one marker and none else and no infobox.
Here is the code:
for (i = 0; i < imgAr.length; i++) {
var location = new google.maps.LatLng(imgAr[i].coords.coordinates[1],
imgAr[i].coords.coordinates[0]);
var marker = new google.maps.Marker({
position : location,
map : map,
icon : "icons/coffee1.png" ,
animation : google.maps.Animation.DROP,
infoboxIndex : i // <--- That's the extra attribute
});
var content = "<h5> Name:" + imgAr[i].name +
"<br> Description:" + imgAr[i].description +
"<br><img src='" + imgAr[i].image +
"' width='100px' height='100px'/> <h5>";
var var_infobox_props = {
content: content,
disableAutoPan: false,
maxWidth: 0,
pixelOffset: new google.maps.Size(-10, 0),
zIndex: null,
boxClass: "myInfobox",
closeBoxMargin: "2px",
closeBoxURL: "icons/close.png",
infoBoxClearance: new google.maps.Size(1, 1),
visible: true,
pane: "floatPane",
enableEventPropagation: false
};
var var_infobox = new InfoBox(var_infobox_props);
google.maps.event.addListener(marker, 'mouseover',
function(event) {
map.panTo(event.latLng);
map.setZoom(16);
infocoffee[this.infoboxIndex].open(map, this);
}
);
// Save infobox in array
infocoffee.push(var_infobox);
// Save marker in array
markers.push(marker);
}
markers.setMap(map);
What is not working? How can I fix it?
It sounds like either infocoffee.push(var_infobox); or markers.push(marker); results in an error, and the javascript stopped execute from there (That's why you have only one markers.)
I reproduce it on the JSFiddle. Take a look at the working sample, and the sample with error.
=-=-=- edited -=-=-=
The same concept should apply to the infobox plugin, as it is shown here.
Related
I've seen other questions related to this and none of the solutions I saw seemed to help. Maybe I'm just overlooking something.
Any help would be appreciated.
I have a map that I'm loading upwards of 1000 markers. When a user performs a mouseover on the marker, I need the infowindow to display for that marker where the marker is.
The issue I'm having is that the same infowindow appears over the same marker no matter which marker I mouseover.
I provided a screenshot below that shows the map with the markers and an infowindow. So, no matter which marker I mouseover, that same infowindow is shown.
This is the code (gm is an instantiated google.maps object):
for (var i = 0; i < opts.LocationsData.length; i ++) {
var datum = opts.LocationsData[i];
var icon = new gm.MarkerImage(datum.map_pin_loc + datum.map_marker + '.svg',null, null, null, new google.maps.Size(31,51));
var loc = new gm.LatLng(datum.latitude, datum.longitude);
var zi = 500;
if(i>9)
{
datum.map_pin_icon = datum.map_pin_loc + 'dot1.svg';
icon = new gm.MarkerImage(datum.map_pin_icon,null, null, null, new google.maps.Size(8,8));
zi=450;
}
var marker = new gm.Marker({
position: loc,
/** title: datum.title != '' ? datum.title : datum.description, **/
icon: icon,
zIndex: zi,
map: map
});
marker.type = 'point';
marker.post_id = datum.pin_id;
marker.scrollAndAnimate = true;
/** (these are used elsewhere in my code for marker management and other purposes) **/
markers.push(marker);
markersLatLngObjs.push(loc);
var infowindow = new gm.InfoWindow({
content: '<strong>' + (datum.title != '' ? datum.title : datum.description) + '</strong>'
});
gm.event.addListener(marker, 'mouseover', function() {
infowindow.open(map,marker);
});
}
The pb is that the mouseover event handler is a closure referencing variables which are unique in the context of the calling function. Better move this part outside the loop to see clearer.
For example you can define a function such as :
function showInfo() {
// called in the context of a marker
var datum = opts.LocationsData[this.placeIndex];
var infowindow = new gm.InfoWindow({
content: '<strong>' + (datum.title != '' ? datum.title : datum.description) + '</strong>'
});
infowindow.open(map, this);
}
just before your loop, then tag the markers with a property placeIndex (for example) in your loop :
marker.placeIndex = i;
and finally bind the handler with :
gm.event.addListener(marker, 'mouseover', showInfo);
Edit: oops, my bad, forgot about the other references, same pb. You can probably replace the marker by 'this' within the handler. I updated the code.
UPDATE
I have added the error up here as its makes it easier to read. Below is the error I now get with that update. P.S it should be InfoBox and not Infobox, I think I made that error somewhere when I typed it up :). So where am I going wrong now? I am not even sure what this error message is saying :
Uncaught TypeError: Cannot read property 'style' of null
InfoBox.setBoxStyle_
InfoBox.setOptions
(anonymous function) PAGE.php:101
N.trigger main.js:23
xK.(anonymous function).e
(anonymous function)
N.trigger main.js:23
F.ie
F.sm
(anonymous function) main.js:11
N.trigger main.js:23
F.Jk
(anonymous function)
OLD POST
I have a custom Google Maps V3 with custom markers being generated with a XML file that is built with a custom DB. I have posted my code below, this all works, only thing is I have now built in the Infobox plugin, which gives me more control over the styling of the marker styles. However they, unlike the Google InfoWindow does not close automatically when another marker is clicked.
This is my load function, which sets the map and build the marker with my XML file,
function load() {
var map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(54.500, 355.000),
zoom: 5,
mapTypeId: 'roadmap'
});
downloadUrl("genxml.php?id=<?php echo $VarToUse ?>",function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name");
var number = markers[i].getAttribute("number");
var address = markers[i].getAttribute("address");
var type = markers[i].getAttribute("type");
var point = new google.maps.LatLng(parseFloat(markers[i].getAttribute("lat")),parseFloat(markers[i].getAttribute("lng")));
var myOptions = {
content: "<b class=\"infoBox_links\">" + name + "</b> <br/>" + address
,disableAutoPan: false
,maxWidth: 0
,pixelOffset: new google.maps.Size(-90, -125)
,zIndex: null
,boxStyle: {
background: "#FFFFFF",
border: "1px solid grey",
width: "170px",
height: "70px",
padding: "8px",
fontSize: "12px",
overflow: "hidden"
}
,closeBoxMargin: "-5px"
,closeBoxURL: "imgs/x_google.png"
,isHidden: false
,pane: "floatPane"
,enableEventPropagation: false
};
var icon = customIcons[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon.icon
});
bindInfoWindow(marker, map, myOptions); //function call to set the markers!
}
});
} //End of function load()
As you can see I have a function that is called within the load, this is my current code, which works fine
function bindInfoWindow(marker, map, myOptions) {
google.maps.event.addListener(marker, 'click', function() {
var ib = new InfoBox(myOptions);
ib.open(map, marker);
});
} //End of bindInfoWindow function!!
This works, custom info boxes with the styles I need are generated, however the current 'open' info box does not close when a new marker is click. And from a number of different attempts and ideas from other people, I am currently working with :
function bindInfoWindow(marker, map, myOptions) {
var ibs = [];
var closeInfoBox = function() {
for (var i in ibs) {
ibs[i].close();
}
}
var ibIndex = ibs.push(new Infobox()) - 1,
ib = ibs[ibIndex];
google.maps.event.addListener(marker, 'click', function() {
closeInfoBox();
ib.setOptions(myOptions);
//var ib = new InfoBox(myOptions);
ib.open(map, marker);
});
}
This code come from Opening only a infobox at a time when multiple markers are displayed on the map
However this only gives me errors, either I have not copied this code right or my set up for the maps different enough for this code not to work (with I don't think is the case). I think it is something I am not doing right. Right now as the code stands, its this line that does not want to work,
var ibIndex = ibs.push(new Infobox()) - 1,
Comes back in the console log with
Uncaught ReferenceError: Infobox is not defined PAGE.php:101
bindInfoWindow PAGE.php:101
(anonymous function) PAGE.php:84
request.onreadystatechange
All ideas most welcome,
Many thanks
Glenn.
Try this. You need the array and closeInfoBox specified outside of the load function, otherwise you just keep resetting the array every time.
var ibs = [];
function closeInfoBox() {
for (var i in ibs) {
ibs[i].close();
}
}
And then you need to push the infobox into the array within the bind function:
function bindInfoWindow(marker, map, myOptions) {
var ib = new Infobox(myOptions);
ibs.push(ib);
google.maps.event.addListener(marker, 'click', function() {
closeInfoBox();
ib.open(map, marker);
});
}
I haven't tested this, but it's similar to what I've done in my code at various points.
However they, unlike the Google InfoWindow does not close automatically when another marker is clicked
This is new to me, a google.maps.InfoWindow will never be closed automatically .
When you only want to have a single InfoBox open use only a single InfoBox-instance for all markers:
function bindInfoWindow(marker, map, myOptions) {
google.maps.event.addListener(marker, 'click', function() {
//create a Infobox that will be used by each marker
if(!this.getMap().get('ib')){this.getMap().set('ib',new InfoBox());}
var ib = this.getMap().get('ib');
ib.setOptions(myOptions);
ib.open(this.getMap(),this);
});
}
I have a map that uses infoBubble.js.
In this map there is an array of locations that I iterate through.
The infoBubble should pop up when the custom icon is clicked but for some reason it only ever opens up the first data item.
Does anyone have an idea as to why that may happen?
I have developed the code for it here;
var arrMarkers = [
['Santiago de Cuba', 20.040450354169483, -75.8331298828125],
['Las Tunas', 20.97682772467435, -76.9482421875],
['Camaguey', 21.39681937408218, -77.9205322265625],
['Playa Santa Lucia', 21.555284406923192, -77.0526123046875],
['Santa Clara', 22.421184710331854, -79.9639892578125],
['Cienfuegos', 22.161970614367977, -80.4473876953125],
['Havana', 23.12520549860231, -82.3919677734375],
['San Cristobel', 22.730590425493833, -83.045654296875],
['Pinar del Rio', 22.43641760076311, -83.69384765625]
];
var arrInfoWindowsCuba = [];
var arrInfoWindows = [];
arrMarkers[i] = marker;
function init() {
var mapCenter = new google.maps.LatLng(21.616579336740603, -78.892822265625);
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 7,
center: mapCenter,
mapTypeId: google.maps.MapTypeId.TERRAIN
});
var image = '/wp-content/themes/Shootcuba/images/map-icon.png';
for (i = 0; i < arrMarkers.length; i++) {
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(arrMarkers[i][1], arrMarkers[i][2]),
icon: image
});
var infoBubble = new InfoBubble({
content: '<div class="phoneytext">' + arrMarkers[i][0] + '<div class="left-col2"></div></div>',
boxClass: 'info-box',
alignBottom: true,
pixelOffset: new google.maps.Size(-150, -40),
maxWidth: 300,
padding: 0,
closeBoxMargin: '0px',
borderColor: '#ffffff',
borderRadius: '0',
maxWidth: 535,
disableAutoPan: false,
hideCloseButton: false,
backgroundClassName: 'phoney'
});
google.maps.event.addListener(marker, 'click', function () {
infoBubble.open(map, marker, i);
console.log(arrMarkers);
});
arrMarkers[i] = marker;
arrInfoWindowsCuba[i] = infoBubble;
}
}
Here's a working example. I took out a few of the arrays you had (I wasn't entirely sure what they were all for, and they were causing errors in just the snippet you posted), but otherwise is pretty true to what you were doing. The big difference is that I made a separate function for creating the markers. This was mainly done to keep the scope of the click events separate from one another, since the click event always triggering the last event indicates to me that the scopes aren't properly separate.
In particular, what I believe was happening is that the event function you kept overriding values to marker and infoBubble, and the event listener would refer to the current values of those variables, not the values when you first attach the listener. Making a separate function call to maintain the scope for the events strikes me as the cleanest solution.
My website has a number of pages that show a Google map with a bunch of markers, here's an example.
As you can see, the maps take a long time to load and I'm looking for ways to improve this. I was hoping to use GeoWebCache to cache the map tiles on the server, but I was informed that this would violate the terms of use for Google maps.
The code that I use to display a map and add a marker is appended below. It's a pretty straightforward usage of the Google Maps V3 JavaScript API, so I don't think there's much scope for optimizing it. Are there any obvious steps I could take to reduce the map-loading time?
SF.Map = function(elementId, zoomLevel, center, baseImageDir) {
this._baseImageDir = baseImageDir;
var focalPoint = new google.maps.LatLng(center.latitude, center.longitude);
var mapOptions = {
streetViewControl: false,
zoom: zoomLevel,
center: focalPoint,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: false
};
this._map = new google.maps.Map(document.getElementById(elementId), mapOptions);
this._shadow = this._getMarkerImage('shadow.png');
};
SF.Map.prototype._getMarkerImage = function(imageFile) {
return new google.maps.MarkerImage(this._baseImageDir + '/map/' + imageFile);
};
SF.Map.prototype._addField = function(label, value) {
return "<span class='mapField'><span class='mapLabel'>" + label + ": </span><span class='mapValue'>" + value + "</span></span>";
};
/**
* Add a marker to the map
* #param festivalData Defines where the marker should be placed, the icon that should be used, etc.
* #param openOnClick
*/
SF.Map.prototype.addMarker = function(festivalData, openOnClick) {
var map = this._map;
var markerFile = festivalData.markerImage;
var marker = new google.maps.Marker({
position: new google.maps.LatLng(festivalData.latitude, festivalData.longitude),
map: map,
title: festivalData.name,
shadow: this._shadow,
animation: google.maps.Animation.DROP,
icon: this._getMarkerImage(markerFile)
});
var bubbleContent = "<a class='festivalName' href='" + festivalData.url + "'>" + festivalData.name + "</a><br/>";
var startDate = festivalData.start;
var endDate = festivalData.end;
if (startDate == endDate) {
bubbleContent += this._addField("Date", startDate);
} else {
bubbleContent += this._addField("Start Date", startDate) + "<br/>";
bubbleContent += this._addField("End Date", endDate);
}
// InfoBubble example page http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobubble/examples/example.html
var infoBubble = new InfoBubble({
map: map,
content: bubbleContent,
shadowStyle: 1,
padding: 10,
borderRadius: 8,
borderWidth: 1,
borderColor: '#2c2c2c',
disableAutoPan: true,
hideCloseButton: false,
arrowSize: 0,
arrowPosition: 50,
arrowStyle: 0
});
var mapEvents = google.maps.event;
// either open on click or open/close on mouse over/out
if (openOnClick) {
var showPopup = function() {
if (!infoBubble.isOpen()) {
infoBubble.open(map, marker);
}
};
mapEvents.addListener(marker, 'click', showPopup);
} else {
mapEvents.addListener(marker, 'mouseover', function() {
infoBubble.open(map, marker);
});
mapEvents.addListener(marker, 'mouseout', function() {
infoBubble.close();
});
}
};
You could try "lazy loading" the google map, something like this:
var script=document.createElement("script");
script.type="text/javascript";
script.async=true;
script.src="http://maps.google.com/maps/api/js?sensor=false&callback=handleApiReady";
document.body.appendChild(script);
Or even like this is how I go it for Facebook AIP so that this doesn't slow down the initial load time.
$.getScript('http://connect.facebook.net/en_US/all.js#xfbml=1', function() {
FB.init({appId: opt.facebook_id, status: true, cookie: true, xfbml: true});
});
Example: http://blog.rotacoo.com/lazy-loading-instances-of-the-google-maps-api
Also looking at your HTML you have a lot of JS which should be in an external JS file and not inline, can you not pass a array instead of having a lot of duplicate inline code.
One option is to take a static snapshot and create the map behind it. once map is fully loaded, replace the dynamic one with the static map.
I also suggest that you take a look at:
https://developers.google.com/maps/documentation/staticmaps/
it might be that you can provide a simpler solution to your site without using the full dynamic maps api.
I'm trying to write a function, that gives a lat & long, a name and a picture as formal parameters, so a marker on the map will display when clicked: the name and picture.
It seems to work, though when I add multiple Markers, the actual parameters of the last call are passed to all. And so every Marker I click, will pop up the same name and picture.
I have no clue what I'm doing wrong here, cause I thought that I scoped everything right.
here is some part of my code
in my Initialise() function, I declared the following:
var marker = add_marker(51.21904,4.32659000000001,"Iggy Jensen","bro.jpg");
fluster.addMarker(marker);
var marker = add_marker(51.20367,4.341480000000047,"John Doe","bro.jpg");
fluster.addMarker(marker);
var marker = add_marker(51.2041539954234,4.327017528991746,"Joske Vermeulen","bro.jpg");
fluster.addMarker(marker);
The function add_marker is written by myself addMarker is a part of Fluster2 a cluster management system that I use.
function add_marker(lat,lng,name,pic) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,lng),
map: map,
icon: 'icon.png',
title: name
});
infoBubble = new InfoBubble({
maxWidth: 300,
backgroundColor: '#dedddd',
borderWidth: 2,
borderColor: 'rgb(68, 68, 68)'
});
var contentString = '<div id="content">'+
'<h2>'+name+'</h2>'+
'<p><span class="myLabel" style="margin-right:10px">Age </span>21</p>'+
'<p><center><img src="'+pic+'" class="bro_image"></center> </p>'+
'</div>';
var div = document.createElement('DIV');
div.innerHTML = 'No pictures uploaded by this user.';
infoBubble.addTab('Personal', contentString);
infoBubble.addTab('Pictures', div);
google.maps.event.addListener(marker, 'click', function() {
if (!infoBubble.isOpen()) {
infoBubble.open(map, marker);
}
});
return marker;
}
function addTab() {
var title = document.getElementById('tab-title').value;
var content = document.getElementById('tab-content').value;
if (title != '' && content != '') {
infoBubble.addTab(title, content);
}
}
Any help is appreciated! Thanks in advance!
Just add 'var' before infoBubble definition, otherwise everytime you are assigning a new InfoBubble object to the same global variable:
var infoBubble = new InfoBubble({
// ^---------here it is