mapbox-gl
Version:
A WebGL interactive maps library
215 lines (179 loc) • 5.83 kB
JavaScript
'use strict';
module.exports = Popup;
var util = require('../util/util');
var Evented = require('../util/evented');
var DOM = require('../util/dom');
var LatLng = require('../geo/lat_lng');
/**
* Creates a popup component
* @class Popup
* @param {Object} options
* @param {boolean} options.closeButton
* @param {boolean} options.closeOnClick
* @example
* var tooltip = new mapboxgl.Popup()
* .setLatLng(map.unproject(e.point))
* .setHTML("<h1>Hello World!</h1>")
* .addTo(map);
*/
function Popup(options) {
util.setOptions(this, options);
util.bindAll([
'_updatePosition',
'_onClickClose'],
this);
}
Popup.prototype = util.inherit(Evented, /** @lends Popup.prototype */{
options: {
closeButton: true,
closeOnClick: true
},
/**
* Attaches the popup to a map
* @param {Map} map
* @returns {Popup} `this`
*/
addTo: function(map) {
this._map = map;
this._map.on('move', this._updatePosition);
if (this.options.closeOnClick) {
this._map.on('click', this._onClickClose);
}
this._update();
return this;
},
/**
* Removes the popup from the map
* @example
* var popup = new mapboxgl.Popup().addTo(map);
* popup.remove();
* @returns {Popup} `this`
*/
remove: function() {
if (this._container) {
this._container.parentNode.removeChild(this._container);
}
if (this._map) {
this._map.off('move', this._updatePosition);
this._map.off('click', this._onClickClose);
delete this._map;
}
return this;
},
/**
* Get the current coordinates of popup element relative to map
* @returns {LatLng}
*/
getLatLng: function() {
return this._latLng;
},
/**
* Set the coordinates of a popup element to a map
* @param {LatLng} latlng
* @returns {Popup} `this`
*/
setLatLng: function(latlng) {
this._latLng = LatLng.convert(latlng);
this._update();
return this;
},
/**
* Fill a popup element with text only content
* @param {string} text
* @returns {Popup} `this`
*/
setText: function(text) {
this._content = document.createTextNode(text);
this._updateContent();
return this;
},
/**
* Fill a popup element with HTML content
* @param {string} html
* @returns {Popup} `this`
*/
setHTML: function(html) {
this._content = document.createDocumentFragment();
var temp = document.createElement('body'), child;
temp.innerHTML = html;
while (true) {
child = temp.firstChild;
if (!child) break;
this._content.appendChild(child);
}
this._updateContent();
return this;
},
_update: function() {
if (!this._map) { return; }
if (!this._container) {
this._container = DOM.create('div', 'mapboxgl-popup', this._map.getContainer());
this._tip = DOM.create('div', 'mapboxgl-popup-tip', this._container);
this._wrapper = DOM.create('div', 'mapboxgl-popup-content', this._container);
if (this.options.closeButton) {
this._closeButton = DOM.create('button', 'mapboxgl-popup-close-button', this._wrapper);
this._closeButton.innerHTML = '×';
this._closeButton.addEventListener('click', this._onClickClose);
}
}
this._updateContent();
this._updatePosition();
},
_updateContent: function() {
if (!this._content || !this._container) { return; }
var node = this._wrapper;
while (node.hasChildNodes()) {
node.removeChild(node.firstChild);
}
if (this.options.closeButton) {
node.appendChild(this._closeButton);
}
node.appendChild(this._content);
},
_updatePosition: function() {
if (!this._latLng || !this._container) { return; }
var pos = this._map.project(this._latLng).round(),
anchor = this.options.anchor;
if (!anchor) {
var width = this._container.offsetWidth,
height = this._container.offsetHeight;
if (pos.y < height) {
anchor = ['top'];
} else if (pos.y > this._map.transform.height - height) {
anchor = ['bottom'];
} else {
anchor = [];
}
if (pos.x < width / 2) {
anchor.push('left');
} else if (pos.x > this._map.transform.width - width / 2) {
anchor.push('right');
}
if (anchor.length === 0) {
anchor = 'bottom';
} else {
anchor = anchor.join('-');
}
this.options.anchor = anchor;
}
var anchorTranslate = {
'top': 'translate(-50%,0)',
'top-left': 'translate(0,0)',
'top-right': 'translate(-100%,0)',
'bottom': 'translate(-50%,-100%)',
'bottom-left': 'translate(0,-100%)',
'bottom-right': 'translate(-100%,-100%)',
'left': 'translate(0,-50%)',
'right': 'translate(-100%,-50%)'
};
var classList = this._container.classList;
for (var key in anchorTranslate) {
classList.remove('mapboxgl-popup-anchor-' + key);
}
classList.add('mapboxgl-popup-anchor-' + anchor);
DOM.setTransform(this._container, anchorTranslate[anchor] + ' translate(' + pos.x + 'px,' + pos.y + 'px)');
},
_onClickClose: function() {
this.remove();
}
});