diff --git a/libs/feature/map/src/lib/manager/map-instance.directive.ts b/libs/feature/map/src/lib/manager/map-instance.directive.ts
deleted file mode 100644
index 692ad3bb57..0000000000
--- a/libs/feature/map/src/lib/manager/map-instance.directive.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Directive } from '@angular/core'
-import { MapManagerService } from './map-manager.service'
-
-@Directive({
- selector: '[gnUiMapContainer]',
- providers: [MapManagerService],
-})
-export class MapInstanceDirective {
- constructor(private manager: MapManagerService) {}
-}
diff --git a/libs/feature/map/src/lib/manager/map-manager.service.spec.ts b/libs/feature/map/src/lib/manager/map-manager.service.spec.ts
deleted file mode 100644
index cab187c00e..0000000000
--- a/libs/feature/map/src/lib/manager/map-manager.service.spec.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { TestBed } from '@angular/core/testing'
-import { MapUtilsService } from '../utils/map-utils.service'
-
-import { MapManagerService } from './map-manager.service'
-
-const mapUtilsServiceMock = {
- createEmptyMap: jest.fn(),
-}
-describe('MapManagerService', () => {
- let service: MapManagerService
-
- beforeEach(() => {
- TestBed.configureTestingModule({
- providers: [
- {
- provide: MapUtilsService,
- useValue: mapUtilsServiceMock,
- },
- ],
- })
- service = TestBed.inject(MapManagerService)
- })
-
- it('should be created', () => {
- expect(service).toBeTruthy()
- })
-
- it('instanciate an empty map', () => {
- expect(mapUtilsServiceMock.createEmptyMap).toHaveBeenCalled()
- })
-})
diff --git a/libs/feature/map/src/lib/manager/map-manager.service.ts b/libs/feature/map/src/lib/manager/map-manager.service.ts
deleted file mode 100644
index d84a068909..0000000000
--- a/libs/feature/map/src/lib/manager/map-manager.service.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Injectable } from '@angular/core'
-import Map from 'ol/Map'
-import { MapUtilsService } from '../utils/map-utils.service'
-
-@Injectable({
- providedIn: 'root',
-})
-export class MapManagerService {
- readonly map: Map
- constructor(private utils: MapUtilsService) {
- this.map = this.utils.createEmptyMap()
- }
-}
diff --git a/libs/feature/map/src/lib/map-container/map-container.component.css b/libs/feature/map/src/lib/map-container/map-container.component.css
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/libs/feature/map/src/lib/map-container/map-container.component.html b/libs/feature/map/src/lib/map-container/map-container.component.html
deleted file mode 100644
index 5fe34f6eb5..0000000000
--- a/libs/feature/map/src/lib/map-container/map-container.component.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/libs/feature/map/src/lib/map-container/map-container.component.spec.ts b/libs/feature/map/src/lib/map-container/map-container.component.spec.ts
deleted file mode 100644
index 74d23e513d..0000000000
--- a/libs/feature/map/src/lib/map-container/map-container.component.spec.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing'
-import { MapContainerComponent } from './map-container.component'
-import { MapFacade } from '../+state/map.facade'
-import { of } from 'rxjs'
-import { mapCtxLayerXyzFixture } from '../map-context/map-context.fixtures'
-import { readFirst } from '@nx/angular/testing'
-import { DEFAULT_BASELAYER_CONTEXT } from '../map-context/map-context.service'
-import { NO_ERRORS_SCHEMA } from '@angular/core'
-
-class MapFacadeMock {
- layers$ = of([mapCtxLayerXyzFixture()])
-}
-
-describe('MapContainerComponent', () => {
- let component: MapContainerComponent
- let fixture: ComponentFixture
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [MapContainerComponent],
- providers: [
- {
- provide: MapFacade,
- useClass: MapFacadeMock,
- },
- ],
- schemas: [NO_ERRORS_SCHEMA],
- }).compileComponents()
-
- fixture = TestBed.createComponent(MapContainerComponent)
- component = fixture.componentInstance
- fixture.detectChanges()
- })
-
- it('should create', () => {
- expect(component).toBeTruthy()
- })
-
- describe('context$', () => {
- it('emits a context containing the layers in the map', async () => {
- const context = await readFirst(component.context$)
- expect(context).toStrictEqual({
- layers: [DEFAULT_BASELAYER_CONTEXT, mapCtxLayerXyzFixture()],
- view: {
- center: expect.any(Array),
- zoom: expect.any(Number),
- },
- })
- })
- })
-})
diff --git a/libs/feature/map/src/lib/map-container/map-container.component.ts b/libs/feature/map/src/lib/map-container/map-container.component.ts
deleted file mode 100644
index 8b9faf42db..0000000000
--- a/libs/feature/map/src/lib/map-container/map-container.component.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core'
-import { Observable } from 'rxjs'
-import { map } from 'rxjs/operators'
-import { MapFacade } from '../+state/map.facade'
-import { MapContextModel } from '../map-context/map-context.model'
-import { DEFAULT_BASELAYER_CONTEXT } from '../map-context/map-context.service'
-
-@Component({
- selector: 'gn-ui-map-container',
- templateUrl: './map-container.component.html',
- styleUrls: ['./map-container.component.css'],
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class MapContainerComponent {
- context$: Observable = this.mapFacade.layers$.pipe(
- map((layers) => ({
- view: {
- center: [4, 42],
- zoom: 6,
- },
- layers: [DEFAULT_BASELAYER_CONTEXT, ...layers],
- }))
- )
-
- constructor(private mapFacade: MapFacade) {}
-}
diff --git a/libs/feature/map/src/lib/map-context/component/map-context.component.css b/libs/feature/map/src/lib/map-context/component/map-context.component.css
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/libs/feature/map/src/lib/map-context/component/map-context.component.html b/libs/feature/map/src/lib/map-context/component/map-context.component.html
deleted file mode 100644
index 84fd91619e..0000000000
--- a/libs/feature/map/src/lib/map-context/component/map-context.component.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/libs/feature/map/src/lib/map-context/component/map-context.component.spec.ts b/libs/feature/map/src/lib/map-context/component/map-context.component.spec.ts
deleted file mode 100644
index 9d5e7f3270..0000000000
--- a/libs/feature/map/src/lib/map-context/component/map-context.component.spec.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import { NO_ERRORS_SCHEMA } from '@angular/core'
-import { ComponentFixture, TestBed } from '@angular/core/testing'
-import { MapManagerService } from '../../manager/map-manager.service'
-import { mapCtxFixture } from '../map-context.fixtures'
-import { MapContextService } from '../map-context.service'
-
-import { MapContextComponent } from './map-context.component'
-import { mapConfigFixture } from '@geonetwork-ui/util/app-config'
-import { HttpClientModule } from '@angular/common/http'
-import { MapUtilsService } from '../../utils'
-
-class MapContextServiceMock {
- resetMapFromContext = jest.fn()
-}
-
-class MapUtilsServiceMock {
- prioritizePageScroll = jest.fn()
-}
-
-let resizeCallBack
-class OpenLayersMapMock {
- _size = undefined
- once(type, callback) {
- if (type === 'change:size') {
- resizeCallBack = callback
- }
- }
- updateSize() {
- this._size = [100, 100]
- }
- getSize() {
- return this._size
- }
-}
-
-class MapManagerMock {
- map = new OpenLayersMapMock()
-}
-
-describe('MapContextComponent', () => {
- let component: MapContextComponent
- let fixture: ComponentFixture
- let mapContextService
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [MapContextComponent],
- schemas: [NO_ERRORS_SCHEMA],
- imports: [HttpClientModule],
- providers: [
- {
- provide: MapContextService,
- useClass: MapContextServiceMock,
- },
- {
- provide: MapUtilsService,
- useClass: MapUtilsServiceMock,
- },
- {
- provide: MapManagerService,
- useClass: MapManagerMock,
- },
- ],
- }).compileComponents()
- mapContextService = TestBed.inject(MapContextService)
- })
-
- beforeEach(() => {
- fixture = TestBed.createComponent(MapContextComponent)
- component = fixture.componentInstance
- })
-
- it('should create', () => {
- fixture.detectChanges()
- expect(component).toBeTruthy()
- })
-
- describe('with initial value', () => {
- beforeEach(() => {
- component.context = mapCtxFixture()
- component.mapConfig = mapConfigFixture()
- fixture.detectChanges()
- component.ngOnChanges({})
- })
- it('reset the map from context', () => {
- expect(mapContextService.resetMapFromContext).toHaveBeenCalledWith(
- expect.any(OpenLayersMapMock),
- mapCtxFixture(),
- mapConfigFixture()
- )
- })
- })
-
- describe('no initial value', () => {
- beforeEach(() => {
- component.context = null
- fixture.detectChanges()
- component.ngOnChanges({})
- })
- it('does not reset the map', () => {
- expect(mapContextService.resetMapFromContext).not.toHaveBeenCalled()
- })
- })
-
- describe('no initial value, two values afterwards', () => {
- beforeEach(() => {
- component.context = null
- component.mapConfig = mapConfigFixture()
- fixture.detectChanges()
- component.ngOnChanges({})
- component.context = { ...mapCtxFixture() }
- component.ngOnChanges({})
- component.context = { ...mapCtxFixture() }
- component.ngOnChanges({})
- })
- it('reset the map from context twice', () => {
- expect(mapContextService.resetMapFromContext).toHaveBeenCalledWith(
- expect.any(OpenLayersMapMock),
- mapCtxFixture(),
- mapConfigFixture()
- )
- expect(mapContextService.resetMapFromContext).toHaveBeenCalledTimes(2)
- })
- })
- describe('mapContext with extent', () => {
- const MAP_CTX_EXTENT = {
- ...mapCtxFixture(),
- view: {
- extent: [-100, -200, 300, 400],
- },
- }
-
- describe('initial context is provided', () => {
- describe('before change detection and when map has no size', () => {
- beforeEach(() => {
- component.context = MAP_CTX_EXTENT
- })
- it('does not reset the map', () => {
- expect(mapContextService.resetMapFromContext).not.toHaveBeenCalled()
- })
- })
- describe('after change detection and when map has no size', () => {
- beforeEach(() => {
- component.context = MAP_CTX_EXTENT
- component.ngOnChanges({ context: MAP_CTX_EXTENT })
- })
- it('does not reset the map', () => {
- expect(mapContextService.resetMapFromContext).not.toHaveBeenCalled()
- })
- })
- describe('after change detection and when map has a size', () => {
- beforeEach(() => {
- component.context = MAP_CTX_EXTENT
- component.mapConfig = mapConfigFixture()
- component.ngOnChanges({ context: MAP_CTX_EXTENT })
- resizeCallBack()
- })
- it('resets the map with a view computed from extent', () => {
- expect(mapContextService.resetMapFromContext).toHaveBeenCalledWith(
- expect.any(OpenLayersMapMock),
- MAP_CTX_EXTENT,
- mapConfigFixture()
- )
- })
- })
- })
- })
-})
diff --git a/libs/feature/map/src/lib/map-context/component/map-context.component.stories.ts b/libs/feature/map/src/lib/map-context/component/map-context.component.stories.ts
deleted file mode 100644
index 74d5aad9c6..0000000000
--- a/libs/feature/map/src/lib/map-context/component/map-context.component.stories.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { HttpClientModule } from '@angular/common/http'
-import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
-import { UiMapModule } from '@geonetwork-ui/ui/map'
-import {
- applicationConfig,
- componentWrapperDecorator,
- Meta,
- moduleMetadata,
- StoryObj,
-} from '@storybook/angular'
-import {
- mapCtxLayerGeojsonFixture,
- mapCtxLayerWmsFixture,
- mapCtxLayerXyzFixture,
-} from '../map-context.fixtures'
-import { MapContextComponent } from './map-context.component'
-import { importProvidersFrom } from '@angular/core'
-
-export default {
- title: 'Map/MapContext',
- component: MapContextComponent,
- decorators: [
- moduleMetadata({
- imports: [UiMapModule],
- }),
- applicationConfig({
- providers: [
- importProvidersFrom(BrowserAnimationsModule),
- importProvidersFrom(HttpClientModule),
- ],
- }),
- componentWrapperDecorator(
- (story) => `${story}
`
- ),
- ],
-} as Meta
-
-type Story = StoryObj
-export const WMS: Story = {
- args: {
- context: {
- layers: [mapCtxLayerXyzFixture(), mapCtxLayerWmsFixture()],
- view: {
- center: [7.75, 48.6],
- zoom: 4,
- },
- },
- },
-}
-
-export const GEOJSON: Story = {
- args: {
- context: {
- layers: [mapCtxLayerXyzFixture(), mapCtxLayerGeojsonFixture()],
- view: {
- center: [7.75, 48.6],
- zoom: 4,
- },
- },
- },
-}
diff --git a/libs/feature/map/src/lib/map-context/component/map-context.component.ts b/libs/feature/map/src/lib/map-context/component/map-context.component.ts
deleted file mode 100644
index f96eafdd19..0000000000
--- a/libs/feature/map/src/lib/map-context/component/map-context.component.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import {
- ChangeDetectionStrategy,
- Component,
- EventEmitter,
- Input,
- OnChanges,
- Output,
-} from '@angular/core'
-import { MapUtilsService } from '../../utils/map-utils.service'
-import Feature from 'ol/Feature'
-import { Geometry } from 'ol/geom'
-
-import Map from 'ol/Map'
-import { FeatureInfoService } from '../../feature-info/feature-info.service'
-import { MapManagerService } from '../../manager/map-manager.service'
-import { MapContextModel } from '../map-context.model'
-import { MapContextService } from '../map-context.service'
-import { MapConfig } from '@geonetwork-ui/util/app-config'
-
-@Component({
- selector: 'gn-ui-map-context',
- templateUrl: './map-context.component.html',
- styleUrls: ['./map-context.component.css'],
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class MapContextComponent implements OnChanges {
- @Input() context: MapContextModel
- @Input() mapConfig: MapConfig
- @Output() featureClicked = new EventEmitter[]>()
-
- map: Map
-
- constructor(
- private service: MapContextService,
- private featureInfo: FeatureInfoService,
- private manager: MapManagerService,
- private utils: MapUtilsService
- ) {
- this.map = manager.map
- }
-
- ngOnChanges() {
- if (this.context?.view) {
- if (this.context.view.extent && !this.map.getSize()) {
- this.map.once('change:size', () => {
- this.service.resetMapFromContext(
- this.map,
- this.context,
- this.mapConfig
- )
- })
- } else {
- this.service.resetMapFromContext(this.map, this.context, this.mapConfig)
- }
- }
- }
-}
diff --git a/libs/feature/map/src/lib/map-context/map-context.fixtures.ts b/libs/feature/map/src/lib/map-context/map-context.fixtures.ts
deleted file mode 100644
index e4e46666e0..0000000000
--- a/libs/feature/map/src/lib/map-context/map-context.fixtures.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { polygonFeatureCollectionFixture } from '@geonetwork-ui/common/fixtures'
-import { Extent } from 'ol/extent'
-import {
- MapContextLayerGeojsonModel,
- MapContextLayerModel,
- MapContextLayerTypeEnum,
- MapContextModel,
- MapContextViewModel,
-} from '../map-context/map-context.model'
-
-export const mapCtxLayerXyzFixture = (): MapContextLayerModel => ({
- type: MapContextLayerTypeEnum.XYZ,
- url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
-})
-
-export const mapCtxLayerWmsFixture = (): MapContextLayerModel => ({
- type: MapContextLayerTypeEnum.WMS,
- url: 'https://www.geograndest.fr/geoserver/region-grand-est/ows?REQUEST=GetCapabilities&SERVICE=WMS',
- name: 'commune_actuelle_3857',
-})
-
-export const mapCtxLayerWfsFixture = (): MapContextLayerModel => ({
- type: MapContextLayerTypeEnum.WFS,
- url: 'https://www.geograndest.fr/geoserver/region-grand-est/ows?REQUEST=GetCapabilities&SERVICE=WFS&VERSION=1.1.0',
- name: 'ms:commune_actuelle_3857',
-})
-
-export const mapCtxLayerGeojsonFixture = (): MapContextLayerGeojsonModel => ({
- type: MapContextLayerTypeEnum.GEOJSON,
- data: polygonFeatureCollectionFixture(),
-})
-
-export const mapCtxLayerGeojsonRemoteFixture =
- (): MapContextLayerGeojsonModel => ({
- type: MapContextLayerTypeEnum.GEOJSON,
- url: 'https://my.host.com/data/regions.json',
- })
-
-export const mapCtxViewFixture = (): MapContextViewModel => ({
- center: [7.75, 48.6],
- zoom: 9,
-})
-
-export const mapCtxFixture = (): MapContextModel => ({
- layers: [
- mapCtxLayerXyzFixture(),
- mapCtxLayerWmsFixture(),
- mapCtxLayerGeojsonFixture(),
- ],
- view: mapCtxViewFixture(),
-})
-
-export const mapCtxExtentFixture = (): Extent => [
- 171083.69713494915, 6246047.945419401, 476970.39956295764, 6631079.362882684,
-]
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
deleted file mode 100644
index 0b138243c8..0000000000
--- a/libs/feature/map/src/lib/map-context/map-context.model.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import type { FeatureCollection } from 'geojson'
-import { Coordinate } from 'ol/coordinate'
-import type { Extent } from 'ol/extent'
-
-export enum MapContextLayerTypeEnum {
- XYZ = 'xyz',
- WMS = 'wms',
- WMTS = 'wmts',
- WFS = 'wfs',
- GEOJSON = 'geojson',
- OGCAPI = 'ogcapi',
-}
-
-export interface MapContextModel {
- layers: MapContextLayerModel[]
- view?: MapContextViewModel
-}
-
-export interface MapContextLayerWmsModel {
- type: 'wms'
- url: string
- name: string
- attributions?: string
-}
-
-export interface MapContextLayerWmtsModel {
- type: 'wmts'
- url: string
- name: string
- attributions?: string
-}
-
-interface MapContextLayerWfsModel {
- type: 'wfs'
- url: string
- name: string
- attributions?: string
-}
-
-export interface MapContextLayerOgcapiModel {
- type: 'ogcapi'
- url: string
- name: string
- layerType: 'feature' | 'vectorTiles' | 'mapTiles' | 'record'
- attributions?: string
-}
-
-interface LayerXyzModel {
- type: 'xyz'
- name?: string
- attributions?: string
-}
-interface LayerXyzModelWithUrl extends LayerXyzModel {
- url: string
- urls?: never
-}
-interface LayerXyzModelWithUrls extends LayerXyzModel {
- urls: string[]
- url?: never
-}
-export type MapContextLayerXyzModel =
- | LayerXyzModelWithUrl
- | LayerXyzModelWithUrls
-
-interface LayerGeojson {
- type: 'geojson'
- attributions?: string
-}
-interface LayerGeojsonWithUrl extends LayerGeojson {
- url: string
- data?: never
-}
-interface LayerGeojsonWithData extends LayerGeojson {
- data: FeatureCollection | string
- url?: never
-}
-export type MapContextLayerGeojsonModel =
- | LayerGeojsonWithUrl
- | LayerGeojsonWithData
-
-export type MapContextLayerModel =
- | MapContextLayerWmsModel
- | MapContextLayerWmtsModel
- | MapContextLayerWfsModel
- | MapContextLayerXyzModel
- | MapContextLayerGeojsonModel
- | MapContextLayerOgcapiModel
-
-export interface MapContextViewModel {
- center?: Coordinate // expressed in long/lat (EPSG:4326)
- zoom?: number
- extent?: Extent // expressed in long/lat (EPSG:4326)
- maxZoom?: number
- maxExtent?: Extent // expressed in long/lat (EPSG:4326)
-}
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
deleted file mode 100644
index 2826f42aaf..0000000000
--- a/libs/feature/map/src/lib/map-context/map-context.service.spec.ts
+++ /dev/null
@@ -1,525 +0,0 @@
-import { HttpClientTestingModule } from '@angular/common/http/testing'
-import { TestBed } from '@angular/core/testing'
-import { MapConfig, mapConfigFixture } from '@geonetwork-ui/util/app-config'
-import { FeatureCollection } from 'geojson'
-import { Geometry } from 'ol/geom'
-import TileLayer from 'ol/layer/Tile'
-import VectorLayer from 'ol/layer/Vector'
-import Map from 'ol/Map'
-import TileWMS from 'ol/source/TileWMS'
-import VectorSource from 'ol/source/Vector'
-import XYZ from 'ol/source/XYZ'
-import { Style } from 'ol/style'
-import View from 'ol/View'
-import GeoJSON from 'ol/format/GeoJSON'
-import {
- defaultMapStyleFixture,
- defaultMapStyleHlFixture,
-} from '../style/map-style.fixtures'
-import { MapStyleService } from '../style/map-style.service'
-import {
- mapCtxExtentFixture,
- mapCtxFixture,
- mapCtxLayerGeojsonFixture,
- mapCtxLayerGeojsonRemoteFixture,
- mapCtxLayerWfsFixture,
- mapCtxLayerWmsFixture,
- mapCtxLayerXyzFixture,
-} from './map-context.fixtures'
-
-import {
- DEFAULT_BASELAYER_CONTEXT,
- DEFAULT_VIEW,
- 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()),
- styles: {
- default: defaultMapStyleFixture(),
- defaultHL: defaultMapStyleHlFixture(),
- },
-}
-
-jest.mock('@camptocamp/ogc-client', () => ({
- WmtsEndpoint: class {
- constructor(private url) {}
- isReady() {
- return Promise.resolve({
- getLayerByName: (name) => {
- if (this.url.indexOf('error') > -1) {
- throw new Error('Something went wrong')
- }
- return {
- name,
- latLonBoundingBox: [1.33, 48.81, 4.3, 51.1],
- }
- },
- })
- }
- },
- WfsEndpoint: class {
- constructor(private url) {}
- isReady() {
- return Promise.resolve({
- getLayerByName: (name) => {
- if (this.url.indexOf('error') > -1) {
- throw new Error('Something went wrong')
- }
- return {
- name,
- latLonBoundingBox: [1.33, 48.81, 4.3, 51.1],
- }
- },
- getSingleFeatureTypeName: () => {
- return 'ms:commune_actuelle_3857'
- },
- getFeatureUrl: () => {
- return 'https://www.geograndest.fr/geoserver/region-grand-est/ows?service=WFS&version=1.1.0&request=GetFeature&outputFormat=application%2Fjson&typename=ms%3Acommune_actuelle_3857&srsname=EPSG%3A3857&bbox=10%2C20%2C30%2C40%2CEPSG%3A3857&maxFeatures=10000'
- },
- })
- }
- },
-}))
-
-describe('MapContextService', () => {
- let service: MapContextService
-
- beforeEach(() => {
- TestBed.configureTestingModule({
- imports: [HttpClientTestingModule],
- providers: [
- {
- provide: MapStyleService,
- useValue: mapStyleServiceMock,
- },
- ],
- })
- service = TestBed.inject(MapContextService)
- })
-
- it('should be created', () => {
- expect(service).toBeTruthy()
- })
-
- describe('#createLayer', () => {
- let layerModel, layer
-
- describe('XYZ', () => {
- beforeEach(() => {
- layerModel = mapCtxLayerXyzFixture()
- layer = service.createLayer(layerModel)
- })
- it('create a tile layer', () => {
- expect(layer).toBeTruthy()
- expect(layer).toBeInstanceOf(TileLayer)
- })
- it('create a XYZ source', () => {
- const source = layer.getSource()
- expect(source).toBeInstanceOf(XYZ)
- })
- it('set correct urls', () => {
- const source = layer.getSource()
- const urls = source.getUrls()
- expect(urls.length).toBe(3)
- expect(urls[0]).toEqual(
- 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'
- )
- })
- })
-
- describe('WMS', () => {
- describe('when mapConfig.DO_NOT_TILE_WMS === false', () => {
- beforeEach(() => {
- const mapConfig: MapConfig = {
- ...mapConfigFixture(),
- DO_NOT_TILE_WMS: false,
- }
- ;(layerModel = mapCtxLayerWmsFixture()),
- (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'
- )
- })
- })
-
- describe('when mapConfig.DO_NOT_TILE_WMS === true', () => {
- beforeEach(() => {
- const mapConfig: MapConfig = {
- ...mapConfigFixture(),
- DO_NOT_TILE_WMS: true,
- }
- ;(layerModel = mapCtxLayerWmsFixture()),
- (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)
- })
- })
- })
-
- describe('WFS', () => {
- beforeEach(() => {
- ;(layerModel = mapCtxLayerWfsFixture()),
- (layer = service.createLayer(layerModel))
- })
- it('create a vector layer', () => {
- expect(layer).toBeTruthy()
- expect(layer).toBeInstanceOf(VectorLayer)
- })
- it('create a Vector source', () => {
- const source = layer.getSource()
- expect(source).toBeInstanceOf(VectorSource)
- })
- it('set correct url load function', () => {
- const source = layer.getSource()
- const urlLoader = source.getUrl()
- expect(urlLoader([10, 20, 30, 40])).toBe(
- 'https://www.geograndest.fr/geoserver/region-grand-est/ows?service=WFS&version=1.1.0&request=GetFeature&outputFormat=application%2Fjson&typename=ms%3Acommune_actuelle_3857&srsname=EPSG%3A3857&bbox=10%2C20%2C30%2C40%2CEPSG%3A3857&maxFeatures=10000'
- )
- })
- })
-
- describe('GEOJSON', () => {
- describe('with inline data', () => {
- beforeEach(() => {
- layerModel = mapCtxLayerGeojsonFixture()
- layer = service.createLayer(layerModel)
- })
- it('create a VectorLayer', () => {
- expect(layer).toBeTruthy()
- expect(layer).toBeInstanceOf(VectorLayer)
- })
- it('create a VectorSource source', () => {
- const source = layer.getSource()
- expect(source).toBeInstanceOf(VectorSource)
- })
- it('add features', () => {
- const source = layer.getSource()
- const features = source.getFeatures()
- expect(features.length).toBe(layerModel.data.features.length)
- })
- })
- describe('with inline data as string', () => {
- beforeEach(() => {
- layerModel = { ...mapCtxLayerGeojsonFixture() }
- layerModel.data = JSON.stringify(layerModel.data)
- layer = service.createLayer(layerModel)
- })
- it('create a VectorLayer', () => {
- expect(layer).toBeTruthy()
- expect(layer).toBeInstanceOf(VectorLayer)
- })
- it('create a VectorSource source', () => {
- const source = layer.getSource()
- expect(source).toBeInstanceOf(VectorSource)
- })
- it('add features', () => {
- const source = layer.getSource()
- const features = source.getFeatures()
- expect(features.length).toBe(
- (mapCtxLayerGeojsonFixture().data as FeatureCollection).features
- .length
- )
- })
- })
- describe('with invalid inline data as string', () => {
- beforeEach(() => {
- const spy = jest.spyOn(global.console, 'warn')
- spy.mockClear()
- layerModel = { ...mapCtxLayerGeojsonFixture(), data: 'blargz' }
- layer = service.createLayer(layerModel)
- })
- it('create a VectorLayer', () => {
- expect(layer).toBeTruthy()
- expect(layer).toBeInstanceOf(VectorLayer)
- })
- it('outputs error in the console', () => {
- expect(global.console.warn).toHaveBeenCalled()
- })
- it('create an empty VectorSource source', () => {
- const source = layer.getSource()
- expect(source).toBeInstanceOf(VectorSource)
- expect(source.getFeatures().length).toBe(0)
- })
- })
- describe('with remote file url', () => {
- beforeEach(() => {
- layerModel = mapCtxLayerGeojsonRemoteFixture()
- layer = service.createLayer(layerModel)
- })
- it('create a VectorLayer', () => {
- expect(layer).toBeTruthy()
- expect(layer).toBeInstanceOf(VectorLayer)
- })
- it('create a VectorSource source', () => {
- const source = layer.getSource()
- expect(source).toBeInstanceOf(VectorSource)
- })
- it('sets the format as GeoJSON', () => {
- const source = layer.getSource()
- expect(source.getFormat()).toBeInstanceOf(GeoJSON)
- })
- it('set the url to point to the file', () => {
- const source = layer.getSource()
- expect(source.getUrl()).toBe(layerModel.url)
- })
- })
- })
- })
-
- describe('#createView', () => {
- describe('from center and zoom', () => {
- let view
- const contextModel = mapCtxFixture()
- beforeEach(() => {
- view = service.createView(contextModel.view)
- })
- it('create a view', () => {
- expect(view).toBeTruthy()
- expect(view).toBeInstanceOf(View)
- })
- it('set center', () => {
- const center = view.getCenter()
- expect(center).toEqual([862726.0536478702, 6207260.308175252])
- })
- it('set zoom', () => {
- const zoom = view.getZoom()
- expect(zoom).toEqual(contextModel.view.zoom)
- })
- })
- describe('from extent', () => {
- let view
- const contextModel = mapCtxFixture()
- contextModel.view.extent = mapCtxExtentFixture()
- const map = new Map({})
- map.setSize([100, 100])
- beforeEach(() => {
- view = service.createView(contextModel.view, map)
- })
- it('create a view', () => {
- expect(view).toBeTruthy()
- expect(view).toBeInstanceOf(View)
- })
- it('set center', () => {
- const center = view.getCenter()
- expect(center).toEqual([324027.04834895337, 6438563.654151043])
- })
- it('set zoom', () => {
- const zoom = view.getZoom()
- expect(zoom).toEqual(5)
- })
- })
- })
- describe('#resetMapFromContext', () => {
- describe('without config', () => {
- const map = new Map({})
- const mapContext = mapCtxFixture()
- beforeEach(() => {
- service.resetMapFromContext(map, mapContext)
- })
- it('create a map', () => {
- expect(map).toBeTruthy()
- expect(map).toBeInstanceOf(Map)
- })
- it('add layers', () => {
- const layers = map.getLayers().getArray()
- expect(layers.length).toEqual(4)
- })
- it('set view', () => {
- const view = map.getView()
- expect(view).toBeTruthy()
- expect(view).toBeInstanceOf(View)
- })
- it('set first layer as baselayer', () => {
- const baselayerUrls = (map.getLayers().item(0) as TileLayer)
- .getSource()
- .getUrls()
- expect(baselayerUrls).toEqual(DEFAULT_BASELAYER_CONTEXT.urls)
- })
- })
- describe('with config', () => {
- const map = new Map({})
- const mapContext = mapCtxFixture()
- const mapConfig = mapConfigFixture()
- beforeEach(() => {
- mapConfig.DO_NOT_USE_DEFAULT_BASEMAP = true
- service.resetMapFromContext(map, mapContext, mapConfig)
- })
- it('set maxZoom', () => {
- const maxZoom = map.getView().getMaxZoom()
- expect(maxZoom).toBe(10)
- })
- it('set first layer as baselayer', () => {
- const baselayerUrls = (map.getLayers().item(0) as TileLayer)
- .getSource()
- .getUrls()
- expect(baselayerUrls).toEqual(['https://some-basemap-server'])
- })
- it('add one WMS layer from config on top of baselayer', () => {
- const layerWMSUrl = (map.getLayers().item(1) as TileLayer)
- .getSource()
- .getUrls()[0]
- expect(layerWMSUrl).toEqual('https://some-wms-server')
- })
- it('add one WFS layer from config on top of baselayer', () => {
- const layerWFSSource = (
- map.getLayers().item(2) as VectorLayer<
- VectorSource>
- >
- ).getSource()
- expect(layerWFSSource).toBeInstanceOf(VectorSource)
- })
- })
- describe('with config, but keeping default basemap', () => {
- const map = new Map({})
- const mapContext = mapCtxFixture()
- const mapConfig = mapConfigFixture()
- beforeEach(() => {
- mapConfig.DO_NOT_USE_DEFAULT_BASEMAP = false
- service.resetMapFromContext(map, mapContext, mapConfig)
- })
- it('set first layer as baselayer', () => {
- const baselayerUrls = (map.getLayers().item(0) as TileLayer)
- .getSource()
- .getUrls()
- expect(baselayerUrls).toEqual(DEFAULT_BASELAYER_CONTEXT.urls)
- })
- })
- describe('uses default fallback view (without config)', () => {
- let view
- const map = new Map({})
- const mapContext = {
- extent: null,
- center: null,
- zoom: null,
- layers: [
- mapCtxLayerXyzFixture(),
- mapCtxLayerWmsFixture(),
- mapCtxLayerGeojsonFixture(),
- ],
- }
- beforeEach(() => {
- service.resetMapFromContext(map, mapContext)
- })
- it('create a map', () => {
- expect(map).toBeTruthy()
- expect(map).toBeInstanceOf(Map)
- })
- it('add layers', () => {
- const layers = map.getLayers().getArray()
- expect(layers.length).toEqual(4)
- })
- it('set view', () => {
- view = map.getView()
- expect(view).toBeTruthy()
- expect(view).toBeInstanceOf(View)
- })
- it('set center', () => {
- const center = view.getCenter()
- expect(center).toEqual([0, 1689200.1396078935])
- })
- it('set zoom', () => {
- const zoom = view.getZoom()
- expect(zoom).toEqual(DEFAULT_VIEW.zoom)
- })
- })
- describe('uses fallback view from config', () => {
- let view
- const map = new Map({})
- const mapConfig = mapConfigFixture()
- const mapContext = {
- extent: null,
- center: null,
- zoom: null,
- layers: [],
- }
- beforeEach(() => {
- service.resetMapFromContext(map, mapContext, mapConfig)
- })
- it('create a map', () => {
- expect(map).toBeTruthy()
- expect(map).toBeInstanceOf(Map)
- })
- it('add layers', () => {
- const layers = map.getLayers().getArray()
- expect(layers.length).toEqual(4)
- })
- it('set view', () => {
- view = map.getView()
- expect(view).toBeTruthy()
- expect(view).toBeInstanceOf(View)
- })
- it('set center', () => {
- const center = view.getCenter()
- expect(center).toEqual([271504.324469, 5979210.100579999])
- })
- it('set zoom', () => {
- const zoom = view.getZoom()
- expect(zoom).toEqual(3)
- })
- })
- })
- describe('#mergeMapConfigWithContext', () => {
- const mapContext = mapCtxFixture()
- const mapConfig = mapConfigFixture()
- beforeEach(() => {
- mapConfig.DO_NOT_USE_DEFAULT_BASEMAP = true
- })
- it('merges mapconfig into existing mapcontext', () => {
- const mergedMapContext = service.mergeMapConfigWithContext(
- mapContext,
- mapConfig
- )
- const layersContext = mapConfigFixture().MAP_LAYERS.map(
- service.getContextLayerFromConfig
- )
-
- expect(mergedMapContext).toEqual({
- ...mapCtxFixture(),
- view: {
- ...mapCtxFixture().view,
- maxZoom: mapConfigFixture().MAX_ZOOM,
- maxExtent: mapConfigFixture().MAX_EXTENT,
- },
- layers: [
- layersContext[0],
- layersContext[1],
- layersContext[2],
- ...mapCtxFixture().layers,
- ],
- })
- })
- })
-})
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
deleted file mode 100644
index 3119c01656..0000000000
--- a/libs/feature/map/src/lib/map-context/map-context.service.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-import { Injectable } from '@angular/core'
-import { MapStyleService } from '../style/map-style.service'
-import {
- MapContextLayerModel,
- MapContextLayerTypeEnum,
- MapContextLayerXyzModel,
- MapContextModel,
- MapContextViewModel,
-} from './map-context.model'
-import Map from 'ol/Map'
-import View from 'ol/View'
-import Layer from 'ol/layer/Base'
-import VectorLayer from 'ol/layer/Vector'
-import TileWMS from 'ol/source/TileWMS'
-import TileLayer from 'ol/layer/Tile'
-import XYZ from 'ol/source/XYZ'
-import VectorSource from 'ol/source/Vector'
-import GeoJSON from 'ol/format/GeoJSON'
-import { MapUtilsService } from '../utils/map-utils.service'
-import { bbox as bboxStrategy } from 'ol/loadingstrategy'
-import { LayerConfig, MapConfig } from '@geonetwork-ui/util/app-config'
-import { FeatureCollection } from 'geojson'
-import { fromLonLat } from 'ol/proj'
-import WMTS from 'ol/source/WMTS'
-import { Geometry } from 'ol/geom'
-import Feature from 'ol/Feature'
-import { WfsEndpoint, WmtsEndpoint } from '@camptocamp/ogc-client'
-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,
- urls: [
- `https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png`,
- `https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png`,
- `https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png`,
- ],
- attributions: `© OpenStreetMap contributors, © Carto`,
-}
-
-export const DEFAULT_VIEW: MapContextViewModel = {
- center: [0, 15],
- zoom: 2,
-}
-
-export const WFS_MAX_FEATURES = 10000
-
-@Injectable({
- providedIn: 'root',
-})
-export class MapContextService {
- constructor(
- private mapUtils: MapUtilsService,
- private styleService: MapStyleService
- ) {}
-
- resetMapFromContext(
- map: Map,
- mapContext: MapContextModel,
- mapConfig?: MapConfig
- ): Map {
- if (mapConfig) {
- mapContext = this.mergeMapConfigWithContext(mapContext, mapConfig)
- } else {
- mapContext.layers = this.addDefaultBaselayerContext(mapContext.layers)
- }
- if (
- !mapContext.view?.extent &&
- (!mapContext.view?.center || !mapContext.view?.zoom)
- ) {
- mapContext.view = this.getFallbackView(mapConfig)
- }
- map.setView(this.createView(mapContext.view, map))
- map.getLayers().clear()
- mapContext.layers.forEach((layer) =>
- map.addLayer(this.createLayer(layer, mapConfig))
- )
- return map
- }
-
- createLayer(layerModel: MapContextLayerModel, mapConfig?: MapConfig): Layer {
- const { type } = layerModel
- const style = this.styleService.styles.default
- switch (type) {
- case MapContextLayerTypeEnum.OGCAPI:
- if (layerModel.layerType === 'vectorTiles') {
- return new VectorTileLayer({
- source: new OGCVectorTile({
- url: layerModel.url,
- format: new MVT(),
- attributions: layerModel.attributions,
- }),
- })
- } else if (layerModel.layerType === 'mapTiles') {
- return new TileLayer({
- source: new OGCMapTile({
- url: layerModel.url,
- attributions: layerModel.attributions,
- }),
- })
- } else {
- return new VectorLayer({
- source: new VectorSource({
- format: new GeoJSON(),
- url: layerModel.url,
- attributions: layerModel.attributions,
- }),
- style,
- })
- }
- case MapContextLayerTypeEnum.XYZ:
- return new TileLayer({
- source: new XYZ({
- url: 'url' in layerModel ? layerModel.url : undefined,
- urls: 'urls' in layerModel ? layerModel.urls : undefined,
- attributions: layerModel.attributions,
- }),
- })
- case MapContextLayerTypeEnum.WMS:
- if (mapConfig?.DO_NOT_TILE_WMS) {
- return new ImageLayer({
- source: new ImageWMS({
- url: layerModel.url,
- params: { LAYERS: layerModel.name },
- attributions: layerModel.attributions,
- }),
- })
- } else {
- return new TileLayer({
- source: new TileWMS({
- url: layerModel.url,
- params: { LAYERS: layerModel.name, TILED: true },
- attributions: layerModel.attributions,
- }),
- })
- }
-
- case MapContextLayerTypeEnum.WMTS: {
- // TODO: isolate this in utils service
- const olLayer = new TileLayer({})
- const endpoint = new WmtsEndpoint(layerModel.url)
- endpoint.isReady().then(async (endpoint) => {
- const layerName = endpoint.getSingleLayerName() ?? layerModel.name
- const layer = endpoint.getLayerByName(layerName)
- const matrixSet = layer.matrixSets[0]
- const tileGrid = await endpoint.getOpenLayersTileGrid(layer.name)
- const resourceUrl = layer.resourceLinks[0]
- const dimensions = endpoint.getDefaultDimensions(layer.name)
- olLayer.setSource(
- new WMTS({
- layer: layer.name,
- style: layer.defaultStyle,
- matrixSet: matrixSet.identifier,
- format: resourceUrl.format,
- url: resourceUrl.url,
- requestEncoding: resourceUrl.encoding,
- tileGrid,
- projection: matrixSet.crs,
- dimensions,
- attributions: layerModel.attributions,
- })
- )
- })
- return olLayer
- }
- case MapContextLayerTypeEnum.WFS: {
- const olLayer = new VectorLayer({
- style,
- })
- new WfsEndpoint(layerModel.url).isReady().then((endpoint) => {
- const featureType =
- endpoint.getSingleFeatureTypeName() ?? layerModel.name
- olLayer.setSource(
- new VectorSource({
- format: new GeoJSON(),
- url: function (extent: [number, number, number, number]) {
- return endpoint.getFeatureUrl(featureType, {
- maxFeatures: WFS_MAX_FEATURES,
- asJson: true,
- outputCrs: 'EPSG:3857',
- extent,
- extentCrs: 'EPSG:3857',
- })
- },
- strategy: bboxStrategy,
- attributions: layerModel.attributions,
- })
- )
- })
- return olLayer
- }
- case MapContextLayerTypeEnum.GEOJSON: {
- if ('url' in layerModel) {
- return new VectorLayer({
- source: new VectorSource({
- format: new GeoJSON(),
- url: layerModel.url,
- }),
- style,
- })
- } else {
- let geojson = layerModel.data
- if (typeof geojson === 'string') {
- try {
- geojson = JSON.parse(geojson)
- } catch (e) {
- console.warn('A layer could not be created', layerModel, e)
- geojson = { type: 'FeatureCollection', features: [] }
- }
- }
- const features = this.mapUtils.readFeatureCollection(
- geojson as FeatureCollection
- ) as Feature[]
- return new VectorLayer({
- source: new VectorSource({
- features,
- }),
- style,
- })
- }
- }
- default:
- throw new Error(`Unrecognized layer type: ${layerModel.type}`)
- }
- }
-
- createView(viewModel: MapContextViewModel, map?: Map): View {
- const { center: centerInViewProj, zoom, maxZoom, maxExtent } = viewModel
- const center = centerInViewProj
- ? fromLonLat(centerInViewProj, 'EPSG:3857')
- : [0, 0]
- const view = new View({
- center,
- zoom,
- maxZoom,
- extent: maxExtent,
- multiWorld: false,
- constrainResolution: true,
- })
- if (viewModel.extent && map) {
- view.fit(viewModel.extent, {
- size: map.getSize(),
- })
- }
- return view
- }
-
- addDefaultBaselayerContext(
- layers: MapContextLayerModel[]
- ): MapContextLayerModel[] {
- return layers.includes(DEFAULT_BASELAYER_CONTEXT)
- ? layers
- : [DEFAULT_BASELAYER_CONTEXT, ...layers]
- }
-
- mergeMapConfigWithContext(
- mapContext: MapContextModel,
- mapConfig: MapConfig
- ): MapContextModel {
- return {
- ...mapContext,
- view: {
- ...mapContext.view,
- ...(mapConfig.MAX_ZOOM && {
- maxZoom: mapConfig.MAX_ZOOM,
- }),
- ...(mapConfig.MAX_EXTENT && {
- maxExtent: mapConfig.MAX_EXTENT,
- }),
- },
- layers: [
- ...(mapConfig.DO_NOT_USE_DEFAULT_BASEMAP
- ? []
- : [DEFAULT_BASELAYER_CONTEXT]),
- ...mapConfig.MAP_LAYERS.map(this.getContextLayerFromConfig),
- ...mapContext.layers,
- ],
- }
- }
-
- getFallbackView(mapConfig: MapConfig): MapContextViewModel {
- return mapConfig?.MAX_EXTENT
- ? { extent: mapConfig.MAX_EXTENT }
- : DEFAULT_VIEW
- }
-
- getContextLayerFromConfig(config: LayerConfig): MapContextLayerModel {
- switch (config.TYPE) {
- case 'wms':
- return {
- type: 'wms',
- url: config.URL,
- name: config.NAME,
- }
- case 'wfs':
- return {
- type: 'wfs',
- url: config.URL,
- name: config.NAME,
- }
- case 'xyz':
- return {
- type: config.TYPE,
- url: config.URL,
- name: config.NAME,
- }
- case 'geojson':
- return {
- type: config.TYPE,
- ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
- }
- }
- }
-}