Skip to main content

alphaThis is a new frontend component. Help us improve it and give your feedback on Slack.

Datasets Plugin

The datasets plugin renders GeoJSON and vector tile datasets on the map, with support for sublayer style rules, layer visibility toggling, a key panel, and runtime style and data updates.

Usage

import createDatasetsPlugin from '@defra/interactive-map/plugins/beta/datasets'
import { maplibreLayerAdapter } from '@defra/interactive-map/plugins/beta/datasets/adapters/maplibre'
const datasetsPlugin = createDatasetsPlugin({
layerAdapter: maplibreLayerAdapter,
datasets: [
{
id: 'my-parcels',
label: 'My parcels',
geojson: 'https://example.com/api/parcels',
minZoom: 10,
maxZoom: 24,
showInKey: true,
toggleVisibility: true,
style: {
stroke: '#d4351c',
strokeWidth: 2,
fill: 'transparent'
}
}
]
})
const interactiveMap = new InteractiveMap({
plugins: [datasetsPlugin]
})

Options

Options are passed to the factory function when creating the plugin.


layerAdapter

Type: LayerAdapter Required

The map provider adapter responsible for rendering datasets. Import maplibreLayerAdapter for MapLibre GL JS, or supply a custom adapter.

import { maplibreLayerAdapter } from '@defra/interactive-map/plugins/beta/datasets/adapters/maplibre'

datasets

Type: Dataset[] Required

Array of dataset configurations to render on the map. See Dataset configuration below.


includeModes

Type: string[]

When set, the plugin only initialises when the app is in one of the specified modes.


excludeModes

Type: string[]

When set, the plugin does not initialise when the app is in one of the specified modes.


Dataset configuration

Each entry in the datasets array describes one data source and how it should be rendered.


id

Type: string Required

Unique identifier for the dataset. Used in all API method calls.


label

Type: string

Human-readable name shown in the Layers panel and Key panel.


geojson

Type: string | GeoJSON.FeatureCollection

GeoJSON source. Provide a URL string for remote data, or a GeoJSON object for inline data. Use alongside transformRequest to add authentication or append bbox parameters to the request.


tiles

Type: string[]

Array of vector tile URL templates (e.g. https://example.com/tiles/{z}/{x}/{y}). When set, the dataset uses a vector tile source instead of GeoJSON.


sourceLayer

Type: string

The layer name within the vector tile source to render. Required when using tiles.


transformRequest

Type: Function

A function called before each fetch to transform the request. Its primary purpose is to attach authentication credentials — API keys, OAuth tokens, or other headers. It also receives the current viewport context so you can append bbox or zoom parameters to the URL if your API supports spatial filtering.

The plugin handles all dynamic fetching concerns (viewport tracking, debouncing, deduplication, caching, request cancellation) — transformRequest only needs to return the final URL and any headers.

Signature: transformRequest(url, { bbox, zoom, dataset })

ArgumentTypeDescription
urlstringThe base URL from geojson
bboxnumber[]Current viewport bounds as [west, south, east, north]
zoomnumberCurrent map zoom level
datasetObjectThe full dataset configuration

Return either a plain URL string or an object { url, headers }. The object form is needed when attaching auth headers.

// Auth headers only (no bbox filtering)
transformRequest: (url) => ({
url,
headers: { Authorization: `Bearer ${getToken()}` }
})
// Append bbox to URL for server-side spatial filtering
transformRequest: (url, { bbox }) => {
const separator = url.includes('?') ? '&' : '?'
return { url: `${url}${separator}bbox=${bbox.join(',')}` }
}
// Both — auth + bbox
transformRequest: (url, { bbox }) => {
const separator = url.includes('?') ? '&' : '?'
return {
url: `${url}${separator}bbox=${bbox.join(',')}`,
headers: { Authorization: `Bearer ${getToken()}` }
}
}

idProperty

Type: string

Property name used to uniquely identify features. Required alongside transformRequest to enable dynamic bbox-based fetching — the plugin uses it internally to deduplicate features across successive viewport fetches.


filter

Type: FilterExpression

A MapLibre filter expression applied to the dataset's map layers. Features not matching the filter are not rendered.

filter: ['==', ['get', 'status'], 'active']

minZoom

Type: number Default: 6

Minimum zoom level at which the dataset is visible.


maxZoom

Type: number Default: 24

Maximum zoom level at which the dataset is visible.


maxFeatures

Type: number

Only applies to dynamic sources (those using transformRequest). Caps the number of features held in memory across all viewport fetches — older out-of-viewport features are evicted when the limit is exceeded. Omit for small or bounded datasets; set it when users are likely to pan extensively over a large dataset.


visibility

Type: 'visible' | 'hidden' Default: 'visible'

Initial visibility of the dataset.


showInKey

Type: boolean Default: false

When true, the dataset appears in the Key panel with its style symbol and label.


toggleVisibility

Type: boolean Default: false

When true, the dataset appears in the Layers panel and can be toggled on and off by the user.


groupLabel

Type: string

Groups this dataset with others sharing the same groupLabel in the Layers panel, rendering them as a single collapsible group.


keySymbolShape

Type: 'polygon' | 'line'

Overrides the shape used to render the key symbol for this dataset. Defaults to a polygon shape.


style

Type: Object

Visual style for the dataset. All style properties must be nested within this object.

PropertyTypeDescription
strokestring | Record<string, string>Stroke (outline) colour. Accepts a plain colour string or a map-style-keyed object e.g. { outdoor: '#ff0000', dark: '#ffffff' }
strokeWidthnumberStroke width in pixels. Default: 2
strokeDashArraynumber[]Dash pattern for the stroke e.g. [4, 2]
fillstring | Record<string, string>Fill colour. Use 'transparent' for no fill
fillPatternstringNamed fill pattern e.g. 'diagonal-cross-hatch', 'horizontal-hatch', 'dot', 'vertical-hatch'
fillPatternSvgContentstringRaw SVG content for a custom fill pattern
fillPatternForegroundColorstring | Record<string, string>Foreground colour for the fill pattern
fillPatternBackgroundColorstring | Record<string, string>Background colour for the fill pattern
opacitynumberLayer opacity from 0 to 1
symbolDescriptionstring | Record<string, string>Accessible description of the symbol shown in the key
keySymbolShape'polygon' | 'line'Shape used for the key symbol
style: {
stroke: { outdoor: '#d4351c', dark: '#ffffff' },
strokeWidth: 2,
fill: 'rgba(212,53,28,0.1)',
symbolDescription: { outdoor: 'Red outline' }
}

sublayers

Type: Sublayer[]

Array of sublayer rules that partition the dataset into visually distinct groups based on feature filters. Each sublayer is rendered as a separate pair of map layers.

Sublayers inherit the parent dataset's style and only override what they specify. Fill precedence (highest to lowest): sublayer's own fillPattern → sublayer's own fill → parent's fillPattern → parent's fill.

Sublayer properties

PropertyTypeDescription
idstringRequired. Unique identifier within the dataset
labelstringHuman-readable name shown in the Layers and Key panels
filterFilterExpressionMapLibre filter expression to match features for this sublayer
styleObjectStyle overrides for this sublayer. Accepts the same properties as the dataset style object
showInKeybooleanShows this sublayer in the Key panel. Inherits from dataset if not set
toggleVisibilitybooleanShows this sublayer in the Layers panel. Default: false
sublayers: [
{
id: 'active',
label: 'Active parcels',
filter: ['==', ['get', 'status'], 'active'],
toggleVisibility: true,
style: {
stroke: '#00703c',
fill: 'rgba(0,112,60,0.1)',
symbolDescription: 'Green outline'
}
},
{
id: 'inactive',
label: 'Inactive parcels',
filter: ['==', ['get', 'status'], 'inactive'],
toggleVisibility: true,
style: {
stroke: '#d4351c',
fillPattern: 'diagonal-cross-hatch',
fillPatternForegroundColor: '#d4351c'
}
}
]

Methods

Methods are called on the plugin instance after the datasets:ready event.

The API follows a consistent pattern: the primary value is the first argument, with an optional scope object as the second argument. Omitting the scope applies the operation globally where supported.


addDataset(dataset)

Add a new dataset to the map at runtime.

ArgumentTypeDescription
datasetDatasetDataset configuration object. Accepts the same properties as datasets array entries
interactiveMap.on('datasets:ready', () => {
datasetsPlugin.addDataset({
id: 'new-layer',
geojson: 'https://example.com/api/features',
minZoom: 10,
style: { stroke: '#0000ff' }
})
})

removeDataset(datasetId)

Remove a dataset from the map.

ArgumentTypeDescription
datasetIdstringID of the dataset to remove
datasetsPlugin.removeDataset('my-parcels')

setDatasetVisibility(visible, scope?)

Set the visibility of datasets or sublayers. Omit scope to apply to all datasets globally.

When showing a dataset that has sublayers, any sublayers that were individually hidden before the dataset was hidden will remain hidden — their individual visibility state is preserved.

ArgumentTypeDescription
visiblebooleantrue to show, false to hide
scope.datasetIdstringOptional. When omitted, applies to all datasets
scope.sublayerIdstringOptional. When provided alongside datasetId, targets a single sublayer
// Global — all datasets
datasetsPlugin.setDatasetVisibility(false)
datasetsPlugin.setDatasetVisibility(true)
// Single dataset
datasetsPlugin.setDatasetVisibility(false, { datasetId: 'my-parcels' })
// Single sublayer
datasetsPlugin.setDatasetVisibility(false, { datasetId: 'my-parcels', sublayerId: 'active' })

setFeatureVisibility(visible, featureIds, scope)

Show or hide specific features within a dataset without removing them from the source.

ArgumentTypeDescription
visiblebooleantrue to show, false to hide
featureIds(string | number)[]IDs of the features to target
scope.datasetIdstringID of the dataset
scope.idPropertystring | nullProperty name to match features on. Pass null to match against the top-level feature.id
// Hide by a feature property
datasetsPlugin.setFeatureVisibility(false, [123, 456], {
datasetId: 'my-parcels',
idProperty: 'parcel_id'
})
// Show using feature.id
datasetsPlugin.setFeatureVisibility(true, [123, 456], {
datasetId: 'my-parcels',
idProperty: null
})

setStyle(style, scope)

Update the visual style of a dataset or sublayer at runtime. When targeting a sublayer, only the properties specified are overridden — the sublayer inherits all other styles from the parent dataset.

ArgumentTypeDescription
styleObjectStyle properties to apply. Accepts the same properties as dataset.style
scope.datasetIdstringID of the dataset
scope.sublayerIdstringOptional. When provided, targets a single sublayer
// Dataset level
datasetsPlugin.setStyle(
{ stroke: '#0000ff', strokeWidth: 3 },
{ datasetId: 'my-parcels' }
)
// Sublayer level
datasetsPlugin.setStyle(
{ stroke: '#00703c', fillPattern: 'diagonal-cross-hatch', fillPatternForegroundColor: '#00703c' },
{ datasetId: 'my-parcels', sublayerId: 'active' }
)

getStyle(scope)

Returns the current style object for a dataset or sublayer, or null if not found.

ArgumentTypeDescription
scope.datasetIdstringID of the dataset
scope.sublayerIdstringOptional. When provided, returns the sublayer's style
// Dataset style
const style = datasetsPlugin.getStyle({ datasetId: 'my-parcels' })
// Sublayer style
const style = datasetsPlugin.getStyle({ datasetId: 'my-parcels', sublayerId: 'active' })

setOpacity(opacity, scope?)

Set the opacity of datasets or a sublayer. Safe to call on every tick from a slider — uses setPaintProperty internally rather than removing and re-adding layers. Omit scope to apply globally.

ArgumentTypeDescription
opacitynumberOpacity from 0 (transparent) to 1 (fully opaque)
scope.datasetIdstringOptional. When omitted, applies to all datasets
scope.sublayerIdstringOptional. When provided alongside datasetId, targets a single sublayer
// Global — all datasets
datasetsPlugin.setOpacity(0.5)
// Single dataset
datasetsPlugin.setOpacity(0.5, { datasetId: 'my-parcels' })
// Single sublayer
datasetsPlugin.setOpacity(0.5, { datasetId: 'my-parcels', sublayerId: 'active' })

getOpacity(scope?)

Returns the current opacity for a dataset or sublayer. When called without arguments, returns the first dataset's opacity — useful for initialising a global slider. Returns null if not found.

ArgumentTypeDescription
scope.datasetIdstringOptional. When omitted, returns the first dataset's opacity
scope.sublayerIdstringOptional. When provided alongside datasetId, returns the sublayer's opacity
// Global — read back after setOpacity() for slider initialisation
const opacity = datasetsPlugin.getOpacity()
// Single dataset
const opacity = datasetsPlugin.getOpacity({ datasetId: 'my-parcels' })
// Single sublayer
const opacity = datasetsPlugin.getOpacity({ datasetId: 'my-parcels', sublayerId: 'active' })

setData(geojson, scope)

Replace the GeoJSON data for a dataset source. Has no effect on vector tile datasets.

ArgumentTypeDescription
geojsonGeoJSON.FeatureCollectionNew GeoJSON data
scope.datasetIdstringID of the dataset
datasetsPlugin.setData(
{ type: 'FeatureCollection', features: [...] },
{ datasetId: 'my-parcels' }
)

Events

Subscribe to events using interactiveMap.on().


datasets:ready

Emitted once all datasets have been initialised and rendered on the map.

Payload: None

interactiveMap.on('datasets:ready', () => {
console.log('Datasets are ready')
// Safe to call API methods from here
const style = datasetsPlugin.getStyle({ datasetId: 'my-parcels' }) // unchanged — scope object
})