nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

commit d2135cb94b339935c5199198c383c2a5af1ed1a3
parent 4f9e61842fcf1fb4c4a340628da4d9a1460d872f
Author: Sergej Orlov <wladimirych@gmail.com>
Date:   Thu,  8 Dec 2016 00:38:48 +0300

[layers] added dialog to select enabled layers

Diffstat:
Msrc/App.js | 12++++++------
Msrc/layers.js | 436+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Asrc/lib/leaflet.control.layers.configure/layers-configure.js | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/leaflet.control.layers.configure/style.css | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 686 insertions(+), 60 deletions(-)

diff --git a/src/App.js b/src/App.js @@ -2,7 +2,6 @@ import './App.css'; import './leaflet-fixes.css'; import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; -import layers from './layers'; import 'lib/leaflet.control.printPages/control' import 'lib/leaflet.control.caption/caption' import config from './config' @@ -19,8 +18,10 @@ import 'lib/leaflet.control.track-list/track-list.hash-state'; import 'lib/leaflet.control.track-list/track-list.localstorage'; import enableLayersControlAdaptiveHeight from 'lib/leaflet.control.layers.adaptive-height/adaptive-height'; import enableLayersMinimize from 'lib/leaflet.control.layers.minimize/minimize'; +import enableLayersConfig from 'lib/leaflet.control.layers.configure/layers-configure'; import hashState from 'lib/leaflet.hashState/hashState'; import raiseControlsOnFocus from 'lib/leaflet.controls.raise-on-focus/raise-on-focus'; +import getLayers from 'layers'; @@ -58,14 +59,13 @@ function setUp() { /////////// controls top-right corner - let baseLayers = layers.getBaseMaps(); - map.addLayer(baseLayers['OpenStreetMap']); - const layersControl = L.control.layers(baseLayers, layers.getOverlays(), {collapsed: false}) - .addTo(map) - .enableHashState('l'); + const layersControl = L.control.layers(null, null, {collapsed: false}) + .addTo(map); enableLayersControlHotKeys (layersControl); enableLayersControlAdaptiveHeight(layersControl); enableLayersMinimize(layersControl); + enableLayersConfig(layersControl, getLayers()); + layersControl.enableHashState('l'); /////////// controls bottom-left corner diff --git a/src/layers.js b/src/layers.js @@ -6,59 +6,388 @@ import config from './config'; import 'lib/leaflet.layer.soviet-topomaps-grid/soviet-topomaps-grid'; import 'lib/leaflet.layer.westraPasses/westraPasses'; -function getBaseMaps() { - return { - 'OpenStreetMap': L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - {code: 'O', scaleDependent: true, print: true, jnx: true} - ), - 'ESRI Sat': L.tileLayer( - 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', - {code: 'E', maxNativeZoom: 17, print: true, jnx: true} - ), - 'Yandex': new L.Layer.Yandex('map', {scaleDependent: true, code: 'Y', print: true, jnx: true}), - 'Yandex Sat': new L.Layer.Yandex('sat', {scaleDependent: false, code: 'S', print: true, jnx: true}), - 'Google': new L.Layer.Google('ROADMAP', {code: 'G', scaleDependent: true, print: true, jnx: true}), - 'Google Sat': new L.Layer.Google('SATELLITE', {code: 'L', print: true, jnx: true}), - 'Bing Sat': L.bingLayer(config.bingKey, {code: 'I', print: true, jnx: true}), - 'marshruty.ru': L.tileLayer('http://maps.marshruty.ru/ml.ashx?x={x}&y={y}&z={z}&i=1&al=1', - {code: 'M', maxNativeZoom: 18, noCors: true, scaleDependent: true, print: true, jnx: true} - ), - 'Topomapper 1km': L.tileLayer( - 'http://144.76.234.107//cgi-bin/ta/tilecache.py/1.0.0/topomapper_v2/{z}/{x}/{y}.jpg', - {code: 'T', maxNativeZoom: 13, noCors: true, print: true, jnx: true} - ) - }; -} +export default function getLayers() { + const layers = [ + { + group: 'Default layers', + layers: [ + { + title: 'OpenStreetMap', + description: 'OSM default style', + order: 10, + isOverlay: false, + isDefault: true, + layer: L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + {code: 'O', scaleDependent: true, print: true, jnx: true} + ) + }, + { + title: 'ESRI Sat', + order: 20, + isOverlay: false, + isDefault: true, + layer: L.tileLayer( + 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', + {code: 'E', scaleDependent: false, maxNativeZoom: 17, print: true, jnx: true} + ) + }, + { + title: 'Yandex map', + order: 30, + isOverlay: false, + isDefault: true, + layer: new L.Layer.Yandex('map', {scaleDependent: true, code: 'Y', print: true, jnx: true}) + }, + { + title: 'Yandex Sat', + order: 40, + isOverlay: false, + isDefault: true, + layer: new L.Layer.Yandex('sat', {scaleDependent: false, code: 'S', print: true, jnx: true}) + }, + { + title: 'Google', + order: 50, + isOverlay: false, + isDefault: true, + layer: new L.Layer.Google('ROADMAP', {code: 'G', scaleDependent: true, print: true, jnx: true}) + }, + { + title: 'Google Sat', + order: 60, + isOverlay: false, + isDefault: true, + layer: new L.Layer.Google('SATELLITE', {code: 'L', scaleDependent: false, print: true, jnx: true}) + }, + { + title: 'Bing Sat', + order: 70, + isOverlay: false, + isDefault: true, + layer: L.bingLayer(config.bingKey, {code: 'I', scaleDependent: false, print: true, jnx: true}) + }, + + { + title: 'marshruty.ru', + order: 80, + isOverlay: false, + isDefault: true, + layer: L.tileLayer('http://maps.marshruty.ru/ml.ashx?x={x}&y={y}&z={z}&i=1&al=1', + {code: 'M', maxNativeZoom: 18, noCors: true, scaleDependent: true, print: true, jnx: true} + ) + }, + { + title: 'Topomapper 1km', + order: 90, + isOverlay: false, + isDefault: true, + layer: L.tileLayer( + 'http://144.76.234.107//cgi-bin/ta/tilecache.py/1.0.0/topomapper_v2/{z}/{x}/{y}.jpg', + {code: 'T', scaleDependent: false, maxNativeZoom: 13, noCors: true, print: true, jnx: true} + ) + }, + + { + title: 'Topo 10km', + order: 1010, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/topo001m/{z}/{x}/{y}", + {code: 'D', tms: true, scaleDependent: false, maxNativeZoom: 9, print: true, jnx: true} + ) + }, + { + title: 'GGC 2 km', + order: 1020, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/ggc2000/{z}/{x}/{y}", + {code: 'N', tms: true, scaleDependent: false, maxNativeZoom: 15, print: true, jnx: true} + ) + }, + { + title: 'ArbaletMO', + order: 1030, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/ArbaletMO/{z}/{x}/{y}", + {code: 'A', tms: true, scaleDependent: false, maxNativeZoom: 13, print: true, jnx: true} + ) + }, + { + title: 'Slazav mountains', + order: 1040, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/map_hr/{z}/{x}/{y}", + {code: 'Q', tms: true, scaleDependent: false, maxNativeZoom: 13, print: true, jnx: true} + ) + }, + { + title: 'GGC 1km', + order: 1050, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/ggc1000/{z}/{x}/{y}", + {code: 'J', tms: true, scaleDependent: false, maxNativeZoom: 13, print: true, jnx: true} + ) + }, + { + title: 'Topo 1km', + order: 1060, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/topo1000/{z}/{x}/{y}", + {code: 'C', tms: true, scaleDependent: false, maxNativeZoom: 13, print: true, jnx: true} + ) + }, + { + title: 'GGC 500m', + order: 1070, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/ggc500/{z}/{x}/{y}", + {code: 'F', tms: true, scaleDependent: false, maxNativeZoom: 14, print: true, jnx: true} + ) + }, + { + title: 'Topo 500m', + order: 1080, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/topo500/{z}/{x}/{y}", + {code: 'B', tms: true, scaleDependent: false, maxNativeZoom: 14, print: true, jnx: true} + ) + }, + { + title: 'GGC 250m', + order: 1090, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/ggc250/{z}/{x}/{y}", + {code: 'K', tms: true, scaleDependent: false, maxNativeZoom: 15, print: true, jnx: true} + ) + }, + { + title: 'Slazav map', + order: 1100, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/map_podm/{z}/{x}/{y}", + {code: 'Z', tms: true, scaleDependent: false, maxNativeZoom: 14, print: true, jnx: true} + ) + }, + { + title: 'O-sport', + order: 1110, + isOverlay: true, + isDefault: true, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/osport/{z}/{x}/{y}", + {code: 'R', tms: true, scaleDependent: false, maxNativeZoom: 17, print: true, jnx: true} + ) + }, + { + title: 'Soviet topo maps grid', + order: 1120, + isOverlay: true, + isDefault: true, + layer: new L.Layer.SovietTopoGrid({code: 'Ng'}) + }, + // { + // title: 'Wikimapia', + // order: 1130, + // isOverlay: true, + // isDefault: true, + // layer: new L.Wikimapia({code: 'W', zIndexOffset: 10000}), + // }, + { + title: 'Mountain passes (Westra)', + order: 1140, + isOverlay: true, + isDefault: true, + layer: new L.Layer.WestraPasses(config.westraDataBaseUrl, { + code: 'Wp', + print: true, + scaleDependent: true + } + ) + }] + }, + + + { + group: 'OpenStreetMap alternatives', + layers: [ + { + title: 'OpenTopoMap', + order: 11, + isOverlay: false, + isDefault: false, + layer: L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', + {code: 'Otm', scaleDependent: true, print: true, jnx: true} + ) + }, + { + title: 'OpenCycleMap', + order: 12, + isOverlay: false, + isDefault: false, + layer: L.tileLayer('http://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png', + {code: 'Ocm', maxNativeZoom: 17, scaleDependent: true, print: true, jnx: true} + ) + }] + }, + { + group: 'Topo maps', + layers: [ + { + title: 'Topo 250m', + order: 1095, + isOverlay: true, + isDefault: false, + layer: L.tileLayer("http://{s}.tiles.nakarte.tk/topo250/{z}/{x}/{y}", + {code: 'T25', tms: true, maxNativeZoom: 15, print: true, jnx: true, scaleDependent: false} + ) + }] + }, + { + group: 'Mountains maps', + layers: [ + { + title: 'Mountains by Aleksey Tsvetkov', + description: 'Tian Shan, Dzungaria, <a href="http://pereval.g-utka.ru/">http://pereval.g-utka.ru/</a>', + order: 1039, + isOverlay: true, + isDefault: false, + layer: L.tileLayer("http://map.g-utka.ru/{z}/{x}/{y}.png", + // FIXME: сделать minZoom=5, когда перейдём на версию leaflet с поддержкой minNativeZoom + { + code: 'Mt', + tms: false, + minZoom: 7, + minNativeZoom: 7, + maxNativeZoom: 15, + print: true, + jnx: true, + scaleDependent: false + } + ) + }] + }, + { + group: 'Norway <a href="https://www.ut.no/kart/">https://www.ut.no/kart/</a>', + layers: [ + { + // Вместо 404 отдают 500 для отсутствующих тайлов + title: 'UT map', + order: 500, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("http://dntutnotilesprod.cloudapp.net/tilestache/ut_topo_light/{z}/{x}/{y}.jpg", + {code: 'Nu', tms: false, maxNativeZoom: 16, print: true, jnx: true, scaleDependent: true} + ) + }, + // { + // title: '', + // order: 0, + // isOverlay: true, + // isDefault: false, + // layer: null + // }, + // { + // title: '', + // order: 0, + // isOverlay: true, + // isDefault: false, + // layer: null + // }, + { + // Вместо 404 отдают 500 для отсутствующих тайлов + title: 'Norway roads', + order: 500, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("http://maptiles1.finncdn.no/tileService/1.0.3/normap/{z}/{x}/{y}.png", + {code: 'Nr', tms: false, print: true, jnx: true, scaleDependent: true} + ) -function getOverlays() { - return { - "Topo 10km": new L.TileLayer("http://{s}.tiles.nakarte.tk/topo001m/{z}/{x}/{y}", - {code: 'D', tms: true, maxNativeZoom: 9, print: true, jnx: true}), - "GGC 2 km": new L.TileLayer("http://{s}.tiles.nakarte.tk/ggc2000/{z}/{x}/{y}", - {code: 'N', tms: true, maxNativeZoom: 15, print: true, jnx: true}), - "ArbaletMO": new L.TileLayer("http://{s}.tiles.nakarte.tk/ArbaletMO/{z}/{x}/{y}", - {code: 'A', tms: true, maxNativeZoom: 13, print: true, jnx: true}), - "Slazav mountains": new L.TileLayer("http://{s}.tiles.nakarte.tk/map_hr/{z}/{x}/{y}", - {code: 'Q', tms: true, maxNativeZoom: 13, print: true, jnx: true}), - "GGC 1km": new L.TileLayer("http://{s}.tiles.nakarte.tk/ggc1000/{z}/{x}/{y}", - {code: 'J', tms: true, maxNativeZoom: 13, print: true, jnx: true}), - "Topo 1km": new L.TileLayer("http://{s}.tiles.nakarte.tk/topo1000/{z}/{x}/{y}", - {code: 'C', tms: true, maxNativeZoom: 13, print: true, jnx: true}), - "GGC 500m": new L.TileLayer("http://{s}.tiles.nakarte.tk/ggc500/{z}/{x}/{y}", - {code: 'F', tms: true, maxNativeZoom: 14, print: true, jnx: true}), - "Topo 500m": new L.TileLayer("http://{s}.tiles.nakarte.tk/topo500/{z}/{x}/{y}", - {code: 'B', tms: true, maxNativeZoom: 14, print: true, jnx: true}), - "GGC 250m": new L.TileLayer("http://{s}.tiles.nakarte.tk/ggc250/{z}/{x}/{y}", - {code: 'K', tms: true, maxNativeZoom: 15, print: true, jnx: true}), - "Slazav map": new L.TileLayer("http://{s}.tiles.nakarte.tk/map_podm/{z}/{x}/{y}", - {code: 'Z', tms: true, maxNativeZoom: 14, print: true, jnx: true}), - "O-sport": new L.TileLayer("http://{s}.tiles.nakarte.tk/osport/{z}/{x}/{y}", - {code: 'R', tms: true, maxNativeZoom: 17, print: true, jnx: true}), - "Soviet topo maps grid": new L.Layer.SovietTopoGrid({code: 'Ng'}), - // "Wikimapia": new L.Wikimapia({code: 'W', zIndexOffset: 10000}), - // "Google Street View": new L.GoogleStreetView('street-view', {print: true, code: 'Gs', zIndexOffset: 10000}), - "Mountain passes (Westra)": new L.Layer.WestraPasses(config.westraDataBaseUrl, {code: 'Wp', print: true}) - }; + }] + }, + { + group: 'Czech <a href="http://mapy.cz">http://mapy.cz</a>', + layers: [ + { + title: 'Czech basic', + order: 501, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/base-m/{z}-{x}-{y}", + {code: 'Czb', tms: false, print: true, jnx: true, subdomains: '1234', scaleDependent: true} + ) + }, + { + title: 'Czhch tourist', + order: 502, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/wturist-m/{z}-{x}-{y}", + {code: 'Czt', tms: false, print: true, jnx: true, subdomains: '1234', scaleDependent: true} + ) + }, + { + title: 'Czech summer', + order: 503, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/turist_aquatic-m/{z}-{x}-{y}", + {code: 'Czs', tms: false, print: true, jnx: true, subdomains: '1234', scaleDependent: true} + ) + }, + { + title: 'Czech winter', + order: 504, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/wturist_winter-m/{z}-{x}-{y}", + {code: 'Czw', tms: false, print: true, jnx: true, subdomains: '1234', scaleDependent: true} + ) + }, + { + title: 'Czech geographical', + order: 505, + isOverlay: false, + isDefault: false, + layer: L.tileLayer("https://m{s}.mapserver.mapy.cz/zemepis-m/{z}-{x}-{y}", + {code: 'Czg', tms: false, print: true, jnx: true, subdomains: '1234', scaleDependent: true} + ) + }] + }, + // { + // title: '', + // order: 0, + // isOverlay: true, + // isDefault: false, + // layer: null + // }, + ]; + // TODO: move it to tests + const codes = {}; + for (let group of layers) { + for (let layer of group.layers) { + layer = layer.layer; + if (!layer.options) { + throw new Error('Layer without options: ' + layer.title); + } + let code = layer.options.code; + if (!code) { + throw new Error('Layer without code: ' + layer.title); + } + if (code in codes) { + throw new Error(`Duplicate layer code "${code}"`); + } + codes[code] = 1; + } + } + return layers; } -export default {getBaseMaps, getOverlays}; -\ No newline at end of file diff --git a/src/lib/leaflet.control.layers.configure/layers-configure.js b/src/lib/leaflet.control.layers.configure/layers-configure.js @@ -0,0 +1,206 @@ +import L from 'leaflet'; +import './style.css'; +import enableTopRow from 'lib/leaflet.control.layers.top-row/top-row'; +import ko from 'knockout'; + + +function enableConfig(control, layers) { + const originalOnAdd = control.onAdd; + const originalUnserializeState = control.unserializeState; + if (control._configEnabled) { + return; + } + enableTopRow(control); + + L.Util.extend(control, { + configEnabled: true, + _allLayersGroups: layers, + _allLayers: [].concat(...layers.map(group => group.layers)), + + onAdd: function(map) { + const container = originalOnAdd.call(this, map); + this.__injectConfigButton(); + return container; + }, + + __injectConfigButton: function() { + const configButton = L.DomUtil.create('div', 'button-config'); + configButton.innerHTML = 'More layers'; + this._topRow.appendChild(configButton); + L.DomEvent.on(configButton, 'click', this._onConfigButtonClick, this); + }, + + _initializeLayersState: function() { + let storedLayersEnabled = {}; + if (window.localStorage) { + const serialized = window.localStorage.getItem('layersEnabled'); + if (serialized) { + try { + storedLayersEnabled = JSON.parse(serialized); + } catch (e) { + } + } + } + for (let layer of this._allLayers) { + // TODO: check if state is stored in localStorage, else + let enabled = storedLayersEnabled[layer.layer.options.code]; + // if storage is empty enable only default layers + // if new default layer appears it will be enabled + if (typeof enabled === 'undefined') { + enabled = layer.isDefault; + } + layer.enabled = enabled; + layer.checked = ko.observable(enabled); + } + this.storeEnabledLayers(); + this.updateEnabledLayers(); + }, + + _onConfigButtonClick: function() { + this.showLayersSelectWindow() + }, + + _initLayersSelectWindow: function() { + if (this._configWindow) { + return; + } + + const container = this._configWindow = + L.DomUtil.create('div', 'leaflet-layers-select-window-wrapper'); + L.DomEvent.disableClickPropagation(container); + if (!L.Browser.touch) { + L.DomEvent.disableScrollPropagation(container); + } + container.innerHTML = ` +<div class="leaflet-layers-select-window"> + <form data-bind="foreach: _allLayersGroups"> + <div class="section-header" data-bind="html: group"></div> + <!-- ko foreach: layers --> + <label> + <input type="checkbox" data-bind="checked: checked"/> + <span data-bind="text: title"></span> + </label> + <!-- /ko --> + </form> + <div class="buttons-row"> + <div href="#" class="button" data-bind="click: onSelectWindowOkClicked">Ok</div> + <div href="#" class="button" data-bind="click: onSelectWindowCancelClicked">Cancel</div> + <div href="#" class="button" data-bind="click: onSelectWindowResetClicked">Reset</div> + </div> +</div> + `; + ko.applyBindings(this, container); + }, + + showLayersSelectWindow: function() { + if (this._configWindowVisible) { + return; + } + this._allLayers.forEach(layer => layer.checked(layer.enabled)); + this._initLayersSelectWindow(); + this._map._controlContainer.appendChild(this._configWindow); + this._configWindowVisible = true; + }, + + hideSelectWindow: function() { + if (!this._configWindowVisible) { + return; + } + this._map._controlContainer.removeChild(this._configWindow); + this._configWindowVisible = false; + }, + + onSelectWindowCancelClicked: function() { + this.hideSelectWindow(); + }, + + onSelectWindowResetClicked: function() { + if (!this._configWindow) { + return; + } + this._allLayers.forEach(layer => layer.checked(layer.isDefault)) + }, + + onSelectWindowOkClicked: function() { + this._allLayers.forEach(layer => layer.enabled = layer.checked()) + this.updateEnabledLayers(); + this.hideSelectWindow(); + this.storeEnabledLayers(); + }, + + updateEnabledLayers: function() { + const layersOnMap = []; + while (this._layers.length) { + let layer = this._layers[0]; + if (this._map.hasLayer(layer.layer)) { + layersOnMap.push(layer.layer); + } + this.removeLayer(layer.layer); + this._map.removeLayer(layer.layer); + } + + let hasBaselayerOnMap = false; + const enabledLayers = []; + for (let layer of this._allLayers) { + if (layer.enabled) { + enabledLayers.push(layer); + } + } + enabledLayers.sort((l1, l2) => l1.order - l2.order); + enabledLayers.forEach((l) => { + l.isOverlay ? this.addOverlay(l.layer, l.title) : this.addBaseLayer(l.layer, l.title); + if (layersOnMap.includes(l.layer)) { + this._map.addLayer(l.layer); + hasBaselayerOnMap = hasBaselayerOnMap || !l.isOverlay; + } + } + ); + // если нет активного базового слоя, включить первый, если он есть + if (!hasBaselayerOnMap) { + for (let layer of enabledLayers) { + if (!layer.isOverlay) { + this._map.addLayer(layer.layer); + break; + } + } + } + + }, + + storeEnabledLayers: function() { + if (!window.localStorage) { + return; + } + const layersState = {}; + for (let layer of this._allLayers) { + if (layer.isDefault || layer.enabled) { + layersState[layer.layer.options.code] = layer.enabled; + } + } + const serialized = JSON.stringify(layersState); + localStorage.setItem('layersEnabled', serialized); + }, + + unserializeState: function(values) { + if (values) { + for (let layer of this._allLayers) { + if (layer.layer.options && values.includes(layer.layer.options.code)) { + layer.enabled = true; + } + } + this.updateEnabledLayers(); + } + this.storeEnabledLayers(); + return originalUnserializeState.call(this, values); + } + + } + ); + if (control._map) { + control.__injectConfigButton() + } + control._initializeLayersState(); +} + + +export default enableConfig; +\ No newline at end of file diff --git a/src/lib/leaflet.control.layers.configure/style.css b/src/lib/leaflet.control.layers.configure/style.css @@ -0,0 +1,90 @@ +.leaflet-control-layers .button-config { + cursor: pointer; + width: auto; + margin-right: auto; + + height: 18px; + border-radius: 4px; + border: 1px solid #ccc; + background-color: white; + + padding: 0 4px; + font-weight: bold; + color: #777777; + float: left; +} + +.leaflet-control-layers .button-config:hover { + background-color: #f4f4f4; +} + +.leaflet-layers-select-window-wrapper { + position: absolute; + top: 25px; + bottom: 25px; + max-width: 100%; + padding-bottom: 50px; + left: 50%; +} + +.leaflet-layers-select-window { + position: relative; + left: -50%; + background-color: white; + border-radius: 5px; + box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4); + z-index: 3000; + max-width: 100%; + overflow: hidden; + height: 100%; + padding: 6px 0 40px 6px; +} + +.leaflet-layers-select-window form { + overflow: auto; + overflow: overlay; + padding-right: 18px; + max-height: 100%; + margin-bottom: 50px; + width: auto ; +} + +.leaflet-layers-select-window * { + white-space: nowrap; +} + +.leaflet-layers-select-window .buttons-row { + position: absolute; + bottom: 0; + margin-bottom: 6px; +} + +.leaflet-layers-select-window label { + display: block; +} + +.leaflet-layers-select-window .button { + display: inline-block; + height: 26px; + border-radius: 4px; + border: 1px solid #ccc; + cursor: pointer; + margin-right: 6px; + padding: 0 1em; + line-height: 26px; + font-weight: bold; + color: #333; +} + +.leaflet-layers-select-window .button:hover { + background-color: #f4f4f4; +} + +.leaflet-layers-select-window .section-header{ + font-size: 14px; + font-weight: bold; +} + +.leaflet-layers-select-window a { + color: #666; +} +\ No newline at end of file