Skip to content
Merged
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
71 changes: 43 additions & 28 deletions demo/js/esri-datasets.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import scaleBarPlugin from '/plugins/beta/scale-bar/src/index.js'
import searchPlugin from '/plugins/search/src/index.js'
import { transformGeocodeRequest, transformVtsRequest3857, setupEsriConfig } from './auth.js'
import createInteractPlugin from '/plugins/interact/src/index.js'
import { siteBoundary } from './planning/siteBoundary.js'

const nonFloodZoneLight = '#2b8cbe'
const nonFloodZoneDark = '#7fcdbb'
Expand Down Expand Up @@ -301,10 +302,9 @@ const surfaceWaterDatasetGenerator = ({id, tileName, sourceLayer, timeframe, aep
if (depthsKey) {
return [extentsDataset, depthDataset]
}
// We only really need one of these with visibleWhen: { menu: {dataset: ['surfacewater'], depth: ['depthAll'] } },
// We only need one depthsKey, so we only return it here if it isn't already defined
depthsKey = {
id: 'depths-key',
label: 'Surface water',
groupId: 'surface-water-depth-in-millimetres',
showInKey: true,
visibleWhen: { menu: { dataset: ['surfacewater'], depth: ['depthAll'] } },
Expand All @@ -316,17 +316,7 @@ const surfaceWaterDatasetGenerator = ({id, tileName, sourceLayer, timeframe, aep
}
})
}
const extraDepthKeys = []
for(let i = 3; i <= depthsKey.sublayers.length; i++) {
extraDepthKeys.push({
...depthsKey,
groupLabel: `${depthsKey.groupLabel} [${i}]`,
id: `${depthsKey.id}-${i}`,
sublayers: depthsKey.sublayers.slice(0, i).map((sublayer) => ({ ...sublayer, label: `${i}.${sublayer.label}`.replaceAll('0', '') })),
})
}
return [depthsKey, extentsDataset, depthDataset]
// return [...extraDepthKeys, extentsDataset, depthDataset]
}

const surfaceWaterExtentsKey = {
Expand Down Expand Up @@ -616,6 +606,23 @@ const interactPlugin = createInteractPlugin({
interactionModes: ['placeMarker'],
})

const mapKeyPlugin = createMapKeyPlugin({
groups: {
'surface-water-depth-in-millimetres': {
groupLabel: 'Surface water depth in millimetres',
groupStyle: 'horizontal-ramp'
}
},
manifest: {
panels: [{
id: 'mapKey',
mobile: { slot: 'drawer', modal: false },
tablet: { slot: 'left-top', width: '360px' },
desktop: { slot: 'left-top', width: '360px' },
}]
},
})

const interactiveMap = new InteractiveMap('map', {
behaviour: 'mapOnly',
mapProvider: esriProvider({ setupConfig: setupEsriConfig }),
Expand Down Expand Up @@ -644,22 +651,7 @@ const interactiveMap = new InteractiveMap('map', {
scaleBarPlugin({ units: 'metric' }),
drawPlugin,
framePlugin,
createMapKeyPlugin({
groups: {
'surface-water-depth-in-millimetres': {
groupLabel: 'Surface water depth in millimetres',
groupStyle: 'horizontal-ramp'
}
},
manifest: {
panels: [{
id: 'mapKey',
mobile: { slot: 'drawer', modal: false },
tablet: { slot: 'left-top', width: '360px' },
desktop: { slot: 'left-top', width: '360px' },
}]
},
}),
mapKeyPlugin,
createMenuPlugin({
manifest: {
panels: [{
Expand Down Expand Up @@ -703,6 +695,29 @@ interactiveMap.on('interact:markerchange', function (e) {
})
})

const siteBoundaryKeyDefinition = {
id: 'site-boundary',
label: 'Location boundary',
// groupLabel: 'Other features',
style: {
strokeWidth: 2,
fill: 'none',
stroke: { outdoor: '#D4351D', dark: '#ffffff' }
},
}

siteBoundary.onSetFeature = (feature) => {
if (feature) {
mapKeyPlugin.addSymbol(siteBoundaryKeyDefinition)
} else {
mapKeyPlugin.removeSymbol(siteBoundaryKeyDefinition)
}
}

interactiveMap.on('map-key:ready', function () {
siteBoundary.onSetFeature(true)
})


const onEditPolygon = (isEditing) => {
// toggleKeyWhenEditing(isEditing)
Expand Down
3 changes: 3 additions & 0 deletions demo/js/planning/siteBoundary.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const FRAME_MAX_ZOOM = 22

export class SiteBoundary {
constructor (id = 'boundary') {
this.onSetFeature = () => {}
this._feature = null
this._id = id
this._state = SiteBoundary.EMPTY
Expand Down Expand Up @@ -66,6 +67,7 @@ export class SiteBoundary {
if (!feature?.geometry?.coordinates) {
this._feature = null
this.state = SiteBoundary.EMPTY
this.onSetFeature(null)
return
}
// round the coordinates to 2 decimal places
Expand All @@ -78,6 +80,7 @@ export class SiteBoundary {
// set the feature and update the state
this._feature = { ...feature, id, properties }
this.state = SiteBoundary.COMPLETE
this.onSetFeature(this._feature)
}


Expand Down
12 changes: 6 additions & 6 deletions plugins/datasets/src/registry/datasetRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,16 @@ const datasetRegistry = {
const groups = new Map()

const getOrCreateGroup = (groupLabel, groupId) => {
if (groups.has(groupLabel)) {
return groups.get(groupLabel)
if (groups.has(groupId)) {
return groups.get(groupId)
}
const groupObject = {
type: 'group',
id: groupId, // groupLabel.toLowerCase().replaceAll(/\s+/g, '-'),
id: groupId,
groupLabel,
keyDefinitions: []
}
groups.set(groupLabel, groupObject)
groups.set(groupId, groupObject)
_items.push(groupObject)
return groupObject
}
Expand All @@ -119,14 +119,14 @@ const datasetRegistry = {
if (!dataset.keyVisibility) {
return
}
const isGroup = dataset.hasSublayers || dataset.groupLabel
const isGroup = dataset.hasSublayers || dataset.groupId || dataset.groupLabel
if (!isGroup) {
_items.push({ type: 'flat', id: dataset.id, keyDefinition: dataset.keyDefinition })
return
}

const groupId = dataset.groupId
const groupLabel = dataset.groupLabel || dataset.label
const groupLabel = dataset.groupLabel || groupId || dataset.label
const groupObject = getOrCreateGroup(groupLabel, groupId)
if (!dataset.hasSublayers) {
groupObject.keyDefinitions.push(dataset.keyDefinition)
Expand Down
3 changes: 3 additions & 0 deletions plugins/map-key/src/api/addSymbol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const addSymbol = ({ pluginState: { dispatch } }, keyDefinition) => {
dispatch({ type: 'ADD_KEY_SYMBOL', payload: keyDefinition })
}
14 changes: 14 additions & 0 deletions plugins/map-key/src/api/addSymbol.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { addSymbol } from './addSymbol.js'

describe('addSymbol', () => {
it('dispatches an ADD_KEY_SYMBOL action with the key definition', () => {
const dispatch = jest.fn()

addSymbol({ pluginState: { dispatch } }, { id: 'map-key', groupLabel: 'Map key' })

expect(dispatch).toHaveBeenCalledWith({
type: 'ADD_KEY_SYMBOL',
payload: { id: 'map-key', groupLabel: 'Map key' }
})
})
})
7 changes: 7 additions & 0 deletions plugins/map-key/src/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { addSymbol } from './addSymbol.js'
import { removeSymbol } from './removeSymbol.js'

export const api = {
addSymbol,
removeSymbol
}
13 changes: 13 additions & 0 deletions plugins/map-key/src/api/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { api } from './index.js'
import { addSymbol } from './addSymbol.js'
import { removeSymbol } from './removeSymbol.js'

describe('api/index', () => {
it('exports the addSymbol API', () => {
expect(api.addSymbol).toBe(addSymbol)
})

it('exports the removeSymbol API', () => {
expect(api.removeSymbol).toBe(removeSymbol)
})
})
3 changes: 3 additions & 0 deletions plugins/map-key/src/api/removeSymbol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const removeSymbol = ({ pluginState: { dispatch } }, keyDefinition) => {
dispatch({ type: 'REMOVE_KEY_SYMBOL', payload: keyDefinition })
}
14 changes: 14 additions & 0 deletions plugins/map-key/src/api/removeSymbol.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { removeSymbol } from './removeSymbol.js'

describe('removeSymbol', () => {
it('dispatches a REMOVE_KEY_SYMBOL action with the key definition', () => {
const dispatch = jest.fn()

removeSymbol({ pluginState: { dispatch } }, { id: 'map-key' })

expect(dispatch).toHaveBeenCalledWith({
type: 'REMOVE_KEY_SYMBOL',
payload: { id: 'map-key' }
})
})
})
14 changes: 11 additions & 3 deletions plugins/map-key/src/components/Key/MapKey.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useState, useEffect } from 'react'
import { getDatasetRegistry } from '../../registry/index.js'
import { mergeKeyGroupItems } from '../../utils/mergeKeyGroupItems.js'
import { mergeKeyGroupItems } from '../../reducers/mergeKeyGroupItems.js'
import { Key } from './Key.jsx'

export function MapKey ({
mapState: { mapStyle },
pluginConfig: { noKeyItemText, groups },
pluginConfig: { noKeyItemText },
pluginState,
services: { eventBus }
}) {
const [datasetRegistry, setDatasetRegistry] = useState(getDatasetRegistry())
Expand All @@ -18,7 +19,7 @@ export function MapKey ({
const getKeyItems = () => {
const { items, hasGroups: _hasGroups } = datasetRegistry.keyItems()
// Post Process the items - based on the map-key pluginConfig adding any groupConfigs
const groupItems = mergeKeyGroupItems(groups, items)
const groupItems = mergeKeyGroupItems(items)
setKeyGroups(groupItems)
setHasGroups(_hasGroups)
}
Expand All @@ -44,6 +45,13 @@ export function MapKey ({
}
}, [datasetRegistry])

useEffect(() => {
if (!datasetRegistry) {
return
}
getKeyItems()
}, [pluginState])

return (
<Key
noKeyItemText={noKeyItemText}
Expand Down
21 changes: 18 additions & 3 deletions plugins/map-key/src/initialise/MapKeyInit.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import { useEffect } from 'react'
import { useEffect, useRef } from 'react'
import { setDatasetRegistry } from '../registry/getDatasetRegistry.js'
import { attachPluginStateRef } from '../reducers/mergeKeyGroupItems.js'

// additional possible params here are: pluginConfig, pluginState, appState, mapProvider,
export function MapKeyInit ({ mapState, services }) {
// additional possible params here are: pluginConfig, appState, mapProvider,
export function MapKeyInit ({ pluginConfig, pluginState, mapState, services }) {
const { dispatch } = pluginState
const { eventBus } = services
const pluginStateRef = useRef(pluginState)
pluginStateRef.current = pluginState

useEffect(() => {
if (!mapState.isMapReady) {
return
}
attachPluginStateRef(pluginStateRef)
// Request a handle on the datasetsRegistry singleton
eventBus.requestOnce('datasets:registry', setDatasetRegistry)
eventBus.emit('map-key:ready')
}, [mapState.isMapReady])

useEffect(() => {
if (!pluginConfig.groups) {
return
}
const groups = Object.entries(pluginConfig.groups).map(([id, group]) => ({ ...group, id, label: group.groupLabel }))

dispatch({ type: 'ADD_KEY_GROUPS', payload: groups })
}, [pluginConfig.groups])
}
52 changes: 44 additions & 8 deletions plugins/map-key/src/initialise/MapKeyInit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,70 @@ jest.mock('../registry/getDatasetRegistry.js', () => ({
setDatasetRegistry: jest.fn()
}))

const eventBus = { requestOnce: jest.fn() }
const services = { eventBus }
const eventBus = { requestOnce: jest.fn(), emit: jest.fn() }
const pluginState = { dispatch: jest.fn() }
const pluginConfig = {
groups: {
alpha: { groupLabel: 'Alpha' }
}
}

beforeEach(() => {
jest.clearAllMocks()
})

describe('MapKeyInit', () => {
const renderInit = ({ isMapReady = false, config = {} } = {}) => render(
<MapKeyInit
pluginConfig={config}
pluginState={pluginState}
mapState={{ isMapReady }}
services={{ eventBus }}
/>
)

it('does not call requestOnce when map is not ready', () => {
render(<MapKeyInit mapState={{ isMapReady: false }} services={services} />)
renderInit({ isMapReady: false })
expect(eventBus.requestOnce).not.toHaveBeenCalled()
})

it('calls requestOnce for datasets:registry when map is ready', () => {
render(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
renderInit({ isMapReady: true })
expect(eventBus.requestOnce).toHaveBeenCalledWith('datasets:registry', setDatasetRegistry)
})

it('dispatches configured groups when pluginConfig.groups is provided', () => {
renderInit({ isMapReady: true, config: pluginConfig })
expect(pluginState.dispatch).toHaveBeenCalledWith({
type: 'ADD_KEY_GROUPS',
payload: [{ id: 'alpha', groupLabel: 'Alpha', label: 'Alpha' }]
})
})

it('calls requestOnce when isMapReady changes to true', () => {
const { rerender } = render(<MapKeyInit mapState={{ isMapReady: false }} services={services} />)
const { rerender } = renderInit({ isMapReady: false })
expect(eventBus.requestOnce).not.toHaveBeenCalled()
rerender(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
rerender(
<MapKeyInit
pluginConfig={{}}
pluginState={pluginState}
mapState={{ isMapReady: true }}
services={{ eventBus }}
/>
)
expect(eventBus.requestOnce).toHaveBeenCalledTimes(1)
})

it('does not call requestOnce again on re-render when isMapReady stays true', () => {
const { rerender } = render(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
rerender(<MapKeyInit mapState={{ isMapReady: true }} services={services} />)
const { rerender } = renderInit({ isMapReady: true })
rerender(
<MapKeyInit
pluginConfig={{}}
pluginState={pluginState}
mapState={{ isMapReady: true }}
services={{ eventBus }}
/>
)
expect(eventBus.requestOnce).toHaveBeenCalledTimes(1)
})
})
Loading
Loading