Skip to content
Open
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
1,272 changes: 1,264 additions & 8 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"dependencies": {
"@defra/forms-model": "^3.0.686",
"@defra/hapi-tracing": "^1.29.0",
"@defra/interactive-map": "^0.0.22-alpha",
"@defra/interactive-map": "^0.0.33-alpha",
"@elastic/ecs-pino-format": "^1.5.0",
"@hapi/boom": "^10.0.1",
"@hapi/bourne": "^3.0.0",
Expand Down
15 changes: 10 additions & 5 deletions src/client/javascripts/geospatial-map.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// @ts-expect-error - no types
import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
// @ts-expect-error - no types
import { maplibreLayerAdapter } from '@defra/interactive-map/plugins/datasets/adapters/maplibre'
// @ts-expect-error - no types
import createDrawPlugin from '@defra/interactive-map/plugins/draw-ml'
import { bbox } from '@turf/bbox'

Expand All @@ -13,6 +11,7 @@ import {
getCentroidGridRef,
getCoordinateGridRef
} from '~/src/client/javascripts/map.js'
import sssiDatasetPlugin from '~/src/client/javascripts/sssi-dataset.js'
import { formatDelimtedList } from '~/src/client/javascripts/utils.js'

const helpPanelConfig = {
Expand Down Expand Up @@ -173,12 +172,14 @@ export function processGeospatial(config, geospatial, index) {
const drawPlugin = createDrawPlugin()
const plugins = [drawPlugin]
const country = geospatial.dataset.country
const mapLayers = geospatial.dataset.maplayers
? geospatial.dataset.maplayers.split(',')
: []

if (country) {
// Add the country bounds as a dataset plugin to show the valid area on the map
// and provide feedback to the user when they add features outside of the bounds.
const datasetsPlugin = createDatasetsPlugin({
layerAdapter: maplibreLayerAdapter,
const countriesDatasetPlugin = createDatasetsPlugin({
datasets: [
{
id: 'invalid-area',
Expand Down Expand Up @@ -206,7 +207,11 @@ export function processGeospatial(config, geospatial, index) {
]
})

plugins.push(datasetsPlugin)
plugins.push(countriesDatasetPlugin)
}

if (mapLayers.includes('sssi')) {
plugins.push(sssiDatasetPlugin)
}

const initConfig = {
Expand Down
9 changes: 9 additions & 0 deletions src/client/javascripts/location-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
latLongToOsGridRef,
osGridRefToLatLong
} from '~/src/client/javascripts/map.js'
import sssiDatasetPlugin from '~/src/client/javascripts/sssi-dataset.js'

const LOCATION_FIELD_SELECTOR = 'input.govuk-input'

Expand Down Expand Up @@ -418,6 +419,14 @@ export function processLocation(config, location, index) {

locationInputs.after(mapContainer)

const mapLayers = location.dataset.maplayers
? location.dataset.maplayers.split(',')
: []

if (mapLayers.includes('sssi')) {
initConfig.plugins = [sssiDatasetPlugin]
}

const { map, interactPlugin } = createMap(mapId, initConfig, config)

map.on(
Expand Down
103 changes: 103 additions & 0 deletions src/client/javascripts/sssi-dataset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// @ts-expect-error - no types
import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'

const style = {
stroke: '#00897B',
fillPattern: 'diagonal-cross-hatch',
fillPatternForegroundColor: '#00897B',
fillPatternBackgroundColor: 'transparent'
}
const minZoom = 12

const englandWFS =
'https://environment.data.gov.uk/geoservices/datasets/ba8dc201-66ef-4983-9d46-7378af21027e/ogc/features/v1/collections/Sites_of_Special_Scientific_Interest_England/items?f=json'
const walesWFS =
'https://datamap.gov.wales/geoserver/wfs?service=WFS&version=2.0.0&request=GetFeature&typeNames=inspire-nrw:NRW_SSSI&outputFormat=application/json&srsName=EPSG:4326'
const scotlandWFS =
'https://services1.arcgis.com/LM9GyVFsughzHdbO/ArcGIS/rest/services/Sites_of_Special_Scientific_Interest/FeatureServer/0/query?f=geojson&where=1%3D1&geometryType=esriGeometryEnvelope&inSR=4326&spatialRel=esriSpatialRelIntersects&returnGeometry=true&outFields=*'

export default createDatasetsPlugin({
datasets: [
{
id: 'sssi-england',
label: 'Sites of Special Scientific Interest',
dynamicGeoJSON: {
url: englandWFS,
idProperty: 'ref_code',
/**
* @type {TransformRequestArgs}
*/
transformRequest: (url, { bbox }) => {
const uri = new URL(url)
uri.searchParams.set('bbox', bbox.join(','))

return {
url: uri.toString()
}
}
},
minZoom,
style,
showInKey: true,
showInMenu: false
},
{
id: 'sssi-wales',
label: 'SSSI Wales',
dynamicGeoJSON: {
url: walesWFS,
idProperty: 'id',
/**
* @type {TransformRequestArgs}
*/
transformRequest: (url, { bbox }) => {
const uri = new URL(url)
uri.searchParams.set('bbox', `${bbox.join(',')},EPSG:4326`)

return {
url: uri.toString()
}
}
},
minZoom,
style,
showInKey: false,
showInMenu: false
},
{
id: 'sssi-scotland',
label: 'SSSI Scotland',
dynamicGeoJSON: {
url: scotlandWFS,
idProperty: 'OBJECTID',
/**
* @type {TransformRequestArgs}
*/
transformRequest: (url, { bbox }) => {
const uri = new URL(url)
uri.searchParams.set('geometry', bbox.join(','))

return {
url: uri.toString()
}
}
},
minZoom,
style,
showInKey: false,
showInMenu: false
}
]
})

/**
* @typedef {object} TransformRequestOptions
* @property {string[]} bbox - the bounding box coordinates
*/

/**
* Transforms the request URL with bounding box parameters
* @callback TransformRequestArgs
* @param {string} url - the request URL
* @param {TransformRequestOptions} options - the bounding box coordinates
*/
2 changes: 0 additions & 2 deletions src/client/stylesheets/shared.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
@use "location-fields";

@use "@defra/interactive-map/css" as core;
@use "@defra/interactive-map/plugins/interact/css" as interact;
@use "@defra/interactive-map/plugins/map-styles/css" as mapStyles;
@use "@defra/interactive-map/plugins/search/css" as search;
@use "@defra/interactive-map/plugins/scale-bar/css" as scaleBar;
@use "@defra/interactive-map/plugins/draw-ml/css" as drawMl;

// Use default GDS Transport font for autocomplete
.autocomplete__hint,
Expand Down
2 changes: 2 additions & 0 deletions src/server/plugins/engine/components/GeospatialField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
FormComponent,
isGeospatialState
} from '~/src/server/plugins/engine/components/FormComponent.js'
import { getMapLayers } from '~/src/server/plugins/engine/components/LocationFieldHelpers.js'
import { getGeospatialSchema } from '~/src/server/plugins/engine/components/helpers/geospatial.js'
import { messageTemplate } from '~/src/server/plugins/engine/pageControllers/validationOptions.js'
import {
Expand Down Expand Up @@ -97,6 +98,7 @@ export class GeospatialField extends FormComponent {
...viewModel,
country: this.options.countries?.at(0),
geometryTypes: this.options.geometryTypes,
mapLayers: getMapLayers(this),
value
}
}
Expand Down
19 changes: 18 additions & 1 deletion src/server/plugins/engine/components/LocationFieldHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import { type EastingNorthingField } from '~/src/server/plugins/engine/components/EastingNorthingField.js'
import { isFormValue } from '~/src/server/plugins/engine/components/FormComponent.js'
import { type GeospatialField } from '~/src/server/plugins/engine/components/GeospatialField.js'
import { type LatLongField } from '~/src/server/plugins/engine/components/LatLongField.js'
import { type OsGridRefField } from '~/src/server/plugins/engine/components/OsGridRefField.js'
import {
type DateInputItem,
type Label,
Expand Down Expand Up @@ -86,6 +88,20 @@
)
}

export function getMapLayers(
component:
| GeospatialField
| OsGridRefField
| LatLongField
| EastingNorthingField
) {
return component.options.mapLayers
? Object.keys(component.options.mapLayers)

Check failure on line 99 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 23)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.

Check failure on line 99 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 24)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.

Check failure on line 99 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 22)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.
.filter((key) => component.options.mapLayers[key] === true)

Check failure on line 100 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 23)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.

Check failure on line 100 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 24)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.

Check failure on line 100 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 22)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.
.join(',')

Check failure on line 101 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 23)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.

Check failure on line 101 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 24)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.

Check failure on line 101 in src/server/plugins/engine/components/LocationFieldHelpers.ts

View workflow job for this annotation

GitHub Actions / Build (Node 22)

Property 'mapLayers' does not exist on type '({ required?: boolean | undefined; optionalText?: boolean | undefined; classes?: string | undefined; customValidationMessages?: LanguageMessages | undefined; instructionText?: string | undefined; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; }) | ({ ...; } & { ...; })'.
: ''
}

export function getLocationFieldViewModel(
component: LocationField,
viewModel: ViewModel & {
Expand Down Expand Up @@ -167,7 +183,8 @@
const result = {
...viewModel,
fieldset,
items
items,
mapLayers: getMapLayers(component)
}

if (component.options.instructionText) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@

{% set hasErrors = showFieldsetError and component.model.errorMessage %}

<div class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}" data-locationtype="{{component.type | lower}}">
<div class="govuk-form-group app-location-field {{ "govuk-form-group--error" if hasErrors }}"
data-locationtype="{{component.type | lower}}"
data-maplayers="{{component.model.mapLayers}}">
{{ govukFieldset({
legend: {
text: component.model.fieldset.legend.text,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{% from "govuk/components/textarea/macro.njk" import govukTextarea %}

{% macro GeospatialField(component) %}
<div class="app-geospatial-field" data-country="{{component.model.country}}" data-geometryTypes="{{component.model.geometryTypes}}">
<div class="app-geospatial-field"
data-country="{{component.model.country}}"
data-geometryTypes="{{component.model.geometryTypes}}"
data-maplayers="{{component.model.mapLayers}}">
{{ govukTextarea(component.model) }}
</div>
{% endmacro %}
2 changes: 1 addition & 1 deletion src/server/plugins/map/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,5 @@ function getGeospatialCountries() {
/**
* @import { ServerRoute } from '@hapi/hapi'
* @import { FeatureCollection } from 'geojson'
* @import { MapConfiguration, MapProxyGetRequestRefs, MapGeocodeGetRequestRefs, MapReverseGeocodeGetRequestRefs, GeospatialCountriesGetRequestRefs } from '~/src/server/plugins/map/types.js'
* @import { MapConfiguration, MapProxyGetRequestRefs, MapGeocodeGetRequestRefs, GeospatialCountriesGetRequestRefs } from '~/src/server/plugins/map/types.js'
*/
17 changes: 1 addition & 16 deletions src/server/plugins/map/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@
* @property {string} query - name query
*/

/**
* Map reverse geocode query params
* @typedef {object} MapReverseGeocodeQuery
* @property {number} easting - the Easting point
* @property {number} northing - the Northing point
*/

/**
* Geospatial countries query params
* @typedef {object} GeospatialCountriesQuery
Expand All @@ -47,12 +40,6 @@
* @property {MapGeocodeQuery} Query - Request query
*/

/**
* Map reverse geocode get request
* @typedef {object} MapReverseGeocodeGetRequestRefs
* @property {MapReverseGeocodeQuery} Query - Request query
*/

/**
* Map countries geojson get request
* @typedef {object} GeospatialCountriesGetRequestRefs
Expand All @@ -62,11 +49,9 @@
/**
* @typedef {MapProxyGetRequestRefs} MapProxyRequestRefs
* @typedef {MapGeocodeGetRequestRefs} MapGeocodeRequestRefs
* @typedef {MapReverseGeocodeGetRequestRefs} MapReverseGeocodeRequestRefs
* @typedef {Request<MapGeocodeGetRequestRefs>} MapProxyGetRequest
* @typedef {Request<MapGeocodeGetRequestRefs>} MapGeocodeGetRequest
* @typedef {Request<MapReverseGeocodeGetRequestRefs>} MapReverseGeocodeGetRequest
* @typedef {MapProxyGetRequest | MapGeocodeGetRequest | MapReverseGeocodeGetRequest} MapRequest
* @typedef {MapProxyGetRequest | MapGeocodeGetRequest } MapRequest
*/

//
Expand Down
Loading