summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chimere/static/ol3-layerswitcher/README.md95
-rw-r--r--chimere/static/ol3-layerswitcher/ol3-layerswitcher.css92
-rw-r--r--chimere/static/ol3-layerswitcher/ol3-layerswitcher.js283
3 files changed, 470 insertions, 0 deletions
diff --git a/chimere/static/ol3-layerswitcher/README.md b/chimere/static/ol3-layerswitcher/README.md
new file mode 100644
index 0000000..13857b8
--- /dev/null
+++ b/chimere/static/ol3-layerswitcher/README.md
@@ -0,0 +1,95 @@
+# OpenLayers 3 LayerSwitcher
+
+Grouped layer list control for an OL3 map.
+
+All layers should have a `title` property and base layers should have a `type` property set to `base`. Group layers (`ol.layer.Group`) can be used to visually group layers together. See [examples/layerswitcher.js](examples/layerswitcher.js) for usage.
+
+## Examples
+
+The examples demonstrate usage and can be viewed online thanks to [RawGit](http://rawgit.com/):
+
+* [Basic usage](http://rawgit.com/walkermatt/ol3-layerswitcher/master/examples/layerswitcher.html)
+ * Create a layer switcher control. Each layer to be displayed in the layer switcher has a `title` property as does each Group; each base map layer has a `type: 'base'` property.
+* [Add layer](http://rawgit.com/walkermatt/ol3-layerswitcher/master/examples/addlayer.html)
+ * Add a layer to an existing layer group after the layer switcher has been added to the map.
+* [Scrolling](http://rawgit.com/walkermatt/ol3-layerswitcher/master/examples/scroll.html)
+ * Demonstrate the panel scrolling vertically, control the height of the layer switcher by setting the `max-height` (see [examples/scroll.css](examples/scroll.css)) and it's position relative to the bottom of the map (see the `.layer-switcher.shown` selector in [src/ol3-layerswitcher.css](src/ol3-layerswitcher.css)).
+
+The source for all examples can be found in [examples](examples).
+
+## Tests
+
+To run the tests you'll need to install the dependencies via `npm`. In the root of the repository run:
+
+ npm install
+
+Then run the tests by opening [test/index.html](test/index.html) in a browser.
+
+## API
+
+### `new ol.control.LayerSwitcher(opt_options)`
+
+OpenLayers 3 Layer Switcher Control.
+See [the examples](./examples) for usage.
+
+#### Parameters:
+
+|Name|Type|Description|
+|:---|:---|:----------|
+|`opt_options`|`Object`| Control options, extends olx.control.ControlOptions adding: **`tipLabel`** `String` - the button tooltip. |
+
+#### Extends
+
+`ol.control.Control`
+
+#### Methods
+
+##### `showPanel()`
+
+Show the layer panel.
+
+##### `hidePanel()`
+
+Hide the layer panel.
+
+##### `renderPanel()`
+
+Re-draw the layer panel to represent the current state of the layers.
+
+##### `setMap(map)`
+
+Set the map instance the control is associated with.
+
+###### Parameters:
+
+|Name|Type|Description|
+|:---|:---|:----------|
+|`map`|`ol.Map`| The map instance. |
+
+
+##### `(static) ol.control.LayerSwitcher.forEachRecursive(lyr,fn)`
+
+**Static** Call the supplied function for each layer in the passed layer group
+recursing nested groups.
+
+###### Parameters:
+
+|Name|Type|Description|
+|:---|:---|:----------|
+|`lyr`|`ol.layer.Group`| The layer group to start iterating from. |
+|`fn`|`function`| 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) ol.control.LayerSwitcher.uuid()`
+
+Generate a UUID
+
+## License
+
+MIT (c) Matt Walker.
+
+## Also see
+
+If you find the layer switcher useful you might also like the
+[ol3-popup](https://github.com/walkermatt/ol3-popup).
+
diff --git a/chimere/static/ol3-layerswitcher/ol3-layerswitcher.css b/chimere/static/ol3-layerswitcher/ol3-layerswitcher.css
new file mode 100644
index 0000000..088abd9
--- /dev/null
+++ b/chimere/static/ol3-layerswitcher/ol3-layerswitcher.css
@@ -0,0 +1,92 @@
+.layer-switcher.shown.ol-control {
+ background-color: transparent;
+}
+
+.layer-switcher.shown.ol-control:hover {
+ background-color: transparent;
+}
+
+.layer-switcher {
+ position: absolute;
+ top: 3.5em;
+ right: 0.5em;
+ text-align: left;
+}
+
+.layer-switcher.shown {
+ bottom: 3em;
+}
+
+.layer-switcher .panel {
+ padding: 0 1em 0 0;
+ margin: 0;
+ border: 4px solid #eee;
+ border-radius: 4px;
+ background-color: white;
+ display: none;
+ max-height: 100%;
+ overflow-y: auto;
+}
+
+.layer-switcher.shown .panel {
+ display: block;
+}
+
+.layer-switcher button {
+ float: right;
+ width: 38px;
+ height: 38px;
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACE1BMVEX///8A//8AgICA//8AVVVAQID///8rVVVJtttgv98nTmJ2xNgkW1ttyNsmWWZmzNZYxM4gWGgeU2JmzNNr0N1Rwc0eU2VXxdEhV2JqytQeVmMhVmNoydUfVGUgVGQfVGQfVmVqy9hqy9dWw9AfVWRpydVry9YhVmMgVGNUw9BrytchVWRexdGw294gVWQgVmUhVWPd4N6HoaZsy9cfVmQgVGRrytZsy9cgVWQgVWMgVWRsy9YfVWNsy9YgVWVty9YgVWVry9UgVWRsy9Zsy9UfVWRsy9YgVWVty9YgVWRty9Vsy9aM09sgVWRTws/AzM0gVWRtzNYgVWRuy9Zsy9cgVWRGcHxty9bb5ORbxdEgVWRty9bn6OZTws9mydRfxtLX3Nva5eRix9NFcXxOd4JPeINQeIMiVmVUws9Vws9Vw9BXw9BYxNBaxNBbxNBcxdJexdElWWgmWmhjyNRlx9IqXGtoipNpytVqytVryNNrytZsjZUuX210k5t1y9R2zNR3y9V4lp57zth9zdaAnKOGoaeK0NiNpquV09mesrag1tuitbmj1tuj19uktrqr2d2svcCu2d2xwMO63N+7x8nA3uDC3uDFz9DK4eHL4eLN4eIyYnDX5OM5Z3Tb397e4uDf4uHf5uXi5ePi5+Xj5+Xk5+Xm5+Xm6OY6aHXQ19fT4+NfhI1Ww89gx9Nhx9Nsy9ZWw9Dpj2abAAAAWnRSTlMAAQICAwQEBgcIDQ0ODhQZGiAiIyYpKywvNTs+QklPUlNUWWJjaGt0dnd+hIWFh4mNjZCSm6CpsbW2t7nDzNDT1dje5efr7PHy9PT29/j4+Pn5+vr8/f39/f6DPtKwAAABTklEQVR4Xr3QVWPbMBSAUTVFZmZmhhSXMjNvkhwqMzMzMzPDeD+xASvObKePPa+ffHVl8PlsnE0+qPpBuQjVJjno6pZpSKXYl7/bZyFaQxhf98hHDKEppwdWIW1frFnrxSOWHFfWesSEWC6R/P4zOFrix3TzDFLlXRTR8c0fEEJ1/itpo7SVO9Jdr1DVxZ0USyjZsEY5vZfiiAC0UoTGOrm9PZLuRl8X+Dq1HQtoFbJZbv61i+Poblh/97TC7n0neCcK0ETNUrz1/xPHf+DNAW9Ac6t8O8WH3Vp98f5lCaYKAOFZMLyHL4Y0fe319idMNgMMp+zWVSybUed/+/h7I4wRAG1W6XDy4XmjR9HnzvDRZXUAYDFOhC1S/Hh+fIXxen+eO+AKqbs+wAo30zDTDvDxKoJN88sjUzDFAvBzEUGFsnADoIvAJzoh2BZ8sner+Ke/vwECuQAAAABJRU5ErkJggg==') /*logo.png*/;
+ background-repeat: no-repeat;
+ background-position: 2px;
+ background-color: white;
+ border: none;
+}
+
+.layer-switcher.shown button {
+ display: none;
+}
+
+.layer-switcher button:focus, .layer-switcher button:hover {
+ background-color: white;
+}
+
+.layer-switcher ul {
+ padding-left: 1em;
+ list-style: none;
+}
+
+.layer-switcher li.group {
+ padding-top: 5px;
+}
+
+.layer-switcher li.group > label {
+ font-weight: bold;
+}
+
+.layer-switcher li.layer {
+ display: table;
+}
+
+.layer-switcher li.layer label, .layer-switcher li.layer input {
+ display: table-cell;
+ vertical-align: sub;
+}
+
+.layer-switcher input {
+ margin: 4px;
+}
+
+.layer-switcher.touch ::-webkit-scrollbar {
+ width: 4px;
+}
+
+.layer-switcher.touch ::-webkit-scrollbar-track {
+ -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
+ border-radius: 10px;
+}
+
+.layer-switcher.touch ::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
+}
diff --git a/chimere/static/ol3-layerswitcher/ol3-layerswitcher.js b/chimere/static/ol3-layerswitcher/ol3-layerswitcher.js
new file mode 100644
index 0000000..ee44e2f
--- /dev/null
+++ b/chimere/static/ol3-layerswitcher/ol3-layerswitcher.js
@@ -0,0 +1,283 @@
+/**
+ * OpenLayers 3 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.
+ */
+ol.control.LayerSwitcher = function(opt_options) {
+
+ var options = opt_options || {};
+
+ var tipLabel = options.tipLabel ?
+ options.tipLabel : 'Legend';
+
+ this.mapListeners = [];
+
+ this.hiddenClassName = 'ol-unselectable ol-control layer-switcher';
+ if (ol.control.LayerSwitcher.isTouchDevice_()) {
+ this.hiddenClassName += ' touch';
+ }
+ this.shownClassName = this.hiddenClassName + ' shown';
+
+ var element = document.createElement('div');
+ 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);
+ ol.control.LayerSwitcher.enableTouchScroll_(this.panel);
+
+ var this_ = this;
+
+ button.onmouseover = function(e) {
+ this_.showPanel();
+ };
+
+ button.onclick = function(e) {
+ e = e || window.event;
+ this_.showPanel();
+ e.preventDefault();
+ };
+
+ this_.panel.onmouseout = function(e) {
+ e = e || window.event;
+ if (!this_.panel.contains(e.toElement || e.relatedTarget)) {
+ this_.hidePanel();
+ }
+ };
+
+ ol.control.Control.call(this, {
+ element: element,
+ target: options.target
+ });
+
+};
+
+ol.inherits(ol.control.LayerSwitcher, ol.control.Control);
+
+/**
+ * Show the layer panel.
+ */
+ol.control.LayerSwitcher.prototype.showPanel = function() {
+ if (this.element.className != this.shownClassName) {
+ this.element.className = this.shownClassName;
+ this.renderPanel();
+ }
+};
+
+/**
+ * Hide the layer panel.
+ */
+ol.control.LayerSwitcher.prototype.hidePanel = function() {
+ if (this.element.className != this.hiddenClassName) {
+ this.element.className = this.hiddenClassName;
+ }
+};
+
+/**
+ * Re-draw the layer panel to represent the current state of the layers.
+ */
+ol.control.LayerSwitcher.prototype.renderPanel = function() {
+
+ this.ensureTopVisibleBaseLayerShown_();
+
+ while(this.panel.firstChild) {
+ this.panel.removeChild(this.panel.firstChild);
+ }
+
+ var ul = document.createElement('ul');
+ this.panel.appendChild(ul);
+ this.renderLayers_(this.getMap(), ul);
+
+};
+
+/**
+ * Set the map instance the control is associated with.
+ * @param {ol.Map} map The map instance.
+ */
+ol.control.LayerSwitcher.prototype.setMap = function(map) {
+ // Clean up listeners associated with the previous map
+ for (var i = 0, key; i < this.mapListeners.length; i++) {
+ this.getMap().unByKey(this.mapListeners[i]);
+ }
+ this.mapListeners.length = 0;
+ // Wire up listeners etc. and store reference to new map
+ ol.control.Control.prototype.setMap.call(this, map);
+ if (map) {
+ var this_ = this;
+ this.mapListeners.push(map.on('pointerdown', function() {
+ this_.hidePanel();
+ }));
+ this.renderPanel();
+ }
+};
+
+/**
+ * Ensure only the top-most base layer is visible if more than one is visible.
+ * @private
+ */
+ol.control.LayerSwitcher.prototype.ensureTopVisibleBaseLayerShown_ = function() {
+ var lastVisibleBaseLyr;
+ ol.control.LayerSwitcher.forEachRecursive(this.getMap(), function(l, idx, a) {
+ if (l.get('type') === 'base' && l.getVisible()) {
+ lastVisibleBaseLyr = l;
+ }
+ });
+ if (lastVisibleBaseLyr) this.setVisible_(lastVisibleBaseLyr, true);
+};
+
+/**
+ * Toggle the visible state of a layer.
+ * Takes care of hiding other layers in the same exclusive group if the layer
+ * is toggle to visible.
+ * @private
+ * @param {ol.layer.Base} The layer whos visibility will be toggled.
+ */
+ol.control.LayerSwitcher.prototype.setVisible_ = function(lyr, visible) {
+ var map = this.getMap();
+ lyr.setVisible(visible);
+ if (visible && lyr.get('type') === 'base') {
+ // Hide all other base layers regardless of grouping
+ ol.control.LayerSwitcher.forEachRecursive(map, function(l, idx, a) {
+ if (l != lyr && l.get('type') === 'base') {
+ l.setVisible(false);
+ }
+ });
+ }
+};
+
+/**
+ * Render all layers that are children of a group.
+ * @private
+ * @param {ol.layer.Base} lyr Layer to be rendered (should have a title property).
+ * @param {Number} idx Position in parent group list.
+ */
+ol.control.LayerSwitcher.prototype.renderLayer_ = function(lyr, idx) {
+
+ var this_ = this;
+
+ var li = document.createElement('li');
+
+ var lyrTitle = lyr.get('title');
+ var lyrId = ol.control.LayerSwitcher.uuid();
+
+ var label = document.createElement('label');
+
+ if (lyr.getLayers && !lyr.get('combine')) {
+
+ li.className = 'group';
+ label.innerHTML = lyrTitle;
+ li.appendChild(label);
+ var ul = document.createElement('ul');
+ li.appendChild(ul);
+
+ this.renderLayers_(lyr, ul);
+
+ } else {
+
+ li.className = 'layer';
+ var input = document.createElement('input');
+ if (lyr.get('type') === 'base') {
+ input.type = 'radio';
+ input.name = 'base';
+ } else {
+ input.type = 'checkbox';
+ }
+ input.id = lyrId;
+ input.checked = lyr.get('visible');
+ input.onchange = function(e) {
+ this_.setVisible_(lyr, e.target.checked);
+ };
+ li.appendChild(input);
+
+ label.htmlFor = lyrId;
+ label.innerHTML = lyrTitle;
+ li.appendChild(label);
+
+ }
+
+ return li;
+
+};
+
+/**
+ * Render all layers that are children of a group.
+ * @private
+ * @param {ol.layer.Group} lyr Group layer whos children will be rendered.
+ * @param {Element} elm DOM element that children will be appended to.
+ */
+ol.control.LayerSwitcher.prototype.renderLayers_ = function(lyr, elm) {
+ var lyrs = lyr.getLayers().getArray().slice().reverse();
+ for (var i = 0, l; i < lyrs.length; i++) {
+ l = lyrs[i];
+ if (l.get('title')) {
+ elm.appendChild(this.renderLayer_(l, i));
+ }
+ }
+};
+
+/**
+ * **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`
+ */
+ol.control.LayerSwitcher.forEachRecursive = function(lyr, fn) {
+ lyr.getLayers().forEach(function(lyr, idx, a) {
+ fn(lyr, idx, a);
+ if (lyr.getLayers) {
+ ol.control.LayerSwitcher.forEachRecursive(lyr, fn);
+ }
+ });
+};
+
+/**
+ * Generate a UUID
+ * @returns {String} UUID
+ *
+ * Adapted from http://stackoverflow.com/a/2117523/526860
+ */
+ol.control.LayerSwitcher.uuid = function() {
+ 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
+*/
+ol.control.LayerSwitcher.enableTouchScroll_ = function(elm) {
+ if(ol.control.LayerSwitcher.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
+ */
+ol.control.LayerSwitcher.isTouchDevice_ = function() {
+ try {
+ document.createEvent("TouchEvent");
+ return true;
+ } catch(e) {
+ return false;
+ }
+};