mapbox-gl
Version:
A WebGL interactive maps library
164 lines (139 loc) • 4.74 kB
JavaScript
/* eslint-disable */
'use strict';
module.exports = Marker;
var DOM = require('../util/dom');
var util = require('../util/util');
var LngLat = require('../geo/lng_lat');
var Point = require('point-geometry');
var Popup = require('./popup');
/**
* Creates a marker component
* @class Marker
* @param {HTMLElement=} element DOM element to use as a marker (creates a div element by default)
* @param {Object=} options
* @param {PointLike=} options.offset The offset in pixels as a [`PointLike`](#PointLike) object to apply relative to the element's top left corner. Negatives indicate left and up.
* @example
* var marker = new mapboxgl.Marker()
* .setLngLat([30.5, 50.5])
* .addTo(map);
* @see [Add custom icons with Markers](https://www.mapbox.com/mapbox-gl-js/example/custom-marker-icons/)
*/
function Marker(element, options) {
this._offset = Point.convert(options && options.offset || [0, 0]);
this._update = this._update.bind(this);
this._onMapClick = this._onMapClick.bind(this);
if (!element) element = DOM.create('div');
element.classList.add('mapboxgl-marker');
this._element = element;
this._popup = null;
}
Marker.prototype = {
/**
* Attaches the marker to a map
* @param {Map} map
* @returns {Marker} `this`
*/
addTo: function (map) {
this.remove();
this._map = map;
map.getCanvasContainer().appendChild(this._element);
map.on('move', this._update);
map.on('moveend', this._update);
this._update();
// If we attached the `click` listener to the marker element, the popup
// would close once the event propogated to `map` due to the
// `Popup#_onClickClose` listener.
this._map.on('click', this._onMapClick);
return this;
},
/**
* Removes the marker from a map
* @example
* var marker = new mapboxgl.Marker().addTo(map);
* marker.remove();
* @returns {Marker} `this`
*/
remove: function () {
if (this._map) {
this._map.off('click', this._onMapClick);
this._map.off('move', this._update);
this._map.off('moveend', this._update);
this._map = null;
}
DOM.remove(this._element);
if (this._popup) this._popup.remove();
return this;
},
/**
* Get the marker's geographical location
* @returns {LngLat}
*/
getLngLat: function () {
return this._lngLat;
},
/**
* Set the marker's geographical position and move it.
* @param {LngLat} lnglat
* @returns {Marker} `this`
*/
setLngLat: function (lnglat) {
this._lngLat = LngLat.convert(lnglat);
if (this._popup) this._popup.setLngLat(this._lngLat);
this._update();
return this;
},
getElement: function () {
return this._element;
},
/**
* Binds a Popup to the Marker
* @param {Popup=} popup an instance of the `Popup` class. If undefined or null, any popup
* set on this `Marker` instance is unset
* @returns {Marker} `this`
*/
setPopup: function (popup) {
var that = this;
if (this._popup) {
this._popup.remove();
this._popup = null;
}
if (popup) {
this._popup = popup;
this._popup.setLngLat(this._lngLat);
}
return this;
},
_onMapClick: function(event) {
var targetElement = event.originalEvent.target;
var element = this._element;
if (this._popup && (targetElement === element || element.contains(targetElement))) {
this.togglePopup();
}
},
/**
* Returns the Popup instance that is bound to the Marker
* @returns {Popup} popup
*/
getPopup: function () {
return this._popup;
},
/**
* Opens or closes the bound popup, depending on the current state
* @returns {Marker} `this`
*/
togglePopup: function () {
var popup = this._popup;
if (!popup) return;
else if (popup.isOpen()) popup.remove();
else popup.addTo(this._map);
},
_update: function (e) {
if (!this._map) return;
var pos = this._map.project(this._lngLat)._add(this._offset);
// because rouding the coordinates at every `move` event causes stuttered zooming
// we only round them when _update is called with `moveend` or when its called with
// no arguments (when the Marker is initialized or Marker#setLngLat is invoked).
if (!e || e.type === "moveend") pos = pos.round();
DOM.setTransform(this._element, 'translate(' + pos.x + 'px,' + pos.y + 'px)');
}
};