ol-legend
Version:
Legend control for OpenLayers v3/v4/v5
215 lines (186 loc) • 6.93 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('ol/control/Control'), require('ol/Observable')) :
typeof define === 'function' && define.amd ? define(['ol/control/Control', 'ol/Observable'], factory) :
(global.LayerLegend = factory(global.ol.control.Control,global.ol.Observable));
}(this, (function (Control,Observable) { 'use strict';
Control = 'default' in Control ? Control['default'] : Control;
Observable = 'default' in Observable ? Observable['default'] : Observable;
/**
* OpenLayers Layer Switcher Control.
* See [the examples](./examples) for usage.
* @constructor
* @extends {ol.control.Control}
* @param {Object} opt_options Control options, extends olx.control.ControlOptions adding:
* **`tipLabel`** `String` - the button tooltip.
*/
class LayerLegend extends Control {
constructor(opt_options) {
var options = opt_options || {};
var tipLabel = options.tipLabel ? options.tipLabel : 'Legend';
var element = document.createElement('div');
super({ element: element, target: options.target });
this.mapListeners = [];
this.hiddenClassName = 'ol-unselectable ol-control layer-legend';
if (LayerLegend.isTouchDevice_()) {
this.hiddenClassName += ' touch';
}
this.shownClassName = 'shown';
this.legendUrl = options.url;
element.className = this.hiddenClassName;
var button = document.createElement('button');
button.setAttribute('title', tipLabel);
element.appendChild(button);
this.panel = document.createElement('div');
this.panel.className = 'panel';
element.appendChild(this.panel);
LayerLegend.enableTouchScroll_(this.panel);
var this_ = this;
button.onmouseover = e => {
this.showPanel();
};
button.onclick = e => {
e = e || window.event;
this.showPanel();
e.preventDefault();
};
this_.panel.onmouseout = e => {
e = e || window.event;
if (!this.panel.contains(e.toElement || e.relatedTarget)) {
this.hidePanel();
}
};
}
/**
* Set the map instance the control is associated with.
* @param {ol.Map} map The map instance.
*/
setMap(map) {
// Clean up listeners associated with the previous map
for (var i = 0, key; i < this.mapListeners.length; i++) {
Observable.unByKey(this.mapListeners[i]);
}
this.mapListeners.length = 0;
// Wire up listeners etc. and store reference to new map
super.setMap(map);
if (map) {
var this_ = this;
this.mapListeners.push(map.on('pointerdown', function () {
this_.hidePanel();
}));
this.renderPanel(this_);
}
}
/**
* Show the layer panel.
*/
showPanel() {
if (!this.element.classList.contains(this.shownClassName)) {
this.element.classList.add(this.shownClassName);
this.renderPanel();
}
}
/**
* Hide the layer panel.
*/
hidePanel() {
if (this.element.classList.contains(this.shownClassName)) {
this.element.classList.remove(this.shownClassName);
}
}
/**
* Re-draw the layer panel to represent the current state of the layers.
*/
renderPanel(obj) {
LayerLegend.renderPanel(this.getMap(), obj.legendUrl, this.panel);
}
/**
* **Static** Re-draw the layer panel to represent the current state of the layers.
* @param {ol.Map} map The OpenLayers Map instance to render layers for
* @param {Element} panel The DOM Element into which the layer tree will be rendered
*/
static renderPanel(map, url, panel) {
while (panel.firstChild) {
panel.removeChild(panel.firstChild);
}
var dv = document.createElement('div');
panel.appendChild(dv);
console.log(this);
// passing two map arguments instead of lyr as we're passing the map as the root of the layers tree
LayerLegend.renderLegend(map, url, dv);
}
/**
* **Static** Render all layers that are children of a group.
* @private
* @param {ol.Map} map The map instance.
* @param {string} url Group layer whos children will be rendered.
* @param {Element} elm DOM element that children will be appended to.
*/
static renderLegend(map, url, elm) {
var img = new Image();
img.src = url;
elm.appendChild(img);
}
/**
* **Static** Call the supplied function for each layer in the passed layer group
* recursing nested groups.
* @param {ol.layer.Group} lyr The layer group to start iterating from.
* @param {Function} fn Callback which will be called for each `ol.layer.Base`
* found under `lyr`. The signature for `fn` is the same as `ol.Collection#forEach`
*/
static forEachRecursive(lyr, fn) {
lyr.getLayers().forEach(function (lyr, idx, a) {
fn(lyr, idx, a);
if (lyr.getLayers) {
LayerLegend.forEachRecursive(lyr, fn);
}
});
}
/**
* **Static** Generate a UUID
* Adapted from http://stackoverflow.com/a/2117523/526860
* @returns {String} UUID
*/
static uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : r & 0x3 | 0x8;
return v.toString(16);
});
}
/**
* @private
* @desc Apply workaround to enable scrolling of overflowing content within an
* element. Adapted from https://gist.github.com/chrismbarr/4107472
*/
static enableTouchScroll_(elm) {
if (LayerLegend.isTouchDevice_()) {
var scrollStartPos = 0;
elm.addEventListener("touchstart", function (event) {
scrollStartPos = this.scrollTop + event.touches[0].pageY;
}, false);
elm.addEventListener("touchmove", function (event) {
this.scrollTop = scrollStartPos - event.touches[0].pageY;
}, false);
}
}
/**
* @private
* @desc Determine if the current browser supports touch events. Adapted from
* https://gist.github.com/chrismbarr/4107472
*/
static isTouchDevice_() {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}
}
// Expose LayerLegend as ol.control.LayerLegend if using a full build of
// OpenLayers
if (window.ol && window.ol.control) {
window.ol.control.LayerLegend = LayerLegend;
}
return LayerLegend;
})));