@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.
Files changed (28) hide show
  1. package/dist/cdcmap.js +50477 -45394
  2. package/examples/test.json +0 -9614
  3. package/examples/{private/zika-issue.json → zika.json} +47 -51
  4. package/index.html +8 -3
  5. package/package.json +3 -3
  6. package/src/CdcMap.tsx +29 -16
  7. package/src/components/CityList.jsx +34 -23
  8. package/src/components/EditorPanel/components/EditorPanel.tsx +3 -4
  9. package/src/components/EditorPanel/components/HexShapeSettings.tsx +2 -2
  10. package/src/components/Geo.jsx +4 -2
  11. package/src/components/Legend/components/LegendItem.Hex.tsx +5 -9
  12. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +2 -2
  13. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +0 -1
  14. package/src/components/UsaMap/components/UsaMap.State.tsx +3 -4
  15. package/src/components/WorldMap/components/WorldMap.jsx +14 -8
  16. package/src/components/WorldMap/data/world-topo-guiana-update.json +1 -0
  17. package/src/components/WorldMap/data/world-topo-old.json +1 -0
  18. package/{examples/private/new-world.json → src/components/WorldMap/data/world-topo-recent.json} +23137 -22280
  19. package/src/components/WorldMap/data/world-topo.json +1 -1
  20. package/src/data/initial-state.js +2 -2
  21. package/src/data/supported-geos.js +21 -1
  22. package/src/hooks/useTooltip.ts +4 -4
  23. package/src/scss/editor-panel.scss +2 -3
  24. package/src/scss/map.scss +22 -12
  25. package/examples/private/map-text-wrap.json +0 -574
  26. package/examples/private/map-world-data.json +0 -1046
  27. package/examples/world-geocode-data.json +0 -18
  28. 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": false
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": "pinkpurple",
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": "Link",
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": true,
88
+ "showDataTableLink": false,
100
89
  "showFullGeoNameInCSV": false,
101
90
  "forceDisplay": true,
102
- "download": false,
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": "Antartica",
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": "Known to have mosquito that transmits Zika, but no reported Zika cases "
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": "Palestinian Territories",
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": "Saint Paul and New Amsterdam Islands",
933
+ "Country": "Sicily",
946
934
  "Category": "Not known to have mosquito that transmits Zika"
947
935
  },
948
936
  {
949
- "Country": "Saint Pierre and Miquelon",
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": "Zimbabwe",
1185
+ "Country": "Dhekelia",
1194
1186
  "Category": "Known to have mosquito that transmits Zika, but no reported Zika cases "
1195
1187
  }
1196
1188
  ],
1197
- "validated": 4.23
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/example-city-state.json"></div> -->
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/example-world-map.json"></div>
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
- <!-- <div class="react-container react-container--maps" data-config="/examples/example-city-state.json"></div> -->
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.1",
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.1",
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": "a352a3f74f4b681191e3244061dbb3621f36eec3"
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 = 0
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 = titleCase(supportedCountries[key][0])
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, isGeoCodeMap }) => {
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
- if (!isGeoCodeMap) {
12
- const citiesList = Object.keys(data).filter(item => Object.keys(supportedCities).includes(item))
11
+ const citiesDictionary = {}
13
12
 
14
- const citiesDictionary = {}
15
-
16
- citiesList.map(city => (citiesDictionary[city] = data[city]))
17
-
18
- setCitiesData(citiesDictionary)
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
- }, [data, state.data])
19
+
20
+ setCitiesData(citiesDictionary)
21
+ }, [data])
25
22
 
26
23
  if (state.general.type === 'bubble') {
27
- const maxDataValue = Math.max(...state.data.map(d => d[state.columns.primary.name]))
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 = isGeoCodeMap ? Object.keys(citiesData).filter(c => undefined !== c) : Object.keys(citiesData).filter(c => undefined !== data[c])
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
- const geoData = isGeoCodeMap ? state.data.filter(item => city === item[state.columns.geo.name])[0] : data[city]
40
- const cityDisplayName = isGeoCodeMap ? city : titleCase(displayGeoName(city))
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 = isGeoCodeMap && geoData ? applyLegendToRow(geoData) : data[city] ? applyLegendToRow(data[city]) : false
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, isGeoCodeMap ? geoData : data[city])
55
+ const toolTip = applyTooltipsToGeo(cityDisplayName, geoData || data[city])
49
56
 
50
- const radius = state.general.geoType === 'us' && !isGeoCodeMap ? 8 : isGeoCodeMap ? state.visual.geoCodeCircleSize : 4
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 (!isGeoCodeMap) {
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 (isGeoCodeMap) {
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
- {('us-geocode' === state.general.type || 'world-geocode' === state.general.type) && (
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
- {('us-geocode' === state.general.type || 'world-geocode' === state.general.type) && state.visual.cityStyle === 'circle' && (
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 up',
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 up', column: '', operator: '=', value: '' }]
312
+ items: [{ key: '', shape: 'Arrow Up', column: '', operator: '=', value: '' }]
313
313
  })
314
314
  copy.legendTitle = ''
315
315
  copy.legendDescription = ''
@@ -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='geo-group' css={styles} {...props}>
6
- <path tabIndex={-1} className='single-geo' stroke={stroke} strokeWidth={strokeWidth} d={path} />
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, runtimeLegend, viewport } = props
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='0'>
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
- {legend.title && <span className={legendClasses.title.join(' ')}>{parse(shapeGroup.legendTitle)}</span>}
35
- {legend.dynamicDescription === false && legend.description && <p className={legendClasses.description.join(' ')}>{parse(shapeGroup.legendDescription)}</p>}
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} />}
@@ -264,7 +264,6 @@ const SingleStateMap = props => {
264
264
  titleCase={titleCase}
265
265
  setSharedFilterValue={setSharedFilterValue}
266
266
  isFilterValueSupported={isFilterValueSupported}
267
- isGeoCodeMap={state.general.type === 'us-geocode'}
268
267
  />
269
268
  )
270
269