Initial commit - Typo3 11.5.41

This commit is contained in:
Matteo Gallo
2026-07-03 17:53:31 +02:00
commit 5ca4743197
6811 changed files with 568848 additions and 0 deletions

View File

@@ -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@4.1.0"></script>
```
#### CSS
```HTML
<link rel="stylesheet" href="https://unpkg.com/ol-layerswitcher@4.1.0/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_Map-Map.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` **[Map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.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` **[Map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.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` **([Map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.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` **([Map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.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

View File

@@ -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: 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;
}
*/

View File

@@ -0,0 +1,597 @@
(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;
/**
* @protected
*/
const 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_Map-Map.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.
*/
class LayerSwitcher extends Control {
constructor(opt_options) {
const options = Object.assign({}, opt_options);
const element = document.createElement('div');
super({ 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 : '\u00BB';
// 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 = (e) => {
const evt = e || window.event;
if (this.element.classList.contains(this.shownClassName)) {
this.hidePanel();
}
else {
this.showPanel();
}
evt.preventDefault();
};
}
else {
this.button.onmouseover = () => {
this.showPanel();
};
this.button.onclick = (e) => {
const evt = e || window.event;
this.showPanel();
evt.preventDefault();
};
this.panel.onmouseout = (evt) => {
if (!this.panel.contains(evt.relatedTarget)) {
this.hidePanel();
}
};
}
this.updateButton();
}
/**
* Set the map instance the control is associated with.
* @param map The map instance.
*/
setMap(map) {
// Clean up listeners associated with the previous map
for (let 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
super.setMap(map);
if (map) {
if (this.startActive) {
this.showPanel();
}
else {
this.renderPanel();
}
if (this.activationMode !== 'click') {
this.mapListeners.push(map.on('pointerdown', () => {
this.hidePanel();
}));
}
}
}
/**
* Show the layer panel. Fires `'show'` event.
* @fires LayerSwitcher#show
*/
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
*/
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
*/
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.
*/
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
*/
static renderPanel(map, panel, options) {
// Create the event.
const 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);
}
const 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.
const 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
*/
static isBaseGroup(grp) {
if (grp instanceof LayerGroup) {
const lyrs = grp.getLayers().getArray();
return lyrs.length && lyrs[0].get('type') === 'base';
}
else {
return false;
}
}
static setGroupVisibility(map) {
// Get a list of groups, with the deepest first
const 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?
const descendantVisibility = grp.getLayersArray().map(function (l) {
const 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);
}
});
}
static setChildVisibility(map) {
// console.log('setChildVisibility');
const groups = LayerSwitcher.getGroupsAndLayers(map, function (l) {
return (l instanceof LayerGroup &&
!l.get('combine') &&
!LayerSwitcher.isBaseGroup(l));
});
groups.forEach(function (grp) {
const group = grp;
// console.log(group.get('title'));
const groupVisible = group.getVisible();
const 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
*/
static ensureTopVisibleBaseLayerShown(map, groupSelectStyle) {
let lastVisibleBaseLyr;
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
*/
static getGroupsAndLayers(grp, filterFn) {
const 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
*/
static 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((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
*/
static renderLayer_(map, lyr, idx, options, render) {
const li = document.createElement('li');
const lyrTitle = lyr.get('title');
const checkboxId = LayerSwitcher.uuid();
const label = document.createElement('label');
if (lyr instanceof LayerGroup && !lyr.get('combine')) {
const 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'));
const btn = document.createElement('button');
btn.onclick = function (e) {
const evt = e || window.event;
LayerSwitcher.toggleFold_(lyr, li);
evt.preventDefault();
};
li.appendChild(btn);
}
if (!isBaseGroup && options.groupSelectStyle != 'none') {
const input = document.createElement('input');
input.type = 'checkbox';
input.id = checkboxId;
input.checked = lyr.getVisible();
input.indeterminate = lyr.get('indeterminate');
input.onchange = function (e) {
const 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);
const ul = document.createElement('ul');
li.appendChild(ul);
LayerSwitcher.renderLayers_(map, lyr, ul, options, render);
}
else {
li.className = 'layer';
const 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) {
const target = e.target;
LayerSwitcher.setVisible_(map, lyr, target.checked, options.groupSelectStyle);
render(lyr);
};
li.appendChild(input);
label.htmlFor = checkboxId;
label.innerHTML = lyrTitle;
const rsl = map.getView().getResolution();
if (rsl >= lyr.getMaxResolution() || rsl < lyr.getMinResolution()) {
label.className += ' disabled';
}
else if (lyr.getMinZoom && lyr.getMaxZoom) {
const 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
*/
static renderLayers_(map, lyr, elm, options, render) {
let lyrs = lyr.getLayers().getArray().slice();
if (options.reverse)
lyrs = lyrs.reverse();
for (let 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`.
*/
static 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
*/
static uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const 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
*/
static enableTouchScroll_(elm) {
if (LayerSwitcher.isTouchDevice_()) {
let 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
*/
static 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
*/
static 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
*/
static getGroupSelectStyle(groupSelectStyle) {
return ['none', 'children', 'group'].indexOf(groupSelectStyle) >= 0
? groupSelectStyle
: 'children';
}
}
// Expose LayerSwitcher as ol.control.LayerSwitcher if using a full build of
// OpenLayers
if (window['ol'] && window['ol']['control']) {
window['ol']['control']['LayerSwitcher'] = LayerSwitcher;
}
return LayerSwitcher;
})));

View File

@@ -0,0 +1,3 @@
.layer-switcher {
top: 2.5em;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,350 @@
:root,
:host {
--ol-background-color: white;
--ol-accent-background-color: #F5F5F5;
--ol-subtle-background-color: rgba(128, 128, 128, 0.25);
--ol-partial-background-color: rgba(255, 255, 255, 0.75);
--ol-foreground-color: #333333;
--ol-subtle-foreground-color: #666666;
--ol-brand-color: #00AAFF;
}
.ol-box {
box-sizing: border-box;
border-radius: 2px;
border: 1.5px solid var(--ol-background-color);
background-color: var(--ol-partial-background-color);
}
.ol-mouse-position {
top: 8px;
right: 8px;
position: absolute;
}
.ol-scale-line {
background: var(--ol-partial-background-color);
border-radius: 4px;
bottom: 8px;
left: 8px;
padding: 2px;
position: absolute;
}
.ol-scale-line-inner {
border: 1px solid var(--ol-subtle-foreground-color);
border-top: none;
color: var(--ol-foreground-color);
font-size: 10px;
text-align: center;
margin: 1px;
will-change: contents, width;
transition: all 0.25s;
}
.ol-scale-bar {
position: absolute;
bottom: 8px;
left: 8px;
}
.ol-scale-bar-inner {
display: flex;
}
.ol-scale-step-marker {
width: 1px;
height: 15px;
background-color: var(--ol-foreground-color);
float: right;
z-index: 10;
}
.ol-scale-step-text {
position: absolute;
bottom: -5px;
font-size: 10px;
z-index: 11;
color: var(--ol-foreground-color);
text-shadow: -1.5px 0 var(--ol-partial-background-color), 0 1.5px var(--ol-partial-background-color), 1.5px 0 var(--ol-partial-background-color), 0 -1.5px var(--ol-partial-background-color);
}
.ol-scale-text {
position: absolute;
font-size: 12px;
text-align: center;
bottom: 25px;
color: var(--ol-foreground-color);
text-shadow: -1.5px 0 var(--ol-partial-background-color), 0 1.5px var(--ol-partial-background-color), 1.5px 0 var(--ol-partial-background-color), 0 -1.5px var(--ol-partial-background-color);
}
.ol-scale-singlebar {
position: relative;
height: 10px;
z-index: 9;
box-sizing: border-box;
border: 1px solid var(--ol-foreground-color);
}
.ol-scale-singlebar-even {
background-color: var(--ol-subtle-foreground-color);
}
.ol-scale-singlebar-odd {
background-color: var(--ol-background-color);
}
.ol-unsupported {
display: none;
}
.ol-viewport,
.ol-unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
.ol-viewport canvas {
all: unset;
overflow: hidden;
}
.ol-viewport {
touch-action: none;
}
.ol-selectable {
-webkit-touch-callout: default;
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
}
.ol-grabbing {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
.ol-grab {
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.ol-control {
position: absolute;
background-color: var(--ol-subtle-background-color);
border-radius: 4px;
}
.ol-zoom {
top: .5em;
left: .5em;
}
.ol-rotate {
top: .5em;
right: .5em;
transition: opacity .25s linear, visibility 0s linear;
}
.ol-rotate.ol-hidden {
opacity: 0;
visibility: hidden;
transition: opacity .25s linear, visibility 0s linear .25s;
}
.ol-zoom-extent {
top: 4.643em;
left: .5em;
}
.ol-full-screen {
right: .5em;
top: .5em;
}
.ol-control button {
display: block;
margin: 1px;
padding: 0;
color: var(--ol-subtle-foreground-color);
font-weight: bold;
text-decoration: none;
font-size: inherit;
text-align: center;
height: 1.375em;
width: 1.375em;
line-height: .4em;
background-color: var(--ol-background-color);
border: none;
border-radius: 2px;
}
.ol-control button::-moz-focus-inner {
border: none;
padding: 0;
}
.ol-zoom-extent button {
line-height: 1.4em;
}
.ol-compass {
display: block;
font-weight: normal;
will-change: transform;
}
.ol-touch .ol-control button {
font-size: 1.5em;
}
.ol-touch .ol-zoom-extent {
top: 5.5em;
}
.ol-control button:hover,
.ol-control button:focus {
text-decoration: none;
outline: 1px solid var(--ol-subtle-foreground-color);
color: var(--ol-foreground-color);
}
.ol-zoom .ol-zoom-in {
border-radius: 2px 2px 0 0;
}
.ol-zoom .ol-zoom-out {
border-radius: 0 0 2px 2px;
}
.ol-attribution {
text-align: right;
bottom: .5em;
right: .5em;
max-width: calc(100% - 1.3em);
display: flex;
flex-flow: row-reverse;
align-items: center;
}
.ol-attribution a {
color: var(--ol-subtle-foreground-color);
text-decoration: none;
}
.ol-attribution ul {
margin: 0;
padding: 1px .5em;
color: var(--ol-foreground-color);
text-shadow: 0 0 2px var(--ol-background-color);
font-size: 12px;
}
.ol-attribution li {
display: inline;
list-style: none;
}
.ol-attribution li:not(:last-child):after {
content: " ";
}
.ol-attribution img {
max-height: 2em;
max-width: inherit;
vertical-align: middle;
}
.ol-attribution button {
flex-shrink: 0;
}
.ol-attribution.ol-collapsed ul {
display: none;
}
.ol-attribution:not(.ol-collapsed) {
background: var(--ol-partial-background-color);
}
.ol-attribution.ol-uncollapsible {
bottom: 0;
right: 0;
border-radius: 4px 0 0;
}
.ol-attribution.ol-uncollapsible img {
margin-top: -.2em;
max-height: 1.6em;
}
.ol-attribution.ol-uncollapsible button {
display: none;
}
.ol-zoomslider {
top: 4.5em;
left: .5em;
height: 200px;
}
.ol-zoomslider button {
position: relative;
height: 10px;
}
.ol-touch .ol-zoomslider {
top: 5.5em;
}
.ol-overviewmap {
left: 0.5em;
bottom: 0.5em;
}
.ol-overviewmap.ol-uncollapsible {
bottom: 0;
left: 0;
border-radius: 0 4px 0 0;
}
.ol-overviewmap .ol-overviewmap-map,
.ol-overviewmap button {
display: block;
}
.ol-overviewmap .ol-overviewmap-map {
border: 1px solid var(--ol-subtle-foreground-color);
height: 150px;
width: 150px;
}
.ol-overviewmap:not(.ol-collapsed) button {
bottom: 0;
left: 0;
position: absolute;
}
.ol-overviewmap.ol-collapsed .ol-overviewmap-map,
.ol-overviewmap.ol-uncollapsible button {
display: none;
}
.ol-overviewmap:not(.ol-collapsed) {
background: var(--ol-subtle-background-color);
}
.ol-overviewmap-box {
border: 1.5px dotted var(--ol-subtle-foreground-color);
}
.ol-overviewmap .ol-overviewmap-box:hover {
cursor: move;
}