<!-- Copyright (c) 2015 Google Inc. All rights reserved. --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../google-apis/google-maps-api.html"> <!-- The `google-map-marker` element represents a map marker. It is used as a child of `google-map`. <b>Example</b>: <google-map latitude="37.77493" longitude="-122.41942"> <google-map-marker latitude="37.779" longitude="-122.3892" title="Go Giants!"></google-map-marker> </google-map> <b>Example</b> - marker with info window (children create the window content): <google-map-marker latitude="37.77493" longitude="-122.41942"> <img src="image.png"> </google-map-marker> <b>Example</b> - a draggable marker: <google-map-marker latitude="37.77493" longitude="-122.41942" draggable="true"></google-map-marker> <b>Example</b> - hide a marker: <google-map-marker latitude="37.77493" longitude="-122.41942" hidden></google-map-marker> --> <dom-module id="google-map-marker"> <style> :host { display: none; } </style> <template><content></content></template> </dom-module> <script> (function() { function setupDragHandler_() { if (this.draggable) { this.dragHandler_ = google.maps.event.addListener( this.marker, 'dragend', onDragEnd_.bind(this)); } else { google.maps.event.removeListener(this.dragHandler_); this.dragHandler_ = null; } } function onDragEnd_(e, details, sender) { this.latitude = e.latLng.lat(); this.longitude = e.latLng.lng(); } Polymer({ is: 'google-map-marker', /** * Fired when the marker icon was clicked. Requires the clickEvents attribute to be true. * @param {google.maps.MouseEvent} event The mouse event. * @event google-map-marker-click */ /** * Fired when the marker icon was double clicked. Requires the clickEvents attribute to be true. * @param {google.maps.MouseEvent} event The mouse event. * @event google-map-marker-dblclick */ /** * Fired for a mousedown on the marker. Requires the mouseEvents attribute to be true. * @event google-map-marker-mousedown * @param {google.maps.MouseEvent} event The mouse event. */ /** * Fired when the DOM `mousemove` event is fired on the marker. Requires the mouseEvents * attribute to be true. * @event google-map-marker-mousemove * @param {google.maps.MouseEvent} event The mouse event. */ /** * Fired when the mouse leaves the area of the marker icon. Requires the mouseEvents attribute to be * true. * @event google-map-marker-mouseout * @param {google.maps.MouseEvent} event The mouse event. */ /** * Fired when the mouse enters the area of the marker icon. Requires the mouseEvents attribute to be * true. * @event google-map-marker-mouseover * @param {google.maps.MouseEvent} event The mouse event. */ /** * Fired for a mouseup on the marker. Requires the mouseEvents attribute to be true. * * @event google-map-marker-mouseup * @param {google.maps.MouseEvent} event The mouse event. */ /** * Fired for a rightclick on the marker. Requires the clickEvents attribute to be true. * @event google-map-marker-rightclick * @param {google.maps.MouseEvent} event The mouse event. */ /** * Fired when an infowindow is opened. * @event google-map-marker-open */ /** * Fired when the close button of the infowindow is pressed. * @event google-map-marker-close */ properties: { /** * A Google Maps marker object. * @type google.maps.Marker */ marker: Object, /** * The Google map object. * @type google.maps.Map */ map: { type: Object, observer: '_mapChanged' }, /** * A Google Map Infowindow object. */ info: { type: Object, value: null }, /** * When true, marker *click events are automatically registered. */ clickEvents: { type: Boolean, value: false, observer: '_clickEventsChanged' }, /** * Image URL for the marker icon. * @type string|google.maps.Icon|google.maps.Symbol */ icon: { type: Object, value: null, observer: '_iconChanged' }, /** * When true, marker mouse* events are automatically registered. */ mouseEvents: { type: Boolean, value: false, observer: '_mouseEventsChanged' }, /** * Z-index for the marker icon. */ zIndex: { type: Number, value: 0, observer: '_zIndexChanged' }, /** * The marker's longitude coordinate. */ longitude: { type: Number, value: null, reflectToAttribute: true }, /** * The marker's latitude coordinate. */ latitude: { type: Number, value: null, reflectToAttribute: true }, /** * A animation for the marker. "DROP" or "BOUNCE". See * https://developers.google.com/maps/documentation/javascript/examples/marker-animations. */ animation: { type: String, value: null, observer: '_animationChanged' }, /** * Specifies whether the InfoWindow is open or not */ open: { type: Boolean, value: false, observer: '_openChanged' } }, observers: [ '_updatePosition(latitude, longitude)' ], detached: function() { if (this.marker) { this.marker.setMap(null); } if (this._contentObserver) this._contentObserver.disconnect(); }, attached: function() { // If element is added back to DOM, put it back on the map. if (this.marker) { this.marker.setMap(this.map); } }, _updatePosition: function() { if (this.marker && this.latitude != null && this.longitude != null) { this.marker.setPosition({ lat: parseFloat(this.latitude), lng: parseFloat(this.longitude) }); } }, _clickEventsChanged: function() { if (this.map) { if (this.clickEvents) { this._forwardEvent('click'); this._forwardEvent('dblclick'); this._forwardEvent('rightclick'); } else { this._clearListener('click'); this._clearListener('dblclick'); this._clearListener('rightclick'); } } }, _mouseEventsChanged: function() { if (this.map) { if (this.mouseEvents) { this._forwardEvent('mousedown'); this._forwardEvent('mousemove'); this._forwardEvent('mouseout'); this._forwardEvent('mouseover'); this._forwardEvent('mouseup'); } else { this._clearListener('mousedown'); this._clearListener('mousemove'); this._clearListener('mouseout'); this._clearListener('mouseover'); this._clearListener('mouseup'); } } }, _animationChanged: function() { if (this.marker) { this.marker.setAnimation(google.maps.Animation[this.animation]); } }, _iconChanged: function() { if (this.marker) { this.marker.setIcon(this.icon); } }, _zIndexChanged: function() { if (this.marker) { this.marker.setZIndex(this.zIndex); } }, _mapChanged: function() { // Marker will be rebuilt, so disconnect existing one from old map and listeners. if (this.marker) { this.marker.setMap(null); google.maps.event.clearInstanceListeners(this.marker); } if (this.map && this.map instanceof google.maps.Map) { this._mapReady(); } }, _contentChanged: function() { if (this._contentObserver) this._contentObserver.disconnect(); // Watch for future updates. this._contentObserver = new MutationObserver( this._contentChanged.bind(this)); this._contentObserver.observe( this, { childList: true, subtree: true }); var content = this.innerHTML.trim(); if (content) { if (!this.info) { // Create a new infowindow this.info = new google.maps.InfoWindow(); this.openInfoHandler_ = google.maps.event.addListener(this.marker, 'click', function() { this.open = true; }.bind(this)); this.closeInfoHandler_ = google.maps.event.addListener(this.info, 'closeclick', function() { this.open = false; }.bind(this)); } this.info.setContent(content); } else { if (this.info) { // Destroy the existing infowindow. It doesn't make sense to have an empty one. google.maps.event.removeListener(this.openInfoHandler_); google.maps.event.removeListener(this.closeInfoHandler_); this.info = null; } } }, _openChanged: function() { if (this.info) { if (this.open) { this.info.open(this.map, this.marker); this.fire('google-map-marker-open'); } else { this.info.close(); this.fire('google-map-marker-close'); } } }, _mapReady: function() { this._listeners = {}; this.marker = new google.maps.Marker({ map: this.map, position: { lat: parseFloat(this.latitude), lng: parseFloat(this.longitude) }, title: this.title, animation: google.maps.Animation[this.animation], draggable: this.draggable, visible: !this.hidden, icon: this.icon, zIndex: this.zIndex }); this._contentChanged(); this._clickEventsChanged(); this._contentChanged(); this._mouseEventsChanged(); this._openChanged(); setupDragHandler_.bind(this)(); }, _clearListener: function(name) { if (this._listeners[name]) { google.maps.event.removeListener(this._listeners[name]); this._listeners[name] = null; } }, _forwardEvent: function(name) { this._listeners[name] = google.maps.event.addListener(this.marker, name, function(event) { this.fire('google-map-marker-' + name, event); }.bind(this)); }, attributeChanged: function(attrName, oldVal, newVal) { if (!this.marker) { return; } // Cannot use *Changed watchers for native properties. switch (attrName) { case 'hidden': this.marker.setVisible(!this.hidden); break; case 'draggable': this.marker.setDraggable(this.draggable); setupDragHandler_.bind(this)(); break; case 'title': this.marker.setTitle(this.title); break; } } }); })(); </script>