@cdc/map 4.24.1 → 4.24.2
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 +50477 -45394
- package/examples/test.json +0 -9614
- package/examples/{private/zika-issue.json → zika.json} +47 -51
- package/index.html +8 -3
- package/package.json +3 -3
- package/src/CdcMap.tsx +29 -16
- package/src/components/CityList.jsx +34 -23
- package/src/components/EditorPanel/components/EditorPanel.tsx +3 -4
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +2 -2
- package/src/components/Geo.jsx +4 -2
- package/src/components/Legend/components/LegendItem.Hex.tsx +5 -9
- package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +2 -2
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +0 -1
- package/src/components/UsaMap/components/UsaMap.State.tsx +3 -4
- package/src/components/WorldMap/components/WorldMap.jsx +14 -8
- package/src/components/WorldMap/data/world-topo-guiana-update.json +1 -0
- package/src/components/WorldMap/data/world-topo-old.json +1 -0
- package/{examples/private/new-world.json → src/components/WorldMap/data/world-topo-recent.json} +23137 -22280
- package/src/components/WorldMap/data/world-topo.json +1 -1
- package/src/data/initial-state.js +2 -2
- package/src/data/supported-geos.js +21 -1
- package/src/hooks/useTooltip.ts +4 -4
- package/src/scss/editor-panel.scss +2 -3
- package/src/scss/map.scss +22 -12
- package/examples/private/map-text-wrap.json +0 -574
- package/examples/private/map-world-data.json +0 -1046
- package/examples/world-geocode-data.json +0 -18
- package/examples/world-geocode.json +0 -108
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"general": {
|
|
3
|
-
"title": "Default World Map",
|
|
4
|
-
"subtext": "",
|
|
5
|
-
"type": "data",
|
|
6
3
|
"geoType": "world",
|
|
7
|
-
"headerColor": "theme-blue",
|
|
8
4
|
"geoBorderColor": "darkGray",
|
|
5
|
+
"headerColor": "theme-blue",
|
|
6
|
+
"title": "Countries and territories where Zika cases have been reported (as of October 5, 2023)*",
|
|
7
|
+
"showTitle": false,
|
|
9
8
|
"showSidebar": true,
|
|
10
|
-
"showTitle": true,
|
|
11
9
|
"showDownloadButton": true,
|
|
12
|
-
"expandDataTable": true,
|
|
13
|
-
"equalNumberOptIn": true,
|
|
14
10
|
"showDownloadMediaButton": false,
|
|
15
11
|
"displayAsHex": false,
|
|
16
12
|
"displayStateLabels": false,
|
|
@@ -20,9 +16,10 @@
|
|
|
20
16
|
"geoLabelOverride": "",
|
|
21
17
|
"hasRegions": false,
|
|
22
18
|
"fullBorder": false,
|
|
19
|
+
"type": "data",
|
|
23
20
|
"convertFipsCodes": true,
|
|
24
21
|
"palette": {
|
|
25
|
-
"isReversed":
|
|
22
|
+
"isReversed": true
|
|
26
23
|
},
|
|
27
24
|
"allowMapZoom": true,
|
|
28
25
|
"hideGeoColumnInTooltip": false,
|
|
@@ -30,10 +27,12 @@
|
|
|
30
27
|
"statePicked": {
|
|
31
28
|
"fipsCode": "01",
|
|
32
29
|
"stateName": "Alabama"
|
|
33
|
-
}
|
|
30
|
+
},
|
|
31
|
+
"footnotes": "*Does not include countries or territories where only imported cases have been documented. Small island nations might not display on the map but data are included in the table above.",
|
|
32
|
+
"introText": ""
|
|
34
33
|
},
|
|
35
34
|
"type": "map",
|
|
36
|
-
"color": "
|
|
35
|
+
"color": "sequential-blue-2(MPX)reverse",
|
|
37
36
|
"columns": {
|
|
38
37
|
"geo": {
|
|
39
38
|
"name": "Country",
|
|
@@ -42,17 +41,15 @@
|
|
|
42
41
|
"dataTable": true
|
|
43
42
|
},
|
|
44
43
|
"primary": {
|
|
45
|
-
"name": "Category",
|
|
46
|
-
"label": "Data Label",
|
|
47
|
-
"prefix": "",
|
|
48
|
-
"suffix": "%",
|
|
49
44
|
"dataTable": true,
|
|
50
|
-
"tooltip": true
|
|
45
|
+
"tooltip": true,
|
|
46
|
+
"prefix": "",
|
|
47
|
+
"suffix": "",
|
|
48
|
+
"name": "Category",
|
|
49
|
+
"label": ""
|
|
51
50
|
},
|
|
52
51
|
"navigate": {
|
|
53
|
-
"name": "
|
|
54
|
-
"tooltip": false,
|
|
55
|
-
"dataTable": false
|
|
52
|
+
"name": ""
|
|
56
53
|
},
|
|
57
54
|
"latitude": {
|
|
58
55
|
"name": ""
|
|
@@ -62,30 +59,22 @@
|
|
|
62
59
|
}
|
|
63
60
|
},
|
|
64
61
|
"legend": {
|
|
65
|
-
"numberOfItems": 3,
|
|
66
|
-
"position": "side",
|
|
67
|
-
"title": "Legend Title",
|
|
68
|
-
"description": "Legend Text",
|
|
69
|
-
"type": "category",
|
|
70
|
-
"specialClasses": [
|
|
71
|
-
{
|
|
72
|
-
"key": "Data",
|
|
73
|
-
"value": "N/A",
|
|
74
|
-
"label": "N/A"
|
|
75
|
-
}
|
|
76
|
-
],
|
|
77
|
-
"separateZero": true,
|
|
78
62
|
"descriptions": {},
|
|
63
|
+
"specialClasses": [],
|
|
79
64
|
"unified": false,
|
|
80
65
|
"singleColumn": false,
|
|
81
66
|
"singleRow": false,
|
|
82
67
|
"verticalSorted": false,
|
|
83
68
|
"showSpecialClassesLast": false,
|
|
84
69
|
"dynamicDescription": false,
|
|
70
|
+
"type": "category",
|
|
71
|
+
"numberOfItems": 3,
|
|
72
|
+
"position": "bottom",
|
|
73
|
+
"title": "Legend",
|
|
85
74
|
"categoryValuesOrder": [
|
|
75
|
+
"Current or past Zika transmission",
|
|
86
76
|
"Known to have mosquito that transmits Zika, but no reported Zika cases ",
|
|
87
|
-
"Not known to have mosquito that transmits Zika"
|
|
88
|
-
"Current or past Zika transmission"
|
|
77
|
+
"Not known to have mosquito that transmits Zika"
|
|
89
78
|
]
|
|
90
79
|
},
|
|
91
80
|
"filters": [],
|
|
@@ -96,11 +85,12 @@
|
|
|
96
85
|
"height": "",
|
|
97
86
|
"caption": "",
|
|
98
87
|
"showDownloadUrl": false,
|
|
99
|
-
"showDataTableLink":
|
|
88
|
+
"showDataTableLink": false,
|
|
100
89
|
"showFullGeoNameInCSV": false,
|
|
101
90
|
"forceDisplay": true,
|
|
102
|
-
"download":
|
|
103
|
-
"indexLabel": ""
|
|
91
|
+
"download": true,
|
|
92
|
+
"indexLabel": "",
|
|
93
|
+
"wrapColumns": false
|
|
104
94
|
},
|
|
105
95
|
"tooltips": {
|
|
106
96
|
"appearanceType": "hover",
|
|
@@ -108,9 +98,6 @@
|
|
|
108
98
|
"capitalizeLabels": true,
|
|
109
99
|
"opacity": 90
|
|
110
100
|
},
|
|
111
|
-
"runtime": {
|
|
112
|
-
"editorErrorMessage": []
|
|
113
|
-
},
|
|
114
101
|
"visual": {
|
|
115
102
|
"minBubbleSize": 1,
|
|
116
103
|
"maxBubbleSize": 20,
|
|
@@ -127,7 +114,8 @@
|
|
|
127
114
|
"zoom": 1
|
|
128
115
|
},
|
|
129
116
|
"map": {
|
|
130
|
-
"layers": []
|
|
117
|
+
"layers": [],
|
|
118
|
+
"patterns": []
|
|
131
119
|
},
|
|
132
120
|
"hexMap": {
|
|
133
121
|
"type": "",
|
|
@@ -148,6 +136,10 @@
|
|
|
148
136
|
]
|
|
149
137
|
},
|
|
150
138
|
"filterBehavior": "Filter Change",
|
|
139
|
+
"openModal": false,
|
|
140
|
+
"uid": "map1701275481219",
|
|
141
|
+
"editing": true,
|
|
142
|
+
"validated": 4.23,
|
|
151
143
|
"data": [
|
|
152
144
|
{
|
|
153
145
|
"Country": "Afghanistan",
|
|
@@ -182,7 +174,7 @@
|
|
|
182
174
|
"Category": "Current or past Zika transmission"
|
|
183
175
|
},
|
|
184
176
|
{
|
|
185
|
-
"Country": "
|
|
177
|
+
"Country": "Antarctica",
|
|
186
178
|
"Category": "Not known to have mosquito that transmits Zika"
|
|
187
179
|
},
|
|
188
180
|
{
|
|
@@ -361,10 +353,6 @@
|
|
|
361
353
|
"Country": "Comoros",
|
|
362
354
|
"Category": "Not known to have mosquito that transmits Zika"
|
|
363
355
|
},
|
|
364
|
-
{
|
|
365
|
-
"Country": "Continental United States",
|
|
366
|
-
"Category": "Known to have mosquito that transmits Zika, but no reported Zika cases "
|
|
367
|
-
},
|
|
368
356
|
{
|
|
369
357
|
"Country": "Cook Islands",
|
|
370
358
|
"Category": "Current or past Zika transmission"
|
|
@@ -719,7 +707,7 @@
|
|
|
719
707
|
},
|
|
720
708
|
{
|
|
721
709
|
"Country": "Mali",
|
|
722
|
-
"Category": "
|
|
710
|
+
"Category": "Current or past Zika transmission"
|
|
723
711
|
},
|
|
724
712
|
{
|
|
725
713
|
"Country": "Malta",
|
|
@@ -854,7 +842,7 @@
|
|
|
854
842
|
"Category": "Current or past Zika transmission"
|
|
855
843
|
},
|
|
856
844
|
{
|
|
857
|
-
"Country": "
|
|
845
|
+
"Country": "Gaza/West Bank",
|
|
858
846
|
"Category": "Not known to have mosquito that transmits Zika"
|
|
859
847
|
},
|
|
860
848
|
{
|
|
@@ -942,11 +930,11 @@
|
|
|
942
930
|
"Category": "Current or past Zika transmission"
|
|
943
931
|
},
|
|
944
932
|
{
|
|
945
|
-
"Country": "
|
|
933
|
+
"Country": "Sicily",
|
|
946
934
|
"Category": "Not known to have mosquito that transmits Zika"
|
|
947
935
|
},
|
|
948
936
|
{
|
|
949
|
-
"Country": "Saint
|
|
937
|
+
"Country": "Saint Paul and Amsterdam Islands",
|
|
950
938
|
"Category": "Not known to have mosquito that transmits Zika"
|
|
951
939
|
},
|
|
952
940
|
{
|
|
@@ -1141,6 +1129,10 @@
|
|
|
1141
1129
|
"Country": "United States Minor Outlying Islands",
|
|
1142
1130
|
"Category": "Not known to have mosquito that transmits Zika"
|
|
1143
1131
|
},
|
|
1132
|
+
{
|
|
1133
|
+
"Country": "United States of America",
|
|
1134
|
+
"Category": "Known to have mosquito that transmits Zika, but no reported Zika cases "
|
|
1135
|
+
},
|
|
1144
1136
|
{
|
|
1145
1137
|
"Country": "Uruguay",
|
|
1146
1138
|
"Category": "Known to have mosquito that transmits Zika, but no reported Zika cases "
|
|
@@ -1190,9 +1182,13 @@
|
|
|
1190
1182
|
"Category": "Known to have mosquito that transmits Zika, but no reported Zika cases "
|
|
1191
1183
|
},
|
|
1192
1184
|
{
|
|
1193
|
-
"Country": "
|
|
1185
|
+
"Country": "Dhekelia",
|
|
1194
1186
|
"Category": "Known to have mosquito that transmits Zika, but no reported Zika cases "
|
|
1195
1187
|
}
|
|
1196
1188
|
],
|
|
1197
|
-
"
|
|
1189
|
+
"dataDescription": {
|
|
1190
|
+
"series": false,
|
|
1191
|
+
"horizontal": false
|
|
1192
|
+
},
|
|
1193
|
+
"dataKey": "Map-data-1_23_24-wMali.csv"
|
|
1198
1194
|
}
|
package/index.html
CHANGED
|
@@ -11,11 +11,16 @@
|
|
|
11
11
|
.cdc-map-outer-container {
|
|
12
12
|
min-height: 100vh;
|
|
13
13
|
}
|
|
14
|
+
/* .alaska,
|
|
15
|
+
.hawaii {
|
|
16
|
+
display: none;
|
|
17
|
+
} */
|
|
14
18
|
</style>
|
|
15
19
|
</head>
|
|
16
20
|
|
|
17
21
|
<body>
|
|
18
22
|
<!-- DEFAULT EXAMPLES -->
|
|
23
|
+
<!-- <div class="react-container" data-config="/examples/private/antarctica.json"></div> -->
|
|
19
24
|
<!-- <div class="react-container" data-config="/examples/private/zika-issue.json"></div> -->
|
|
20
25
|
|
|
21
26
|
<!-- <div class="react-container react-container--maps" data-config="/examples/private/tooltip-issue.json"></div> -->
|
|
@@ -38,15 +43,15 @@
|
|
|
38
43
|
<!-- <div class="react-container" data-config="/examples/private/wastewater.json"></div> -->
|
|
39
44
|
|
|
40
45
|
<!-- TP4 EXAMPLES -->
|
|
41
|
-
<!-- <div class="react-container react-container--maps" data-config="/examples/
|
|
46
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/private/solr.json"></div> -->
|
|
42
47
|
<!-- <div class="react-container react-container--maps" data-config="/examples/custom-map-layers.json"></div> -->
|
|
43
48
|
<!-- <div class="react-container react-container--maps" data-config="/examples/example-city-stateBAD.json"></div> -->
|
|
44
|
-
<div class="react-container react-container--maps" data-config="/examples/
|
|
49
|
+
<!-- <div class="react-container react-container--maps" data-config="/examples/private/world-map.json"></div> -->
|
|
45
50
|
<!-- <div class="react-container react-container--maps" data-config="/examples/default-hex.json"></div> -->
|
|
46
51
|
<!-- <div class="react-container react-container--maps" data-config="/examples/hex-with-arrows.json"></div> -->
|
|
47
52
|
|
|
48
53
|
<!-- TP4 EXAMPLES -->
|
|
49
|
-
|
|
54
|
+
<div class="react-container react-container--maps" data-config="/examples/example-city-state.json"></div>
|
|
50
55
|
<!-- <div class="react-container react-container--maps" data-config="/examples/example-city-state-no-territories.json"></div> -->
|
|
51
56
|
<!-- <div class="react-container react-container--maps" data-config="/examples/example-world-map.json"></div> -->
|
|
52
57
|
<!-- <div class="react-container react-container--maps" data-config="/examples/default-hex.json"></div> -->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/map",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.2",
|
|
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",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@cdc/core": "^4.24.
|
|
27
|
+
"@cdc/core": "^4.24.2",
|
|
28
28
|
"@emotion/core": "^10.0.28",
|
|
29
29
|
"@emotion/react": "^11.1.5",
|
|
30
30
|
"@hello-pangea/dnd": "^16.2.0",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"react": "^18.2.0",
|
|
52
52
|
"react-dom": "^18.2.0"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "edde49c96dee146de5e3a4537880b1bcf4dbee08"
|
|
55
55
|
}
|
package/src/CdcMap.tsx
CHANGED
|
@@ -52,6 +52,7 @@ import NavigationMenu from './components/NavigationMenu' // Future: Lazy
|
|
|
52
52
|
import UsaMap from './components/UsaMap' // Future: Lazy
|
|
53
53
|
import WorldMap from './components/WorldMap' // Future: Lazy
|
|
54
54
|
import useTooltip from './hooks/useTooltip'
|
|
55
|
+
import { isSolrCsv, isSolrJson } from '@cdc/core/helpers/isSolr'
|
|
55
56
|
|
|
56
57
|
// Data props
|
|
57
58
|
const stateKeys = Object.keys(supportedStates)
|
|
@@ -239,8 +240,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
// Cities
|
|
242
|
-
if (!uid) {
|
|
243
|
-
uid = cityKeys.find(key => key === geoName)
|
|
243
|
+
if (!uid && geoName) {
|
|
244
|
+
uid = cityKeys.find(key => key === geoName.toUpperCase())
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
|
|
@@ -267,6 +268,11 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
267
268
|
if (!uid && 'world-geocode' === state.general.type) {
|
|
268
269
|
uid = cityKeys.find(key => key === geoName?.toUpperCase())
|
|
269
270
|
}
|
|
271
|
+
|
|
272
|
+
// Cities
|
|
273
|
+
if (!uid && geoName) {
|
|
274
|
+
uid = cityKeys.find(key => key === geoName.toUpperCase())
|
|
275
|
+
}
|
|
270
276
|
}
|
|
271
277
|
|
|
272
278
|
// County Check
|
|
@@ -279,6 +285,10 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
279
285
|
uid = row[state.columns.geo.name]
|
|
280
286
|
}
|
|
281
287
|
|
|
288
|
+
if (!uid && state.columns.latitude?.name && state.columns.longitude?.name && row[state.columns.latitude?.name] && row[state.columns.longitude?.name]) {
|
|
289
|
+
uid = row[state.columns.geo.name]
|
|
290
|
+
}
|
|
291
|
+
|
|
282
292
|
if (uid) {
|
|
283
293
|
Object.defineProperty(row, 'uid', {
|
|
284
294
|
value: uid,
|
|
@@ -687,12 +697,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
687
697
|
|
|
688
698
|
dataSet.forEach((row, dataIndex) => {
|
|
689
699
|
let number = row[state.columns.primary.name]
|
|
690
|
-
let updated =
|
|
691
|
-
|
|
692
|
-
// check if we're seperating zero out
|
|
693
|
-
updated = state.legend.separateZero && hasZeroInData ? index : index
|
|
694
|
-
// check for special classes
|
|
695
|
-
updated = state.legend.specialClasses ? updated + state.legend.specialClasses.length : index
|
|
700
|
+
let updated = result.length - 1
|
|
696
701
|
|
|
697
702
|
if (result[updated]?.min === (null || undefined) || result[updated]?.max === (null || undefined)) return
|
|
698
703
|
|
|
@@ -1074,6 +1079,12 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1074
1079
|
// Attempts to find the corresponding value
|
|
1075
1080
|
const displayGeoName = key => {
|
|
1076
1081
|
if (!state.general.convertFipsCodes) return key
|
|
1082
|
+
|
|
1083
|
+
// World Map
|
|
1084
|
+
// If we're returning a city name instead of a country ISO code, capitalize it for the data table.
|
|
1085
|
+
if (state.type === 'map' && state.general.geoType === 'world') {
|
|
1086
|
+
if (String(key).length > 3) return titleCase(key)
|
|
1087
|
+
}
|
|
1077
1088
|
let value = key
|
|
1078
1089
|
// Map to first item in values array which is the preferred label
|
|
1079
1090
|
if (stateKeys.includes(value)) {
|
|
@@ -1085,7 +1096,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1085
1096
|
}
|
|
1086
1097
|
|
|
1087
1098
|
if (countryKeys.includes(value)) {
|
|
1088
|
-
value =
|
|
1099
|
+
value = supportedCountries[key][0]
|
|
1089
1100
|
}
|
|
1090
1101
|
|
|
1091
1102
|
if (countyKeys.includes(value)) {
|
|
@@ -1266,18 +1277,19 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1266
1277
|
const regex = /(?:\.([^.]+))?$/
|
|
1267
1278
|
|
|
1268
1279
|
const ext = regex.exec(dataUrl.pathname)[1]
|
|
1269
|
-
if ('csv' === ext) {
|
|
1280
|
+
if ('csv' === ext || isSolrCsv(dataUrlFinal)) {
|
|
1270
1281
|
data = await fetch(dataUrlFinal)
|
|
1271
1282
|
.then(response => response.text())
|
|
1272
1283
|
.then(responseText => {
|
|
1273
1284
|
const parsedCsv = Papa.parse(responseText, {
|
|
1274
1285
|
header: true,
|
|
1275
1286
|
dynamicTyping: true,
|
|
1276
|
-
skipEmptyLines: true
|
|
1287
|
+
skipEmptyLines: true,
|
|
1288
|
+
encoding: 'utf-8'
|
|
1277
1289
|
})
|
|
1278
1290
|
return parsedCsv.data
|
|
1279
1291
|
})
|
|
1280
|
-
} else if ('json' === ext) {
|
|
1292
|
+
} else if ('json' === ext || isSolrJson(dataUrlFinal)) {
|
|
1281
1293
|
data = await fetch(dataUrlFinal).then(response => response.json())
|
|
1282
1294
|
} else {
|
|
1283
1295
|
data = []
|
|
@@ -1293,6 +1305,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1293
1305
|
data = transform.developerStandardize(data, state.dataDescription)
|
|
1294
1306
|
}
|
|
1295
1307
|
|
|
1308
|
+
console.log('data', data)
|
|
1309
|
+
|
|
1296
1310
|
setState({ ...state, runtimeDataUrl: dataUrlFinal, data })
|
|
1297
1311
|
}
|
|
1298
1312
|
}
|
|
@@ -1610,6 +1624,9 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1610
1624
|
config={config}
|
|
1611
1625
|
classes={['map-title', general.showTitle === true ? 'visible' : 'hidden', `${general.headerColor}`]}
|
|
1612
1626
|
/>
|
|
1627
|
+
<a id='skip-geo-container' className='cdcdataviz-sr-only-focusable' href={tabId}>
|
|
1628
|
+
Skip Over Map Container
|
|
1629
|
+
</a>
|
|
1613
1630
|
{general.introText && <section className='introText'>{parse(general.introText)}</section>}
|
|
1614
1631
|
|
|
1615
1632
|
{/* prettier-ignore */}
|
|
@@ -1626,10 +1643,6 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
|
|
|
1626
1643
|
}
|
|
1627
1644
|
}}
|
|
1628
1645
|
>
|
|
1629
|
-
<a id='skip-geo-container' className='cdcdataviz-sr-only-focusable' href={tabId}>
|
|
1630
|
-
Skip Over Map Container
|
|
1631
|
-
</a>
|
|
1632
|
-
|
|
1633
1646
|
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}
|
|
1634
1647
|
<section className='outline-none geography-container' ref={mapSvg} tabIndex='0' style={{ width: '100%' }}>
|
|
1635
1648
|
{currentViewport && (
|
|
@@ -4,50 +4,57 @@ import { jsx } from '@emotion/react'
|
|
|
4
4
|
import { supportedCities } from '../data/supported-geos'
|
|
5
5
|
import { scaleLinear } from 'd3-scale'
|
|
6
6
|
|
|
7
|
-
const CityList = ({ data, state, geoClickHandler, applyTooltipsToGeo, displayGeoName, applyLegendToRow, projection, titleCase, setSharedFilterValue, isFilterValueSupported
|
|
7
|
+
const CityList = ({ data, state, geoClickHandler, applyTooltipsToGeo, displayGeoName, applyLegendToRow, projection, titleCase, setSharedFilterValue, isFilterValueSupported }) => {
|
|
8
8
|
const [citiesData, setCitiesData] = useState({})
|
|
9
9
|
|
|
10
10
|
useEffect(() => {
|
|
11
|
-
|
|
12
|
-
const citiesList = Object.keys(data).filter(item => Object.keys(supportedCities).includes(item))
|
|
11
|
+
const citiesDictionary = {}
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} else {
|
|
20
|
-
const citiesDictionary = {}
|
|
21
|
-
state.data.map(city => (citiesDictionary[city[state.columns.geo.name]] = city))
|
|
22
|
-
setCitiesData(citiesDictionary)
|
|
13
|
+
if (data) {
|
|
14
|
+
Object.keys(data).forEach(key => {
|
|
15
|
+
const city = data[key]
|
|
16
|
+
citiesDictionary[city[state.columns.geo.name]] = city
|
|
17
|
+
})
|
|
23
18
|
}
|
|
24
|
-
|
|
19
|
+
|
|
20
|
+
setCitiesData(citiesDictionary)
|
|
21
|
+
}, [data])
|
|
25
22
|
|
|
26
23
|
if (state.general.type === 'bubble') {
|
|
27
|
-
const maxDataValue = Math.max(...
|
|
24
|
+
const maxDataValue = Math.max(...(data ? Object.keys(data).map(key => data[key][state.columns.primary.name]) : [0]))
|
|
28
25
|
const sortedRuntimeData = Object.values(data).sort((a, b) => (a[state.columns.primary.name] < b[state.columns.primary.name] ? 1 : -1))
|
|
29
26
|
if (!sortedRuntimeData) return
|
|
30
27
|
|
|
31
28
|
// Set bubble sizes
|
|
32
29
|
var size = scaleLinear().domain([1, maxDataValue]).range([state.visual.minBubbleSize, state.visual.maxBubbleSize])
|
|
33
30
|
}
|
|
34
|
-
let cityList =
|
|
31
|
+
let cityList = Object.keys(citiesData).filter(c => undefined !== c || undefined !== data[c])
|
|
35
32
|
if (!cityList) return true
|
|
36
33
|
|
|
37
34
|
// Cities output
|
|
38
35
|
const cities = cityList.map((city, i) => {
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
let geoData
|
|
37
|
+
if (data) {
|
|
38
|
+
Object.keys(data).forEach(key => {
|
|
39
|
+
if (city === data[key][state.columns.geo.name]) {
|
|
40
|
+
geoData = data[key]
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
if (!geoData) {
|
|
45
|
+
geoData = data ? data[city] : undefined
|
|
46
|
+
}
|
|
47
|
+
const cityDisplayName = titleCase(displayGeoName(city))
|
|
41
48
|
|
|
42
|
-
const legendColors =
|
|
49
|
+
const legendColors = geoData ? applyLegendToRow(geoData) : data[city] ? applyLegendToRow(data[city]) : false
|
|
43
50
|
|
|
44
51
|
if (legendColors === false) {
|
|
45
52
|
return true
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
const toolTip = applyTooltipsToGeo(cityDisplayName,
|
|
55
|
+
const toolTip = applyTooltipsToGeo(cityDisplayName, geoData || data[city])
|
|
49
56
|
|
|
50
|
-
const radius = state.
|
|
57
|
+
const radius = state.visual.geoCodeCircleSize || 8
|
|
51
58
|
|
|
52
59
|
const additionalProps = {
|
|
53
60
|
fillOpacity: state.general.type === 'bubble' ? 0.4 : 1
|
|
@@ -71,18 +78,22 @@ const CityList = ({ data, state, geoClickHandler, applyTooltipsToGeo, displayGeo
|
|
|
71
78
|
|
|
72
79
|
let transform = ''
|
|
73
80
|
|
|
74
|
-
if (!
|
|
75
|
-
transform = `translate(${projection(supportedCities[city])})`
|
|
81
|
+
if (!geoData?.[state.columns.longitude.name] && !geoData?.[state.columns.latitude.name] && city && supportedCities[city.toUpperCase()]) {
|
|
82
|
+
transform = `translate(${projection(supportedCities[city.toUpperCase()])})`
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
let needsPointer = false
|
|
79
86
|
|
|
80
|
-
if (
|
|
87
|
+
if (geoData?.[state.columns.longitude.name] && geoData?.[state.columns.latitude.name]) {
|
|
81
88
|
let coords = [Number(geoData?.[state.columns.longitude.name]), Number(geoData?.[state.columns.latitude.name])]
|
|
82
89
|
transform = `translate(${projection(coords)})`
|
|
83
90
|
needsPointer = true
|
|
84
91
|
}
|
|
85
92
|
|
|
93
|
+
if (!transform) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
86
97
|
const styles = {
|
|
87
98
|
fill: legendColors[0],
|
|
88
99
|
opacity: setSharedFilterValue && isFilterValueSupported && data[city][state.columns.geo.name] !== setSharedFilterValue ? 0.5 : 1,
|
|
@@ -134,8 +134,6 @@ const EditorPanel = props => {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
const handleEditorChanges = async (property, value) => {
|
|
137
|
-
console.log('prop', property)
|
|
138
|
-
console.log('value', value)
|
|
139
137
|
switch (property) {
|
|
140
138
|
// change these to be more generic.
|
|
141
139
|
// updateVisualPropertyValue
|
|
@@ -278,6 +276,7 @@ const EditorPanel = props => {
|
|
|
278
276
|
setState({
|
|
279
277
|
...state,
|
|
280
278
|
visual: {
|
|
279
|
+
...state.visual,
|
|
281
280
|
cityStyle: value
|
|
282
281
|
}
|
|
283
282
|
})
|
|
@@ -1929,7 +1928,7 @@ const EditorPanel = props => {
|
|
|
1929
1928
|
</label>
|
|
1930
1929
|
</fieldset>
|
|
1931
1930
|
)}
|
|
1932
|
-
{(
|
|
1931
|
+
{(
|
|
1933
1932
|
<>
|
|
1934
1933
|
<label>Latitude Column</label>
|
|
1935
1934
|
<select
|
|
@@ -2850,7 +2849,7 @@ const EditorPanel = props => {
|
|
|
2850
2849
|
)
|
|
2851
2850
|
})}
|
|
2852
2851
|
</ul>
|
|
2853
|
-
{
|
|
2852
|
+
{state.visual.cityStyle === 'circle' && (
|
|
2854
2853
|
<label>
|
|
2855
2854
|
Geocode Settings
|
|
2856
2855
|
<TextField type='number' value={state.visual.geoCodeCircleSize} section='visual' max='10' fieldName='geoCodeCircleSize' label='Geocode Circle Size' updateField={updateField} />
|
|
@@ -255,7 +255,7 @@ const HexSettingShapeColumns = props => {
|
|
|
255
255
|
...group.items,
|
|
256
256
|
{
|
|
257
257
|
key: '',
|
|
258
|
-
shape: 'Arrow
|
|
258
|
+
shape: 'Arrow Up',
|
|
259
259
|
column: '',
|
|
260
260
|
operator: '=',
|
|
261
261
|
value: ''
|
|
@@ -309,7 +309,7 @@ const HexSettingShapeColumns = props => {
|
|
|
309
309
|
copy.push({
|
|
310
310
|
legendTitle: '',
|
|
311
311
|
legendDescription: '',
|
|
312
|
-
items: [{ key: '', shape: 'Arrow
|
|
312
|
+
items: [{ key: '', shape: 'Arrow Up', column: '', operator: '=', value: '' }]
|
|
313
313
|
})
|
|
314
314
|
copy.legendTitle = ''
|
|
315
315
|
copy.legendDescription = ''
|
package/src/components/Geo.jsx
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React, { memo } from 'react'
|
|
2
2
|
|
|
3
3
|
const Geo = ({ path, styles, stroke, strokeWidth, ...props }) => {
|
|
4
|
+
const { className, ...restProps } = props
|
|
5
|
+
const geoClassName = String(props.additionalData?.name)?.toLowerCase()?.replaceAll(' ', '') || 'country'
|
|
4
6
|
return (
|
|
5
|
-
<g className=
|
|
6
|
-
<path tabIndex={-1} className=
|
|
7
|
+
<g className={`geo-group ${geoClassName}`} style={styles} {...restProps}>
|
|
8
|
+
<path tabIndex={-1} className={`single-geo ${geoClassName}`} stroke={stroke} strokeWidth={strokeWidth} d={path} />
|
|
7
9
|
</g>
|
|
8
10
|
)
|
|
9
11
|
}
|
|
@@ -3,11 +3,7 @@ import { AiOutlineArrowUp, AiOutlineArrowDown, AiOutlineArrowRight } from 'react
|
|
|
3
3
|
import parse from 'html-react-parser'
|
|
4
4
|
|
|
5
5
|
const LegendItemHex = props => {
|
|
6
|
-
const { state,
|
|
7
|
-
const { legend } = state
|
|
8
|
-
const { title } = state.general
|
|
9
|
-
|
|
10
|
-
const columnLogic = legend.position === 'side' && legend.singleColumn ? 'single-column' : legend.position === 'bottom' && legend.singleRow ? 'single-row' : ''
|
|
6
|
+
const { state, viewport } = props
|
|
11
7
|
|
|
12
8
|
const getItemShape = shape => {
|
|
13
9
|
switch (shape) {
|
|
@@ -29,15 +25,15 @@ const LegendItemHex = props => {
|
|
|
29
25
|
state.hexMap.type === 'shapes' &&
|
|
30
26
|
state.hexMap.shapeGroups.map((shapeGroup, shapeGroupIndex) => {
|
|
31
27
|
return (
|
|
32
|
-
<aside id='legend' className={legendClasses.aside.join(' ')} role='region' aria-label='Legend' tabIndex=
|
|
28
|
+
<aside id='legend' className={legendClasses.aside.join(' ')} role='region' aria-label='Legend' tabIndex={0}>
|
|
33
29
|
<section className={legendClasses.section.join(' ')} aria-label='Map Legend'>
|
|
34
|
-
{
|
|
35
|
-
{
|
|
30
|
+
{shapeGroup.legendTitle && <span className={legendClasses.title.join(' ')}>{parse(shapeGroup.legendTitle)}</span>}
|
|
31
|
+
{shapeGroup.legendDescription && <p className={legendClasses.description.join(' ')}>{parse(shapeGroup.legendDescription)}</p>}
|
|
36
32
|
|
|
37
33
|
<ul className={legendClasses.ul.join(' ')} aria-label='Legend items' style={{ listStyle: 'none' }}>
|
|
38
34
|
{shapeGroup.items.map((item, itemIndex) => {
|
|
39
35
|
return (
|
|
40
|
-
<li className={legendClasses.li.join(' ')}>
|
|
36
|
+
<li className={legendClasses.li.join(' ')} key={`hex-legend-item-${itemIndex}`}>
|
|
41
37
|
{getItemShape(item.shape)} {item.value}
|
|
42
38
|
</li>
|
|
43
39
|
)
|
|
@@ -53,9 +53,9 @@ const TerritoryHexagon = ({ label, text, stroke, strokeWidth, textColor, territo
|
|
|
53
53
|
{state.hexMap.shapeGroups.map((group, groupIndex) => {
|
|
54
54
|
return group.items.map((item, itemIndex) => {
|
|
55
55
|
if (item.operator === '=') {
|
|
56
|
-
if (geoData[item.key] === item.value) {
|
|
56
|
+
if (geoData[item.key] === item.value || Number(geoData[item.key]) === Number(item.value)) {
|
|
57
57
|
return (
|
|
58
|
-
<Group style={{ transform: `translate(36%, 50%)`, fill: 'currentColor' }}>
|
|
58
|
+
<Group style={{ transform: `translate(36%, 50%)`, fill: 'currentColor' }} key={`territory-hex--${itemIndex}`}>
|
|
59
59
|
{item.shape === 'Arrow Down' && <AiOutlineArrowDown size={12} stroke='none' fontWeight={100} />}
|
|
60
60
|
{item.shape === 'Arrow Up' && <AiOutlineArrowUp size={12} stroke='none' fontWeight={100} />}
|
|
61
61
|
{item.shape === 'Arrow Right' && <AiOutlineArrowRight size={12} stroke='none' fontWeight={100} />}
|