@cdc/map 4.23.2 → 4.23.3
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/cdcmap.js +21645 -21544
- package/examples/default-county.json +1 -1
- package/examples/default-geocode.json +744 -744
- package/examples/default-hex.json +3 -5
- package/examples/example-city-state-no-territories.json +703 -0
- package/examples/example-city-state.json +4 -7
- package/examples/example-city-stateBAD.json +744 -0
- package/examples/gallery/city-state.json +478 -478
- package/examples/world-geocode-data.json +18 -0
- package/examples/world-geocode.json +108 -0
- package/index.html +34 -29
- package/package.json +6 -3
- package/src/CdcMap.jsx +127 -64
- package/src/components/CityList.jsx +35 -35
- package/src/components/CountyMap.jsx +285 -447
- package/src/components/DataTable.jsx +7 -31
- package/src/components/EditorPanel.jsx +227 -102
- package/src/components/Sidebar.jsx +2 -0
- package/src/components/UsaMap.jsx +24 -19
- package/src/components/WorldMap.jsx +40 -8
- package/src/data/feature-test.json +73 -0
- package/src/data/initial-state.js +3 -0
- package/src/data/supported-geos.js +7 -7
- package/src/scss/map.scss +12 -0
- package/src/test/CdcMap.test.jsx +19 -0
- package/vite.config.js +3 -3
- package/src/hooks/useColorPalette.ts +0 -88
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"Country": "Argentina",
|
|
4
|
+
"Cases": "100",
|
|
5
|
+
"Category": "Has not historically reported monkeypox",
|
|
6
|
+
"AsOf": "11 Jul 2022 5:00 PM EDT",
|
|
7
|
+
"longitude": "-63.6",
|
|
8
|
+
"latitude": "-38.4"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"Country": "New York City",
|
|
12
|
+
"Cases": "10",
|
|
13
|
+
"Category": "Has not historically reported monkeypox",
|
|
14
|
+
"AsOf": "11 Jul 2022 5:00 PM EDT",
|
|
15
|
+
"longitude": "-74.006",
|
|
16
|
+
"latitude": "40.712"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"general": {
|
|
3
|
+
"title": "Default World Map",
|
|
4
|
+
"subtext": "",
|
|
5
|
+
"type": "world-geocode",
|
|
6
|
+
"geoType": "world",
|
|
7
|
+
"headerColor": "theme-blue",
|
|
8
|
+
"geoBorderColor": "darkGray",
|
|
9
|
+
"showSidebar": true,
|
|
10
|
+
"showTitle": true,
|
|
11
|
+
"showDownloadButton": true,
|
|
12
|
+
"expandDataTable": true,
|
|
13
|
+
"equalNumberOptIn": true,
|
|
14
|
+
"showDownloadMediaButton": false,
|
|
15
|
+
"displayAsHex": false,
|
|
16
|
+
"displayStateLabels": false,
|
|
17
|
+
"territoriesLabel": "Territories",
|
|
18
|
+
"language": "en",
|
|
19
|
+
"geoLabelOverride": "",
|
|
20
|
+
"hasRegions": false,
|
|
21
|
+
"fullBorder": false,
|
|
22
|
+
"palette": {
|
|
23
|
+
"isReversed": false
|
|
24
|
+
},
|
|
25
|
+
"allowMapZoom": true,
|
|
26
|
+
"hideGeoColumnInTooltip": false,
|
|
27
|
+
"hidePrimaryColumnInTooltip": false,
|
|
28
|
+
"statePicked": {
|
|
29
|
+
"fipsCode": "01",
|
|
30
|
+
"stateName": "Alabama"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"type": "map",
|
|
34
|
+
"color": "pinkpurple",
|
|
35
|
+
"columns": {
|
|
36
|
+
"geo": {
|
|
37
|
+
"name": "Country",
|
|
38
|
+
"label": "Location",
|
|
39
|
+
"tooltip": false,
|
|
40
|
+
"dataTable": true
|
|
41
|
+
},
|
|
42
|
+
"primary": {
|
|
43
|
+
"name": "Cases",
|
|
44
|
+
"label": "Data Label",
|
|
45
|
+
"prefix": "",
|
|
46
|
+
"suffix": "%",
|
|
47
|
+
"dataTable": true,
|
|
48
|
+
"tooltip": true
|
|
49
|
+
},
|
|
50
|
+
"navigate": {
|
|
51
|
+
"name": "Link",
|
|
52
|
+
"tooltip": false,
|
|
53
|
+
"dataTable": false
|
|
54
|
+
},
|
|
55
|
+
"latitude": {
|
|
56
|
+
"name": "latitude"
|
|
57
|
+
},
|
|
58
|
+
"longitude": {
|
|
59
|
+
"name": "longitude"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"legend": {
|
|
63
|
+
"numberOfItems": 3,
|
|
64
|
+
"position": "side",
|
|
65
|
+
"title": "Legend Title",
|
|
66
|
+
"description": "Legend Text",
|
|
67
|
+
"type": "equalnumber",
|
|
68
|
+
"specialClasses": [],
|
|
69
|
+
"separateZero": true,
|
|
70
|
+
"descriptions": {},
|
|
71
|
+
"unified": false,
|
|
72
|
+
"singleColumn": false,
|
|
73
|
+
"singleRow": false,
|
|
74
|
+
"dynamicDescription": false
|
|
75
|
+
},
|
|
76
|
+
"filters": [],
|
|
77
|
+
"dataTable": {
|
|
78
|
+
"title": "Data Table",
|
|
79
|
+
"forceDisplay": true
|
|
80
|
+
},
|
|
81
|
+
"table": {
|
|
82
|
+
"showDownloadUrl": false
|
|
83
|
+
},
|
|
84
|
+
"tooltips": {
|
|
85
|
+
"appearanceType": "hover",
|
|
86
|
+
"linkLabel": "Learn More",
|
|
87
|
+
"capitalizeLabels": true
|
|
88
|
+
},
|
|
89
|
+
"runtime": {
|
|
90
|
+
"editorErrorMessage": []
|
|
91
|
+
},
|
|
92
|
+
"visual": {
|
|
93
|
+
"minBubbleSize": 1,
|
|
94
|
+
"maxBubbleSize": 20,
|
|
95
|
+
"extraBubbleBorder": false,
|
|
96
|
+
"cityStyle": "circle",
|
|
97
|
+
"geoCodeCircleSize": 8,
|
|
98
|
+
"showBubbleZeros": false
|
|
99
|
+
},
|
|
100
|
+
"mapPosition": {
|
|
101
|
+
"coordinates": [
|
|
102
|
+
0,
|
|
103
|
+
30
|
|
104
|
+
],
|
|
105
|
+
"zoom": 1
|
|
106
|
+
},
|
|
107
|
+
"dataUrl": "http://localhost:8080/examples/world-geocode-data.json"
|
|
108
|
+
}
|
package/index.html
CHANGED
|
@@ -1,39 +1,44 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
|
6
|
+
<style type="text/css">
|
|
7
|
+
body {
|
|
8
|
+
margin: 0;
|
|
9
|
+
}
|
|
3
10
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
margin: 0;
|
|
10
|
-
}
|
|
11
|
+
.cdc-map-outer-container {
|
|
12
|
+
min-height: 100vh;
|
|
13
|
+
}
|
|
14
|
+
</style>
|
|
15
|
+
</head>
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
</head>
|
|
17
|
-
|
|
18
|
-
<body>
|
|
19
|
-
<!-- DEFAULT EXAMPLES -->
|
|
20
|
-
<!-- <div class="react-container react-container--maps" data-config="/examples/default-county.json"></div> -->
|
|
21
|
-
<!-- <div class="react-container react-container--maps" data-config="/examples/default-geocode.json"></div>-->
|
|
17
|
+
<body>
|
|
18
|
+
<!-- DEFAULT EXAMPLES -->
|
|
19
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/default-county.json"></div> -->
|
|
20
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/default-geocode.json"></div> -->
|
|
22
21
|
<!-- <div class="react-container react-container--maps" data-config="/examples/default-usa-regions.json"></div> -->
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/default-single-state.json"></div>-->
|
|
23
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/default-world.json"></div>-->
|
|
24
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/bubble-us.json"></div>-->
|
|
25
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/bubble-world.json"></div> -->
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
<!-- TP4 EXAMPLES -->
|
|
28
|
+
<div class="react-container react-container--maps" data-config="/examples/example-city-state.json"></div>
|
|
29
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/example-city-stateBAD.json"></div> -->
|
|
30
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/example-world-map.json"></div> -->
|
|
31
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/default-hex.json"></div> -->
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
<!-- TP4 EXAMPLES -->
|
|
34
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/example-city-state.json"></div> -->
|
|
35
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/example-city-state-no-territories.json"></div> -->
|
|
36
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/example-world-map.json"></div> -->
|
|
37
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/default-hex.json"></div> -->
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
<script type="module" src="./src/index.jsx"></script>
|
|
37
|
-
</body>
|
|
39
|
+
<!-- <div class="react-container" data-config="/examples/example-hex-map-with-filter.json"></div> -->
|
|
38
40
|
|
|
41
|
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
42
|
+
<script type="module" src="./src/index.jsx"></script>
|
|
43
|
+
</body>
|
|
39
44
|
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/map",
|
|
3
|
-
"version": "4.23.
|
|
3
|
+
"version": "4.23.3",
|
|
4
4
|
"description": "React component for visualizing tabular data on a map of the United States or the world.",
|
|
5
5
|
"moduleName": "CdcMap",
|
|
6
6
|
"main": "dist/cdcmap",
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"start": "vite --open",
|
|
10
10
|
"build": "vite build",
|
|
11
|
+
"test": "vitest watch --reporter verbose",
|
|
12
|
+
"test:ui": "vitest --ui",
|
|
11
13
|
"preview": "vite preview",
|
|
12
14
|
"graph": "nx graph",
|
|
13
15
|
"prepublishOnly": "lerna run --scope @cdc/map build"
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
},
|
|
23
25
|
"license": "Apache-2.0",
|
|
24
26
|
"dependencies": {
|
|
25
|
-
"@cdc/core": "^4.23.
|
|
27
|
+
"@cdc/core": "^4.23.3",
|
|
26
28
|
"@emotion/core": "^10.0.28",
|
|
27
29
|
"@emotion/react": "^11.1.5",
|
|
28
30
|
"@hello-pangea/dnd": "^16.2.0",
|
|
@@ -35,6 +37,7 @@
|
|
|
35
37
|
"d3-zoom": "^3.0.0",
|
|
36
38
|
"html-react-parser": "^3.0.8",
|
|
37
39
|
"html2canvas": "^1.0.0-rc.7",
|
|
40
|
+
"lodash.debounce": "^4.0.8",
|
|
38
41
|
"papaparse": "^5.3.0",
|
|
39
42
|
"react-accessible-accordion": "^3.0.1",
|
|
40
43
|
"react-table": "^7.5.0",
|
|
@@ -48,5 +51,5 @@
|
|
|
48
51
|
"react": "^18.2.0",
|
|
49
52
|
"react-dom": "^18.2.0"
|
|
50
53
|
},
|
|
51
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "6fa3b11db159d38538f18023fe70b67a29e7d327"
|
|
52
55
|
}
|
package/src/CdcMap.jsx
CHANGED
|
@@ -88,7 +88,7 @@ const hashObj = row => {
|
|
|
88
88
|
|
|
89
89
|
const indexOfIgnoreType = (arr, item) => {
|
|
90
90
|
for (let i = 0; i < arr.length; i++) {
|
|
91
|
-
if (item
|
|
91
|
+
if (item === arr[i]) {
|
|
92
92
|
return i
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -147,7 +147,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
147
147
|
} catch (e) {
|
|
148
148
|
console.error('Failed to set world map zoom.')
|
|
149
149
|
}
|
|
150
|
-
}, [filteredCountryCode])
|
|
150
|
+
}, [filteredCountryCode]) // eslint-disable-line
|
|
151
151
|
|
|
152
152
|
useEffect(() => {
|
|
153
153
|
setTimeout(() => {
|
|
@@ -159,7 +159,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
159
159
|
setRuntimeData(tmpData)
|
|
160
160
|
}
|
|
161
161
|
}, 100)
|
|
162
|
-
}, [filteredCountryCode])
|
|
162
|
+
}, [filteredCountryCode]) // eslint-disable-line
|
|
163
163
|
|
|
164
164
|
useEffect(() => {
|
|
165
165
|
if (state.mapPosition) {
|
|
@@ -167,6 +167,22 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
167
167
|
}
|
|
168
168
|
}, [state.mapPosition, setPosition])
|
|
169
169
|
|
|
170
|
+
const generateRuntimeLegendHash = () => {
|
|
171
|
+
return hashObj({
|
|
172
|
+
color: state.color,
|
|
173
|
+
customColors: state.customColors,
|
|
174
|
+
numberOfItems: state.legend.numberOfItems,
|
|
175
|
+
type: state.legend.type,
|
|
176
|
+
separateZero: state.legend.separateZero ?? false,
|
|
177
|
+
primary: state.columns.primary.name,
|
|
178
|
+
categoryValuesOrder: state.legend.categoryValuesOrder,
|
|
179
|
+
specialClasses: state.legend.specialClasses,
|
|
180
|
+
geoType: state.general.geoType,
|
|
181
|
+
data: state.data,
|
|
182
|
+
...runtimeFilters
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
const resizeObserver = new ResizeObserver(entries => {
|
|
171
187
|
for (let entry of entries) {
|
|
172
188
|
let newViewport = getViewport(entry.contentRect.width)
|
|
@@ -177,6 +193,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
177
193
|
|
|
178
194
|
// Tag each row with a UID. Helps with filtering/placing geos. Not enumerable so doesn't show up in loops/console logs except when directly addressed ex row.uid
|
|
179
195
|
// We are mutating state in place here (depending on where called) - but it's okay, this isn't used for rerender
|
|
196
|
+
// eslint-disable-next-line
|
|
180
197
|
const addUIDs = useCallback((obj, fromColumn) => {
|
|
181
198
|
obj.data.forEach(row => {
|
|
182
199
|
let uid = null
|
|
@@ -225,6 +242,11 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
225
242
|
const geoName = row[obj.columns.geo.name]
|
|
226
243
|
|
|
227
244
|
uid = countryKeys.find(key => supportedCountries[key].includes(geoName))
|
|
245
|
+
|
|
246
|
+
// Cities
|
|
247
|
+
if (!uid && 'world-geocode' === state.general.type) {
|
|
248
|
+
uid = cityKeys.find(key => key === geoName?.toUpperCase())
|
|
249
|
+
}
|
|
228
250
|
}
|
|
229
251
|
|
|
230
252
|
// County Check
|
|
@@ -248,9 +270,10 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
248
270
|
obj.data.fromColumn = fromColumn
|
|
249
271
|
})
|
|
250
272
|
|
|
273
|
+
// eslint-disable-next-line
|
|
251
274
|
const generateRuntimeLegend = useCallback((obj, runtimeData, hash) => {
|
|
252
275
|
const newLegendMemo = new Map() // Reset memoization
|
|
253
|
-
|
|
276
|
+
let primaryCol = obj.columns.primary.name,
|
|
254
277
|
isBubble = obj.general.type === 'bubble',
|
|
255
278
|
categoricalCol = obj.columns.categorical ? obj.columns.categorical.name : undefined,
|
|
256
279
|
type = obj.legend.type,
|
|
@@ -457,6 +480,11 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
457
480
|
}
|
|
458
481
|
|
|
459
482
|
legendMemo.current = newLegendMemo
|
|
483
|
+
|
|
484
|
+
result.forEach((row, i) => {
|
|
485
|
+
row.bin = i // set bin number to index
|
|
486
|
+
})
|
|
487
|
+
|
|
460
488
|
return result
|
|
461
489
|
}
|
|
462
490
|
|
|
@@ -536,6 +564,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
536
564
|
let min = removedRows[0][primaryCol],
|
|
537
565
|
max = removedRows[removedRows.length - 1][primaryCol]
|
|
538
566
|
|
|
567
|
+
// eslint-disable-next-line
|
|
539
568
|
removedRows.forEach(row => {
|
|
540
569
|
newLegendMemo.set(hashObj(row), result.length)
|
|
541
570
|
})
|
|
@@ -574,6 +603,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
574
603
|
breaks.unshift(0)
|
|
575
604
|
}
|
|
576
605
|
|
|
606
|
+
// eslint-disable-next-line array-callback-return
|
|
577
607
|
breaks.map((item, index) => {
|
|
578
608
|
const setMin = index => {
|
|
579
609
|
let min = breaks[index]
|
|
@@ -646,7 +676,6 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
646
676
|
}
|
|
647
677
|
|
|
648
678
|
// Equal Interval
|
|
649
|
-
|
|
650
679
|
if (type === 'equalinterval' && dataSet?.length !== 0) {
|
|
651
680
|
if (!dataSet || dataSet.length === 0) {
|
|
652
681
|
setState({
|
|
@@ -695,11 +724,29 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
695
724
|
})
|
|
696
725
|
|
|
697
726
|
legendMemo.current = newLegendMemo
|
|
727
|
+
|
|
728
|
+
//----------
|
|
729
|
+
// DEV-784
|
|
730
|
+
// before returning the legend result
|
|
731
|
+
// add property for bin number and set to index location
|
|
732
|
+
result.forEach((row, i) => {
|
|
733
|
+
row.bin = i // set bin number to index
|
|
734
|
+
})
|
|
735
|
+
|
|
736
|
+
// Move all special legend items from "Special Classes" to the end of the legend
|
|
737
|
+
if (state.legend.showSpecialClassesLast) {
|
|
738
|
+
let specialRows = result.filter(d => d.special === true)
|
|
739
|
+
let otherRows = result.filter(d => !d.special)
|
|
740
|
+
result = [...otherRows, ...specialRows]
|
|
741
|
+
}
|
|
742
|
+
//-----------
|
|
743
|
+
|
|
698
744
|
return result
|
|
699
745
|
})
|
|
700
746
|
|
|
747
|
+
// eslint-disable-next-line
|
|
701
748
|
const generateRuntimeFilters = useCallback((obj, hash, runtimeFilters) => {
|
|
702
|
-
if (undefined === obj.filters || obj.filters.length === 0) return []
|
|
749
|
+
if (typeof obj === 'undefined' || undefined === obj.filters || obj.filters.length === 0) return []
|
|
703
750
|
|
|
704
751
|
let filters = []
|
|
705
752
|
|
|
@@ -750,17 +797,17 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
750
797
|
})
|
|
751
798
|
|
|
752
799
|
// Calculates what's going to be displayed on the map and data table at render.
|
|
800
|
+
// eslint-disable-next-line
|
|
753
801
|
const generateRuntimeData = useCallback((obj, filters, hash, test) => {
|
|
754
802
|
try {
|
|
755
803
|
const result = {}
|
|
756
804
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
})
|
|
762
|
-
}
|
|
805
|
+
// Adding property this way prevents it from being enumerated
|
|
806
|
+
Object.defineProperty(result, 'fromHash', {
|
|
807
|
+
value: hash
|
|
808
|
+
})
|
|
763
809
|
|
|
810
|
+
addUIDs(obj, obj.columns.geo.name)
|
|
764
811
|
obj.data.forEach(row => {
|
|
765
812
|
if (test) {
|
|
766
813
|
console.log('object', obj)
|
|
@@ -816,7 +863,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
816
863
|
resizeObserver.observe(node)
|
|
817
864
|
}
|
|
818
865
|
setContainer(node)
|
|
819
|
-
}, [])
|
|
866
|
+
}, []) // eslint-disable-line
|
|
820
867
|
|
|
821
868
|
const mapSvg = useRef(null)
|
|
822
869
|
|
|
@@ -897,6 +944,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
897
944
|
return formattedValue
|
|
898
945
|
}
|
|
899
946
|
|
|
947
|
+
// this is passed DOWN into the various components
|
|
948
|
+
// then they do a lookup based on the bin number as index into here (TT)
|
|
900
949
|
const applyLegendToRow = rowObj => {
|
|
901
950
|
try {
|
|
902
951
|
if (!rowObj) throw new Error('COVE: No rowObj in applyLegendToRow')
|
|
@@ -911,7 +960,11 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
911
960
|
if (legendMemo.current.has(hash)) {
|
|
912
961
|
let idx = legendMemo.current.get(hash)
|
|
913
962
|
if (runtimeLegend[idx]?.disabled) return false
|
|
914
|
-
|
|
963
|
+
|
|
964
|
+
// DEV-784 changed to use bin prop to get color instead of idx
|
|
965
|
+
// bc we re-order legend when showSpecialClassesLast is checked
|
|
966
|
+
let legendBinColor = runtimeLegend.find(o => o.bin === idx)?.color
|
|
967
|
+
return generateColorsArray(legendBinColor, runtimeLegend[idx]?.special)
|
|
915
968
|
}
|
|
916
969
|
|
|
917
970
|
// Fail state
|
|
@@ -927,6 +980,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
927
980
|
|
|
928
981
|
// Adds geo label, ie State: Georgia
|
|
929
982
|
let stateOrCounty = state.general.geoType === 'us' ? 'State: ' : state.general.geoType === 'us-county' || state.general.geoType === 'single-state' ? 'County: ' : ''
|
|
983
|
+
|
|
930
984
|
// check the override
|
|
931
985
|
stateOrCounty = state.general.geoLabelOverride !== '' ? state.general.geoLabelOverride + ': ' : stateOrCounty
|
|
932
986
|
|
|
@@ -939,7 +993,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
939
993
|
|
|
940
994
|
toolTipText += !state.general.hideGeoColumnInTooltip ? `<strong>${stateOrCounty}${displayGeoName(geoName)}</strong>` : `<strong>${displayGeoName(geoName)}</strong>`
|
|
941
995
|
|
|
942
|
-
if (('data' === state.general.type || state.general.type === 'bubble' || state.general.type === 'us-geocode') && undefined !== row) {
|
|
996
|
+
if (('data' === state.general.type || state.general.type === 'bubble' || state.general.type === 'us-geocode' || state.general.type === 'world-geocode') && undefined !== row) {
|
|
943
997
|
toolTipText += `<dl>`
|
|
944
998
|
|
|
945
999
|
Object.keys(state.columns).forEach(columnKey => {
|
|
@@ -951,10 +1005,15 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
951
1005
|
let value
|
|
952
1006
|
|
|
953
1007
|
if (state.legend.specialClasses && state.legend.specialClasses.length && typeof state.legend.specialClasses[0] === 'object') {
|
|
1008
|
+
// THIS CODE SHOULD NOT ACT ON THE ENTIRE ROW OF KEYS BUT ONLY THE ONE KEY IN THE SPECIAL CLASS
|
|
954
1009
|
for (let i = 0; i < state.legend.specialClasses.length; i++) {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1010
|
+
// DEV-3303 - Special Classes label in HOVERS should only apply to selected special class key
|
|
1011
|
+
// - you have to ALSO check that the key matches - putting here otherwise the if stmt too long
|
|
1012
|
+
if (columnKey === state.legend.specialClasses[i].key) {
|
|
1013
|
+
if (String(row[state.legend.specialClasses[i].key]) === state.legend.specialClasses[i].value) {
|
|
1014
|
+
value = displayDataAsText(state.legend.specialClasses[i].label, columnKey)
|
|
1015
|
+
break
|
|
1016
|
+
}
|
|
958
1017
|
}
|
|
959
1018
|
}
|
|
960
1019
|
}
|
|
@@ -1100,6 +1159,17 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1100
1159
|
setSharedFilter(state.uid, value)
|
|
1101
1160
|
}
|
|
1102
1161
|
|
|
1162
|
+
// If world-geocode map zoom to geo point
|
|
1163
|
+
if ('world-geocode' === state.general.type) {
|
|
1164
|
+
let lat = value[state.columns.latitude.name]
|
|
1165
|
+
let long = value[state.columns.longitude.name]
|
|
1166
|
+
|
|
1167
|
+
setState({
|
|
1168
|
+
...state,
|
|
1169
|
+
mapPosition: { coordinates: [long, lat], zoom: 3 }
|
|
1170
|
+
})
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1103
1173
|
// If modals are set or we are on a mobile viewport, display modal
|
|
1104
1174
|
if (window.matchMedia('(any-hover: none)').matches || 'click' === state.tooltips.appearanceType) {
|
|
1105
1175
|
setModal({
|
|
@@ -1247,28 +1317,28 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1247
1317
|
// Initial load
|
|
1248
1318
|
useEffect(() => {
|
|
1249
1319
|
init()
|
|
1250
|
-
}, [])
|
|
1320
|
+
}, []) // eslint-disable-line
|
|
1251
1321
|
|
|
1252
1322
|
useEffect(() => {
|
|
1253
1323
|
if (state && !coveLoadedHasRan && container) {
|
|
1254
1324
|
publish('cove_loaded', { config: state })
|
|
1255
1325
|
setCoveLoadedHasRan(true)
|
|
1256
1326
|
}
|
|
1257
|
-
}, [state, container])
|
|
1327
|
+
}, [state, container]) // eslint-disable-line
|
|
1258
1328
|
|
|
1259
1329
|
useEffect(() => {
|
|
1260
1330
|
if (state.data) {
|
|
1261
1331
|
let newData = generateRuntimeData(state)
|
|
1262
1332
|
setRuntimeData(newData)
|
|
1263
1333
|
}
|
|
1264
|
-
}, [state.general.statePicked])
|
|
1334
|
+
}, [state.general.statePicked]) // eslint-disable-line
|
|
1265
1335
|
|
|
1266
1336
|
useEffect(() => {
|
|
1267
1337
|
// When geotype changes - add UID
|
|
1268
1338
|
if (state.data && state.columns.geo.name) {
|
|
1269
1339
|
addUIDs(state, state.columns.geo.name)
|
|
1270
1340
|
}
|
|
1271
|
-
}, [state])
|
|
1341
|
+
}, [state]) // eslint-disable-line
|
|
1272
1342
|
|
|
1273
1343
|
// DEV-769 make "Data Table" both a required field and default value
|
|
1274
1344
|
useEffect(() => {
|
|
@@ -1281,13 +1351,13 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1281
1351
|
}
|
|
1282
1352
|
})
|
|
1283
1353
|
}
|
|
1284
|
-
}, [state.dataTable])
|
|
1354
|
+
}, [state.dataTable]) // eslint-disable-line
|
|
1285
1355
|
|
|
1286
1356
|
// When geo label override changes
|
|
1287
1357
|
// - redo the tooltips
|
|
1288
1358
|
useEffect(() => {
|
|
1289
1359
|
applyTooltipsToGeo()
|
|
1290
|
-
}, [state.general.geoLabelOverride])
|
|
1360
|
+
}, [state.general.geoLabelOverride]) // eslint-disable-line
|
|
1291
1361
|
|
|
1292
1362
|
useEffect(() => {
|
|
1293
1363
|
// UID
|
|
@@ -1307,28 +1377,15 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1307
1377
|
}
|
|
1308
1378
|
}
|
|
1309
1379
|
|
|
1310
|
-
const hashLegend =
|
|
1311
|
-
color: state.color,
|
|
1312
|
-
customColors: state.customColors,
|
|
1313
|
-
numberOfItems: state.legend.numberOfItems,
|
|
1314
|
-
type: state.legend.type,
|
|
1315
|
-
separateZero: state.legend.separateZero ?? false,
|
|
1316
|
-
categoryValuesOrder: state.legend.categoryValuesOrder,
|
|
1317
|
-
specialClasses: state.legend.specialClasses,
|
|
1318
|
-
geoType: state.general.geoType,
|
|
1319
|
-
data: state.data,
|
|
1320
|
-
...runtimeLegend,
|
|
1321
|
-
...runtimeFilters
|
|
1322
|
-
})
|
|
1380
|
+
const hashLegend = generateRuntimeLegendHash()
|
|
1323
1381
|
|
|
1324
1382
|
const hashData = hashObj({
|
|
1383
|
+
data: state.data,
|
|
1325
1384
|
columns: state.columns,
|
|
1326
1385
|
geoType: state.general.geoType,
|
|
1327
1386
|
type: state.general.type,
|
|
1328
1387
|
geo: state.columns.geo.name,
|
|
1329
1388
|
primary: state.columns.primary.name,
|
|
1330
|
-
data: state.data,
|
|
1331
|
-
...runtimeFilters,
|
|
1332
1389
|
mapPosition: state.mapPosition,
|
|
1333
1390
|
...runtimeFilters
|
|
1334
1391
|
})
|
|
@@ -1345,38 +1402,34 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1345
1402
|
const legend = generateRuntimeLegend(state, newRuntimeData || runtimeData, hashLegend)
|
|
1346
1403
|
setRuntimeLegend(legend)
|
|
1347
1404
|
}
|
|
1348
|
-
}, [state])
|
|
1405
|
+
}, [state]) // eslint-disable-line
|
|
1349
1406
|
|
|
1350
1407
|
useEffect(() => {
|
|
1351
|
-
const hashLegend =
|
|
1352
|
-
color: state.color,
|
|
1353
|
-
customColors: state.customColors,
|
|
1354
|
-
numberOfItems: state.legend.numberOfItems,
|
|
1355
|
-
type: state.legend.type,
|
|
1356
|
-
separateZero: state.legend.separateZero ?? false,
|
|
1357
|
-
categoryValuesOrder: state.legend.categoryValuesOrder,
|
|
1358
|
-
specialClasses: state.legend.specialClasses,
|
|
1359
|
-
geoType: state.general.geoType,
|
|
1360
|
-
data: state.data
|
|
1361
|
-
})
|
|
1408
|
+
const hashLegend = generateRuntimeLegendHash()
|
|
1362
1409
|
|
|
1363
1410
|
// Legend - Update when runtimeData does
|
|
1364
1411
|
if (hashLegend !== runtimeLegend.fromHash && undefined === runtimeData.init) {
|
|
1365
|
-
const legend = generateRuntimeLegend(state, runtimeData)
|
|
1412
|
+
const legend = generateRuntimeLegend(state, runtimeData, hashLegend)
|
|
1366
1413
|
setRuntimeLegend(legend)
|
|
1367
1414
|
}
|
|
1368
|
-
}, [runtimeData])
|
|
1415
|
+
}, [runtimeData]) // eslint-disable-line
|
|
1369
1416
|
|
|
1370
1417
|
if (config) {
|
|
1371
1418
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
1372
1419
|
useEffect(() => {
|
|
1373
1420
|
loadConfig(config)
|
|
1374
|
-
}, [config.data])
|
|
1421
|
+
}, [config.data]) // eslint-disable-line
|
|
1375
1422
|
}
|
|
1376
1423
|
|
|
1377
1424
|
// Destructuring for more readable JSX
|
|
1378
1425
|
const { general, tooltips, dataTable } = state
|
|
1379
|
-
|
|
1426
|
+
let { title, subtext = '' } = general
|
|
1427
|
+
|
|
1428
|
+
// if no title AND in editor then set a default
|
|
1429
|
+
if (isEditor) {
|
|
1430
|
+
if (!title || title === '') title = 'Map Title'
|
|
1431
|
+
}
|
|
1432
|
+
if (!dataTable.title || dataTable.title === '') dataTable.title = 'Data Table'
|
|
1380
1433
|
|
|
1381
1434
|
// Outer container classes
|
|
1382
1435
|
let outerContainerClasses = ['cdc-open-viz-module', 'cdc-map-outer-container', currentViewport]
|
|
@@ -1421,7 +1474,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1421
1474
|
handleMapAriaLabels,
|
|
1422
1475
|
runtimeFilters,
|
|
1423
1476
|
setRuntimeFilters,
|
|
1424
|
-
innerContainerRef
|
|
1477
|
+
innerContainerRef,
|
|
1478
|
+
currentViewport
|
|
1425
1479
|
}
|
|
1426
1480
|
|
|
1427
1481
|
if (!mapProps.data || !state.data) return <Loading />
|
|
@@ -1455,13 +1509,24 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1455
1509
|
return (
|
|
1456
1510
|
<ConfigContext.Provider value={mapProps}>
|
|
1457
1511
|
<div className={outerContainerClasses.join(' ')} ref={outerContainerRef} data-download-id={imageId}>
|
|
1458
|
-
{isEditor &&
|
|
1512
|
+
{isEditor && (
|
|
1513
|
+
<EditorPanel
|
|
1514
|
+
isDashboard={isDashboard}
|
|
1515
|
+
state={state}
|
|
1516
|
+
setState={setState}
|
|
1517
|
+
loadConfig={loadConfig}
|
|
1518
|
+
setParentConfig={setConfig}
|
|
1519
|
+
setRuntimeFilters={setRuntimeFilters}
|
|
1520
|
+
runtimeFilters={runtimeFilters}
|
|
1521
|
+
runtimeLegend={runtimeLegend}
|
|
1522
|
+
columnsInData={Object.keys(state.data[0])}
|
|
1523
|
+
changeFilterActive={changeFilterActive}
|
|
1524
|
+
/>
|
|
1525
|
+
)}
|
|
1459
1526
|
{!runtimeData.init && (general.type === 'navigation' || runtimeLegend) && (
|
|
1460
1527
|
<section className={`cdc-map-inner-container ${currentViewport}`} aria-label={'Map: ' + title} ref={innerContainerRef}>
|
|
1461
|
-
{!window.matchMedia('(any-hover: none)').matches && 'hover' === tooltips.appearanceType &&
|
|
1462
|
-
|
|
1463
|
-
}
|
|
1464
|
-
{state.general.title && (
|
|
1528
|
+
{!window.matchMedia('(any-hover: none)').matches && 'hover' === tooltips.appearanceType && <ReactTooltip id='tooltip' variant='light' float={true} className={`${tooltips.capitalizeLabels ? 'capitalize tooltip' : 'tooltip'}`} />}
|
|
1529
|
+
{title && (
|
|
1465
1530
|
<header className={general.showTitle === true ? 'visible' : 'hidden'} {...(!general.showTitle || !state.general.title ? { 'aria-hidden': true } : { 'aria-hidden': false })}>
|
|
1466
1531
|
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}
|
|
1467
1532
|
<div role='heading' className={'map-title ' + general.headerColor} tabIndex='0' aria-level='2'>
|
|
@@ -1470,9 +1535,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1470
1535
|
</div>
|
|
1471
1536
|
</header>
|
|
1472
1537
|
)}
|
|
1473
|
-
{general.introText &&
|
|
1474
|
-
<section className='introText'>{parse(general.introText)}</section>
|
|
1475
|
-
}
|
|
1538
|
+
{general.introText && <section className='introText'>{parse(general.introText)}</section>}
|
|
1476
1539
|
|
|
1477
1540
|
<Filters />
|
|
1478
1541
|
|