@cdc/map 2.6.3 → 4.22.10

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 (75) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcmap.js +32 -18
  3. package/examples/bubble-us.json +363 -0
  4. package/examples/bubble-world.json +427 -0
  5. package/examples/default-county.json +64 -12
  6. package/examples/default-geocode.json +746 -0
  7. package/examples/default-hex.json +477 -0
  8. package/examples/default-usa-regions.json +118 -0
  9. package/examples/default-usa.json +1 -1
  10. package/examples/default-world-data.json +1450 -0
  11. package/examples/default-world.json +5 -3
  12. package/examples/example-city-state.json +46 -1
  13. package/examples/gallery/categorical-qualitative.json +797 -0
  14. package/examples/gallery/categorical-scale-based.json +739 -0
  15. package/examples/gallery/city-state.json +479 -0
  16. package/examples/gallery/county.json +22731 -0
  17. package/examples/gallery/equal-interval.json +1027 -0
  18. package/examples/gallery/equal-number.json +1027 -0
  19. package/examples/gallery/filterable.json +909 -0
  20. package/examples/gallery/hex-filtered.json +420 -0
  21. package/examples/gallery/hex.json +413 -0
  22. package/examples/gallery/single-state.json +21402 -0
  23. package/examples/gallery/world.json +1592 -0
  24. package/examples/private/atsdr.json +439 -0
  25. package/examples/private/atsdr_new.json +436 -0
  26. package/examples/private/bubble.json +285 -0
  27. package/examples/private/city-state.json +428 -0
  28. package/examples/private/cty-issue.json +42768 -0
  29. package/examples/private/default-usa.json +460 -0
  30. package/examples/private/default-world-data.json +1444 -0
  31. package/examples/private/default.json +968 -0
  32. package/examples/private/legend-issue.json +1 -0
  33. package/examples/private/map-rounding-error.json +42759 -0
  34. package/examples/private/map.csv +60 -0
  35. package/examples/private/mdx.json +210 -0
  36. package/examples/private/monkeypox.json +376 -0
  37. package/examples/private/regions.json +52 -0
  38. package/examples/private/valid-data-map.csv +59 -0
  39. package/examples/private/wcmsrd-13881-data.json +2858 -0
  40. package/examples/private/wcmsrd-13881.json +5823 -0
  41. package/examples/private/wcmsrd-14492-data.json +292 -0
  42. package/examples/private/wcmsrd-14492.json +114 -0
  43. package/examples/private/wcmsrd-test.json +268 -0
  44. package/examples/private/world.json +1580 -0
  45. package/examples/private/worldmap.json +1490 -0
  46. package/package.json +51 -50
  47. package/src/CdcMap.js +1384 -1075
  48. package/src/components/BubbleList.js +244 -0
  49. package/src/components/CityList.js +79 -17
  50. package/src/components/CountyMap.js +104 -44
  51. package/src/components/DataTable.js +32 -22
  52. package/src/components/EditorPanel.js +977 -414
  53. package/src/components/Geo.js +1 -1
  54. package/src/components/Modal.js +2 -1
  55. package/src/components/NavigationMenu.js +4 -3
  56. package/src/components/Sidebar.js +14 -19
  57. package/src/components/SingleStateMap.js +178 -249
  58. package/src/components/UsaMap.js +104 -36
  59. package/src/components/UsaRegionMap.js +320 -0
  60. package/src/components/WorldMap.js +117 -34
  61. package/src/data/country-coordinates.js +250 -0
  62. package/src/data/{dfc-map.json → county-map.json} +0 -0
  63. package/src/data/initial-state.js +23 -3
  64. package/src/data/state-coordinates.js +55 -0
  65. package/src/data/supported-geos.js +101 -15
  66. package/src/data/us-regions-topo-2.json +360525 -0
  67. package/src/data/us-regions-topo.json +37894 -0
  68. package/src/hooks/useColorPalette.ts +96 -0
  69. package/src/index.html +8 -4
  70. package/src/scss/editor-panel.scss +78 -57
  71. package/src/scss/main.scss +1 -6
  72. package/src/scss/map.scss +126 -2
  73. package/src/scss/sidebar.scss +2 -1
  74. package/src/data/color-palettes.js +0 -200
  75. package/src/images/map-folded.svg +0 -1
@@ -9,6 +9,8 @@ import hexTopoJSON from '../data/us-hex-topo.json';
9
9
  import { AlbersUsa, Mercator } from '@visx/geo';
10
10
  import chroma from 'chroma-js';
11
11
  import CityList from './CityList';
12
+ import BubbleList from './BubbleList';
13
+ import { supportedCities, supportedStates } from '../data/supported-geos';
12
14
 
13
15
  const { features: unitedStates } = feature(topoJSON, topoJSON.objects.states)
14
16
  const { features: unitedStatesHex } = feature(hexTopoJSON, hexTopoJSON.objects.states)
@@ -68,9 +70,32 @@ const UsaMap = (props) => {
68
70
  displayGeoName,
69
71
  supportedTerritories,
70
72
  rebuildTooltips,
71
- titleCase
73
+ titleCase,
74
+ handleCircleClick,
75
+ setSharedFilterValue,
76
+ handleMapAriaLabels
72
77
  } = props;
73
78
 
79
+ let isFilterValueSupported = false;
80
+
81
+ if(setSharedFilterValue){
82
+ Object.keys(supportedStates).forEach(supportedState => {
83
+ if(supportedStates[supportedState].indexOf(setSharedFilterValue.toUpperCase()) !== -1){
84
+ isFilterValueSupported = true;
85
+ }
86
+ });
87
+ Object.keys(supportedTerritories).forEach(supportedTerritory => {
88
+ if(supportedTerritories[supportedTerritory].indexOf(setSharedFilterValue.toUpperCase()) !== -1){
89
+ isFilterValueSupported = true;
90
+ }
91
+ });
92
+ Object.keys(supportedCities).forEach(supportedCity => {
93
+ if(supportedCity === setSharedFilterValue.toUpperCase()){
94
+ isFilterValueSupported = true;
95
+ }
96
+ });
97
+ }
98
+
74
99
  // "Choose State" options
75
100
  const [extent, setExtent] = useState(null)
76
101
  const [focusedStates, setFocusedStates] = useState(unitedStates)
@@ -123,7 +148,7 @@ const UsaMap = (props) => {
123
148
 
124
149
  if (legendColors) {
125
150
  // Use white text if the background is dark, and dark grey if it's light
126
- if (chroma.contrast(textColor, legendColors[0]) < 4.5) {
151
+ if (chroma.contrast(textColor, legendColors[0]) < 3.5) {
127
152
  textColor = '#202020';
128
153
  }
129
154
 
@@ -137,6 +162,8 @@ const UsaMap = (props) => {
137
162
  styles = {
138
163
  color: textColor,
139
164
  fill: legendColors[0],
165
+ opacity: setSharedFilterValue && isFilterValueSupported && setSharedFilterValue !== territoryData[state.columns.geo.name] ? .5 : 1,
166
+ stroke: setSharedFilterValue && isFilterValueSupported && setSharedFilterValue === territoryData[state.columns.geo.name] ? 'rgba(0, 0, 0, 1)' : geoStrokeColor,
140
167
  cursor: needsPointer ? 'pointer' : 'default',
141
168
  '&:hover': {
142
169
  fill: legendColors[1],
@@ -153,7 +180,6 @@ const UsaMap = (props) => {
153
180
  text={styles.color}
154
181
  data-tip={toolTip}
155
182
  data-for="tooltip"
156
- stroke={geoStrokeColor}
157
183
  strokeWidth={1.5}
158
184
  onClick={() => geoClickHandler(territory, territoryData)}
159
185
  />)
@@ -169,7 +195,7 @@ const UsaMap = (props) => {
169
195
  let textColor = "#FFF"
170
196
 
171
197
  // Dynamic text color
172
- if (chroma.contrast(textColor, bgColor) < 4.5 ) {
198
+ if (chroma.contrast(textColor, bgColor) < 3.5 ) {
173
199
  textColor = '#202020';
174
200
  }
175
201
 
@@ -206,6 +232,25 @@ const UsaMap = (props) => {
206
232
  const constructGeoJsx = (geographies, projection) => {
207
233
  let showLabel = state.general.displayStateLabels
208
234
 
235
+ // Order alphabetically. Important for accessibility if ever read out loud.
236
+ geographies.map ( state => {
237
+ if(!state.feature.properties.iso) return;
238
+ state.feature.properties.name = titleCase(supportedStates[state.feature.properties.iso][0])
239
+ })
240
+
241
+ geographies.sort( (a,b) => {
242
+ const first = a.feature.properties.name.toUpperCase(); // ignore upper and lowercase
243
+ const second = b.feature.properties.name.toUpperCase(); // ignore upper and lowercase
244
+ if (first < second) {
245
+ return -1;
246
+ }
247
+ if (first > second) {
248
+ return 1;
249
+ }
250
+
251
+ // names must be equal
252
+ return 0;
253
+ })
209
254
  const geosJsx = geographies.map(( {feature: geo, path = ''}) => {
210
255
  const key = isHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
211
256
 
@@ -216,11 +261,9 @@ const UsaMap = (props) => {
216
261
 
217
262
  // Map the name from the geo data with the appropriate key for the processed data
218
263
  let geoKey = geo.properties.iso;
264
+ let geoName = geo.properties.name;
219
265
 
220
266
  // Manually add Washington D.C. in for Hex maps
221
- if(isHex && geoKey === 'US-DC') {
222
- geoKey = 'District of Columbia'
223
- }
224
267
 
225
268
  if(!geoKey) return
226
269
 
@@ -240,13 +283,15 @@ const UsaMap = (props) => {
240
283
  const tooltip = applyTooltipsToGeo(geoDisplayName, geoData);
241
284
 
242
285
  styles = {
243
- fill: legendColors[0],
286
+ fill: state.general.type !== 'bubble' ? legendColors[0] : '#E6E6E6',
287
+ opacity: setSharedFilterValue && isFilterValueSupported && setSharedFilterValue !== geoData[state.columns.geo.name] ? .5 : 1,
288
+ stroke: setSharedFilterValue && isFilterValueSupported && setSharedFilterValue === geoData[state.columns.geo.name] ? 'rgba(0, 0, 0, 1)' : geoStrokeColor,
244
289
  cursor: 'default',
245
290
  '&:hover': {
246
- fill: legendColors[1],
291
+ fill: state.general.type !== 'bubble' ? legendColors[1] : '#e6e6e6',
247
292
  },
248
293
  '&:active': {
249
- fill: legendColors[2],
294
+ fill: state.general.type !== 'bubble' ? legendColors[2] : '#e6e6e6',
250
295
  },
251
296
  };
252
297
 
@@ -254,43 +299,43 @@ const UsaMap = (props) => {
254
299
  if ((state.columns.navigate && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
255
300
  styles.cursor = 'pointer'
256
301
  }
257
-
258
302
  return (
303
+ <g data-name={geoName} key={key}>
304
+ <g
305
+ data-for="tooltip"
306
+ data-tip={tooltip}
307
+ className="geo-group"
308
+ css={styles}
309
+ onClick={() => geoClickHandler(geoDisplayName, geoData)}
310
+ >
311
+ <path
312
+ tabIndex={-1}
313
+ className='single-geo'
314
+ strokeWidth={1.3}
315
+ d={path}
316
+ />
317
+ {(isHex || showLabel) && geoLabel(geo, legendColors[0], projection)}
318
+ </g>
319
+ </g>
320
+ )
321
+ }
322
+
323
+ // Default return state, just geo with no additional information
324
+ return (
325
+ <g data-name={geoName} key={key}>
259
326
  <g
260
- data-for="tooltip"
261
- data-tip={tooltip}
262
- key={key}
263
327
  className="geo-group"
264
328
  css={styles}
265
- onClick={() => geoClickHandler(geoDisplayName, geoData)}
266
329
  >
267
330
  <path
268
331
  tabIndex={-1}
269
332
  className='single-geo'
270
333
  stroke={geoStrokeColor}
271
- strokeWidth={1.3}
334
+ strokeWidth={1.3}
272
335
  d={path}
273
336
  />
274
- {(isHex || showLabel) && geoLabel(geo, legendColors[0], projection)}
337
+ {(isHex || showLabel) && geoLabel(geo, styles.fill, projection)}
275
338
  </g>
276
- )
277
- }
278
-
279
- // Default return state, just geo with no additional information
280
- return (
281
- <g
282
- key={key}
283
- className="geo-group"
284
- css={styles}
285
- >
286
- <path
287
- tabIndex={-1}
288
- className='single-geo'
289
- stroke={geoStrokeColor}
290
- strokeWidth={1.3}
291
- d={path}
292
- />
293
- {(isHex || showLabel) && geoLabel(geo, styles.fill, projection)}
294
339
  </g>
295
340
  )
296
341
  });
@@ -308,14 +353,37 @@ const UsaMap = (props) => {
308
353
  displayGeoName={displayGeoName}
309
354
  applyLegendToRow={applyLegendToRow}
310
355
  titleCase={titleCase}
356
+ setSharedFilterValue={setSharedFilterValue}
357
+ isFilterValueSupported={isFilterValueSupported}
358
+ isGeoCodeMap={state.general.type === 'us-geocode'}
311
359
  />)
312
360
 
361
+ // Bubbles
362
+ if (state.general.type === 'bubble') {
363
+ geosJsx.push(
364
+ <BubbleList
365
+ key="bubbles"
366
+ data={state.data}
367
+ runtimeData={data}
368
+ state={state}
369
+ projection={projection}
370
+ applyLegendToRow={applyLegendToRow}
371
+ applyTooltipsToGeo={applyTooltipsToGeo}
372
+ displayGeoName={displayGeoName}
373
+ />
374
+ )
375
+ }
376
+
313
377
  return geosJsx;
314
378
  };
315
379
 
316
380
  return (
317
381
  <ErrorBoundary component="UsaMap">
318
- <svg viewBox="0 0 880 500">
382
+ <svg
383
+ viewBox="0 0 880 500"
384
+ role="img"
385
+ aria-label={handleMapAriaLabels(state)}
386
+ >
319
387
  {state.general.displayAsHex ?
320
388
  (<Mercator data={unitedStatesHex} scale={650} translate={[1600, 775]}>
321
389
  {({ features, projection }) => constructGeoJsx(features, projection)}
@@ -0,0 +1,320 @@
1
+ import React, { useState, useEffect, memo } from 'react';
2
+ /** @jsx jsx */
3
+ import { jsx } from '@emotion/react'
4
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
5
+ import { geoCentroid } from "d3-geo";
6
+ import { feature } from "topojson-client";
7
+ import topoJSON from '../data/us-regions-topo-2.json';
8
+ import { Mercator } from '@visx/geo';
9
+ import chroma from 'chroma-js';
10
+
11
+ const { features: unitedStates } = feature(topoJSON, topoJSON.objects.regions)
12
+
13
+ const Rect = ({label, text, stroke, strokeWidth, ...props}) => {
14
+ return (
15
+ <svg viewBox="0 0 45 28">
16
+ <g {...props} strokeLinejoin="round">
17
+ <path stroke={stroke} strokeWidth={strokeWidth} d="M40,0.5 C41.2426407,0.5 42.3676407,1.00367966 43.1819805,1.81801948 C43.9963203,2.63235931 44.5,3.75735931 44.5,5 L44.5,5 L44.5,23 C44.5,24.2426407 43.9963203,25.3676407 43.1819805,26.1819805 C42.3676407,26.9963203 41.2426407,27.5 40,27.5 L40,27.5 L5,27.5 C3.75735931,27.5 2.63235931,26.9963203 1.81801948,26.1819805 C1.00367966,25.3676407 0.5,24.2426407 0.5,23 L0.5,23 L0.5,5 C0.5,3.75735931 1.00367966,2.63235931 1.81801948,1.81801948 C2.63235931,1.00367966 3.75735931,0.5 5,0.5 L5,0.5 Z" />
18
+ <text textAnchor="middle" dominantBaseline="middle" x="50%" y="54%" fill={text}>{label}</text>
19
+ </g>
20
+ </svg>
21
+ )
22
+ }
23
+
24
+ const UsaRegionMap = (props) => {
25
+ const {
26
+ state,
27
+ applyTooltipsToGeo,
28
+ data,
29
+ geoClickHandler,
30
+ applyLegendToRow,
31
+ displayGeoName,
32
+ supportedTerritories,
33
+ rebuildTooltips,
34
+ titleCase,
35
+ handleCircleClick,
36
+ handleMapAriaLabels
37
+ } = props;
38
+
39
+ // "Choose State" options
40
+ const [extent, setExtent] = useState(null)
41
+ const [focusedStates, setFocusedStates] = useState(unitedStates)
42
+ const [translate, setTranslate] = useState([455,200])
43
+
44
+ // When returning from another map we want to reset the state
45
+ useEffect(() => {
46
+ setTranslate( [455,250] )
47
+ setExtent( null )
48
+ }, [state.general.geoType]);
49
+
50
+ const isHex = state.general.displayAsHex
51
+
52
+ const [territoriesData, setTerritoriesData] = useState([]);
53
+
54
+ const territoriesKeys = Object.keys(supportedTerritories); // data will have already mapped abbreviated territories to their full names
55
+
56
+ useEffect(() => {
57
+ // Territories need to show up if they're in the data at all, not just if they're "active". That's why this is different from Cities
58
+ const territoriesList = territoriesKeys.filter(key => data[key]);
59
+
60
+ setTerritoriesData(territoriesList);
61
+ }, [data]);
62
+
63
+ useEffect(() => rebuildTooltips());
64
+
65
+ const geoStrokeColor = state.general.geoBorderColor === 'darkGray' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255,255,255,0.7)'
66
+
67
+ const territories = territoriesData.map(territory => {
68
+ const Shape = Rect
69
+
70
+ const territoryData = data[territory];
71
+
72
+ let toolTip;
73
+
74
+ let styles = {
75
+ fill: '#E6E6E6',
76
+ color: '#202020',
77
+ };
78
+
79
+ const label = supportedTerritories[territory][1]
80
+
81
+ if(!territoryData) return <Shape key={label} label={label} css={styles} text={styles.color} />
82
+
83
+ toolTip = applyTooltipsToGeo(displayGeoName(territory), territoryData);
84
+
85
+ const legendColors = applyLegendToRow(territoryData);
86
+
87
+ let textColor = '#FFF';
88
+
89
+ if (legendColors) {
90
+ // Use white text if the background is dark, and dark grey if it's light
91
+ if (chroma.contrast(textColor, legendColors[0]) < 3.5) {
92
+ textColor = '#202020';
93
+ }
94
+
95
+ let needsPointer = false;
96
+
97
+ // If we need to add a pointer cursor
98
+ if ((state.columns.navigate && territoryData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
99
+ needsPointer = true;
100
+ }
101
+
102
+ styles = {
103
+ color: textColor,
104
+ fill: legendColors[0],
105
+ cursor: needsPointer ? 'pointer' : 'default',
106
+ '&:hover': {
107
+ fill: legendColors[1],
108
+ },
109
+ '&:active': {
110
+ fill: legendColors[2],
111
+ }
112
+ };
113
+
114
+ return (<Shape
115
+ key={label}
116
+ label={label}
117
+ css={styles}
118
+ text={styles.color}
119
+ data-tip={toolTip}
120
+ data-for="tooltip"
121
+ stroke={geoStrokeColor}
122
+ strokeWidth={1.5}
123
+ onClick={() => geoClickHandler(territory, territoryData)}
124
+ />)
125
+ }
126
+ });
127
+
128
+ const geoLabel = (geo, bgColor = "#FFFFFF", projection) => {
129
+ let centroid = projection(geoCentroid(geo))
130
+ let abbr = geo.properties.iso
131
+
132
+ if(undefined === abbr) return null
133
+
134
+ let textColor = "#FFF"
135
+
136
+ // Dynamic text color
137
+ if (chroma.contrast(textColor, bgColor) < 3.5 ) {
138
+ textColor = '#202020';
139
+ }
140
+
141
+ let x = 0, y = 5
142
+
143
+
144
+ return (
145
+ <g>
146
+ <line x1={centroid[0]} y1={centroid[1]} x2={centroid[0] + dx} y2={centroid[1] + dy} stroke="rgba(0,0,0,.5)" strokeWidth={1} />
147
+ <text x={4} strokeWidth="0" fontSize={13} style={{fill: "#202020"}} alignmentBaseline="middle" transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}>
148
+ {abbr.substring(3)}
149
+ </text>
150
+ </g>
151
+ )
152
+ }
153
+
154
+ // Constructs and displays markup for all geos on the map (except territories right now)
155
+ const constructGeoJsx = (geographies, projection) => {
156
+ let showLabel = state.general.displayStateLabels
157
+
158
+ const geosJsx = geographies.map(( {feature: geo, path = '', index}) => {
159
+ const key = isHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
160
+
161
+ let styles = {
162
+ fill: '#E6E6E6',
163
+ cursor: 'default'
164
+ }
165
+
166
+ // Map the name from the geo data with the appropriate key for the processed data
167
+ let geoKey = geo.properties.iso;
168
+
169
+ // Manually add Washington D.C. in for Hex maps
170
+
171
+ if(!geoKey) return
172
+
173
+ const geoData = data[geoKey];
174
+
175
+ let legendColors;
176
+ // Once we receive data for this geographic item, setup variables.
177
+ if (geoData !== undefined) {
178
+ legendColors = applyLegendToRow(geoData);
179
+ }
180
+
181
+ const geoDisplayName = displayGeoName(geoKey);
182
+
183
+ // If a legend applies, return it with appropriate information.
184
+ if (legendColors && legendColors[0] !== '#000000') {
185
+ const tooltip = applyTooltipsToGeo(geoDisplayName, geoData);
186
+
187
+ styles = {
188
+ fill: state.general.type !== 'bubble' ? legendColors[0] : '#E6E6E6',
189
+ cursor: 'default',
190
+ '&:hover': {
191
+ fill: state.general.type !== 'bubble' ? legendColors[1] : '#e6e6e6',
192
+ },
193
+ '&:active': {
194
+ fill: state.general.type !== 'bubble' ? legendColors[2] : '#e6e6e6',
195
+ },
196
+ };
197
+
198
+ // When to add pointer cursor
199
+ if ((state.columns.navigate && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
200
+ styles.cursor = 'pointer'
201
+ }
202
+
203
+ const TerratoryRect = (props) => {
204
+ const { posX = 0, tName } = props
205
+ let textColor = "#fff"
206
+
207
+ if (chroma.contrast(textColor, legendColors[0]) < 4.5) {
208
+ textColor = '#202020';
209
+ }
210
+ return (
211
+ <>
212
+ <rect x={posX} width="36" height="24" rx="6" stroke="#fff" strokeWidth="1" />
213
+ <text x={posX + 8} y="17" fill={textColor}>{tName}</text>
214
+ </>
215
+ )
216
+ }
217
+
218
+ const circleRadius = 15;
219
+
220
+ // SIDE CHART EXPERIMENT
221
+ // const height = state.data[index].Change;
222
+ // const barHeight = Math.abs(height * 20 );
223
+ // const barPositive = height > 0;
224
+ // const barY = barPositive ? -barHeight + 15 : 15;
225
+ // const baseY = 14;
226
+ // const barFill = barPositive ? "#fff" : "#fff";
227
+
228
+ return (
229
+ <g
230
+ data-for="tooltip"
231
+ data-tip={tooltip}
232
+ key={key}
233
+ className="geo-group"
234
+ css={styles}
235
+ onClick={() => geoClickHandler(geoDisplayName, geoData)}
236
+ >
237
+
238
+ <path
239
+ tabIndex={-1}
240
+ className='single-geo'
241
+ stroke={geoStrokeColor}
242
+ strokeWidth={1.3}
243
+ d={path}
244
+ />
245
+ <g id={`region-${index+1}-label`}>
246
+ <circle fill="#fff" stroke="#999" cx={circleRadius} cy={circleRadius} r={circleRadius}/>
247
+ <text fill="#333" x="15px" y="20px" textAnchor="middle">{index+1}</text>
248
+ {/* SIDE CHART EXPERIMENT */}
249
+ {/*<g y={barY*20}>*/}
250
+ {/* <rect x="-20" y={barY} width="10" height={barHeight} fill={barFill} stroke="#333"/>*/}
251
+ {/* <rect x="-23" y={baseY} width="16" height="2" fill="#000" />*/}
252
+ {/*</g>*/}
253
+ {/* / SIDE CHART EXPERIMENT */}
254
+ </g>
255
+ {geoKey === 'region 2' &&
256
+ <g id="region-2-territories">
257
+ <TerratoryRect tName="PR" />
258
+ <TerratoryRect posX={45} tName="VI" />
259
+ </g>
260
+ }
261
+
262
+ { geoKey === 'region 9' &&
263
+ <g id="region-9-territories">
264
+ <g className="region-9-row1">
265
+ <TerratoryRect tName="AS" />
266
+ <TerratoryRect posX={45} tName="GU" />
267
+ <TerratoryRect posX={90} tName="MP" />
268
+ </g>
269
+ <g className="region-9-row2">
270
+ <TerratoryRect tName="FM" />
271
+ <TerratoryRect posX={45} tName="PW" />
272
+ <TerratoryRect posX={90} tName="MH" />
273
+ </g>
274
+ </g>
275
+ }
276
+ </g>
277
+ )
278
+ }
279
+
280
+ // Default return state, just geo with no additional information
281
+ return (
282
+ <g
283
+ key={key}
284
+ className="geo-group"
285
+ css={styles}
286
+ >
287
+ <path
288
+ tabIndex={-1}
289
+ className='single-geo'
290
+ stroke={geoStrokeColor}
291
+ strokeWidth={1.3}
292
+ d={path}
293
+ />
294
+ {(isHex || showLabel) && geoLabel(geo, styles.fill, projection)}
295
+ </g>
296
+ )
297
+ });
298
+ return geosJsx;
299
+ };
300
+
301
+ return (
302
+ <ErrorBoundary component="UsaRegionMap">
303
+ <svg viewBox="0 0 880 500" role="img" aria-label={handleMapAriaLabels(state)}>
304
+
305
+ <Mercator data={focusedStates} scale={620} translate={[1500, 735]}>
306
+ {({ features, projection }) => constructGeoJsx(features, projection)}
307
+ </Mercator>
308
+
309
+ </svg>
310
+ {territories.length > 0 && (
311
+ <section className="territories">
312
+ <span className="label">{state.general.territoriesLabel}</span>
313
+ {territories}
314
+ </section>
315
+ )}
316
+ </ErrorBoundary>
317
+ );
318
+ };
319
+
320
+ export default memo(UsaRegionMap)