summaryrefslogtreecommitdiff
path: root/ishtar_common/static
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2022-06-10 15:27:18 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2022-12-12 12:21:01 +0100
commit046fc176ad188faffb4e386d02dac5d6705a4b5a (patch)
treed79de9dbcccd0b15255af94fbcbab7e8766a96d0 /ishtar_common/static
parentf4bbccb5214ff0dd2cbd7bc76973f64c06fc9509 (diff)
downloadIshtar-046fc176ad188faffb4e386d02dac5d6705a4b5a.tar.bz2
Ishtar-046fc176ad188faffb4e386d02dac5d6705a4b5a.zip
Geo: add ol-layerswitcher lib
Diffstat (limited to 'ishtar_common/static')
-rw-r--r--ishtar_common/static/ol-layerswitcher/LICENSE9
-rw-r--r--ishtar_common/static/ol-layerswitcher/README.md521
-rw-r--r--ishtar_common/static/ol-layerswitcher/ol-layerswitcher.css188
-rw-r--r--ishtar_common/static/ol-layerswitcher/ol-layerswitcher.js725
4 files changed, 1443 insertions, 0 deletions
diff --git a/ishtar_common/static/ol-layerswitcher/LICENSE b/ishtar_common/static/ol-layerswitcher/LICENSE
new file mode 100644
index 000000000..71464d1a7
--- /dev/null
+++ b/ishtar_common/static/ol-layerswitcher/LICENSE
@@ -0,0 +1,9 @@
+MIT license
+
+Copyright (C) 2017-2022, Matt Walker.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/ishtar_common/static/ol-layerswitcher/README.md b/ishtar_common/static/ol-layerswitcher/README.md
new file mode 100644
index 000000000..470ce1395
--- /dev/null
+++ b/ishtar_common/static/ol-layerswitcher/README.md
@@ -0,0 +1,521 @@
+# OpenLayers LayerSwitcher
+
+Grouped layer list control for an OpenLayer map.
+
+To be shown in the LayerSwitcher layers should have a `title` property; base
+layers should have a `type` property set to `base`. Group layers
+(`LayerGroup`) can be used to visually group layers together; a group with
+a `fold` property set to either `open` or `close` will be displayed with a
+toggle.
+
+See [**API documentation**](#api) and [**Examples**](#examples) for usage.
+
+Compatible with OpenLayers version 3, 4, 5 and 6 (see note in [Install - Parcel,
+Webpack etc.](#parcel-webpack-etc) regarding installing the appropriate version
+of `ol-layerswitcher` for OpenLayers).
+
+## Examples
+
+The examples demonstrate usage and can be viewed online thanks to [raw.githack.com](http://raw.githack.com/):
+
+- [Basic usage](http://raw.githack.com/walkermatt/ol-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. See the comments in [examples/layerswitcher.js](./examples/layerswitcher.js) for other layer/ group options including `combine` and `fold`.
+- [Add layer](http://raw.githack.com/walkermatt/ol-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://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/scroll.html)
+ - Makes the panel scroll vertically, the height of the layer switcher is controlled by setting the `max-height` style (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 [dist/ol-layerswitcher.css](dist/ol-layerswitcher.css)).
+- [Side bar](http://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/sidebar.html)
+ - Demonstrates rendering the layer tree into a [Turbo87/sidebar-v2](https://github.com/Turbo87/sidebar-v2) pane. This uses the static method [`LayerSwitcher.renderPanel`](#renderpanel) which can be used to render the layer tree to any arbitrary HTML element.
+- [Collapse groups](http://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/collapse-groups.html)
+ - Shows the effect of setting the `fold` property of a Group to allow the group to be collapsed.
+- [Selectable Groups](http://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/select-groups.html)
+ - Demonstrates setting the [`groupSelectStyle`](#layerswitcher) option which determines if groups have a checkbox and how toggling a groups visibility affects it's children. The demo includes the ability to change the `groupSelectStyle` to easily see the effect of the different values.
+- [Bundling with `ol` package (Browserify, Parcel, Webpack...)](https://github.com/walkermatt/ol-layerswitcher-examples)
+- [Activate panel with click](http://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/activation-mode-click.html)
+ - Shows setting `activationMode: 'click'` (default is `'mouseover'`). When using this mode the control's button persists in the panel - use `collapseLabel` to set its text (default is `collapseLabel: '»'`, see the comments in [examples/layerswitcher.js](./examples/layerswitcher.js) for other examples). The close button is positioned to the left of the panel, to move it to the right add the following to your CSS:
+
+```CSS
+.layer-switcher.shown.layer-switcher-activation-mode-click {
+ padding-right: 34px;
+}
+.layer-switcher.shown.layer-switcher-activation-mode-click > button {
+ right: 0;
+ border-left: 0;
+}
+```
+
+- [Start with panel active](http://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/startactive-click.html)
+ - Example with the layer switcher starting open using `startActive: true`. Here shown in combination with \`activationMode: 'click' which, while not required, is probably the most common scenario.
+- [Multiple maps](http://raw.githack.com/walkermatt/ol-layerswitcher/master/examples/two-maps.html)
+
+ - Demonstrates creating two independent maps each with a layer switcher control.
+
+- To use the layer switcher with the [`ol` package](https://www.npmjs.com/package/ol) and a module bundler such as Browserify, Parcel, Webpack, TypeScript etc. see [ol-layerswitcher-examples](https://github.com/walkermatt/ol-layerswitcher-examples).
+
+The source for all examples can be found in [examples](examples).
+
+## Changelog
+
+See [CHANGELOG](./CHANGELOG.md) for details of changes in each release.
+
+## Install
+
+### Browser
+
+#### JS
+
+Load `ol-layerswitcher.js` after OpenLayers. The layerswitcher control is available as `LayerSwitcher` or `ol.control.LayerSwitcher`.
+
+```HTML
+<script src="https://unpkg.com/ol-layerswitcher@3.8.3"></script>
+```
+
+#### CSS
+
+```HTML
+<link rel="stylesheet" href="https://unpkg.com/ol-layerswitcher@3.8.3/dist/ol-layerswitcher.css" />
+```
+
+### Parcel, Rollup, Webpack, TypeScript etc.
+
+NPM package: [ol-layerswitcher](https://www.npmjs.com/package/ol-layerswitcher).
+
+#### JS
+
+Install the package via `npm`
+
+ npm install ol-layerswitcher --save
+
+:warning: If you're using the [`ol` package](https://www.npmjs.com/package/ol) prior to v5 you'll need to install `ol-layerswitcher@v2.0.0`.
+
+#### CSS
+
+The CSS file `ol-layerswitcher.css` can be found in `./node_modules/ol-layerswitcher/dist`
+
+To use the layerswitcher with the [`ol` package](https://www.npmjs.com/package/ol) and a module bundler such as Parcel, Webpack etc. see [ol-layerswitcher-examples](https://github.com/walkermatt/ol-layerswitcher-examples).
+
+#### TypeScript type definition
+
+TypeScript types are shipped with the project in the `dist` directory and should be automatically used in a TypeScript project. Interfaces are provided for LayerSwitcher Options as well as extend interfaces for BaseLayer and LayerGroup Options that include the LayerSwitcher specific properties such as `title`, `combine` etc.
+
+These interfaces can be imported into your project and used to cast object literals passed to layer or group constructors:
+
+```typescript
+import 'ol/ol.css';
+import 'ol-layerswitcher/dist/ol-layerswitcher.css';
+
+import Map from 'ol/Map';
+import View from 'ol/View';
+import LayerGroup from 'ol/layer/Group';
+import LayerTile from 'ol/layer/Tile';
+import SourceOSM from 'ol/source/OSM';
+import SourceStamen from 'ol/source/Stamen';
+
+import LayerSwitcher from 'ol-layerswitcher';
+import { BaseLayerOptions, GroupLayerOptions } from 'ol-layerswitcher';
+
+const osm = new LayerTile({
+ title: 'OSM',
+ type: 'base',
+ visible: true,
+ source: new SourceOSM()
+} as BaseLayerOptions);
+
+const watercolor = new LayerTile({
+ title: 'Water color',
+ type: 'base',
+ visible: false,
+ source: new SourceStamen({
+ layer: 'watercolor'
+ })
+} as BaseLayerOptions);
+
+const baseMaps = new LayerGroup({
+ title: 'Base maps',
+ layers: [osm, watercolor]
+} as GroupLayerOptions);
+
+const map = new Map({
+ target: 'map',
+ layers: [baseMaps]
+});
+
+const layerSwitcher = new LayerSwitcher({
+ reverse: true,
+ groupSelectStyle: 'group'
+});
+map.addControl(layerSwitcher);
+```
+
+See [BaseLayerOptions](#baselayeroptions) and [GroupLayerOptions](#grouplayeroptions).
+
+## API
+
+<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
+
+#### Table of Contents
+
+- [LayerSwitcher](#layerswitcher)
+ - [Parameters](#parameters)
+ - [setMap](#setmap)
+ - [Parameters](#parameters-1)
+ - [showPanel](#showpanel)
+ - [hidePanel](#hidepanel)
+ - [renderPanel](#renderpanel)
+ - [renderPanel](#renderpanel-1)
+ - [Parameters](#parameters-2)
+ - [isBaseGroup](#isbasegroup)
+ - [Parameters](#parameters-3)
+ - [getGroupsAndLayers](#getgroupsandlayers)
+ - [Parameters](#parameters-4)
+ - [forEachRecursive](#foreachrecursive)
+ - [Parameters](#parameters-5)
+ - [uuid](#uuid)
+- [LayerSwitcher#show](#layerswitchershow)
+- [LayerSwitcher#hide](#layerswitcherhide)
+- [Options](#options)
+ - [activationMode](#activationmode)
+ - [startActive](#startactive)
+ - [label](#label)
+ - [collapseLabel](#collapselabel)
+ - [tipLabel](#tiplabel)
+ - [collapseTipLabel](#collapsetiplabel)
+- [RenderOptions](#renderoptions)
+ - [groupSelectStyle](#groupselectstyle)
+ - [reverse](#reverse)
+- [GroupSelectStyle](#groupselectstyle-1)
+- [BaseLayerOptions](#baselayeroptions)
+ - [title](#title)
+ - [type](#type)
+- [GroupLayerOptions](#grouplayeroptions)
+ - [combine](#combine)
+ - [fold](#fold)
+
+### LayerSwitcher
+
+**Extends ol/control/Control~Control**
+
+OpenLayers LayerSwitcher Control, displays a list of layers and groups
+associated with a map which have a `title` property.
+
+To be shown in the LayerSwitcher panel layers must have a `title` property;
+base map layers should have a `type` property set to `base`. Group layers
+(`LayerGroup`) can be used to visually group layers together; a group
+with a `fold` property set to either `'open'` or `'close'` will be displayed
+with a toggle.
+
+See [BaseLayerOptions](#baselayeroptions) for a full list of LayerSwitcher
+properties for layers (`TileLayer`, `ImageLayer`, `VectorTile` etc.) and
+[GroupLayerOptions](#grouplayeroptions) for group layer (`LayerGroup`)
+LayerSwitcher properties.
+
+Layer and group properties can either be set by adding extra properties
+to their options when they are created or via their set method.
+
+Specify a `title` for a Layer by adding a `title` property to it's options object:
+
+```javascript
+var lyr = new ol.layer.Tile({
+ // Specify a title property which will be displayed by the layer switcher
+ title: 'OpenStreetMap',
+ visible: true,
+ source: new ol.source.OSM()
+});
+```
+
+Alternatively the properties can be set via the `set` method after a layer has been created:
+
+```javascript
+var lyr = new ol.layer.Tile({
+ visible: true,
+ source: new ol.source.OSM()
+});
+// Specify a title property which will be displayed by the layer switcher
+lyr.set('title', 'OpenStreetMap');
+```
+
+To create a LayerSwitcher and add it to a map, create a new instance then pass it to the map's [`addControl` method](https://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html#addControl).
+
+```javascript
+var layerSwitcher = new LayerSwitcher({
+ reverse: true,
+ groupSelectStyle: 'group'
+});
+map.addControl(layerSwitcher);
+```
+
+#### Parameters
+
+- `opt_options` **[Options](#options)?** LayerSwitcher options, see [LayerSwitcher Options](#options) and [RenderOptions](#renderoptions) which LayerSwitcher `Options` extends for more details.
+
+#### setMap
+
+Set the map instance the control is associated with.
+
+##### Parameters
+
+- `map` **[PluggableMap](https://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html)** The map instance.
+
+Returns **void**
+
+#### showPanel
+
+Show the layer panel. Fires `'show'` event.
+
+Returns **void**
+
+#### hidePanel
+
+Hide the layer panel. Fires `'hide'` event.
+
+Returns **void**
+
+#### renderPanel
+
+Re-draw the layer panel to represent the current state of the layers.
+
+Returns **void**
+
+#### renderPanel
+
+**_[static]_** - Re-draw the layer panel to represent the current state of the layers.
+
+##### Parameters
+
+- `map` **[PluggableMap](https://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html)** The OpenLayers Map instance to render layers for
+- `panel` **[HTMLElement](https://developer.mozilla.org/docs/Web/HTML/Element)** The DOM Element into which the layer tree will be rendered
+- `options` **[RenderOptions](#renderoptions)** Options for panel, group, and layers
+
+Returns **void**
+
+#### isBaseGroup
+
+**_[static]_** - Determine if a given layer group contains base layers
+
+##### Parameters
+
+- `grp` **[LayerGroup](https://openlayers.org/en/latest/apidoc/module-ol_layer_Group-LayerGroup.html)** Group to test
+
+Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
+
+#### getGroupsAndLayers
+
+**_[static]_** - Get an Array of all layers and groups displayed by the LayerSwitcher (has a `'title'` property)
+contained by the specified map or layer group; optionally filtering via `filterFn`
+
+##### Parameters
+
+- `grp` **([PluggableMap](https://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html) | [LayerGroup](https://openlayers.org/en/latest/apidoc/module-ol_layer_Group-LayerGroup.html))** The map or layer group for which layers are found.
+- `filterFn` **function (lyr: [BaseLayer](https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html), idx: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), arr: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[BaseLayer](https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html)>): [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Optional function used to filter the returned layers
+
+Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[BaseLayer](https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html)>**
+
+#### forEachRecursive
+
+**_[static]_** - Call the supplied function for each layer in the passed layer group
+recursing nested groups.
+
+##### Parameters
+
+- `lyr` **([PluggableMap](https://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html) | [LayerGroup](https://openlayers.org/en/latest/apidoc/module-ol_layer_Group-LayerGroup.html))** The layer group to start iterating from.
+- `fn` **function (lyr: [BaseLayer](https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html), idx: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), arr: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[BaseLayer](https://openlayers.org/en/latest/apidoc/module-ol_layer_Base-BaseLayer.html)>): void** Callback which will be called for each layer
+ found under `lyr`.
+
+Returns **void**
+
+#### uuid
+
+**_[static]_** - Generate a UUID
+Adapted from <http://stackoverflow.com/a/2117523/526860>
+
+Returns **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** UUID
+
+### LayerSwitcher#show
+
+Event triggered after the panel has been shown.
+Listen to the event via the `on` or `once` methods; for example:
+
+```js
+var layerSwitcher = new LayerSwitcher();
+map.addControl(layerSwitcher);
+
+layerSwitcher.on('show', (evt) => {
+ console.log('show', evt);
+});
+```
+
+### LayerSwitcher#hide
+
+Event triggered after the panel has been hidden.
+
+### Options
+
+**Extends ControlOptions, RenderOptions**
+
+**_[interface]_** - LayerSwitcher Options specified when creating a LayerSwitcher
+instance, extends [RenderOptions](#renderoptions) and
+[Control Options](https://openlayers.org/en/latest/apidoc/module-ol_control_Control-Control.html#Control).
+
+Default values:
+
+```javascript
+{
+ activationMode: 'mouseover',
+ startActive: false,
+ label: ''
+ collapseLabel: '\u00BB',
+ tipLabel: 'Legend',
+ collapseTipLabel: 'Collapse legend',
+ groupSelectStyle: 'children',
+ reverse: false
+}
+```
+
+#### activationMode
+
+Event to use on the button to collapse or expand the panel. Defaults to
+`"mouseover"`.
+
+Type: (`"mouseover"` \| `"click"`)
+
+#### startActive
+
+Whether panel is open when created. Defaults to `false`.
+
+Type: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
+
+#### label
+
+Text label to use for the button that opens the panel. E.g.: `''` (default), `'«'` or `'\u00AB'`, `'+'`.
+
+Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
+
+#### collapseLabel
+
+Text label to use for the button that closes the panel. E.g.: `'»'` (default) or `'\u00BB'`, `'-'` or `'\u2212'`. Only used when `activationMode: 'mouseover'`.
+
+Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
+
+#### tipLabel
+
+The button tooltip when the panel is closed.
+
+Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
+
+#### collapseTipLabel
+
+The button tooltip when the panel is open.
+
+Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
+
+### RenderOptions
+
+**_[interface]_** - LayerSwitcher Render Options as passed to [LayerSwitcher
+constructor](#layerswitcher) as part of [Options](#options) and [static
+LayerSwitcher.renderPanel](#renderpanel)
+
+#### groupSelectStyle
+
+How layers and groups behave when a given layer's visibility is set. See [GroupSelectStyle type for possible values](#groupselectstyle).
+
+Type: [GroupSelectStyle](#groupselectstyle)
+
+#### reverse
+
+Should the order of layers in the panel be reversed?
+
+Type: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
+
+### GroupSelectStyle
+
+**_[type]_** - How layers and groups behave when a given layer's visibility is set, either:
+
+- `'none'` - groups don't get a checkbox,
+- `'children'` (default) groups have a checkbox and affect child visibility or
+- `'group'` groups have a checkbox but do not alter child visibility (like QGIS).
+
+Type: (`"none"` \| `"children"` \| `"group"`)
+
+### BaseLayerOptions
+
+**Extends [ol/layer/Base~Options](https://openlayers.org/en/latest/apidoc/module-ol_layer_Base.html#~Options)**
+
+**_[interface]_** - Extended BaseLayer Options interface adding properties
+used by the LayerSwitcher
+
+#### title
+
+Title of the layer displayed in the LayerSwitcher panel
+
+Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)
+
+#### type
+
+Type of the layer, a layer of `type: 'base'` is treated as a base map
+layer by the LayerSwitcher and is displayed with a radio button
+
+Type: `"base"`
+
+### GroupLayerOptions
+
+**Extends [ol/layer/Group~Options](https://openlayers.org/en/latest/apidoc/module-ol_layer_Group.html#~Options), BaseLayerOptions**
+
+**_[interface]_** - Extended LayerGroup Options interface adding
+properties used by the LayerSwitcher.
+
+#### combine
+
+When `true` child layers are not shown in the Layer Switcher panel
+
+Type: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
+
+#### fold
+
+Fold state of the group, if set then the group will be displayed with a
+button to allow the user to show/ hide the child layers.
+
+Type: (`"open"` \| `"close"`)
+
+## 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.
+
+## License
+
+MIT (c) Matt Walker.
+
+## Also see
+
+If you find the layer switcher useful you might also like the
+[ol-popup](https://github.com/walkermatt/ol-popup).
+
+## Publishing
+
+ npm run build
+ # Open ./tests/ in browser
+ # Open examples and manually test
+ # Determine new version number (check current with `git tag --list`, check npm and GitHub)
+ # Update version number in `package.json`, `bower.json` and `README.md`
+ # Add entry to CHANGELOG.md
+ git commit bower.json package.json CHANGELOG.md README.md
+ git tag vX.Y.Z
+ git push origin master --tags
+ npm publish
+
+### Beta release
+
+ npm run build
+ # Tests/ examples
+ # Beta version should be X.Y.Z-beta.N
+ # Update version number in `package.json`, `bower.json` and `README.md`
+ # Add entry to CHANGELOG.md
+ git commit bower.json package.json CHANGELOG.md README.md
+ git tag vX.Y.Z-beta.N
+ git push --tags
+ npm publish --tag beta
+ # To list all version on npm
+ npm show ol-layerswitcher versions --json
diff --git a/ishtar_common/static/ol-layerswitcher/ol-layerswitcher.css b/ishtar_common/static/ol-layerswitcher/ol-layerswitcher.css
new file mode 100644
index 000000000..7cf1961c7
--- /dev/null
+++ b/ishtar_common/static/ol-layerswitcher/ol-layerswitcher.css
@@ -0,0 +1,188 @@
+.layer-switcher {
+ position: absolute;
+ top: 3.5em;
+ right: 0.5em;
+ text-align: left;
+}
+
+.layer-switcher .panel {
+ margin: 0;
+ border: 4px solid #eee;
+ border-radius: 4px;
+ background-color: white;
+ display: none;
+ max-height: inherit;
+ height: 100%;
+ box-sizing: border-box;
+ overflow-y: auto;
+}
+
+.layer-switcher button {
+ float: right;
+ z-index: 1;
+ 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;
+ color: black;
+ border: none;
+}
+
+.layer-switcher button:focus,
+.layer-switcher button:hover {
+ background-color: white;
+}
+
+.layer-switcher.shown {
+ overflow-y: hidden;
+ display: flex;
+ flex-direction: column;
+ max-height: calc(100% - 5.5em);
+}
+
+.layer-switcher.shown.ol-control {
+ background-color: transparent;
+}
+
+.layer-switcher.shown.ol-control:hover {
+ background-color: transparent;
+}
+.layer-switcher.shown .panel {
+ display: block;
+}
+
+.layer-switcher.shown button {
+ display: none;
+}
+
+.layer-switcher.shown.layer-switcher-activation-mode-click > button {
+ display: block;
+ background-image: unset;
+ right: 2px;
+ position: absolute;
+ background-color: #eee;
+ margin: 0 1px;
+}
+
+.layer-switcher.shown button:focus,
+.layer-switcher.shown button:hover {
+ background-color: #fafafa;
+}
+
+.layer-switcher ul {
+ list-style: none;
+ margin: 1.6em 0.4em;
+ padding-left: 0;
+}
+.layer-switcher ul ul {
+ padding-left: 1.2em;
+ margin: 0.1em 0 0 0;
+}
+.layer-switcher li.group + li.group {
+ margin-top: 0.4em;
+}
+.layer-switcher li.group + li.layer-switcher-base-group {
+}
+
+.layer-switcher li.group > label {
+ font-weight: bold;
+}
+
+.layer-switcher.layer-switcher-group-select-style-none li.group > label {
+ padding-left: 1.2em;
+}
+
+.layer-switcher li {
+ position: relative;
+ margin-top: 0.3em;
+}
+
+.layer-switcher li input {
+ position: absolute;
+ left: 1.2em;
+ height: 1em;
+ width: 1em;
+ font-size: 1em;
+}
+.layer-switcher li label {
+ padding-left: 2.7em;
+ padding-right: 1.2em;
+ display: inline-block;
+ margin-top: 1px;
+}
+
+.layer-switcher label.disabled {
+ opacity: 0.4;
+}
+
+.layer-switcher input {
+ margin: 0px;
+}
+
+.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);
+}
+
+li.layer-switcher-base-group > label {
+ padding-left: 1.2em;
+}
+
+.layer-switcher .group button {
+ position: absolute;
+ left: 0;
+ display: inline-block;
+ vertical-align: top;
+ float: none;
+ font-size: 1em;
+ width: 1em;
+ height: 1em;
+ margin: 0;
+ background-position: center 2px;
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVR4nGNgGAWMyBwXFxcGBgaGeii3EU0tXHzPnj1wQRYsihqQ+I0ExDEMQAYNONgoAN0AmMkNaDSyQSheY8JiaCMOGzE04zIAmyFYNTMw4A+DRhzsUUBtAADw4BCeIZkGdwAAAABJRU5ErkJggg==');
+ -webkit-transition: -webkit-transform 0.2s ease-in-out;
+ -ms-transition: -ms-transform 0.2s ease-in-out;
+ transition: transform 0.2s ease-in-out;
+}
+
+.layer-switcher .group.layer-switcher-close button {
+ transform: rotate(-90deg);
+ -webkit-transform: rotate(-90deg);
+}
+
+.layer-switcher .group.layer-switcher-fold.layer-switcher-close > ul {
+ overflow: hidden;
+ height: 0;
+}
+
+/*layerswitcher on the right*/
+.layer-switcher.shown.layer-switcher-activation-mode-click {
+ padding-left: 34px;
+}
+.layer-switcher.shown.layer-switcher-activation-mode-click > button {
+ left: 0;
+ border-right: 0;
+}
+
+/*layerswitcher on the left*/
+/*
+.layer-switcher.shown.layer-switcher-activation-mode-click {
+ padding-right: 34px;
+}
+.layer-switcher.shown.layer-switcher-activation-mode-click > button {
+ right: 0;
+ border-left: 0;
+}
+*/
diff --git a/ishtar_common/static/ol-layerswitcher/ol-layerswitcher.js b/ishtar_common/static/ol-layerswitcher/ol-layerswitcher.js
new file mode 100644
index 000000000..d5ca3c7aa
--- /dev/null
+++ b/ishtar_common/static/ol-layerswitcher/ol-layerswitcher.js
@@ -0,0 +1,725 @@
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('ol/control/Control'), require('ol/Observable'), require('ol/layer/Group')) :
+ typeof define === 'function' && define.amd ? define(['ol/control/Control', 'ol/Observable', 'ol/layer/Group'], factory) :
+ (global.LayerSwitcher = factory(global.ol.control.Control,global.ol.Observable,global.ol.layer.Group));
+}(this, (function (Control,ol_Observable,LayerGroup) { 'use strict';
+
+Control = 'default' in Control ? Control['default'] : Control;
+LayerGroup = 'default' in LayerGroup ? LayerGroup['default'] : LayerGroup;
+
+var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+};
+
+var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+}();
+
+
+
+
+
+
+
+var get = function get(object, property, receiver) {
+ if (object === null) object = Function.prototype;
+ var desc = Object.getOwnPropertyDescriptor(object, property);
+
+ if (desc === undefined) {
+ var parent = Object.getPrototypeOf(object);
+
+ if (parent === null) {
+ return undefined;
+ } else {
+ return get(parent, property, receiver);
+ }
+ } else if ("value" in desc) {
+ return desc.value;
+ } else {
+ var getter = desc.get;
+
+ if (getter === undefined) {
+ return undefined;
+ }
+
+ return getter.call(receiver);
+ }
+};
+
+var inherits = function (subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+};
+
+
+
+
+
+
+
+
+
+
+
+var possibleConstructorReturn = function (self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+};
+
+/**
+ * @protected
+ */
+var CSS_PREFIX = 'layer-switcher-';
+/**
+ * OpenLayers LayerSwitcher Control, displays a list of layers and groups
+ * associated with a map which have a `title` property.
+ *
+ * To be shown in the LayerSwitcher panel layers must have a `title` property;
+ * base map layers should have a `type` property set to `base`. Group layers
+ * (`LayerGroup`) can be used to visually group layers together; a group
+ * with a `fold` property set to either `'open'` or `'close'` will be displayed
+ * with a toggle.
+ *
+ * See [BaseLayerOptions](#baselayeroptions) for a full list of LayerSwitcher
+ * properties for layers (`TileLayer`, `ImageLayer`, `VectorTile` etc.) and
+ * [GroupLayerOptions](#grouplayeroptions) for group layer (`LayerGroup`)
+ * LayerSwitcher properties.
+ *
+ * Layer and group properties can either be set by adding extra properties
+ * to their options when they are created or via their set method.
+ *
+ * Specify a `title` for a Layer by adding a `title` property to it's options object:
+ * ```javascript
+ * var lyr = new ol.layer.Tile({
+ * // Specify a title property which will be displayed by the layer switcher
+ * title: 'OpenStreetMap',
+ * visible: true,
+ * source: new ol.source.OSM()
+ * })
+ * ```
+ *
+ * Alternatively the properties can be set via the `set` method after a layer has been created:
+ * ```javascript
+ * var lyr = new ol.layer.Tile({
+ * visible: true,
+ * source: new ol.source.OSM()
+ * })
+ * // Specify a title property which will be displayed by the layer switcher
+ * lyr.set('title', 'OpenStreetMap');
+ * ```
+ *
+ * To create a LayerSwitcher and add it to a map, create a new instance then pass it to the map's [`addControl` method](https://openlayers.org/en/latest/apidoc/module-ol_PluggableMap-PluggableMap.html#addControl).
+ * ```javascript
+ * var layerSwitcher = new LayerSwitcher({
+ * reverse: true,
+ * groupSelectStyle: 'group'
+ * });
+ * map.addControl(layerSwitcher);
+ * ```
+ *
+ * @constructor
+ * @extends {ol/control/Control~Control}
+ * @param opt_options LayerSwitcher options, see [LayerSwitcher Options](#options) and [RenderOptions](#renderoptions) which LayerSwitcher `Options` extends for more details.
+ */
+
+var LayerSwitcher = function (_Control) {
+ inherits(LayerSwitcher, _Control);
+
+ function LayerSwitcher(opt_options) {
+ classCallCheck(this, LayerSwitcher);
+
+ var options = Object.assign({}, opt_options);
+ var element = document.createElement('div');
+
+ var _this = possibleConstructorReturn(this, (LayerSwitcher.__proto__ || Object.getPrototypeOf(LayerSwitcher)).call(this, { element: element, target: options.target }));
+
+ _this.activationMode = options.activationMode || 'mouseover';
+ _this.startActive = options.startActive === true;
+ // TODO Next: Rename to showButtonContent
+ _this.label = options.label !== undefined ? options.label : '';
+ // TODO Next: Rename to hideButtonContent
+ _this.collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\xBB';
+ // TODO Next: Rename to showButtonTitle
+ _this.tipLabel = options.tipLabel ? options.tipLabel : 'Legend';
+ // TODO Next: Rename to hideButtonTitle
+ _this.collapseTipLabel = options.collapseTipLabel ? options.collapseTipLabel : 'Collapse legend';
+ _this.groupSelectStyle = LayerSwitcher.getGroupSelectStyle(options.groupSelectStyle);
+ _this.reverse = options.reverse !== false;
+ _this.mapListeners = [];
+ _this.hiddenClassName = 'ol-unselectable ol-control layer-switcher';
+ if (LayerSwitcher.isTouchDevice_()) {
+ _this.hiddenClassName += ' touch';
+ }
+ _this.shownClassName = 'shown';
+ element.className = _this.hiddenClassName;
+ _this.button = document.createElement('button');
+ element.appendChild(_this.button);
+ _this.panel = document.createElement('div');
+ _this.panel.className = 'panel';
+ element.appendChild(_this.panel);
+ LayerSwitcher.enableTouchScroll_(_this.panel);
+ element.classList.add(CSS_PREFIX + 'group-select-style-' + _this.groupSelectStyle);
+ element.classList.add(CSS_PREFIX + 'activation-mode-' + _this.activationMode);
+ if (_this.activationMode === 'click') {
+ // TODO Next: Remove in favour of layer-switcher-activation-mode-click
+ element.classList.add('activationModeClick');
+ _this.button.onclick = function (e) {
+ var evt = e || window.event;
+ if (_this.element.classList.contains(_this.shownClassName)) {
+ _this.hidePanel();
+ } else {
+ _this.showPanel();
+ }
+ evt.preventDefault();
+ };
+ } else {
+ _this.button.onmouseover = function () {
+ _this.showPanel();
+ };
+ _this.button.onclick = function (e) {
+ var evt = e || window.event;
+ _this.showPanel();
+ evt.preventDefault();
+ };
+ _this.panel.onmouseout = function (evt) {
+ if (!_this.panel.contains(evt.relatedTarget)) {
+ _this.hidePanel();
+ }
+ };
+ }
+ _this.updateButton();
+ return _this;
+ }
+ /**
+ * Set the map instance the control is associated with.
+ * @param map The map instance.
+ */
+
+
+ createClass(LayerSwitcher, [{
+ key: 'setMap',
+ value: function setMap(map) {
+ var _this2 = this;
+
+ // Clean up listeners associated with the previous map
+ for (var i = 0; i < this.mapListeners.length; i++) {
+ ol_Observable.unByKey(this.mapListeners[i]);
+ }
+ this.mapListeners.length = 0;
+ // Wire up listeners etc. and store reference to new map
+ get(LayerSwitcher.prototype.__proto__ || Object.getPrototypeOf(LayerSwitcher.prototype), 'setMap', this).call(this, map);
+ if (map) {
+ if (this.startActive) {
+ this.showPanel();
+ } else {
+ this.renderPanel();
+ }
+ if (this.activationMode !== 'click') {
+ this.mapListeners.push(map.on('pointerdown', function () {
+ _this2.hidePanel();
+ }));
+ }
+ }
+ }
+ /**
+ * Show the layer panel. Fires `'show'` event.
+ * @fires LayerSwitcher#show
+ */
+
+ }, {
+ key: 'showPanel',
+ value: function showPanel() {
+ if (!this.element.classList.contains(this.shownClassName)) {
+ this.element.classList.add(this.shownClassName);
+ this.updateButton();
+ this.renderPanel();
+ }
+ /**
+ * Event triggered after the panel has been shown.
+ * Listen to the event via the `on` or `once` methods; for example:
+ * ```js
+ * var layerSwitcher = new LayerSwitcher();
+ * map.addControl(layerSwitcher);
+ *
+ * layerSwitcher.on('show', evt => {
+ * console.log('show', evt);
+ * });
+ * @event LayerSwitcher#show
+ */
+ this.dispatchEvent('show');
+ }
+ /**
+ * Hide the layer panel. Fires `'hide'` event.
+ * @fires LayerSwitcher#hide
+ */
+
+ }, {
+ key: 'hidePanel',
+ value: function hidePanel() {
+ if (this.element.classList.contains(this.shownClassName)) {
+ this.element.classList.remove(this.shownClassName);
+ this.updateButton();
+ }
+ /**
+ * Event triggered after the panel has been hidden.
+ * @event LayerSwitcher#hide
+ */
+ this.dispatchEvent('hide');
+ }
+ /**
+ * Update button text content and attributes based on current
+ * state
+ */
+
+ }, {
+ key: 'updateButton',
+ value: function updateButton() {
+ if (this.element.classList.contains(this.shownClassName)) {
+ this.button.textContent = this.collapseLabel;
+ this.button.setAttribute('title', this.collapseTipLabel);
+ this.button.setAttribute('aria-label', this.collapseTipLabel);
+ } else {
+ this.button.textContent = this.label;
+ this.button.setAttribute('title', this.tipLabel);
+ this.button.setAttribute('aria-label', this.tipLabel);
+ }
+ }
+ /**
+ * Re-draw the layer panel to represent the current state of the layers.
+ */
+
+ }, {
+ key: 'renderPanel',
+ value: function renderPanel() {
+ this.dispatchEvent('render');
+ LayerSwitcher.renderPanel(this.getMap(), this.panel, {
+ groupSelectStyle: this.groupSelectStyle,
+ reverse: this.reverse
+ });
+ this.dispatchEvent('rendercomplete');
+ }
+ /**
+ * **_[static]_** - Re-draw the layer panel to represent the current state of the layers.
+ * @param map The OpenLayers Map instance to render layers for
+ * @param panel The DOM Element into which the layer tree will be rendered
+ * @param options Options for panel, group, and layers
+ */
+
+ }], [{
+ key: 'renderPanel',
+ value: function renderPanel(map, panel, options) {
+ // Create the event.
+ var render_event = new Event('render');
+ // Dispatch the event.
+ panel.dispatchEvent(render_event);
+ options = options || {};
+ options.groupSelectStyle = LayerSwitcher.getGroupSelectStyle(options.groupSelectStyle);
+ LayerSwitcher.ensureTopVisibleBaseLayerShown(map, options.groupSelectStyle);
+ while (panel.firstChild) {
+ panel.removeChild(panel.firstChild);
+ }
+ // Reset indeterminate state for all layers and groups before
+ // applying based on groupSelectStyle
+ LayerSwitcher.forEachRecursive(map, function (l, _idx, _a) {
+ l.set('indeterminate', false);
+ });
+ if (options.groupSelectStyle === 'children' || options.groupSelectStyle === 'none') {
+ // Set visibile and indeterminate state of groups based on
+ // their children's visibility
+ LayerSwitcher.setGroupVisibility(map);
+ } else if (options.groupSelectStyle === 'group') {
+ // Set child indetermiate state based on their parent's visibility
+ LayerSwitcher.setChildVisibility(map);
+ }
+ var ul = document.createElement('ul');
+ panel.appendChild(ul);
+ // passing two map arguments instead of lyr as we're passing the map as the root of the layers tree
+ LayerSwitcher.renderLayers_(map, map, ul, options, function render(_changedLyr) {
+ LayerSwitcher.renderPanel(map, panel, options);
+ });
+ // Create the event.
+ var rendercomplete_event = new Event('rendercomplete');
+ // Dispatch the event.
+ panel.dispatchEvent(rendercomplete_event);
+ }
+ /**
+ * **_[static]_** - Determine if a given layer group contains base layers
+ * @param grp Group to test
+ */
+
+ }, {
+ key: 'isBaseGroup',
+ value: function isBaseGroup(grp) {
+ if (grp instanceof LayerGroup) {
+ var lyrs = grp.getLayers().getArray();
+ return lyrs.length && lyrs[0].get('type') === 'base';
+ } else {
+ return false;
+ }
+ }
+ }, {
+ key: 'setGroupVisibility',
+ value: function setGroupVisibility(map) {
+ // Get a list of groups, with the deepest first
+ var groups = LayerSwitcher.getGroupsAndLayers(map, function (l) {
+ return l instanceof LayerGroup && !l.get('combine') && !LayerSwitcher.isBaseGroup(l);
+ }).reverse();
+ // console.log(groups.map(g => g.get('title')));
+ groups.forEach(function (grp) {
+ // TODO Can we use getLayersArray, is it public in the esm build?
+ var descendantVisibility = grp.getLayersArray().map(function (l) {
+ var state = l.getVisible();
+ // console.log('>', l.get('title'), state);
+ return state;
+ });
+ // console.log(descendantVisibility);
+ if (descendantVisibility.every(function (v) {
+ return v === true;
+ })) {
+ grp.setVisible(true);
+ grp.set('indeterminate', false);
+ } else if (descendantVisibility.every(function (v) {
+ return v === false;
+ })) {
+ grp.setVisible(false);
+ grp.set('indeterminate', false);
+ } else {
+ grp.setVisible(true);
+ grp.set('indeterminate', true);
+ }
+ });
+ }
+ }, {
+ key: 'setChildVisibility',
+ value: function setChildVisibility(map) {
+ // console.log('setChildVisibility');
+ var groups = LayerSwitcher.getGroupsAndLayers(map, function (l) {
+ return l instanceof LayerGroup && !l.get('combine') && !LayerSwitcher.isBaseGroup(l);
+ });
+ groups.forEach(function (grp) {
+ var group = grp;
+ // console.log(group.get('title'));
+ var groupVisible = group.getVisible();
+ var groupIndeterminate = group.get('indeterminate');
+ group.getLayers().getArray().forEach(function (l) {
+ l.set('indeterminate', false);
+ if ((!groupVisible || groupIndeterminate) && l.getVisible()) {
+ l.set('indeterminate', true);
+ }
+ });
+ });
+ }
+ /**
+ * Ensure only the top-most base layer is visible if more than one is visible.
+ * @param map The map instance.
+ * @param groupSelectStyle
+ * @protected
+ */
+
+ }, {
+ key: 'ensureTopVisibleBaseLayerShown',
+ value: function ensureTopVisibleBaseLayerShown(map, groupSelectStyle) {
+ var lastVisibleBaseLyr = void 0;
+ LayerSwitcher.forEachRecursive(map, function (lyr, _idx, _arr) {
+ if (lyr.get('type') === 'base' && lyr.getVisible()) {
+ lastVisibleBaseLyr = lyr;
+ }
+ });
+ if (lastVisibleBaseLyr) LayerSwitcher.setVisible_(map, lastVisibleBaseLyr, true, groupSelectStyle);
+ }
+ /**
+ * **_[static]_** - Get an Array of all layers and groups displayed by the LayerSwitcher (has a `'title'` property)
+ * contained by the specified map or layer group; optionally filtering via `filterFn`
+ * @param grp The map or layer group for which layers are found.
+ * @param filterFn Optional function used to filter the returned layers
+ */
+
+ }, {
+ key: 'getGroupsAndLayers',
+ value: function getGroupsAndLayers(grp, filterFn) {
+ var layers = [];
+ filterFn = filterFn || function (_lyr, _idx, _arr) {
+ return true;
+ };
+ LayerSwitcher.forEachRecursive(grp, function (lyr, idx, arr) {
+ if (lyr.get('title')) {
+ if (filterFn(lyr, idx, arr)) {
+ layers.push(lyr);
+ }
+ }
+ });
+ return layers;
+ }
+ /**
+ * 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.
+ * @protected
+ * @param map The map instance.
+ * @param lyr layer whose visibility will be toggled.
+ * @param visible Set whether the layer is shown
+ * @param groupSelectStyle
+ * @protected
+ */
+
+ }, {
+ key: 'setVisible_',
+ value: function setVisible_(map, lyr, visible, groupSelectStyle) {
+ // console.log(lyr.get('title'), visible, groupSelectStyle);
+ lyr.setVisible(visible);
+ if (visible && lyr.get('type') === 'base') {
+ // Hide all other base layers regardless of grouping
+ LayerSwitcher.forEachRecursive(map, function (l, _idx, _arr) {
+ if (l != lyr && l.get('type') === 'base') {
+ l.setVisible(false);
+ }
+ });
+ }
+ if (lyr instanceof LayerGroup && !lyr.get('combine') && groupSelectStyle === 'children') {
+ lyr.getLayers().forEach(function (l) {
+ LayerSwitcher.setVisible_(map, l, lyr.getVisible(), groupSelectStyle);
+ });
+ }
+ }
+ /**
+ * Render all layers that are children of a group.
+ * @param map The map instance.
+ * @param lyr Layer to be rendered (should have a title property).
+ * @param idx Position in parent group list.
+ * @param options Options for groups and layers
+ * @protected
+ */
+
+ }, {
+ key: 'renderLayer_',
+ value: function renderLayer_(map, lyr, idx, options, render) {
+ var li = document.createElement('li');
+ var lyrTitle = lyr.get('title');
+ var checkboxId = LayerSwitcher.uuid();
+ var label = document.createElement('label');
+ if (lyr instanceof LayerGroup && !lyr.get('combine')) {
+ var isBaseGroup = LayerSwitcher.isBaseGroup(lyr);
+ li.classList.add('group');
+ if (isBaseGroup) {
+ li.classList.add(CSS_PREFIX + 'base-group');
+ }
+ // Group folding
+ if (lyr.get('fold')) {
+ li.classList.add(CSS_PREFIX + 'fold');
+ li.classList.add(CSS_PREFIX + lyr.get('fold'));
+ var btn = document.createElement('button');
+ btn.onclick = function (e) {
+ var evt = e || window.event;
+ LayerSwitcher.toggleFold_(lyr, li);
+ evt.preventDefault();
+ };
+ li.appendChild(btn);
+ }
+ if (!isBaseGroup && options.groupSelectStyle != 'none') {
+ var input = document.createElement('input');
+ input.type = 'checkbox';
+ input.id = checkboxId;
+ input.checked = lyr.getVisible();
+ input.indeterminate = lyr.get('indeterminate');
+ input.onchange = function (e) {
+ var target = e.target;
+ LayerSwitcher.setVisible_(map, lyr, target.checked, options.groupSelectStyle);
+ render(lyr);
+ };
+ li.appendChild(input);
+ label.htmlFor = checkboxId;
+ }
+ label.innerHTML = lyrTitle;
+ li.appendChild(label);
+ var ul = document.createElement('ul');
+ li.appendChild(ul);
+ LayerSwitcher.renderLayers_(map, lyr, ul, options, render);
+ } else {
+ li.className = 'layer';
+ var _input = document.createElement('input');
+ if (lyr.get('type') === 'base') {
+ _input.type = 'radio';
+ } else {
+ _input.type = 'checkbox';
+ }
+ _input.id = checkboxId;
+ _input.checked = lyr.get('visible');
+ _input.indeterminate = lyr.get('indeterminate');
+ _input.onchange = function (e) {
+ var target = e.target;
+ LayerSwitcher.setVisible_(map, lyr, target.checked, options.groupSelectStyle);
+ render(lyr);
+ };
+ li.appendChild(_input);
+ label.htmlFor = checkboxId;
+ label.innerHTML = lyrTitle;
+ var rsl = map.getView().getResolution();
+ if (rsl >= lyr.getMaxResolution() || rsl < lyr.getMinResolution()) {
+ label.className += ' disabled';
+ } else if (lyr.getMinZoom && lyr.getMaxZoom) {
+ var zoom = map.getView().getZoom();
+ if (zoom <= lyr.getMinZoom() || zoom > lyr.getMaxZoom()) {
+ label.className += ' disabled';
+ }
+ }
+ li.appendChild(label);
+ }
+ return li;
+ }
+ /**
+ * Render all layers that are children of a group.
+ * @param map The map instance.
+ * @param lyr Group layer whose children will be rendered.
+ * @param elm DOM element that children will be appended to.
+ * @param options Options for groups and layers
+ * @protected
+ */
+
+ }, {
+ key: 'renderLayers_',
+ value: function renderLayers_(map, lyr, elm, options, render) {
+ var lyrs = lyr.getLayers().getArray().slice();
+ if (options.reverse) lyrs = lyrs.reverse();
+ for (var i = 0, l; i < lyrs.length; i++) {
+ l = lyrs[i];
+ if (l.get('title')) {
+ elm.appendChild(LayerSwitcher.renderLayer_(map, l, i, options, render));
+ }
+ }
+ }
+ /**
+ * **_[static]_** - Call the supplied function for each layer in the passed layer group
+ * recursing nested groups.
+ * @param lyr The layer group to start iterating from.
+ * @param fn Callback which will be called for each layer
+ * found under `lyr`.
+ */
+
+ }, {
+ key: 'forEachRecursive',
+ value: function forEachRecursive(lyr, fn) {
+ lyr.getLayers().forEach(function (lyr, idx, a) {
+ fn(lyr, idx, a);
+ if (lyr instanceof LayerGroup) {
+ LayerSwitcher.forEachRecursive(lyr, fn);
+ }
+ });
+ }
+ /**
+ * **_[static]_** - Generate a UUID
+ * Adapted from http://stackoverflow.com/a/2117523/526860
+ * @returns {String} UUID
+ */
+
+ }, {
+ key: 'uuid',
+ value: function 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);
+ });
+ }
+ /**
+ * Apply workaround to enable scrolling of overflowing content within an
+ * element. Adapted from https://gist.github.com/chrismbarr/4107472
+ * @param elm Element on which to enable touch scrolling
+ * @protected
+ */
+
+ }, {
+ key: 'enableTouchScroll_',
+ value: function enableTouchScroll_(elm) {
+ if (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);
+ }
+ }
+ /**
+ * Determine if the current browser supports touch events. Adapted from
+ * https://gist.github.com/chrismbarr/4107472
+ * @returns {Boolean} True if client can have 'TouchEvent' event
+ * @protected
+ */
+
+ }, {
+ key: 'isTouchDevice_',
+ value: function isTouchDevice_() {
+ try {
+ document.createEvent('TouchEvent');
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+ /**
+ * Fold/unfold layer group
+ * @param lyr Layer group to fold/unfold
+ * @param li List item containing layer group
+ * @protected
+ */
+
+ }, {
+ key: 'toggleFold_',
+ value: function toggleFold_(lyr, li) {
+ li.classList.remove(CSS_PREFIX + lyr.get('fold'));
+ lyr.set('fold', lyr.get('fold') === 'open' ? 'close' : 'open');
+ li.classList.add(CSS_PREFIX + lyr.get('fold'));
+ }
+ /**
+ * If a valid groupSelectStyle value is not provided then return the default
+ * @param groupSelectStyle The string to check for validity
+ * @returns The value groupSelectStyle, if valid, the default otherwise
+ * @protected
+ */
+
+ }, {
+ key: 'getGroupSelectStyle',
+ value: function getGroupSelectStyle(groupSelectStyle) {
+ return ['none', 'children', 'group'].indexOf(groupSelectStyle) >= 0 ? groupSelectStyle : 'children';
+ }
+ }]);
+ return LayerSwitcher;
+}(Control);
+if (window['ol'] && window['ol']['control']) {
+ window['ol']['control']['LayerSwitcher'] = LayerSwitcher;
+}
+
+return LayerSwitcher;
+
+})));