ol-ext
Version:
A set of cool extensions for OpenLayers (ol) in node modules structure
327 lines (313 loc) • 10 kB
JavaScript
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol_Overlay from 'ol/Overlay.js'
import ol_ext_element from '../util/element.js'
/**
* @classdesc
* A popup element to be displayed over the map and attached to a single map
* location. The popup are customized using CSS.
*
* @example
var popup = new ol_Overlay_Popup();
map.addOverlay(popup);
popup.show(coordinate, "Hello!");
popup.hide();
*
* @constructor
* @extends {ol_Overlay}
* @fires show
* @fires hide
* @param {} options Extend Overlay options
* @param {String} [options.popupClass] the a class of the overlay to style the popup.
* @param {boolean} [options.anim Animate=false] the popup the popup, default false.
* @param {bool} [options.closeBox=false] popup has a close box, default false.
* @param {function|undefined} [options.onclose] callback function when popup is closed
* @param {function|undefined} [options.onshow] callback function when popup is shown
* @param {Number|Array<number>} [options.offsetBox] an offset box
* @param {ol.OverlayPositioning | string | undefined} options.positioning
* the 'auto' positioning var the popup choose its positioning to stay on the map.
* @param {boolean} [options.minibar=false] add a mini vertical bar
* @api stable
*/
var ol_Overlay_Popup = class olOverlayPopup extends ol_Overlay {
constructor(options) {
options = options || {};
// Popup div
var element = document.createElement("div");
//element.classList.add('ol-overlaycontainer-stopevent');
options.element = element;
super(options);
if (typeof (options.offsetBox) === 'number') {
this.offsetBox = [options.offsetBox, options.offsetBox, options.offsetBox, options.offsetBox];
} else {
this.offsetBox = options.offsetBox;
}
// Closebox
this.closeBox = options.closeBox;
this.onclose = options.onclose;
this.onshow = options.onshow;
ol_ext_element.create('BUTTON', {
className: 'closeBox' + (options.closeBox ? ' hasclosebox' : ''),
type: 'button',
click: function () {
this.hide();
}.bind(this),
parent: element
});
// Anchor div
if (options.anchor !== false) {
ol_ext_element.create('DIV', {
className: 'anchor',
parent: element
});
}
// Content
this.content = ol_ext_element.create('DIV', {
html: options.html || '',
className: "ol-popup-content",
parent: element
});
if (options.minibar) {
ol_ext_element.scrollDiv(this.content, {
vertical: true,
mousewheel: true,
minibar: true
});
}
// Stop event
if (options.stopEvent) {
element.addEventListener("mousedown", function (e) { e.stopPropagation(); });
element.addEventListener("touchstart", function (e) { e.stopPropagation(); });
}
this._elt = element;
// call setPositioning first in constructor so getClassPositioning is called only once
this.setPositioning(options.positioning || 'auto');
this.setPopupClass(options.popupClass || options.className || 'default');
if (options.anim)
this.addPopupClass('anim');
// Show popup on timeout (for animation purposes)
if (options.position) {
setTimeout(function () { this.show(options.position); }.bind(this));
}
}
/**
* Get CSS class of the popup according to its positioning.
* @private
*/
getClassPositioning() {
var c = "";
var pos = this.getPositioning();
if (/bottom/.test(pos))
c += "ol-popup-bottom ";
if (/top/.test(pos))
c += "ol-popup-top ";
if (/left/.test(pos))
c += "ol-popup-left ";
if (/right/.test(pos))
c += "ol-popup-right ";
if (/^center/.test(pos))
c += "ol-popup-middle ";
if (/center$/.test(pos))
c += "ol-popup-center ";
return c;
}
/**
* Set a close box to the popup.
* @param {bool} b
* @api stable
*/
setClosebox(b) {
this.closeBox = b;
if (b)
this.element.classList.add("hasclosebox");
else
this.element.classList.remove("hasclosebox");
}
/**
* Set the CSS class of the popup.
* @param {string} c class name.
* @api stable
*/
setPopupClass(c) {
var classes = ["ol-popup"];
if (this.getVisible())
classes.push('visible');
this.element.className = "";
var classesPositioning = this.getClassPositioning().split(' ')
.filter(function (className) {
return className.length > 0;
});
if (c) {
c.split(' ').filter(function (className) {
return className.length > 0;
})
.forEach(function (className) {
classes.push(className);
});
} else {
classes.push("default");
}
classesPositioning.forEach(function (className) {
classes.push(className);
});
if (this.closeBox) {
classes.push("hasclosebox");
}
this.element.classList.add.apply(this.element.classList, classes);
}
/**
* Add a CSS class to the popup.
* @param {string} c class name.
* @api stable
*/
addPopupClass(c) {
this.element.classList.add(c);
}
/**
* Remove a CSS class to the popup.
* @param {string} c class name.
* @api stable
*/
removePopupClass(c) {
this.element.classList.remove(c);
}
/**
* Set positionning of the popup
* @param {ol.OverlayPositioning | string | undefined} pos an ol.OverlayPositioning
* or 'auto' to var the popup choose the best position
* @api stable
*/
setPositioning(pos) {
if (pos === undefined)
return;
if (/auto/.test(pos)) {
this.autoPositioning = pos.split('-');
if (this.autoPositioning.length == 1)
this.autoPositioning[1] = "auto";
} else {
this.autoPositioning = false;
}
pos = pos.replace(/auto/g, "center");
if (pos == "center")
pos = "bottom-center";
this.setPositioning_(pos);
}
/** @private
* @param {ol.OverlayPositioning | string | undefined} pos
*/
setPositioning_(pos) {
if (this.element) {
super.setPositioning(pos);
this.element.classList.remove("ol-popup-top", "ol-popup-bottom", "ol-popup-left", "ol-popup-right", "ol-popup-center", "ol-popup-middle");
var classes = this.getClassPositioning().split(' ')
.filter(function (className) {
return className.length > 0;
});
this.element.classList.add.apply(this.element.classList, classes);
}
}
/** Check if popup is visible
* @return {boolean}
*/
getVisible() {
return this.element.classList.contains("visible");
}
/**
* Set the position and the content of the popup.
* @param {ol.Coordinate|string} coordinate the coordinate of the popup or the HTML content.
* @param {string|undefined} html the HTML content (undefined = previous content).
* @example
var popup = new ol_Overlay_Popup();
// Show popup
popup.show([166000, 5992000], "Hello world!");
// Move popup at coord with the same info
popup.show([167000, 5990000]);
// set new info
popup.show("New informations");
* @api stable
*/
show(coordinate, html) {
if (!html && typeof (coordinate) == 'string') {
html = coordinate;
coordinate = null;
}
if (coordinate === true) {
coordinate = this.getPosition();
}
var self = this;
var map = this.getMap();
if (!map)
return;
if (html && html !== this.prevHTML) {
// Prevent flickering effect
this.prevHTML = html;
this.content.innerHTML = '';
if (html instanceof Element) {
this.content.appendChild(html);
} else {
ol_ext_element.create('DIV', {
html: html,
parent: this.content
});
}
// Refresh when loaded (img)
Array.prototype.slice.call(this.content.querySelectorAll('img'))
.forEach(function (image) {
image.addEventListener('load', function () {
try { map.renderSync(); } catch (e) { /* ok */ }
self.content.dispatchEvent(new Event('scroll'));
});
});
}
if (coordinate) {
// Auto positionning
if (this.autoPositioning) {
var p = map.getPixelFromCoordinate(coordinate);
var s = map.getSize();
var pos = [];
if (this.autoPositioning[0] == 'auto') {
pos[0] = (p[1] < s[1] / 3) ? "top" : "bottom";
}
else
pos[0] = this.autoPositioning[0];
pos[1] = (p[0] < 2 * s[0] / 3) ? "left" : "right";
this.setPositioning_(pos[0] + "-" + pos[1]);
if (this.offsetBox) {
this.setOffset([this.offsetBox[pos[1] == "left" ? 2 : 0], this.offsetBox[pos[0] == "top" ? 3 : 1]]);
}
} else {
if (this.offsetBox) {
this.setOffset(this.offsetBox);
}
}
// Show
this.setPosition(coordinate);
// Set visible class (wait to compute the size/position first)
this.element.parentElement.style.display = '';
if (typeof (this.onshow) == 'function')
this.onshow();
this.dispatchEvent({ type: 'show' });
this._tout = setTimeout(function () {
self.element.classList.add('visible');
}, 0);
}
}
/**
* Hide the popup
* @api stable
*/
hide() {
if (this.getPosition() == undefined)
return;
if (typeof (this.onclose) == 'function')
this.onclose();
this.setPosition(undefined);
if (this._tout)
clearTimeout(this._tout);
this.element.classList.remove("visible");
this.dispatchEvent({ type: 'hide' });
}
}
export default ol_Overlay_Popup