diff --git a/client/js/map/colours.js b/client/js/map/colours.js
index 8be7888c..dc019fc0 100644
--- a/client/js/map/colours.js
+++ b/client/js/map/colours.js
@@ -25,10 +25,10 @@ export const COLOURS = {
floodZone3: { default: '#003078', dark: '#e5f5e0' },
floodZone2: { default: '#1d70b8', dark: '#41ab5d' },
- floodZoneClimateChange: { default: '#F4A582', dark: '#BF3D4A' },
+ floodZoneClimateChange: { default: floodZoneCCLight, dark: floodZoneCCDark },
floodZoneClimateChangeNoData: { default: darkTeal, dark: white },
- floodDefences: { default: '#f47738', dark: '#f47738' },
+ floodDefences: { default: floodDefences, dark: floodDefences },
waterStorageAreas: { default: darkTeal, dark: white },
mainRivers: { default: darkTeal, dark: white }
}
@@ -39,7 +39,16 @@ const nonFloodZoneDepthBandsLight = [COLOURS.depthOver2300.default, COLOURS.dept
const nonFloodZoneDepthBandsDark = [COLOURS.depthOver2300.dark, COLOURS.depth2300.dark, COLOURS.depth1200.dark, COLOURS.depth900.dark, COLOURS.depth600.dark, COLOURS.depth300.dark, COLOURS.depth150.dark]
export const colours = { // [default, dark]
+ nonFloodZoneLight,
+ nonFloodZoneDark,
nonFloodZone: [nonFloodZoneLight, nonFloodZoneDark],
+ depthOver2300: { default: '#7f2704', dark: '#238b45' },
+ depth2300: { default: '#a63603', dark: '#41ab5d' },
+ depth1200: { default: '#d94801', dark: '#74c476' },
+ depth900: { default: '#f16913', dark: '#a1d99b' },
+ depth600: { default: '#fd8d3c', dark: '#c7e9c0' },
+ depth300: { default: '#fdae6b', dark: '#e5f5e0' },
+ depth150: { default: '#fdd0a2', dark: '#f7fcf5' },
nonFloodZoneDepthBands: [
[nonFloodZoneDepthBandsLight[0], nonFloodZoneDepthBandsDark[0]],
[nonFloodZoneDepthBandsLight[1], nonFloodZoneDepthBandsDark[1]],
@@ -53,9 +62,9 @@ export const colours = { // [default, dark]
floodZone3: [floodZone3Light, floodZone3Dark],
floodZoneClimateChange: [floodZoneCCLight, floodZoneCCDark],
floodZoneClimateChangeNoData: [black, white],
- waterStorageAreas: [darkTeal, white],
- mainRivers: [darkTeal, white],
- floodDefences: [floodDefences, floodDefences],
+ waterStorageAreas: { default: darkTeal, dark: white },
+ mainRivers: { default: darkTeal, dark: white },
+ floodDefences: { default: floodDefences, dark: floodDefences },
floodExtents: [nonFloodZoneLight, nonFloodZoneDark]
}
diff --git a/client/js/map/datasets/datasetsMenu.js b/client/js/map/datasets/datasetsMenu.js
new file mode 100644
index 00000000..98c220f1
--- /dev/null
+++ b/client/js/map/datasets/datasetsMenu.js
@@ -0,0 +1,72 @@
+export const menu = [
+ {
+ id: 'dataset',
+ label: 'Datasets',
+ urlKey: 'dataset',
+ visibleWhen: true,
+ type: 'radio', // 'checkbox' or 'radio'
+ value: 'floodzones', // this is the default value for the menu, it should be one of the items' id
+ items: [
+ { id: 'floodzones', label: 'Flood zones' },
+ { id: 'surfacewater', label: 'Surface water' },
+ { id: 'none', label: 'None', },
+ ],
+ },
+ {
+ id: 'timeframe',
+ label: 'Timeframe',
+ urlKey: 'dataset',
+ urlIndex: 1, // eg: surfacewater-presentday-high-depth or floodzones-climatechange
+ type: 'radio',
+ visibleWhen: { menu: { dataset: ['floodzones', 'surfacewater'] } },
+ value: 'presentday',
+ items: [
+ { id: 'presentday', label: 'Present day' },
+ { id: 'climatechange', label: '2070 to 2125', visibleWhen: { menu: { dataset: ['floodzones'] } } },
+ { id: 'climatechange', label: '2061 to 2125', visibleWhen: { menu: { dataset: ['surfacewater'] } } },
+ ]
+ }, {
+ id: 'aep',
+ label: 'Annual likelihood of flooding',
+ urlKey: 'dataset',
+ urlIndex: 2,
+ type: 'radio',
+ visibleWhen: { menu: { dataset: ['surfacewater'] } },
+ value: 'medium',
+ items: [
+ { id: 'high', label: '1 in 30' },
+ { id: 'medium', label: '1 in 100' },
+ { id: 'low', label: '1 in 1000' },
+ ]
+ }, {
+ id: 'depth',
+ label: 'Depth',
+ urlKey: 'dataset',
+ urlIndex: 3,
+ type: 'radio',
+ visibleWhen: { menu: { dataset: ['surfacewater'] } },
+ subMenu: true,
+ value: 'depthAll',
+ items: [
+ { id: 'depthAll', label: 'All depths', },
+ { id: 'depth150', label: 'Full extent of flooding', },
+ { id: 'depth300', label: 'Extent over 150mm', },
+ { id: 'depth600', label: 'Extent over 300mm', },
+ { id: 'depth900', label: 'Extent over 600mm', },
+ { id: 'depth1200', label: 'Extent over 900mm', },
+ { id: 'depth2300', label: 'Extent over 1200mm', },
+ { id: 'depthOver2300', label: 'Extent over 2300mm', },
+ ]
+ }, {
+ id: 'features',
+ groupLabel: 'Map features',
+ urlKey: 'features',
+ type: 'checkbox',
+ visibleWhen: true,
+ items: [
+ { id: 'waterstorage', label: 'Water storage' },
+ { id: 'flooddefence', label: 'Flood defence' },
+ { id: 'mainrivers', label: 'Main rivers' },
+ ]
+ }
+]
diff --git a/client/js/map/datasets/datasetsPlugin.js b/client/js/map/datasets/datasetsPlugin.js
new file mode 100644
index 00000000..bfbde3a0
--- /dev/null
+++ b/client/js/map/datasets/datasetsPlugin.js
@@ -0,0 +1,37 @@
+import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
+import { surfaceWaterDatasets, surfaceWaterExtentsKey } from './surfaceWater.js'
+import { floodZonesDatasets } from './floodZones.js'
+import { featureLayers } from './featureLayers.js'
+import { menu } from './datasetsMenu.js'
+
+export const datasetsPlugin = ({ agolServiceUrl, agolVectorTileUrl, layerNameSuffix }) => {
+ const datasets = [
+ ...floodZonesDatasets({ agolVectorTileUrl, layerNameSuffix }),
+ surfaceWaterExtentsKey,
+ ...surfaceWaterDatasets({ agolVectorTileUrl, layerNameSuffix }),
+ ...featureLayers(agolServiceUrl, layerNameSuffix),
+ ]
+
+ return createDatasetsPlugin({
+ manifest: {
+ panels: [{
+ id: 'datasetsLayers',
+ desktop: { open: true, slot: 'side', width: '280px', dismissible: false },
+ tablet: { slot: 'side', width: '280px', modal: true }
+ }],
+ buttons: [
+ {
+ id: 'datasetsLayers',
+ excludeWhen: ({ appState }) => (appState?.breakpoint === 'desktop'),
+ }
+ ]
+ },
+ globals: {
+ opacityMode: 'global',
+ opacity: 0.75,
+ visible: true
+ },
+ datasets,
+ menu
+ })
+}
diff --git a/client/js/map/datasets/featureLayers.js b/client/js/map/datasets/featureLayers.js
new file mode 100644
index 00000000..e2ed6a1b
--- /dev/null
+++ b/client/js/map/datasets/featureLayers.js
@@ -0,0 +1,82 @@
+import { terms } from '../terms.js'
+import { colours } from '../colours.js'
+
+export const featureLayers = (agolServiceUrl, layerNameSuffix) => {
+ const datasetMainRivers = {
+ id: 'mainrivers',
+ label: terms.labels.mainRivers,
+ groupLabel: terms.labels.mapFeatures,
+ type: 'FeatureService',
+ // NOTE: Main Rivers does not have the _NON_PRODUCTION ${layerNameSuffix}
+ tiles: `${agolServiceUrl}/Statutory_Main_River_Map/FeatureServer`,
+ showInKey: true,
+ sourceLayer: 'Statutory_Main_River_Map',
+ visible: false,
+ style: {
+ renderer: {
+ type: 'simple',
+ symbol: {
+ type: 'simple-line',
+ width: '3px',
+ color: { outdoor: colours.mainRivers.default, dark: colours.mainRivers.dark },
+ }
+ },
+ stroke: { outdoor: colours.mainRivers.default, dark: colours.mainRivers.dark },
+ strokeWidth: 3
+ }
+ }
+
+ const datasetWaterStorageAreas = {
+ id: 'waterstorage',
+ label: terms.labels.waterStorage,
+ groupLabel: terms.labels.mapFeatures,
+ type: 'FeatureService',
+ tiles: `${agolServiceUrl}/Flood_Storage_Areas${layerNameSuffix}/FeatureServer`,
+ showInKey: true,
+ sourceLayer: 'Flood_Storage_Areas',
+ visible: false,
+ style: {
+ renderer: {
+ type: 'simple',
+ symbol: {
+ type: 'simple-fill',
+ style: 'diagonal-cross',
+ color: { outdoor: colours.waterStorageAreas.default, dark: colours.waterStorageAreas.dark },
+ outline: {
+ color: { outdoor: colours.waterStorageAreas.default, dark: colours.waterStorageAreas.dark },
+ width: 1
+ }
+ }
+ },
+ stroke: { outdoor: colours.waterStorageAreas.default, dark: colours.waterStorageAreas.dark },
+ strokeWidth: 1,
+ fillPattern: 'diagonal-cross-hatch',
+ fillPatternForegroundColor: { outdoor: colours.waterStorageAreas.default, dark: colours.waterStorageAreas.dark },
+ fillPatternBackgroundColor: 'transparent'
+ }
+ }
+
+ const datasetFloodDefences = {
+ id: 'flooddefence',
+ label: terms.labels.floodDefence,
+ groupLabel: terms.labels.mapFeatures,
+ type: 'FeatureService',
+ tiles: `${agolServiceUrl}/Defences${layerNameSuffix}/FeatureServer`,
+ showInKey: true,
+ sourceLayer: 'Defences',
+ visible: false,
+ style: {
+ renderer: {
+ type: 'simple',
+ symbol: {
+ type: 'simple-line',
+ width: '3px',
+ color: { outdoor: colours.floodDefences.default, dark: colours.floodDefences.dark },
+ }
+ },
+ stroke: { outdoor: colours.floodDefences.default, dark: colours.floodDefences.dark },
+ strokeWidth: 3
+ }
+ }
+ return [datasetMainRivers, datasetWaterStorageAreas, datasetFloodDefences]
+}
diff --git a/client/js/map/datasets/floodZones.js b/client/js/map/datasets/floodZones.js
new file mode 100644
index 00000000..28aedc68
--- /dev/null
+++ b/client/js/map/datasets/floodZones.js
@@ -0,0 +1,110 @@
+export const floodZonesDatasets = ({ agolVectorTileUrl, layerNameSuffix }) => {
+ const datasetFloodZonesCC = {
+ id: 'floodzonescc',
+ label: 'Flood Zones Climate Change',
+ groupLabel: 'Datasets',
+ esriGroupId: 'floodzones-group',
+ tiles: `${agolVectorTileUrl}/Flood_Zones_2_and_3_Rivers_and_Sea_CCP1${layerNameSuffix}/VectorTileServer`,
+ showInKey: true,
+ visible: true,
+ sourceLayer: 'Flood Zones 2 and 3 Rivers and Sea CCP1',
+ visibleWhen: { menu: { dataset: ['floodzones'] } },
+ sublayers: [
+ {
+ id: 'climate-change',
+ label: 'Climate change (2070 to 2125)',
+ esriStyleLayerId: 'Flood Zones 2 and 3 Rivers and Sea CCP1/Flood Zones plus climate change/1',
+ showInKey: true,
+ visibleWhen: {
+ menu: {
+ dataset: ['floodzones'], timeframe: ['climatechange']
+ }
+ },
+ style: {
+ fill: { outdoor: '#F4A582', dark: '#BF3D4A' },
+ stroke: 'none'
+ },
+ },
+ {
+ id: 'data-unavailable',
+ label: 'Climate change data unavailable',
+ showInKey: true,
+ visibleWhen: {
+ menu: {
+ dataset: ['floodzones'], timeframe: ['climatechange']
+ }
+ },
+ style: { // This is used just for the key - so that it renders the pattern correctly.
+ fillPattern: 'dot',
+ fillPatternForegroundColor: { outdoor: '#000000', dark: '#ffffff' },
+ stroke: { outdoor: '#000000', dark: '#FFFFFF' },
+ }
+ },
+ {
+ id: 'data-unavailable-outline',
+ showInKey: false,
+ visibleWhen: {
+ menu: { dataset: ['floodzones'], timeframe: ['climatechange'] }
+ },
+ style: {
+ stroke: { outdoor: '#000000', dark: '#FFFFFF' },
+ },
+ esriStyleLayerId: 'Flood Zones 2 and 3 Rivers and Sea CCP1/Unavailable/0'
+ },
+ {
+ id: 'data-unavailable-light',
+ visibleWhen: {
+ mapStyleId: ['outdoor', 'black-and-white'],
+ menu: { dataset: ['floodzones'], timeframe: ['climatechange'] }
+ },
+ esriStyleLayerId: 'Flood Zones 2 and 3 Rivers and Sea CCP1/Unavailable/1',
+ esriUseServerStyle: true,
+ showInKey: false,
+ },
+ {
+ id: 'data-unavailable-dark',
+ visibleWhen: {
+ menu: { dataset: ['floodzones'], timeframe: ['climatechange'] },
+ mapStyleId: ['dark']
+ },
+ esriStyleLayerId: 'Flood Zones 2 and 3 Rivers and Sea CCP1/Unavailable/2',
+ esriUseServerStyle: true,
+ showInKey: false,
+ }
+ ]
+ }
+
+ const datasetFloodZones = {
+ id: 'floodzones',
+ label: 'Flood Zones',
+ groupLabel: 'Datasets',
+ esriGroupId: 'floodzones-group',
+ tiles: `${agolVectorTileUrl}/Flood_Zones_2_and_3_Rivers_and_Sea${layerNameSuffix}/VectorTileServer`,
+ showInKey: true,
+ sourceLayer: 'Flood Zones 2 and 3 Rivers and Sea',
+ visibleWhen: {
+ menu: { dataset: ['floodzones'] }
+ },
+ sublayers: [
+ {
+ id: 'flood-zone-2',
+ label: 'Flood Zone 2',
+ esriStyleLayerId: 'Flood Zones 2 and 3 Rivers and Sea/Flood Zone 2/1',
+ style: {
+ fill: { outdoor: '#1d70b8', dark: '#7fcdbb' },
+ stroke: 'none'
+ },
+ },
+ {
+ id: 'flood-zone-3',
+ label: 'Flood Zone 3',
+ esriStyleLayerId: 'Flood Zones 2 and 3 Rivers and Sea/Flood Zone 3/1',
+ style: {
+ fill: { outdoor: '#003078', dark: '#e5f5e0' },
+ stroke: 'none'
+ },
+ }
+ ]
+ }
+ return [datasetFloodZonesCC, datasetFloodZones]
+}
diff --git a/client/js/map/datasets/surfaceWater.js b/client/js/map/datasets/surfaceWater.js
new file mode 100644
index 00000000..74684a48
--- /dev/null
+++ b/client/js/map/datasets/surfaceWater.js
@@ -0,0 +1,133 @@
+import { terms } from '../terms.js'
+import { colours } from '../colours.js'
+import { surfaceWaterDatasetGenerator } from './surfaceWaterDatasetGenerator.js'
+
+export const surfaceWaterDatasets = ({ agolVectorTileUrl, layerNameSuffix }) => {
+ const datasets = [
+ // Surface Water Present Day
+ ...surfaceWaterDatasetGenerator({
+ agolVectorTileUrl,
+ layerNameSuffix,
+ id: 'surfacewater-presentday-low',
+ tileName: 'Surface_Water_Spatial_Planning_1_in_1000_Depths',
+ sourceLayer: 'Surface Water Spatial Planning 1 in 1000 Depths',
+ timeframe: ['presentday'],
+ aep: ['low'],
+ }),
+
+ ...surfaceWaterDatasetGenerator({
+ agolVectorTileUrl,
+ layerNameSuffix,
+ id: 'surfacewater-presentday-medium',
+ tileName: 'Surface_Water_Spatial_Planning_1_in_100_Depths',
+ sourceLayer: 'Surface Water Spatial Planning 1 in 100 Depths',
+ timeframe: ['presentday'],
+ aep: ['medium'],
+ }),
+
+ ...surfaceWaterDatasetGenerator({
+ agolVectorTileUrl,
+ layerNameSuffix,
+ id: 'surfacewater-presentday-high',
+ tileName: 'Surface_Water_Spatial_Planning_1_in_30_Depths',
+ sourceLayer: 'Surface Water Spatial Planning 1 in 30 Depths',
+ timeframe: ['presentday'],
+ aep: ['high'],
+ }),
+
+ // Surface Water Climate Change
+ ...surfaceWaterDatasetGenerator({
+ agolVectorTileUrl,
+ layerNameSuffix,
+ id: 'surfacewater-climatechange-low',
+ tileName: 'Surface_Water_Spatial_Planning_1_in_1000_CCP1_Depths',
+ sourceLayer: 'Surface Water Spatial Planning 1 in 1000 CCP1 Depths',
+ timeframe: ['climatechange'],
+ aep: ['low'],
+ }),
+
+ ...surfaceWaterDatasetGenerator({
+ agolVectorTileUrl,
+ layerNameSuffix,
+ id: 'surfacewater-climatechange-medium',
+ tileName: 'Surface_Water_Spatial_Planning_1_in_100_CCP1_Depths',
+ sourceLayer: 'Surface Water Spatial Planning 1 in 100 CCP1 Depths',
+ timeframe: ['climatechange'],
+ aep: ['medium'],
+ }),
+
+ ...surfaceWaterDatasetGenerator({
+ agolVectorTileUrl,
+ layerNameSuffix,
+ id: 'surfacewater-climatechange-high',
+ tileName: 'Surface_Water_Spatial_Planning_1_in_30_CCP1_Depths',
+ sourceLayer: 'Surface Water Spatial Planning 1 in 30 CCP1 Depths',
+ timeframe: ['climatechange'],
+ aep: ['high'],
+ })
+ ]
+ return datasets
+}
+const surfaceWaterExtentsKeyStyle = {
+ stroke: { outdoor: colours.nonFloodZoneLight, dark: colours.nonFloodZoneDark },
+ fill: { outdoor: colours.nonFloodZoneLight, dark: colours.nonFloodZoneDark },
+}
+
+export const surfaceWaterExtentsKey = {
+ id: 'surfacewater-extents-key',
+ label: terms.labels.surfaceWater,
+ // groupLabel: 'Datasets',
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ sublayers: [
+ {
+ id: 'key-150',
+ label: terms.depth.depth150,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depth150'] } }
+ },
+ {
+ id: 'key-300',
+ label: terms.depth.depth300,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depth300'] } }
+ },
+ {
+ id: 'key-600',
+ label: terms.depth.depth600,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depth600'] } }
+ },
+ {
+ id: 'key-900',
+ label: terms.depth.depth900,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depth900'] } }
+ },
+ {
+ id: 'key-1200',
+ label: terms.depth.depth1200,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depth1200'] } }
+ },
+ {
+ id: 'key-2300',
+ label: terms.depth.depth2300,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depth2300'] } }
+ },
+ {
+ id: 'key-over-2300',
+ label: terms.depth.depthOver2300,
+ showInKey: true,
+ style: surfaceWaterExtentsKeyStyle,
+ visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depthOver2300'] } }
+ }
+ ]
+}
diff --git a/client/js/map/datasets/surfaceWaterDatasetGenerator.js b/client/js/map/datasets/surfaceWaterDatasetGenerator.js
new file mode 100644
index 00000000..df04bf1d
--- /dev/null
+++ b/client/js/map/datasets/surfaceWaterDatasetGenerator.js
@@ -0,0 +1,130 @@
+import { terms } from '../terms.js'
+import { colours } from '../colours.js'
+
+export const surfaceWaterDatasetGenerator = ({ agolVectorTileUrl, layerNameSuffix, id, tileName, sourceLayer, timeframe, aep }) => {
+ const visibleWhenMenu = { dataset: ['surfacewater'], timeframe, aep }
+
+ const extentsDataset = {
+ id: `${id}-extents`,
+ label: terms.labels.surfaceWater,
+ groupLabel: terms.labels.datasets,
+ tiles: `${agolVectorTileUrl}/${tileName}${layerNameSuffix}/VectorTileServer`,
+ showInKey: true,
+ sourceLayer,
+ style: { fill: { outdoor: colours.nonFloodZoneLight, dark: colours.nonFloodZoneDark }, },
+ visibleWhen: { menu: visibleWhenMenu },
+ sublayers: [
+ {
+ id: 'depthOver2300',
+ esriStyleLayerId: `${sourceLayer}/>2300mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150', 'depth300', 'depth600', 'depth900', 'depth1200', 'depth2300', 'depthOver2300'] } },
+ },
+ {
+ id: 'depth2300',
+ esriStyleLayerId: `${sourceLayer}/1200-2300mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150', 'depth300', 'depth600', 'depth900', 'depth1200', 'depth2300'] } },
+ },
+ {
+ id: 'depth1200',
+ esriStyleLayerId: `${sourceLayer}/900-1200mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150', 'depth300', 'depth600', 'depth900', 'depth1200'] } },
+ },
+ {
+ id: 'depth900',
+ esriStyleLayerId: `${sourceLayer}/600-900mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150', 'depth300', 'depth600', 'depth900'] } },
+ },
+ {
+ id: 'depth600',
+ esriStyleLayerId: `${sourceLayer}/300-600mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150', 'depth300', 'depth600'] } },
+ },
+ {
+ id: 'depth300',
+ esriStyleLayerId: `${sourceLayer}/150-300mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150', 'depth300'] } },
+ },
+ {
+ id: 'depth150',
+ esriStyleLayerId: `${sourceLayer}/<150mm/1`,
+ showInKey: false,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depth150'] } },
+ },
+ ]
+ }
+
+ const depthDataset = {
+ id: `${id}-depths`,
+ label: terms.labels.surfaceWaterDepthInMillimetres,
+ groupLabel: terms.labels.datasets,
+ tiles: `${agolVectorTileUrl}/${tileName}${layerNameSuffix}/VectorTileServer`,
+ showInKey: true,
+ sourceLayer,
+ visibleWhen: { menu: { ...visibleWhenMenu, depth: ['depthAll'] } },
+ sublayers: [
+ {
+ id: 'depthOver2300',
+ esriStyleLayerId: `${sourceLayer}/>2300mm/1`,
+ label: terms.depth.key.depthOver2300,
+ style: {
+ fill: { outdoor: colours.depthOver2300.default, dark: colours.depthOver2300.dark },
+ }
+ },
+ {
+ id: 'depth2300',
+ esriStyleLayerId: `${sourceLayer}/1200-2300mm/1`,
+ label: terms.depth.key.depth2300,
+ style: {
+ fill: { outdoor: colours.depth2300.default, dark: colours.depth2300.dark },
+ }
+ },
+ {
+ id: 'depth1200',
+ esriStyleLayerId: `${sourceLayer}/900-1200mm/1`,
+ label: terms.depth.key.depth1200,
+ style: {
+ fill: { outdoor: colours.depth1200.default, dark: colours.depth1200.dark },
+ }
+ },
+ {
+ id: 'depth900',
+ esriStyleLayerId: `${sourceLayer}/600-900mm/1`,
+ label: terms.depth.key.depth900,
+ style: {
+ fill: { outdoor: colours.depth900.default, dark: colours.depth900.dark },
+ }
+ },
+ {
+ id: 'depth600',
+ esriStyleLayerId: `${sourceLayer}/300-600mm/1`,
+ label: terms.depth.key.depth600,
+ style: {
+ fill: { outdoor: colours.depth600.default, dark: colours.depth600.dark },
+ }
+ },
+ {
+ id: 'depth300',
+ esriStyleLayerId: `${sourceLayer}/150-300mm/1`,
+ label: terms.depth.key.depth300,
+ style: {
+ fill: { outdoor: colours.depth300.default, dark: colours.depth300.dark },
+ }
+ },
+ {
+ id: 'depth150',
+ esriStyleLayerId: `${sourceLayer}/<150mm/1`,
+ label: terms.depth.key.depth150,
+ style: {
+ fill: { outdoor: colours.depth150.default, dark: colours.depth150.dark },
+ }
+ },
+ ]
+ }
+ return [extentsDataset, depthDataset]
+}
diff --git a/client/js/map/index.js b/client/js/map/index.js
index e497ed8c..355eb450 100644
--- a/client/js/map/index.js
+++ b/client/js/map/index.js
@@ -7,25 +7,18 @@ import createScaleBarPlugin from '@defra/interactive-map/plugins/scale-bar'
import createSearchPlugin from '@defra/interactive-map/plugins/search'
import { interactPlugin, attachInteractPlugin } from './interactive-map-helpers/interact'
-import { setupEsriConfig, getRequest, getDefraMapConfig, setEsriConfig } from './tokens.js'
-import { terms } from './terms.js'
-import { colours, getKeyItemFill } from './colours.js'
-import { attachLayers, vtLayers, FloodMapLayer } from './mapLayers/index.js'
-import { addFeatureLayers } from './mapLayers/featureLayers/featureLayers.js'
+import { setupEsriConfig, getRequest, getDefraMapConfig } from './tokens.js'
import { setUpBaseMaps } from './baseMap.js'
import { checkParamsForPolygon, encodePolygon } from '../../../server/services/shape-utils.js'
-import { sliderMarkUp, initialiseSlider } from './slider/index.js'
+// TODO: add the slider to the dataset plugin
+// import { sliderMarkUp, initialiseSlider } from './slider/index.js'
import { getInfoPanel } from './infoPanel.js'
//
-import { renderMenuHTML } from './interactive-map-helpers/menu.js'
-import { renderKeyHTML, attachKeyHandlers } from './interactive-map-helpers/key.js'
+import { datasetsPlugin } from './datasets/datasetsPlugin.js'
import { drawPlugin, framePlugin, attachDrawPluginHandlers } from './interactive-map-helpers/draw.js'
-
//
-const feature = null// TODO - make this non global
-
const mapDiv = document.getElementById('map')
const symbols = {
@@ -35,103 +28,7 @@ const symbols = {
mainRivers: '/assets/images/main-rivers.svg'
}
-const MAX_POLYGON_AREA = 3000000
-
-const keyItemDefinitions = {
- floodZone2: {
- label: 'Flood zone 2',
- fill: getKeyItemFill(colours.floodZone2)
- },
- floodZone3: {
- label: 'Flood zone 3',
- fill: getKeyItemFill(colours.floodZone3)
- },
- floodZone2PresentDay: {
- label: 'Flood zone 2 (present day)',
- fill: getKeyItemFill(colours.floodZone2)
- },
- floodZone3PresentDay: {
- label: 'Flood zone 3 (present day)',
- fill: getKeyItemFill(colours.floodZone3)
- },
- floodZone3CC: {
- label: terms.labels.floodZoneClimateChange,
- fill: getKeyItemFill(colours.floodZoneClimateChange)
- },
- floodZoneClimateChangeNoData: {
- label: terms.labels.noData,
- icon: symbols.noData,
- fill: getKeyItemFill(colours.floodZoneClimateChangeNoData)
- },
- waterStorageAreas: {
- id: 'fsa',
- label: 'Water storage',
- icon: symbols.waterStorageAreas,
- fill: getKeyItemFill(colours.waterStorageAreas)
- },
- floodDefences: {
- id: 'fd',
- label: 'Flood defence',
- icon: symbols.floodDefences,
- fill: getKeyItemFill(colours.floodDefences)
- },
- mainRivers: {
- id: 'mainr',
- label: 'Main Rivers',
- icon: symbols.mainRivers,
- fill: getKeyItemFill(colours.mainRivers)
- },
- floodExtents: {
- // id: 'fz2',
- label: 'Flood extent',
- fill: getKeyItemFill(colours.floodExtents)
- },
- surfaceWater0: {
- label: '2300',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[0])
- },
- surfaceWater1: {
- label: '1200',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[1])
- },
- surfaceWater2: {
- label: '900',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[2])
- },
- surfaceWater3: {
- label: '600',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[3])
- },
- surfaceWater4: {
- label: '300',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[4])
- },
- surfaceWater5: {
- label: '150',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[5])
- },
- surfaceWater6: {
- label: '',
- fill: getKeyItemFill(colours.nonFloodZoneDepthBands[6])
- },
- surfaceWaterDepth150: { label: terms.depth.depth150, fill: getKeyItemFill(colours.nonFloodZone) },
- surfaceWaterDepth300: { label: terms.depth.depth300, fill: getKeyItemFill(colours.nonFloodZone) },
- surfaceWaterDepth600: { label: terms.depth.depth600, fill: getKeyItemFill(colours.nonFloodZone) },
- surfaceWaterDepth900: { label: terms.depth.depth900, fill: getKeyItemFill(colours.nonFloodZone) },
- surfaceWaterDepth1200: { label: terms.depth.depth1200, fill: getKeyItemFill(colours.nonFloodZone) },
- surfaceWaterDepth2300: { label: terms.depth.depth2300, fill: getKeyItemFill(colours.nonFloodZone) },
- surfaceWaterDepthOver2300: { label: terms.depth.depthOver2300, fill: getKeyItemFill(colours.nonFloodZone) }
-}
-
-keyItemDefinitions.common = {
- heading: terms.labels.mapFeatures,
- collapse: 'collapse',
- items: [
- keyItemDefinitions.waterStorageAreas,
- keyItemDefinitions.floodDefences,
- keyItemDefinitions.mainRivers
- ]
-}
+// const MAX_POLYGON_AREA = 3000000
// capture polygon from query string
const queryParams = new URLSearchParams(window.location.search)
@@ -147,18 +44,10 @@ const calculateExtent = (polygonToCalculate) => {
return calculatedExtent
}
-let featureQuery, extent
+let extent
if (queryParams.get('encodedPolygon') || queryParams.get('polygon')) {
const { polygon: polygonString } = checkParamsForPolygon({ encodedPolygon: queryParams.get('encodedPolygon'), polygon: queryParams.get('polygon'), encode: false })
const polygon = JSON.parse(polygonString)
-
- featureQuery = {
- type: 'feature',
- geometry: {
- type: 'polygon',
- coordinates: polygon
- }
- }
extent = calculateExtent(polygon)
}
@@ -190,6 +79,7 @@ getDefraMapConfig().then((defraMapConfig) => {
setupConfig: setupEsriConfig
}),
plugins: [
+ datasetsPlugin(defraMapConfig),
mapStylePlugin,
createScaleBarPlugin({ units: 'metric' }),
createSearchPlugin({
@@ -213,7 +103,6 @@ getDefraMapConfig().then((defraMapConfig) => {
containerHeight: '100%',
enableZoomControls: true,
symbols: [symbols.waterStorageAreas, symbols.floodDefences, symbols.mainRivers, symbols.noData],
- // interceptorsCallback: getInterceptors,
warningPosition: 'top',
search: {
label: 'Search for a place',
@@ -221,316 +110,7 @@ getDefraMapConfig().then((defraMapConfig) => {
isExpanded: false,
country: 'england'
},
- legend: {
- htmlAfter: sliderMarkUp,
- width: '280px',
- isVisible: true,
- keyWidth: '360px',
- keyDisplay: 'min',
- segments: [{
- heading: 'Datasets',
- collapse: 'collapse',
- items: [
- {
- id: 'fz',
- label: 'Flood zones 2 and 3'
- },
- // Left in place for reinstating later
- // {
- // id: 'rsd',
- // label: 'River and sea with defences'
- // },
- // {
- // id: 'rsu',
- // label: 'River and sea without defences'
- // },
- {
- id: 'sw',
- label: 'Surface water'
- },
- {
- id: 'mo',
- label: 'None'
- }
- ]
- },
- {
- id: 'tf',
- heading: terms.labels.climateChange,
- collapse: 'collapse',
- parentIds: ['fz'],
- items: [
- {
- id: 'fzpd',
- label: terms.labels.presentDay
- },
- {
- id: 'fzcl',
- label: terms.labels.fzClimateChange
- }
- ]
- },
- {
- id: 'tf',
- heading: terms.labels.climateChange,
- collapse: 'collapse',
- parentIds: ['rsd', 'rsu'],
- items: [
- {
- id: 'pd',
- label: terms.labels.presentDay
- },
- {
- id: 'cl',
- label: 'Years 2070 to 2125'
- }
- ]
- },
- {
- id: 'tf',
- heading: terms.labels.climateChange,
- collapse: 'collapse',
- parentIds: ['sw'],
- items: [
- {
- id: 'pd',
- label: terms.labels.presentDay
- },
- {
- id: 'cl',
- label: '2061 to 2125'
- }
- ]
- },
- {
- id: 'af1',
- heading: terms.labels.annualLikelihood,
- collapse: 'collapse',
- parentIds: ['rsd'],
- items: [
- {
- id: 'hr',
- label: terms.chance.rsHigh
- },
- {
- id: 'mr',
- label: terms.chance.rsMedium
- },
- {
- id: 'lr',
- label: terms.chance.rsLow
- }
- ]
- },
- {
- id: 'sw1',
- heading: terms.labels.annualLikelihood,
- collapse: 'collapse',
- parentIds: ['sw'],
- items: [
- {
- id: 'hr',
- label: terms.chance.swHigh
- },
- {
- id: 'mr',
- label: terms.chance.swMedium,
- isSelected: true
- },
- {
- id: 'lr',
- label: terms.chance.swLow
- }
- ]
- },
- {
- id: 'sw2',
- heading: terms.labels.depth,
- collapse: 'collapse',
- parentIds: ['sw'],
- items: [
- {
- id: 'depthAll',
- label: terms.depth.depthAll
- },
- {
- id: 'depth150',
- label: terms.depth.depth150
- },
- {
- id: 'depth300',
- label: terms.depth.depth300
- },
- {
- id: 'depth600',
- label: terms.depth.depth600
- },
- {
- id: 'depth900',
- label: terms.depth.depth900
- },
- {
- id: 'depth1200',
- label: terms.depth.depth1200
- },
- {
- id: 'depth2300',
- label: terms.depth.depth2300
- },
- {
- id: 'depthOver2300',
- label: terms.depth.depthOver2300
- }
- ]
- },
- {
- id: 'af2',
- heading: terms.labels.annualLikelihood,
- parentIds: ['rsu'],
- items: [
- {
- id: 'mr',
- label: terms.chance.rsMedium
- },
- {
- id: 'lr',
- label: terms.chance.rsLow
- }
- ]
- }
- ],
- key: [
- {
- heading: terms.labels.mapFeatures,
- collapse: 'collapse',
- parentIds: ['fzpd'],
- items: [
- keyItemDefinitions.floodZone2,
- keyItemDefinitions.floodZone3,
- keyItemDefinitions.waterStorageAreas,
- keyItemDefinitions.floodDefences,
- keyItemDefinitions.mainRivers
- ]
- },
- {
- heading: terms.labels.mapFeatures,
- collapse: 'collapse',
- parentIds: ['fzcl'],
- items: [
- keyItemDefinitions.floodZone2PresentDay,
- keyItemDefinitions.floodZone3PresentDay,
- keyItemDefinitions.floodZone3CC,
- keyItemDefinitions.floodZoneClimateChangeNoData,
- keyItemDefinitions.waterStorageAreas,
- keyItemDefinitions.floodDefences,
- keyItemDefinitions.mainRivers
- ]
- },
- { // Surface Water DepthAll
- heading: terms.labels.mapFeatures,
- collapse: 'collapse',
- parentIds: ['rsd', 'rsu', 'depthAll'],
- items: [
- keyItemDefinitions.waterStorageAreas,
- keyItemDefinitions.floodDefences,
- keyItemDefinitions.mainRivers,
- {
- label: 'Surface water depth in millimetres',
- display: 'ramp',
- numLabels: 1,
- items: [
- keyItemDefinitions.surfaceWater6,
- keyItemDefinitions.surfaceWater5,
- keyItemDefinitions.surfaceWater4,
- keyItemDefinitions.surfaceWater3,
- keyItemDefinitions.surfaceWater2,
- keyItemDefinitions.surfaceWater1,
- keyItemDefinitions.surfaceWater0
- ]
- }
- ]
- },
- // Surface Water Extents:
- {
- parentIds: ['depth150'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepth150]
- },
- {
- parentIds: ['depth300'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepth300]
- },
- {
- parentIds: ['depth600'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepth600]
- },
- {
- parentIds: ['depth900'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepth900]
- },
- {
- parentIds: ['depth1200'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepth1200]
- },
- {
- parentIds: ['depth2300'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepth2300]
- },
- {
- parentIds: ['depthOver2300'],
- ...keyItemDefinitions.common,
- items: [...keyItemDefinitions.common.items, keyItemDefinitions.surfaceWaterDepthOver2300]
- },
- {
- heading: terms.labels.mapFeatures,
- collapse: 'collapse',
- parentIds: ['mo'],
- items: [
- keyItemDefinitions.waterStorageAreas,
- keyItemDefinitions.floodDefences,
- keyItemDefinitions.mainRivers
- ]
- }
- ]
- },
scaleBar: 'metric',
- queryArea: {
- collapse: 'collapse',
- heading: 'Get data for your location',
- submitLabel: 'Get summary report',
- keyLabel: 'Location boundary',
- summary: 'Add or edit a location boundary',
- maxZoom: 22,
- drawTools: ['polygon', 'square'],
- areaUnits: 'hectares',
- feature: featureQuery, // feature derived from polygon query string or null if not present
- onShapeUpdate: ({ area, geometry }) => {
- // We seem to be getting this when we are not editing a shape = one to ask Dan about.
- if (!area || !geometry) {
- return {}
- }
- const isValid = area <= MAX_POLYGON_AREA
- const warningText = isValid ? null : 'Boundary must be under 300 hectares to order data. You can still download a flood map.'
- // This longer version was Rachel's initial suggestion, but was reduced to fit on screen,
- // with css we can make it fit, but awaiting opinions from the design team.
- // const warningText = isValid ? null : 'Reduce your boundary size to under 300 hectares to order detailed flood risk information (product 4). You can still download a flood map (product 1).'
- mapState.shapeIsValid = isValid
- return { warningText, allowShape: true }
- }
- },
- queryLocation: {
- layers: vtLayers.map(vtLayer => vtLayer.name)
- }
- }, (esriMapObjects) => {
- const { esriConfig } = esriMapObjects
- mapState.esriConfig = esriConfig
- mapState.polygon = featureQuery?.geometry?.coordinates
- setEsriConfig(esriConfig)
})
let reported = false
interactiveMap.addEventListener = () => {
@@ -539,9 +119,6 @@ getDefraMapConfig().then((defraMapConfig) => {
reported = true
}
}
- attachLayers(interactiveMap, defraMapConfig)
- addFeatureLayers(interactiveMap, defraMapConfig)
- attachKeyHandlers(interactiveMap)
attachDrawPluginHandlers(interactiveMap)
attachInteractPlugin(interactiveMap)
@@ -554,41 +131,18 @@ getDefraMapConfig().then((defraMapConfig) => {
tablet: { slot: 'right-top', showLabel: false, order: 1 },
desktop: { slot: 'right-top', showLabel: true, order: 1 }
})
- interactiveMap.addButton('menu', {
- label: 'Menu',
- panelId: 'menu',
- iconSvgContent: '',
- mobile: { slot: 'top-left', order: 1, showLabel: false },
- tablet: { slot: 'top-left', order: 2 },
- desktop: { slot: 'top-left', order: 2 }
- })
- interactiveMap.addButton('key', {
- label: 'Key',
- panelId: 'key',
- iconSvgContent: '',
- mobile: { slot: 'top-left', order: 2, showLabel: false },
- tablet: { slot: 'top-left', order: 3 },
- desktop: { slot: 'top-left', order: 3 }
- })
- interactiveMap.addPanel('menu', {
- label: 'Menu',
- html: renderMenuHTML(feature),
- mobile: { slot: 'side', modal: true, open: false, dismissible: true },
- tablet: { slot: 'side', width: '260px', open: true, dismissible: true },
- desktop: { slot: 'side', width: '280px', open: true, dismissible: false }
- })
- interactiveMap.addPanel('key', {
- label: 'Key',
- html: renderKeyHTML(),
- mobile: { slot: 'drawer', open: false, exclusive: true },
- tablet: { slot: 'left-top', width: '260px', open: false, exclusive: true },
- desktop: { slot: 'left-top', width: '280px', open: true, exclusive: false }
- })
- initialiseSlider(interactiveMap)
+ // TODO: add the slider to the dataset plugin
+ // initialiseSlider(interactiveMap)
+ })
+
+ interactiveMap.on('datasets:ready', function () {
+ updateVisibleLayers()
+ initPointerMove(mapState.view)
})
- interactiveMap.on('map:ready', function ({ map, view, mapStyleId, mapSize, crs }) {
- initPointerMove(view)
+ interactiveMap.on('map:ready', function ({ map, view, _mapStyleId, _mapSize, _crs }) {
+ mapState.map = map
+ mapState.view = view
interactiveMap.addPanel('help-banner', {
label: 'Click on the flood zones for information',
@@ -608,6 +162,7 @@ getDefraMapConfig().then((defraMapConfig) => {
})
const mapState = {
+ map: null,
isDark: false,
isRamp: false,
layers: [],
@@ -616,32 +171,53 @@ getDefraMapConfig().then((defraMapConfig) => {
isFloodZone: false
}
+ const updateVisibleLayers = () => {
+ mapState.visibleLayers = mapState.map.allLayers.items.filter((item) => (item.type === 'group' || item.type === 'vector-tile') && item.visible === true && item.id !== 'baselayer')
+ console.log('visibleLayers', mapState.visibleLayers)
+ }
+
const initPointerMove = (view) => {
let lastHit = 0
const throttleMs = 20 // Throttle to reduce hitTest usage
const minScale = 250000 // vector tile layers use minScale value from arcgis online config for visibility
- view.on('pointer-move', e => {
+ view.on('pointer-enter', updateVisibleLayers)
+
+ view.on('pointer-move', event => {
const now = Date.now()
- if (!FloodMapLayer.visibleLayer || now - lastHit < throttleMs || view.scale > minScale) {
+ if (!mapState.visibleLayers || now - lastHit < throttleMs || view.scale > minScale) {
return
}
lastHit = now
- const layersToTest = FloodMapLayer.visibleLayer.allLayers || [FloodMapLayer.visibleLayer]
- view.hitTest(e, { include: layersToTest }).then((response) => {
+ view.hitTest(event, { include: mapState.visibleLayers }).then((response) => {
+ let topVisibleStyleLayerId = null
if (response?.results?.length > 0) {
- // Now do an additional check for the SW layers, in case we are hovering over a hidden SW style layer
- // if it is NOT a SW layer, then FloodMapLayer.visibleLayer.isStyleLayerIdVisible will always return true.
- const { layerId } = response?.results?.[0]?.graphic?.origin || {}
- document.body.style.cursor = FloodMapLayer.visibleLayer.isStyleLayerIdVisible(layerId) ? 'pointer' : 'default'
- return
+ const visibleStyleLayerIds = response?.results.reduce((layerIds, result) => {
+ const { layerId } = result.graphic?.origin || {}
+ if (!layerId) {
+ return layerIds
+ }
+ const vtLayer = result.layer
+ const styleLayer = vtLayer?.getStyleLayer(layerId)
+ if (styleLayer?.layout?.visibility === 'visible') {
+ layerIds.push(layerId)
+ }
+ return layerIds
+ }, [])
+
+ topVisibleStyleLayerId = visibleStyleLayerIds?.[0] || null
+ }
+ if (mapState.cursorStyleLayer !== topVisibleStyleLayerId) {
+ mapState.cursorStyleLayer = topVisibleStyleLayerId
+ console.log('cursorStyleLayer', mapState.cursorStyleLayer)
}
- document.body.style.cursor = 'default'
+ document.body.style.cursor = topVisibleStyleLayerId ? 'pointer' : 'default'
})
})
- view.on('pointer-leave', _e => {
+ view.on('pointer-leave', () => {
document.body.style.cursor = 'default'
+ mapState.visibleLayers = null
})
}
diff --git a/client/js/map/terms.js b/client/js/map/terms.js
index bf3c575e..3df5f4d6 100644
--- a/client/js/map/terms.js
+++ b/client/js/map/terms.js
@@ -6,8 +6,10 @@ const terms = {
fzNoData: 'FZNODATA'
},
labels: {
+ datasets: 'Datasets',
floodZones: 'Flood zones',
surfaceWater: 'Surface water',
+ surfaceWaterDepthInMillimetres: 'Surface water depth in millimetres',
floodZone2: 'Flood zone 2',
floodZone3: 'Flood zone 3',
floodZone2PresentDay: 'Flood zone 2 (present day)',
@@ -24,7 +26,6 @@ const terms = {
waterStorage: 'Water storage',
floodDefence: 'Flood defence',
mainRivers: 'Main rivers',
-
},
chance: {
rsHigh: 'Rivers and sea 1 in 30',
diff --git a/client/js/map/tokens.js b/client/js/map/tokens.js
index 9ca20c16..d7d359bf 100644
--- a/client/js/map/tokens.js
+++ b/client/js/map/tokens.js
@@ -25,7 +25,10 @@ export const getOsToken = async () => {
return osAuth
}
+let _esriConfig
export const setupEsriConfig = async (esriConfig) => {
+ _esriConfig = esriConfig
+
// Set ESRI API key (using cached token)
esriConfig.apiKey = await getEsriToken()
@@ -33,7 +36,7 @@ export const setupEsriConfig = async (esriConfig) => {
getInterceptors().forEach((interceptor) => esriConfig.request.interceptors.push(interceptor))
}
-export const getInterceptors = () => {
+const getInterceptors = () => {
return [{
urls: 'https://api.os.uk/maps/vector/v1/vts',
before: async params => {
@@ -100,9 +103,6 @@ export const getDefraMapConfig = async () => {
return defraMapConfig
}
-let _esriConfig
-export const setEsriConfig = (esriConfig) => (_esriConfig = esriConfig)
-
const refreshEsriToken = async () => {
if (_esriConfig) {
const { token } = await getEsriToken(true) // forceRefresh = true
diff --git a/client/sass/map/index.scss b/client/sass/map/index.scss
index 60b2161c..e3ec410b 100644
--- a/client/sass/map/index.scss
+++ b/client/sass/map/index.scss
@@ -10,6 +10,7 @@ $govuk-new-typography-scale: true;
@import '../../../node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css';
@import '../../../node_modules/@defra/interactive-map/dist/css/index.css';
+@import '../../../node_modules/@defra/interactive-map/plugins/datasets/dist/css/index.css';
@import '../../../node_modules/@defra/interactive-map/plugins/search/dist/css/index.css';
@import '../../../node_modules/@defra/interactive-map/plugins/beta/map-styles/dist/css/index.css';
@import '../../../node_modules/@defra/interactive-map/plugins/beta/frame/dist/css/index.css';
diff --git a/package-lock.json b/package-lock.json
index 83fb4a30..f8781d6d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,13 +10,13 @@
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
- "@arcgis/core": "^5.0.9",
+ "@arcgis/core": "^5.1.13",
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.25.9",
"@defra/flood-map": "^0.6.8",
"@defra/fmp-utilities": "github:DEFRA/fmp-utilities",
- "@defra/interactive-map": "^0.0.34-alpha",
+ "@defra/interactive-map": "^0.0.35-alpha",
"@esri/arcgis-rest-request": "^4.2.3",
"@hapi/boom": "^10.0.1",
"@hapi/catbox": "^12.1.1",
@@ -78,9 +78,9 @@
}
},
"node_modules/@amcharts/amcharts5": {
- "version": "5.15.6",
- "resolved": "https://registry.npmjs.org/@amcharts/amcharts5/-/amcharts5-5.15.6.tgz",
- "integrity": "sha512-6gVWngHgkMN+v6dJhZ4XJE3fcHjvD5hyjgyNnfvVE1H0ukmHpfFmhI7cCX0cgy0NRyZc4fwgxDMZsiNA7yYKjA==",
+ "version": "5.18.0",
+ "resolved": "https://registry.npmjs.org/@amcharts/amcharts5/-/amcharts5-5.18.0.tgz",
+ "integrity": "sha512-2pIka1IrHO0mnTI7A9haq8aaq8leZZhFDythxNA7qYNg/iyGWuNcuzoyzJkybJLlNSlR5crkeNqZQL5up+IF3A==",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@types/d3": "^7.0.0",
@@ -103,37 +103,51 @@
"d3-voronoi-treemap": "^1.1.2",
"flatpickr": "^4.6.13",
"markerjs2": "^2.29.4",
- "pdfmake": "^0.2.2",
+ "pdfmake": "~0.3.9",
"polylabel": "^1.1.0",
"seedrandom": "^3.0.5",
"svg-arc-to-cubic-bezier": "^3.2.0",
"tslib": "^2.2.0"
}
},
+ "node_modules/@amcharts/amcharts5/node_modules/pdfmake": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.3.11.tgz",
+ "integrity": "sha512-Uc49J9hUMyuqJk+U+PxlpBpPr96A4HOOfesGx609EPr2ue82+5/Smq/KTAkEqh0/jUGSi1fumvqZ5yAWijJTJg==",
+ "license": "MIT",
+ "dependencies": {
+ "linebreak": "^1.1.0",
+ "pdfkit": "^0.19.1",
+ "xmldoc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/@arcgis/core": {
- "version": "5.0.10",
- "resolved": "https://registry.npmjs.org/@arcgis/core/-/core-5.0.10.tgz",
- "integrity": "sha512-FKGkVe3zDw5L2jS3mrFhXm+4O5dNZ6uNwQQGf7CwVjCeYXtrKbxk2xTB9d64ccEnXg2XwL7IOyR6wGIlmA3oMQ==",
+ "version": "5.1.13",
+ "resolved": "https://registry.npmjs.org/@arcgis/core/-/core-5.1.13.tgz",
+ "integrity": "sha512-jpU2HMaHXZ7arde5RAzrulw4ZQrOydcqLsQ/o94XQy0ud/MAsoHZctZ0ncGoocYILYH0FPddBacRPg+vmu6AQQ==",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
- "@amcharts/amcharts5": "~5.15.5",
- "@arcgis/toolkit": "^5.0.0",
+ "@amcharts/amcharts5": "~5.18.0",
+ "@arcgis/toolkit": "^5.1.0",
"@esri/arcgis-html-sanitizer": "~4.1.0",
- "@esri/calcite-components": "^5.0.2",
- "@vaadin/grid": "~25.0.3",
- "@zip.js/zip.js": "~2.8.16",
+ "@esri/calcite-components": "^5.1.1",
+ "@vaadin/grid": "~25.1.4",
+ "@zip.js/zip.js": "~2.8.26",
"luxon": "~3.7.2",
- "marked": "~17.0.3",
+ "marked": "~18.0.5",
"tslib": "^2.8.1"
}
},
"node_modules/@arcgis/lumina": {
- "version": "5.0.10",
- "resolved": "https://registry.npmjs.org/@arcgis/lumina/-/lumina-5.0.10.tgz",
- "integrity": "sha512-3Bk63oYbTVkNmHXREFFUnedvxPvAEm/aVXE7mXXwJSEqodq0mJhe/EubnZNI2PMSQa1gjEZTzHZjIzJnqyJkJQ==",
+ "version": "5.1.13",
+ "resolved": "https://registry.npmjs.org/@arcgis/lumina/-/lumina-5.1.13.tgz",
+ "integrity": "sha512-jDaOKgTWZzrCLiGAJoBAgq2xkq1XqnyIiZCDZHwMjOIuVXc69Yvi83Q3Ao6Rzm1TtX0p7NGRi5wuKn22TZcqBw==",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
- "@arcgis/toolkit": "~5.0.10",
+ "@arcgis/toolkit": "~5.1.13",
"csstype": "^3.1.3",
"tslib": "^2.8.1"
},
@@ -148,9 +162,9 @@
}
},
"node_modules/@arcgis/toolkit": {
- "version": "5.0.10",
- "resolved": "https://registry.npmjs.org/@arcgis/toolkit/-/toolkit-5.0.10.tgz",
- "integrity": "sha512-ZEKolhmoAOl5wl4DoMjn57YqPLNu1QM+x1e3Z4KhwegI9B+An2LXQBM+/UwWPKavKthB8ePPAqXnfctREd2OOQ==",
+ "version": "5.1.13",
+ "resolved": "https://registry.npmjs.org/@arcgis/toolkit/-/toolkit-5.1.13.tgz",
+ "integrity": "sha512-Zo2RV3Wr5WvHpprgJK1wzeOg3dLMMfY0e2HvUJS4yBH/3IUpyPnFR33DF65JPaVLeMY0B+V2LiOr99C5lhZo1Q==",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"tslib": "^2.8.1"
@@ -2371,9 +2385,9 @@
}
},
"node_modules/@defra/interactive-map": {
- "version": "0.0.34-alpha",
- "resolved": "https://registry.npmjs.org/@defra/interactive-map/-/interactive-map-0.0.34-alpha.tgz",
- "integrity": "sha512-NYEapl6cpFS5aiWXKNJnCQXt6f9RVcmyizxIkMrgYahjGL4Q/d4ijWo3IX/E0SLHze43topDSrtD1j/YZ0ZYYw==",
+ "version": "0.0.35-alpha",
+ "resolved": "https://registry.npmjs.org/@defra/interactive-map/-/interactive-map-0.0.35-alpha.tgz",
+ "integrity": "sha512-v7BgPY8ON9NlmRdwtk6IJ5dEY2qlqYYGOYc3XMogUtakVARI78oMiryRTgEpFxkLvxRfxHDOEeQRpEoruK0iZg==",
"dependencies": {
"@babel/runtime": "^7.28.6",
"@turf/area": "^7.2.0",
@@ -2743,21 +2757,21 @@
}
},
"node_modules/@esri/calcite-components": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/@esri/calcite-components/-/calcite-components-5.0.2.tgz",
- "integrity": "sha512-AE8AQBsdpWWAPJEBc/nabJbdN+H+iuVBJv215mm8xjlyqpHd6BLsD8nG/K8IywDFHeB9TyHLQdYCk/sNiyQo7w==",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@esri/calcite-components/-/calcite-components-5.1.2.tgz",
+ "integrity": "sha512-KdCk68T+UzVeAMA+kHW5UZ8msedBAH10k1J9Vkhqc8DtpJ0L/j2rw0ve9pbq1sW+hAAbhnTj+0OyP3R5bp1dEg==",
"license": "SEE LICENSE.md",
"dependencies": {
- "@arcgis/lumina": ">=5.0.0-next.144 <6.0.0",
- "@arcgis/toolkit": ">=5.0.0-next.144 <6.0.0",
- "@esri/calcite-ui-icons": "4.4.0",
+ "@arcgis/lumina": ">=5.1.0-next.96 <6.0.0",
+ "@arcgis/toolkit": ">=5.1.0-next.96 <6.0.0",
+ "@esri/calcite-ui-icons": "4.5.0",
"@floating-ui/dom": "^1.6.12",
"@floating-ui/utils": "^0.2.8",
"@types/sortablejs": "^1.15.8",
"color": "^5.0.3",
"composed-offset-position": "^0.0.6",
"es-toolkit": "^1.39.8",
- "focus-trap": "^7.6.5",
+ "focus-trap": "^8.2.1",
"interactjs": "^1.10.27",
"lit": "^3.3.0",
"sortablejs": "^1.15.6",
@@ -2765,10 +2779,19 @@
"type-fest": "^4.30.1"
}
},
+ "node_modules/@esri/calcite-components/node_modules/focus-trap": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-8.2.2.tgz",
+ "integrity": "sha512-qV0g8hRYBqgACcFOH3f9wXc4zPKhr/0z9RI2a6ZijZ72EeBi4g8oBy8zAWuUR1TsMpOzwpUMFvjdasrC41Joug==",
+ "license": "MIT",
+ "dependencies": {
+ "tabbable": "^6.5.0"
+ }
+ },
"node_modules/@esri/calcite-ui-icons": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@esri/calcite-ui-icons/-/calcite-ui-icons-4.4.0.tgz",
- "integrity": "sha512-PcCGId6vKBysRuuoCIYrVsaC+YVv1lFMqVUQn3Qna0BHOIyf7Mursf3NStELNjYdmL0MRYfmLDEDYQwnAJ/tSA==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@esri/calcite-ui-icons/-/calcite-ui-icons-4.5.0.tgz",
+ "integrity": "sha512-MuXK8o5qefXXV/vdDucQUm8zno+9Q0KjadCX82gYX1VgHMLPp0x2+pbQzG3c0MDbRqkidhTqL/zwq/eVq282qg==",
"license": "SEE LICENSE.md",
"bin": {
"spriter": "bin/spriter.js"
@@ -4206,6 +4229,30 @@
"@tybys/wasm-util": "^0.10.0"
}
},
+ "node_modules/@noble/ciphers": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
+ "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@noble/hashes": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
+ "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/@nolyfill/is-core-module": {
"version": "1.0.39",
"resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
@@ -4674,6 +4721,15 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/@swc/helpers": {
+ "version": "0.5.23",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
+ "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
"node_modules/@turf/along": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@turf/along/-/along-7.2.0.tgz",
@@ -7800,34 +7856,34 @@
]
},
"node_modules/@vaadin/a11y-base": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/a11y-base/-/a11y-base-25.0.7.tgz",
- "integrity": "sha512-Un2XCTK/wseP02KSUPR/JCuBgm3+uRpjm1S2YFQFaXdXFG1xsFOX0KAs9yRj2MxUsdCK75AU3Upnfbwln173lg==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/a11y-base/-/a11y-base-25.1.8.tgz",
+ "integrity": "sha512-CcAvMfHB/NeFuRNzkgDoqhFOjRzdm7qXEvEFErP9mB7nnsE6NY6wNlEpcUcxo5UtHADI37j8O5ESMTfgMHwHeQ==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
- "@vaadin/component-base": "~25.0.7",
+ "@vaadin/component-base": "~25.1.8",
"lit": "^3.0.0"
}
},
"node_modules/@vaadin/checkbox": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/checkbox/-/checkbox-25.0.7.tgz",
- "integrity": "sha512-wVweFiU5TDvwZE+BdGMIYrlv+409Vwv4dLv8jPOGOU05dS2koVYQLJVrlSQO4+3PUj799yqV9r8I3u7avcYIUg==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/checkbox/-/checkbox-25.1.8.tgz",
+ "integrity": "sha512-2PoppbhSGgzjHaK6HkRzyy+mmUMbPCIEdjRt+NdAzpCBMVBlr0Bc5xGS1NU8hk9snu3T11Ve7blWPGoA5++28A==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
- "@vaadin/a11y-base": "~25.0.7",
- "@vaadin/component-base": "~25.0.7",
- "@vaadin/field-base": "~25.0.7",
- "@vaadin/vaadin-themable-mixin": "~25.0.7",
+ "@vaadin/a11y-base": "~25.1.8",
+ "@vaadin/component-base": "~25.1.8",
+ "@vaadin/field-base": "~25.1.8",
+ "@vaadin/vaadin-themable-mixin": "~25.1.8",
"lit": "^3.0.0"
}
},
"node_modules/@vaadin/component-base": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/component-base/-/component-base-25.0.7.tgz",
- "integrity": "sha512-HzZiw+sHHWbYbXguNpegwK85KqCepjc1+saOJ9z/b7tyIr4XJUkP0Cg3IUC9AdBIVdYYQ8RoD+sSgcAwp31zCg==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/component-base/-/component-base-25.1.8.tgz",
+ "integrity": "sha512-hk/mFUCiJGj8y7snjOYNGPBa6RSZfACQawZ+QbyG1molkl9o66G5DPskWTLZHo5ps6vssKCXuOSm8dt4nhLfaQ==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
@@ -7837,30 +7893,30 @@
}
},
"node_modules/@vaadin/field-base": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/field-base/-/field-base-25.0.7.tgz",
- "integrity": "sha512-phr1GrHgl+UuakbByzCywqwtDdJSPuHFriPqe8fZ4GeD+OMVOBHJJy24frncIlvZVM+rJHA59GMj2iTlF3Zhrg==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/field-base/-/field-base-25.1.8.tgz",
+ "integrity": "sha512-zJOFNodbPE02drccgLzPV+6CxI3l0BvkP2lVJfZLkJQEkJv/3vOiLbuC/5ZqgLU+AS2xpjfSDZ77obqNm8CTlg==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
- "@vaadin/a11y-base": "~25.0.7",
- "@vaadin/component-base": "~25.0.7",
+ "@vaadin/a11y-base": "~25.1.8",
+ "@vaadin/component-base": "~25.1.8",
"lit": "^3.0.0"
}
},
"node_modules/@vaadin/grid": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/grid/-/grid-25.0.7.tgz",
- "integrity": "sha512-rUzoISbqkZL6FaRyZJh5+A/U5nEd8Rnx9n+agHrZ6w6x04Wh6UdW327ZKRGHXJiN4u8anTX0m14YJ3j50V9ChA==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/grid/-/grid-25.1.8.tgz",
+ "integrity": "sha512-TL24sncop8l1S9EYcIXQZ54295GoymehWoxGBMFDOINGCqID6hUUFeVmRCg0gnRD/sKRYQML81oX36lFeH47ww==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
- "@vaadin/a11y-base": "~25.0.7",
- "@vaadin/checkbox": "~25.0.7",
- "@vaadin/component-base": "~25.0.7",
- "@vaadin/lit-renderer": "~25.0.7",
- "@vaadin/text-field": "~25.0.7",
- "@vaadin/vaadin-themable-mixin": "~25.0.7",
+ "@vaadin/a11y-base": "~25.1.8",
+ "@vaadin/checkbox": "~25.1.8",
+ "@vaadin/component-base": "~25.1.8",
+ "@vaadin/lit-renderer": "~25.1.8",
+ "@vaadin/text-field": "~25.1.8",
+ "@vaadin/vaadin-themable-mixin": "~25.1.8",
"lit": "^3.0.0"
}
},
@@ -7903,37 +7959,37 @@
}
},
"node_modules/@vaadin/input-container": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/input-container/-/input-container-25.0.7.tgz",
- "integrity": "sha512-ECmJ1rm6b/T920JCP9eQkUMffKiX5xjzLDKbRyWVf6JS3+ZU0s/U0iOsY1YXnAMvbuJlv0cvbrkgA7mrbmKtKw==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/input-container/-/input-container-25.1.8.tgz",
+ "integrity": "sha512-GKHbCaCutC65wn23jfNFi/IOCkDBxTDfDToC+zlEhkuEl8clYaU/BF9cIiQxJL67K8N7yroDPeZqdNY+oc3PRQ==",
"license": "Apache-2.0",
"dependencies": {
- "@vaadin/component-base": "~25.0.7",
- "@vaadin/vaadin-themable-mixin": "~25.0.7",
+ "@vaadin/component-base": "~25.1.8",
+ "@vaadin/vaadin-themable-mixin": "~25.1.8",
"lit": "^3.0.0"
}
},
"node_modules/@vaadin/lit-renderer": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/lit-renderer/-/lit-renderer-25.0.7.tgz",
- "integrity": "sha512-ZSGmsXz28P+PzVupYvYx9amSMsGUPkoSRc56s6moggK/2InVwbud56T5+TczdujjRSjRg7HyQ/LXUjRUF6CBEQ==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/lit-renderer/-/lit-renderer-25.1.8.tgz",
+ "integrity": "sha512-J+TTNfy/qAXDjXlvOJ0Sar0Cl6kpCxv00BSgDaUAMh0oNnR1WkeJ2Muq76wGt5u8FOtGWn9TzYi9+H/NcBTdPQ==",
"license": "Apache-2.0",
"dependencies": {
"lit": "^3.0.0"
}
},
"node_modules/@vaadin/text-field": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/text-field/-/text-field-25.0.7.tgz",
- "integrity": "sha512-oYcpT2Mp8SCy3H1j+blN2pKkIv/QhXHnlYMzU+RdeIC1ef+NJUthsbf1A7UL8LDnWuPUORo6Eri7Z6Izxxjn+w==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/text-field/-/text-field-25.1.8.tgz",
+ "integrity": "sha512-Mxt/QavVGiOJYAtdlAqm1QllwyWk5GVf92jlV8JKQdRdVCi46rbSifXLaZQOFKlS5yOKGGQolWL1FFYRkz3Eqg==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
- "@vaadin/a11y-base": "~25.0.7",
- "@vaadin/component-base": "~25.0.7",
- "@vaadin/field-base": "~25.0.7",
- "@vaadin/input-container": "~25.0.7",
- "@vaadin/vaadin-themable-mixin": "~25.0.7",
+ "@vaadin/a11y-base": "~25.1.8",
+ "@vaadin/component-base": "~25.1.8",
+ "@vaadin/field-base": "~25.1.8",
+ "@vaadin/input-container": "~25.1.8",
+ "@vaadin/vaadin-themable-mixin": "~25.1.8",
"lit": "^3.0.0"
}
},
@@ -8015,13 +8071,13 @@
}
},
"node_modules/@vaadin/vaadin-themable-mixin": {
- "version": "25.0.7",
- "resolved": "https://registry.npmjs.org/@vaadin/vaadin-themable-mixin/-/vaadin-themable-mixin-25.0.7.tgz",
- "integrity": "sha512-HpDsQ0N+8Dcw6ur7AakXoEJsTUN28aGH3k29YUVdOAAtquN++siOrCpNhosVS8laI1X0uYI7w1dvQLSNAbZccg==",
+ "version": "25.1.8",
+ "resolved": "https://registry.npmjs.org/@vaadin/vaadin-themable-mixin/-/vaadin-themable-mixin-25.1.8.tgz",
+ "integrity": "sha512-eTGecAh1tzG8lXjIoYI1vMqaMm7CTBAQZhFL+c2xIYGQsGfuqk6+5ikdmq9KyDozR2i1K3qw00+fQQPZHNIKKg==",
"license": "Apache-2.0",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
- "@vaadin/component-base": "~25.0.7",
+ "@vaadin/component-base": "~25.1.8",
"lit": "^3.0.0"
}
},
@@ -8247,9 +8303,9 @@
"license": "Apache-2.0"
},
"node_modules/@zip.js/zip.js": {
- "version": "2.8.23",
- "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.23.tgz",
- "integrity": "sha512-RB+RLnxPJFPrGvQ9rgO+4JOcsob6lD32OcF0QE0yg24oeW9q8KnTTNlugcDaIveEcCbclobJcZP+fLQ++sH0bw==",
+ "version": "2.8.33",
+ "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.33.tgz",
+ "integrity": "sha512-Mc+s4DdDl9lmhFmkOmNDryC/b4rZm7y2/qBUQTCwPYGkQ8dkCeykILqEYBd+14ATuj93XWZJBrPe2x+cF9LcGA==",
"license": "BSD-3-Clause",
"engines": {
"bun": ">=0.7.0",
@@ -8474,7 +8530,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "devOptional": true,
+ "dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
@@ -9002,6 +9058,21 @@
"base64-js": "^1.1.2"
}
},
+ "node_modules/browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "license": "MIT",
+ "dependencies": {
+ "pako": "~1.0.5"
+ }
+ },
+ "node_modules/browserify-zlib/node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "license": "(MIT AND Zlib)"
+ },
"node_modules/browserslist": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
@@ -11596,6 +11667,23 @@
}
}
},
+ "node_modules/fontkit": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
+ "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@swc/helpers": "^0.5.12",
+ "brotli": "^1.3.2",
+ "clone": "^2.1.2",
+ "dfa": "^1.2.0",
+ "fast-deep-equal": "^3.1.3",
+ "restructure": "^3.0.0",
+ "tiny-inflate": "^1.0.3",
+ "unicode-properties": "^1.4.0",
+ "unicode-trie": "^2.0.0"
+ }
+ },
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -11680,6 +11768,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -14093,6 +14182,12 @@
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "MIT"
},
+ "node_modules/js-md5": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz",
+ "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==",
+ "license": "MIT"
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -14308,6 +14403,25 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/linebreak": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
+ "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "0.0.8",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/linebreak/node_modules/base64-js": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
+ "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -14782,9 +14896,9 @@
"license": "AGPL-3.0"
},
"node_modules/marked": {
- "version": "17.0.4",
- "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz",
- "integrity": "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==",
+ "version": "18.0.7",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.7.tgz",
+ "integrity": "sha512-iDVQ5ldaiKXn6b2JroX5kgRfmwgqolW7NpaEzTl1k/2Zh1njIEN9yniyLV/mOvWwtsE8OGgkjsCYvijuPk1dtA==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
@@ -15756,6 +15870,20 @@
"pbf": "bin/pbf"
}
},
+ "node_modules/pdfkit": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.19.1.tgz",
+ "integrity": "sha512-6Gzk+wDwTs4VSxsR5rCMTnIl5nlmkye1oWB0l2hDB1EX6ZNSIBroKQEv+2+fPPn+stVjyqzmsqRJVDfB9fo5DA==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/ciphers": "^1.0.0",
+ "@noble/hashes": "^1.6.0",
+ "fontkit": "^2.0.4",
+ "js-md5": "^0.8.3",
+ "linebreak": "^1.1.0",
+ "png-js": "^1.1.0"
+ }
+ },
"node_modules/pdfmake": {
"version": "0.2.23",
"resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.23.tgz",
@@ -15926,9 +16054,12 @@
}
},
"node_modules/png-js": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
- "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.1.0.tgz",
+ "integrity": "sha512-PM/uYGzGdNSzqeOgly68+6wKQDL1SY0a/N+OEa/+br6LnHWOAJB0Npiamnodfq3jd2LS/i2fMeOKSAILjA+m5Q==",
+ "dependencies": {
+ "browserify-zlib": "^0.2.0"
+ }
},
"node_modules/point-in-polygon": {
"version": "1.1.0",
@@ -16890,6 +17021,12 @@
"protocol-buffers-schema": "^3.3.1"
}
},
+ "node_modules/restructure": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
+ "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
+ "license": "MIT"
+ },
"node_modules/robust-predicates": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz",
@@ -17904,9 +18041,9 @@
}
},
"node_modules/tabbable": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
- "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz",
+ "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==",
"license": "MIT"
},
"node_modules/tapable": {
diff --git a/package.json b/package.json
index 19dbb94e..ebcc941c 100644
--- a/package.json
+++ b/package.json
@@ -28,13 +28,13 @@
"author": "defra",
"license": "ISC",
"dependencies": {
- "@arcgis/core": "^5.0.9",
+ "@arcgis/core": "^5.1.13",
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.25.9",
"@defra/flood-map": "^0.6.8",
"@defra/fmp-utilities": "github:DEFRA/fmp-utilities",
- "@defra/interactive-map": "^0.0.34-alpha",
+ "@defra/interactive-map": "^0.0.35-alpha",
"@esri/arcgis-rest-request": "^4.2.3",
"@hapi/boom": "^10.0.1",
"@hapi/catbox": "^12.1.1",