@h21-map/google-infobox
Version:
A library of Google Map JS API
529 lines (465 loc) • 17.1 kB
JavaScript
/**
* @name InfoBox
* @version 1.1.19 [April 6, 2018]
* @author Gary Little (inspired by proof-of-concept code from Pamela Fox of Google)
* @copyright Copyright 2010 Gary Little [gary at luxcentral.com]
* @fileoverview InfoBox extends the Google Maps JavaScript API V3 <tt>OverlayView</tt> class.
* <p>
* An InfoBox behaves like a <tt>google.maps.InfoWindow</tt>, but it supports several
* additional properties for advanced styling. An InfoBox can also be used as a map label.
* <p>
* An InfoBox also fires the same events as a <tt>google.maps.InfoWindow</tt>.
*/
function InfoBox(opt_opts) {
opt_opts = opt_opts || {};
this.extend(InfoBox, google.maps.OverlayView);
this.content_ = opt_opts.content || "";
this.disableAutoPan_ = opt_opts.disableAutoPan || false;
this.maxWidth_ = opt_opts.maxWidth || 0;
this.pixelOffset_ = opt_opts.pixelOffset || new google.maps.Size(0, 0);
this.position_ = opt_opts.position || new google.maps.LatLng(0, 0);
this.zIndex_ = opt_opts.zIndex || null;
this.boxClass_ = opt_opts.boxClass || "infoBox";
this.boxStyle_ = opt_opts.boxStyle || {};
this.closeBoxMargin_ = opt_opts.closeBoxMargin || "2px";
this.closeBoxURL_ = opt_opts.closeBoxURL || "//www.google.com/intl/en_us/mapfiles/close.gif";
if (opt_opts.closeBoxURL === "") {
this.closeBoxURL_ = "";
}
this.closeBoxTitle_ = opt_opts.closeBoxTitle || " Close ";
this.infoBoxClearance_ = opt_opts.infoBoxClearance || new google.maps.Size(1, 1);
if (typeof opt_opts.visible === "undefined") {
if (typeof opt_opts.isHidden === "undefined") {
opt_opts.visible = true;
} else {
opt_opts.visible = !opt_opts.isHidden;
}
}
this.isHidden_ = !opt_opts.visible;
this.alignBottom_ = opt_opts.alignBottom || false;
this.pane_ = opt_opts.pane || "floatPane";
this.enableEventPropagation_ = opt_opts.enableEventPropagation || false;
this.div_ = null;
this.closeListener_ = null;
this.moveListener_ = null;
this.contextListener_ = null;
this.eventListeners_ = null;
this.fixedWidthSet_ = null;
}
InfoBox.prototype.extend = function (obj1, obj2) {
return (function (object) {
var property;
for (property in object.prototype) {
this.prototype[property] = object.prototype[property];
}
return this;
}).apply(obj1, [obj2]);
};
InfoBox.prototype.createInfoBoxDiv_ = function () {
var i;
var events;
var bw;
var me = this;
var cancelHandler = function (e) {
e.cancelBubble = true;
if (e.stopPropagation) {
e.stopPropagation();
}
};
var ignoreHandler = function (e) {
e.returnValue = false;
if (e.preventDefault) {
e.preventDefault();
}
if (!me.enableEventPropagation_) {
cancelHandler(e);
}
};
if (!this.div_) {
this.div_ = document.createElement("div");
this.setBoxStyle_();
if (typeof this.content_.nodeType === "undefined") {
this.div_.innerHTML = this.getCloseBoxImg_() + this.content_;
} else {
this.div_.innerHTML = this.getCloseBoxImg_();
this.div_.appendChild(this.content_);
}
this.getPanes()[this.pane_].appendChild(this.div_);
this.addClickHandler_();
if (this.div_.style.width) {
this.fixedWidthSet_ = true;
} else {
if (this.maxWidth_ !== 0 && this.div_.offsetWidth > this.maxWidth_) {
this.div_.style.width = this.maxWidth_;
this.div_.style.overflow = "auto";
this.fixedWidthSet_ = true;
} else {
bw = this.getBoxWidths_();
this.div_.style.width = (this.div_.offsetWidth - bw.left - bw.right) + "px";
this.fixedWidthSet_ = false;
}
}
this.panBox_(this.disableAutoPan_);
if (!this.enableEventPropagation_) {
this.eventListeners_ = [];
events = ["mousedown", "mouseover", "mouseout", "mouseup",
"click", "dblclick", "touchstart", "touchend", "touchmove"];
for (i = 0; i < events.length; i++) {
this.eventListeners_.push(google.maps.event.addDomListener(this.div_, events[i], cancelHandler));
}
this.eventListeners_.push(google.maps.event.addDomListener(this.div_, "mouseover", function (e) {
this.style.cursor = "default";
}));
}
this.contextListener_ = google.maps.event.addDomListener(this.div_, "contextmenu", ignoreHandler);
google.maps.event.trigger(this, "domready");
}
};
InfoBox.prototype.getCloseBoxImg_ = function () {
var img = "";
if (this.closeBoxURL_ !== "") {
img = "<img";
img += " src='" + this.closeBoxURL_ + "'";
img += " align=right"; // Do this because Opera chokes on style='float: right;'
img += " title='" + this.closeBoxTitle_ + "'";
img += " style='";
img += " position: relative;"; // Required by MSIE
img += " cursor: pointer;";
img += " margin: " + this.closeBoxMargin_ + ";";
img += "'>";
}
return img;
};
InfoBox.prototype.addClickHandler_ = function () {
var closeBox;
if (this.closeBoxURL_ !== "") {
closeBox = this.div_.firstChild;
this.closeListener_ = google.maps.event.addDomListener(closeBox, "click", this.getCloseClickHandler_());
} else {
this.closeListener_ = null;
}
};
InfoBox.prototype.getCloseClickHandler_ = function () {
var me = this;
return function (e) {
e.cancelBubble = true;
if (e.stopPropagation) {
e.stopPropagation();
}
google.maps.event.trigger(me, "closeclick");
me.close();
};
};
InfoBox.prototype.panBox_ = function (disablePan) {
var map;
var bounds;
var xOffset = 0, yOffset = 0;
if (!disablePan) {
map = this.getMap();
if (map instanceof google.maps.Map) {
if (!map.getBounds().contains(this.position_)) {
map.setCenter(this.position_);
}
var iwOffsetX = this.pixelOffset_.width;
var iwOffsetY = this.pixelOffset_.height;
var iwWidth = this.div_.offsetWidth;
var iwHeight = this.div_.offsetHeight;
var padX = this.infoBoxClearance_.width;
var padY = this.infoBoxClearance_.height;
if (map.panToBounds.length == 2) {
var padding = {left: 0, right: 0, top: 0, bottom: 0};
padding.left = -iwOffsetX + padX;
padding.right = iwOffsetX + iwWidth + padX;
if (this.alignBottom_) {
padding.top = -iwOffsetY + padY + iwHeight;
padding.bottom = iwOffsetY + padY;
} else {
padding.top = -iwOffsetY + padY;
padding.bottom = iwOffsetY + iwHeight + padY;
}
map.panToBounds(new google.maps.LatLngBounds(this.position_), padding);
} else {
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var pixPosition = this.getProjection().fromLatLngToContainerPixel(this.position_);
if (pixPosition.x < (-iwOffsetX + padX)) {
xOffset = pixPosition.x + iwOffsetX - padX;
} else if ((pixPosition.x + iwWidth + iwOffsetX + padX) > mapWidth) {
xOffset = pixPosition.x + iwWidth + iwOffsetX + padX - mapWidth;
}
if (this.alignBottom_) {
if (pixPosition.y < (-iwOffsetY + padY + iwHeight)) {
yOffset = pixPosition.y + iwOffsetY - padY - iwHeight;
} else if ((pixPosition.y + iwOffsetY + padY) > mapHeight) {
yOffset = pixPosition.y + iwOffsetY + padY - mapHeight;
}
} else {
if (pixPosition.y < (-iwOffsetY + padY)) {
yOffset = pixPosition.y + iwOffsetY - padY;
} else if ((pixPosition.y + iwHeight + iwOffsetY + padY) > mapHeight) {
yOffset = pixPosition.y + iwHeight + iwOffsetY + padY - mapHeight;
}
}
if (!(xOffset === 0 && yOffset === 0)) {
var c = map.getCenter();
map.panBy(xOffset, yOffset);
}
}
}
}
};
InfoBox.prototype.setBoxStyle_ = function () {
var i, boxStyle;
if (this.div_) {
this.div_.className = this.boxClass_;
this.div_.style.cssText = "";
boxStyle = this.boxStyle_;
for (i in boxStyle) {
if (boxStyle.hasOwnProperty(i)) {
this.div_.style[i] = boxStyle[i];
}
}
if ((typeof this.div_.style.WebkitTransform === "undefined") || (this.div_.style.WebkitTransform.indexOf("translateZ") === -1 && this.div_.style.WebkitTransform.indexOf("matrix") === -1)) {
this.div_.style.WebkitTransform = "translateZ(0)";
}
if (typeof this.div_.style.opacity !== "undefined" && this.div_.style.opacity !== "") {
this.div_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (this.div_.style.opacity * 100) + ")\"";
this.div_.style.filter = "alpha(opacity=" + (this.div_.style.opacity * 100) + ")";
}
this.div_.style.position = "absolute";
this.div_.style.visibility = 'hidden';
if (this.zIndex_ !== null) {
this.div_.style.zIndex = this.zIndex_;
}
}
};
InfoBox.prototype.getBoxWidths_ = function () {
var computedStyle;
var bw = {top: 0, bottom: 0, left: 0, right: 0};
var box = this.div_;
if (document.defaultView && document.defaultView.getComputedStyle) {
computedStyle = box.ownerDocument.defaultView.getComputedStyle(box, "");
if (computedStyle) {
bw.top = parseInt(computedStyle.borderTopWidth, 10) || 0;
bw.bottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
bw.left = parseInt(computedStyle.borderLeftWidth, 10) || 0;
bw.right = parseInt(computedStyle.borderRightWidth, 10) || 0;
}
} else if (document.documentElement.currentStyle) { // MSIE
if (box.currentStyle) {
bw.top = parseInt(box.currentStyle.borderTopWidth, 10) || 0;
bw.bottom = parseInt(box.currentStyle.borderBottomWidth, 10) || 0;
bw.left = parseInt(box.currentStyle.borderLeftWidth, 10) || 0;
bw.right = parseInt(box.currentStyle.borderRightWidth, 10) || 0;
}
}
return bw;
};
InfoBox.prototype.onRemove = function () {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
InfoBox.prototype.draw = function () {
this.createInfoBoxDiv_();
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.position_);
this.div_.style.left = (pixPosition.x + this.pixelOffset_.width) + "px";
if (this.alignBottom_) {
this.div_.style.bottom = -(pixPosition.y + this.pixelOffset_.height) + "px";
} else {
this.div_.style.top = (pixPosition.y + this.pixelOffset_.height) + "px";
}
if (this.isHidden_) {
this.div_.style.visibility = "hidden";
} else {
this.div_.style.visibility = "visible";
}
};
InfoBox.prototype.setOptions = function (opt_opts) {
if (typeof opt_opts.boxClass !== "undefined") { // Must be first
this.boxClass_ = opt_opts.boxClass;
this.setBoxStyle_();
}
if (typeof opt_opts.boxStyle !== "undefined") { // Must be second
this.boxStyle_ = opt_opts.boxStyle;
this.setBoxStyle_();
}
if (typeof opt_opts.content !== "undefined") {
this.setContent(opt_opts.content);
}
if (typeof opt_opts.disableAutoPan !== "undefined") {
this.disableAutoPan_ = opt_opts.disableAutoPan;
}
if (typeof opt_opts.maxWidth !== "undefined") {
this.maxWidth_ = opt_opts.maxWidth;
}
if (typeof opt_opts.pixelOffset !== "undefined") {
this.pixelOffset_ = opt_opts.pixelOffset;
}
if (typeof opt_opts.alignBottom !== "undefined") {
this.alignBottom_ = opt_opts.alignBottom;
}
if (typeof opt_opts.position !== "undefined") {
this.setPosition(opt_opts.position);
}
if (typeof opt_opts.zIndex !== "undefined") {
this.setZIndex(opt_opts.zIndex);
}
if (typeof opt_opts.closeBoxMargin !== "undefined") {
this.closeBoxMargin_ = opt_opts.closeBoxMargin;
}
if (typeof opt_opts.closeBoxURL !== "undefined") {
this.closeBoxURL_ = opt_opts.closeBoxURL;
}
if (typeof opt_opts.closeBoxTitle !== "undefined") {
this.closeBoxTitle_ = opt_opts.closeBoxTitle;
}
if (typeof opt_opts.infoBoxClearance !== "undefined") {
this.infoBoxClearance_ = opt_opts.infoBoxClearance;
}
if (typeof opt_opts.isHidden !== "undefined") {
this.isHidden_ = opt_opts.isHidden;
}
if (typeof opt_opts.visible !== "undefined") {
this.isHidden_ = !opt_opts.visible;
}
if (typeof opt_opts.enableEventPropagation !== "undefined") {
this.enableEventPropagation_ = opt_opts.enableEventPropagation;
}
if (this.div_) {
this.draw();
}
};
InfoBox.prototype.setContent = function (content) {
this.content_ = content;
if (this.div_) {
if (this.closeListener_) {
google.maps.event.removeListener(this.closeListener_);
this.closeListener_ = null;
}
if (!this.fixedWidthSet_) {
this.div_.style.width = "";
}
if (typeof content.nodeType === "undefined") {
this.div_.innerHTML = this.getCloseBoxImg_() + content;
} else {
this.div_.innerHTML = this.getCloseBoxImg_();
this.div_.appendChild(content);
}
if (!this.fixedWidthSet_) {
this.div_.style.width = this.div_.offsetWidth + "px";
if (typeof content.nodeType === "undefined") {
this.div_.innerHTML = this.getCloseBoxImg_() + content;
} else {
this.div_.innerHTML = this.getCloseBoxImg_();
this.div_.appendChild(content);
}
}
this.addClickHandler_();
}
google.maps.event.trigger(this, "content_changed");
};
InfoBox.prototype.setPosition = function (latlng) {
this.position_ = latlng;
if (this.div_) {
this.draw();
}
google.maps.event.trigger(this, "position_changed");
};
InfoBox.prototype.setZIndex = function (index) {
this.zIndex_ = index;
if (this.div_) {
this.div_.style.zIndex = index;
}
google.maps.event.trigger(this, "zindex_changed");
};
InfoBox.prototype.setVisible = function (isVisible) {
this.isHidden_ = !isVisible;
if (this.div_) {
this.div_.style.visibility = (this.isHidden_ ? "hidden" : "visible");
}
};
InfoBox.prototype.getContent = function () {
return this.content_;
};
InfoBox.prototype.getPosition = function () {
return this.position_;
};
InfoBox.prototype.getZIndex = function () {
return this.zIndex_;
};
InfoBox.prototype.getVisible = function () {
var isVisible;
if ((typeof this.getMap() === "undefined") || (this.getMap() === null)) {
isVisible = false;
} else {
isVisible = !this.isHidden_;
}
return isVisible;
};
InfoBox.prototype.getWidth = function () {
var width = null;
if (this.div_) {
width = this.div_.offsetWidth;
}
return width;
};
InfoBox.prototype.getHeight = function () {
var height = null;
if (this.div_) {
height = this.div_.offsetHeight;
}
return height;
};
InfoBox.prototype.show = function () {
this.isHidden_ = false;
if (this.div_) {
this.div_.style.visibility = "visible";
}
};
InfoBox.prototype.hide = function () {
this.isHidden_ = true;
if (this.div_) {
this.div_.style.visibility = "hidden";
}
};
InfoBox.prototype.open = function (map, anchor) {
var me = this;
if (anchor) {
this.setPosition(anchor.getPosition()); // BUG FIX 2/17/2018: needed for v3.32
this.moveListener_ = google.maps.event.addListener(anchor, "position_changed", function () {
me.setPosition(this.getPosition());
});
}
this.setMap(map);
if (this.div_) {
this.panBox_(this.disableAutoPan_); // BUG FIX 2/17/2018: add missing parameter
}
};
InfoBox.prototype.close = function () {
var i;
if (this.closeListener_) {
google.maps.event.removeListener(this.closeListener_);
this.closeListener_ = null;
}
if (this.eventListeners_) {
for (i = 0; i < this.eventListeners_.length; i++) {
google.maps.event.removeListener(this.eventListeners_[i]);
}
this.eventListeners_ = null;
}
if (this.moveListener_) {
google.maps.event.removeListener(this.moveListener_);
this.moveListener_ = null;
}
if (this.contextListener_) {
google.maps.event.removeListener(this.contextListener_);
this.contextListener_ = null;
}
this.setMap(null);
};
if (typeof module == 'object') {
module.exports = { default: InfoBox, InfoBox: InfoBox };
}