Skip to content

Commit

Permalink
Merge pull request #227 from geonetwork/custom_layers
Browse files Browse the repository at this point in the history
Enable configuring custom layers
  • Loading branch information
tkohr authored Feb 18, 2022
2 parents 7f4a746 + cc9a43b commit 147fd22
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 57 deletions.
30 changes: 26 additions & 4 deletions conf/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,35 @@ geonetwork4_api_url = "/geonetwork/srv/api"
proxy_path = ""

### MAP SETTINGS
# The map section allows to override default settings of the map view.
# Example:
#
# [map]

# The map section allows to customize how maps are configured.
[map]
# Optional; Will limit the possibility to zoom in past a certain zoom level
# max_zoom = 10

# Optional; will limit the possibility to pan or zoom out outside of an extent
# Expressed in the map view projection (EPSG:3857)
# max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]

# Optional; if true, the default basemap will not be added to the map.
# Use [[map_layer]] sections to define your own custom layers (see below)
# do_not_use_default_basemap = false

# One or several layers (as background or overlay) can be added to the map with the following properties:
# - type (mandatory): Indicates the layer type. Possible values are 'xyz', 'wms', 'wfs'.
# - url (mandatory): Layer endpoint URL.
# - name: Mandatory for 'wms', 'wfs' types where it indicates the layer name or feature type.
# Layer order in the config is the same as in the map, the first one being the bottom one.
# Each layer is defined in its own [[map_layer]] section.
# Example:
# [[map_layer]]
# type = "xyz"
# url = "https://{a-c}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"
# [[map_layer]]
# type = "wfs"
# url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
# name = "masque_hdf_ign_carto_latin1"

### VISUAL THEME

# All parameters are expressed in CSS format, see:
Expand Down
62 changes: 61 additions & 1 deletion libs/feature/map/src/lib/map-context/map-context.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import {
MAP_CTX_LAYER_XYZ_FIXTURE,
} from './map-context.fixtures'

import { MapContextService } from './map-context.service'
import {
DEFAULT_BASELAYER_CONTEXT,
MapContextService,
} from './map-context.service'

const mapStyleServiceMock = {
createDefaultStyle: jest.fn(() => new Style()),
Expand Down Expand Up @@ -191,12 +194,69 @@ describe('MapContextService', () => {
const mapContext = MAP_CTX_FIXTURE
const mapConfig = MAP_CONFIG_FIXTURE
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).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).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).getSource()
expect(layerWFSSource).toBeInstanceOf(VectorSource)
})
})
describe('with config, but keeping default basemap', () => {
const map = new Map({})
const mapContext = MAP_CTX_FIXTURE
const mapConfig = MAP_CONFIG_FIXTURE
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).getSource().getUrls()
expect(baselayerUrls).toEqual(DEFAULT_BASELAYER_CONTEXT.urls)
})
})
})
describe('#mergeMapConfigWithContext', () => {
const mapContext = MAP_CTX_FIXTURE
const mapConfig = MAP_CONFIG_FIXTURE
beforeEach(() => {
mapConfig.DO_NOT_USE_DEFAULT_BASEMAP = true
})
it('merges mapconfig into existing mapcontext', () => {
const mergedMapContext = service.mergeMapConfigWithContext(
mapContext,
mapConfig
)
const layersContext = service.getLayersContextFromConfig(
MAP_CONFIG_FIXTURE.MAP_LAYERS
)

expect(mergedMapContext).toEqual({
...MAP_CTX_FIXTURE,
view: {
...MAP_CTX_FIXTURE.view,
maxZoom: MAP_CONFIG_FIXTURE.MAX_ZOOM,
maxExtent: MAP_CONFIG_FIXTURE.MAX_EXTENT,
},
layers: [
layersContext[0],
layersContext[1],
layersContext[2],
...MAP_CTX_FIXTURE.layers,
],
})
})
})
})
34 changes: 33 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 @@ -17,7 +17,16 @@ import VectorSource from 'ol/source/Vector'
import { MapUtilsService } from '../utils/map-utils.service'
import { bbox as bboxStrategy } from 'ol/loadingstrategy'
import GeoJSON from 'ol/format/GeoJSON'
import { MapConfig } from '@geonetwork-ui/util/app-config'
import { LayerConfig, MapConfig } from '@geonetwork-ui/util/app-config'

export const DEFAULT_BASELAYER_CONTEXT: MapContextLayerModel = {
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`,
],
}

@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -122,6 +131,29 @@ export class MapContextService {
maxExtent: mapConfig.MAX_EXTENT,
}),
},
layers: [
...(mapConfig.DO_NOT_USE_DEFAULT_BASEMAP
? []
: [DEFAULT_BASELAYER_CONTEXT]),
...(mapConfig.MAP_LAYERS
? this.getLayersContextFromConfig(mapConfig.MAP_LAYERS)
: []),
...mapContext.layers,
],
}
}

getLayersContextFromConfig(
layersConfig: LayerConfig[]
): MapContextLayerModel[] {
const layersModel: MapContextLayerModel[] = []
layersConfig.forEach((layerConfig) => {
layersModel.push({
type: MapContextLayerTypeEnum[layerConfig.TYPE.toUpperCase()],
url: layerConfig.URL,
name: layerConfig.NAME,
})
})
return layersModel
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,23 @@ import { delay } from 'rxjs/operators'
import { FEATURE_COLLECTION_POINT_FIXTURE_4326 } from '@geonetwork-ui/util/shared'
import { MapConfig } from '@geonetwork-ui/util/app-config'

const mapConfigMock = { MAX_ZOOM: 10 }
const mapConfigMock = {
MAX_ZOOM: 10,
MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
DO_NOT_USE_DEFAULT_BASEMAP: false,
MAP_LAYERS: [
{
TYPE: 'wms',
URL: 'https://some-wms-server',
NAME: 'some_layername',
},
{
TYPE: 'wfs',
URL: 'https://some-wfs-server',
NAME: 'some_layername',
},
],
}
jest.mock('@geonetwork-ui/util/app-config', () => ({
getMapConfig: () => mapConfigMock,
isConfigLoaded: jest.fn(() => true),
Expand Down Expand Up @@ -208,9 +224,9 @@ describe('DataViewMapComponent', () => {
mdViewFacade.geoDataLinks$.next([])
fixture.detectChanges()
})
it('emits a map context with only the base layer', () => {
it('emits a map context with no layer', () => {
expect(mapComponent.context).toEqual({
layers: [component.getBackgroundLayer()],
layers: [],
view: expect.any(Object),
})
})
Expand Down Expand Up @@ -244,10 +260,9 @@ describe('DataViewMapComponent', () => {
mdViewFacade.geoDataLinks$.next([])
fixture.detectChanges()
})
it('emits a map context with the base layer and the first compatible link', () => {
it('emits a map context with the first compatible link', () => {
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
url: 'http://abcd.com/',
name: 'layer1',
Expand Down Expand Up @@ -326,10 +341,9 @@ describe('DataViewMapComponent', () => {
tick(200)
fixture.detectChanges()
}))
it('emits a map context with the base layer and the downloaded data from WFS', () => {
it('emits a map context with the downloaded data from WFS', () => {
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
type: 'geojson',
data: SAMPLE_GEOJSON,
Expand All @@ -353,10 +367,9 @@ describe('DataViewMapComponent', () => {
tick(200)
fixture.detectChanges()
}))
it('emits a map context with the base layer and the downloaded data from WFS', () => {
it('emits a map context with the the downloaded data from WFS', () => {
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
type: 'geojson',
data: SAMPLE_GEOJSON,
Expand Down Expand Up @@ -422,11 +435,10 @@ describe('DataViewMapComponent', () => {
fixture.detectChanges()
tick(200)
}))
it('emits a map context after loading with the base layer and the downloaded data', () => {
it('emits a map context after loading with the downloaded data', () => {
fixture.detectChanges()
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
type: 'geojson',
data: SAMPLE_GEOJSON,
Expand Down Expand Up @@ -468,7 +480,6 @@ describe('DataViewMapComponent', () => {
it('emits a map context with the link from the last record', () => {
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
url: 'http://abcd.com/',
name: 'layer',
Expand Down Expand Up @@ -520,7 +531,6 @@ describe('DataViewMapComponent', () => {
it('emits a new map context with the selected layer and the computed extent', () => {
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
url: 'http://abcd.com/',
name: 'layer2',
Expand All @@ -541,7 +551,6 @@ describe('DataViewMapComponent', () => {
it('emits a new map context with the selected layer and a default view', () => {
expect(mapComponent.context).toEqual({
layers: [
component.getBackgroundLayer(),
{
url: 'http://abcd.com/',
name: 'layer2',
Expand All @@ -560,7 +569,6 @@ describe('DataViewMapComponent', () => {
}))
it('does not emit another map context', () => {
expect(mapComponent.context.layers).toEqual([
component.getBackgroundLayer(),
{
url: 'http://abcd.com/',
name: 'layer2',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ export class DataViewMapComponent implements OnInit, OnDestroy {
map(([links, index]) => links[index]),
switchMap((link) => {
if (!link) {
return of([this.getBackgroundLayer()])
return of([])
}
this.loading = true
this.error = null
return this.getLayerFromLink(link).pipe(
map((layer) => [this.getBackgroundLayer(), layer]),
map((layer) => [layer]),
catchError((e) => {
this.error = e.message
return of([this.getBackgroundLayer()])
return of([])
}),
finalize(() => (this.loading = false))
)
Expand All @@ -97,7 +97,7 @@ export class DataViewMapComponent implements OnInit, OnDestroy {

mapContext$ = this.currentLayers$.pipe(
switchMap((layers) =>
this.mapUtils.getLayerExtent(layers[1]).pipe(
this.mapUtils.getLayerExtent(layers[0]).pipe(
catchError((error) => {
console.warn(error) // FIXME: report this to the user somehow
return of(undefined)
Expand Down Expand Up @@ -164,17 +164,6 @@ export class DataViewMapComponent implements OnInit, OnDestroy {
this.selection = null
}

getBackgroundLayer(): MapContextLayerModel {
return {
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`,
],
}
}

getLayerFromLink(link: MetadataLinkValid): Observable<MapContextLayerModel> {
if (this.linkHelper.isWmsLink(link)) {
return of({
Expand Down
Loading

0 comments on commit 147fd22

Please sign in to comment.