From 4cf3b730b6cde7cd297bf7e63b5f86c869475833 Mon Sep 17 00:00:00 2001 From: andrei <фкрфт89"пьфшдюсщь> Date: Fri, 16 Feb 2018 15:36:38 +0300 Subject: [PATCH 1/2] MarkerWithLabel fix for latest maps version --- index.js | 1065 +++++++++++++++++++++++++++--------------------------- 1 file changed, 539 insertions(+), 526 deletions(-) diff --git a/index.js b/index.js index e084e8f..a4db1bf 100644 --- a/index.js +++ b/index.js @@ -33,6 +33,7 @@ */ /*jslint browser:true */ + /*global document,google */ /** @@ -40,556 +41,568 @@ * @param {Function} parentCtor Parent class. */ function inherits(childCtor, parentCtor) { - /** @constructor */ - function tempCtor() {}; - tempCtor.prototype = parentCtor.prototype; - childCtor.superClass_ = parentCtor.prototype; - childCtor.prototype = new tempCtor(); - /** @override */ - childCtor.prototype.constructor = childCtor; + /** @constructor */ + function tempCtor() { + }; + tempCtor.prototype = parentCtor.prototype; + childCtor.superClass_ = parentCtor.prototype; + childCtor.prototype = new tempCtor(); + /** @override */ + childCtor.prototype.constructor = childCtor; } /** * @param {Object} gMapsApi The Google Maps API instance (usually `google.maps`) * @return {Function} The instantiable MarkerWithLabel class */ -module.exports = function(gMapsApi) { - - /** - * This constructor creates a label and associates it with a marker. - * It is for the private use of the MarkerWithLabel class. - * @constructor - * @param {Marker} marker The marker with which the label is to be associated. - * @param {string} crossURL The URL of the cross image =. - * @param {string} handCursor The URL of the hand cursor. - * @private - */ - function MarkerLabel_(marker, crossURL, handCursorURL) { - this.marker_ = marker; - this.handCursorURL_ = marker.handCursorURL; - - this.labelDiv_ = document.createElement("div"); - this.labelDiv_.style.cssText = "position: absolute; overflow: hidden;"; - - // Set up the DIV for handling mouse events in the label. This DIV forms a transparent veil - // in the "overlayMouseTarget" pane, a veil that covers just the label. This is done so that - // events can be captured even if the label is in the shadow of a google.maps.InfoWindow. - // Code is included here to ensure the veil is always exactly the same size as the label. - this.eventDiv_ = document.createElement("div"); - this.eventDiv_.style.cssText = this.labelDiv_.style.cssText; - - // This is needed for proper behavior on MSIE: - this.eventDiv_.addEventListener('selectstart', function() { return false; }); - this.eventDiv_.addEventListener('dragstart', function() { return false; }); - - // Get the DIV for the "X" to be displayed when the marker is raised. - this.crossDiv_ = MarkerLabel_.getSharedCross(crossURL); - } - inherits(MarkerLabel_, gMapsApi.OverlayView); - - /** - * Returns the DIV for the cross used when dragging a marker when the - * raiseOnDrag parameter set to true. One cross is shared with all markers. - * @param {string} crossURL The URL of the cross image =. - * @private - */ - MarkerLabel_.getSharedCross = function (crossURL) { - var div; - if (typeof MarkerLabel_.getSharedCross.crossDiv === "undefined") { - div = document.createElement("img"); - div.style.cssText = "position: absolute; z-index: 1000002; display: none;"; - // Hopefully Google never changes the standard "X" attributes: - div.style.marginLeft = "-8px"; - div.style.marginTop = "-9px"; - div.src = crossURL; - MarkerLabel_.getSharedCross.crossDiv = div; +module.exports = function (gMapsApi) { + + /** + * This constructor creates a label and associates it with a marker. + * It is for the private use of the MarkerWithLabel class. + * @constructor + * @param {Marker} marker The marker with which the label is to be associated. + * @param {string} crossURL The URL of the cross image =. + * @param {string} handCursor The URL of the hand cursor. + * @private + */ + function MarkerLabel_(marker, crossURL, handCursorURL) { + this.marker_ = marker; + this.handCursorURL_ = marker.handCursorURL; + + this.labelDiv_ = document.createElement("div"); + this.labelDiv_.style.cssText = "position: absolute; overflow: hidden;"; + + // Set up the DIV for handling mouse events in the label. This DIV forms a transparent veil + // in the "overlayMouseTarget" pane, a veil that covers just the label. This is done so that + // events can be captured even if the label is in the shadow of a google.maps.InfoWindow. + // Code is included here to ensure the veil is always exactly the same size as the label. + this.eventDiv_ = document.createElement("div"); + this.eventDiv_.style.cssText = this.labelDiv_.style.cssText; + + // This is needed for proper behavior on MSIE: + this.eventDiv_.addEventListener('selectstart', function () { + return false; + }); + this.eventDiv_.addEventListener('dragstart', function () { + return false; + }); + + // Get the DIV for the "X" to be displayed when the marker is raised. + this.crossDiv_ = MarkerLabel_.getSharedCross(crossURL); } - return MarkerLabel_.getSharedCross.crossDiv; - }; - - /** - * Adds the DIV representing the label to the DOM. This method is called - * automatically when the marker's setMap method is called. - * @private - */ - MarkerLabel_.prototype.onAdd = function () { - var me = this; - var cMouseIsDown = false; - var cDraggingLabel = false; - var cSavedZIndex; - var cLatOffset, cLngOffset; - var cIgnoreClick; - var cRaiseEnabled; - var cStartPosition; - var cStartCenter; - // Constants: - var cRaiseOffset = 20; - var cDraggingCursor = "url(" + this.handCursorURL_ + ")"; - - // Stops all processing of an event. - // - var cAbortEvent = function (e) { - if (e.preventDefault) { - e.preventDefault(); - } - e.cancelBubble = true; - if (e.stopPropagation) { - e.stopPropagation(); - } - }; - var cStopBounce = function () { - me.marker_.setAnimation(null); + inherits(MarkerLabel_, gMapsApi.OverlayView); + + /** + * Returns the DIV for the cross used when dragging a marker when the + * raiseOnDrag parameter set to true. One cross is shared with all markers. + * @param {string} crossURL The URL of the cross image =. + * @private + */ + MarkerLabel_.getSharedCross = function (crossURL) { + var div; + if (typeof MarkerLabel_.getSharedCross.crossDiv === "undefined") { + div = document.createElement("img"); + div.style.cssText = "position: absolute; z-index: 1000002; display: none;"; + // Hopefully Google never changes the standard "X" attributes: + div.style.marginLeft = "-8px"; + div.style.marginTop = "-9px"; + div.src = crossURL; + MarkerLabel_.getSharedCross.crossDiv = div; + } + return MarkerLabel_.getSharedCross.crossDiv; }; - this.getPanes().markerLayer.appendChild(this.labelDiv_); - this.getPanes().overlayMouseTarget.appendChild(this.eventDiv_); - // One cross is shared with all markers, so only add it once: - if (typeof MarkerLabel_.getSharedCross.processed === "undefined") { - this.getPanes().markerLayer.appendChild(this.crossDiv_); - MarkerLabel_.getSharedCross.processed = true; - } + /** + * Adds the DIV representing the label to the DOM. This method is called + * automatically when the marker's setMap method is called. + * @private + */ + MarkerLabel_.prototype.onAdd = function () { + var me = this; + var cMouseIsDown = false; + var cDraggingLabel = false; + var cSavedZIndex; + var cLatOffset, cLngOffset; + var cIgnoreClick; + var cRaiseEnabled; + var cStartPosition; + var cStartCenter; + // Constants: + var cRaiseOffset = 20; + var cDraggingCursor = "url(" + this.handCursorURL_ + ")"; + + // Stops all processing of an event. + // + var cAbortEvent = function (e) { + if (e.preventDefault) { + e.preventDefault(); + } + e.cancelBubble = true; + if (e.stopPropagation) { + e.stopPropagation(); + } + }; + + var cStopBounce = function () { + me.marker_.setAnimation(null); + }; + + this.getPanes().markerLayer.appendChild(this.labelDiv_); + this.getPanes().overlayMouseTarget.appendChild(this.eventDiv_); + // One cross is shared with all markers, so only add it once: + if (typeof MarkerLabel_.getSharedCross.processed === "undefined") { + this.getPanes().markerLayer.appendChild(this.crossDiv_); + MarkerLabel_.getSharedCross.processed = true; + } - this.listeners_ = [ - gMapsApi.event.addDomListener(this.eventDiv_, "mouseover", function (e) { - if (me.marker_.getDraggable() || me.marker_.getClickable()) { - this.style.cursor = "pointer"; - gMapsApi.event.trigger(me.marker_, "mouseover", e); + this.listeners_ = [ + gMapsApi.event.addDomListener(this.eventDiv_, "mouseover", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + this.style.cursor = "pointer"; + gMapsApi.event.trigger(me.marker_, "mouseover", e); + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "mouseout", function (e) { + if ((me.marker_.getDraggable() || me.marker_.getClickable()) && !cDraggingLabel) { + this.style.cursor = me.marker_.getCursor(); + gMapsApi.event.trigger(me.marker_, "mouseout", e); + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "mousedown", function (e) { + cDraggingLabel = false; + if (me.marker_.getDraggable()) { + cMouseIsDown = true; + this.style.cursor = cDraggingCursor; + } + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + gMapsApi.event.trigger(me.marker_, "mousedown", e); + cAbortEvent(e); // Prevent map pan when starting a drag on a label + } + }), + gMapsApi.event.addDomListener(document, "mouseup", function (mEvent) { + var position; + if (cMouseIsDown) { + cMouseIsDown = false; + me.eventDiv_.style.cursor = "pointer"; + gMapsApi.event.trigger(me.marker_, "mouseup", mEvent); + } + if (cDraggingLabel) { + if (cRaiseEnabled) { // Lower the marker & label + position = me.getProjection().fromLatLngToDivPixel(me.marker_.getPosition()); + position.y += cRaiseOffset; + me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); + // This is not the same bouncing style as when the marker portion is dragged, + // but it will have to do: + try { // Will fail if running Google Maps API earlier than V3.3 + me.marker_.setAnimation(gMapsApi.Animation.BOUNCE); + setTimeout(cStopBounce, 1406); + } catch (e) { + } + } + me.crossDiv_.style.display = "none"; + me.marker_.setZIndex(cSavedZIndex); + cIgnoreClick = true; // Set flag to ignore the click event reported after a label drag + cDraggingLabel = false; + mEvent.latLng = me.marker_.getPosition(); + gMapsApi.event.trigger(me.marker_, "dragend", mEvent); + } + }), + gMapsApi.event.addListener(me.marker_.getMap(), "mousemove", function (mEvent) { + var position; + if (cMouseIsDown) { + if (cDraggingLabel) { + // Change the reported location from the mouse position to the marker position: + mEvent.latLng = new gMapsApi.LatLng(mEvent.latLng.lat() - cLatOffset, mEvent.latLng.lng() - cLngOffset); + position = me.getProjection().fromLatLngToDivPixel(mEvent.latLng); + if (cRaiseEnabled) { + me.crossDiv_.style.left = position.x + "px"; + me.crossDiv_.style.top = position.y + "px"; + me.crossDiv_.style.display = ""; + position.y -= cRaiseOffset; + } + me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); + if (cRaiseEnabled) { // Don't raise the veil; this hack needed to make MSIE act properly + me.eventDiv_.style.top = (position.y + cRaiseOffset) + "px"; + } + gMapsApi.event.trigger(me.marker_, "drag", mEvent); + } else { + // Calculate offsets from the click point to the marker position: + cLatOffset = mEvent.latLng.lat() - me.marker_.getPosition().lat(); + cLngOffset = mEvent.latLng.lng() - me.marker_.getPosition().lng(); + cSavedZIndex = me.marker_.getZIndex(); + cStartPosition = me.marker_.getPosition(); + cStartCenter = me.marker_.getMap().getCenter(); + cRaiseEnabled = me.marker_.get("raiseOnDrag"); + cDraggingLabel = true; + me.marker_.setZIndex(1000000); // Moves the marker & label to the foreground during a drag + mEvent.latLng = me.marker_.getPosition(); + gMapsApi.event.trigger(me.marker_, "dragstart", mEvent); + } + } + }), + gMapsApi.event.addDomListener(document, "keydown", function (e) { + if (cDraggingLabel) { + if (e.keyCode === 27) { // Esc key + cRaiseEnabled = false; + me.marker_.setPosition(cStartPosition); + me.marker_.getMap().setCenter(cStartCenter); + gMapsApi.event.trigger(document, "mouseup", e); + } + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "click", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + if (cIgnoreClick) { // Ignore the click reported when a label drag ends + cIgnoreClick = false; + } else { + gMapsApi.event.trigger(me.marker_, "click", e); + cAbortEvent(e); // Prevent click from being passed on to map + } + } + }), + gMapsApi.event.addDomListener(this.eventDiv_, "dblclick", function (e) { + if (me.marker_.getDraggable() || me.marker_.getClickable()) { + gMapsApi.event.trigger(me.marker_, "dblclick", e); + cAbortEvent(e); // Prevent map zoom when double-clicking on a label + } + }), + gMapsApi.event.addListener(this.marker_, "dragstart", function (mEvent) { + if (!cDraggingLabel) { + cRaiseEnabled = this.get("raiseOnDrag"); + } + }), + gMapsApi.event.addListener(this.marker_, "drag", function (mEvent) { + if (!cDraggingLabel) { + if (cRaiseEnabled) { + me.setPosition(cRaiseOffset); + // During a drag, the marker's z-index is temporarily set to 1000000 to + // ensure it appears above all other markers. Also set the label's z-index + // to 1000000 (plus or minus 1 depending on whether the label is supposed + // to be above or below the marker). + me.labelDiv_.style.zIndex = 1000000 + (this.get("labelInBackground") ? -1 : +1); + } + } + }), + gMapsApi.event.addListener(this.marker_, "dragend", function (mEvent) { + if (!cDraggingLabel) { + if (cRaiseEnabled) { + me.setPosition(0); // Also restores z-index of label + } + } + }), + gMapsApi.event.addListener(this.marker_, "position_changed", function () { + me.setPosition(); + }), + gMapsApi.event.addListener(this.marker_, "zindex_changed", function () { + me.setZIndex(); + }), + gMapsApi.event.addListener(this.marker_, "visible_changed", function () { + me.setVisible(); + }), + gMapsApi.event.addListener(this.marker_, "labelvisible_changed", function () { + me.setVisible(); + }), + gMapsApi.event.addListener(this.marker_, "title_changed", function () { + me.setTitle(); + }), + gMapsApi.event.addListener(this.marker_, "labelcontent_changed", function () { + me.setContent(); + }), + gMapsApi.event.addListener(this.marker_, "labelanchor_changed", function () { + me.setAnchor(); + }), + gMapsApi.event.addListener(this.marker_, "labelclass_changed", function () { + me.setStyles(); + }), + gMapsApi.event.addListener(this.marker_, "labelstyle_changed", function () { + me.setStyles(); + }) + ]; + }; + + /** + * Removes the DIV for the label from the DOM. It also removes all event handlers. + * This method is called automatically when the marker's setMap(null) + * method is called. + * @private + */ + MarkerLabel_.prototype.onRemove = function () { + var i; + if (this.labelDiv_.parentNode) { + this.labelDiv_.parentNode.removeChild(this.labelDiv_); } - }), - gMapsApi.event.addDomListener(this.eventDiv_, "mouseout", function (e) { - if ((me.marker_.getDraggable() || me.marker_.getClickable()) && !cDraggingLabel) { - this.style.cursor = me.marker_.getCursor(); - gMapsApi.event.trigger(me.marker_, "mouseout", e); + this.eventDiv_.parentNode.removeChild(this.eventDiv_); + + // Remove event listeners: + if (this.listeners_) { + for (i = 0; i < this.listeners_.length; i++) { + gMapsApi.event.removeListener(this.listeners_[i]); + } } - }), - gMapsApi.event.addDomListener(this.eventDiv_, "mousedown", function (e) { - cDraggingLabel = false; - if (me.marker_.getDraggable()) { - cMouseIsDown = true; - this.style.cursor = cDraggingCursor; + }; + + /** + * Draws the label on the map. + * @private + */ + MarkerLabel_.prototype.draw = function () { + this.setContent(); + this.setTitle(); + this.setStyles(); + }; + + /** + * Sets the content of the label. + * The content can be plain text or an HTML DOM node. + * @private + */ + MarkerLabel_.prototype.setContent = function () { + var content = this.marker_.get("labelContent"); + if (typeof content.nodeType === "undefined") { + this.labelDiv_.innerHTML = content; + this.eventDiv_.innerHTML = this.labelDiv_.innerHTML; + } else { + // Remove current content + while (this.labelDiv_.lastChild) { + this.labelDiv_.removeChild(this.labelDiv_.lastChild); + } + + while (this.eventDiv_.lastChild) { + this.eventDiv_.removeChild(this.eventDiv_.lastChild); + } + + this.labelDiv_.appendChild(content); + content = content.cloneNode(true); + this.eventDiv_.appendChild(content); } - if (me.marker_.getDraggable() || me.marker_.getClickable()) { - gMapsApi.event.trigger(me.marker_, "mousedown", e); - cAbortEvent(e); // Prevent map pan when starting a drag on a label + }; + + /** + * Sets the content of the tool tip for the label. It is + * always set to be the same as for the marker itself. + * @private + */ + MarkerLabel_.prototype.setTitle = function () { + this.eventDiv_.title = this.marker_.getTitle() || ""; + }; + + /** + * Sets the style of the label by setting the style sheet and applying + * other specific styles requested. + * @private + */ + MarkerLabel_.prototype.setStyles = function () { + var i, labelStyle; + + // Apply style values from the style sheet defined in the labelClass parameter: + this.labelDiv_.className = this.marker_.get("labelClass"); + this.eventDiv_.className = this.labelDiv_.className; + + // Clear existing inline style values: + this.labelDiv_.style.cssText = ""; + this.eventDiv_.style.cssText = ""; + // Apply style values defined in the labelStyle parameter: + labelStyle = this.marker_.get("labelStyle"); + for (i in labelStyle) { + if (labelStyle.hasOwnProperty(i)) { + this.labelDiv_.style[i] = labelStyle[i]; + this.eventDiv_.style[i] = labelStyle[i]; + } } - }), - gMapsApi.event.addDomListener(document, "mouseup", function (mEvent) { - var position; - if (cMouseIsDown) { - cMouseIsDown = false; - me.eventDiv_.style.cursor = "pointer"; - gMapsApi.event.trigger(me.marker_, "mouseup", mEvent); + this.setMandatoryStyles(); + }; + + /** + * Sets the mandatory styles to the DIV representing the label as well as to the + * associated event DIV. This includes setting the DIV position, z-index, and visibility. + * @private + */ + MarkerLabel_.prototype.setMandatoryStyles = function () { + this.labelDiv_.style.position = "absolute"; + this.labelDiv_.style.overflow = "hidden"; + // Make sure the opacity setting causes the desired effect on MSIE: + if (typeof this.labelDiv_.style.opacity !== "undefined" && this.labelDiv_.style.opacity !== "") { + this.labelDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")\""; + this.labelDiv_.style.filter = "alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")"; } - if (cDraggingLabel) { - if (cRaiseEnabled) { // Lower the marker & label - position = me.getProjection().fromLatLngToDivPixel(me.marker_.getPosition()); - position.y += cRaiseOffset; - me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); - // This is not the same bouncing style as when the marker portion is dragged, - // but it will have to do: - try { // Will fail if running Google Maps API earlier than V3.3 - me.marker_.setAnimation(gMapsApi.Animation.BOUNCE); - setTimeout(cStopBounce, 1406); - } catch (e) {} - } - me.crossDiv_.style.display = "none"; - me.marker_.setZIndex(cSavedZIndex); - cIgnoreClick = true; // Set flag to ignore the click event reported after a label drag - cDraggingLabel = false; - mEvent.latLng = me.marker_.getPosition(); - gMapsApi.event.trigger(me.marker_, "dragend", mEvent); + + this.eventDiv_.style.position = this.labelDiv_.style.position; + this.eventDiv_.style.overflow = this.labelDiv_.style.overflow; + this.eventDiv_.style.opacity = 0.01; // Don't use 0; DIV won't be clickable on MSIE + this.eventDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=1)\""; + this.eventDiv_.style.filter = "alpha(opacity=1)"; // For MSIE + + this.setAnchor(); + this.setPosition(); // This also updates z-index, if necessary. + this.setVisible(); + }; + + /** + * Sets the anchor point of the label. + * @private + */ + MarkerLabel_.prototype.setAnchor = function () { + var anchor = this.marker_.get("labelAnchor"); + this.labelDiv_.style.marginLeft = -anchor.x + "px"; + this.labelDiv_.style.marginTop = -anchor.y + "px"; + this.eventDiv_.style.marginLeft = -anchor.x + "px"; + this.eventDiv_.style.marginTop = -anchor.y + "px"; + }; + + /** + * Sets the position of the label. The z-index is also updated, if necessary. + * @private + */ + MarkerLabel_.prototype.setPosition = function (yOffset) { + var position = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition()); + if (typeof yOffset === "undefined") { + yOffset = 0; } - }), - gMapsApi.event.addListener(me.marker_.getMap(), "mousemove", function (mEvent) { - var position; - if (cMouseIsDown) { - if (cDraggingLabel) { - // Change the reported location from the mouse position to the marker position: - mEvent.latLng = new gMapsApi.LatLng(mEvent.latLng.lat() - cLatOffset, mEvent.latLng.lng() - cLngOffset); - position = me.getProjection().fromLatLngToDivPixel(mEvent.latLng); - if (cRaiseEnabled) { - me.crossDiv_.style.left = position.x + "px"; - me.crossDiv_.style.top = position.y + "px"; - me.crossDiv_.style.display = ""; - position.y -= cRaiseOffset; - } - me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position)); - if (cRaiseEnabled) { // Don't raise the veil; this hack needed to make MSIE act properly - me.eventDiv_.style.top = (position.y + cRaiseOffset) + "px"; - } - gMapsApi.event.trigger(me.marker_, "drag", mEvent); - } else { - // Calculate offsets from the click point to the marker position: - cLatOffset = mEvent.latLng.lat() - me.marker_.getPosition().lat(); - cLngOffset = mEvent.latLng.lng() - me.marker_.getPosition().lng(); - cSavedZIndex = me.marker_.getZIndex(); - cStartPosition = me.marker_.getPosition(); - cStartCenter = me.marker_.getMap().getCenter(); - cRaiseEnabled = me.marker_.get("raiseOnDrag"); - cDraggingLabel = true; - me.marker_.setZIndex(1000000); // Moves the marker & label to the foreground during a drag - mEvent.latLng = me.marker_.getPosition(); - gMapsApi.event.trigger(me.marker_, "dragstart", mEvent); - } + this.labelDiv_.style.left = Math.round(position.x) + "px"; + this.labelDiv_.style.top = Math.round(position.y - yOffset) + "px"; + this.eventDiv_.style.left = this.labelDiv_.style.left; + this.eventDiv_.style.top = this.labelDiv_.style.top; + + this.setZIndex(); + }; + + /** + * Sets the z-index of the label. If the marker's z-index property has not been defined, the z-index + * of the label is set to the vertical coordinate of the label. This is in keeping with the default + * stacking order for Google Maps: markers to the south are in front of markers to the north. + * @private + */ + MarkerLabel_.prototype.setZIndex = function () { + var zAdjust = (this.marker_.get("labelInBackground") ? -1 : +1); + if (typeof this.marker_.getZIndex() === "undefined") { + this.labelDiv_.style.zIndex = parseInt(this.labelDiv_.style.top, 10) + zAdjust; + this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; + } else { + this.labelDiv_.style.zIndex = this.marker_.getZIndex() + zAdjust; + this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; } - }), - gMapsApi.event.addDomListener(document, "keydown", function (e) { - if (cDraggingLabel) { - if (e.keyCode === 27) { // Esc key - cRaiseEnabled = false; - me.marker_.setPosition(cStartPosition); - me.marker_.getMap().setCenter(cStartCenter); - gMapsApi.event.trigger(document, "mouseup", e); - } + }; + + /** + * Sets the visibility of the label. The label is visible only if the marker itself is + * visible (i.e., its visible property is true) and the labelVisible property is true. + * @private + */ + MarkerLabel_.prototype.setVisible = function () { + if (this.marker_.get("labelVisible")) { + this.labelDiv_.style.display = this.marker_.getVisible() ? "block" : "none"; + } else { + this.labelDiv_.style.display = "none"; } - }), - gMapsApi.event.addDomListener(this.eventDiv_, "click", function (e) { - if (me.marker_.getDraggable() || me.marker_.getClickable()) { - if (cIgnoreClick) { // Ignore the click reported when a label drag ends - cIgnoreClick = false; - } else { - gMapsApi.event.trigger(me.marker_, "click", e); - cAbortEvent(e); // Prevent click from being passed on to map - } + this.eventDiv_.style.display = this.labelDiv_.style.display; + }; + + /** + * @name MarkerWithLabelOptions + * @class This class represents the optional parameter passed to the {@link MarkerWithLabel} constructor. + * The properties available are the same as for google.maps.Marker with the addition + * of the properties listed below. To change any of these additional properties after the labeled + * marker has been created, call google.maps.Marker.set(propertyName, propertyValue). + *

+ * When any of these properties changes, a property changed event is fired. The names of these + * events are derived from the name of the property and are of the form propertyname_changed. + * For example, if the content of the label changes, a labelcontent_changed event + * is fired. + *

+ * @property {string|Node} [labelContent] The content of the label (plain text or an HTML DOM node). + * @property {Point} [labelAnchor] By default, a label is drawn with its anchor point at (0,0) so + * that its top left corner is positioned at the anchor point of the associated marker. Use this + * property to change the anchor point of the label. For example, to center a 50px-wide label + * beneath a marker, specify a labelAnchor of google.maps.Point(25, 0). + * (Note: x-values increase to the right and y-values increase to the top.) + * @property {string} [labelClass] The name of the CSS class defining the styles for the label. + * Note that style values for position, overflow, top, + * left, zIndex, display, marginLeft, and + * marginTop are ignored; these styles are for internal use only. + * @property {Object} [labelStyle] An object literal whose properties define specific CSS + * style values to be applied to the label. Style values defined here override those that may + * be defined in the labelClass style sheet. If this property is changed after the + * label has been created, all previously set styles (except those defined in the style sheet) + * are removed from the label before the new style values are applied. + * Note that style values for position, overflow, top, + * left, zIndex, display, marginLeft, and + * marginTop are ignored; these styles are for internal use only. + * @property {boolean} [labelInBackground] A flag indicating whether a label that overlaps its + * associated marker should appear in the background (i.e., in a plane below the marker). + * The default is false, which causes the label to appear in the foreground. + * @property {boolean} [labelVisible] A flag indicating whether the label is to be visible. + * The default is true. Note that even if labelVisible is + * true, the label will not be visible unless the associated marker is also + * visible (i.e., unless the marker's visible property is true). + * @property {boolean} [raiseOnDrag] A flag indicating whether the label and marker are to be + * raised when the marker is dragged. The default is true. If a draggable marker is + * being created and a version of Google Maps API earlier than V3.3 is being used, this property + * must be set to false. + * @property {boolean} [optimized] A flag indicating whether rendering is to be optimized for the + * marker. Important: The optimized rendering technique is not supported by MarkerWithLabel, + * so the value of this parameter is always forced to false. + * @property {string} [crossImage="http://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"] + * The URL of the cross image to be displayed while dragging a marker. + * @property {string} [handCursor="http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"] + * The URL of the cursor to be displayed while dragging a marker. + */ + /** + * Creates a MarkerWithLabel with the options specified in {@link MarkerWithLabelOptions}. + * @constructor + * @param {MarkerWithLabelOptions} [opt_options] The optional parameters. + */ + function MarkerWithLabel(opt_options) { + opt_options = opt_options || {}; + opt_options.labelContent = opt_options.labelContent || ""; + opt_options.labelAnchor = opt_options.labelAnchor || new gMapsApi.Point(0, 0); + opt_options.labelClass = opt_options.labelClass || "markerLabels"; + opt_options.labelStyle = opt_options.labelStyle || {}; + opt_options.labelInBackground = opt_options.labelInBackground || false; + if (typeof opt_options.labelVisible === "undefined") { + opt_options.labelVisible = true; } - }), - gMapsApi.event.addDomListener(this.eventDiv_, "dblclick", function (e) { - if (me.marker_.getDraggable() || me.marker_.getClickable()) { - gMapsApi.event.trigger(me.marker_, "dblclick", e); - cAbortEvent(e); // Prevent map zoom when double-clicking on a label + if (typeof opt_options.raiseOnDrag === "undefined") { + opt_options.raiseOnDrag = true; } - }), - gMapsApi.event.addListener(this.marker_, "dragstart", function (mEvent) { - if (!cDraggingLabel) { - cRaiseEnabled = this.get("raiseOnDrag"); + if (typeof opt_options.clickable === "undefined") { + opt_options.clickable = true; } - }), - gMapsApi.event.addListener(this.marker_, "drag", function (mEvent) { - if (!cDraggingLabel) { - if (cRaiseEnabled) { - me.setPosition(cRaiseOffset); - // During a drag, the marker's z-index is temporarily set to 1000000 to - // ensure it appears above all other markers. Also set the label's z-index - // to 1000000 (plus or minus 1 depending on whether the label is supposed - // to be above or below the marker). - me.labelDiv_.style.zIndex = 1000000 + (this.get("labelInBackground") ? -1 : +1); - } + if (typeof opt_options.draggable === "undefined") { + opt_options.draggable = false; } - }), - gMapsApi.event.addListener(this.marker_, "dragend", function (mEvent) { - if (!cDraggingLabel) { - if (cRaiseEnabled) { - me.setPosition(0); // Also restores z-index of label - } + if (typeof opt_options.optimized === "undefined") { + opt_options.optimized = false; } - }), - gMapsApi.event.addListener(this.marker_, "position_changed", function () { - me.setPosition(); - }), - gMapsApi.event.addListener(this.marker_, "zindex_changed", function () { - me.setZIndex(); - }), - gMapsApi.event.addListener(this.marker_, "visible_changed", function () { - me.setVisible(); - }), - gMapsApi.event.addListener(this.marker_, "labelvisible_changed", function () { - me.setVisible(); - }), - gMapsApi.event.addListener(this.marker_, "title_changed", function () { - me.setTitle(); - }), - gMapsApi.event.addListener(this.marker_, "labelcontent_changed", function () { - me.setContent(); - }), - gMapsApi.event.addListener(this.marker_, "labelanchor_changed", function () { - me.setAnchor(); - }), - gMapsApi.event.addListener(this.marker_, "labelclass_changed", function () { - me.setStyles(); - }), - gMapsApi.event.addListener(this.marker_, "labelstyle_changed", function () { - me.setStyles(); - }) - ]; - }; - - /** - * Removes the DIV for the label from the DOM. It also removes all event handlers. - * This method is called automatically when the marker's setMap(null) - * method is called. - * @private - */ - MarkerLabel_.prototype.onRemove = function () { - var i; - this.labelDiv_.parentNode.removeChild(this.labelDiv_); - this.eventDiv_.parentNode.removeChild(this.eventDiv_); - - // Remove event listeners: - for (i = 0; i < this.listeners_.length; i++) { - gMapsApi.event.removeListener(this.listeners_[i]); - } - }; - - /** - * Draws the label on the map. - * @private - */ - MarkerLabel_.prototype.draw = function () { - this.setContent(); - this.setTitle(); - this.setStyles(); - }; - - /** - * Sets the content of the label. - * The content can be plain text or an HTML DOM node. - * @private - */ - MarkerLabel_.prototype.setContent = function () { - var content = this.marker_.get("labelContent"); - if (typeof content.nodeType === "undefined") { - this.labelDiv_.innerHTML = content; - this.eventDiv_.innerHTML = this.labelDiv_.innerHTML; - } else { - // Remove current content - while (this.labelDiv_.lastChild) { - this.labelDiv_.removeChild(this.labelDiv_.lastChild); - } - - while (this.eventDiv_.lastChild) { - this.eventDiv_.removeChild(this.eventDiv_.lastChild); - } - - this.labelDiv_.appendChild(content); - content = content.cloneNode(true); - this.eventDiv_.appendChild(content); - } - }; - - /** - * Sets the content of the tool tip for the label. It is - * always set to be the same as for the marker itself. - * @private - */ - MarkerLabel_.prototype.setTitle = function () { - this.eventDiv_.title = this.marker_.getTitle() || ""; - }; - - /** - * Sets the style of the label by setting the style sheet and applying - * other specific styles requested. - * @private - */ - MarkerLabel_.prototype.setStyles = function () { - var i, labelStyle; - - // Apply style values from the style sheet defined in the labelClass parameter: - this.labelDiv_.className = this.marker_.get("labelClass"); - this.eventDiv_.className = this.labelDiv_.className; - - // Clear existing inline style values: - this.labelDiv_.style.cssText = ""; - this.eventDiv_.style.cssText = ""; - // Apply style values defined in the labelStyle parameter: - labelStyle = this.marker_.get("labelStyle"); - for (i in labelStyle) { - if (labelStyle.hasOwnProperty(i)) { - this.labelDiv_.style[i] = labelStyle[i]; - this.eventDiv_.style[i] = labelStyle[i]; - } - } - this.setMandatoryStyles(); - }; - - /** - * Sets the mandatory styles to the DIV representing the label as well as to the - * associated event DIV. This includes setting the DIV position, z-index, and visibility. - * @private - */ - MarkerLabel_.prototype.setMandatoryStyles = function () { - this.labelDiv_.style.position = "absolute"; - this.labelDiv_.style.overflow = "hidden"; - // Make sure the opacity setting causes the desired effect on MSIE: - if (typeof this.labelDiv_.style.opacity !== "undefined" && this.labelDiv_.style.opacity !== "") { - this.labelDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")\""; - this.labelDiv_.style.filter = "alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")"; - } + opt_options.crossImage = opt_options.crossImage || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"; + opt_options.handCursor = opt_options.handCursor || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"; + opt_options.optimized = false; // Optimized rendering is not supported - this.eventDiv_.style.position = this.labelDiv_.style.position; - this.eventDiv_.style.overflow = this.labelDiv_.style.overflow; - this.eventDiv_.style.opacity = 0.01; // Don't use 0; DIV won't be clickable on MSIE - this.eventDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=1)\""; - this.eventDiv_.style.filter = "alpha(opacity=1)"; // For MSIE - - this.setAnchor(); - this.setPosition(); // This also updates z-index, if necessary. - this.setVisible(); - }; - - /** - * Sets the anchor point of the label. - * @private - */ - MarkerLabel_.prototype.setAnchor = function () { - var anchor = this.marker_.get("labelAnchor"); - this.labelDiv_.style.marginLeft = -anchor.x + "px"; - this.labelDiv_.style.marginTop = -anchor.y + "px"; - this.eventDiv_.style.marginLeft = -anchor.x + "px"; - this.eventDiv_.style.marginTop = -anchor.y + "px"; - }; - - /** - * Sets the position of the label. The z-index is also updated, if necessary. - * @private - */ - MarkerLabel_.prototype.setPosition = function (yOffset) { - var position = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition()); - if (typeof yOffset === "undefined") { - yOffset = 0; - } - this.labelDiv_.style.left = Math.round(position.x) + "px"; - this.labelDiv_.style.top = Math.round(position.y - yOffset) + "px"; - this.eventDiv_.style.left = this.labelDiv_.style.left; - this.eventDiv_.style.top = this.labelDiv_.style.top; - - this.setZIndex(); - }; - - /** - * Sets the z-index of the label. If the marker's z-index property has not been defined, the z-index - * of the label is set to the vertical coordinate of the label. This is in keeping with the default - * stacking order for Google Maps: markers to the south are in front of markers to the north. - * @private - */ - MarkerLabel_.prototype.setZIndex = function () { - var zAdjust = (this.marker_.get("labelInBackground") ? -1 : +1); - if (typeof this.marker_.getZIndex() === "undefined") { - this.labelDiv_.style.zIndex = parseInt(this.labelDiv_.style.top, 10) + zAdjust; - this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; - } else { - this.labelDiv_.style.zIndex = this.marker_.getZIndex() + zAdjust; - this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex; - } - }; - - /** - * Sets the visibility of the label. The label is visible only if the marker itself is - * visible (i.e., its visible property is true) and the labelVisible property is true. - * @private - */ - MarkerLabel_.prototype.setVisible = function () { - if (this.marker_.get("labelVisible")) { - this.labelDiv_.style.display = this.marker_.getVisible() ? "block" : "none"; - } else { - this.labelDiv_.style.display = "none"; - } - this.eventDiv_.style.display = this.labelDiv_.style.display; - }; - - /** - * @name MarkerWithLabelOptions - * @class This class represents the optional parameter passed to the {@link MarkerWithLabel} constructor. - * The properties available are the same as for google.maps.Marker with the addition - * of the properties listed below. To change any of these additional properties after the labeled - * marker has been created, call google.maps.Marker.set(propertyName, propertyValue). - *

- * When any of these properties changes, a property changed event is fired. The names of these - * events are derived from the name of the property and are of the form propertyname_changed. - * For example, if the content of the label changes, a labelcontent_changed event - * is fired. - *

- * @property {string|Node} [labelContent] The content of the label (plain text or an HTML DOM node). - * @property {Point} [labelAnchor] By default, a label is drawn with its anchor point at (0,0) so - * that its top left corner is positioned at the anchor point of the associated marker. Use this - * property to change the anchor point of the label. For example, to center a 50px-wide label - * beneath a marker, specify a labelAnchor of google.maps.Point(25, 0). - * (Note: x-values increase to the right and y-values increase to the top.) - * @property {string} [labelClass] The name of the CSS class defining the styles for the label. - * Note that style values for position, overflow, top, - * left, zIndex, display, marginLeft, and - * marginTop are ignored; these styles are for internal use only. - * @property {Object} [labelStyle] An object literal whose properties define specific CSS - * style values to be applied to the label. Style values defined here override those that may - * be defined in the labelClass style sheet. If this property is changed after the - * label has been created, all previously set styles (except those defined in the style sheet) - * are removed from the label before the new style values are applied. - * Note that style values for position, overflow, top, - * left, zIndex, display, marginLeft, and - * marginTop are ignored; these styles are for internal use only. - * @property {boolean} [labelInBackground] A flag indicating whether a label that overlaps its - * associated marker should appear in the background (i.e., in a plane below the marker). - * The default is false, which causes the label to appear in the foreground. - * @property {boolean} [labelVisible] A flag indicating whether the label is to be visible. - * The default is true. Note that even if labelVisible is - * true, the label will not be visible unless the associated marker is also - * visible (i.e., unless the marker's visible property is true). - * @property {boolean} [raiseOnDrag] A flag indicating whether the label and marker are to be - * raised when the marker is dragged. The default is true. If a draggable marker is - * being created and a version of Google Maps API earlier than V3.3 is being used, this property - * must be set to false. - * @property {boolean} [optimized] A flag indicating whether rendering is to be optimized for the - * marker. Important: The optimized rendering technique is not supported by MarkerWithLabel, - * so the value of this parameter is always forced to false. - * @property {string} [crossImage="http://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"] - * The URL of the cross image to be displayed while dragging a marker. - * @property {string} [handCursor="http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"] - * The URL of the cursor to be displayed while dragging a marker. - */ - /** - * Creates a MarkerWithLabel with the options specified in {@link MarkerWithLabelOptions}. - * @constructor - * @param {MarkerWithLabelOptions} [opt_options] The optional parameters. - */ - function MarkerWithLabel(opt_options) { - opt_options = opt_options || {}; - opt_options.labelContent = opt_options.labelContent || ""; - opt_options.labelAnchor = opt_options.labelAnchor || new gMapsApi.Point(0, 0); - opt_options.labelClass = opt_options.labelClass || "markerLabels"; - opt_options.labelStyle = opt_options.labelStyle || {}; - opt_options.labelInBackground = opt_options.labelInBackground || false; - if (typeof opt_options.labelVisible === "undefined") { - opt_options.labelVisible = true; - } - if (typeof opt_options.raiseOnDrag === "undefined") { - opt_options.raiseOnDrag = true; - } - if (typeof opt_options.clickable === "undefined") { - opt_options.clickable = true; - } - if (typeof opt_options.draggable === "undefined") { - opt_options.draggable = false; - } - if (typeof opt_options.optimized === "undefined") { - opt_options.optimized = false; + this.label = new MarkerLabel_(this, opt_options.crossImage, opt_options.handCursor); // Bind the label to the marker + + // Call the parent constructor. It calls Marker.setValues to initialize, so all + // the new parameters are conveniently saved and can be accessed with get/set. + // Marker.set triggers a property changed event (called "propertyname_changed") + // that the marker label listens for in order to react to state changes. + gMapsApi.Marker.apply(this, arguments); } - opt_options.crossImage = opt_options.crossImage || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"; - opt_options.handCursor = opt_options.handCursor || "http" + (document.location.protocol === "https:" ? "s" : "") + "://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur"; - opt_options.optimized = false; // Optimized rendering is not supported - - this.label = new MarkerLabel_(this, opt_options.crossImage, opt_options.handCursor); // Bind the label to the marker - - // Call the parent constructor. It calls Marker.setValues to initialize, so all - // the new parameters are conveniently saved and can be accessed with get/set. - // Marker.set triggers a property changed event (called "propertyname_changed") - // that the marker label listens for in order to react to state changes. - gMapsApi.Marker.apply(this, arguments); - } - inherits(MarkerWithLabel, gMapsApi.Marker); - - /** - * Overrides the standard Marker setMap function. - * @param {Map} theMap The map to which the marker is to be added. - * @private - */ - MarkerWithLabel.prototype.setMap = function (theMap) { - - // Call the inherited function... - gMapsApi.Marker.prototype.setMap.apply(this, arguments); - - // ... then deal with the label: - this.label.setMap(theMap); - }; - - return MarkerWithLabel; + + inherits(MarkerWithLabel, gMapsApi.Marker); + + /** + * Overrides the standard Marker setMap function. + * @param {Map} theMap The map to which the marker is to be added. + * @private + */ + MarkerWithLabel.prototype.setMap = function (theMap) { + + // Call the inherited function... + gMapsApi.Marker.prototype.setMap.apply(this, arguments); + + // ... then deal with the label: + this.label.setMap(theMap); + }; + + return MarkerWithLabel; } From 7b963ccc815e0229f4d7ad05ff45fe4be0984f33 Mon Sep 17 00:00:00 2001 From: andrei <фкрфт89"пьфшдюсщь> Date: Fri, 16 Feb 2018 15:43:46 +0300 Subject: [PATCH 2/2] MarkerWithLabel fix for latest maps version --- index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/index.js b/index.js index a4db1bf..3d73790 100644 --- a/index.js +++ b/index.js @@ -333,8 +333,6 @@ module.exports = function (gMapsApi) { if (this.labelDiv_.parentNode) { this.labelDiv_.parentNode.removeChild(this.labelDiv_); } - this.eventDiv_.parentNode.removeChild(this.eventDiv_); - // Remove event listeners: if (this.listeners_) { for (i = 0; i < this.listeners_.length; i++) {