Resposive Google Maps javascript api turns out grey (sometimes) - wordpress

I have two websites which attempt to display a map of bushfires in an area, using the Google Maps javascript api and a GeoJson from the NSW RFS. Both are resposive sites.
The maps seem very twitchy about displaying the actual map background, and in one case I always get a grey background (though markers etc are properly displayed).
This seems to be related to the way the map canvas is sized; if a fixed width and height are set then all is well, but if % are used grey is displayed. In the one case setting width and height in vw (% of viewport width) works, but in the other it does not.
The site that works is http://lansdowne.rfsa.org.au/firemap.php
the one that does not is http://www.upperlansdownehall.org.au/firemap/ - if you zoon out to a larger area ytou will see that markers appear in both maps.
The major difference is that one is Wordpress, with the javascript enqueued with the footer, while the other is imbedded in the html.
I have tried setting the size (width and height) of the map-canvas in js (or that of an enclosing division) using the following code either in the initilize routine or just before the addDomListener(window, 'load', initialize);
var mw = document.getElementById('map-canvasout').offsetWidth;
var mw = document.documentElement.clientWidth * .5;
var mh = mw * .75;
var mhx = mh + "px";
var mapara = document.getElementById('map-canvasout');
mapara.style.height= mhx;
I would be very grateful for any ideas, as I am out of them. code for the wordpress scripts encode and js follows:-
add_action('wp_enqueue_scripts', 'ulmh_googlemaps', 105);
function ulmh_googlemaps(){
if (is_page('32') || is_page('233')) {
wp_register_script( 'gmap', 'https://maps.googleapis.com/maps/api/js?key=AIzaSyBAlriyR-tmJU4jrd0z9nmWEmw4XSS0nC0',true);
wp_register_script( 'ulmh_gmap', plugins_url( 'firemap.js', __FILE__ ),true);
wp_enqueue_script('gmap');
wp_enqueue_script('ulmh_gmap');
}
}
function initialize() {
var lat = -31.71 ;
var lng = 152.47;
var zom = 12;
var nam = "Upper Lansdowne";
var mapOptions = {
center: { lat: lat, lng: lng},
zoom: zom
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
map.data.loadGeoJson('http://www.upperlansdownehall.org.au/wp-content/uploads/majorIncidents.json');
map.data.setStyle(function(feature) {
var IconBase = 'http://www.rfs.nsw.gov.au/_designs/geojson/fires-near-me/images/';
var image = {
url: IconBase + 'watch-and-act.png',
size: new google.maps.Size(27, 27),
origin: new google.maps.Point(0,0),
anchor: new google.maps.Point(14, 13)
};
var ctg = feature.getProperty('category');
switch (ctg) {
case "Emergency Warning": image.url = IconBase + 'emergency-warning.png'; break;
case "Watch and Act": image.url = IconBase + 'watch-and-act.png'; break;
case "Advice": image.url = IconBase + 'advice.png'; break;
default: image.url = IconBase + 'not-applicable.png';
}
return {
icon: image
};
});
var infowindow = new google.maps.InfoWindow();
map.data.addListener('click', function(event) {
var ef = event.feature;
var myHTML = '<b>'+ef.getProperty("title") + '</b></br>' + ef.getProperty("description");
infowindow.setContent("<div style='width:250px;'>"+myHTML+"</div>");
infowindow.setPosition(event.latLng);
infowindow.setOptions({pixelOffset: new google.maps.Size(0,0)});
infowindow.open(map);
});
nam = 'Fire Map of the ' + nam + ' Area';
lat = Math.round(lat*10000)/10000;
lng = Math.round(lng*10000)/10000;
google.maps.event.addListener(map, 'idle', function() { // 'bounds_changed'
google.maps.event.trigger(map, 'resize');
var mapbnd = map.getBounds();
var nbrfre = 0;
map.data.forEach(function(feature) {
var geo = feature.getGeometry();
if (geo.getType() == 'Point') {
var LatLng = geo.get();
if (mapbnd.contains(LatLng)) {
nbrfre = nbrfre +1;
}
} else if (geo.getType() == 'GeometryCollection') {
var LatLng = geo.getAt(0).get();
console.log(LatLng);
if (mapbnd.contains(LatLng)) {
nbrfre = nbrfre +1;
}
}
});
var fretxt = ' (No Fires)';
if (nbrfre == 1) {
fretxt = ' (1 Fire)';
} else if (nbrfre > 1) {
fretxt = ' (' + nbrfre + ' Fires)';
}
var ctr = map.getCenter();
clt = Math.round(ctr.lat()*10000)/10000;
cln = Math.round(ctr.lng()*10000)/10000;
if ((clt != lat) || (cln != lng) ||(zom != map.getZoom())) {
nn = 'General Fire Map';
} else {
nn = nam;
}
var pstttl = document.getElementsByClassName("posttitle");
pstttl[0].innerHTML = nn + fretxt;
if (nbrfre != 0) {
pstttl[0].style.backgroundColor='red';
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);

Well it seems my unconscious is better at this than the rest of me, as I woke up this morning with a partial answer. One site was using the experimental version of Google Maps (by default) while the other specified v=3 and therefore got the release version.
Of course that raises the question of what is happening at Googles end, but I’ll chase that up with them.
Thanks to anyone who looked at the question.

Related

Markercluster Doubling Markers

For some reason, Markercluster is doubling the markers in a group. For example, when I click on a group I see four individual markers instead of two. The names are duplicated too. I looked through other posts but am still confused by this. Thanks!
<script>
var mapData = <?php echo wp_json_encode($mapData); ?>;
var map = L.map('map').setView([40, 0], 2);
var markers = new L.MarkerClusterGroup();
L.mapbox.accessToken = 'myToken';
var geocoder = L.mapbox.geocoder('mapbox.places');
for ( var i = 0; i < mapData.length; i++ )
{
geocoder.query(mapData[i].city, showLoc);
}
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=myToken', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(map);
function showLoc (err, data) {
var city = data.results.query.join(' ');
for ( var i = 0; i < mapData.length; i++ )
{
if ( mapData[i].city.toLowerCase() === city ) {
var marker = L.marker(new L.LatLng(data.latlng[0], data.latlng[1]), {
icon: L.mapbox.marker.icon({'marker-color': 'c70c2b'}),
title: mapData[i].name
});
//new L.Marker([data.latlng[0], data.latlng[1]], 2)
marker.bindPopup("<strong>" + mapData[i].name + "</strong>")
markers.addLayer(marker);
}
}
markers.addTo(map);
}
Think I figured it out. Very simple fix. Had to move var markers = new L.MarkerClusterGroup(); in my showLoc (err, data) function. I think it has to do with declaring it after the map tiles load. Not sure though.

Can't get Google Maps api v3 to display markers from xml file

I should have on my hands what is proper working JS and an xml file...I'm simply trying to take advantage of the huge database of locations that has been offered up as free for everyone to use - located # http://www.craftbeer.com/breweries/brewery-locator/find-a-us-brewery
I'm tried using their maps.js and xml file...but all I end up with is a blank maps screen...
Here is the Javascript...
/*********************************************
**Google Maps Custom API work**
This code can be reused on any site to display a local map of breweries from our local iMis dump, as well as pull in beermapping.
Hey! Don't forget to include API in functions.php! Function is conditionally initialized in footer.php
*/
//Set up variables to create marker
var gmarkers = [];
var mapMarkers = [];
var geocoder = new google.maps.Geocoder();
var icon = 'http://www.craftbeer.com/wp-content/uploads/marker.png';
//Initialize Map
function view_map(xml_file, latitude, longitude, varZoom) {
console.log('view map');
map = new google.maps.Map(document.getElementById("map_canvas"), { //Create the map, Set Default Zoom level and type
center: new google.maps.LatLng(latitude, longitude),
zoom: varZoom,
mapTypeId: 'roadmap',
panControl: true,
zoomControl: true,
mapTypeControl: false,
scaleControl: true,
streetViewControl: false,
overviewMapControl: false
});
//-- Listeners --//
google.maps.event.addListener(map, 'center_changed', function() {
console.log('center changed');
//clearMarkers();
});
google.maps.event.addListenerOnce(map, 'tilesloaded', function(){
//this part runs when the mapobject is created and rendered
console.log("loaded");
$("#loading-screen").fadeOut(250, function(){});
$("#loading-icon").fadeOut();
//google.maps.event.addListenerOnce(map, 'tilesloaded', function(){ });
});
//console.log(xml_file);
var download_file = xml_file; //this variable is passed in so we can re-use this script
//Pull in the XML feed
downloadUrl(download_file, function(data) {
console.log("downloading xml");
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
//Loop through all markers in the XML file
for (var i = 0; i < markers.length; i++) {
var state = markers[i].getAttribute("state");
var x = markers[i].getAttribute("lat");
var y = markers[i].getAttribute("lng");
if ( state != 'PR' && state != 'VI' && state != 'GU' && x != "" ){
//console.log(state);
var ids = parseFloat(markers[i].getAttribute("id"));
var z = new google.maps.LatLng(x,y,i);
//console.log(x);
var _id = markers[i].getAttribute("id");
var name = markers[i].getAttribute("company");
var address = markers[i].getAttribute("address");
var city = markers[i].getAttribute("city");
var zip = markers[i].getAttribute("zip");
var phone = markers[i].getAttribute("phone");
var url = markers[i].getAttribute("url");
var brewery_type = markers[i].getAttribute("type");
var member_type = '';
var member_type = markers[i].getAttribute("member_type");
var offer = markers[i].getAttribute("offer");
var html = "<div class='bubble_content'><strong>" + name + "</strong><br />";
html += address + "<br/>" + city + ", " + state + " " + zip;
if(url) html += "<br /><br /><a href='http://" + url + "' target='_blank'>Visit Web Site</a></div>";
//var marker = createMarker(ids, z, title, contentstring);
var marker = new google.maps.Marker({
position: z,
map: map,
title: name,
icon: icon,
html: html,
zindex: i
});
//Add a listener for every icon click
google.maps.event.addListener(marker,'click',function(){
infowindow.setContent(this.html);
infowindow.open(map,this);
//map.setZoom(10);
//map.setCenter(this.getPosition());
console.log(this);
});
gmarkers[ids] = marker;
mapMarkers.push(marker);
if( x && y ){
//console.log(ids);
var infowindow = new google.maps.InfoWindow({content: html});
}
/* google.maps.event.addListener(marker, 'click', function() {
console.log('marker clicked');
});
*/
//bounds.extend(z);
//map.fitBounds(bounds);
}//end check for US states only!
} //end for loop
var mcOptions = {gridSize: 60, maxZoom: 9};
var markerCluster = new MarkerClusterer(map, mapMarkers, mcOptions); //this is the function that groups the icons into markers
});
} //End full function to create map
/*
* FUNCTION
*
* click to bring up one icon when clicked from the list.
*/
function myclick(i){
console.log('clicked a title ' + i);
smoothScroll("#primary");
var lat = parseFloat(gmarkers[i].position.k);
var lng = parseFloat(gmarkers[i].position.B);
console.log(lat);
map.setCenter({lat: lat, lng: lng});
map.setZoom(13);
google.maps.event.trigger(gmarkers[i], 'click');
};
function createMarker(ids, z, title, contentstring){
console.log('createMarker');
var marker = new google.maps.Marker({
position: z,
map: map,
title: title,
html: contentstring,
icon: 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png'
});
google.maps.event.addListener(marker,'click',function(){
infowindow.setContent(this.html);
infowindow.open(map,marker);
});
gmarkers[ids] = marker;
//console.log(gmarkers[ids]);
};
/*
* FUNCTION findAddress()
*
* given an adress string, zoom the map to the proper state
*/
function findAddress(position) {
//Let's determind if we have a state (address) or LatLng
var addressStr = $("#state_select li.active").data('state-id');
if (addressStr != 'Select a State') address = "US State of "+addressStr;
if(position) {
var lat = parseFloat(position['latitude']);
var lng = parseFloat(position['longitude']);
var latlng = new google.maps.LatLng(lat, lng);
//console.log(latlng);
}
//Now let's geocode - two different cases
if (geocoder && position) { //If LatLng
//console.log('near me');
geocoder.geocode( { 'location': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
if (results && results[0] && results[0].geometry && results[0].geometry.viewport && addressStr!="ON" && addressStr!="INT") {
map.fitBounds(results[0].geometry.viewport); //resize map to fit.
map.setZoom(13);
}
} else {
alert("No results found");
}
}
});
} else if (geocoder && address!="") { //If State
//console.log('by state');
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
if (results && results[0] && results[0].geometry && results[0].geometry.viewport && addressStr!="ON" && addressStr!="INT") {
map.fitBounds(results[0].geometry.viewport); //resize map to fit.
map.setZoom(6);
}
} else {
alert("No results found");
}
}
});
} else {
//alert("Geocode was not successful for the following reason: " + status);
}
}
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() {}
And here is the link to the xml file....
http://www.straighttothepint.com/wp-content/uploads/wp-google-maps/Google_Map_APIs.xml
I've spent days doing google searches and testing different sections of code to at least get a basic google map to show up via the xml file markers...but to no avail - Any help would be tremendously appreciated!!
~Cheers
EDIT:
Everything worked as expected once I included the following script inline on the page prior to calling the maps.js file. Thanks everyone!
<script>
$(document).ready(function(){
var latitude = 39.300299;
var longitude = -97.382812;
view_map('./uploads/your_xml_file.xml', latitude,longitude,4);
//scripts to handle mapping are in js/mylibs/map.js.php
});
</script>
Looking at the html and the code you provided above I constructed a fiddle for you:
http://jsfiddle.net/loanburger/qafsex5x/
I added two markers in an xml string at the top in the fiddle.
I basically parse the xml doing this:
var markers = $(xml).find("marker");
Its then simply the same for loop you had:
for (var i = 0; i < markers.length; i++)
{
...
}
The fiddle will show you the markers.

How to populate sidebar information with infowindow data?

I have a fully-functioning Google Maps V3 map that works fine the way it is. However, I dislike InfoWindows because they take up too much map space when displaying the info. My solution around that is to place information in a sidebar to the right of the map. The information inside the InfoWindow would be transferred to a in that sidebar using an event to first clear existing data and then repopulate it with the current data.
I'm not sure how to take data from inside the map and bring it outside, nor how to use an event inside to move that that data outside on a 'click'.
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP file
downloadUrl("tests/cfdstationsxml.php", 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 address = markers[i].getAttribute("address");
var city = markers[i].getAttribute("city");
var state = markers[i].getAttribute("state");
var zip = markers[i].getAttribute("zip");
var engine = markers[i].getAttribute("engine");
var truck = markers[i].getAttribute("truck");
var ambulance = markers[i].getAttribute("ambulance");
var special_units = markers[i].getAttribute("special_units");
var battalion = markers[i].getAttribute("battalion");
var district = markers[i].getAttribute("district");
var office = markers[i].getAttribute("office");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var html = "<div id='info' style='overflow:hidden;line-height:15px;color:black;height:200px;width:225px;'><span style='font-weight:500;text-decoration:underline;font-size:13px;'>" + name + "</span><br><span style='font-size:10px;'>" + address + "<br>" + city + ", " + state + " " + zip + "</span><br><table style='color:black;font-size:12;'><tr><td>Engine:</td><td>" + engine + "</td></tr><tr><td>Truck:</td><td>" + truck + "</td></tr><tr><td>Ambulance:</td><td>" + ambulance + "</td></tr><tr><td>Special Units:</td><td>" + special_units + "</td></tr><tr><td>Battalion:</td><td>" + battalion + "</td></tr><tr><td>District:</td><td>" + district + "</td><tr><td>Office:</td><td>" + office + "</td></tr></tr></table></div>";
var icon = 'http://www.radioman911.com/images/9px_marker.png'; // anywhere from 3px_marker.png to 8px_marker.png
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon,
title: name,
});
bindInfoWindow(marker, map, infoWindow, html);
}
});
}
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
$("#info").appendTo("#sidebar");
//infoWindow.setContent(lmth);
infoWindow.open(map, marker);
});
}
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() {}
ANY help at all would be much appreciated - this has been driving me nuts on and off for a month!!
Tim
This should work for the correct value of 'id of your sidebar div';
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
document.getElementById('id of your sidebar div').innerHTML = html;
});
}
working example

Google Maps changing a marker back to its original image

A wee bit out of my depth here, I hope someone can help me resolve this...
I have a Google map which loads data from an array and also populates a sidebar list of the items.
A click on the sidebar item opens the corresponding infowindow as expected o.k.
When I mouseenter a sidebar item it pans to if necessary and highlights the corresponding marker (and closes any infowindow currently open ).
(.locs is the sidebar container, .loc is an item)
$(document).on("mouseenter",".loc",function() {
var thisloc = $(this).data("locid");
for(var i=0; i<markers.length; i++) {
if(markers[i].locid == thisloc) { //get the latlong
if(lastinfowindow instanceof google.maps.InfoWindow) lastinfowindow.close();
map.panTo(markers[i].getPosition());
markers[i].setIcon('../mapIcons/mini-white.png');
}
}
});
This bit works fine as I'm just setting a fixed image.
However, when I mouseleave the marker fails to revert back to its original state.
If I use the setIcon for a specic image it works fine, but I want to refer back to the original icon from the dataset item.
markers[i].setIcon("currmark");
currmark is the var I used to hold the original icon.
$(document).on("mouseleave",".loc",function() {
var thisloc = $(this).data("locid");
var currmark = getIcon("mapData.type");
for(var i=0; i<markers.length; i++) {
if(markers[i].locid == thisloc) { //get the latlong
map.panTo(markers[i].getPosition());
markers[i].setIcon("currmark");
}
}
});
An alert set on 'currmark', the var I used to hold the original icon, shows only the last icon set by the mouseenter setIcon.
This seems to idicate to me that the original icon from the dataset (mapdata.type) has been forgotten / replaced by the last setting applied to markers[i].
I think I need to reaccess the dataset to remind the var of the original state when I set
var currmark = getIcon("mapData.type");
Some added info....
I'm using a utility function that translates a given 'type' in the dataset to an icon, hence the getIcon(type) function.
function getIcon(type) {
switch(type) {
case "bar": return "../mapIcons/mini-blue.png";
case "restaurant": return "../mapIcons/mini-red.png";
case "cafe": return "../mapIcons/mini-yellow.png";
default: return "../mapIcons/mini-white.png";
}
}
An example of a data entry...
var data = [
{address:'Rua Calheta',detail:'Restaurant',title:'Dolphin',type:'restaurant',ico:'red',lat:"37.08570947136275",long:"-8.731633722782135"}
];
I hope I've explained this half sensibly. Can anyone assist me, as I was dead chuffed I'd got this far.
2nd Additional Info for Beetroot showing how my marker and sidebar are initially setup....
data.forEach(function(mapData,idx) {
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(mapData.lat,mapData.long),
title: mapData.title,
icon: getIcon(mapData.type)
});
var link=('<a href="#"' + mapData.title +'">');
var contentHtml = "<div id='iw' class='iw2'><h3>" + link + mapData.title+"</a></h3>" + mapData.detail+"<br>"+mapData.address+"</div>";
var infowindow = new google.maps.InfoWindow({
content: contentHtml
});
google.maps.event.addListener(marker, 'click', function() {
if(lastinfowindow instanceof google.maps.InfoWindow) lastinfowindow.close();
marker.infowindow.open(map, marker);
lastinfowindow = marker.infowindow;
});
marker.locid = idx+1;
marker.infowindow = infowindow;
markers[markers.length] = marker;
var spot=('<img src="' + (getIcon(mapData.type)) + '" />');
var sideHtml = '<p class="loc" data-locid="'+marker.locid+'">'+spot+mapData.title+'</p>';
$("#locs").append(sideHtml);
if(markers.length == data.length) doFilter();
});
EDIT 02/07
The complete source after incorporating Beetroot-Beetroot's slick changes. Here in its entirety as I'm now vary aware that he can only help if he has the whole picture!
Now attempting to debug after learning I'm not such a smartass.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false& style=feature:all|element:labels|visibility:off">
</script>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">
var map;
var markers = [];
var lastinfowindow;
var locIndex;
//Credit: MDN
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope, this[i], i, this);
}
}
}
//my data ~ cutdown and local for testing
var data = [
{address:'Rua Calheta',detail:'Restaurant',title:'Dolphin',type:'restaurant',icotyp:'red',lat:"37.08570947136275",long:"-8.731633722782135"},
{address:'Rua Calheta',detail:'Cafe',title:'Cafe Calheta',type:'cafe',icotyp:'yellow',lat:"37.0858150589029",long:"-8.731550574302673"},
{address:'Rua Calheta',detail:'Bar',title:'Kellys',type:'bar',icotyp:'red',lat:"37.08583217639933",long:"-8.731239438056945"},
{address:'Rua 2nd Abril',detail:'Bar',title:'Godots',type:'bar',icotyp:'blue',lat:"37.08602046860496",long:"-8.731470108032226"}
];
// translate data type: to icon
function getIcon(type) {
switch(type) {
case "bar": return "../mapIcons/mini-blue.png";
case "restaurant": return "../mapIcons/mini-red.png";
case "cafe": return "../mapIcons/mini-yellow.png";
default: return "../mapIcons/mini-white.png";
}
}
function initialize() {
var latlng = new google.maps.LatLng(37.08597981464561, -8.730670809745788);
var myOptions = {
zoom: 18,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
// revised beetroot-beetroot 'loop' function to set markers and sidebar at the same time
var $locs = $("#locs");//Used repeatedly inside the loop.
$.each(data, function(idx, mapData) {
//Note: critical assignment of the new marker as a property of `mapData`.
mapData.marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(mapData.lat,mapData.long),
title: mapData.title,
icon: getIcon(mapData.type)
});
var link = '' + mapData.title + '';
var contentHtml = "<div id='iw' class='iw2'><h3>" + link + "</h3>" + mapData.detail + "<br>" + mapData.address + "</div>";
//What was `marker` must now be referred to as `mapData.marker`
mapData.marker.infowindow = new google.maps.InfoWindow({
content: contentHtml
});
google.maps.event.addListener(mapData.marker, 'click', function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
//`this` refers back to the clicked element; the appropriate marker
this.infowindow.open(map, this);
lastinfowindow = this.infowindow;
});
var spot = '<img src="' + (getIcon(mapData.type)) + '" />';
//Here, it's convenient to create what was `sideitem` as a jQuery object, so we can apply several jquery methods (without making an assignment).
$('<p class="loc" />')
.html(spot + mapData.title)
.appendTo($locs)
.data('mapData', mapData);//<<<<<<<< critical
});
doFilter(); //It should be possible to execute this statement when the loop is finished.
$(document).on("mouseenter", ".loc", function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
var mapData = $(this).data("mapData");
map.panTo(mapData.marker.getPosition());//<<<< direct reference to the marker avoids the need to loop.
mapData.marker.setIcon(getIcon(''));//get the default icon.
}).on("mouseleave", ".loc", function() {
var mapData = $(this).data("mapData");
mapData.marker.setIcon(getIcon(mapData.type));
}).on("click",".loc",function() {
var mapData = $(this).data("mapData");
mapData.marker.infowindow.open(map, mapData.marker);
lastinfowindow = mapData.marker.infowindow;
});
/*
Run on every change to any of the checkboxes
*/
function doFilter() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close(); //Close last info windows if still open and new filter applied
if(!locIndex) {
locIndex = {};
//I reverse index markers to figure out the position of loc to marker index
for(var x=0, len=markers.length; x<len; x++) {
locIndex[markers[x].locid] = x;
}
}
//what's checked?
var checked = $("input[type=checkbox]:checked");
var selTypes = [];
for(var i=0, len=checked.length; i<len; i++) {
selTypes.push($(checked[i]).val());
}
for(var i=0, len=data.length; i<len; i++) {
var sideDom = "p.loc[data-locid="+(i+1)+"]";
//Only hide if length != 0
if(checked.length !=0 && selTypes.indexOf(data[i].type) < 0) {
$(sideDom).hide();
markers[locIndex[i+1]].setVisible(false);
} else {
$(sideDom).show();
markers[locIndex[i+1]].setVisible(true);
}
}
}
$(document).on("click", "input[type=checkbox]", doFilter);
}
</script>
<style type="text/css">
#container {width:920px;height:500px; margin-left:auto;margin-right:auto;}
#map_canvas {width: 700px; height: 500px;float:left;border:1px gray solid;margin-right:10px;}
/* sidebar styling */
#locs {margin-top: 0px;padding-top: 0px;margin-left: 5px;height: 500px;width:200px;overflow-y: auto;overflow-x: hidden;}
#locs img {float:left;padding-right:5px;}
.loc {border: 0;width: 200px;padding: 2px;cursor: pointer;margin:0;text-transform:uppercase;font-family:Arial, Helvetica, sans-serif;font-size:0.90em;}
/* checkbox styling */
#form {margin-top: 0px;padding-top: 0px;height: 29px;}
.label {width: 32.5%;margin: 0;padding: 4px 0 4px 4px;display: inline-block;font-family: "Trebuchet MS", Verdana, Arial, sans-serif;text-transform: uppercase;font-size: 0.75em;font-weight: bold;}
.red {color:white;background-color:red;}
.yellow {color:yellow;background-color:black;}
.blue {color:white;background-color:blue;}
/* Map info styling */
#map_canvas div#iw {width:250px;height:65px;overflow:hidden;}
#map_canvas h3 {font-size:1em; margin:0; padding:3px;}
#map_canvas .iw2 a {text-decoration:none;border-bottom:thin blue dashed;}
#map_canvas .iw2 a:hover {text-decoration:none;border-bottom:thin red solid;}
</style>
</head>
<body onLoad="initialize()">
<div id="container">
<div id="map_canvas"></div> <!-- map //-->
<div id="locs"></div> <!-- sidebar //-->
<div id="form" style="margin:0;padding:0;border:thin gray solid;width:910px">
<span class="label blue"><input type="checkbox" name="bars" value="bar">Bars</span>
<span class="label yellow"><input type="checkbox" name="cafes" value="cafe">Cafes</span>
<span class="label red"><input type="checkbox" name="restaurants" value="restaurant">Restaurants</span>
</div>
</div> <!-- end of container //-->
</body>
</html>
EDIT 3 - 03/07 - Revised initialise marker / sidebar
// BB - revised each loop function to set markers and sidebar at the same time
var $locs = $("#locs");//Used repeatedly inside the loop.
$.each(data, function(idx, mapData) {
//BB - Note: critical assignment of the new marker as a property of `mapData`.
mapData.marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(mapData.lat,mapData.long),
title: mapData.title,
icon: getIcon(mapData.type)
});
var link = '' + mapData.title + '';
var contentHtml = "<div id='iw' class='iw2'><h3>" + link + "</h3>" + mapData.detail + "<br>" + mapData.address + "</div>";
//What was `marker` must now be referred to as `mapData.marker`
mapData.marker.infowindow = new google.maps.InfoWindow({
content: contentHtml
});
google.maps.event.addListener(mapData.marker, 'click', function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
//BB - `this` refers back to the clicked element; the appropriate marker
this.infowindow.open(map, this);
lastinfowindow = this.infowindow;
});
//BB - Here, it's convenient to create what was `sideitem` as a jQuery object, so we can apply several jquery methods (without making an assignment).
var spot = '<img src="' + (getIcon(mapData.type)) + '" />';
$('<p class="loc" />')
.html(spot + mapData.title)
.appendTo($locs)
.data('mapData', mapData);//<<<<<<<< critical
//BB - At the bottom of the $.each() loop in initialize(), create and populate one array per category, as properties of markers ://
if(!markers[mapData.type]) markers[mapData.type] = [];
markers[mapData.type].push(mapData.marker);
});
// End of for/each loop
EDIT 4 - 07/07 - Revised full script for comment
<script type="text/javascript">
var map;
//var markers = [];
//object, not array. BB
var markers = {};
var lastinfowindow;
//var locIndex;
//Credit: MDN
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope, this[i], i, this);
}
}
}
//my data ~ cutdown and local for testing
var data = [
{address:'Rua Calheta',detail:'South African & Portuguese Restaurant',title:'Dolphin',type:'restaurant',lat:"37.08570947136275",long:"-8.731633722782135"},
{address:'Rua Calheta',detail:'Poruguese Cafe / Bar',title:'Cafe Calheta',type:'cafe',lat:"37.0858150589029",long:"-8.731550574302673"},
{address:'Rua Calheta',detail:'English Bar',title:'Kellys',type:'bar',lat:"37.08583217639933",long:"-8.731239438056945"},
{address:'Rua 2nd Abril',detail:'English Bar',title:'Godots',type:'bar',lat:"37.08602046860496",long:"-8.731470108032226"},
{address:'Rua 2nd Abril',detail:'Chinese Restaurant',title:'Royal Garden',type:'restaurant',lat:"37.086164896968405",long:"-8.731738328933715"},
{address:'Rua 2nd Abril',detail:'English Bar',title:'Clives',type:'bar',lat:"37.086125",long:"-8.731374"},
{address:'Rua 2nd Abril',detail:'English Restaurant',title:'The Lime Tree',type:'restaurant',lat:"37.086125877750365",long:"-8.731588125228881"},
{address:'Praia da Luz',detail:'Portuguese Restaurant',title:'Alloro',type:'restaurant',lat:"37.09158",long:"-8.724850"},
{address:'Rua Calheta',detail:'English Cafe / Bistro',title:'Jakes',type:'cafe',lat:"37.0862601125538",long:"-8.732671737670898"},
{address:'Av dos Pescadores',detail:'English & Portuguese Restaurant',title:'Chaplins',type:'restaurant',lat:"37.08550480361006",long:"-8.730005621910095"},
{address:'Av dos Pescadores',detail:'English & Portuguese Restaurant',title:'Atlantico',type:'restaurant',lat:"37.085425634814705",long:"-8.729941248893737"},
{address:'Av dos Pescadores',detail:'Indian Restaurant',title:'Saffron',type:'restaurant',lat:"37.08534432623613",long:"-8.729884922504425"},
{address:'Av dos Pescadores',detail:'Indian Restaurant',title:'Pashmina',type:'restaurant',lat:"37.08526729697597",long:"-8.729839324951171"},
{address:'Rua Calheta',detail:'English Bar',title:'The Bull',type:'bar',lat:"37.085652442494",long:"-8.73089075088501"},
{address:'Av dos Pescadores',detail:'English & Portuguese Restaurant',title:'Galley',type:'restaurant',lat:"37.08571577732778",long:"-8.729227781295776"},
{address:'Av dos Pescadores',detail:'English & Portuguese Bar',title:'Carlos',type:'bar',lat:"37.0856306176238",long:"-8.729227781295776"}
];
// translate data.type: to icon
function getIcon(type) {
switch(type) {
case "bar": return "../mapIcons/mini-blue.png";
case "restaurant": return "../mapIcons/mini-red.png";
case "cafe": return "../mapIcons/mini-green.png";
default: return "../mapIcons/mini-white.png"; // used as current selection indicator
//default: return "../mapIcons/marker-yellow-dot.png"; // will use instead of white later
}
}
function initialize() {
var latlng = new google.maps.LatLng(37.08597981464561, -8.730670809745788);
var myOptions = {
zoom: 17,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),myOptions);
//-----------------------------------------------------------------------------------------
/*
Start of for/each loop
*/
var $locs = $("#locs");//Used repeatedly inside the loop.
$.each(data, function(idx, mapData) {
//BB - Note: critical assignment of the new marker as a property of `mapData`.
// section 1 - Marker construct
mapData.marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(mapData.lat,mapData.long),
title: mapData.title,
icon: getIcon(mapData.type)
});
// section 1 end
// section 2 - Infowindow construct
var link = '' + mapData.title + ''; // make a link of name
var contentHtml = "<div id='iw' class='iw2'><h3>" + link + "</h3>" + mapData.detail + "</div>"; // style info window and add detail
// What was `marker` must now be referred to as `mapData.marker`
mapData.marker.infowindow = new google.maps.InfoWindow({
content: contentHtml,
});
// section 2 end
// section 3 - Map marker click function
google.maps.event.addListener(mapData.marker, 'click', function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close(); // close any open infowindows
map.setZoom(18); // zoom in
map.setCenter(mapData.marker.getPosition());// centre on selection
//BB - `this` refers back to the clicked element; the appropriate marker
this.infowindow.open(map, this); // open infowindow
lastinfowindow = this.infowindow; // remember for closing this infowindow, if still open when selection changes
});
// section 3 end
// section 4 - Display Map marker and sidebar item
// BB - Here, it's convenient to create what was `sideitem` as a jQuery object, so we can apply several jquery methods (without making an assignment).
var spot = '<img src="' + (getIcon(mapData.type)) + '" />'; // sidebar copy of marker for display
$('<p class="loc" />')
.html(spot + mapData.title) // sidebar icon and name
.appendTo($locs) // add to sidebar container
.data('mapData', mapData); //<<<<<<<< critical
// BB Remove non matching from sidebar
marker.loc = $('<p class="loc" />').addClass(mapData.type).html(spot + mapData.title).data('marker', {m:marker, type:mapData.type}).appendTo($locs).get(0);
// BB - At the bottom of the $.each() loop in initialize(), create and populate one array per category, as properties of markers ://
if(!markers[mapData.type]) markers[mapData.type] = [];
markers[mapData.type].push(marker);
});
// End of for/each loop
//-----------------------------------------------------------------------------------------
} // end of initialise (?)
//-----------------------------------------------------------------------------------------
/*
Sidebar Functions
*/
$(document).on("mouseenter", ".loc", function() {
//if(lastinfowindow && lastinfowindow.close) lastinfowindow.close(); // moved to on click, avoids closing when accidently moving mouse
var mapData = $(this).data("mapData");
map.setZoom(18); // zoom in a bit
map.setCenter(mapData.marker.getPosition());// centre on selection
//map.panTo(mapData.marker.getPosition());// direct reference to the marker avoids the need to loop.
mapData.marker.setIcon(getIcon(''));//get the default icon ie. larger yellow spot.
}).on("mouseleave", ".loc", function() {
var mapData = $(this).data("mapData");
mapData.marker.setIcon(getIcon(mapData.type));//reset marker to correct type
map.setZoom(17); //rest zoom to default
map.setCenter(marker.getPosition()); // centre on map middle
}).on("click", ".loc", function() { // opens corresponding info window on map
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
var mapData = $(this).data("mapData");
//map.setZoom(19); // zoom in more maybe
mapData.marker.infowindow.open(map, mapData.marker); // open infowindow
lastinfowindow = mapData.marker.infowindow; // remember for closing this infowindow, if still open when selection changes
})
//-----------------------------------------------------------------------------------------
/*
Run on every change to any of the checkboxes
*/
function doFilter() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close(); // close last infowindow if still open
alert ("filter triggered");
$("input[type=checkbox]").each(function(i, checkbox) {
var markersArr = markers[checkbox.value];
if(markersArr) {
$.each(markersArr, function(i, marker) {
marker.loc.style.display = ['none', 'block'][Number(checkbox.checked)]; // don't display non selected types
marker.setVisible(checkbox.checked); // display selected type(s)
});
};
});
}
//-----------------------------------------------------------------------------------------
/*
Run on initial setup
*/
doFilter();
//-----------------------------------------------------------------------------------------
/*
fires on every checkbox change
*/
$("#form").on("click", ".cat", doFilter)
</script>
If, in the loop where the markers are created, you give each sidebar item a reference to its marker instead of the locid, then there's no need to loop to rediscover the marker on mouseenter/mouseleave.
ie, instead of setting :
//My best guess at what the statement must be.
thisloc.data("locid", id);
//Keep this line if thisloc.data("locid") is used elsewhere.
set (within the sidebar item/marker creation loop) :
var marker = ....;
var thisloc = ...;
...
data[i].marker = marker;//add a .marker property to the original dataset.
thisloc.data("itemData", data[i]);//associate the original dataset with the sidebar item
Now the mouseenter/mouseleave handlers should simplify as follows:
$(document).on("mouseenter", ".loc", function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
var data = $(this).data("itemData");
map.panTo(data.marker.getPosition());//<<<< direct reference to the marker avoids the need to loop.
data.marker.setIcon(getIcon(''));//get the default icon.
}).on("mouseleave", ".loc", function() {
var data = $(this).data("itemData");
data.marker.setIcon(getIcon(data.type));
});
Note: You shouldn't need to pan to the marker again on mouseleave.
This should answer the question posed plus other advantages.
EDIT:
OK, now I've seen the main loop, it can be revised something like this, with various mods all through :
var $locs = $("#locs");//Used repeatedly inside the loop.
$.each(data, function(idx, mapData) {
//Note: critical assignment of the new marker as a property of `mapData`.
mapData.marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(mapData.lat,mapData.long),
title: mapData.title,
icon: getIcon(mapData.type)
});
var link = '' + mapData.title + '';
var contentHtml = "<div id='iw' class='iw2'><h3>" + link + "</h3>" + mapData.detail + "<br>" + mapData.address + "</div>";
//What was `marker` must now be referred to as `mapData.marker`
mapData.marker.infowindow = new google.maps.InfoWindow({
content: contentHtml
});
google.maps.event.addListener(mapData.marker, 'click', function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
//`this` refers back to the clicked element; the appropriate marker
this.infowindow.open(map, this);
lastinfowindow = this.infowindow;
});
var spot = '<img src="' + (getIcon(mapData.type)) + '" />';
//Here, it's convenient to create what was `sideitem` as a jQuery object, so we can apply several jquery methods (without making an assignment).
$('<p class="loc" />')
.html(spot + mapData.title)
.appendTo($locs)
.data('mapData', mapData);//<<<<<<<< critical
});
doFilter();//It should be possible to execute this statement when the loop is finished.
And the corresponding mouseenter/mouseleave handlers would be :
$(document).on("mouseenter", ".loc", function() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
var mapData = $(this).data("mapData");
map.panTo(mapData.marker.getPosition());//<<<< direct reference to the marker avoids the need to loop.
mapData.marker.setIcon(getIcon(''));//get the default icon.
}).on("mouseleave", ".loc", function() {
var mapData = $(this).data("mapData");
mapData.marker.setIcon(getIcon(mapData.type));
});
All untested, so may well need debugging.
EDIT2 :
The way I left it above, the array markers wasn't being populated. Now I have seen the function doFilter() I can see that markers should be populated, however it is more convenient for it to be an object rather than an array.
markers = {};//in the same scope as before
At the bottom of the $.each() loop in initialize(), create and populate one array per category, as properties of markers :
if(!markers[mapData.type]) markers[mapData.type] = [];
markers[mapData.type].push(mapData.marker);
With the markers populated in this way, you have a very simple means of identifying all markers in each category, and doFilter() will simplify enormously to :
function doFilter() {
if(lastinfowindow && lastinfowindow.close) lastinfowindow.close();
$("input[type=checkbox]").each(function(i, checkbox) {
var markersArr = markers[checkbox.value];
if(markersArr) {
$.each(markersArr, function(i, marker) {
marker.setVisible(checkbox.checked);
});
}
});
}
EDIT3
To get the sidebar entries to show/hide in sympathy with the category controls, initialize() should be as follows :
function initialize() {
var latlng = new google.maps.LatLng(37.08597981464561, -8.730670809745788);
var myOptions = {
zoom: 18,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var $locs = $("#locs");//Used repeatedly inside the loop.
var marker;
$.each(data, function(idx, mapData) {
//Note: critical assignment of the new marker as a property of `mapData`.
marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(mapData.lat, mapData.long),
title: mapData.title,
icon: getIcon(mapData.type)
});
var link = '' + mapData.title + '';
var contentHtml = "<div id='iw' class='iw2'><h3>" + link + "</h3>" + mapData.detail + "<br>" + mapData.address + "</div>";
marker.infowindow = new google.maps.InfoWindow({
content: contentHtml
});
google.maps.event.addListener(marker, 'click', function() {
closeLastInfoWindow();
//`this` refers back to the clicked element; the appropriate marker
this.infowindow.open(map, this);
lastinfowindow = this.infowindow;
});
var spot = '<img src="' + (getIcon(mapData.type)) + '" />';
//Here, it's convenient to create what was `sideitem` as a jQuery object, so we can apply several jquery methods.
marker.loc = $('<p class="loc" />')
.addClass(mapData.type)
.html(spot + mapData.title)
.data('marker', {m:marker, type:mapData.type})
.appendTo($locs).get(0);
if(!markers[mapData.type]) markers[mapData.type] = [];
markers[mapData.type].push(marker);
});
$(document).on("mouseenter", ".loc", function() {
closeLastInfoWindow();
var m = $(this).data("marker").m;
map.panTo(m.getPosition());//<<<< direct reference to the marker avoids the need to loop.
m.setIcon(getIcon(''));//get the default icon.
}).on("mouseleave", ".loc", function() {
var data = $(this).data("marker");
data.m.setIcon(getIcon(data.type));
}).on("click",".loc",function() {
var m = $(this).data("marker").m;
m.infowindow.open(map, m);
lastinfowindow = m.infowindow;
});
$("#form").on("click", ".cat", doFilter);
doFilter();
}
markers[i].setIcon("currmark") won't work (sets the icon to the string "currmark"). Use the variable: markers[i].setIcon(currmark).
$(document).on("mouseleave",".loc",function() {
var thisloc = $(this).data("locid");
var currmark = getIcon("mapData.type");
for(var i=0; i<markers.length; i++) {
if(markers[i].locid == thisloc) { //get the latlong
map.panTo(markers[i].getPosition());
markers[i].setIcon(currmark);
}
}
});

Google Map Tooltip

I wonder whether someone may be able to help me please.
I've been working on a tooltip for markers that I place on a google map. I can get this to work showing the information that I would like the user to see, in this case the fields name and address, so the code line is title: name+address.
Could someone please tell me how I could put a space between these so the tooltip would read 'name address' rather than 'nameaddress'.
I've tried all sorts of things using e.g.title: name'_'+ address, title: name' '+address and I can't get it to work.
Any help would be greatly appreciated.
Many thanks
Chris
You can try this
name + ' ' + address
NB: you need a space in the quotes and a + on either side.
I use this function to initialize started values:
//Inicialize map values
function initialize() {
latCenterMap=41.50347;
lonCenterMap=-5.74638;
zommCeneterMap=14;
latPoint=41.50347;
lonPoint=-5.74638;
//Values default initialize
var latlng = new google.maps.LatLng(latCenterMap, lonCenterMap);
var mapOptions = {
zoom: zommCeneterMap,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas_'), mapOptions);
codePoint(map, lat, lon);
}
I used this function to set values point position into map
//Get position by Latitude and Longitude
function codePoint(map, lat, lon) {
var latlng = new google.maps.LatLng(parseFloat(lat), parseFloat(lon));
var title = "Your text";
var iconPoint = new google.maps.MarkerImage('images/pointBlue.png',
//Measure image
new google.maps.Size(25,25),
new google.maps.Point(0,0),
//Half measure image
new google.maps.Point(12.5,12.5)
);
marker = new google.maps.Marker({
position: latlng,
map: map,
icon: iconPoint,
tooltip: title
});
customTooltip(marker);
}
I use this function to create a tooltip to point position
//TOOLTIP
function customTooltip(marker){
// Constructor function
function Tooltip(opts, marker) {
// Initialization
this.setValues(opts);
this.map_ = opts.map;
this.marker_ = marker;
var div = this.div_ = document.createElement("div");
// Class name of div element to style it via CSS
div.className = "tooltip";
this.markerDragging = false;
}
Tooltip.prototype = {
// Define draw method to keep OverlayView happy
draw: function() {},
visible_changed: function() {
var vis = this.get("visible");
this.div_.style.visibility = vis ? "visible" : "hidden";
},
getPos: function(e) {
var projection = this.getProjection();
// Position of mouse cursor
var pixel = projection.fromLatLngToDivPixel(e.latLng);
var div = this.div_;
// Adjust the tooltip's position
var gap = 15;
var posX = pixel.x + gap;
var posY = pixel.y + gap;
var menuwidth = div.offsetWidth;
// Right boundary of the map
var boundsNE = this.map_.getBounds().getNorthEast();
boundsNE.pixel = projection.fromLatLngToDivPixel(boundsNE);
if (menuwidth + posX > boundsNE.pixel.x) {
posX -= menuwidth + gap;
}
div.style.left = posX + "px";
div.style.top = posY + "px";
if (!this.markerDragging) {
this.set("visible", true);
}
},
// This is added to avoid using listener (Listener is not working when Map is quickly loaded with icons)
getPos2: function(latLng) {
var projection = this.getProjection();
// Position of mouse cursor
var pixel = projection.fromLatLngToDivPixel(latLng);
var div = this.div_;
// Adjust the tooltip's position
var gap = 5;
var posX = pixel.x + gap;
var posY = pixel.y + gap;
var menuwidth = div.offsetWidth;
// Right boundary of the map
var boundsNE = this.map_.getBounds().getNorthEast();
boundsNE.pixel = projection.fromLatLngToDivPixel(boundsNE);
if (menuwidth + posX > boundsNE.pixel.x) {
posX -= menuwidth + gap;
}
div.style.left = posX + "px";
div.style.top = posY + "px";
if (!this.markerDragging) {
this.set("visible", true);
}
},
addTip: function() {
var me = this;
var g = google.maps.event;
var div = me.div_;
div.innerHTML = me.get("text").toString();
// Tooltip is initially hidden
me.set("visible", false);
// Append the tooltip's div to the floatPane
me.getPanes().floatPane.appendChild(this.div_);
// In IE this listener gets randomly lost after it's been cleared once.
// So keep it out of the listeners array.
g.addListener(me.marker_, "dragend", function() {
me.markerDragging = false; });
// Register listeners
me.listeners = [
// g.addListener(me.marker_, "dragend", function() {
// me.markerDragging = false; }),
g.addListener(me.marker_, "position_changed", function() {
me.markerDragging = true;
me.set("visible", false); }),
g.addListener(me.map_, "mousemove", function(e) {
me.getPos(e); })
];
},
removeTip: function() {
// Clear the listeners to stop events when not needed.
if (this.listeners) {
for (var i = 0, listener; listener = this.listeners[i]; i++) {
google.maps.event.removeListener(listener);
}
delete this.listeners;
}
// Remove the tooltip from the map pane.
var parent = this.div_.parentNode;
if (parent) parent.removeChild(this.div_);
}
};
function inherit(addTo, getFrom) {
var from = getFrom.prototype; // prototype object to get methods from
var to = addTo.prototype; // prototype object to add methods to
for (var prop in from) {
if (typeof to[prop] == "undefined") to[prop] = from[prop];
}
}
// Inherits from OverlayView from the Google Maps API
inherit(Tooltip, google.maps.OverlayView);
var tooltip = new Tooltip({map: map}, marker);
tooltip.bindTo("text", marker, "tooltip");
google.maps.event.addListener(marker, 'mouseover', function() {
tooltip.addTip();
tooltip.getPos2(marker.getPosition());
});
google.maps.event.addListener(marker, 'mouseout', function() {
tooltip.removeTip();
});
}
I use this style to css file
//CSS
.tooltip {
position:absolute;
top:0;
left:0;
z-index: 300;
width: 11.5em;
padding: 5px;
font-size: 12pt;
font-family: klavika;
color: #fff;
background-color: #04A2CA;
border-radius: 10px;
box-shadow: 2px 2px 5px 0 rgba(50, 50, 50, 0.75);
}

Resources