Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(DH): Center bbox extent with different coordinate reference system #698

Merged
merged 9 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,21 @@ import {
ViewChild,
} from '@angular/core'
import { ThemeService } from '@geonetwork-ui/util/shared'
import type { Feature } from 'geojson'
import type { Feature as FeatureType } from 'geojson'
import { asArray, asString } from 'ol/color'
import { isEmpty } from 'ol/extent'
import GeoJSON from 'ol/format/GeoJSON'
import { Geometry } from 'ol/geom'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import Map from 'ol/Map'
import Feature from 'ol/Feature'
import OSM from 'ol/source/OSM'
import VectorSource from 'ol/source/Vector'
import { Fill, RegularShape, Stroke, Style } from 'ol/style'
import { StyleLike } from 'ol/style/Style'
import View from 'ol/View'
import { FeatureLike } from 'ol/Feature'

const DEFAULT_PRIMARY_COLOR = '#9a9a9a'
const PADDING = 50
Expand All @@ -41,7 +43,7 @@ export class DataImportValidationMapPanelComponent
@Input() headerLabel = ''
@Input() footerLabel = ''
@Input() footerList = []
@Input() geoJson?: Feature
@Input() geoJson?: FeatureType
@Input() footerValue = ''
@Input() padding = []

Expand All @@ -50,8 +52,8 @@ export class DataImportValidationMapPanelComponent
selectedValue: any

private map: Map
private source: VectorSource<Geometry>
private vectorLayer: VectorLayer<VectorSource<Geometry>>
private source: VectorSource<FeatureLike>
private vectorLayer: VectorLayer<VectorSource<Feature<Geometry>>>
private format: any = new GeoJSON({})

ngOnInit(): void {
Expand Down Expand Up @@ -158,8 +160,8 @@ export class DataImportValidationMapPanelComponent
]
}

private buildVectorLayer(): VectorLayer<VectorSource<Geometry>> {
this.source = new VectorSource({})
private buildVectorLayer(): VectorLayer<VectorSource<Feature<Geometry>>> {
this.source = new VectorSource<Feature<Geometry>>({})
if (this.geoJson) {
this.source.addFeatures(
this.format.readFeatures(this.geoJson, {
Expand All @@ -168,7 +170,7 @@ export class DataImportValidationMapPanelComponent
)
}
return new VectorLayer({
source: this.source,
source: this.source as VectorSource<Feature<Geometry>>,
style: this.getDefaultStyle(),
})
}
Expand Down
11 changes: 7 additions & 4 deletions apps/datahub-e2e/src/e2e/datasetDetailPage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,18 @@ describe('dataset pages', () => {
})
})
it('downloads a file on click', () => {
cy.intercept(
'GET',
'https://www.geo2france.fr/geoserver/insee/ows?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=insee%3Arectangles_200m_menage_erbm&OUTPUTFORMAT=csv'
).as('downloadRequest')

cy.get('datahub-record-downloads')
.find('gn-ui-download-item')
.first()
.click()
cy.exec('ls cypress/downloads').then((result) => {
const fileList = result.stdout.split('\n')

const isFileDownloaded = fileList[0]
expect(/\S/.test(isFileDownloaded)).to.be.true
cy.wait('@downloadRequest').then((interception) => {
expect(interception.response.statusCode).to.equal(200)
})
})
it('displays the full list after clicking two times on one filter', () => {
Expand Down
2 changes: 1 addition & 1 deletion jest.preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module.exports = {
...nxPreset,
coverageReporters: ['text'],
setupFiles: ['jest-canvas-mock'],
transformIgnorePatterns: ['node_modules/(?!(ol|@mapbox|.*.mjs$))'],
transformIgnorePatterns: ['node_modules/(?!(color-*|ol|@mapbox|.*.mjs$))'],
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
MapManagerService,
} from '@geonetwork-ui/feature/map'
import { FEATURE_COLLECTION_POINT_FIXTURE_4326 } from '@geonetwork-ui/common/fixtures'
import { Map } from 'ol'
import Map from 'ol/Map'
import Feature from 'ol/Feature'
import GeoJSON from 'ol/format/GeoJSON'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
Expand All @@ -21,6 +22,7 @@ import XYZ from 'ol/source/XYZ'
import { Subject } from 'rxjs'

import { GeoTableViewComponent } from './geo-table-view.component'
import { Geometry } from 'ol/geom'

const vectorLayer = new VectorLayer({
source: new VectorSource({
Expand All @@ -31,7 +33,7 @@ const vectorLayer = new VectorLayer({
dataProjection: 'EPSG:4326',
}
),
}),
}) as VectorSource<Feature<Geometry>>,
})

const mapMock = new Map({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export class GeoTableViewComponent implements OnInit, AfterViewInit, OnDestroy {

private map: Map
private view: View
private vectorLayer: VectorLayer<VectorSource<Geometry>>
private vectorSource: VectorSource<Geometry>
private vectorLayer: VectorLayer<VectorSource<Feature<Geometry>>>
private vectorSource: VectorSource<Feature<Geometry>>
private features: Feature<Geometry>[]

tableData: TableItemModel[]
Expand Down Expand Up @@ -76,7 +76,7 @@ export class GeoTableViewComponent implements OnInit, AfterViewInit, OnDestroy {
const map = (this.map = this.manager.map)
this.view = map.getView()
this.vectorLayer = this.manager.map.getLayers().item(1) as VectorLayer<
VectorSource<Geometry>
VectorSource<Feature<Geometry>>
>
this.vectorLayer.setStyle(this.styleFn.bind(this))
this.vectorSource = this.vectorLayer.getSource()
Expand Down
7 changes: 7 additions & 0 deletions libs/feature/dataviz/src/test-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ getTestBed().initTestEnvironment(
platformBrowserDynamicTesting(),
{ teardown: { destroyAfterEach: false } }
)

class ResizeObserverMock {
observe = jest.fn()
unobserve = jest.fn()
}

;(window as any).ResizeObserver = ResizeObserverMock
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
DEFAULT_VIEW,
MapContextService,
} from './map-context.service'
import Feature from 'ol/Feature'

const mapStyleServiceMock = {
createDefaultStyle: jest.fn(() => new Style()),
Expand Down Expand Up @@ -319,7 +320,9 @@ describe('MapContextService', () => {
})
it('add one WFS layer from config on top of baselayer', () => {
const layerWFSSource = (
map.getLayers().item(2) as VectorLayer<VectorSource<Geometry>>
map.getLayers().item(2) as VectorLayer<
VectorSource<Feature<Geometry>>
>
).getSource()
expect(layerWFSSource).toBeInstanceOf(VectorSource)
})
Expand Down
4 changes: 3 additions & 1 deletion libs/feature/map/src/lib/map-context/map-context.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { FeatureCollection } from 'geojson'
import { fromLonLat } from 'ol/proj'
import WMTS from 'ol/source/WMTS'
import { removeSearchParams } from '@geonetwork-ui/util/shared'
import { Geometry } from 'ol/geom'
import Feature from 'ol/Feature'

export const DEFAULT_BASELAYER_CONTEXT: MapContextLayerXyzModel = {
type: MapContextLayerTypeEnum.XYZ,
Expand Down Expand Up @@ -136,7 +138,7 @@ export class MapContextService {
}
const features = this.mapUtils.readFeatureCollection(
geojson as FeatureCollection
)
) as Feature<Geometry>[]
return new VectorLayer({
source: new VectorSource({
features,
Expand Down
34 changes: 27 additions & 7 deletions libs/feature/map/src/lib/utils/map-utils-wms.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TestBed } from '@angular/core/testing'
import { readFirst } from '@nx/angular/testing'

import { MapUtilsWMSService } from './map-utils-wms.service'
import { fromEPSGCode } from 'ol/proj/proj4'

jest.mock('@camptocamp/ogc-client', () => ({
WmsEndpoint: class {
Expand All @@ -22,6 +23,24 @@ jest.mock('@camptocamp/ogc-client', () => ({
},
}))

jest.mock('ol/proj/proj4', () => {
const fromEPSGCodeMock = jest.fn()
const registerMock = jest.fn()
return {
fromEPSGCode: fromEPSGCodeMock,
register: registerMock,
}
})

jest.mock('ol/proj', () => {
const extent = [1, 2, 3, 4]
const transformExtentMock = jest.fn().mockReturnValue(extent)

return {
transformExtent: transformExtentMock,
}
})

describe('MapUtilsWMSService', () => {
let service: MapUtilsWMSService

Expand Down Expand Up @@ -80,8 +99,8 @@ describe('MapUtilsWMSService', () => {
}
})
it('returns CRS:84 bbox', async () => {
const extent = service.getLonLatBBox(wmsLayerFull)
expect(extent).toEqual(['2.3', '50.6', '2.8', '50.9'])
const extent = await service.getLonLatBBox(wmsLayerFull)
expect(extent).toStrictEqual(['2.3', '50.6', '2.8', '50.9'])
})
})
describe('bbox in EPSG:4326', () => {
Expand All @@ -94,8 +113,8 @@ describe('MapUtilsWMSService', () => {
}
})
it('returns EPSG:4326 bbox', async () => {
const extent = service.getLonLatBBox(wmsLayerFull)
expect(extent).toEqual(['1', '2.6', '3.3', '4.2'])
const extent = await service.getLonLatBBox(wmsLayerFull)
expect(extent).toStrictEqual(['1', '2.6', '3.3', '4.2'])
})
})
describe('no lon lat bbox', () => {
Expand All @@ -106,9 +125,10 @@ describe('MapUtilsWMSService', () => {
},
}
})
it('returns EPSG:4326 bbox', async () => {
const extent = service.getLonLatBBox(wmsLayerFull)
expect(extent).toBeUndefined()
it('transforms to EPSG:4326 bbox', async () => {
const extent = await service.getLonLatBBox(wmsLayerFull)
expect(fromEPSGCode).toHaveBeenCalled()
expect(extent).toStrictEqual([1, 2, 3, 4])
})
})
})
Expand Down
24 changes: 21 additions & 3 deletions libs/feature/map/src/lib/utils/map-utils-wms.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import { WmsEndpoint, WmsLayerFull } from '@camptocamp/ogc-client'
import { MapContextLayerWmsModel } from '../map-context/map-context.model'
import { ProxyService } from '@geonetwork-ui/util/shared'
import { from, Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { map, switchMap } from 'rxjs/operators'
import { LONLAT_CRS_CODES } from './projections'
import { fromEPSGCode, register } from 'ol/proj/proj4'
import { Extent } from 'ol/extent'
import proj4 from 'proj4/dist/proj4'
import { transformExtent } from 'ol/proj'

@Injectable({
providedIn: 'root',
Expand All @@ -24,17 +28,31 @@ export class MapUtilsWMSService {

getLayerLonLatBBox(layer: MapContextLayerWmsModel) {
return this.getLayerFull(layer).pipe(
map((wmsLayerFull) => this.getLonLatBBox(wmsLayerFull))
switchMap((wmsLayerFull) => from(this.getLonLatBBox(wmsLayerFull)))
)
}

getLonLatBBox(wmsLayerFull: WmsLayerFull) {
async getLonLatBBox(wmsLayerFull: WmsLayerFull): Promise<Extent> {
const { boundingBoxes } = wmsLayerFull
const lonLatCRS = Object.keys(boundingBoxes)?.find((crs) =>
LONLAT_CRS_CODES.includes(crs)
)
if (lonLatCRS) {
return boundingBoxes[lonLatCRS]
} else {
const availableEPSGCode = Object.keys(boundingBoxes)[0]
register(proj4)
const proj = await fromEPSGCode(availableEPSGCode)
proj4.defs(availableEPSGCode, proj)

const bboxWithFiniteNumbers = [
parseFloat(boundingBoxes[availableEPSGCode][0]),
parseFloat(boundingBoxes[availableEPSGCode][1]),
parseFloat(boundingBoxes[availableEPSGCode][2]),
parseFloat(boundingBoxes[availableEPSGCode][3]),
]
const extent = transformExtent(bboxWithFiniteNumbers, proj, 'EPSG:4326')
return extent
}
}
}
11 changes: 10 additions & 1 deletion libs/feature/map/src/lib/utils/map-utils.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ import {
import { DatasetServiceDistribution } from '@geonetwork-ui/common/domain/model/record'
import MapBrowserEvent from 'ol/MapBrowserEvent'

jest.mock('ol/proj/proj4', () => {
const fromEPSGCodeMock = jest.fn()
const registerMock = jest.fn()
return {
fromEPSGCode: fromEPSGCodeMock,
register: registerMock,
}
})

const wmsUtilsMock = {
getLayerLonLatBBox: jest.fn(() => of([1.33, 48.81, 4.3, 51.1])),
}
Expand Down Expand Up @@ -146,7 +155,7 @@ describe('MapUtilsService', () => {
})
it('returns true', () => {
expect(url).toEqual(
'url?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=layerName&LAYERS=layerName&INFO_FORMAT=application%2Fjson&I=50&J=50&CRS=EPSG%3A3857&STYLES=&WIDTH=101&HEIGHT=101&BBOX=-1697932.4932933417%2C4610319.813853541%2C1332067.5067066583%2C7640319.813853541'
'url?QUERY_LAYERS=layerName&INFO_FORMAT=application%2Fjson&REQUEST=GetFeatureInfo&SERVICE=WMS&VERSION=1.3.0&FORMAT=image%2Fpng&STYLES=&TRANSPARENT=true&LAYERS=layerName&I=50&J=50&WIDTH=101&HEIGHT=101&CRS=EPSG%3A3857&BBOX=-1697932.4932933417%2C4610319.813853541%2C1332067.5067066583%2C7640319.813853541'
)
})
})
Expand Down
4 changes: 2 additions & 2 deletions libs/feature/map/src/lib/utils/map-utils.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import type { FeatureCollection } from 'geojson'
import { extend, Extent, isEmpty } from 'ol/extent'
import OlFeature from 'ol/Feature'
import OlFeature, { FeatureLike } from 'ol/Feature'
import GeoJSON from 'ol/format/GeoJSON'
import { Geometry } from 'ol/geom'
import Layer from 'ol/layer/Layer'
Expand Down Expand Up @@ -50,7 +50,7 @@ export class MapUtilsService {
featureCollection: FeatureCollection,
featureProjection = FEATURE_PROJECTION,
dataProjection = DATA_PROJECTION
): OlFeature<Geometry>[] => {
): FeatureLike[] => {
const olFeatures = new GeoJSON().readFeatures(featureCollection, {
featureProjection,
dataProjection,
Expand Down
7 changes: 7 additions & 0 deletions libs/feature/map/src/test-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ getTestBed().initTestEnvironment(
platformBrowserDynamicTesting(),
{ teardown: { destroyAfterEach: false } }
)

class ResizeObserverMock {
observe = jest.fn()
unobserve = jest.fn()
}

;(window as any).ResizeObserver = ResizeObserverMock
Loading
Loading