diff --git a/conf/default.toml b/conf/default.toml index 52ff28de20..50d40a6fb0 100644 --- a/conf/default.toml +++ b/conf/default.toml @@ -122,6 +122,9 @@ background_color = "#fdfbff" # Optional; Will limit the possibility to zoom in past a certain zoom level # max_zoom = 10 +# Optional; Will not tile WMS. False by default. +# do_not_tile_wms = false + # Optional; will limit the possibility to pan or zoom out outside of an extent # Expressed in the map view projection (EPSG:3857) # max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855] diff --git a/docs/guide/configure.md b/docs/guide/configure.md index 5c07b54f26..18adfdf327 100644 --- a/docs/guide/configure.md +++ b/docs/guide/configure.md @@ -206,6 +206,10 @@ The map section lets you customize how maps appear and behave across GeoNetwork- Will limit the possibility to zoom in past a certain zoom level. +- `do_not_tile_wms` (optional) + + Will not tile WMS. Defaults to `false` (WMS are tiled). + - `max_extent` (optional) Will limit the possibility to pan or zoom outside of an extent. Expressed as an array of _minX_, _minY_, _maxX_ and _maxY_ numerical components in the map view projection (EPSG:3857 by default), e.g.: diff --git a/libs/feature/map/src/lib/map-context/map-context.service.spec.ts b/libs/feature/map/src/lib/map-context/map-context.service.spec.ts index 9de1279924..6ad4b96600 100644 --- a/libs/feature/map/src/lib/map-context/map-context.service.spec.ts +++ b/libs/feature/map/src/lib/map-context/map-context.service.spec.ts @@ -1,6 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing' import { TestBed } from '@angular/core/testing' -import { MAP_CONFIG_FIXTURE } from '@geonetwork-ui/util/app-config' +import { MAP_CONFIG_FIXTURE, MapConfig } from '@geonetwork-ui/util/app-config' import { FeatureCollection } from 'geojson' import { Geometry } from 'ol/geom' import TileLayer from 'ol/layer/Tile' @@ -33,6 +33,8 @@ import { MapContextService, } from './map-context.service' import Feature from 'ol/Feature' +import ImageWMS from 'ol/source/ImageWMS' +import ImageLayer from 'ol/layer/Image' const mapStyleServiceMock = { createDefaultStyle: jest.fn(() => new Style()), @@ -130,35 +132,60 @@ describe('MapContextService', () => { }) describe('WMS', () => { - beforeEach(() => { - ;(layerModel = MAP_CTX_LAYER_WMS_FIXTURE), - (layer = service.createLayer(layerModel)) - }) - it('create a tile layer', () => { - expect(layer).toBeTruthy() - expect(layer).toBeInstanceOf(TileLayer) - }) - it('create a TileWMS source', () => { - const source = layer.getSource() - expect(source).toBeInstanceOf(TileWMS) - }) - it('set correct WMS params', () => { - const source = layer.getSource() - const params = source.getParams() - expect(params.LAYERS).toBe(layerModel.name) - }) - it('set correct url without existing REQUEST and SERVICE params', () => { - const source = layer.getSource() - const urls = source.getUrls() - expect(urls.length).toBe(1) - expect(urls[0]).toBe( - 'https://www.geograndest.fr/geoserver/region-grand-est/ows?REQUEST=GetCapabilities&SERVICE=WMS' - ) + describe('when mapConfig.DO_NOT_TILE_WMS === false', () => { + beforeEach(() => { + const mapConfig: MapConfig = { + ...MAP_CONFIG_FIXTURE, + DO_NOT_TILE_WMS: false, + } + ;(layerModel = MAP_CTX_LAYER_WMS_FIXTURE), + (layer = service.createLayer(layerModel, mapConfig)) + }) + it('create a tile layer', () => { + expect(layer).toBeTruthy() + expect(layer).toBeInstanceOf(TileLayer) + }) + it('create a TileWMS source', () => { + const source = layer.getSource() + expect(source).toBeInstanceOf(TileWMS) + }) + it('set correct WMS params', () => { + const source = layer.getSource() + const params = source.getParams() + expect(params.LAYERS).toBe(layerModel.name) + }) + it('set correct url without existing REQUEST and SERVICE params', () => { + const source = layer.getSource() + const urls = source.getUrls() + expect(urls.length).toBe(1) + expect(urls[0]).toBe( + 'https://www.geograndest.fr/geoserver/region-grand-est/ows?REQUEST=GetCapabilities&SERVICE=WMS' + ) + }) }) - it('set WMS gutter of 20px', () => { - const source = layer.getSource() - const gutter = source.gutter_ - expect(gutter).toBe(20) + + describe('when mapConfig.DO_NOT_TILE_WMS === true', () => { + beforeEach(() => { + const mapConfig: MapConfig = { + ...MAP_CONFIG_FIXTURE, + DO_NOT_TILE_WMS: true, + } + ;(layerModel = MAP_CTX_LAYER_WMS_FIXTURE), + (layer = service.createLayer(layerModel, mapConfig)) + }) + it('create an image layer', () => { + expect(layer).toBeTruthy() + expect(layer).toBeInstanceOf(ImageLayer) + }) + it('create an ImageWMS source', () => { + const source = layer.getSource() + expect(source).toBeInstanceOf(ImageWMS) + }) + it('set correct WMS params', () => { + const source = layer.getSource() + const params = source.getParams() + expect(params.LAYERS).toBe(layerModel.name) + }) }) }) diff --git a/libs/feature/map/src/lib/map-context/map-context.service.ts b/libs/feature/map/src/lib/map-context/map-context.service.ts index 8b63e20b48..eed2f51d89 100644 --- a/libs/feature/map/src/lib/map-context/map-context.service.ts +++ b/libs/feature/map/src/lib/map-context/map-context.service.ts @@ -29,6 +29,8 @@ import OGCVectorTile from 'ol/source/OGCVectorTile.js' import { MVT } from 'ol/format' import VectorTileLayer from 'ol/layer/VectorTile' import OGCMapTile from 'ol/source/OGCMapTile.js' +import ImageLayer from 'ol/layer/Image' +import ImageWMS from 'ol/source/ImageWMS' export const DEFAULT_BASELAYER_CONTEXT: MapContextLayerXyzModel = { type: MapContextLayerTypeEnum.XYZ, @@ -73,11 +75,13 @@ export class MapContextService { } map.setView(this.createView(mapContext.view, map)) map.getLayers().clear() - mapContext.layers.forEach((layer) => map.addLayer(this.createLayer(layer))) + mapContext.layers.forEach((layer) => + map.addLayer(this.createLayer(layer, mapConfig)) + ) return map } - createLayer(layerModel: MapContextLayerModel): Layer { + createLayer(layerModel: MapContextLayerModel, mapConfig?: MapConfig): Layer { const { type } = layerModel const style = this.styleService.styles.default switch (type) { @@ -112,13 +116,22 @@ export class MapContextService { }), }) case MapContextLayerTypeEnum.WMS: - return new TileLayer({ - source: new TileWMS({ - url: layerModel.url, - params: { LAYERS: layerModel.name }, - gutter: 20, - }), - }) + if (mapConfig?.DO_NOT_TILE_WMS) { + return new ImageLayer({ + source: new ImageWMS({ + url: layerModel.url, + params: { LAYERS: layerModel.name }, + }), + }) + } else { + return new TileLayer({ + source: new TileWMS({ + url: layerModel.url, + params: { LAYERS: layerModel.name, TILED: true }, + }), + }) + } + case MapContextLayerTypeEnum.WMTS: { // TODO: isolate this in utils service const olLayer = new TileLayer({}) diff --git a/libs/feature/record/src/lib/map-view/map-view.component.ts b/libs/feature/record/src/lib/map-view/map-view.component.ts index 137fa856ad..24870f16b6 100644 --- a/libs/feature/record/src/lib/map-view/map-view.component.ts +++ b/libs/feature/record/src/lib/map-view/map-view.component.ts @@ -15,7 +15,7 @@ import { MapUtilsService, } from '@geonetwork-ui/feature/map' import { getOptionalMapConfig, MapConfig } from '@geonetwork-ui/util/app-config' -import { getLinkLabel, ProxyService } from '@geonetwork-ui/util/shared' +import { getLinkLabel } from '@geonetwork-ui/util/shared' import Feature from 'ol/Feature' import { Geometry } from 'ol/geom' import { StyleLike } from 'ol/style/Style' @@ -23,10 +23,8 @@ import { BehaviorSubject, combineLatest, from, - lastValueFrom, Observable, of, - startWith, Subscription, throwError, withLatestFrom, @@ -117,7 +115,9 @@ export class MapViewComponent implements OnInit, OnDestroy { }, } as MapContextModel) ), - tap(() => this.resetSelection()) + tap((res) => { + this.resetSelection() + }) ) ), withLatestFrom(this.mdViewFacade.metadata$), diff --git a/libs/util/app-config/src/lib/app-config.ts b/libs/util/app-config/src/lib/app-config.ts index 35edc71193..04ca6b87fd 100644 --- a/libs/util/app-config/src/lib/app-config.ts +++ b/libs/util/app-config/src/lib/app-config.ts @@ -144,6 +144,7 @@ export function loadAppConfig() { [], [ 'max_zoom', + 'do_not_tile_wms', 'max_extent', 'baselayer', 'do_not_use_default_basemap', @@ -158,6 +159,7 @@ export function loadAppConfig() { ? null : ({ MAX_ZOOM: parsedMapSection.max_zoom, + DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms, MAX_EXTENT: parsedMapSection.max_extent, EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template, diff --git a/libs/util/app-config/src/lib/fixtures.ts b/libs/util/app-config/src/lib/fixtures.ts index 243a955c65..cd86492fff 100644 --- a/libs/util/app-config/src/lib/fixtures.ts +++ b/libs/util/app-config/src/lib/fixtures.ts @@ -81,6 +81,7 @@ export const MAP_CONFIG_FIXTURE: MapConfig = { MAX_ZOOM: 10, MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855], DO_NOT_USE_DEFAULT_BASEMAP: false, + DO_NOT_TILE_WMS: false, EXTERNAL_VIEWER_URL_TEMPLATE: 'https://example.com/myviewer/#/?actions=[{"type":"CATALOG:ADD_LAYERS_FROM_CATALOGS","layers":["${layer_name}"],"sources":[{"url":"${service_url}","type":"${service_type}"}]}]', EXTERNAL_VIEWER_OPEN_NEW_TAB: true, diff --git a/libs/util/app-config/src/lib/model.ts b/libs/util/app-config/src/lib/model.ts index ebf926f2ff..84682b6eee 100644 --- a/libs/util/app-config/src/lib/model.ts +++ b/libs/util/app-config/src/lib/model.ts @@ -20,6 +20,7 @@ export interface LayerConfig { export interface MapConfig { MAX_ZOOM?: number + DO_NOT_TILE_WMS: boolean MAX_EXTENT?: [number, number, number, number] // Expressed as [minx, miny, maxx, maxy] EXTERNAL_VIEWER_URL_TEMPLATE?: string EXTERNAL_VIEWER_OPEN_NEW_TAB?: boolean