I've been using code from http://gmaps-samples-v3.googlecode.com/svn/trunk/infowindow_custom/infowindow-custom.html, which is currently google's best example of how to create custom InfoWindow's in Maps API v3. I've been working on it and so far I've got it close to working except for one thing, it the div container the text content won't expand to fit the content, so it just drops off instead of expanding the bubble. if I give the content container a fixed pixel width it works fine but I can't get it to expand depending on the amount of text in it.
I've been stuck on this one for a while. Any help would be greatly appreciated!
Here is the HTML page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Gayborhood Map Test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map_canvas { width: 900px;
height: 400px;
margin: 200px auto 0 auto; }
</style>
<link rel="stylesheet" type="text/css" href="map.css" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript" src="InfoBox.js"></script>
<script type="text/javascript">
function initialize() {
var latlng = new google.maps.LatLng(39.947137,-75.161824);
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.HYBRID
};
var gayborhood;
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
var gayborhoodcoords = [
new google.maps.LatLng(39.9492017, -75.1631272),
new google.maps.LatLng(39.945423, -75.1639561),
new google.maps.LatLng(39.9450064, -75.160579),
new google.maps.LatLng(39.9487765, -75.1597468),
new google.maps.LatLng(39.9492017, -75.1631272)
];
gayborhood = new google.maps.Polygon({
paths: gayborhoodcoords,
strokeColor: "#00ff00",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#00ff00",
fillOpacity: 0.35
});
gayborhood.setMap(map);
var image = 'red_icon.png';
var myLatLng = new google.maps.LatLng(39.948883,-75.162246);
var redMarker = new google.maps.Marker({
position: myLatLng,
map: map,
icon: image
});
var contentString = '<h4>Woody\'s Bar</h4>';
/*var infowindow = new google.maps.InfoWindow({
content: contentString,
disableAutoPan: true
});*/
google.maps.event.addListener(redMarker, 'mouseover', function() {
var infoBox = new InfoBox({marker: redMarker, map: map});
});
/*google.maps.event.addListener(redMarker, 'mouseout', function() {
infowindow.close();
});*/
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
</body>
</html>
Here's the InfoBox.js:
/* An InfoBox is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {GLatLng} latlng Point to place bar at
* #param {Map} map The map on which to display this InfoBox.
* #param {Object} opts Passes configuration options - content,
* offsetVertical, offsetHorizontal, className, height, width
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.marker_ = opts.marker
this.latlng_ = opts.marker.getPosition();
this.map_ = opts.map;
this.offsetVertical_ = -65;
this.offsetHorizontal_ = -20;
this.height_ = 50;
//this.width_ = 159;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
/* InfoBox extends GOverlay class from the Google Maps API
*/
InfoBox.prototype = new google.maps.OverlayView();
/* Creates the DIV representing this InfoBox
*/
InfoBox.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
/* Redraw the Bar based on the current projection and zoom level
*/
InfoBox.prototype.draw = function() {
// Creates the element if it doesn't exist already.
this.createElement();
if (!this.div_) return;
// Calculate the DIV coordinates of two opposite corners of our bounds to
// get the size and position of our Bar
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition) return;
// Now position our DIV based on the DIV coordinates of our bounds
//this.div_.style.width = this.width_ + "px";
this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
this.div_.style.height = this.height_ + "px";
this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
this.div_.style.display = 'block';
};
/* Creates the DIV representing this InfoBox in the floatPane. If the panes
* object, retrieved by calling getPanes, is null, remove the element from the
* DOM. If the div exists, but its parent is not the floatPane, move the div
* to the new pane.
* Called from within draw. Alternatively, this can be called specifically on
* a panes_changed event.
*/
InfoBox.prototype.createElement = function() {
var panes = this.getPanes();
var div = this.div_;
if (!div) {
// This does not handle changing panes. You can set the map to be null and
// then reset the map to move the div.
div = this.div_ = document.createElement("div");
div.className = "infobox";
//div.style.width = this.width_ + "px";
//div.style.height = this.height_ + "px";
var leftDiv = document.createElement("div");
leftDiv.className = "bubbleLeftDiv";
var containerDiv = document.createElement("div");
containerDiv.className = "infoboxContainer";
var contentDiv = document.createElement("div");
contentDiv.className = "infoboxContent";
var title = "Much longer title than woody's"
//var infoboxWidth = ( title.length*10 - (title.length) - 40) + "px"
//containerDiv.style.width = infoboxWidth;
//this.width_ = infoboxWidth + 47;
contentDiv.innerHTML = "<h3>" + title + "</h3>";
var rightDiv = document.createElement("div");
rightDiv.className = "bubbleRightDiv";
function removeInfoBox(ib) {
return function() {
ib.setMap(null);
};
}
google.maps.event.addListener(this.marker_, 'mouseout', removeInfoBox(this));
div.appendChild(leftDiv)
div.appendChild(containerDiv);
containerDiv.appendChild(contentDiv);
div.appendChild(rightDiv);
div.style.display = 'none';
panes.floatPane.appendChild(div);
this.panMap();
} else if (div.parentNode != panes.floatPane) {
// The panes have changed. Move the div.
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
// The panes have not changed, so no need to create or move the div.
}
}
/* Pan the map to fit the InfoBox.
*/
InfoBox.prototype.panMap = function() {
// if we go beyond map, pan map
var map = this.map_;
var bounds = map.getBounds();
if (!bounds) return;
// The position of the infowindow
var position = this.latlng_;
// The dimension of the infowindow
var iwWidth = this.width_;
var iwHeight = this.height_;
// The offset position of the infowindow
var iwOffsetX = this.offsetHorizontal_;
var iwOffsetY = this.offsetVertical_;
// Padding on the infowindow
var padX = 40;
var padY = 40;
// The degrees per pixel
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var boundsSpan = bounds.toSpan();
var longSpan = boundsSpan.lng();
var latSpan = boundsSpan.lat();
var degPixelX = longSpan / mapWidth;
var degPixelY = latSpan / mapHeight;
// The bounds of the map
var mapWestLng = bounds.getSouthWest().lng();
var mapEastLng = bounds.getNorthEast().lng();
var mapNorthLat = bounds.getNorthEast().lat();
var mapSouthLat = bounds.getSouthWest().lat();
// The bounds of the infowindow
var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;
// calculate center shift
var shiftLng =
(iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
(iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
var shiftLat =
(iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
(iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);
// The center of the map
var center = map.getCenter();
// The new map center
var centerX = center.lng() - shiftLng;
var centerY = center.lat() - shiftLat;
// center the map to the new shifted center
map.setCenter(new google.maps.LatLng(centerY, centerX));
// Remove the listener after panning is complete.
google.maps.event.removeListener(this.boundsChangedListener_);
this.boundsChangedListener_ = null;
};
And here's the CSS:
.infobox {
border: 0px none;
position: absolute;
width: auto;
height: auto;
}
.infoboxContent {
font-family: arial, helvetica, sans-serif;
font-size: 15px;
padding: 0px;
margin: 9px 0px 0px -24px;
position: absolute;
z-index: 105;
}
.infoboxContainer {
background: url('infowindow_bg.png') repeat-x;
height: 50px;
margin-left: 47px;
}
.bubbleLeftDiv {
width: 47px;
height: 50px;
background: url('infowindow_left.png') no-repeat;
position: absolute;
z-index: 102;
}
.bubbleRightDiv {
width: 26px;
height: 50px;
background: url('infowindow_right.png') no-repeat;
position: absolute;
right: -26px;
top: 0px;
}
.clear { clear: both; }
Thank you!!
I've faced the same problem. The approach that worked for me was to dynamically determine the dimensions of the content and set the height and width of the InfoBox correctly. The problem that I encountered with this was that before the content is inserted into the DOM it doesn't have (correct) dimension values. As a result my approach was the following:
Create the DOM content element that needs to be inserted
Insert it in a temp container
Get dimensions of temp container
Remove temp container
Insert content in InfoBox and set its height and width based on temp container dimensions
Here is an example done with the jQuery framework:
var temp = $("<div class='temp'></div>").html(content).hide().appendTo("body");
var dimentions = {
width : temp.outerWidth(true),
height : temp.outerHeight(true)
};
temp.remove();
var overlayProjection = this.getProjection();
var top_left = overlayProjection.fromLatLngToDivPixel(this.point_);
var dimensions= $.extend({}, dimensions, {
y : top_left.y - dimensions.height,
x : top_left.x - dimensions.width/2
});
var div = this.div_;
$(div).css({
"top": dimensions.y + 'px',
"left" : dimensions.x + 'px',
"width" : dimensions.width + 'px',
"height" : dimensions.height + 'px'
}).html(content);
Hope that helps!
You may override the the infobox draw method and reposition the infobox after it has been rendered:
var infobox = new InfoBox(myOptions);
infobox.initReady = false;
var oldDraw = infobox.draw;
infobox.draw = function() {
oldDraw.apply(this);
if( ! infobox.initReady) {
// Calculate the required offset
var offsetY = -($(infobox.div_).outerHeight());
var offsetX = -110;
infobox.initReady = true;
// Set the new pixelOffset
infobox.setOptions({
pixelOffset: new google.maps.Size(offsetX, offsetY)
});
}
}
Related
By reference to Goomap map overlays DEMO https://google-developers.gonglchuangl.net/maps/documentation/javascript/examples/overlay-hideshow,I modify from this to dynamically load the map by create a element in a HTML File. However, I can see that Map Tiles shows correctly, but missing the overlays.
Besides, when I click the button, a TypeError occurs: overlay.toggle is not a function: TypeErrorPic
How can I dynamic load a Element in a HTML file?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Showing/Hiding Overlays</title>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#floating-panel {
position: absolute;
top: 10px;
left: 25%;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
text-align: center;
font-family: 'Roboto','sans-serif';
line-height: 30px;
padding-left: 10px;
}
</style>
<!-- <script src="https://maps.googleapis.com/maps/api/js?key=MY_KEY"></script> -->
<script>
var myscript = document.createElement("script");
myscript.type = "text/javascript";
myscript.src = "https://maps.googleapis.com/maps/api/js?key=MY_KEY&callback=init_callback";
document.getElementsByTagName('head')[0].appendChild(myscript);
</script>
<script>
// This example adds hide() and show() methods to a custom overlay's prototype.
// These methods toggle the visibility of the container <div>.
// Additionally, we add a toggleDOM() method, which attaches or detaches the
// overlay to or from the map.
var overlay;
function init_callback()
{
USGSOverlay.prototype = new google.maps.OverlayView();
initMap();
}
function initMap() {
//alert("initMap");
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 11,
center: {lat: 62.323907, lng: -150.109291},
mapTypeId: 'satellite'
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(62.281819, -150.287132),
new google.maps.LatLng(62.400471, -150.005608));
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'https://developers.google.com/maps/documentation/javascript/';
srcImage += 'examples/full/images/talkeetna.png';
overlay = new USGSOverlay(bounds, srcImage, map);
}
/** #constructor */
function USGSOverlay(bounds, image, map) {
// Now initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay
this.setMap(map);
}
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.border = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayImage" pane.
var panes = this.getPanes();
panes.overlayImage.appendChild(this.div_);
};
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
};
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
};
// Set the visibility to 'hidden' or 'visible'.
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
// Detach the map from the DOM via toggleDOM().
// Note that if we later reattach the map, it will be visible again,
// because the containing <div> is recreated in the overlay's onAdd() method.
USGSOverlay.prototype.toggleDOM = function() {
if (this.getMap()) {
// Note: setMap(null) calls OverlayView.onRemove()
this.setMap(null);
} else {
this.setMap(this.map_);
}
};
//google.maps.event.addDomListener(window, 'load', initMap);
</script>
</head>
<body>
<!-- Add an input button to initiate the toggle method on the overlay. -->
<div id="floating-panel">
<input type="button" value="Toggle visibility" onclick="overlay.toggle();"></input>
<input type="button" value="Toggle DOM attachment" onclick="overlay.toggleDOM();"></input>
</div>
<div id="map"></div>
</body>
</html>
It is an ordering issue. You need to define the entire USGSOverlay class inside the init_callback function (that runs once the API is loaded). The way the code in your question runs, the init_callback function runs after the rest of the USGSOverlay class is defined and overwrites it.
proof of concept fiddle
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#floating-panel {
position: absolute;
top: 10px;
left: 25%;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
text-align: center;
font-family: 'Roboto', 'sans-serif';
line-height: 30px;
padding-left: 10px;
}
<script>
var myscript = document.createElement("script");
myscript.type = "text/javascript";
myscript.src = "https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=init_callback";
document.getElementsByTagName('head')[0].appendChild(myscript);
</script>
<script>
// This example adds hide() and show() methods to a custom overlay's prototype.
// These methods toggle the visibility of the container <div>.
// Additionally, we add a toggleDOM() method, which attaches or detaches the
// overlay to or from the map.
var overlay;
/** #constructor */
function USGSOverlay(bounds, image, map) {
// Now initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay
this.setMap(map);
}
function init_callback() {
USGSOverlay.prototype = new google.maps.OverlayView();
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.border = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayImage" pane.
var panes = this.getPanes();
panes.overlayImage.appendChild(this.div_);
};
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
};
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
};
// Set the visibility to 'hidden' or 'visible'.
USGSOverlay.prototype.hide = function() {
if (this.div_) {
// The visibility property must be a string enclosed in quotes.
this.div_.style.visibility = 'hidden';
}
};
USGSOverlay.prototype.show = function() {
if (this.div_) {
this.div_.style.visibility = 'visible';
}
};
USGSOverlay.prototype.toggle = function() {
if (this.div_) {
if (this.div_.style.visibility === 'hidden') {
this.show();
} else {
this.hide();
}
}
};
// Detach the map from the DOM via toggleDOM().
// Note that if we later reattach the map, it will be visible again,
// because the containing <div> is recreated in the overlay's onAdd() method.
USGSOverlay.prototype.toggleDOM = function() {
if (this.getMap()) {
// Note: setMap(null) calls OverlayView.onRemove()
this.setMap(null);
} else {
this.setMap(this.map_);
}
};
initMap();
}
function initMap() {
//alert("initMap");
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 11,
center: {
lat: 62.323907,
lng: -150.109291
},
mapTypeId: 'satellite'
});
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(62.281819, -150.287132),
new google.maps.LatLng(62.400471, -150.005608));
// The photograph is courtesy of the U.S. Geological Survey.
var srcImage = 'https://developers.google.com/maps/documentation/javascript/';
srcImage += 'examples/full/images/talkeetna.png';
overlay = new USGSOverlay(bounds, srcImage, map);
}
//google.maps.event.addDomListener(window, 'load', initMap);
</script>
<!-- Add an input button to initiate the toggle method on the overlay. -->
<div id="floating-panel">
<input type="button" value="Toggle visibility" onclick="overlay.toggle();" />
<input type="button" value="Toggle DOM attachment" onclick="overlay.toggleDOM();" />
</div>
<div id="map"></div>
can you uncomment this line in your code and try again?
google.maps.event.addDomListener(window, 'load', initMap);
code below includes appropriate comments for proper understanding. Please let me know if the question is not clear
My requirement is to get the information of all markers under a rectangle selection made by user over the map. (using control key + mouse down + mouse move event)
I have a list of markers to be plotted in the google map. In order to manipulate it later I have used Custom Overlays provided by the API. it works fine.
Now I need to allow user to draw a rectangle selection by pressing Control key + mouse down. When the mouse moves, a rectangle is drawn over the map and a check is done whether any marker lies below the rectangle drawn. This also works fine.
However If I scroll the map using mouse the values are wrongly calculated and not getting result. i.e the rectangle is not drawn properly.
My analysis is something wrong with the usage of PageX and PageY of mouse move event. Initially I used clientX and clientY, but to account scroll I used PageX and PageY.
What could be wrong here ? Kindly let me know.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Proto 1 displaying a list of cameras with custom markers.</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
#rectangle {
position: absolute;
border: 1px solid #c1e0ff;
z-index: 100000;
visibility: hidden;
background-color: #c1e0ff;
opacity: 0.5
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBY_Jb6UGbhR1g9cM3uPGStdevUputZh5s"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
var map;
/* Need to listen for control key + mouse down + mouse move to draw a rectangle over google map and check for markers below the selection*/
document.addEventListener('keydown', multipleCameraSelection);
function multipleCameraSelection(e) {
if (e.ctrlKey) {
map.setOptions({
draggable: false
});
document.onmousedown = function(event) {
/*get div having ID of rectangle.This is created and added to the overlay image pane of map in the draw() function*/
var rectangleDiv = document.getElementById('rectangle');
/*get the co ordinates where mouse is clicked*/
var initialX = event.pageX;
var initialY = event.pageY;
rectangleDiv.style.left = initialX + 'px';
rectangleDiv.style.top = initialY + 'px';
document.onmousemove = function(event) {
/*on mouse move width and height of rectangle is calculated and set*/
var wid = Math.abs(event.pageX - initialX);
var hei = Math.abs(event.pageY - initialY);
rectangleDiv.style.width = wid + 'px';
rectangleDiv.style.height = hei + 'px';
rectangleDiv.style.visibility = 'visible';
if (event.pageX < initialX && event.pageY >= initialY) {
rectangleDiv.style.left = event.pageX + 'px';
} else if (event.pageY <= initialY && event.pageX >= initialX) {
rectangleDiv.style.top = event.pageY + 'px';
} else if (event.pageY < initialY && event.pageX < initialX) {
rectangleDiv.style.left = event.pageX + 'px';
rectangleDiv.style.top = event.pageY + 'px';
}
}
document.onmouseup = function(event) {
document.onmousedown = null;
document.onmousemove = null;
document.onmouseup = null;
rectangleDiv.style.visibility = 'hidden';
/*get the current left , top value of element*/
var rectPos = getOffsetValues(rectangleDiv);
/*all markers have a name starting with cameraDiv. checking whether they lies between the rectangle drawn*/
$("div[id^='cameraDiv']").each(function(index, value) {
var elemToFind = value;
var elemToFindpos = getOffsetValues(elemToFind);
if ((((rectPos.topValue + rectangleDiv.offsetHeight) > elemToFindpos.topValue) && (rectPos.topValue < elemToFindpos.topValue || rectPos.topValue <= (elemToFindpos.topValue + elemToFind.offsetHeight))) &&
(((rectPos.leftValue + rectangleDiv.offsetWidth) > elemToFindpos.leftValue) && (rectPos.leftValue < elemToFindpos.leftValue || rectPos.leftValue <= (elemToFindpos.leftValue + elemToFind.offsetWidth)))) {
console.log(value);
}
})
map.setOptions({
draggable: true
});
}
}
}
}
function getOffsetValues(elem) {
var left = 0,
top = 0;
while (elem) {
left += elem.offsetLeft;
top += elem.offsetTop;
elem = elem.offsetParent;
}
return {
leftValue: left,
topValue: top
};
}
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: {
lat: 8.5241,
lng: 76.9366
}
});
overlay = new CameraLayer(map);
//setMarkers(map);
}
var overlay;
CameraLayer.prototype = new google.maps.OverlayView();
function CameraLayer(map) {
this.map_ = map;
this.div_ = null;
this.setMap(map);
//window.alert('constructor called');
}
CameraLayer.prototype.onAdd = function() {
var panes = this.getPanes();
var div = document.createElement('div');
div.style.position = 'absolute';
div.id = 'myCustomdiv';
this.div_ = div;
panes.overlayImage.appendChild(this.div_);
}
CameraLayer.prototype.draw = function() {
/*when a scroll happens replot the markers in correct pixel coordinates using methods exposed by map api*/
while (this.div_.firstChild)
this.div_.removeChild(this.div_.firstChild);
var msgContainer = document.createDocumentFragment();
for (i = 0; i < camerasToPlace.length; i++) {
var lat = camerasToPlace[i];
var lat1 = lat[1];
var lng1 = lat[2];
var latLng = new google.maps.LatLng({
lat: lat1,
lng: lng1
});
var pixelPosition = this.getProjection().fromLatLngToDivPixel(latLng);
//msgContainer.appendChild()
var div1 = document.createElement('div');
div1.id = 'cameraDiv' + i;
div1.style.position = 'absolute';
var img = document.createElement('img');
img.src = 'camera.png';
img.style.position = 'absolute';
//img.style.width = '100%';
//img.style.height = '100%';
div1.style.left = pixelPosition.x + 'px';
div1.style.top = pixelPosition.y + 'px';
//
div1.style.width = '32px';
div1.style.height = '32px';
div1.appendChild(img);
msgContainer.appendChild(div1)
}
/*creating and appending a div to the overlay image , width and height calculated when the mouse move event happens , style applied above*/
var rectDiv = document.createElement('div');
rectDiv.id = 'rectangle';
rectDiv.style.position = 'absolute';
this.div_.appendChild(rectDiv);
/*container holding marker data to plot in map with left and top values*/
this.div_.appendChild(msgContainer);
}
/* a list holding the latitude and longitude values to be used in draw function to plot in map*/
var camerasToPlace = [
['Camera1 located at TVM', 8.545394, 76.883503],
['Camera2 located at TVM', 8.7379, 76.7163],
['Camera3 located at TVM', 8.8932, 76.6141],
['Camera4 located at TVM', 8.7707, 76.8836],
['Camera5 located at TVM', 8.936906, 76.871831],
['Camera6 located at TVM', 8.485295, 76.916806]
];
google.maps.event.addDomListener(window, 'load', initMap);
</script>
</body>
</html>
As suggested by Emmanuel Delay, reworked on this using map events and its working
Here is the code for that, if it helps anyone. Please note we have to do control + mouse down + mouse move to draw a selection. Also the div element holding marker have a predefined name appended to identify it later
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Proto 1 displaying a list of cameras with custom markers.</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
#rectangle {
position: absolute;
border: 1px solid #c1e0ff;
z-index: 100000;
visibility: hidden;
background-color: #c1e0ff;
opacity: 0.5
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBY_Jb6UGbhR1g9cM3uPGStdevUputZh5s"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
var map;
var mapMouseMoveHandler;
var mapMouseDownHandler;
var mapMouseUpHandler;
document.addEventListener('keydown', controlKeyDown);
document.addEventListener('keyup', controlKeyUp);
function controlKeyDown(e) {
if (e.ctrlKey) {
mapMouseDownHandler = google.maps.event.addListener(map, 'mousedown', cameraSelectionOnMouseDown);
}
}
function controlKeyUp(e) {
if (e.key == 'Control') {
google.maps.event.removeListener(mapMouseDownHandler);
}
}
function getElementOffsetValues(elem) {
var left = 0,
top = 0;
while (elem) {
left += elem.offsetLeft;
top += elem.offsetTop;
elem = elem.offsetParent;
}
return {
leftValue: left,
topValue: top
};
}
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: {
lat: 8.5241,
lng: 76.9366
}
});
overlay = new CameraLayer(map);
//setMarkers(map);
}
function cameraSelectionOnMouseDown(e) {
map.setOptions({
draggable: false
});
var rectangleDiv = document.getElementById('rectangle');
var pixelPosition = overlay.getProjection().fromLatLngToDivPixel(e.latLng);
var initialX = pixelPosition.x;
var initialY = pixelPosition.y;
rectangleDiv.style.left = initialX + 'px';
rectangleDiv.style.top = initialY + 'px';
mapMouseMoveHandler = google.maps.event.addListener(map, 'mousemove', function(e) {
var newXY = overlay.getProjection().fromLatLngToDivPixel(e.latLng);
var wid = Math.abs(newXY.x - initialX);
var hei = Math.abs(newXY.y - initialY);
rectangleDiv.style.width = wid + 'px';
rectangleDiv.style.height = hei + 'px';
rectangleDiv.style.visibility = 'visible';
if (newXY.x < initialX && newXY.y >= initialY) {
rectangleDiv.style.left = newXY.x + 'px';
} else if (newXY.y <= initialY && newXY.x >= initialX) {
rectangleDiv.style.top = newXY.y + 'px';
} else if (newXY.y < initialY && newXY.x < initialX) {
rectangleDiv.style.left = newXY.x + 'px';
rectangleDiv.style.top = newXY.y + 'px';
}
})
mapMouseUpHandler = google.maps.event.addListener(map, 'mouseup', function(e) {
google.maps.event.removeListener(mapMouseMoveHandler);
google.maps.event.removeListener(mapMouseUpHandler);
var rectPosition = getElementOffsetValues(rectangleDiv);
$("div[id^='cameraDiv']").each(function(index, value) {
var elemToFind = value;
var elemToFindposition = getElementOffsetValues(elemToFind);
if ((((rectPosition.topValue + rectangleDiv.offsetHeight) > elemToFindposition.topValue) && (rectPosition.topValue < elemToFindposition.topValue || rectPosition.topValue <= (elemToFindposition.topValue + elemToFind.offsetHeight))) &&
(((rectPosition.leftValue + rectangleDiv.offsetWidth) > elemToFindposition.leftValue) && (rectPosition.leftValue < elemToFindposition.leftValue || rectPosition.leftValue <= (elemToFindposition.leftValue + elemToFind.offsetWidth)))) {
console.log(value);
}
})
rectangleDiv.style.visibility = 'hidden';
map.setOptions({
draggable: true
});
});
}
var overlay;
CameraLayer.prototype = new google.maps.OverlayView();
function CameraLayer(map) {
this.map_ = map;
this.div_ = null;
this.setMap(map);
}
CameraLayer.prototype.onAdd = function() {
var panes = this.getPanes();
var div = document.createElement('div');
div.style.position = 'absolute';
div.id = 'myCustomdiv';
this.div_ = div;
panes.overlayImage.appendChild(this.div_);
}
CameraLayer.prototype.draw = function() {
while (this.div_.firstChild)
this.div_.removeChild(this.div_.firstChild);
var msgContainer = document.createDocumentFragment();
for (i = 0; i < camerasToPlace.length; i++) {
var lat = camerasToPlace[i];
var lat1 = lat[1];
var lng1 = lat[2];
var latLng = new google.maps.LatLng({
lat: lat1,
lng: lng1
});
var pixelPosition = this.getProjection().fromLatLngToDivPixel(latLng);
var div1 = document.createElement('div');
div1.id = 'cameraDiv' + i;
div1.style.position = 'absolute';
var img = document.createElement('img');
img.src = 'camera.png';
img.style.position = 'absolute';
//img.style.width = '100%';
//img.style.height = '100%';
div1.style.left = pixelPosition.x + 'px';
div1.style.top = pixelPosition.y + 'px';
//
div1.style.width = '32px';
div1.style.height = '32px';
div1.appendChild(img);
msgContainer.appendChild(div1)
}
var rectDiv = document.createElement('div');
rectDiv.id = 'rectangle';
rectDiv.style.position = 'absolute';
this.div_.appendChild(rectDiv);
this.div_.appendChild(msgContainer);
}
var camerasToPlace = [
['Camera1 located at TVM', 8.545394, 76.883503],
['Camera2 located at TVM', 8.7379, 76.7163],
['Camera3 located at TVM', 8.8932, 76.6141],
['Camera4 located at TVM', 8.7707, 76.8836],
['Camera5 located at TVM', 8.936906, 76.871831],
['Camera6 located at TVM', 8.485295, 76.916806]
];
google.maps.event.addDomListener(window, 'load', initMap);
</script>
</body>
</html>
I have a page where I have a tiny person that can be dragged around using RxJS. When the drag ends, if it ends over a google map on the page, I want to convert the mouse coordinates at the point the person was dropped into a latitude and longitude.
I've found/cobbled together this implementation from elsewhere on SO and the Web.
function pixelOffsetToLatLng(map, offsetx, offsety) {
var mapZoom = map.getZoom();
var scale = Math.pow(2, mapZoom);
var mapCenter = map.getCenter();
var worldCoordinateCenter = map.getProjection().fromLatLngToPoint(mapCenter);
var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0);
var worldCoordinateNewCenter = new google.maps.Point(
worldCoordinateCenter.x - pixelOffset.x,
worldCoordinateCenter.y + pixelOffset.y
);
var latLngPosition = map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
return latLngPosition;
}
But it is giving incorrect results. It seems to be particular sensitive to position on the planet and to zoom level.
I've included a snippet below that centres on 0,0 with a marker nearby. If you repeatedly drop the person on the marker and zoom out, you'll see that the value of lat, lng changes significantly with zoom level. And I don't understand why...
Thanks in advance!
//adapted from here https://gist.github.com/mattpodwysocki/2156153
//this is an RXJS drag and drop implementation. It is used below to provide screen coordinates to Google Maps
(function(dragger) {
'use strict';
dragger.init = function() {
var dragTarget = $('#dragTarget');
// Get the three major events
window.dragger.mouseup = dragTarget.onAsObservable('mouseup');
window.dragger.mousemove = dragTarget.onAsObservable('mousemove');
window.dragger.mousedown = dragTarget.onAsObservable('mousedown').select(function(event) {
// calculate offsets when mouse down
event.preventDefault();
return {
left: event.clientX - dragTarget.offset().left,
top: event.clientY - dragTarget.offset().top
};
});
// Combine mouse down with mouse move until mouse up
window.dragger.mousedrag = window.dragger.mousedown.selectMany(function(offset) {
return window.dragger.mousemove.select(function(pos) {
// calculate offsets from mouse down to mouse moves
return {
left: pos.clientX - offset.left,
top: pos.clientY - offset.top
};
}).takeUntil(window.dragger.mouseup);
});
window.dragger.mousedrag.subscribe(function(pos) {
// Update position
dragTarget.css({
top: pos.top,
left: pos.left
});
});
window.dragger.mousedown.subscribe(function() {
$('#dragTarget #person').hide();
$('#dragTarget #shopper').show();
});
window.dragger.mouseup.subscribe(function(pos) {
$('#dragTarget #person').show();
$('#dragTarget #shopper').hide();
$('aside ul').append($('<li>').append('shopper dropped at <br/>x:' + pos.clientX + ' and y:' + pos.clientY));
});
};
}(window.dragger = window.dragger || {}));
window.dragger.init();
(function(gmaps) {
'use strict';
//a function cobbled together from elsewhere on StackOverflow to convert from page coordinates
//to a latitude and longitude
function pixelOffsetToLatLng(map, offsetx, offsety) {
var mapZoom = map.getZoom();
var scale = Math.pow(2, mapZoom);
var mapCenter = map.getCenter();
var worldCoordinateCenter = map.getProjection().fromLatLngToPoint(mapCenter);
var pixelOffset = new google.maps.Point((offsetx/scale) || 0,(offsety/scale) ||0);
var worldCoordinateNewCenter = new google.maps.Point(
worldCoordinateCenter.x - pixelOffset.x,
worldCoordinateCenter.y + pixelOffset.y
);
var latLngPosition = map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
return latLngPosition;
}
gmaps.init = function() {
//setup a map centered on 0,0
var mapCanvas = $('#map');
var mapOptions = {
center: new google.maps.LatLng(0, 0),
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(mapCanvas[0], mapOptions);
//put a marker nearby as a reference point
var marker = new google.maps.Marker({
position: new google.maps.Marker({lat:0.001, lng:0.001}),
map: map,
title: '0.001, 0.001'
});
//run this function every time the draggable person is dropped
window.dragger.mouseup.subscribe(function(pos) {
var ll = pixelOffsetToLatLng(map, pos.pageX, pos.pageY);
$('aside ul').append($('<li>').append('shopper dropped at <br/>lat:' + ll.lat() + ' and y:' + ll.lng()));
});
};
}(window.gmaps = window.gmaps || {}));
window.gmaps.init();
#dragTarget {
position:absolute;
z-index: 999;
}
.grabbable {
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
/* (Optional) Apply a "closed-hand" cursor during drag operation. */
.grabbable:active {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
}
#map {
height:400px;
width:400px;
float:left;
background-color:lightyellow;
}
aside {
height:400px;
width:200px;
float:right;
background-color:lightgrey;
}
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs-jquery/1.1.6/rx.jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div class="grabbable fa fa-2x fa-female" id="dragTarget"></div>
<div id="map"></div>
<aside><ul></ul></aside>
Is it possible to change the color of the border, the alignment, padding and other attributes of an InfoWindow? I've been looking for this for a week but I always end up here. And it does not provide a code.
Here's my code.
//Declare an infoWindow variable - shows when a marker is tapped/clicked
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP file
downloadUrl("outputXML.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 type = markers[i].getAttribute("type");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var html = "<b>" + name + "</b> <br/>" + address;
var icon = customIcons[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon.icon,
title:name
});
bindInfoWindow(marker, map, infoWindow, html);
}
});
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
infoWindow.setContent(html);
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);
}//END FUNCTION BINDINFOWINDOW
function doNothing() {} //For request.onreadystatechange
By the way, I'm catching those values from an online database, we don't have to mind that, they're all working fine, the only problem is how to customize an infoWindow.
Please help me. Thanks.
ADD: I forgot to say that I will insert this into an android application. I'm using webview.
The content that you pass to an InfoWindow may be: text, HTML, or a DOM element. The InfoWindow is by default sized to fit whataver content you pass, so the best way to control the content the way you describe is to create a div, assign a CSS class to the div, and then you will have complete control over the appearance of your InfoWindow content.
Also, if you want to have more control over the actual appearance of the window structure itself, you may want to consider using the InfoBubble Utility Library as a stylable drop-in replacement for the standard InfoWindow.
Checkout the sample code of this url,
In this code, InfoBox extends GOverlay class from the Google Maps API and creating div dynamically and drawing into the map.
Another Example page
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps JavaScript API v3 Example: Info Window Custom</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
/* An InfoBox is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {GLatLng} latlng Point to place bar at
* #param {Map} map The map on which to display this InfoBox.
* #param {Object} opts Passes configuration options - content,
* offsetVertical, offsetHorizontal, className, height, width
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -195;
this.offsetHorizontal_ = 0;
this.height_ = 165;
this.width_ = 266;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
/* InfoBox extends GOverlay class from the Google Maps API
*/
InfoBox.prototype = new google.maps.OverlayView();
/* Creates the DIV representing this InfoBox
*/
InfoBox.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
/* Redraw the Bar based on the current projection and zoom level
*/
InfoBox.prototype.draw = function() {
// Creates the element if it doesn't exist already.
this.createElement();
if (!this.div_) return;
// Calculate the DIV coordinates of two opposite corners of our bounds to
// get the size and position of our Bar
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition) return;
// Now position our DIV based on the DIV coordinates of our bounds
this.div_.style.width = this.width_ + "px";
this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
this.div_.style.height = this.height_ + "px";
this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
this.div_.style.display = 'block';
};
/* Creates the DIV representing this InfoBox in the floatPane. If the panes
* object, retrieved by calling getPanes, is null, remove the element from the
* DOM. If the div exists, but its parent is not the floatPane, move the div
* to the new pane.
* Called from within draw. Alternatively, this can be called specifically on
* a panes_changed event.
*/
InfoBox.prototype.createElement = function() {
var panes = this.getPanes();
var div = this.div_;
if (!div) {
// This does not handle changing panes. You can set the map to be null and
// then reset the map to move the div.
div = this.div_ = document.createElement("div");
div.style.border = "0px none";
div.style.position = "absolute";
div.style.background = "url('http://gmaps-samples.googlecode.com/svn/trunk/images/blueinfowindow.gif')";
div.style.width = this.width_ + "px";
div.style.height = this.height_ + "px";
var contentDiv = document.createElement("div");
contentDiv.style.padding = "30px"
contentDiv.innerHTML = "<b>Hello World! </b>";
var topDiv = document.createElement("div");
topDiv.style.textAlign = "right";
var closeImg = document.createElement("img");
closeImg.style.width = "32px";
closeImg.style.height = "32px";
closeImg.style.cursor = "pointer";
closeImg.src = "http://gmaps-samples.googlecode.com/svn/trunk/images/closebigger.gif";
topDiv.appendChild(closeImg);
function removeInfoBox(ib) {
return function() {
ib.setMap(null);
};
}
google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));
div.appendChild(topDiv);
div.appendChild(contentDiv);
div.style.display = 'none';
panes.floatPane.appendChild(div);
this.panMap();
} else if (div.parentNode != panes.floatPane) {
// The panes have changed. Move the div.
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
// The panes have not changed, so no need to create or move the div.
}
}
/* Pan the map to fit the InfoBox.
*/
InfoBox.prototype.panMap = function() {
// if we go beyond map, pan map
var map = this.map_;
var bounds = map.getBounds();
if (!bounds) return;
// The position of the infowindow
var position = this.latlng_;
// The dimension of the infowindow
var iwWidth = this.width_;
var iwHeight = this.height_;
// The offset position of the infowindow
var iwOffsetX = this.offsetHorizontal_;
var iwOffsetY = this.offsetVertical_;
// Padding on the infowindow
var padX = 40;
var padY = 40;
// The degrees per pixel
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var boundsSpan = bounds.toSpan();
var longSpan = boundsSpan.lng();
var latSpan = boundsSpan.lat();
var degPixelX = longSpan / mapWidth;
var degPixelY = latSpan / mapHeight;
// The bounds of the map
var mapWestLng = bounds.getSouthWest().lng();
var mapEastLng = bounds.getNorthEast().lng();
var mapNorthLat = bounds.getNorthEast().lat();
var mapSouthLat = bounds.getSouthWest().lat();
// The bounds of the infowindow
var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;
// calculate center shift
var shiftLng =
(iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
(iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
var shiftLat =
(iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
(iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);
// The center of the map
var center = map.getCenter();
// The new map center
var centerX = center.lng() - shiftLng;
var centerY = center.lat() - shiftLat;
// center the map to the new shifted center
map.setCenter(new google.maps.LatLng(centerY, centerX));
// Remove the listener after panning is complete.
google.maps.event.removeListener(this.boundsChangedListener_);
this.boundsChangedListener_ = null;
};
function initialize() {
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(-33.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP,
sensor: 'true'
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(-34, 150),
map: map
});
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({latlng: marker.getPosition(), map: map});
});
google.maps.event.trigger(marker, "click");
}
</script>
</head>
<body style="margin:0px; padding:0px;" onload="initialize()">
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>
I'm trying to implement the 'Smart Info Window' code by Pamela Fox into my Google map and I just can't seem to get this to work. The map appears with the markers correctly positioned on it. But when I click on the marker nothing happens, but I don't get any error messages and I must admit to being a bit lost with this.
Where am I going wrong?
HTML Form
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>All Locations</title>
<link rel="stylesheet" href="css/alllocationsstyle.css" type="text/css" media="all" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&language=en"></script>
<script type="text/javascript" src="js/smartinfowindow.js"></script>
<script type="text/javascript">
var customIcons = {
0: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_red.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
},
1: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_green.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
}
};
function load() {
var map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(54.312195845815246,-4.45948481875007),
zoom:6,
mapTypeId: 'roadmap'
});
downloadUrl("phpfile.php", function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
var locationname = markers[i].getAttribute("locationname");
var address = markers[i].getAttribute("address");
var totalfinds = markers[i].getAttribute("totalfinds");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("osgb36lat")),
parseFloat(markers[i].getAttribute("osgb36lon")));
var html = locationname + "<p>" + 'No. of finds: ' + "<b>" + totalfinds + "</b>" + "</p>";
var icon = {};
if (totalfinds == 0) {
icon = customIcons[0];
} else if (totalfinds >= 1) {
icon = customIcons[1];
}
var marker = new google.maps.Marker({
map: map,
position: point,
title: address,
icon: icon.icon,
shadow: icon.shadow
});
bounds.extend(point);
map.fitBounds(bounds);
google.maps.event.addListener(point, 'click', function(e) {
var infobox = new SmartInfoWindow({position: point, map: map, html: html});
});
}
});
}
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() {}
</script>
</head>
<body onLoad="load()">
<div id="map"></div>
</body>
</html>
Smart Window JS
/* An SmartInfoWindow is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {Object} opts Passes configuration options.
*/
function SmartInfoWindow(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.position;
this.content_ = opts.content;
this.map_ = opts.map;
this.height_ = 351;
this.width_ = 280;
this.size_ = new google.maps.Size(this.height_, this.width_);
this.offsetVertical_ = -this.height_;
this.offsetHorizontal_ = 0;
this.panned_ = false;
this.setMap(this.map_);
// We need to listen to bounds_changed event so that we can redraw
// absolute position every time the map moves.
// This is only needed because we append to body instead of map panes.
var me = this;
google.maps.event.addListener(this.map_, 'bounds_changed', function() {
me.draw();
});
}
/**
* SmartInfoWindow extends GOverlay class from the Google Maps API
*/
SmartInfoWindow.prototype = new google.maps.OverlayView();
/**
* Creates the DIV representing this SmartInfoWindow
*/
SmartInfoWindow.prototype.onRemove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
/**
* Called when the overlay is first added to the map.
*/
SmartInfoWindow.prototype.onAdd = function() {
// Creates the element if it doesn't exist already.
this.createElement();
};
/**
* Redraw based on the current projection and zoom level.
*/
SmartInfoWindow.prototype.draw = function() {
// Since we use bounds changed listener, projection is sometimes null
if (!this.getProjection()) {
return;
}
// This gives us the position in the tiles div.
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
var centerPosition = this.getProjection().fromLatLngToDivPixel(this.map_.getCenter());
var centerPositionReal = new google.maps.Point(this.map_.getDiv().offsetWidth/2, this.map_.getDiv().offsetHeight/2);
// Figure out difference between map div and tiles div, so that we can
// calculate position in map div
var centerOffsetX = -centerPosition.x + centerPositionReal.x;
var centerOffsetY = -centerPosition.y + centerPositionReal.y;
if (!pixPosition) return;
var alignment = this.getBestAlignment();
var paddingTop = 0;
var paddingLeft = 0;
var widthLess = 0;
switch (alignment) {
case SmartInfoWindow.Align.ABOVE:
this.width_ = 280;
this.height_ = 351;
image = 'infobox_above.gif';
this.offsetX_ = -(this.width_ / 2 - 17);
this.offsetY_ = -(this.height_ + 12);
break;
case SmartInfoWindow.Align.BELOW:
this.width_ = 280;
this.height_ = 351;
image = 'infobox_below.gif';
this.offsetX_ = -(this.width_ / 2 - 17);
this.offsetY_ = -15;
paddingTop = 20;
break;
case SmartInfoWindow.Align.LEFT:
this.width_ = 307;
this.height_ = 326;
image = 'infobox_left.gif';
this.offsetX_ = -(this.width_) + 10;
this.offsetY_ = -(this.height_ / 2 + 33);
widthLess = 20;
break;
case SmartInfoWindow.Align.RIGHT:
image = 'infobox_right.gif';
this.width_ = 307;
this.height_ = 326;
this.offsetX_ = 6;
this.offsetY_ = -(this.height_ / 2 + 33);
paddingLeft = 20;
widthLess = 20;
break;
}
// Now position our DIV based on the DIV coordinates of our bounds
this.div_.style.width = this.width_ + 'px';
this.div_.style.left = (pixPosition.x + this.offsetX_) + centerOffsetX + 'px';
this.div_.style.height = this.height_ + 'px';
this.div_.style.top = (pixPosition.y + this.offsetY_) + centerOffsetY + 'px';
//this.div_.style.paddingTop = paddingTop + 'px';
//this.div_.style.paddingLeft = paddingLeft + 'px';
this.div_.style.background = 'url("images/' + image + '")';
this.div_.style.display = 'block';
this.wrapperDiv_.style.width = (this.width_- widthLess) + 'px';
this.wrapperDiv_.style.height = this.height_ + 'px';
this.wrapperDiv_.style.marginTop = paddingTop + 'px';
this.wrapperDiv_.style.marginLeft = paddingLeft + 'px';
this.wrapperDiv_.style.overflow = 'hidden';
if (!this.panned_) {
this.panned_ = true;
this.maybePanMap();
}
};
/**
* Creates the DIV representing this SmartInfoWindow in the floatPane. If the panes
* object, retrieved by calling getPanes, is null, remove the element from the
* DOM. If the div exists, but its parent is not the floatPane, move the div
* to the new pane.
* Called from within draw. Alternatively, this can be called specifically on
* a panes_changed event.
*/
SmartInfoWindow.prototype.createElement = function() {
var panes = this.getPanes();
var div = this.div_;
if (!div) {
// This does not handle changing panes. You can set the map to be null and
// then reset the map to move the div.
div = this.div_ = document.createElement('div');
div.style.border = '0px none';
div.style.position = 'absolute';
div.style.overflow = 'hidden';
var wrapperDiv = this.wrapperDiv_ = document.createElement('div');
var contentDiv = document.createElement('div');
if (typeof this.content_ == 'string') {
contentDiv.innerHTML = this.content_;
} else {
contentDiv.appendChild(this.content_);
}
var topDiv = document.createElement('div');
topDiv.style.textAlign = 'right';
var closeImg = document.createElement('img');
closeImg.src = 'images/closebigger.gif';
closeImg.style.width = '32px';
closeImg.style.height = '32px';
closeImg.style.cursor = 'pointer';
topDiv.appendChild(closeImg);
function removeSmartInfoWindow(ib) {
return function() {
ib.setMap(null);
};
}
google.maps.event.addDomListener(closeImg, 'click', removeSmartInfoWindow(this));
wrapperDiv.appendChild(topDiv);
wrapperDiv.appendChild(contentDiv);
div.appendChild(wrapperDiv);
div.style.display = 'none';
// Append to body, to avoid bug with Webkit browsers
// attempting CSS transforms on IFRAME or SWF objects
// and rendering badly.
document.body.appendChild(div);
} else if (div.parentNode != panes.floatPane) {
// The panes have changed. Move the div.
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
// The panes have not changed, so no need to create or move the div.
}
};
SmartInfoWindow.mouseFilter = function(e) {
e.returnValue = 'true';
e['handled'] = true;
}
/**
* Closes infowindow
*/
SmartInfoWindow.prototype.close = function() {
this.setMap(null);
};
/**
* Pan the map to fit the SmartInfoWindow,
* if its top or bottom corners aren't visible.
*/
SmartInfoWindow.prototype.maybePanMap = function() {
// if we go beyond map, pan map
var map = this.map_;
var projection = this.getProjection();
var bounds = map.getBounds();
if (!bounds) return;
// The dimension of the infowindow
var iwWidth = this.width_;
var iwHeight = this.height_;
// The offset position of the infowindow
var iwOffsetX = this.offsetX_;
var iwOffsetY = this.offsetY_;
var anchorPixel = projection.fromLatLngToDivPixel(this.latlng_);
var bl = new google.maps.Point(anchorPixel.x + iwOffsetX + 20,
anchorPixel.y + iwOffsetY + iwHeight);
var tr = new google.maps.Point(anchorPixel.x + iwOffsetX + iwWidth,
anchorPixel.y + iwOffsetY);
var sw = projection.fromDivPixelToLatLng(bl);
var ne = projection.fromDivPixelToLatLng(tr);
// The bounds of the infowindow
if (!map.getBounds().contains(ne) || !map.getBounds().contains(sw)) {
map.panToBounds(new google.maps.LatLngBounds(sw, ne));
}
};
/**
* #enum {number}
*/
SmartInfoWindow.Align = {
ABOVE: 0,
LEFT: 1,
RIGHT: 2,
BELOW: 3
};
/**
* Finds best alignment for infowindow.
* #return {number} Alignment.
*/
SmartInfoWindow.prototype.getBestAlignment = function() {
var bestAlignment = SmartInfoWindow.Align.LEFT;
var minPan = 0;
for (var alignment in SmartInfoWindow.Align) {
var alignment = SmartInfoWindow.Align[alignment];
var panValue = this.getPanValue(alignment);
if (panValue > minPan) {
minPan = panValue;
bestAlignment = alignment;
}
}
return bestAlignment;
};
/**
* Calculates distance of corner for each alignment.
* #param {number} alignment An alignment constant.
* #return {number} Distance for that alignment.
*/
SmartInfoWindow.prototype.getPanValue = function(alignment) {
var mapSize = new google.maps.Size(this.map_.getDiv().offsetWidth,
this.map_.getDiv().offsetHeight);
var bounds = this.map_.getBounds();
var sideLatLng;
switch (alignment) {
case SmartInfoWindow.Align.ABOVE:
sideLatLng = new google.maps.LatLng(bounds.getNorthEast().lat(),
this.latlng_.lng());
break;
case SmartInfoWindow.Align.BELOW:
sideLatLng = new google.maps.LatLng(bounds.getSouthWest().lat(),
this.latlng_.lng());
break;
case SmartInfoWindow.Align.RIGHT:
sideLatLng = new google.maps.LatLng(this.latlng_.lat(),
bounds.getNorthEast().lng());
break;
case SmartInfoWindow.Align.LEFT:
sideLatLng = new google.maps.LatLng(this.latlng_.lat(),
bounds.getSouthWest().lng());
break;
}
var dist = SmartInfoWindow.distHaversine(this.latlng_.lat(), this.latlng_.lng(),
sideLatLng.lat(), sideLatLng.lng());
return dist;
};
/**
* Converts degrees to radians.
* #param {number} num Angle in degrees.
* #return {number} Angle in radians.
*/
SmartInfoWindow.toRad = function(num) {
return num * Math.PI / 180;
}
/**
* Calculates distance between two coordinates.
* #param {number} lat1 Latitude of first coord.
* #param {number} lon1 Longitude of second coord.
* #param {number} lat2 Latitude of second coord.
* #param {number} lon2 Longitude of second coord.
* #return {number} The distance.
*/
SmartInfoWindow.distHaversine = function(lat1, lon1, lat2, lon2) {
var R = 6371; // earth's mean radius in km
var dLat = SmartInfoWindow.toRad(lat2 - lat1);
var dLon = SmartInfoWindow.toRad(lon2 - lon1);
lat1 = SmartInfoWindow.toRad(lat1), lat2 = SmartInfoWindow.toRad(lat2);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d;
}
UPDATED CODE
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Locations</title>
<link rel="stylesheet" href="css/alllocationsstyle.css" type="text/css" media="all" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&language=en"></script>
<script type="text/javascript">
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -195;
this.offsetHorizontal_ = 0;
this.height_ = 165;
this.width_ = 266;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
/* InfoBox extends GOverlay class from the Google Maps API
*/
InfoBox.prototype = new google.maps.OverlayView();
/* Creates the DIV representing this InfoBox
*/
InfoBox.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
/* Redraw the Bar based on the current projection and zoom level
*/
InfoBox.prototype.draw = function() {
// Creates the element if it doesn't exist already.
this.createElement();
if (!this.div_) return;
// Calculate the DIV coordinates of two opposite corners of our bounds to
// get the size and position of our Bar
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition) return;
// Now position our DIV based on the DIV coordinates of our bounds
this.div_.style.width = this.width_ + "px";
this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
this.div_.style.height = this.height_ + "px";
this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
this.div_.style.display = 'block';
};
/* Creates the DIV representing this InfoBox in the floatPane. If the panes
* object, retrieved by calling getPanes, is null, remove the element from the
* DOM. If the div exists, but its parent is not the floatPane, move the div
* to the new pane.
* Called from within draw. Alternatively, this can be called specifically on
* a panes_changed event.
*/
InfoBox.prototype.createElement = function() {
var panes = this.getPanes();
var div = this.div_;
if (!div) {
// This does not handle changing panes. You can set the map to be null and
// then reset the map to move the div.
div = this.div_ = document.createElement("div");
div.style.border = "0px none";
div.style.position = "absolute";
div.style.background = "url('http://gmaps-samples.googlecode.com/svn/trunk/images/blueinfowindow.gif')";
div.style.width = this.width_ + "px";
div.style.height = this.height_ + "px";
var contentDiv = document.createElement("div");
contentDiv.style.padding = "30px"
contentDiv.innerHTML = "<b>Hello World!</b>";
var topDiv = document.createElement("div");
topDiv.style.textAlign = "right";
var closeImg = document.createElement("img");
closeImg.style.width = "32px";
closeImg.style.height = "32px";
closeImg.style.cursor = "pointer";
closeImg.src = "http://gmaps-samples.googlecode.com/svn/trunk/images/closebigger.gif";
topDiv.appendChild(closeImg);
function removeInfoBox(ib) {
return function() {
ib.setMap(null);
};
}
google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));
div.appendChild(topDiv);
div.appendChild(contentDiv);
div.style.display = 'none';
panes.floatPane.appendChild(div);
this.panMap();
} else if (div.parentNode != panes.floatPane) {
// The panes have changed. Move the div.
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
// The panes have not changed, so no need to create or move the div.
}
}
/* Pan the map to fit the InfoBox.
*/
InfoBox.prototype.panMap = function() {
// if we go beyond map, pan map
var map = this.map_;
var bounds = map.getBounds();
if (!bounds) return;
// The position of the infowindow
var position = this.latlng_;
// The dimension of the infowindow
var iwWidth = this.width_;
var iwHeight = this.height_;
// The offset position of the infowindow
var iwOffsetX = this.offsetHorizontal_;
var iwOffsetY = this.offsetVertical_;
// Padding on the infowindow
var padX = 40;
var padY = 40;
// The degrees per pixel
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var boundsSpan = bounds.toSpan();
var longSpan = boundsSpan.lng();
var latSpan = boundsSpan.lat();
var degPixelX = longSpan / mapWidth;
var degPixelY = latSpan / mapHeight;
// The bounds of the map
var mapWestLng = bounds.getSouthWest().lng();
var mapEastLng = bounds.getNorthEast().lng();
var mapNorthLat = bounds.getNorthEast().lat();
var mapSouthLat = bounds.getSouthWest().lat();
// The bounds of the infowindow
var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;
// calculate center shift
var shiftLng =
(iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
(iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
var shiftLat =
(iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
(iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);
// The center of the map
var center = map.getCenter();
// The new map center
var centerX = center.lng() - shiftLng;
var centerY = center.lat() - shiftLat;
// center the map to the new shifted center
map.setCenter(new google.maps.LatLng(centerY, centerX));
// Remove the listener after panning is complete.
google.maps.event.removeListener(this.boundsChangedListener_);
this.boundsChangedListener_ = null;
};
</script>
<script type="text/javascript">
var customIcons = {
0: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_red.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
},
1: {
icon: 'http://labs.google.com/ridefinder/images/mm_20_green.png',
shadow: 'http://labs.google.com/ridefinder/images/mm_20_shadow.png'
}
};
function load() {
var map = new google.maps.Map(document.getElementById("map"), {
center: new google.maps.LatLng(54.312195845815246,-4.45948481875007),
zoom:6,
mapTypeId: 'roadmap'
});
// Change this depending on the name of your PHP file
downloadUrl("phpfile.php", function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
var locationname = markers[i].getAttribute("locationname");
var address = markers[i].getAttribute("address");
var totalfinds = markers[i].getAttribute("totalfinds");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("osgb36lat")),
parseFloat(markers[i].getAttribute("osgb36lon")));
var html = locationname + "<p>" + 'No. of finds: ' + "<b>" + totalfinds + "</b>" + "</p>";
var icon = {};
if (totalfinds == 0) {
icon = customIcons[0];
} else if (totalfinds >= 1) {
icon = customIcons[1];
}
var marker = new google.maps.Marker({
map: map,
position: point,
title: address,
icon: icon.icon,
shadow: icon.shadow
});
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({latlng: marker.getPosition(), map: map});
});
bounds.extend(point);
map.fitBounds(bounds);
}
});
}
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() {}
</script>
</head>
<body onLoad="load()">
<div id="map"></div>
</body>
</html>
If I am reading your code correctly you assign listener to point (google.maps.LatLng), while you should do it for a marker. In fragment:
google.maps.event.addListener(point, 'click', function(e) {
var infobox = new SmartInfoWindow({position: point, map: map, html: html});
});
change point to marker:
google.maps.event.addListener(marker, 'click', function(e) {
var infobox = new SmartInfoWindow({position: point, map: map, html: html});
});