diff --git a/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component.ts b/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component.ts index 07bc6804a1..278dca0fc2 100644 --- a/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component.ts +++ b/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component.ts @@ -59,12 +59,7 @@ export class AddLayerRecordPreviewComponent extends RecordPreviewComponent { name: link.name, }) } else if (link.accessServiceProtocol === 'wmts') { - return this.mapUtils.getWmtsOptionsFromCapabilities(link).pipe( - map((options) => ({ - type: MapContextLayerTypeEnum.WMTS, - options: options, - })) - ) + return this.mapUtils.getWmtsLayerFromCapabilities(link) } return throwError(() => 'protocol not supported') } diff --git a/libs/feature/map/src/lib/map-context/map-context.model.ts b/libs/feature/map/src/lib/map-context/map-context.model.ts index 6c40ecd8ed..e005842a20 100644 --- a/libs/feature/map/src/lib/map-context/map-context.model.ts +++ b/libs/feature/map/src/lib/map-context/map-context.model.ts @@ -25,6 +25,7 @@ export interface MapContextLayerWmsModel { export interface MapContextLayerWmtsModel { type: 'wmts' options: Options + extent?: Extent } interface MapContextLayerWfsModel { diff --git a/libs/feature/map/src/lib/utils/map-utils.service.spec.ts b/libs/feature/map/src/lib/utils/map-utils.service.spec.ts index 2dc0bf257a..545e746b09 100644 --- a/libs/feature/map/src/lib/utils/map-utils.service.spec.ts +++ b/libs/feature/map/src/lib/utils/map-utils.service.spec.ts @@ -9,7 +9,6 @@ import Map from 'ol/Map' import ImageWMS from 'ol/source/ImageWMS' import TileWMS from 'ol/source/TileWMS' import XYZ from 'ol/source/XYZ' -import { Options } from 'ol/source/WMTS' import { of } from 'rxjs' import { MapUtilsWMSService } from './map-utils-wms.service' import { @@ -27,6 +26,7 @@ import { } from 'ol/interaction' import { DatasetServiceDistribution } from '@geonetwork-ui/common/domain/model/record' import MapBrowserEvent from 'ol/MapBrowserEvent' +import type { MapContextLayerWmtsModel } from '../map-context/map-context.model' jest.mock('ol/proj/proj4', () => { const fromEPSGCodeMock = jest.fn() @@ -444,7 +444,7 @@ describe('MapUtilsService', () => { window.fetch = originalFetch }) describe('nominal', () => { - let wmtsOptions: Options + let wmtsLayer: MapContextLayerWmtsModel beforeEach(async () => { ;(window as any).fetch = jest.fn(() => Promise.resolve({ @@ -453,8 +453,8 @@ describe('MapUtilsService', () => { text: () => Promise.resolve(SAMPLE_WMTS_CAPABILITIES), }) ) - wmtsOptions = await readFirst( - service.getWmtsOptionsFromCapabilities(SAMPLE_WMTS_LINK) + wmtsLayer = await readFirst( + service.getWmtsLayerFromCapabilities(SAMPLE_WMTS_LINK) ) }) it('appends query params to the URL', () => { @@ -463,13 +463,49 @@ describe('MapUtilsService', () => { ) }) it('returns appropriate WMTS options', () => { - expect(wmtsOptions).toMatchObject({ - format: 'image/jpeg', - layer: 'GEOGRAPHICALGRIDSYSTEMS.ETATMAJOR10', - matrixSet: 'PM', - requestEncoding: 'KVP', - style: 'normal', - urls: ['https://wxs.ign.fr/cartes/geoportail/wmts?'], + expect(wmtsLayer).toMatchObject({ + type: 'wmts', + options: { + format: 'image/jpeg', + layer: 'GEOGRAPHICALGRIDSYSTEMS.ETATMAJOR10', + matrixSet: 'PM', + requestEncoding: 'KVP', + style: 'normal', + urls: ['https://wxs.ign.fr/cartes/geoportail/wmts?'], + }, + }) + }) + describe('layer extent', () => { + describe('when the WGS84BoundingBox is defined', () => { + it('set the WGS84BoundingBox', () => { + expect(wmtsLayer.extent).toEqual([ + 1.82682, 48.3847, 2.79738, 49.5142, + ]) + }) + }) + describe('when the WGS84BoundingBox is not defined', () => { + beforeEach(async () => { + ;(window as any).fetch = jest.fn(() => + Promise.resolve({ + ok: true, + status: 200, + text: () => + Promise.resolve( + SAMPLE_WMTS_CAPABILITIES.replace( + /WGS84BoundingBox/g, + 'NoWGS84BoundingBox' + ) + ), + }) + ) + wmtsLayer = await readFirst( + service.getWmtsLayerFromCapabilities(SAMPLE_WMTS_LINK) + ) + }) + + it('set the WGS84BoundingBox', () => { + expect(wmtsLayer.extent).toBeUndefined() + }) }) }) }) @@ -489,7 +525,7 @@ describe('MapUtilsService', () => { ) try { await readFirst( - service.getWmtsOptionsFromCapabilities(SAMPLE_WMTS_LINK) + service.getWmtsLayerFromCapabilities(SAMPLE_WMTS_LINK) ) } catch (e) { error = e @@ -515,7 +551,7 @@ describe('MapUtilsService', () => { ) try { await readFirst( - service.getWmtsOptionsFromCapabilities(SAMPLE_WMTS_LINK) + service.getWmtsLayerFromCapabilities(SAMPLE_WMTS_LINK) ) } catch (e) { error = e diff --git a/libs/feature/map/src/lib/utils/map-utils.service.ts b/libs/feature/map/src/lib/utils/map-utils.service.ts index 03871ce085..92ab59ac87 100644 --- a/libs/feature/map/src/lib/utils/map-utils.service.ts +++ b/libs/feature/map/src/lib/utils/map-utils.service.ts @@ -23,7 +23,11 @@ import { import WMTSCapabilities from 'ol/format/WMTSCapabilities' import { from, Observable, of } from 'rxjs' import { map } from 'rxjs/operators' -import { MapContextLayerModel } from '../map-context/map-context.model' +import { + MapContextLayerModel, + MapContextLayerTypeEnum, + MapContextLayerWmtsModel, +} from '../map-context/map-context.model' import { MapUtilsWMSService } from './map-utils-wms.service' import Collection from 'ol/Collection' import MapBrowserEvent from 'ol/MapBrowserEvent' @@ -150,7 +154,11 @@ export class MapUtilsService { } else if (layer && layer.type === 'wms') { geographicExtent = this.wmsUtils.getLayerLonLatBBox(layer) } else if (layer && layer.type === 'wmts') { - return of(layer.options.tileGrid.getExtent()) + if (layer.extent) { + geographicExtent = of(layer.extent) + } else { + return of(layer.options.tileGrid.getExtent()) + } } else { return of(null) } @@ -163,9 +171,9 @@ export class MapUtilsService { ) } - getWmtsOptionsFromCapabilities( + getWmtsLayerFromCapabilities( link: DatasetDistribution - ): Observable { + ): Observable { const getCapabilitiesUrl = new URL(link.url, window.location.toString()) getCapabilitiesUrl.searchParams.set('SERVICE', 'WMTS') getCapabilitiesUrl.searchParams.set('REQUEST', 'GetCapabilities') @@ -183,10 +191,20 @@ ${await response.text()}`) .then(function (text) { try { const result = new WMTSCapabilities().read(text) - return optionsFromCapabilities(result, { + const options = optionsFromCapabilities(result, { layer: link.name, matrixSet: 'EPSG:3857', }) + const layerCap = result?.Contents?.Layer.find( + (layer) => layer.Identifier === link.name + ) + return { + options, + type: MapContextLayerTypeEnum.WMTS as 'wmts', + ...(layerCap?.WGS84BoundingBox + ? { extent: layerCap.WGS84BoundingBox } + : {}), + } } catch (e: any) { throw new Error(`WMTS GetCapabilities parsing failed: ${e.stack || e.message || e}`) diff --git a/libs/feature/record/src/lib/map-view/map-view.component.spec.ts b/libs/feature/record/src/lib/map-view/map-view.component.spec.ts index d8a495eda7..54680f2ba2 100644 --- a/libs/feature/record/src/lib/map-view/map-view.component.spec.ts +++ b/libs/feature/record/src/lib/map-view/map-view.component.spec.ts @@ -80,9 +80,9 @@ class MapUtilsServiceMock { } }) }) - getWmtsOptionsFromCapabilities = jest.fn(function () { + getWmtsLayerFromCapabilities = jest.fn(function () { return new Observable((observer) => { - observer.next(null) + observer.next({ type: 'wmts', options: null }) }) }) prioritizePageScroll = jest.fn() 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 e638a14263..2adc81284c 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 @@ -173,12 +173,7 @@ export class MapViewComponent implements OnInit, OnDestroy { link.type === 'service' && link.accessServiceProtocol === 'wmts' ) { - return this.mapUtils.getWmtsOptionsFromCapabilities(link).pipe( - map((options) => ({ - type: MapContextLayerTypeEnum.WMTS, - options: options, - })) - ) + return this.mapUtils.getWmtsLayerFromCapabilities(link) } else if ( (link.type === 'service' && (link.accessServiceProtocol === 'wfs' ||