As an alternative to accessing the DKS service directly a JavaScript/TypeScript API has been developed and packaged as an npm package. It is the same logic that has been used to implement LayerControl and the DatasetStore. This package also has API documentation which can be here. The client API models the data in the catalog service and handles all requests for the service. Furthermore it includes several helper functions that can be used creating applications.
To install the Client API use npm like this:
npm install @dmp/lagvaelger-client-api
Basic use of the Client API:
import { Api } from '@dmp/lagvaelger-client-api'
const api = new Api()
See the Client API documentation for detailed information.
The Client API and the components can be used with or without a map. Normally it is used in combination with a map. A map can be created using a variety of map libraries. The most common is OpenLayers and the Client API is build around OpenLayers to make it easy to use. Other libraries, like MapLibre can be used, but you need to do more of the implementation youself.
To control the initial state of the datasets and how they are presented, use the followning options.
The Datacatalog contains some datasets, that are not renderable, like zip-file. If the Client API is purely used for map rendering, you need to add the onlyRenderable
when instantiating the Client API like this:
import { Api } from '@dmp/lagvaelger-client-api'
const api = new Api({
onlyRenderable: true,
})
Then only renderable datasets will be available to the user.
By default the locale is dk-DK
but it is possible to get the metadata and the components in en-US
like this:
const api = new Api({
locale: 'en-US',
})
Furthermore you can dynamically change the locale with:
api.setLocale('en-US')
The default active datasets are defined by adding a datasetState like this:
import { Api } from '@dmp/lagvaelger-client-api'
const api = new Api({
onlyRenderable: true,
datasetState: [
{
id: 'urn:dmp:ds:skaermkort-daempet',
visible: true,
opacity: 0.5,
}
],
})
Call the api.load()
method to initialize the state of the active datasets. Changes to the active datasets are stored in local storage in the browser. By calling load
witout arguments, local storage is read and used as current datasetState:
api.load()
If you want a specifik state and ignore the datasetState in the local storage in the browser, add the datasetState as the argument to the load method like this:
api.load([
{
id: 'urn:dmp:ds:skaermkort-daempet',
visible: true,
opacity: 0.5,
}
])
To use the Client API with OpenLayers, the active datasets can be added to the map with:
import Map from 'ol/Map'
import View from 'ol/View'
import { Api, projections } from '@dmp/lagvaelger-client-api'
const api = new Api({
onlyRenderable: true,
})
const map = new Map({
target: 'map',
layers: [api.getOlGroup()],
view: new View({
center: [601283, 6206304],
zoom: 3,
projection: projections[25832].projection,
}),
})
map.addLayer(api.getOlGroup())
The layerGroup
is a collection that the Client API is maintaining. By adding the layers as a group, the Client API can change and reorder the internal layers as needed.
On each dataset, there are a getOlLayer method that will create an OpenLayers layer. This can be used if you are creating your own layer control or a more specific map like an overview map.
If the application need to know when something changes in the Client API, there at multiple event to listen to. Read more here. There are events directly on the API but there are also events on each dataset.
The API contains functionality to query a single dataset or a liste of datasets. This can be used for something like click in the map to show information about the datasets visible in that location. But it can also be used for other kinds of quering.
To query all visible datasets by a specific coordinate, use somthing like this:
const promises = api.queryByCoordinate(coordinate, undefined, {
buffer: 1,
resolution: map.getView().getResolution()
})
const result = await Promise.all(promises)
Other query methods can be used like queryByExtent
or the full flexible query
for queriing with more advanced filters, both spatial and/or attribute filters.
A query
can be found on a dataset as well.
By using this functionality, you don’t need to know anything about the datasource and how to make the request.
The Client API contains a helper function that makes it possible to download a list of datasets as a QGIS project. This makes it easier to continue work in a desktop application. In your application add something like this:
import { saveToQgs } from '@dmp/lagvaelger-client-api'
saveToQgs({
name: 'download',
datasets,
})
Read more about the option here.
TBD
The UI components consists of multiple components, that can be used independently from each other as stand alone or in combination. All components are using the Client API to get access to the Datacatalog service and handling state.
The UI components can be integrated into most web client projects as demonstrated by example code here via npm package @dmp/lagvaelger-client-ui
.
The use of the following components depend on witch framework you are using. These examples are using Vue.js, but the main principals are the same ind Vanilla JavaScript, EmberJS, Angular and other frameworks.
In all the components you need an instance of the Client API that can be created as described above.
The layer control component is a simple, user friendly UI that gives the user the ability to control the state og each dataset. The state contains information about witch datasets is available in the UI, if the datasets are visible or not and the order of the datasets.
The content of the LayerControl can be modified by the application if needed. But it is possible to add datasets to the UI by using the DatasetStore component.
Basic implementation:
import { Api } from '@dmp/lagvaelger-client-api'
import { LayerControl } from '@dmp/lagvaelger-client-ui'
import '@dmp/lagvaelger-client-ui/style.css'
const api = new Api({
onlyRenderable: true,
})
api.load()
In the template
add the component with a reference to the Client API, that the component should use:
<LayerControl :api="api"/>
Thas is all you need.
Beside adding the api
to the component, there are multiple options to add:
As default the LayerControl is expanded. But by adding the collapsed
option, it is possible to force the LayerControl as collapsed instead:
<LayerControl :api="api" :collapsed="true"/>
To remove the “Add layers” button from the LayerControl, just add disableDatasetStore
like this:
<LayerControl :api="api" :disableDatasetStore="true"/>
This will remove the buttom as well as the “Show metadata” button and the “Remove layer” button from each dataset in the LayerControl.
If you are using the OpenLayers like descibed above, you can add a reactive property with the current resolution to the component. Then the component will indicate if the dataset is visible in the current zoom level:
const currentResolution = ref<number>()
map.on('moveend', () => currentResolution.value = map.getView().getResolution())
<LayerControl :api="api" :currentResolution="currentResolution"/>
In some cases, like when using the LayerToggle compoment, you would like to hide some specific datasets in the LayerControl and in the DatasetStore. You can do this using the hiddenDatasets
options like this:
const layerToggleLayers = ['urn:dmp:ds:skaermkort-daempet', 'urn:dmp:ds:ortofoto-foraar-nyeste-tilgaengelige']
<LayerControl :api="api" :hiddenDatasets="layerToggleLayers"/>
On the ClientAPI, there is a helper function for downloading datasets as a QGIS project. It is possible to add a “Download QGIS project” button to the settings menu in the LayerControl. Just add showQGISButton
as an option like this:
<LayerControl :api="api" :showQGISButton="true"/>
When the user presses the button, the datasets that are visible in the LayerControl, will be included in the QGOS projekt.
The DatasetStore component can be activated though the LayerControl or as a stand alone. The DatasetStore component is using the Client API to get access to the Datacatalog service. The DatasetStore component makes it easy to find a dataset, see the relations between datasets and add datasets to the LayerControl. The DatasetStore component shows all the details of a dataset including information about the related sources (like WMS and more) and the owner of a dataset.
The DatasetStore component can be activated though the LayerControl or as a stand alone. The DatasetStore component is using the Client API to get access to the Datacatalog service. The DatasetStore component makes it easy to find a dataset, see the relations between datasets and add datasets to the LayerControl. The DatasetStore component shows all the details of a dataset including information about the related sources (like WMS and more) and the owner of a dataset.
Basic implementation (not needed if the LayerControl is added!):
import { Api } from '@dmp/lagvaelger-client-api'
import { DatasetStore } from '@dmp/lagvaelger-client-ui'
import '@dmp/lagvaelger-client-ui/style.css'
const api = new Api()
api.load()
In the template
add the component with a reference to the Client API, that the component should use:
<DatasetStore :api="api"/>
Beside adding the api
to the component, there are multiple options to add:
In some cases, like when using the LayerToggle compoment, you would like to hide some specific datasets in the LayerControl and in the DatasetStore. You can do this using the hiddenDatasets
options like this:
const layerToggleLayers = ['urn:dmp:ds:skaermkort-daempet', 'urn:dmp:ds:ortofoto-foraar-nyeste-tilgaengelige']
<DatasetStore :api="api" :hiddenDatasets="layerToggleLayers"/>
The LayerToggle component is a simple Google Maps-like baselayer control. It gives the user the ability to toggle between a list of baselayers provided by the application. The list of dataset contains two or more datasets.
Basic implementation:
import { Api } from '@dmp/lagvaelger-client-api'
import { LayerToggle } from '@dmp/lagvaelger-client-ui'
import '@dmp/lagvaelger-client-ui/style.css'
const layerToggleDatasets = ['urn:dmp:ds:skaermkort-daempet', 'urn:dmp:ds:ortofoto-foraar-nyeste-tilgaengelige']
const api = new Api({
onlyRenderable: true,
datasetState: layerToggleDatasets.map((id, index) => ({id,visible: index===0,opacity:1})),
})
api.load()
In the template
add the component with a reference to the Client API and the list of ID’s of datasets, that the component should use:
<LayerToggle :api="api" :datasets="layerToggleDatasets"/>
The datasetState
is set on the API to match the datasets in the LayerToggle.
Note: If the active datasets doesn’t match the list of datasets provides to the LayerToggle, the component is hidden. While testing, it can be a good idea to clear the local storage in the browser, or whipe it by calling the load
method with a specific state, that matches the list of datasets provides to the LayerToggle.
The Attribution
component will provide a list of attributions for the current active visible datasets. The list will update automatically when the active datasets changes. Duplicates are removed.
Just like for the LayerToggle component, you can create an api
like this like described above (or reuse the one that is already created):
import { Api } from '@dmp/lagvaelger-client-api'
import { Attribution } from '@dmp/lagvaelger-client-ui'
import '@dmp/lagvaelger-client-ui/style.css'
const api = new Api()
api.load()
In the template
add the component with a reference to the Client API:
<Attribution :api="api"/>
To change the active datasets, just modify the api.activeDatasets
property. The layerGroup
in OpenLayers will reflect the state and the order of the api.activeDatasets
collection.
Don’t modify the layerGroup
from the Client API programmatically.
OpenLayers 7+ is required.
If you are using Typescript, then you need to use the same Major and Minor version as the TypeScript used in the Client API package.