@defra/interactive-map 0.0.30-alpha → 0.0.31-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/im-shell.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/context.md +4 -4
- package/docs/api.md +111 -37
- package/docs/assets/css/docusaurus.scss +20 -4
- package/docs/assets/images/basic-map.jpg +0 -0
- package/docs/assets/images/button-first.jpg +0 -0
- package/docs/assets/images/deuteranopia-ozs-map-thumb.jpg +0 -0
- package/docs/assets/images/draw.jpg +0 -0
- package/docs/assets/images/marker-panel.jpg +0 -0
- package/docs/assets/images/night-ozs-map-thumb.jpg +0 -0
- package/docs/assets/images/outdoor-ozs-map-thumb.jpg +0 -0
- package/docs/assets/images/search.jpg +0 -0
- package/docs/assets/images/select-feature.jpg +0 -0
- package/docs/assets/images/style-switcher.jpg +0 -0
- package/docs/assets/images/toggle-marker-label.jpg +0 -0
- package/docs/assets/images/tritanopia-ozs-map-thumb.jpg +0 -0
- package/docs/examples/add-marker-with-panel.mdx +2 -2
- package/docs/examples/basic-map.mdx +2 -2
- package/docs/examples/draw.mdx +271 -0
- package/docs/examples/index.mdx +58 -10
- package/docs/examples/search-control.mdx +71 -0
- package/docs/examples/select-feature.mdx +146 -0
- package/docs/examples/style-switcher.mdx +135 -0
- package/docs/examples/toggle-marker-label.mdx +3 -3
- package/docs/plugins/datasets.md +15 -28
- package/docusaurus.config.cjs +5 -1
- package/package.json +1 -1
- package/plugins/beta/datasets/dist/css/index.css +4 -0
- package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -0
- package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/esm/index.js +1 -1
- package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +2 -0
- package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +2 -0
- package/plugins/beta/datasets/dist/umd/index.js +2 -0
- package/plugins/beta/datasets/src/adapters/loadLayerAdapter.js +33 -0
- package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +44 -120
- package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +145 -245
- package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +516 -0
- package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +191 -0
- package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +441 -0
- package/plugins/beta/datasets/src/api/addDataset.js +2 -5
- package/plugins/beta/datasets/src/api/addDataset.test.js +16 -0
- package/plugins/beta/datasets/src/api/getOpacity.js +14 -14
- package/plugins/beta/datasets/src/api/getOpacity.test.js +72 -0
- package/plugins/beta/datasets/src/api/getStyle.js +8 -9
- package/plugins/beta/datasets/src/api/getStyle.test.js +42 -0
- package/plugins/beta/datasets/src/api/removeDataset.js +7 -7
- package/plugins/beta/datasets/src/api/removeDataset.test.js +45 -0
- package/plugins/beta/datasets/src/api/setData.js +9 -3
- package/plugins/beta/datasets/src/api/setData.test.js +62 -0
- package/plugins/beta/datasets/src/api/setDatasetVisibility.js +5 -30
- package/plugins/beta/datasets/src/api/setDatasetVisibility.test.js +31 -0
- package/plugins/beta/datasets/src/api/setFeatureVisibility.js +3 -21
- package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +32 -0
- package/plugins/beta/datasets/src/api/setGlobals.js +20 -0
- package/plugins/beta/datasets/src/api/setGlobals.test.js +63 -0
- package/plugins/beta/datasets/src/api/setOpacity.js +8 -27
- package/plugins/beta/datasets/src/api/setOpacity.test.js +31 -0
- package/plugins/beta/datasets/src/api/setStyle.js +5 -21
- package/plugins/beta/datasets/src/api/setStyle.test.js +53 -0
- package/plugins/beta/datasets/src/components/Key/Key.jsx +51 -0
- package/plugins/beta/datasets/src/components/Key/KeyGroupItem.jsx +18 -0
- package/plugins/beta/datasets/src/components/Key/KeyItem.jsx +20 -0
- package/plugins/beta/datasets/src/components/Key/KeySvg.jsx +22 -0
- package/plugins/beta/datasets/src/components/Key/KeySvg.test.jsx +87 -0
- package/plugins/beta/datasets/src/components/Key/KeySvgLine.jsx +19 -0
- package/plugins/beta/datasets/src/components/Key/KeySvgLine.test.jsx +71 -0
- package/plugins/beta/datasets/src/components/{KeySvgPattern.jsx → Key/KeySvgPattern.jsx} +3 -4
- package/plugins/beta/datasets/src/components/Key/KeySvgPattern.test.jsx +55 -0
- package/plugins/beta/datasets/src/components/Key/KeySvgRect.jsx +22 -0
- package/plugins/beta/datasets/src/components/Key/KeySvgRect.test.jsx +85 -0
- package/plugins/beta/datasets/src/components/{KeySvgSymbol.jsx → Key/KeySvgSymbol.jsx} +5 -5
- package/plugins/beta/datasets/src/components/Key/KeySvgSymbol.test.jsx +80 -0
- package/plugins/beta/datasets/src/components/Key/svgProperties.test.js +61 -0
- package/plugins/beta/datasets/src/{panels → components/LayersMenu}/Layers.module.scss +4 -0
- package/plugins/beta/datasets/src/components/LayersMenu/LayersMenu.jsx +33 -0
- package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuCheckbox.jsx +31 -0
- package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuGroupWrapper.jsx +19 -0
- package/plugins/beta/datasets/src/datasets.scss +2 -2
- package/plugins/beta/datasets/src/fetch/createDynamicSource.js +8 -8
- package/plugins/beta/datasets/src/{DatasetsInit.jsx → initialise/DatasetsInit.jsx} +19 -21
- package/plugins/beta/datasets/src/{defaults.js → initialise/defaults.js} +17 -2
- package/plugins/beta/datasets/src/initialise/defaults.test.js +127 -0
- package/plugins/beta/datasets/src/{datasets.js → initialise/initialiseDatasets.js} +30 -26
- package/plugins/beta/datasets/src/initialise/initialiseDatasets.test.js +273 -0
- package/plugins/beta/datasets/src/manifest.js +8 -6
- package/plugins/beta/datasets/src/reducers/__data__/demoDatasets.js +253 -0
- package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +78 -0
- package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +35 -0
- package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +34 -0
- package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js +117 -0
- package/plugins/beta/datasets/src/reducers/pluginState.js +206 -0
- package/plugins/beta/datasets/src/reducers/pluginState.test.js +386 -0
- package/plugins/beta/datasets/src/registry/__mocks__/datasetRegistry.js +29 -0
- package/plugins/beta/datasets/src/registry/createDataset.js +5 -0
- package/plugins/beta/datasets/src/registry/dataset.js +172 -0
- package/plugins/beta/datasets/src/registry/dataset.test.js +483 -0
- package/plugins/beta/datasets/src/registry/datasetDefinitionCache.js +35 -0
- package/plugins/beta/datasets/src/registry/datasetRegistry.js +116 -0
- package/plugins/beta/datasets/src/registry/datasetRegistry.test.js +335 -0
- package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +17 -0
- package/plugins/beta/datasets/src/registry/globalDataset.js +36 -0
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/src/events.js +13 -1
- package/plugins/beta/draw-ml/src/index.js +1 -1
- package/plugins/beta/draw-ml/src/manifest.js +3 -0
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/src/InteractInit.jsx +2 -2
- package/plugins/interact/src/InteractInit.test.js +1 -1
- package/plugins/interact/src/events.js +2 -29
- package/plugins/interact/src/events.test.js +4 -102
- package/plugins/interact/src/hooks/useAttachEvents.js +3 -4
- package/plugins/interact/src/hooks/useAttachEvents.test.js +1 -3
- package/plugins/interact/src/hooks/useInteractionHandlers.js +10 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +23 -4
- package/plugins/interact/src/manifest.js +0 -35
- package/plugins/interact/src/manifest.test.js +3 -43
- package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
- package/providers/beta/esri/src/esriProvider.js +4 -0
- package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/src/openlayersProvider.js +4 -0
- package/providers/beta/openlayers/src/openlayersProvider.test.js +5 -0
- package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
- package/providers/maplibre/src/maplibreProvider.js +6 -4
- package/providers/maplibre/src/maplibreProvider.test.js +5 -0
- package/providers/maplibre/src/utils/highlightFeatures.js +74 -25
- package/providers/maplibre/src/utils/highlightFeatures.test.js +132 -0
- package/providers/maplibre/src/utils/patternImages.js +2 -4
- package/providers/maplibre/src/utils/symbolImages.js +1 -4
- package/rollup.esm.mjs +2 -8
- package/src/App/components/MapButton/MapButton.jsx +16 -1
- package/src/App/components/MapButton/MapButton.module.scss +12 -1
- package/src/App/components/MapButton/MapButton.test.jsx +40 -1
- package/src/App/hooks/useContinueEnabledEvaluator.js +31 -0
- package/src/App/hooks/useContinueEnabledEvaluator.test.js +118 -0
- package/src/App/hooks/useEvaluateProp.js +15 -15
- package/src/App/hooks/useEvaluateProp.test.js +80 -76
- package/src/App/hooks/useLayoutMeasurements.js +1 -3
- package/src/App/hooks/useResizeObserver.js +12 -1
- package/src/App/hooks/useResizeObserver.test.js +1 -0
- package/src/App/renderer/PluginInits.jsx +2 -0
- package/src/App/renderer/mapButtons.js +21 -1
- package/src/App/renderer/mapButtons.test.js +46 -1
- package/src/App/store/appReducer.js +1 -1
- package/src/App/store/appReducer.test.js +37 -0
- package/src/InteractiveMap/InteractiveMap.js +10 -0
- package/src/InteractiveMap/InteractiveMap.test.js +8 -0
- package/src/config/appConfig.js +25 -0
- package/src/config/appConfig.test.js +50 -0
- package/src/config/defaults.js +1 -0
- package/src/scss/settings/_dimensions.scss +1 -0
- package/src/services/patternRegistry.js +8 -4
- package/src/types.js +7 -0
- package/src/utils/patternUtils.js +1 -2
- package/src/utils/patternUtils.test.js +9 -0
- package/webpack.dev.mjs +10 -0
- package/webpack.umd.mjs +1 -1
- package/plugins/beta/datasets/dist/adapters/maplibre/esm/im-datasets-ml-adapter.js +0 -1
- package/plugins/beta/datasets/dist/adapters/maplibre/esm/index.js +0 -1
- package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-maplibre-adapter.js +0 -2
- package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-plugin.js +0 -2
- package/plugins/beta/datasets/dist/umd/maplibre/index.js +0 -2
- package/plugins/beta/datasets/src/adapters/maplibre/index.js +0 -18
- package/plugins/beta/datasets/src/adapters/maplibre/layerIds.js +0 -75
- package/plugins/beta/datasets/src/adapters/maplibre/patternImages.js +0 -27
- package/plugins/beta/datasets/src/adapters/maplibre/symbolImages.js +0 -31
- package/plugins/beta/datasets/src/components/KeySvg.jsx +0 -24
- package/plugins/beta/datasets/src/components/KeySvgLine.jsx +0 -19
- package/plugins/beta/datasets/src/components/KeySvgRect.jsx +0 -22
- package/plugins/beta/datasets/src/index.maplibre.umd.js +0 -23
- package/plugins/beta/datasets/src/panels/Key.jsx +0 -62
- package/plugins/beta/datasets/src/panels/Layers.jsx +0 -141
- package/plugins/beta/datasets/src/reducer.js +0 -219
- package/plugins/beta/datasets/src/reducers/keyReducer.js +0 -34
- package/plugins/beta/datasets/src/utils/filters.js +0 -34
- package/plugins/beta/datasets/src/utils/mergeSublayer.js +0 -86
- package/plugins/beta/draw-ml/dist/css/index.css +0 -21
- /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-maplibre-adapter.js.LICENSE.txt → im-datasets-ml-adapter.js.LICENSE.txt} +0 -0
- /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-plugin.js.LICENSE.txt → im-datasets-plugin.js.LICENSE.txt} +0 -0
- /package/plugins/beta/datasets/dist/umd/{maplibre/index.js.LICENSE.txt → index.js.LICENSE.txt} +0 -0
- /package/plugins/beta/datasets/src/components/{EmptyKey.jsx → Key/EmptyKey.jsx} +0 -0
- /package/plugins/beta/datasets/src/components/{EmptyKey.test.jsx → Key/EmptyKey.test.jsx} +0 -0
- /package/plugins/beta/datasets/src/{panels → components/Key}/Key.module.scss +0 -0
- /package/plugins/beta/datasets/src/components/{svgProperties.js → Key/svgProperties.js} +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { Dataset } from './dataset.js'
|
|
2
|
+
import { datasetRegistry } from './datasetRegistry.js'
|
|
3
|
+
import { mappedDatasetsReducer } from '../reducers/mappedDatasetsReducer.js'
|
|
4
|
+
import { datasetsWithGroups } from '../reducers/__data__/demoDatasets.js'
|
|
5
|
+
// Use the mock datasetRegistry with the demo datasets attached before each test.
|
|
6
|
+
// Dataset must be imported before datasetRegistry so that dataset.js is cached before
|
|
7
|
+
// the mock initialization triggers requireActual, avoiding a circular re-entry that
|
|
8
|
+
// would leave datasetRegistry undefined inside the mock.
|
|
9
|
+
jest.mock('./datasetRegistry.js')
|
|
10
|
+
|
|
11
|
+
describe('datasetRegistry', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks()
|
|
14
|
+
datasetRegistry._invalidateCache()
|
|
15
|
+
})
|
|
16
|
+
describe('attach', () => {
|
|
17
|
+
it("doesn't throw when no datasets are attached", () => {
|
|
18
|
+
expect(() => datasetRegistry.attach(undefined)).not.toThrow()
|
|
19
|
+
})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('getDataset', () => {
|
|
23
|
+
it('returns a Dataset instance for a known id', () => {
|
|
24
|
+
const dataset = datasetRegistry.getDataset('land-covers')
|
|
25
|
+
expect(dataset).toBeInstanceOf(Dataset)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('returns the correct id', () => {
|
|
29
|
+
const dataset = datasetRegistry.getDataset('existing-fields')
|
|
30
|
+
expect(dataset.id).toBe('existing-fields')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('returns a Dataset instance for a sublayer id', () => {
|
|
34
|
+
const dataset = datasetRegistry.getDataset('land-covers-130-131')
|
|
35
|
+
expect(dataset).toBeInstanceOf(Dataset)
|
|
36
|
+
expect(dataset.id).toBe('land-covers-130-131')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('returns undefined for an unknown id', () => {
|
|
40
|
+
expect(datasetRegistry.getDataset('non-existent')).toBeUndefined()
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('forEach', () => {
|
|
45
|
+
it('calls the callback once per dataset in orderedDatasets order', () => {
|
|
46
|
+
const ids = []
|
|
47
|
+
datasetRegistry.forEach(dataset => ids.push(dataset.id))
|
|
48
|
+
expect(ids).toEqual(datasetRegistry._orderedDatasets)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('passes Dataset instances to the callback', () => {
|
|
52
|
+
datasetRegistry.forEach(dataset => expect(dataset).toBeInstanceOf(Dataset))
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('forEachDataset', () => {
|
|
57
|
+
it('calls the callback only for top-level datasets', () => {
|
|
58
|
+
const ids = []
|
|
59
|
+
datasetRegistry.forEachDataset(dataset => ids.push(dataset.id))
|
|
60
|
+
expect(ids).toEqual(['land-covers', 'existing-fields', 'historic-monuments', 'hedge-control'])
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('does not include sublayers', () => {
|
|
64
|
+
const ids = []
|
|
65
|
+
datasetRegistry.forEachDataset(dataset => ids.push(dataset.id))
|
|
66
|
+
expect(ids).not.toContain('land-covers-130-131')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('passes Dataset instances to the callback', () => {
|
|
70
|
+
datasetRegistry.forEachDataset(dataset => expect(dataset).toBeInstanceOf(Dataset))
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('topLevelDatasets', () => {
|
|
75
|
+
it('returns only top-level dataset ids', () => {
|
|
76
|
+
const ids = datasetRegistry.topLevelDatasets().map(d => d.id)
|
|
77
|
+
expect(ids).toEqual(['land-covers', 'existing-fields', 'historic-monuments', 'hedge-control'])
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('does not include sublayers', () => {
|
|
81
|
+
const ids = datasetRegistry.topLevelDatasets().map(d => d.id)
|
|
82
|
+
expect(ids).not.toContain('land-covers-130-131')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('returns Dataset instances', () => {
|
|
86
|
+
datasetRegistry.topLevelDatasets().forEach(d => expect(d).toBeInstanceOf(Dataset))
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
describe('getPatternAndSymbolConfigs', () => {
|
|
91
|
+
it('returns an object with patternConfigs and symbolConfigs arrays', () => {
|
|
92
|
+
const result = datasetRegistry.getPatternAndSymbolConfigs()
|
|
93
|
+
expect(Array.isArray(result.patternConfigs)).toBe(true)
|
|
94
|
+
expect(Array.isArray(result.symbolConfigs)).toBe(true)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('collects fill pattern configs from sublayers', () => {
|
|
98
|
+
const { patternConfigs } = datasetRegistry.getPatternAndSymbolConfigs()
|
|
99
|
+
// land-covers sublayers each have a fillPattern style
|
|
100
|
+
expect(patternConfigs.length).toBeGreaterThan(0)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('collects symbol configs from sublayers', () => {
|
|
104
|
+
const { symbolConfigs } = datasetRegistry.getPatternAndSymbolConfigs()
|
|
105
|
+
// historic-monuments sublayers inherit symbol: 'square' from their parent
|
|
106
|
+
expect(symbolConfigs.length).toBeGreaterThan(0)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('returns empty arrays when no datasets have patterns or symbols', () => {
|
|
110
|
+
datasetRegistry.attach({ simple: { id: 'simple', style: { stroke: '#ff0000' } } })
|
|
111
|
+
const { patternConfigs, symbolConfigs } = datasetRegistry.getPatternAndSymbolConfigs()
|
|
112
|
+
expect(patternConfigs).toHaveLength(0)
|
|
113
|
+
expect(symbolConfigs).toHaveLength(0)
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
describe('keyItems', () => {
|
|
118
|
+
it('returns an object with an items array and hasGroups boolean', () => {
|
|
119
|
+
const { items, hasGroups } = datasetRegistry.keyItems()
|
|
120
|
+
expect(Array.isArray(items)).toBe(true)
|
|
121
|
+
expect(typeof hasGroups).toBe('boolean')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('includes a sublayers entry for each dataset that has sublayers', () => {
|
|
125
|
+
const { items } = datasetRegistry.keyItems()
|
|
126
|
+
const sublayerItems = items.filter(item => item.type === 'sublayers')
|
|
127
|
+
expect(sublayerItems).toHaveLength(2) // land-covers and historic-monuments
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('includes a flat entry for datasets without sublayers and no groupLabel', () => {
|
|
131
|
+
const { items } = datasetRegistry.keyItems()
|
|
132
|
+
const flatItems = items.filter(item => item.type === 'flat')
|
|
133
|
+
expect(flatItems).toHaveLength(1) // existing-fields
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('sets hasGroups to true when any item has sublayers', () => {
|
|
137
|
+
const { hasGroups } = datasetRegistry.keyItems()
|
|
138
|
+
expect(hasGroups).toBe(true)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('sets hasGroups to false when all items are flat with no groupLabel', () => {
|
|
142
|
+
datasetRegistry.attach({ simple: { id: 'simple', showInKey: true, visible: true, style: {} } })
|
|
143
|
+
const { hasGroups } = datasetRegistry.keyItems()
|
|
144
|
+
expect(hasGroups).toBe(false)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('sets hasGroups to false when a dataset has only one sublayer and it is not visible', () => {
|
|
148
|
+
const { mappedDatasets: singleHiddenSublayer } = mappedDatasetsReducer({
|
|
149
|
+
datasets: [{
|
|
150
|
+
id: 'single-sublayer-dataset',
|
|
151
|
+
showInKey: true,
|
|
152
|
+
visible: true,
|
|
153
|
+
style: {},
|
|
154
|
+
sublayers: [{ id: 'sub', visible: false, style: {} }]
|
|
155
|
+
}]
|
|
156
|
+
})
|
|
157
|
+
datasetRegistry.attach(singleHiddenSublayer)
|
|
158
|
+
const { hasGroups } = datasetRegistry.keyItems()
|
|
159
|
+
expect(hasGroups).toBe(false)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('only includes visible sublayers in sublayers items', () => {
|
|
163
|
+
const { items } = datasetRegistry.keyItems()
|
|
164
|
+
const landCoversItem = items.find(item => item.type === 'sublayers' && item.dataset.id === 'land-covers')
|
|
165
|
+
const sublayerIds = landCoversItem.sublayers.map(s => s.id)
|
|
166
|
+
expect(sublayerIds).not.toContain('land-covers-379') // land-covers-379 has visible: false
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('includes a group entry for datasets sharing a groupLabel', () => {
|
|
170
|
+
const { mappedDatasets: grouped } = mappedDatasetsReducer({ datasets: datasetsWithGroups })
|
|
171
|
+
datasetRegistry.attach(grouped)
|
|
172
|
+
const { items } = datasetRegistry.keyItems()
|
|
173
|
+
const groupItems = items.filter(item => item.type === 'group')
|
|
174
|
+
expect(groupItems).toHaveLength(1)
|
|
175
|
+
expect(groupItems[0].groupLabel).toBe('Test group')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('only adds one group entry per unique groupLabel', () => {
|
|
179
|
+
const { mappedDatasets: grouped } = mappedDatasetsReducer({ datasets: datasetsWithGroups })
|
|
180
|
+
datasetRegistry.attach(grouped)
|
|
181
|
+
const { items } = datasetRegistry.keyItems()
|
|
182
|
+
const groupLabels = items.filter(i => i.type === 'group').map(i => i.groupLabel)
|
|
183
|
+
expect(groupLabels.length).toBe(new Set(groupLabels).size)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('populates group item datasets with matching showInKey datasets', () => {
|
|
187
|
+
const { mappedDatasets: grouped } = mappedDatasetsReducer({ datasets: datasetsWithGroups })
|
|
188
|
+
datasetRegistry.attach(grouped)
|
|
189
|
+
const { items } = datasetRegistry.keyItems()
|
|
190
|
+
const groupItem = items.find(item => item.type === 'group' && item.groupLabel === 'Test group')
|
|
191
|
+
const ids = groupItem.datasets.map(d => d.id)
|
|
192
|
+
expect(ids).toContain('existing-fields')
|
|
193
|
+
expect(ids).toContain('hedge-control')
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('caches the result when datasets ref has not changed', () => {
|
|
197
|
+
const result1 = datasetRegistry.keyItems()
|
|
198
|
+
const result2 = datasetRegistry.keyItems()
|
|
199
|
+
expect(result1).toBe(result2)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('recomputes when the datasets ref changes', () => {
|
|
203
|
+
const result1 = datasetRegistry.keyItems()
|
|
204
|
+
datasetRegistry.attach({ simple: { id: 'simple', showInKey: true, visible: true, style: {} } })
|
|
205
|
+
const result2 = datasetRegistry.keyItems()
|
|
206
|
+
expect(result1).not.toBe(result2)
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
describe('attachCreateDataset', () => {
|
|
211
|
+
let originalCreateDataset
|
|
212
|
+
|
|
213
|
+
beforeEach(() => {
|
|
214
|
+
originalCreateDataset = datasetRegistry._createDataset
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
afterEach(() => {
|
|
218
|
+
datasetRegistry._createDataset = originalCreateDataset
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('overrides the factory used by getDataset', () => {
|
|
222
|
+
const customFactory = jest.fn((def) => new Dataset(def))
|
|
223
|
+
datasetRegistry.attachCreateDataset(customFactory)
|
|
224
|
+
datasetRegistry.getDataset('land-covers')
|
|
225
|
+
expect(customFactory).toHaveBeenCalled()
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
it('uses the return value of the custom factory', () => {
|
|
229
|
+
const sentinel = { id: 'sentinel' }
|
|
230
|
+
datasetRegistry.attachCreateDataset(() => sentinel)
|
|
231
|
+
const result = datasetRegistry.getDataset('land-covers')
|
|
232
|
+
expect(result).toBe(sentinel)
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
describe('avoid recreating Dataset instances', () => {
|
|
237
|
+
// Because the registryDataset instances are pure and immutable wrappers
|
|
238
|
+
// around the dataset definition, we can return the same registryDataset
|
|
239
|
+
// instances as long as the definitions are the same.
|
|
240
|
+
// Avoiding unnecessary re-calculation of registryDataset instance members
|
|
241
|
+
// like patternConfigs and symbolConfigs which are derived from the definition.
|
|
242
|
+
const createDatasetSpy = jest.spyOn(datasetRegistry, '_createDataset')
|
|
243
|
+
|
|
244
|
+
it("doesn't throw invalidating before caching anything", () => {
|
|
245
|
+
expect(() => {
|
|
246
|
+
datasetRegistry.attach({
|
|
247
|
+
...datasetRegistry.datasets,
|
|
248
|
+
'land-covers-130-131': { id: 'land-covers-130-131', style: { stroke: '#00ff00' } }
|
|
249
|
+
})
|
|
250
|
+
}).not.toThrow()
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it("doesn't throw if a sublayer without a valid parent is attached", () => {
|
|
254
|
+
expect(() => {
|
|
255
|
+
datasetRegistry.attach({
|
|
256
|
+
...datasetRegistry.datasets,
|
|
257
|
+
'no-parent': { id: 'no-parent', parentId: 'no-exists', style: {} }
|
|
258
|
+
|
|
259
|
+
})
|
|
260
|
+
datasetRegistry.getDataset('no-parent')
|
|
261
|
+
datasetRegistry.attach({
|
|
262
|
+
...datasetRegistry.datasets,
|
|
263
|
+
'no-parent': { id: 'no-parent', parentId: 'no-exists', style: {} }
|
|
264
|
+
})
|
|
265
|
+
}).not.toThrow()
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
it('returns the same Dataset instance for the same dataset definition', () => {
|
|
269
|
+
expect(datasetRegistry.getDataset('land-covers'))
|
|
270
|
+
.toBe(datasetRegistry.getDataset('land-covers'))
|
|
271
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(1)
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('removes cached Dataset instances when new datasets definition are attached', () => {
|
|
275
|
+
const landCovers1 = datasetRegistry.getDataset('land-covers') // createDatasetSpy called once
|
|
276
|
+
const landCovers1Definition = landCovers1._datasetDefinition
|
|
277
|
+
// attach new definitions, with a different land-covers definition
|
|
278
|
+
datasetRegistry.attach({ ...datasetRegistry.datasets, 'land-covers': { id: 'land-covers', style: {} } })
|
|
279
|
+
|
|
280
|
+
expect(datasetRegistry.getDataset('land-covers')).not.toBe(landCovers1) // should be different as the definition has changed
|
|
281
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(2)
|
|
282
|
+
// ensure the old definition is no longer cached - which could cause a memory leak
|
|
283
|
+
expect(datasetRegistry._definitionCache.getByDefinition(landCovers1Definition)).toBeUndefined()
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it('should invalidate the cache of sublayers(children) when a parent dataset definition is updated', () => {
|
|
287
|
+
const landCovers = datasetRegistry.getDataset('land-covers')
|
|
288
|
+
const landCoversSublayer = datasetRegistry.getDataset('land-covers-130-131')
|
|
289
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(2)
|
|
290
|
+
const landCoversDefinition = landCovers._datasetDefinition
|
|
291
|
+
|
|
292
|
+
// Update the parent dataset definition, which should invalidate both the parent and sublayer cache entries
|
|
293
|
+
const newLandCoversDefinition = { ...landCoversDefinition, style: { stroke: '#00ff00' } }
|
|
294
|
+
datasetRegistry.attach({ ...datasetRegistry.datasets, 'land-covers': newLandCoversDefinition })
|
|
295
|
+
|
|
296
|
+
expect(datasetRegistry.getDataset('land-covers')).not.toBe(landCovers)
|
|
297
|
+
expect(datasetRegistry.getDataset('land-covers-130-131')).not.toBe(landCoversSublayer)
|
|
298
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(4)
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
it('should invalidate the cache of the parent and siblings when a sublayers dataset definition is updated', () => {
|
|
302
|
+
const landCovers = datasetRegistry.getDataset('land-covers')
|
|
303
|
+
const landCoversSublayer130 = datasetRegistry.getDataset('land-covers-130-131')
|
|
304
|
+
const landCoversSublayer332 = datasetRegistry.getDataset('land-covers-332')
|
|
305
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(3)
|
|
306
|
+
const sublayerDefinition = landCoversSublayer130._datasetDefinition
|
|
307
|
+
|
|
308
|
+
// Update the parent dataset definition, which should invalidate both the parent and sublayer cache entries
|
|
309
|
+
const newSublayerDefinition = { ...sublayerDefinition, style: { stroke: '#00ff00' } }
|
|
310
|
+
datasetRegistry.attach({ ...datasetRegistry.datasets, 'land-covers-130-131': newSublayerDefinition })
|
|
311
|
+
|
|
312
|
+
expect(datasetRegistry.getDataset('land-covers')).not.toBe(landCovers)
|
|
313
|
+
expect(datasetRegistry.getDataset('land-covers-130-131')).not.toBe(landCoversSublayer130)
|
|
314
|
+
expect(datasetRegistry.getDataset('land-covers-332')).not.toBe(landCoversSublayer332)
|
|
315
|
+
|
|
316
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(6)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('should not invalidate the cache of different datasets when a definition is updated', () => {
|
|
320
|
+
const landCovers = datasetRegistry.getDataset('land-covers')
|
|
321
|
+
const existingFields = datasetRegistry.getDataset('existing-fields')
|
|
322
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(2)
|
|
323
|
+
const existingFieldsDefinition = existingFields._datasetDefinition
|
|
324
|
+
|
|
325
|
+
// Update existing-fields, which should not invalidate land-covers
|
|
326
|
+
const newExistingFieldsDefinition = { id: 'existing-fields', style: {} }
|
|
327
|
+
datasetRegistry.attach({ ...datasetRegistry.datasets, 'existing-fields': newExistingFieldsDefinition })
|
|
328
|
+
|
|
329
|
+
expect(datasetRegistry.getDataset('land-covers')).toBe(landCovers)
|
|
330
|
+
expect(datasetRegistry.getDataset('existing-fields')).not.toBe(existingFields)
|
|
331
|
+
expect(createDatasetSpy).toHaveBeenCalledTimes(3) // should have been called one more time
|
|
332
|
+
expect(datasetRegistry._definitionCache.getByDefinition(existingFieldsDefinition)).toBeUndefined() // old definition should no longer be cached
|
|
333
|
+
})
|
|
334
|
+
})
|
|
335
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class DynamicGeoJson {
|
|
2
|
+
constructor (dynamicGeoJSONDefinition) {
|
|
3
|
+
this.id = dynamicGeoJSONDefinition.id
|
|
4
|
+
this.url = dynamicGeoJSONDefinition.url
|
|
5
|
+
this.transformRequest = dynamicGeoJSONDefinition.transformRequest
|
|
6
|
+
this.maxFeatures = dynamicGeoJSONDefinition.maxFeatures
|
|
7
|
+
this.minZoom = dynamicGeoJSONDefinition.minZoom
|
|
8
|
+
this.idProperty = dynamicGeoJSONDefinition.idProperty
|
|
9
|
+
this.hiddenFeaturesIdExpression = ['to-string', ['get', this.idProperty]]
|
|
10
|
+
this.sourceId = `geojson-dynamic-${this.id}`
|
|
11
|
+
this.source = {
|
|
12
|
+
type: 'geojson',
|
|
13
|
+
data: { type: 'FeatureCollection', features: [] },
|
|
14
|
+
generateId: true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
let globalState = {}
|
|
2
|
+
|
|
3
|
+
export const attachGlobalState = (globalStateRef) => {
|
|
4
|
+
globalState = globalStateRef
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// TODO - remove this once testing finishes
|
|
8
|
+
window.getGlobalState = () => Object.freeze(globalState)
|
|
9
|
+
|
|
10
|
+
const calculateLocalOpacity = (opacityValue, parentOpacityValue) => {
|
|
11
|
+
if (opacityValue === undefined) {
|
|
12
|
+
if (parentOpacityValue === undefined) {
|
|
13
|
+
return globalState.opacity
|
|
14
|
+
}
|
|
15
|
+
return parentOpacityValue
|
|
16
|
+
}
|
|
17
|
+
return opacityValue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const multiplyOpacities = (opacityValue = 1, parentOpacityValue = 1) => {
|
|
21
|
+
return Math.round((opacityValue * parentOpacityValue * globalState.opacity + Number.EPSILON) * 100) / 100
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const calculateOpacity = (opacityValue, parentOpacityValue) => {
|
|
25
|
+
switch (globalState.opacityMode) {
|
|
26
|
+
case 'global':
|
|
27
|
+
return globalState.opacity
|
|
28
|
+
case 'multiply':
|
|
29
|
+
return multiplyOpacities(opacityValue, parentOpacityValue)
|
|
30
|
+
case 'dataset':
|
|
31
|
+
default:
|
|
32
|
+
return calculateLocalOpacity(opacityValue, parentOpacityValue)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const getGlobalVisibility = () => globalState.visible
|