geonetwork-ui 2.2.0-dev.bea8410b → 2.2.0-dev.ca028047
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/atomic-operations.mjs +2 -1
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +36 -2
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +2 -1
- package/esm2022/libs/api/repository/src/lib/gn4/index.mjs +3 -1
- package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
- package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +5 -4
- package/esm2022/libs/feature/editor/src/lib/record-form/record-form.component.mjs +5 -3
- package/esm2022/libs/feature/map/src/index.mjs +2 -1
- package/esm2022/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component.mjs +1 -1
- package/esm2022/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.mjs +106 -0
- package/esm2022/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.mjs +64 -0
- package/esm2022/libs/feature/map/src/lib/constant/index.mjs +2 -1
- package/esm2022/libs/feature/map/src/lib/constant/projections.mjs +2 -0
- package/esm2022/libs/feature/map/src/lib/feature-map.module.mjs +23 -3
- package/esm2022/libs/feature/map/src/lib/geocoding/geocoding.component.mjs +93 -0
- package/esm2022/libs/feature/map/src/lib/geocoding.service.mjs +40 -0
- package/esm2022/libs/feature/map/src/lib/layers-panel/layers-panel.component.mjs +5 -3
- package/esm2022/libs/feature/map/src/lib/map-context/map-context.service.mjs +3 -1
- package/esm2022/libs/feature/map/src/lib/utils/index.mjs +1 -3
- package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +60 -29
- package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +29 -20
- package/esm2022/libs/ui/catalog/src/lib/organisation-preview/organisation-preview.component.mjs +1 -1
- package/esm2022/libs/ui/elements/src/index.mjs +3 -1
- package/esm2022/libs/ui/elements/src/lib/downloads-list/downloads-list.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.mjs +27 -0
- package/esm2022/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.mjs +2 -2
- package/esm2022/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/related-record-card/related-record-card.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/thumbnail/thumbnail.component.mjs +7 -3
- package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +10 -3
- package/esm2022/libs/ui/inputs/src/lib/button/button.component.mjs +2 -2
- package/esm2022/libs/ui/inputs/src/lib/editable-label/editable-label.directive.mjs +46 -0
- package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +8 -3
- package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +2 -2
- package/esm2022/libs/ui/search/src/lib/record-preview-card/record-preview-card.component.mjs +1 -1
- package/esm2022/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.mjs +1 -1
- package/esm2022/libs/ui/search/src/lib/record-preview-list/record-preview-list.component.mjs +1 -1
- package/esm2022/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.mjs +1 -1
- package/esm2022/libs/ui/search/src/lib/record-preview-title/record-preview-title.component.mjs +1 -1
- package/esm2022/libs/ui/search/src/lib/record-table/record-table.component.mjs +3 -3
- package/esm2022/libs/util/shared/src/lib/links/link-utils.mjs +29 -13
- package/esm2022/translations/de.json +99 -95
- package/esm2022/translations/en.json +20 -16
- package/esm2022/translations/es.json +4 -0
- package/esm2022/translations/fr.json +4 -0
- package/esm2022/translations/it.json +4 -0
- package/esm2022/translations/nl.json +4 -0
- package/esm2022/translations/pt.json +4 -0
- package/fesm2022/geonetwork-ui.mjs +673 -235
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/atomic-operations.d.ts +1 -0
- package/libs/api/metadata-converter/src/lib/gn4/atomic-operations.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/index.d.ts +2 -0
- package/libs/api/repository/src/lib/gn4/index.d.ts.map +1 -1
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +10 -5
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
- package/libs/feature/dataviz/src/lib/service/data.service.d.ts +15 -2
- package/libs/feature/dataviz/src/lib/service/data.service.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/record-form/record-form.component.d.ts.map +1 -1
- package/libs/feature/map/src/index.d.ts +1 -0
- package/libs/feature/map/src/index.d.ts.map +1 -1
- package/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.d.ts +22 -0
- package/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.d.ts.map +1 -0
- package/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.d.ts +22 -0
- package/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.d.ts.map +1 -0
- package/libs/feature/map/src/lib/constant/index.d.ts +1 -0
- package/libs/feature/map/src/lib/constant/index.d.ts.map +1 -1
- package/libs/feature/map/src/lib/constant/projections.d.ts.map +1 -0
- package/libs/feature/map/src/lib/feature-map.module.d.ts +15 -12
- package/libs/feature/map/src/lib/feature-map.module.d.ts.map +1 -1
- package/libs/feature/map/src/lib/geocoding/geocoding.component.d.ts +25 -0
- package/libs/feature/map/src/lib/geocoding/geocoding.component.d.ts.map +1 -0
- package/libs/feature/map/src/lib/geocoding.service.d.ts +18 -0
- package/libs/feature/map/src/lib/geocoding.service.d.ts.map +1 -0
- package/libs/feature/map/src/lib/map-context/map-context.service.d.ts +1 -0
- package/libs/feature/map/src/lib/map-context/map-context.service.d.ts.map +1 -1
- package/libs/feature/map/src/lib/utils/index.d.ts +0 -2
- package/libs/feature/map/src/lib/utils/index.d.ts.map +1 -1
- package/libs/feature/map/src/lib/utils/map-utils.service.d.ts +13 -11
- package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts +1 -3
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
- package/libs/ui/dataviz/src/lib/chart/chart.component.d.ts +1 -1
- package/libs/ui/elements/src/index.d.ts +2 -0
- package/libs/ui/elements/src/index.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/downloads-list/downloads-list.component.d.ts +1 -1
- package/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.d.ts +10 -0
- package/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.d.ts.map +1 -0
- package/libs/ui/elements/src/lib/thumbnail/thumbnail.component.d.ts +3 -2
- package/libs/ui/elements/src/lib/thumbnail/thumbnail.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts +12 -11
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/editable-label/editable-label.directive.d.ts +13 -0
- package/libs/ui/inputs/src/lib/editable-label/editable-label.directive.d.ts.map +1 -0
- package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +2 -1
- package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts.map +1 -1
- package/libs/util/shared/src/lib/links/link-utils.d.ts +19 -7
- package/libs/util/shared/src/lib/links/link-utils.d.ts.map +1 -1
- package/package.json +4 -1
- package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +3 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +43 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.ts +1 -0
- package/src/libs/api/repository/src/lib/gn4/index.ts +2 -0
- package/src/libs/common/domain/src/lib/index.ts +2 -0
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +12 -7
- package/src/libs/feature/dataviz/src/lib/service/data.service.ts +8 -5
- package/src/libs/feature/editor/src/lib/record-form/record-form.component.ts +2 -1
- package/src/libs/feature/map/src/index.ts +1 -0
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.css +0 -0
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.html +21 -0
- package/src/libs/feature/map/src/lib/add-layer-from-file/add-layer-from-file.component.ts +107 -0
- package/src/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.css +0 -0
- package/src/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.html +37 -0
- package/src/libs/feature/map/src/lib/add-layer-from-wfs/add-layer-from-wfs.component.ts +64 -0
- package/src/libs/feature/map/src/lib/constant/index.ts +1 -0
- package/src/libs/feature/map/src/lib/feature-map.module.ts +12 -0
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.css +0 -0
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.html +39 -0
- package/src/libs/feature/map/src/lib/geocoding/geocoding.component.ts +99 -0
- package/src/libs/feature/map/src/lib/geocoding.service.ts +59 -0
- package/src/libs/feature/map/src/lib/layers-panel/layers-panel.component.html +6 -2
- package/src/libs/feature/map/src/lib/map-context/map-context.service.ts +6 -0
- package/src/libs/feature/map/src/lib/utils/index.ts +0 -2
- package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +85 -50
- package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +18 -3
- package/src/libs/ui/elements/src/index.ts +2 -0
- package/src/libs/ui/elements/src/lib/downloads-list/downloads-list.component.html +4 -1
- package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +0 -0
- package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +30 -0
- package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +15 -0
- package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.css +52 -52
- package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.html +2 -2
- package/src/libs/ui/elements/src/lib/related-record-card/related-record-card.component.html +1 -1
- package/src/libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts +4 -0
- package/src/libs/ui/elements/src/lib/ui-elements.module.ts +4 -0
- package/src/libs/ui/inputs/src/lib/button/button.component.css +1 -1
- package/src/libs/ui/inputs/src/lib/editable-label/editable-label.directive.ts +48 -0
- package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +3 -0
- package/src/libs/ui/layout/src/lib/carousel/carousel.component.css +1 -1
- package/src/libs/ui/search/src/lib/record-table/record-table.component.html +2 -2
- package/src/libs/util/shared/src/lib/links/link-utils.ts +34 -11
- package/translations/de.json +99 -95
- package/translations/en.json +20 -16
- package/translations/es.json +4 -0
- package/translations/fr.json +4 -0
- package/translations/it.json +4 -0
- package/translations/nl.json +4 -0
- package/translations/pt.json +4 -0
- package/translations/sk.json +4 -0
- package/esm2022/libs/feature/map/src/lib/utils/map-utils-wms.service.mjs +0 -55
- package/esm2022/libs/feature/map/src/lib/utils/projections.mjs +0 -2
- package/libs/feature/map/src/lib/utils/map-utils-wms.service.d.ts +0 -17
- package/libs/feature/map/src/lib/utils/map-utils-wms.service.d.ts.map +0 -1
- package/libs/feature/map/src/lib/utils/projections.d.ts.map +0 -1
- package/src/libs/feature/map/src/lib/utils/map-utils-wms.service.ts +0 -58
- /package/libs/feature/map/src/lib/{utils → constant}/projections.d.ts +0 -0
- /package/src/libs/feature/map/src/lib/{utils → constant}/projections.ts +0 -0
|
@@ -21,6 +21,10 @@ import { AddLayerRecordPreviewComponent } from './add-layer-from-catalog/add-lay
|
|
|
21
21
|
import { UiElementsModule } from '../../../../../libs/ui/elements/src'
|
|
22
22
|
import { UiInputsModule } from '../../../../../libs/ui/inputs/src'
|
|
23
23
|
import { AddLayerFromWmsComponent } from './add-layer-from-wms/add-layer-from-wms.component'
|
|
24
|
+
import { AddLayerFromFileComponent } from './add-layer-from-file/add-layer-from-file.component'
|
|
25
|
+
import { AddLayerFromWfsComponent } from './add-layer-from-wfs/add-layer-from-wfs.component'
|
|
26
|
+
import { GeocodingComponent } from './geocoding/geocoding.component'
|
|
27
|
+
import { GEOCODING_PROVIDER, GeocodingProvider } from './geocoding.service'
|
|
24
28
|
|
|
25
29
|
@NgModule({
|
|
26
30
|
declarations: [
|
|
@@ -31,6 +35,9 @@ import { AddLayerFromWmsComponent } from './add-layer-from-wms/add-layer-from-wm
|
|
|
31
35
|
MapContainerComponent,
|
|
32
36
|
AddLayerRecordPreviewComponent,
|
|
33
37
|
AddLayerFromWmsComponent,
|
|
38
|
+
AddLayerFromFileComponent,
|
|
39
|
+
AddLayerFromWfsComponent,
|
|
40
|
+
GeocodingComponent,
|
|
34
41
|
],
|
|
35
42
|
exports: [
|
|
36
43
|
MapContextComponent,
|
|
@@ -38,6 +45,7 @@ import { AddLayerFromWmsComponent } from './add-layer-from-wms/add-layer-from-wm
|
|
|
38
45
|
LayersPanelComponent,
|
|
39
46
|
AddLayerFromCatalogComponent,
|
|
40
47
|
MapContainerComponent,
|
|
48
|
+
GeocodingComponent,
|
|
41
49
|
],
|
|
42
50
|
imports: [
|
|
43
51
|
CommonModule,
|
|
@@ -58,6 +66,10 @@ import { AddLayerFromWmsComponent } from './add-layer-from-wms/add-layer-from-wm
|
|
|
58
66
|
useValue: defaultMapOptions,
|
|
59
67
|
},
|
|
60
68
|
MapFacade,
|
|
69
|
+
{
|
|
70
|
+
provide: GEOCODING_PROVIDER,
|
|
71
|
+
useValue: ['geonames', { maxRows: 5 }] as GeocodingProvider,
|
|
72
|
+
},
|
|
61
73
|
],
|
|
62
74
|
})
|
|
63
75
|
export class FeatureMapModule {}
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<gn-ui-search-input
|
|
2
|
+
[(value)]="searchText"
|
|
3
|
+
(valueChange)="onSearchChange($event)"
|
|
4
|
+
(keyup.enter)="onEnterPress()"
|
|
5
|
+
[placeholder]="'map.geocoding.placeholder' | translate"
|
|
6
|
+
>
|
|
7
|
+
</gn-ui-search-input>
|
|
8
|
+
<ul
|
|
9
|
+
class="bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg"
|
|
10
|
+
*ngIf="results && results.length"
|
|
11
|
+
>
|
|
12
|
+
<li
|
|
13
|
+
*ngFor="let result of results"
|
|
14
|
+
(click)="zoomToLocation(result)"
|
|
15
|
+
class="flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out"
|
|
16
|
+
>
|
|
17
|
+
<svg
|
|
18
|
+
class="stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
fill="none"
|
|
21
|
+
viewBox="0 0 24 24"
|
|
22
|
+
stroke="currentColor"
|
|
23
|
+
>
|
|
24
|
+
<path
|
|
25
|
+
stroke-linecap="round"
|
|
26
|
+
stroke-linejoin="round"
|
|
27
|
+
stroke-width="2"
|
|
28
|
+
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
|
|
29
|
+
/>
|
|
30
|
+
<path
|
|
31
|
+
stroke-linecap="round"
|
|
32
|
+
stroke-linejoin="round"
|
|
33
|
+
stroke-width="2"
|
|
34
|
+
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
|
|
35
|
+
/>
|
|
36
|
+
</svg>
|
|
37
|
+
<span class="font-sans font-semibold ml-4">{{ result.label }}</span>
|
|
38
|
+
</li>
|
|
39
|
+
</ul>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Component, OnDestroy } from '@angular/core'
|
|
2
|
+
import { catchError, from, Subject, takeUntil } from 'rxjs'
|
|
3
|
+
import { debounceTime, switchMap } from 'rxjs/operators'
|
|
4
|
+
import { MapManagerService } from '../manager/map-manager.service'
|
|
5
|
+
import { fromLonLat } from 'ol/proj'
|
|
6
|
+
import { Polygon } from 'ol/geom'
|
|
7
|
+
import { GeocodingService } from '../geocoding.service'
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'gn-ui-geocoding',
|
|
11
|
+
templateUrl: './geocoding.component.html',
|
|
12
|
+
styleUrls: ['./geocoding.component.css'],
|
|
13
|
+
})
|
|
14
|
+
export class GeocodingComponent implements OnDestroy {
|
|
15
|
+
searchText = ''
|
|
16
|
+
results: any[] = []
|
|
17
|
+
searchTextChanged = new Subject<string>()
|
|
18
|
+
destroy$ = new Subject<void>()
|
|
19
|
+
errorMessage: string | null = null
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
private mapManager: MapManagerService,
|
|
23
|
+
private geocodingService: GeocodingService
|
|
24
|
+
) {
|
|
25
|
+
this.searchTextChanged
|
|
26
|
+
.pipe(
|
|
27
|
+
debounceTime(300),
|
|
28
|
+
switchMap((searchText) => {
|
|
29
|
+
return from(this.geocodingService.query(searchText)).pipe(
|
|
30
|
+
catchError((error) => {
|
|
31
|
+
this.errorMessage =
|
|
32
|
+
'An error occurred while searching. Please try again.'
|
|
33
|
+
console.error(error)
|
|
34
|
+
return []
|
|
35
|
+
})
|
|
36
|
+
)
|
|
37
|
+
}),
|
|
38
|
+
takeUntil(this.destroy$)
|
|
39
|
+
)
|
|
40
|
+
.subscribe((results) => {
|
|
41
|
+
this.results = results
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
ngOnDestroy() {
|
|
46
|
+
this.destroy$.next()
|
|
47
|
+
this.destroy$.complete()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onSearchChange(searchText: string) {
|
|
51
|
+
if (!searchText) {
|
|
52
|
+
this.clearSearch()
|
|
53
|
+
return
|
|
54
|
+
} else {
|
|
55
|
+
this.searchTextChanged.next(searchText)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
clearSearch() {
|
|
60
|
+
this.searchText = ''
|
|
61
|
+
this.results = []
|
|
62
|
+
this.errorMessage = null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
zoomToLocation(result: any) {
|
|
66
|
+
const map = this.mapManager.map
|
|
67
|
+
const view = map.getView()
|
|
68
|
+
const geometry = result.geom
|
|
69
|
+
|
|
70
|
+
if (geometry.type === 'Point') {
|
|
71
|
+
this.zoomToPoint(geometry.coordinates, view)
|
|
72
|
+
} else if (geometry.type === 'Polygon') {
|
|
73
|
+
this.zoomToPolygon(geometry.coordinates, view)
|
|
74
|
+
} else {
|
|
75
|
+
console.error(`Unsupported geometry type: ${geometry.type}`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
zoomToPoint(pointCoords: [number, number], view: any) {
|
|
80
|
+
const transformedCoords = fromLonLat(pointCoords)
|
|
81
|
+
view.setCenter(transformedCoords)
|
|
82
|
+
view.setZoom(12)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
zoomToPolygon(polygonCoords: [[number, number][]], view: any) {
|
|
86
|
+
const transformedCoords = polygonCoords[0].map((coord) => fromLonLat(coord))
|
|
87
|
+
const polygon = new Polygon([transformedCoords])
|
|
88
|
+
view.fit(polygon, {
|
|
89
|
+
duration: 100,
|
|
90
|
+
maxZoom: 12,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
onEnterPress() {
|
|
95
|
+
if (this.results && this.results.length > 0) {
|
|
96
|
+
this.zoomToLocation(this.results[0])
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Injectable, Inject, InjectionToken } from '@angular/core'
|
|
2
|
+
import {
|
|
3
|
+
queryGeoadmin,
|
|
4
|
+
GeoadminOptions,
|
|
5
|
+
GeocodingResult,
|
|
6
|
+
queryGeonames,
|
|
7
|
+
GeonamesOptions,
|
|
8
|
+
DataGouvFrOptions,
|
|
9
|
+
queryDataGouvFr,
|
|
10
|
+
} from '@geospatial-sdk/geocoding'
|
|
11
|
+
import { from, Observable, throwError } from 'rxjs'
|
|
12
|
+
import { catchError } from 'rxjs/operators'
|
|
13
|
+
|
|
14
|
+
type GeoadminGeocodingProvider = ['geoadmin', GeoadminOptions]
|
|
15
|
+
type GeonamesGeocodingProvider = ['geonames', GeonamesOptions]
|
|
16
|
+
type DataGouvFrGeocodingProvider = ['data-gouv-fr', DataGouvFrOptions]
|
|
17
|
+
export type GeocodingProvider =
|
|
18
|
+
| GeoadminGeocodingProvider
|
|
19
|
+
| GeonamesGeocodingProvider
|
|
20
|
+
| DataGouvFrGeocodingProvider
|
|
21
|
+
|
|
22
|
+
export const GEOCODING_PROVIDER = new InjectionToken<GeocodingProvider>(
|
|
23
|
+
'geocoding-provider'
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
@Injectable({
|
|
27
|
+
providedIn: 'root',
|
|
28
|
+
})
|
|
29
|
+
export class GeocodingService {
|
|
30
|
+
constructor(
|
|
31
|
+
@Inject(GEOCODING_PROVIDER) private provider: GeocodingProvider
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
query(text: string): Observable<GeocodingResult[]> {
|
|
35
|
+
let queryObservable: Observable<GeocodingResult[]>
|
|
36
|
+
switch (this.provider[0]) {
|
|
37
|
+
case 'geoadmin':
|
|
38
|
+
queryObservable = from(
|
|
39
|
+
queryGeoadmin(text, this.provider[1] as GeoadminOptions)
|
|
40
|
+
)
|
|
41
|
+
break
|
|
42
|
+
case 'geonames':
|
|
43
|
+
queryObservable = from(
|
|
44
|
+
queryGeonames(text, this.provider[1] as GeonamesOptions)
|
|
45
|
+
)
|
|
46
|
+
break
|
|
47
|
+
case 'data-gouv-fr':
|
|
48
|
+
queryObservable = from(
|
|
49
|
+
queryDataGouvFr(text, this.provider[1] as DataGouvFrOptions)
|
|
50
|
+
)
|
|
51
|
+
break
|
|
52
|
+
default:
|
|
53
|
+
return throwError(
|
|
54
|
+
() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`)
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
return queryObservable.pipe(catchError((error) => throwError(error)))
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -36,10 +36,14 @@
|
|
|
36
36
|
</div>
|
|
37
37
|
</mat-tab>
|
|
38
38
|
<mat-tab [label]="'map.add.layer.wfs' | translate" bodyClass="h-full">
|
|
39
|
-
<div class="p-3
|
|
39
|
+
<div class="p-3">
|
|
40
|
+
<gn-ui-add-layer-from-wfs></gn-ui-add-layer-from-wfs>
|
|
41
|
+
</div>
|
|
40
42
|
</mat-tab>
|
|
41
43
|
<mat-tab [label]="'map.add.layer.file' | translate" bodyClass="h-full">
|
|
42
|
-
<div class="p-3
|
|
44
|
+
<div class="p-3">
|
|
45
|
+
<gn-ui-add-layer-from-file></gn-ui-add-layer-from-file>
|
|
46
|
+
</div>
|
|
43
47
|
</mat-tab>
|
|
44
48
|
</mat-tab-group>
|
|
45
49
|
</gn-ui-expandable-panel-button>
|
|
@@ -40,6 +40,8 @@ export const DEFAULT_VIEW: MapContextViewModel = {
|
|
|
40
40
|
zoom: 2,
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export const WFS_MAX_FEATURES = 10000
|
|
44
|
+
|
|
43
45
|
@Injectable({
|
|
44
46
|
providedIn: 'root',
|
|
45
47
|
})
|
|
@@ -111,6 +113,10 @@ export class MapContextService {
|
|
|
111
113
|
urlObj.searchParams.set('typename', layerModel.name)
|
|
112
114
|
urlObj.searchParams.set('srsname', 'EPSG:3857')
|
|
113
115
|
urlObj.searchParams.set('bbox', `${extent.join(',')},EPSG:3857`)
|
|
116
|
+
urlObj.searchParams.set(
|
|
117
|
+
'maxFeatures',
|
|
118
|
+
WFS_MAX_FEATURES.toString()
|
|
119
|
+
)
|
|
114
120
|
return urlObj.toString()
|
|
115
121
|
},
|
|
116
122
|
strategy: bboxStrategy,
|
|
@@ -2,18 +2,18 @@ import { HttpClient } from '@angular/common/http'
|
|
|
2
2
|
import { Injectable } from '@angular/core'
|
|
3
3
|
import type { FeatureCollection } from 'geojson'
|
|
4
4
|
import { extend, Extent, isEmpty } from 'ol/extent'
|
|
5
|
-
import
|
|
5
|
+
import Feature from 'ol/Feature'
|
|
6
6
|
import GeoJSON from 'ol/format/GeoJSON'
|
|
7
7
|
import { Geometry } from 'ol/geom'
|
|
8
8
|
import Layer from 'ol/layer/Layer'
|
|
9
9
|
import Map from 'ol/Map'
|
|
10
|
-
import {
|
|
10
|
+
import { transformExtent } from 'ol/proj'
|
|
11
11
|
import Source from 'ol/source/Source'
|
|
12
12
|
import ImageWMS from 'ol/source/ImageWMS'
|
|
13
13
|
import TileWMS from 'ol/source/TileWMS'
|
|
14
14
|
import VectorSource from 'ol/source/Vector'
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { optionsFromCapabilities } from 'ol/source/WMTS'
|
|
16
|
+
import { defaults, DragPan, Interaction, MouseWheelZoom } from 'ol/interaction'
|
|
17
17
|
import {
|
|
18
18
|
mouseOnly,
|
|
19
19
|
noModifierKeys,
|
|
@@ -21,45 +21,53 @@ import {
|
|
|
21
21
|
primaryAction,
|
|
22
22
|
} from 'ol/events/condition'
|
|
23
23
|
import WMTSCapabilities from 'ol/format/WMTSCapabilities'
|
|
24
|
-
import { from, Observable
|
|
24
|
+
import { from, Observable } from 'rxjs'
|
|
25
25
|
import { map } from 'rxjs/operators'
|
|
26
26
|
import {
|
|
27
27
|
MapContextLayerModel,
|
|
28
28
|
MapContextLayerTypeEnum,
|
|
29
|
+
MapContextLayerWmsModel,
|
|
29
30
|
MapContextLayerWmtsModel,
|
|
30
31
|
} from '../map-context/map-context.model'
|
|
31
|
-
import { MapUtilsWMSService } from './map-utils-wms.service'
|
|
32
32
|
import Collection from 'ol/Collection'
|
|
33
33
|
import MapBrowserEvent from 'ol/MapBrowserEvent'
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
CatalogRecord,
|
|
36
|
+
DatasetDistribution,
|
|
37
|
+
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
38
|
+
import { ProxyService } from '../../../../../../libs/util/shared/src'
|
|
39
|
+
import { WmsEndpoint } from '@camptocamp/ogc-client'
|
|
40
|
+
import { LONLAT_CRS_CODES } from '../constant/projections'
|
|
41
|
+
import { fromEPSGCode, register } from 'ol/proj/proj4'
|
|
42
|
+
import proj4 from 'proj4/dist/proj4'
|
|
35
43
|
|
|
36
44
|
const FEATURE_PROJECTION = 'EPSG:3857'
|
|
37
45
|
const DATA_PROJECTION = 'EPSG:4326'
|
|
38
46
|
|
|
47
|
+
const GEOJSON = new GeoJSON()
|
|
48
|
+
|
|
39
49
|
@Injectable({
|
|
40
50
|
providedIn: 'root',
|
|
41
51
|
})
|
|
42
52
|
export class MapUtilsService {
|
|
43
|
-
constructor(private http: HttpClient, private
|
|
53
|
+
constructor(private http: HttpClient, private proxy: ProxyService) {}
|
|
44
54
|
|
|
45
55
|
createEmptyMap(): Map {
|
|
46
|
-
|
|
56
|
+
return new Map({
|
|
47
57
|
controls: [],
|
|
48
58
|
pixelRatio: 1,
|
|
49
59
|
})
|
|
50
|
-
return map
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
readFeatureCollection = (
|
|
54
63
|
featureCollection: FeatureCollection,
|
|
55
64
|
featureProjection = FEATURE_PROJECTION,
|
|
56
65
|
dataProjection = DATA_PROJECTION
|
|
57
|
-
):
|
|
58
|
-
|
|
66
|
+
): Feature<Geometry>[] => {
|
|
67
|
+
return GEOJSON.readFeatures(featureCollection, {
|
|
59
68
|
featureProjection,
|
|
60
69
|
dataProjection,
|
|
61
|
-
})
|
|
62
|
-
return olFeatures
|
|
70
|
+
}) as Feature<Geometry>[]
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
isWMSLayer(layer: Layer<Source>): boolean {
|
|
@@ -78,20 +86,14 @@ export class MapUtilsService {
|
|
|
78
86
|
...source.getParams(),
|
|
79
87
|
INFO_FORMAT: 'application/json',
|
|
80
88
|
}
|
|
81
|
-
|
|
82
|
-
coordinate,
|
|
83
|
-
resolution,
|
|
84
|
-
projection,
|
|
85
|
-
params
|
|
86
|
-
)
|
|
87
|
-
return url
|
|
89
|
+
return source.getFeatureInfoUrl(coordinate, resolution, projection, params)
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
getVectorFeaturesFromClick(olMap, event):
|
|
92
|
+
getVectorFeaturesFromClick(olMap, event): Feature<Geometry>[] {
|
|
91
93
|
const features = []
|
|
92
94
|
const hit = olMap.forEachFeatureAtPixel(
|
|
93
95
|
event.pixel,
|
|
94
|
-
(feature:
|
|
96
|
+
(feature: Feature<Geometry>) => {
|
|
95
97
|
return feature
|
|
96
98
|
},
|
|
97
99
|
{ layerFilter: (layer) => layer.getSource() instanceof VectorSource }
|
|
@@ -103,9 +105,9 @@ export class MapUtilsService {
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
getGFIFeaturesObservablesFromClick(
|
|
106
|
-
olMap,
|
|
107
|
-
event
|
|
108
|
-
): Observable<
|
|
108
|
+
olMap: Map,
|
|
109
|
+
event: MapBrowserEvent<PointerEvent>
|
|
110
|
+
): Observable<Feature<Geometry>[]>[] {
|
|
109
111
|
const wmsLayers = olMap.getLayers().getArray().filter(this.isWMSLayer)
|
|
110
112
|
|
|
111
113
|
if (wmsLayers.length > 0) {
|
|
@@ -128,8 +130,8 @@ export class MapUtilsService {
|
|
|
128
130
|
/**
|
|
129
131
|
* Will emit `null` if no extent could be computed
|
|
130
132
|
*/
|
|
131
|
-
getLayerExtent(layer: MapContextLayerModel):
|
|
132
|
-
let
|
|
133
|
+
async getLayerExtent(layer: MapContextLayerModel): Promise<Extent | null> {
|
|
134
|
+
let latLonExtent: Extent
|
|
133
135
|
if (
|
|
134
136
|
layer &&
|
|
135
137
|
layer.type === 'geojson' &&
|
|
@@ -138,37 +140,55 @@ export class MapUtilsService {
|
|
|
138
140
|
layer.data.features[0] &&
|
|
139
141
|
layer.data.features[0].geometry
|
|
140
142
|
) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.
|
|
148
|
-
|
|
149
|
-
prev ? extend(prev, curr.getExtent()) : curr.getExtent(),
|
|
150
|
-
null as Extent
|
|
151
|
-
)
|
|
143
|
+
latLonExtent = new GeoJSON()
|
|
144
|
+
.readFeatures(layer.data)
|
|
145
|
+
.map((feature) => feature.getGeometry())
|
|
146
|
+
.filter((geom) => !!geom)
|
|
147
|
+
.reduce(
|
|
148
|
+
(prev, curr) =>
|
|
149
|
+
prev ? extend(prev, curr.getExtent()) : curr.getExtent(),
|
|
150
|
+
null as Extent
|
|
152
151
|
)
|
|
153
|
-
)
|
|
154
152
|
} else if (layer && layer.type === 'wms') {
|
|
155
|
-
|
|
153
|
+
latLonExtent = await this.getWmsLayerExtent(layer)
|
|
156
154
|
} else if (layer && layer.type === 'wmts') {
|
|
157
155
|
if (layer.extent) {
|
|
158
|
-
|
|
156
|
+
latLonExtent = layer.extent
|
|
159
157
|
} else {
|
|
160
|
-
return
|
|
158
|
+
return layer.options.tileGrid.getExtent()
|
|
161
159
|
}
|
|
162
160
|
} else {
|
|
163
|
-
return
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
if (!latLonExtent || isEmpty(latLonExtent)) {
|
|
164
|
+
return null
|
|
164
165
|
}
|
|
165
|
-
return
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
return transformExtent(latLonExtent, 'EPSG:4326', 'EPSG:3857')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async getWmsLayerExtent(
|
|
170
|
+
layer: MapContextLayerWmsModel
|
|
171
|
+
): Promise<Extent | null> {
|
|
172
|
+
const endpoint = await new WmsEndpoint(
|
|
173
|
+
this.proxy.getProxiedUrl(layer.url)
|
|
174
|
+
).isReady()
|
|
175
|
+
const { boundingBoxes } = endpoint.getLayerByName(layer.name)
|
|
176
|
+
if (!Object.keys(boundingBoxes).length) {
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
const lonLatCRS = Object.keys(boundingBoxes)?.find((crs) =>
|
|
180
|
+
LONLAT_CRS_CODES.includes(crs)
|
|
171
181
|
)
|
|
182
|
+
if (lonLatCRS) {
|
|
183
|
+
return boundingBoxes[lonLatCRS].map(parseFloat)
|
|
184
|
+
} else {
|
|
185
|
+
const availableEPSGCode = Object.keys(boundingBoxes)[0]
|
|
186
|
+
register(proj4)
|
|
187
|
+
const proj = await fromEPSGCode(availableEPSGCode)
|
|
188
|
+
const bboxWithFiniteNumbers =
|
|
189
|
+
boundingBoxes[availableEPSGCode].map(parseFloat)
|
|
190
|
+
return transformExtent(bboxWithFiniteNumbers, proj, 'EPSG:4326')
|
|
191
|
+
}
|
|
172
192
|
}
|
|
173
193
|
|
|
174
194
|
getWmtsLayerFromCapabilities(
|
|
@@ -235,6 +255,21 @@ ${e.stack || e.message || e}`)
|
|
|
235
255
|
.getArray()
|
|
236
256
|
)
|
|
237
257
|
}
|
|
258
|
+
|
|
259
|
+
getRecordExtent(record: Partial<CatalogRecord>): Extent {
|
|
260
|
+
if (!('spatialExtents' in record)) {
|
|
261
|
+
return null
|
|
262
|
+
}
|
|
263
|
+
// transform an array of geojson geometries into a bbox
|
|
264
|
+
const totalExtent = record.spatialExtents.reduce(
|
|
265
|
+
(prev, curr) => {
|
|
266
|
+
const geom = GEOJSON.readGeometry(curr.geometry)
|
|
267
|
+
return extend(prev, geom.getExtent())
|
|
268
|
+
},
|
|
269
|
+
[Infinity, Infinity, -Infinity, -Infinity]
|
|
270
|
+
)
|
|
271
|
+
return transformExtent(totalExtent, 'EPSG:4326', 'EPSG:3857')
|
|
272
|
+
}
|
|
238
273
|
}
|
|
239
274
|
|
|
240
275
|
export function dragPanCondition(
|
|
@@ -22,10 +22,14 @@ import { StyleLike } from 'ol/style/Style'
|
|
|
22
22
|
import {
|
|
23
23
|
BehaviorSubject,
|
|
24
24
|
combineLatest,
|
|
25
|
+
from,
|
|
26
|
+
lastValueFrom,
|
|
25
27
|
Observable,
|
|
26
28
|
of,
|
|
29
|
+
startWith,
|
|
27
30
|
Subscription,
|
|
28
31
|
throwError,
|
|
32
|
+
withLatestFrom,
|
|
29
33
|
} from 'rxjs'
|
|
30
34
|
import {
|
|
31
35
|
catchError,
|
|
@@ -99,7 +103,7 @@ export class MapViewComponent implements OnInit, OnDestroy {
|
|
|
99
103
|
|
|
100
104
|
mapContext$ = this.currentLayers$.pipe(
|
|
101
105
|
switchMap((layers) =>
|
|
102
|
-
this.mapUtils.getLayerExtent(layers[0]).pipe(
|
|
106
|
+
from(this.mapUtils.getLayerExtent(layers[0])).pipe(
|
|
103
107
|
catchError((error) => {
|
|
104
108
|
console.warn(error) // FIXME: report this to the user somehow
|
|
105
109
|
return of(undefined)
|
|
@@ -115,7 +119,19 @@ export class MapViewComponent implements OnInit, OnDestroy {
|
|
|
115
119
|
),
|
|
116
120
|
tap(() => this.resetSelection())
|
|
117
121
|
)
|
|
118
|
-
)
|
|
122
|
+
),
|
|
123
|
+
withLatestFrom(this.mdViewFacade.metadata$),
|
|
124
|
+
map(([context, metadata]) => {
|
|
125
|
+
if (context.view.extent) return context
|
|
126
|
+
const extent = this.mapUtils.getRecordExtent(metadata)
|
|
127
|
+
return {
|
|
128
|
+
...context,
|
|
129
|
+
view: {
|
|
130
|
+
...context.view,
|
|
131
|
+
extent,
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
})
|
|
119
135
|
)
|
|
120
136
|
|
|
121
137
|
constructor(
|
|
@@ -123,7 +139,6 @@ export class MapViewComponent implements OnInit, OnDestroy {
|
|
|
123
139
|
private mapManager: MapManagerService,
|
|
124
140
|
private mapUtils: MapUtilsService,
|
|
125
141
|
private dataService: DataService,
|
|
126
|
-
private proxy: ProxyService,
|
|
127
142
|
private featureInfo: FeatureInfoService,
|
|
128
143
|
private changeRef: ChangeDetectorRef,
|
|
129
144
|
private styleService: MapStyleService
|
|
@@ -18,5 +18,7 @@ export * from './lib/pagination/pagination.component'
|
|
|
18
18
|
export * from './lib/related-record-card/related-record-card.component'
|
|
19
19
|
export * from './lib/search-results-error/search-results-error.component'
|
|
20
20
|
export * from './lib/user-preview/user-preview.component'
|
|
21
|
+
export * from './lib/max-lines/max-lines.component'
|
|
21
22
|
export * from './lib/record-api-form/record-api-form.component'
|
|
22
23
|
export * from './lib/markdown-parser/markdown-parser.component'
|
|
24
|
+
export * from './lib/image-overlay-preview/image-overlay-preview.component'
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
>
|
|
9
9
|
record.metadata.download
|
|
10
10
|
</p>
|
|
11
|
-
<div
|
|
11
|
+
<div
|
|
12
|
+
class="flex flex-wrap justify-start sm:justify-end sm:pb-4"
|
|
13
|
+
data-cy="download-format-filters"
|
|
14
|
+
>
|
|
12
15
|
<gn-ui-button
|
|
13
16
|
class="m-1 format-filter"
|
|
14
17
|
[extraClass]="
|
package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css
ADDED
|
File without changes
|
package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<gn-ui-content-ghost
|
|
2
|
+
[showContent]="imageUrl !== undefined"
|
|
3
|
+
ghostClass="h-48 mb-3"
|
|
4
|
+
>
|
|
5
|
+
<div
|
|
6
|
+
*ngIf="imageUrl"
|
|
7
|
+
[showContent]="imageUrl !== undefined"
|
|
8
|
+
data-cy="record-thumbnail"
|
|
9
|
+
class="flex-shrink-0 bg-gray-100 rounded-lg overflow-hidden w-full border border-gray-300 group-hover:shadow-xl group-hover:border-0 h-48 mb-3"
|
|
10
|
+
>
|
|
11
|
+
<gn-ui-thumbnail
|
|
12
|
+
class="relative h-full w-full"
|
|
13
|
+
[thumbnailUrl]="imageUrl"
|
|
14
|
+
fit="cover"
|
|
15
|
+
(placeholderShown)="isPlaceholderShown.emit($event)"
|
|
16
|
+
></gn-ui-thumbnail>
|
|
17
|
+
<div class="relative">
|
|
18
|
+
<gn-ui-button
|
|
19
|
+
class="absolute bottom-0 right-0 z-10 mr-2 mb-2"
|
|
20
|
+
[type]="'outline'"
|
|
21
|
+
[extraClass]="'!py-2 !px-0'"
|
|
22
|
+
(buttonClick)="openLightbox(imageUrl)"
|
|
23
|
+
>
|
|
24
|
+
<mat-icon class="material-symbols-outlined font-extralight"
|
|
25
|
+
>zoom_out_map</mat-icon
|
|
26
|
+
>
|
|
27
|
+
</gn-ui-button>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</gn-ui-content-ghost>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
|
2
|
+
import * as basicLightbox from 'basiclightbox'
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'gn-ui-image-overlay-preview',
|
|
6
|
+
templateUrl: './image-overlay-preview.component.html',
|
|
7
|
+
styleUrls: ['./image-overlay-preview.component.css'],
|
|
8
|
+
})
|
|
9
|
+
export class ImageOverlayPreviewComponent {
|
|
10
|
+
@Input() imageUrl: string
|
|
11
|
+
@Output() isPlaceholderShown = new EventEmitter<boolean>()
|
|
12
|
+
openLightbox(src: string) {
|
|
13
|
+
basicLightbox.create(`<img src="${src}"/>`).show()
|
|
14
|
+
}
|
|
15
|
+
}
|