From 77ae3ea8ccb275ede9bc292210e173a8902e7d50 Mon Sep 17 00:00:00 2001 From: rldhont Date: Thu, 20 Jul 2023 17:04:23 +0200 Subject: [PATCH] [JavaScript] State BaseLayer enhancing --- assets/src/components/BaseLayers.js | 15 +- assets/src/modules/BaseLayersMap.js | 77 ++-- assets/src/modules/State.js | 2 +- assets/src/modules/state/BaseLayer.js | 393 +++++++++++++++++++- tests/js-units/node/state.test.js | 4 +- tests/js-units/node/state/baselayer.test.js | 106 +++++- 6 files changed, 531 insertions(+), 66 deletions(-) diff --git a/assets/src/components/BaseLayers.js b/assets/src/components/BaseLayers.js index 0680b18817..9548964211 100644 --- a/assets/src/components/BaseLayers.js +++ b/assets/src/components/BaseLayers.js @@ -1,4 +1,5 @@ import { mainLizmap, mainEventDispatcher } from '../modules/Globals.js'; +import { BaseLayerTypes } from '../modules/config/BaseLayer.js'; import {html, render} from 'lit-html'; @@ -9,21 +10,21 @@ export default class BaseLayers extends HTMLElement { connectedCallback() { - if (mainLizmap.state.baseLayers.baseLayerConfigs.length === 0) { + if (mainLizmap.state.baseLayers.baseLayers.length === 0) { document.getElementById('switcher-baselayer').classList.add('hide'); return; } this._template = () => html` - ${mainLizmap.state.baseLayers.baseLayerConfigs.length > 1 + ${mainLizmap.state.baseLayers.baseLayers.length > 1 ? html` ` - : - html`${mainLizmap.state.baseLayers.baseLayerConfigs[0].title}` + : + html`${mainLizmap.state.baseLayers.baseLayers[0].title}` } `; @@ -43,4 +44,4 @@ export default class BaseLayers extends HTMLElement { }, ['baselayers.selection.changed'] ); } -} \ No newline at end of file +} diff --git a/assets/src/modules/BaseLayersMap.js b/assets/src/modules/BaseLayersMap.js index d15d32fe93..607d0032ae 100644 --- a/assets/src/modules/BaseLayersMap.js +++ b/assets/src/modules/BaseLayersMap.js @@ -1,5 +1,6 @@ import { mainLizmap, mainEventDispatcher } from '../modules/Globals.js'; import Utils from '../modules/Utils.js'; +import { BaseLayerTypes } from '../modules/config/BaseLayer.js'; import olMap from 'ol/Map.js'; import View from 'ol/View.js'; import { transformExtent, get as getProjection } from 'ol/proj.js'; @@ -53,35 +54,35 @@ export default class BaseLayersMap extends olMap { this._hasEmptyBaseLayer = false; const baseLayers = []; - for (const baseLayerCfg of mainLizmap.initialConfig.baseLayers.getBaseLayerConfigs()) { + for (const baseLayerState of mainLizmap.state.baseLayers.getBaseLayers()) { let baseLayer; - if (baseLayerCfg.type === 'xyz') { + if (baseLayerState.type === BaseLayerTypes.XYZ) { baseLayer = new TileLayer({ source: new XYZ({ - url: baseLayerCfg.url, - projection: baseLayerCfg.crs, - minZoom: baseLayerCfg.zmin, - maxZoom: baseLayerCfg.zmax, + url: baseLayerState.url, + projection: baseLayerState.crs, + minZoom: baseLayerState.zmin, + maxZoom: baseLayerState.zmax, }) }); - } else if (baseLayerCfg.type === 'wms') { + } else if (baseLayerState.type === 'wms') { baseLayer = new ImageLayer({ source: new ImageWMS({ - url: baseLayerCfg.url, - projection: baseLayerCfg.crs, + url: baseLayerState.url, + projection: baseLayerState.crs, params: { - LAYERS: baseLayerCfg.layer, - FORMAT: baseLayerCfg.format + LAYERS: baseLayerState.layer, + FORMAT: baseLayerState.format }, }) }); - } else if (baseLayerCfg.type === 'wmts') { + } else if (baseLayerState.type === BaseLayerTypes.WMTS) { const proj3857 = getProjection('EPSG:3857'); const maxResolution = getWidth(proj3857.getExtent()) / 256; const resolutions = []; const matrixIds = []; - for (let i = 0; i < baseLayerCfg.numZoomLevels; i++) { + for (let i = 0; i < baseLayerState.numZoomLevels; i++) { matrixIds[i] = i.toString(); resolutions[i] = maxResolution / Math.pow(2, i); } @@ -92,34 +93,52 @@ export default class BaseLayersMap extends olMap { matrixIds: matrixIds, }); - let url = baseLayerCfg.url; - if(baseLayerCfg.key && url.includes('{key}')){ - url = url.replaceAll('{key}', baseLayerCfg.key); + let url = baseLayerState.url; + if(baseLayerState.key && url.includes('{key}')){ + url = url.replaceAll('{key}', baseLayerState.key); } baseLayer = new TileLayer({ source: new WMTS({ url: url, - layer: baseLayerCfg.layer, - matrixSet: baseLayerCfg.matrixSet, - format: baseLayerCfg.format, - projection: baseLayerCfg.crs, + layer: baseLayerState.layer, + matrixSet: baseLayerState.matrixSet, + format: baseLayerState.format, + projection: baseLayerState.crs, tileGrid: tileGrid, - style: baseLayerCfg.style + style: baseLayerState.style }) }); - } else if (baseLayerCfg.type === 'bing') { + } else if (baseLayerState.type === BaseLayerTypes.Bing) { baseLayer = new TileLayer({ preload: Infinity, source: new BingMaps({ - key: baseLayerCfg.key, - imagerySet: baseLayerCfg.imagerySet, + key: baseLayerState.key, + imagerySet: baseLayerState.imagerySet, // use maxZoom 19 to see stretched tiles instead of the BingMaps // "no photos at this zoom level" tiles // maxZoom: 19 }), }); - } else if (baseLayerCfg.type === 'empty') { + } else if (baseLayerState.type === BaseLayerTypes.Lizmap) { + let minResolution = baseLayerState.layerConfig.minScale === 1 ? undefined : Utils.getResolutionFromScale(baseLayerState.layerConfig.minScale); + let maxResolution = baseLayerState.layerConfig.maxScale === 1000000000000 ? undefined : Utils.getResolutionFromScale(baseLayerState.layerConfig.maxScale); + baseLayer = new ImageLayer({ + // extent: extent, + minResolution: minResolution, + maxResolution: maxResolution, + source: new ImageWMS({ + url: mainLizmap.serviceURL, + projection: qgisProjectProjection, + serverType: 'qgis', + params: { + LAYERS: baseLayerState.itemState.wmsName, + FORMAT: baseLayerState.layerConfig.imageFormat, + DPI: 96 + }, + }) + }); + } else if (baseLayerState.type === BaseLayerTypes.Empty) { this._hasEmptyBaseLayer = true; } @@ -127,17 +146,17 @@ export default class BaseLayersMap extends olMap { continue; } - const visible = mainLizmap.initialConfig.baseLayers.startupBaselayerName === baseLayerCfg.name; + const visible = mainLizmap.initialConfig.baseLayers.startupBaselayerName === baseLayerState.name; baseLayer.setProperties({ - name: baseLayerCfg.name, - title: baseLayerCfg.title, + name: baseLayerState.name, + title: baseLayerState.title, visible: visible }); baseLayers.push(baseLayer); - if (visible && baseLayerCfg.crs !== qgisProjectProjection) { + if (visible && baseLayer.getSource().getProjection().getCode() !== qgisProjectProjection) { this.getView().getProjection().setExtent(mainLizmap.lizmap3.map.restrictedExtent.toArray()); } } diff --git a/assets/src/modules/State.js b/assets/src/modules/State.js index 6ee9716efd..7089371bcc 100644 --- a/assets/src/modules/State.js +++ b/assets/src/modules/State.js @@ -36,7 +36,7 @@ export class State extends EventDispatcher { **/ get baseLayers() { if (this._baseLayers == null) { - this._baseLayers = new BaseLayersState(this._initialConfig.baseLayers); + this._baseLayers = new BaseLayersState(this._initialConfig.baseLayers, this.layersAndGroupsCollection); // Dispatch events from base layers this._baseLayers.addListener(this.dispatch.bind(this), 'baselayers.selection.changed'); } diff --git a/assets/src/modules/state/BaseLayer.js b/assets/src/modules/state/BaseLayer.js index b2e1e77f7e..97422a284b 100644 --- a/assets/src/modules/state/BaseLayer.js +++ b/assets/src/modules/state/BaseLayer.js @@ -1,4 +1,350 @@ import EventDispatcher from './../../utils/EventDispatcher.js'; +import { convertBoolean } from './../utils/Converters.js'; +import { BaseLayerTypes } from './../config/BaseLayer.js'; + +/** + * Class representing a base layer state + * @class + */ +export class BaseLayerState extends EventDispatcher { + /** + * Create a base layer state based on the base layer config + * + * @param {BaseLayersConfig} baseLayersCfg - the lizmap config object for base layer + * @param {LayerVectorState|LayerRasterState|LayerGroupState} [itemState] - the lizmap layer item state of the base layer if exists + */ + constructor(baseLayerCfg, itemState = null ) { + if (itemState !== null && baseLayerCfg.name !== itemState.name) { + throw new TypeError('Base layer config and layer item sate have not the same name!\n- `'+baseLayerCfg.name+'` for base layer config\n- `'+itemState.name+'` for layer item state'); + } + super() + this._baseLayerConfig = baseLayerCfg; + this._itemState = itemState; + } + + /** + * The base layer type + * + * @type {String} + **/ + get type() { + return this._baseLayerConfig.type; + } + + /** + * The base layer name + * + * @type {String} + **/ + get name() { + return this._baseLayerConfig.name; + } + + /** + * The base layer title + * + * @type {String} + **/ + get title() { + return this._baseLayerConfig.title; + } + + /** + * The base layer key is defined + * + * @type {boolean} + **/ + get hasKey() { + return this._baseLayerConfig.hasKey; + } + + /** + * The base layer key + * + * @type {?String} + **/ + get key() { + return this._baseLayerConfig.key; + } + + /** + * Attribution is defined + * + * @type {Boolean} + **/ + get hasAttribution() { + return this._baseLayerConfig.hasAttribution; + } + /** + * Attribution + * + * @type {?AttributionConfig} + **/ + get attribution() { + return this._baseLayerConfig.attribution; + } + + /** + * A Lizmap layer config is associated with this base layer + * + * @type {Boolean} + **/ + get hasLayerConfig() { + return this._baseLayerConfig.hasLayerConfig; + } + /** + * The Lizmap layer config associated with this base layer + * + * @type {?LayerConfig} + **/ + get layerConfig() { + return this._baseLayerConfig.layerConfig; + } + + /** + * A Lizmap layer item state is associated with this base layer + * + * @type {Boolean} + **/ + get hasItemState() { + return this._itemState !== null; + } + /** + * The Lizmap layer item state associated with this base layer + * + * @type {?LayerVectorState|LayerRasterState|LayerGroupState} + **/ + get itemState() { + return this._itemState; + } + + /** + * Is base layer loading? + * + * @type {Boolean} + **/ + get loading() { + return this._loading; + } + + /** + * Set base layer's loading state + * + * @param {Boolean} + **/ + set loading(loading) { + const newVal = convertBoolean(loading); + // No changes + if (this._loading == newVal) { + return; + } + // Set new value + this._loading = newVal; + + this.dispatch({ + type: 'baselayer.loading.changed', + name: this.name, + loading: this.loading, + }) + } +} + +/** + * Class representing an empty base layer state + * @class + * @augments BaseLayerState + */ +export class EmptyBaseLayerState extends BaseLayerState { + /** + * Create a base layers empty state based on the empty base layer config + * + * @param {EmptyBaseLayersConfig} baseLayersCfg - the lizmap empty base layer config object + * @param {LayerGroupState} [itemState] - the lizmap empty layer group state + */ + constructor(baseLayerCfg, itemState = null ) { + if (baseLayerCfg.type !== BaseLayerTypes.Empty) { + throw new TypeError('Not an `' + BaseLayerTypes.Empty + '` base layer config. Get `' + baseLayerCfg.type + '` for `' + baseLayerCfg.name + '`!'); + } + super(baseLayerCfg, itemState) + } +} + +/** + * Class representing an xyz base layer state + * @class + * @augments BaseLayerState + */ +export class XyzBaseLayerState extends BaseLayerState { + /** + * Create a base layers xyz state based on the xyz base layer config + * + * @param {EmptyBaseLayersConfig} baseLayersCfg - the lizmap xyz base layer config object + * @param {LayerRasterState} [itemState] - the lizmap xyz layer layer state + */ + constructor(baseLayerCfg, itemState = null ) { + if (baseLayerCfg.type !== BaseLayerTypes.XYZ) { + throw new TypeError('Not an `' + BaseLayerTypes.XYZ + '` base layer config. Get `' + baseLayerCfg.type + '` for `' + baseLayerCfg.name + '`!'); + } + super(baseLayerCfg, itemState) + } + + /** + * The base layer url + * + * @type {String} + **/ + get url() { + return this._baseLayerConfig.url; + } + + /** + * The base layer zmin + * + * @type {Number} + **/ + get zmin() { + return this._baseLayerConfig.zmin; + } + + /** + * The base layer zmax + * + * @type {Number} + **/ + get zmax() { + return this._baseLayerConfig.zmax; + } + + /** + * The base layer crs + * + * @type {String} + **/ + get crs() { + return this._baseLayerConfig.crs; + } +} + +/** + * Class representing an bing base layer state + * @class + * @augments BaseLayerState + */ +export class BingBaseLayerState extends BaseLayerState { + /** + * Create a base layers bing state based on the bing base layer config + * + * @param {EmptyBaseLayersConfig} baseLayersCfg - the lizmap bing base layer config object + * @param {LayerRasterState} [itemState] - the lizmap bing layer layer state + */ + constructor(baseLayerCfg, itemState = null ) { + if (baseLayerCfg.type !== BaseLayerTypes.Bing) { + throw new TypeError('Not an `' + BaseLayerTypes.Bing + '` base layer config. Get `' + baseLayerCfg.type + '` for `' + baseLayerCfg.name + '`!'); + } + super(baseLayerCfg, itemState) + } + + /** + * The bing imagerySet + * + * @type {String} + **/ + get imagerySet() { + return this._baseLayerConfig.imagerySet; + } +} + +/** + * Class representing an WMTS base layer state + * @class + * @augments BaseLayerState + */ +export class WmtsBaseLayerState extends BaseLayerState { + /** + * Create a base layers WMTS state based on the WMTS base layer config + * + * @param {EmptyBaseLayersConfig} baseLayersCfg - the lizmap WMTS base layer config object + * @param {LayerRasterState} [itemState] - the lizmap WMTS layer layer state + */ + constructor(baseLayerCfg, itemState = null ) { + if (baseLayerCfg.type !== BaseLayerTypes.WMTS) { + throw new TypeError('Not an `' + BaseLayerTypes.WMTS + '` base layer config. Get `' + baseLayerCfg.type + '` for `' + baseLayerCfg.name + '`!'); + } + super(baseLayerCfg, itemState) + } + + /** + * The base layer url + * + * @type {String} + **/ + get url() { + return this._baseLayerConfig.url; + } + + /** + * The base layer wmts layer + * + * @type {String} + **/ + get layer() { + return this._baseLayerConfig.layer; + } + + /** + * The base layer wmts format + * + * @type {String} + **/ + get format() { + return this._baseLayerConfig.format; + } + + /** + * The base layer wmts style + * + * @type {String} + **/ + get style() { + return this._baseLayerConfig.style; + } + + /** + * The base layer matrixSet + * + * @type {String} + **/ + get matrixSet() { + return this._baseLayerConfig.matrixSet; + } + + /** + * The base layer crs + * + * @type {String} + **/ + get crs() { + return this._baseLayerConfig.crs; + } + + /** + * The base layer numZoomLevels + * + * @type {Number} + **/ + get numZoomLevels() { + return this._baseLayerConfig.numZoomLevels; + } + + /** + * The base layer zmax + * + * @type {Number} + **/ + get zmax() { + return this._baseLayerConfig.zmax; + } +} /** * Class representing a base layers state @@ -9,12 +355,37 @@ export class BaseLayersState extends EventDispatcher { /** * Create a base layers state based on the base layers config * - * @param {BaseLayersConfig} baseLayersCfg - the lizmap config object for base layers + * @param {BaseLayersConfig} baseLayersCfg - the lizmap config object for base layers + * @param {LayersAndGroupsCollection} lgCollection - the collection of layers and groups state */ - constructor(baseLayersCfg) { + constructor(baseLayersCfg, lgCollection) { super() - this._baseLayersMap = new Map(baseLayersCfg.baseLayerConfigs.map(l => [l.name, l])); + //this._baseLayersMap = new Map(baseLayersCfg.baseLayerConfigs.map(l => [l.name, l])); + this._baseLayersMap = new Map() + for (const blConfig of baseLayersCfg.getBaseLayerConfigs()) { + let itemState = null; + if (blConfig.hasLayerConfig) { + itemState = lgCollection.getLayerOrGroupByName(blConfig.name); + } + switch(blConfig.type) { + case BaseLayerTypes.Empty: + this._baseLayersMap.set(blConfig.name, new EmptyBaseLayerState(blConfig, itemState)); + break; + case BaseLayerTypes.XYZ: + this._baseLayersMap.set(blConfig.name, new XyzBaseLayerState(blConfig, itemState)); + break; + case BaseLayerTypes.Bing: + this._baseLayersMap.set(blConfig.name, new BingBaseLayerState(blConfig, itemState)); + break; + case BaseLayerTypes.WMTS: + this._baseLayersMap.set(blConfig.name, new WmtsBaseLayerState(blConfig, itemState)); + break; + default: + this._baseLayersMap.set(blConfig.name, new BaseLayerState(blConfig, itemState)); + break; + } + } this._selectedBaseLayerName = baseLayersCfg.startupBaselayerName; } @@ -51,9 +422,9 @@ export class BaseLayersState extends EventDispatcher { /** * Selected base layer config * - * @type {BaseLayerConfig} + * @type {BaseLayerState} **/ - get selectedBaseLayerConfig() { + get selectedBaseLayer() { return this._baseLayersMap.get(this._selectedBaseLayerName); } @@ -69,9 +440,9 @@ export class BaseLayersState extends EventDispatcher { /** * Base layer configs * - * @type {BaseLayerConfig[]} + * @type {BaseLayerState[]} **/ - get baseLayerConfigs() { + get baseLayers() { return [...this._baseLayersMap.values()]; } @@ -80,11 +451,11 @@ export class BaseLayersState extends EventDispatcher { * * @param {String} name - the base layer name * - * @returns {BaseLayerConfig} The base layer config associated to the name + * @returns {BaseLayerState} The base layer config associated to the name * * @throws {RangeError} The base layer name is unknown **/ - getBaseLayerConfigByName(name) { + getBaseLayerByName(name) { const layer = this._baseLayersMap.get(name); if (layer !== undefined) { if (layer.name !== name) { @@ -111,9 +482,9 @@ export class BaseLayersState extends EventDispatcher { * Iterate through base layer configs * * @generator - * @yields {BaseLayerConfig} The next base layer config + * @yields {BaseLayerState} The next base layer config **/ - *getBaseLayerConfigs() { + *getBaseLayers() { for (const layer of this._baseLayersMap.values()) { yield layer; } diff --git a/tests/js-units/node/state.test.js b/tests/js-units/node/state.test.js index 79d26c26a7..5a7037d685 100644 --- a/tests/js-units/node/state.test.js +++ b/tests/js-units/node/state.test.js @@ -81,8 +81,8 @@ describe('State', function () { 'osm-stamen-toner', ]) expect(state.baseLayers.selectedBaseLayerName).to.be.eq('osm-stamen-toner') - expect(state.baseLayers.selectedBaseLayerConfig).to.not.be.undefined - expect(state.baseLayers.selectedBaseLayerConfig.name).to.be.eq('osm-stamen-toner') + expect(state.baseLayers.selectedBaseLayer).to.not.be.undefined + expect(state.baseLayers.selectedBaseLayer.name).to.be.eq('osm-stamen-toner') eventLogs = [] // Update selected base layer diff --git a/tests/js-units/node/state/baselayer.test.js b/tests/js-units/node/state/baselayer.test.js index 09fd8f765a..85f82d6a10 100644 --- a/tests/js-units/node/state/baselayer.test.js +++ b/tests/js-units/node/state/baselayer.test.js @@ -4,10 +4,18 @@ import { readFileSync } from 'fs'; import { LayersConfig } from '../../../../assets/src/modules/config/Layer.js'; import { LayerTreeGroupConfig, buildLayerTreeConfig } from '../../../../assets/src/modules/config/LayerTree.js'; -import { BaseLayersConfig } from '../../../../assets/src/modules/config/BaseLayer.js'; +import { BaseLayerTypes, BaseLayersConfig } from '../../../../assets/src/modules/config/BaseLayer.js'; +import { buildLayersOrder } from '../../../../assets/src/modules/config/LayersOrder.js'; +import { LayersAndGroupsCollection } from '../../../../assets/src/modules/state/Layer.js'; import { BaseLayersState } from '../../../../assets/src/modules/state/BaseLayer.js'; +describe('BaseLayerState', function () { + + it('From options and layers tree', function () { + }) +}) + describe('BaseLayersState', function () { it('From options and layers tree', function () { @@ -28,9 +36,9 @@ describe('BaseLayersState', function () { config.layers[blName] = blGroupCfg; const layers = new LayersConfig(config.layers); - const root = buildLayerTreeConfig(capabilities.Capability.Layer, layers); + const rootCfg = buildLayerTreeConfig(capabilities.Capability.Layer, layers); - const blGroup = root.children[6]; + const blGroup = rootCfg.children[6]; expect(blGroup).to.be.instanceOf(LayerTreeGroupConfig) const options = { @@ -38,31 +46,35 @@ describe('BaseLayersState', function () { }; const baseLayersConfig = new BaseLayersConfig({}, options, layers, blGroup) - const baseLayers = new BaseLayersState(baseLayersConfig) + const layersOrder = buildLayersOrder(config, rootCfg); + + const collection = new LayersAndGroupsCollection(rootCfg, layersOrder); + + const baseLayers = new BaseLayersState(baseLayersConfig, collection) expect(baseLayers.selectedBaseLayerName).to.be.eq('osm-mapnik') - expect(baseLayers.selectedBaseLayerConfig).to.not.be.undefined - expect(baseLayers.selectedBaseLayerConfig.name).to.be.eq('osm-mapnik') + expect(baseLayers.selectedBaseLayer).to.not.be.undefined + expect(baseLayers.selectedBaseLayer.name).to.be.eq('osm-mapnik') expect(baseLayers.baseLayerNames).to.be.an('array').that.have.length(3).that.ordered.members([ 'osm-mapnik', 'osm-stamen-toner', 'empty' ]) - expect(baseLayers.baseLayerConfigs).to.be.an('array').that.have.length(3) - expect(baseLayers.baseLayerConfigs.map(l => l.name)).to.be.an('array').that.have.length(3).that.ordered.members([ + expect(baseLayers.baseLayers).to.be.an('array').that.have.length(3) + expect(baseLayers.baseLayers.map(l => l.name)).to.be.an('array').that.have.length(3).that.ordered.members([ 'osm-mapnik', 'osm-stamen-toner', 'empty' ]) - expect(baseLayers.baseLayerConfigs.map(l => l.type)).to.be.an('array').that.have.length(3).that.ordered.members([ - 'xyz', - 'xyz', - 'empty' + expect(baseLayers.baseLayers.map(l => l.type)).to.be.an('array').that.have.length(3).that.ordered.members([ + BaseLayerTypes.XYZ, + BaseLayerTypes.XYZ, + BaseLayerTypes.Empty ]) baseLayers.selectedBaseLayerName = 'osm-stamen-toner' expect(baseLayers.selectedBaseLayerName).to.be.eq('osm-stamen-toner') - expect(baseLayers.selectedBaseLayerConfig).to.not.be.undefined - expect(baseLayers.selectedBaseLayerConfig.name).to.be.eq('osm-stamen-toner') + expect(baseLayers.selectedBaseLayer).to.not.be.undefined + expect(baseLayers.selectedBaseLayer.name).to.be.eq('osm-stamen-toner') // Try set an unknown base layer try { @@ -73,16 +85,78 @@ describe('BaseLayersState', function () { expect(error).to.be.instanceOf(RangeError) } - expect(baseLayers.getBaseLayerConfigByName('empty').type).to.be.eq('empty') + expect(baseLayers.getBaseLayerByName('empty').type).to.be.eq(BaseLayerTypes.Empty) // Try get an unknown base layer try { - baseLayers.getBaseLayerConfigByName('project-background-layer') + baseLayers.getBaseLayerByName('project-background-layer') } catch (error) { expect(error.name).to.be.eq('RangeError') expect(error.message).to.be.eq('The base layer name `project-background-layer` is unknown!') expect(error).to.be.instanceOf(RangeError) } + }) + + it('From baselayers user defined', function () { + const capabilities = JSON.parse(readFileSync('./data/backgrounds-capabilities.json', 'utf8')); + expect(capabilities).to.not.be.undefined + expect(capabilities.Capability).to.not.be.undefined + const config = JSON.parse(readFileSync('./data/backgrounds-config.json', 'utf8')); + expect(config).to.not.be.undefined + + const layers = new LayersConfig(config.layers); + const rootCfg = buildLayerTreeConfig(capabilities.Capability.Layer, layers); + + const blGroup = rootCfg.children[1]; + expect(blGroup).to.be.instanceOf(LayerTreeGroupConfig) + + const baseLayersConfig = new BaseLayersConfig({}, {}, layers, blGroup) + + const layersOrder = buildLayersOrder(config, rootCfg); + + const collection = new LayersAndGroupsCollection(rootCfg, layersOrder); + + const baseLayers = new BaseLayersState(baseLayersConfig, collection) + expect(baseLayers.selectedBaseLayerName).to.be.eq('project-background-color') + expect(baseLayers.selectedBaseLayer).to.not.be.undefined + expect(baseLayers.selectedBaseLayer.name).to.be.eq('project-background-color') + expect(baseLayers.baseLayerNames) + .to.be.an('array') + .that.have.length(9) + .that.be.deep.eq([ + "project-background-color", + "OpenStreetMap", + "Stamen Watercolor", + "group with many layers", + "local vector layer", + "local raster layer", + "WMTS demo.lizmap.com grouped", + "WMTS demo.lizmap.com communes", + "WMS demo.lizmap.com communes", + ]) + expect(baseLayers.baseLayers).to.be.an('array').that.have.length(9) + expect(baseLayers.baseLayers.map(l => l.name)).to.be.an('array').that.have.length(9).that.ordered.members([ + "project-background-color", + "OpenStreetMap", + "Stamen Watercolor", + "group with many layers", + "local vector layer", + "local raster layer", + "WMTS demo.lizmap.com grouped", + "WMTS demo.lizmap.com communes", + "WMS demo.lizmap.com communes", + ]) + expect(baseLayers.baseLayers.map(l => l.type)).to.be.an('array').that.have.length(9).that.ordered.members([ + BaseLayerTypes.Empty, + BaseLayerTypes.XYZ, + BaseLayerTypes.XYZ, + BaseLayerTypes.Lizmap, + BaseLayerTypes.Lizmap, + BaseLayerTypes.Lizmap, + BaseLayerTypes.Lizmap, + BaseLayerTypes.Lizmap, + BaseLayerTypes.Lizmap, + ]) }); })