diff --git a/packages/core/src/layers/Layer.ts b/packages/core/src/layers/Layer.ts index 874f3a439..742c0267f 100644 --- a/packages/core/src/layers/Layer.ts +++ b/packages/core/src/layers/Layer.ts @@ -18,9 +18,14 @@ */ import {Listener as Listeners} from '@here/xyz-maps-common'; +import {LayerOptions} from './LayerOptions'; -const REMOVE_LAYER_EVENT = 'layerRemove'; -const ADD_LAYER_EVENT = 'layerAdd'; + +enum LAYER_EVENT { + REMOVE = 'layerRemove', + ADD = 'layerAdd', + VISIBILITY_CHANGE = 'layerVisibilityChange', +} let UNDEF; @@ -54,12 +59,16 @@ export class Layer { */ public max: number; + private visible: boolean; + /** * @param options - options to configure the Layer */ - constructor(options) { + constructor(options: LayerOptions) { const layer = this; + options = {visible: true, ...options}; + for (const c in options) { layer[c] = options[c]; } @@ -68,10 +77,7 @@ export class Layer { (layer).id = 'L-' + (Math.random() * 1e8 ^ 0); } - layer._l = new Listeners([ - ADD_LAYER_EVENT, - REMOVE_LAYER_EVENT - ]); + layer._l = new Listeners(Object.values(LAYER_EVENT)); }; addEventListener(type: string, listener: (event: CustomEvent) => void, _c?) { @@ -105,4 +111,62 @@ export class Layer { const event = new CustomEvent(type, {detail}); this._l.trigger(type, event, !async); } + + /** + * Sets the visibility of the Layer. + * + * This function controls whether the tile layer is currently displayed or hidden. + * + * @param {boolean} [isVisible] - A boolean value indicating whether the tile layer should be visible (true) or hidden (false). + * + * @returns {boolean} - The current visibility state of the tile layer. + * + * @example + * ``` + * // Create a new tile layer + * let tileLayer = new XYZMapsTileLayer(); + * + * // Hide the tile layer + * tileLayer.visible(false); + * + * // Show the tile layer + * tileLayer.visible(true); + * ``` + */ + setVisible(isVisible?: boolean) { + if (typeof isVisible == 'boolean') { + const {visible} = this; + this.visible = !!isVisible; + + if (visible != isVisible) { + this._l.trigger(LAYER_EVENT.VISIBILITY_CHANGE, new CustomEvent(LAYER_EVENT.VISIBILITY_CHANGE, { + detail: { + visible: isVisible, + layer: this + } + }), false); + } + } + } + + /** + * Checks whether the xyz-maps tile layer is currently visible. + * + * @returns {boolean} - Returns `true` if the layer is visible, otherwise `false`. + * + * @example + * ``` + * if (layer.isVisible()) { + * console.log("Layer is visible"); + * } else { + * console.log("Layer is not visible"); + * } + * ``` + */ + isVisible(): boolean; + isVisible(zoomLevel?: number): boolean { + return (!this.visible || zoomLevel == UNDEF) + ? this.visible + : zoomLevel >= this.min && zoomLevel <= this.max; + } } diff --git a/packages/core/src/layers/LayerOptions.ts b/packages/core/src/layers/LayerOptions.ts new file mode 100644 index 000000000..85e43c4ed --- /dev/null +++ b/packages/core/src/layers/LayerOptions.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019-2024 HERE Europe B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +import TileProvider from '../providers/TileProvider/TileProvider'; +import {LayerStyle} from '../styles/LayerStyle'; + + +/** + * Configuration options for a Layer. + */ +export interface LayerOptions { + /** + * Name of the Layer. + */ + name?: string; + + /** + * minimum zoom level at which data from the Layer will be displayed. + */ + min?: number; + + /** + * maximum zoom level at which data from the Layer will be displayed. + */ + max?: number; + + /** + * Indicates whether the layer should be visible (`true`) or hidden (`false`). + * @defaultValue true + */ + visible?: boolean +} diff --git a/packages/core/src/layers/TileLayer.ts b/packages/core/src/layers/TileLayer.ts index 1abaca8e5..1d8a5d44c 100644 --- a/packages/core/src/layers/TileLayer.ts +++ b/packages/core/src/layers/TileLayer.ts @@ -167,7 +167,6 @@ export class TileLayer extends Layer { layer.setMargin(layer.getMargin()); - let style; // deprecated fallback const deprecatedProviderStyles = this._fp && ( this._fp).styles; diff --git a/packages/core/src/layers/TileLayerOptions.ts b/packages/core/src/layers/TileLayerOptions.ts index df8ae9310..821c1db25 100644 --- a/packages/core/src/layers/TileLayerOptions.ts +++ b/packages/core/src/layers/TileLayerOptions.ts @@ -19,12 +19,13 @@ import TileProvider from '../providers/TileProvider/TileProvider'; import {LayerStyle} from '../styles/LayerStyle'; +import {LayerOptions} from './LayerOptions'; /** * Configuration options for a TileLayer. */ -export interface TileLayerOptions { +export interface TileLayerOptions extends LayerOptions { /** * Name of the TileLayer. */ diff --git a/packages/display/src/Map.ts b/packages/display/src/Map.ts index 738b4732b..2e50c9c7a 100644 --- a/packages/display/src/Map.ts +++ b/packages/display/src/Map.ts @@ -329,7 +329,7 @@ export class Map { tigerMap.setZoomlevel(zoomLevel); - tigerMap._layerClearListener = tigerMap._layerClearListener.bind(tigerMap); + tigerMap._layerChangeListener = tigerMap._layerChangeListener.bind(tigerMap); for (let layer of (options['layers'] || [])) { tigerMap.addLayer(layer); @@ -342,9 +342,9 @@ export class Map { } } - private _layerClearListener(ev) { - // refresh(re-fetch) data if layer get's cleared - this.refresh(ev.detail.layer); + private _layerChangeListener(ev) { + // refresh render-data if layer is cleared + this.refresh(ev.type === 'clear'??ev.detail.layer); } private initViewPort(): [number, number] { @@ -1268,7 +1268,8 @@ export class Map { this._display.addLayer(layer, index, (layer as TileLayer).getStyleManager?.()); // if layer get's cleared -> refresh/re-fetch data // layer.addEventListener('clear', (ev)=>this.refresh(ev.detail.layer)); - layer.addEventListener('clear', this._layerClearListener); + layer.addEventListener('clear', this._layerChangeListener); + layer.addEventListener('layerVisibilityChange', this._layerChangeListener); const eventDetail = { @@ -1301,7 +1302,8 @@ export class Map { if (index >= 0) { this._display.removeLayer(layer); // layer.removeEventListener('clear', (ev)=>this.refresh(ev.detail.layer)); - layer.removeEventListener('clear', this._layerClearListener); + layer.removeEventListener('clear', this._layerChangeListener); + layer.removeEventListener('layerVisibilityChange', this._layerChangeListener); layers.splice(index, 1); diff --git a/packages/display/src/displays/BasicDisplay.ts b/packages/display/src/displays/BasicDisplay.ts index 334316243..a9fa85b29 100644 --- a/packages/display/src/displays/BasicDisplay.ts +++ b/packages/display/src/displays/BasicDisplay.ts @@ -404,10 +404,8 @@ abstract class Display { let layerTileSize = layer.tileSize || 256; if (layerTileSize == gridTileSize) { - if (dLayer.tiles != screenTiles) { + if (layer.isVisible(zoomLevel)) { dLayer.tiles = screenTiles; - } - if (zoomLevel >= layer.min && zoomLevel <= layer.max) { display.initTile(displayTile, dLayer); layer.getTile(quadkey, dLayer.handleTile); } @@ -511,6 +509,7 @@ abstract class Display { } this.dirty = true; + display.update(); } diff --git a/packages/display/src/displays/Layers.ts b/packages/display/src/displays/Layers.ts index f8740d76c..fc193224e 100644 --- a/packages/display/src/displays/Layers.ts +++ b/packages/display/src/displays/Layers.ts @@ -239,7 +239,7 @@ class Layers extends Array { dLayer.cnt = 0; dLayer.tiles = []; - if (dLayer.visible = zoomlevel >= layer['min'] && zoomlevel <= layer['max']) { + if (dLayer.visible = layer.isVisible(zoomlevel)) { dLayer.ready = false; if (layer.custom) continue; diff --git a/packages/display/src/search/Search.ts b/packages/display/src/search/Search.ts index ca56e93b9..94809a5b5 100644 --- a/packages/display/src/search/Search.ts +++ b/packages/display/src/search/Search.ts @@ -18,7 +18,7 @@ */ import Hit from './Hit'; -import {CustomLayer, Feature, TileLayer} from '@here/xyz-maps-core'; +import {CustomLayer, Feature, TileLayer, TileLayerOptions} from '@here/xyz-maps-core'; import {Map} from '../Map'; import {Layers} from '../displays/Layers'; @@ -95,7 +95,7 @@ export class Search { let found = []; let viewbounds; let provider; - let layer; + let layer: TileLayer; let feature; let features; let length; @@ -139,7 +139,7 @@ export class Search { const displayLayer = this.layers.get(layer); - if (zoomlevel <= layer.max && zoomlevel >= layer.min && provider?.search) { + if (provider?.search && layer.isVisible(zoomlevel) ) { features = provider.search(viewbounds); length = features.length; while (length--) {