@cdc/map 4.25.3 → 4.25.5-1

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 (111) hide show
  1. package/dist/cdcmap.js +38945 -41511
  2. package/examples/hex-colors.json +3 -3
  3. package/examples/private/test.json +470 -1457
  4. package/examples/private/{mmr.json → wastewatermap.json} +86 -115
  5. package/index.html +13 -41
  6. package/package.json +4 -10
  7. package/src/CdcMap.tsx +51 -1555
  8. package/src/CdcMapComponent.tsx +594 -0
  9. package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +10 -0
  10. package/src/_stories/CdcMap.Legend.stories.tsx +67 -0
  11. package/src/_stories/CdcMap.stories.tsx +4 -1
  12. package/src/_stories/UsaMap.NoData.stories.tsx +4 -4
  13. package/{examples/private/default-patterns.json → src/_stories/_mock/legends/legend-tests.json} +36 -131
  14. package/src/cdcMapComponent.styles.css +9 -0
  15. package/src/components/Annotation/Annotation.Draggable.tsx +27 -26
  16. package/src/components/Annotation/AnnotationDropdown.tsx +5 -6
  17. package/src/components/BubbleList.tsx +135 -49
  18. package/src/components/CityList.tsx +89 -87
  19. package/src/components/DataTable.tsx +8 -8
  20. package/src/components/EditorPanel/components/EditorPanel.tsx +714 -820
  21. package/src/components/EditorPanel/components/Error.tsx +9 -2
  22. package/src/components/EditorPanel/components/HexShapeSettings.tsx +127 -141
  23. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +55 -86
  24. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +89 -75
  25. package/src/components/EditorPanel/components/editorPanel.styles.css +95 -0
  26. package/src/components/Geo.tsx +9 -1
  27. package/src/components/GoogleMap/components/GoogleMap.tsx +1 -1
  28. package/src/components/Legend/components/Legend.tsx +92 -87
  29. package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +128 -0
  30. package/src/components/Legend/components/LegendGroup/legend.group.css +27 -0
  31. package/src/components/Legend/components/LegendItem.Hex.tsx +4 -1
  32. package/src/components/Legend/components/index.scss +18 -6
  33. package/src/components/Modal.tsx +17 -7
  34. package/src/components/NavigationMenu.tsx +11 -9
  35. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +12 -8
  36. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +4 -4
  37. package/src/components/UsaMap/components/TerritoriesSection.tsx +33 -10
  38. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +12 -10
  39. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -14
  40. package/src/components/UsaMap/components/Territory/TerritoryShape.ts +2 -1
  41. package/src/components/UsaMap/components/UsaMap.County.tsx +138 -96
  42. package/src/components/UsaMap/components/UsaMap.Region.styles.css +72 -0
  43. package/src/components/UsaMap/components/UsaMap.Region.tsx +56 -103
  44. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +10 -0
  45. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +59 -66
  46. package/src/components/UsaMap/components/UsaMap.State.tsx +112 -91
  47. package/src/components/UsaMap/helpers/map.ts +1 -1
  48. package/src/components/UsaMap/helpers/shapes.ts +20 -7
  49. package/src/components/WorldMap/WorldMap.tsx +64 -118
  50. package/src/components/WorldMap/worldMap.styles.css +28 -0
  51. package/src/components/ZoomControls.tsx +15 -13
  52. package/src/components/zoomControls.styles.css +53 -0
  53. package/src/context.ts +17 -9
  54. package/src/data/initial-state.js +5 -2
  55. package/src/helpers/addUIDs.ts +151 -0
  56. package/src/helpers/applyColorToLegend.ts +39 -64
  57. package/src/helpers/applyLegendToRow.ts +51 -0
  58. package/src/helpers/colorDistributions.ts +12 -0
  59. package/src/helpers/constants.ts +44 -0
  60. package/src/helpers/displayGeoName.ts +9 -2
  61. package/src/helpers/generateColorsArray.ts +2 -1
  62. package/src/helpers/generateRuntimeData.ts +74 -0
  63. package/src/helpers/generateRuntimeFilters.ts +63 -0
  64. package/src/helpers/generateRuntimeLegend.ts +537 -0
  65. package/src/helpers/generateRuntimeLegendHash.ts +16 -15
  66. package/src/helpers/getColumnNames.ts +19 -0
  67. package/src/helpers/getMapContainerClasses.ts +23 -0
  68. package/src/helpers/handleMapTabbing.ts +31 -0
  69. package/src/helpers/hashObj.ts +1 -1
  70. package/src/helpers/index.ts +22 -0
  71. package/src/helpers/navigationHandler.ts +3 -3
  72. package/src/helpers/resetLegendToggles.ts +13 -0
  73. package/src/helpers/setBinNumbers.ts +5 -0
  74. package/src/helpers/sortSpecialClassesLast.ts +7 -0
  75. package/src/helpers/tests/getColumnNames.test.ts +52 -0
  76. package/src/helpers/titleCase.ts +1 -1
  77. package/src/helpers/toggleLegendActive.ts +25 -0
  78. package/src/hooks/useApplyTooltipsToGeo.tsx +51 -0
  79. package/src/hooks/useColumnsRequiredChecker.ts +51 -0
  80. package/src/hooks/useGeoClickHandler.ts +45 -0
  81. package/src/hooks/useLegendSeparators.ts +26 -0
  82. package/src/hooks/useMapLayers.tsx +34 -60
  83. package/src/hooks/useModal.ts +22 -0
  84. package/src/hooks/useResizeObserver.ts +4 -5
  85. package/src/hooks/useStateZoom.tsx +52 -75
  86. package/src/hooks/useTooltip.ts +2 -3
  87. package/src/index.jsx +3 -9
  88. package/src/scss/editor-panel.scss +3 -99
  89. package/src/scss/main.scss +1 -19
  90. package/src/scss/map.scss +15 -220
  91. package/src/store/map.actions.ts +46 -0
  92. package/src/store/map.reducer.ts +96 -0
  93. package/src/types/Annotations.ts +24 -0
  94. package/src/types/MapConfig.ts +23 -3
  95. package/src/types/MapContext.ts +36 -35
  96. package/src/types/Modal.ts +1 -0
  97. package/src/types/RuntimeData.ts +3 -0
  98. package/LICENSE +0 -201
  99. package/examples/private/DEV-9644.json +0 -184
  100. package/examples/private/DEV-9989.json +0 -229
  101. package/examples/private/ardi.json +0 -180
  102. package/examples/private/colors 2.json +0 -416
  103. package/examples/private/colors.json +0 -416
  104. package/examples/private/colors.json.zip +0 -0
  105. package/examples/private/customColors.json +0 -45348
  106. package/examples/test.json +0 -183
  107. package/src/helpers/closeModal.ts +0 -9
  108. package/src/scss/btn.scss +0 -69
  109. package/src/scss/filters.scss +0 -27
  110. package/src/scss/variables.scss +0 -1
  111. /package/src/hooks/{useActiveElement.js → useActiveElement.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, memo, useContext } from 'react'
1
+ import React, { memo, useContext, useEffect, useState } from 'react'
2
2
 
3
3
  // 3rd party
4
4
  import { geoCentroid } from 'd3-geo'
@@ -15,10 +15,25 @@ import { supportedTerritories } from '../../../data/supported-geos'
15
15
 
16
16
  // Helpers
17
17
  import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
18
- import { getGeoFillColor, getGeoStrokeColor } from '../../../helpers/colors'
19
- import { handleMapAriaLabels } from '../../../helpers/handleMapAriaLabels'
18
+ import { displayGeoName, getGeoFillColor, getGeoStrokeColor, handleMapAriaLabels, SVG_VIEWBOX } from '../../../helpers'
19
+ import useGeoClickHandler from '../../../hooks/useGeoClickHandler'
20
+ import useApplyTooltipsToGeo from '../../../hooks/useApplyTooltipsToGeo'
21
+ import './UsaMap.Region.styles.css'
22
+ import { applyLegendToRow } from '../../../helpers/applyLegendToRow'
23
+
24
+ type TerritoryRectProps = {
25
+ posX?: number
26
+ tName: string
27
+ }
28
+
29
+ type RectProps = {
30
+ label: string
31
+ text: string
32
+ stroke: string
33
+ strokeWidth: number
34
+ }
20
35
 
21
- const Rect = ({ label, text, stroke, strokeWidth, ...props }) => {
36
+ const Rect: React.FC<RectProps> = ({ label, text, stroke, strokeWidth, ...props }) => {
22
37
  return (
23
38
  <svg viewBox='0 0 45 28'>
24
39
  <g {...props} strokeLinejoin='round'>
@@ -35,22 +50,17 @@ const Rect = ({ label, text, stroke, strokeWidth, ...props }) => {
35
50
  )
36
51
  }
37
52
 
38
- const UsaRegionMap = props => {
39
- // prettier-ignore
40
- const {
41
- applyLegendToRow,
42
- applyTooltipsToGeo,
43
- data,
44
- displayGeoName,
45
- geoClickHandler,
46
- state,
47
- tooltipId
48
- } = useContext(ConfigContext)
49
-
50
- // "Choose State" options
51
- const [extent, setExtent] = useState(null)
53
+ const UsaRegionMap = () => {
54
+ const { data, config, tooltipId, legendMemo, legendSpecialClassLastMemo, runtimeLegend } = useContext(ConfigContext)
52
55
  const [focusedStates, setFocusedStates] = useState(null)
53
- const [translate, setTranslate] = useState([455, 200])
56
+ const { geoClickHandler } = useGeoClickHandler()
57
+ const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
58
+ const { general } = config
59
+ const { displayStateLabels, territoriesLabel, displayAsHex, type } = general
60
+ const tooltipInteractionType = config.tooltips.appearanceType
61
+ const isHex = displayAsHex
62
+ const [territoriesData, setTerritoriesData] = useState([])
63
+ const CIRCLE_RADIUS = 15
54
64
 
55
65
  useEffect(() => {
56
66
  const fetchData = async () => {
@@ -61,16 +71,6 @@ const UsaRegionMap = props => {
61
71
  fetchData()
62
72
  }, [])
63
73
 
64
- // When returning from another map we want to reset the state
65
- useEffect(() => {
66
- setTranslate([455, 250])
67
- setExtent(null)
68
- }, [state.general.geoType])
69
-
70
- const isHex = state.general.displayAsHex
71
-
72
- const [territoriesData, setTerritoriesData] = useState([])
73
-
74
74
  const territoriesKeys = Object.keys(supportedTerritories) // data will have already mapped abbreviated territories to their full names
75
75
 
76
76
  useEffect(() => {
@@ -84,19 +84,18 @@ const UsaRegionMap = props => {
84
84
  return <></>
85
85
  }
86
86
 
87
- const geoStrokeColor = getGeoStrokeColor(state)
88
- const geoFillColor = getGeoFillColor(state)
87
+ const geoStrokeColor = getGeoStrokeColor(config)
88
+ const geoFillColor = getGeoFillColor(config)
89
89
 
90
90
  const territories = territoriesData.map(territory => {
91
91
  const Shape = Rect
92
92
 
93
93
  const territoryData = data[territory]
94
94
 
95
- let toolTip
95
+ let toolTip: string
96
96
 
97
97
  let styles: React.CSSProperties = {
98
- fill: geoFillColor,
99
- color: '#202020'
98
+ fill: geoFillColor
100
99
  }
101
100
 
102
101
  const label = supportedTerritories[territory][1]
@@ -105,7 +104,7 @@ const UsaRegionMap = props => {
105
104
 
106
105
  toolTip = applyTooltipsToGeo(displayGeoName(territory), territoryData)
107
106
 
108
- const legendColors = applyLegendToRow(territoryData)
107
+ const legendColors = applyLegendToRow(territoryData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
109
108
 
110
109
  if (legendColors) {
111
110
  const textColor = getContrastColor('#FFF', legendColors[0])
@@ -114,8 +113,8 @@ const UsaRegionMap = props => {
114
113
 
115
114
  // If we need to add a pointer cursor
116
115
  if (
117
- (state.columns.navigate && territoryData[state.columns.navigate.name]) ||
118
- state.tooltips.appearanceType === 'click'
116
+ (config.columns.navigate && territoryData[config.columns.navigate.name]) ||
117
+ tooltipInteractionType === 'click'
119
118
  ) {
120
119
  needsPointer = true
121
120
  }
@@ -148,46 +147,9 @@ const UsaRegionMap = props => {
148
147
  }
149
148
  })
150
149
 
151
- const geoLabel = (geo, bgColor = '#FFFFFF', projection) => {
152
- let centroid = projection(geoCentroid(geo))
153
- let abbr = geo.properties.iso
154
-
155
- if (undefined === abbr) return null
156
-
157
- const textColor = getContrastColor('#FFF', bgColor)
158
-
159
- let x = 0,
160
- y = 5
161
-
162
- return (
163
- <g>
164
- <line
165
- x1={centroid[0]}
166
- y1={centroid[1]}
167
- x2={centroid[0] + x}
168
- y2={centroid[1] + y}
169
- stroke='rgba(0,0,0,.5)'
170
- strokeWidth={1}
171
- />
172
- <text
173
- x={4}
174
- strokeWidth='0'
175
- fontSize={13}
176
- style={{ fill: '#202020' }}
177
- alignmentBaseline='middle'
178
- transform={`translate(${centroid[0] + x}, ${centroid[1] + y})`}
179
- >
180
- {abbr.substring(3)}
181
- </text>
182
- </g>
183
- )
184
- }
185
-
186
150
  // Constructs and displays markup for all geos on the map (except territories right now)
187
151
  const constructGeoJsx = (geographies, projection) => {
188
- let showLabel = state.general.displayStateLabels
189
-
190
- const geosJsx = geographies.map(({ feature: geo, path = '', index }) => {
152
+ return geographies.map(({ feature: geo, path = '', index }) => {
191
153
  const key = isHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
192
154
 
193
155
  let styles = {
@@ -198,8 +160,6 @@ const UsaRegionMap = props => {
198
160
  // Map the name from the geo data with the appropriate key for the processed data
199
161
  let geoKey = geo.properties.iso
200
162
 
201
- // Manually add Washington D.C. in for Hex maps
202
-
203
163
  if (!geoKey) return
204
164
 
205
165
  const geoData = data[geoKey]
@@ -207,7 +167,7 @@ const UsaRegionMap = props => {
207
167
  let legendColors
208
168
  // Once we receive data for this geographic item, setup variables.
209
169
  if (geoData !== undefined) {
210
- legendColors = applyLegendToRow(geoData)
170
+ legendColors = applyLegendToRow(geoData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
211
171
  }
212
172
 
213
173
  const geoDisplayName = displayGeoName(geoKey)
@@ -217,28 +177,25 @@ const UsaRegionMap = props => {
217
177
  const toolTip = applyTooltipsToGeo(geoDisplayName, geoData)
218
178
 
219
179
  styles = {
220
- fill: state.general.type !== 'bubble' ? legendColors[0] : geoFillColor,
180
+ fill: type !== 'bubble' ? legendColors[0] : geoFillColor,
221
181
  cursor: 'default',
222
182
  '&:hover': {
223
- fill: state.general.type !== 'bubble' ? legendColors[1] : geoFillColor
183
+ fill: type !== 'bubble' ? legendColors[1] : geoFillColor
224
184
  },
225
185
  '&:active': {
226
- fill: state.general.type !== 'bubble' ? legendColors[2] : geoFillColor
186
+ fill: type !== 'bubble' ? legendColors[2] : geoFillColor
227
187
  }
228
188
  }
229
189
 
230
190
  // When to add pointer cursor
231
- if (
232
- (state.columns.navigate && geoData[state.columns.navigate.name]) ||
233
- state.tooltips.appearanceType === 'click'
234
- ) {
191
+ if ((config.columns.navigate && geoData[config.columns.navigate.name]) || tooltipInteractionType === 'click') {
235
192
  styles.cursor = 'pointer'
236
193
  }
237
194
 
238
- const TerratoryRect = props => {
195
+ const TerritoryRect: React.FC<TerritoryRectProps> = props => {
239
196
  const { posX = 0, tName } = props
240
197
  const textColor = getContrastColor('#FFF', legendColors[0])
241
- const geoStrokeColor = getGeoStrokeColor(state)
198
+ const geoStrokeColor = getGeoStrokeColor(config)
242
199
  return (
243
200
  <>
244
201
  <rect x={posX} width='36' height='24' rx='2' stroke={geoStrokeColor} strokeWidth='1' />
@@ -249,8 +206,6 @@ const UsaRegionMap = props => {
249
206
  )
250
207
  }
251
208
 
252
- const circleRadius = 15
253
-
254
209
  return (
255
210
  <g
256
211
  key={key}
@@ -263,29 +218,29 @@ const UsaRegionMap = props => {
263
218
  >
264
219
  <path tabIndex={-1} className='single-geo' stroke={geoStrokeColor} strokeWidth={1} d={path} />
265
220
  <g id={`region-${index + 1}-label`}>
266
- <circle fill='#fff' stroke='#999' cx={circleRadius} cy={circleRadius} r={circleRadius} />
221
+ <circle fill='#fff' stroke='#999' cx={CIRCLE_RADIUS} cy={CIRCLE_RADIUS} r={CIRCLE_RADIUS} />
267
222
  <text fill='#333' x='15px' y='20px' textAnchor='middle'>
268
223
  {index + 1}
269
224
  </text>
270
225
  </g>
271
226
  {geoKey === 'region 2' && (
272
227
  <g id='region-2-territories'>
273
- <TerratoryRect tName='PR' />
274
- <TerratoryRect posX={45} tName='VI' />
228
+ <TerritoryRect tName='PR' />
229
+ <TerritoryRect posX={45} tName='VI' />
275
230
  </g>
276
231
  )}
277
232
 
278
233
  {geoKey === 'region 9' && (
279
234
  <g id='region-9-territories'>
280
235
  <g className='region-9-row1'>
281
- <TerratoryRect tName='AS' />
282
- <TerratoryRect posX={45} tName='GU' />
283
- <TerratoryRect posX={90} tName='MP' />
236
+ <TerritoryRect tName='AS' />
237
+ <TerritoryRect posX={45} tName='GU' />
238
+ <TerritoryRect posX={90} tName='MP' />
284
239
  </g>
285
240
  <g className='region-9-row2'>
286
- <TerratoryRect tName='FM' />
287
- <TerratoryRect posX={45} tName='PW' />
288
- <TerratoryRect posX={90} tName='MH' />
241
+ <TerritoryRect tName='FM' />
242
+ <TerritoryRect posX={45} tName='PW' />
243
+ <TerritoryRect posX={90} tName='MH' />
289
244
  </g>
290
245
  </g>
291
246
  )}
@@ -297,24 +252,22 @@ const UsaRegionMap = props => {
297
252
  return (
298
253
  <g key={key} className='geo-group' style={styles}>
299
254
  <path tabIndex={-1} className='single-geo' stroke={geoStrokeColor} strokeWidth={1} d={path} />
300
- {(isHex || showLabel) && geoLabel(geo, styles.fill, projection)}
301
255
  </g>
302
256
  )
303
257
  })
304
- return geosJsx
305
258
  }
306
259
 
307
260
  return (
308
261
  <ErrorBoundary component='UsaRegionMap'>
309
- <svg viewBox='0 0 880 500' role='img' aria-label={handleMapAriaLabels(state)}>
262
+ <svg viewBox={SVG_VIEWBOX} role='img' aria-label={handleMapAriaLabels(config)}>
310
263
  <Mercator data={focusedStates} scale={620} translate={[1500, 735]}>
311
264
  {({ features, projection }) => constructGeoJsx(features, projection)}
312
265
  </Mercator>
313
- {state.annotations.length > 0 && <Annotation.Draggable />}
266
+ {config.annotations.length > 0 && <Annotation.Draggable />}
314
267
  </svg>
315
268
  {territories.length > 0 && (
316
269
  <section className='territories'>
317
- <span className='label'>{state.general.territoriesLabel}</span>
270
+ <span className='label'>{territoriesLabel}</span>
318
271
  {territories}
319
272
  </section>
320
273
  )}
@@ -0,0 +1,10 @@
1
+ .countyMapGroup {
2
+ transition: transform 1s;
3
+ will-change: transform;
4
+ transform-origin: center;
5
+ stroke: none !important;
6
+ }
7
+
8
+ .countyMapGroup--no-transition {
9
+ transition: none !important;
10
+ }
@@ -1,75 +1,73 @@
1
- import { useEffect, memo, useContext, useRef, useState } from 'react'
1
+ import { useEffect, memo, useContext } from 'react'
2
2
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
3
3
  import { geoPath } from 'd3-geo'
4
4
  import { CustomProjection } from '@visx/geo'
5
5
  import Loading from '@cdc/core/components/Loading'
6
6
  import { geoAlbersUsaTerritories } from 'd3-composite-projections'
7
7
  import CityList from '../../CityList'
8
- import ConfigContext from '../../../context'
8
+ import ConfigContext, { MapDispatchContext } from '../../../context'
9
9
  import Annotation from '../../Annotation'
10
10
  import SingleState from './SingleState'
11
- import { getTopoData, getCurrentTopoYear, isTopoReady } from './../helpers/map'
12
11
  import ZoomableGroup from '../../ZoomableGroup'
13
12
  import ZoomControls from '../../ZoomControls'
14
13
  import { MapContext } from '../../../types/MapContext'
15
14
  import useStateZoom from '../../../hooks/useStateZoom'
16
15
  import { Text } from '@visx/text'
17
- import { getGeoStrokeColor } from '../../../helpers/colors'
18
- import { handleMapAriaLabels } from '../../../helpers/handleMapAriaLabels'
19
- import { titleCase } from '../../../helpers/titleCase'
20
16
 
21
- // SVG ITEMS
22
- const WIDTH = 880
23
- const HEIGHT = 500
24
- const PADDING = 25
17
+ import './UsaMap.SingleState.styles.css'
25
18
 
26
- const SingleStateMap = props => {
19
+ // map-level helpers
20
+ import { titleCase, handleMapAriaLabels, getGeoStrokeColor, MAX_ZOOM_LEVEL } from '../../../helpers'
21
+
22
+ // state-level helpers
23
+ import { getTopoData, getCurrentTopoYear, isTopoReady } from '../helpers/map'
24
+ import useGeoClickHandler from '../../../hooks/useGeoClickHandler'
25
+ import { SVG_WIDTH, SVG_HEIGHT, SVG_PADDING, SVG_VIEWBOX } from '../../../helpers'
26
+
27
+ const SingleStateMap = () => {
27
28
  const {
28
- state,
29
- applyTooltipsToGeo,
30
- data,
31
- geoClickHandler,
32
- applyLegendToRow,
33
- displayGeoName,
29
+ config,
34
30
  setSharedFilterValue,
35
31
  isFilterValueSupported,
36
32
  runtimeFilters,
37
33
  tooltipId,
38
34
  position,
39
- setPosition,
40
35
  stateToShow,
41
36
  topoData,
42
- setTopoData,
43
37
  scale,
44
38
  translate,
45
- setStateToShow
39
+ legendMemo,
40
+ legendSpecialClassLastMemo
46
41
  } = useContext<MapContext>(ConfigContext)
47
42
 
43
+ const dispatch = useContext(MapDispatchContext)
48
44
  const { handleMoveEnd, handleZoomIn, handleZoomOut, handleReset, projection, statePicked } = useStateZoom(topoData)
45
+ const { geoClickHandler } = useGeoClickHandler()
49
46
 
50
47
  const cityListProjection = geoAlbersUsaTerritories()
51
- .translate([WIDTH / 2, HEIGHT / 2])
48
+ .translate([SVG_WIDTH / 2, SVG_HEIGHT / 2])
52
49
  .scale(1)
53
- const geoStrokeColor = getGeoStrokeColor(state)
50
+ const geoStrokeColor = getGeoStrokeColor(config)
54
51
  const path = geoPath().projection(projection)
55
52
 
56
53
  useEffect(() => {
57
- setStateToShow(topoData?.states?.find(s => s.properties.name === state.general.statePicked.stateName))
54
+ const stateToShow = topoData?.states?.find(s => s.properties.name === config.general.statePicked.stateName)
55
+ dispatch({ type: 'SET_STATE_TO_SHOW', payload: stateToShow })
58
56
  }, [statePicked])
59
57
 
60
58
  useEffect(() => {
61
- let currentYear = getCurrentTopoYear(state, runtimeFilters)
59
+ let currentYear = getCurrentTopoYear(config, runtimeFilters)
62
60
 
63
- if (currentYear !== topoData.year) {
61
+ if (currentYear !== topoData?.year) {
64
62
  getTopoData(currentYear).then(response => {
65
- setTopoData(response)
63
+ dispatch({ type: 'SET_TOPO_DATA', payload: response })
66
64
  })
67
65
  }
68
- }, [state.general.countyCensusYear, state.general.filterControlsCountyYear, JSON.stringify(runtimeFilters)])
66
+ }, [config.general.countyCensusYear, config.general.filterControlsCountyYear, JSON.stringify(runtimeFilters)])
69
67
 
70
- if (!isTopoReady(topoData, state, runtimeFilters)) {
68
+ if (!isTopoReady(topoData, config, runtimeFilters)) {
71
69
  return (
72
- <div style={{ height: `${HEIGHT}px` }}>
70
+ <div style={{ height: `${SVG_HEIGHT}px` }}>
73
71
  <Loading />
74
72
  </div>
75
73
  )
@@ -77,16 +75,16 @@ const SingleStateMap = props => {
77
75
 
78
76
  const checkForNoData = () => {
79
77
  // If no statePicked, return true
80
- if (!state.general.statePicked.fipsCode) return true
78
+ if (!config.general.statePicked.fipsCode) return true
81
79
  }
82
80
 
83
81
  // Constructs and displays markup for all geos on the map (except territories right now)
84
- const constructGeoJsx = (geographies, projection) => {
82
+ const constructGeoJsx = geographies => {
85
83
  const counties = geographies[0].feature.counties
86
84
 
87
85
  let geosJsx = []
88
86
 
89
- // Push state lines
87
+ // Push config lines
90
88
  geosJsx.push(
91
89
  // prettier-ignore
92
90
  <SingleState.StateOutput
@@ -113,12 +111,7 @@ const SingleStateMap = props => {
113
111
  <CityList
114
112
  projection={cityListProjection}
115
113
  key='cities'
116
- data={data}
117
- state={state}
118
114
  geoClickHandler={geoClickHandler}
119
- applyTooltipsToGeo={applyTooltipsToGeo}
120
- displayGeoName={displayGeoName}
121
- applyLegendToRow={applyLegendToRow}
122
115
  titleCase={titleCase}
123
116
  setSharedFilterValue={setSharedFilterValue}
124
117
  isFilterValueSupported={isFilterValueSupported}
@@ -130,28 +123,28 @@ const SingleStateMap = props => {
130
123
  }
131
124
  return (
132
125
  <ErrorBoundary component='SingleStateMap'>
133
- {statePicked && state.general.allowMapZoom && state.general.statePicked.fipsCode && (
126
+ {statePicked && config.general.allowMapZoom && config.general.statePicked.fipsCode && (
134
127
  <svg
135
- viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
128
+ viewBox={SVG_VIEWBOX}
136
129
  preserveAspectRatio='xMinYMin'
137
130
  className='svg-container'
138
131
  role='img'
139
- aria-label={handleMapAriaLabels(state)}
132
+ aria-label={handleMapAriaLabels(config)}
140
133
  >
141
134
  <ZoomableGroup
142
135
  center={position.coordinates}
143
136
  zoom={position.zoom}
144
137
  minZoom={1} // Adjust this value if needed
145
- maxZoom={4} // Adjust this value to limit the maximum zoom level
138
+ maxZoom={MAX_ZOOM_LEVEL}
146
139
  onMoveEnd={handleMoveEnd}
147
140
  projection={projection}
148
- width={880}
149
- height={500}
141
+ width={SVG_WIDTH}
142
+ height={SVG_HEIGHT}
150
143
  >
151
144
  <rect
152
145
  className='background center-container ocean'
153
- width={WIDTH}
154
- height={HEIGHT}
146
+ width={SVG_WIDTH}
147
+ height={SVG_HEIGHT}
155
148
  fillOpacity={1}
156
149
  fill='white'
157
150
  ></rect>
@@ -159,14 +152,14 @@ const SingleStateMap = props => {
159
152
  data={[
160
153
  {
161
154
  states: topoData?.states,
162
- counties: topoData.counties.filter(c => c.id.substring(0, 2) === state.general.statePicked.fipsCode)
155
+ counties: topoData.counties.filter(c => c.id.substring(0, 2) === config.general.statePicked.fipsCode)
163
156
  }
164
157
  ]}
165
158
  projection={geoAlbersUsaTerritories}
166
159
  fitExtent={[
167
160
  [
168
- [PADDING, PADDING],
169
- [WIDTH - PADDING, HEIGHT - PADDING]
161
+ [SVG_PADDING, SVG_PADDING],
162
+ [SVG_WIDTH - SVG_PADDING, SVG_HEIGHT - SVG_PADDING]
170
163
  ],
171
164
  stateToShow
172
165
  ]}
@@ -176,7 +169,7 @@ const SingleStateMap = props => {
176
169
  <g
177
170
  id='mapGroup'
178
171
  className={`countyMapGroup ${
179
- state.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
172
+ config.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
180
173
  }`}
181
174
  transform={`translate(${translate}) scale(${scale})`}
182
175
  data-scale=''
@@ -187,22 +180,22 @@ const SingleStateMap = props => {
187
180
  )
188
181
  }}
189
182
  </CustomProjection>
190
- {state.annotations.length > 0 && <Annotation.Draggable />}
183
+ {config.annotations.length > 0 && <Annotation.Draggable />}
191
184
  </ZoomableGroup>
192
185
  </svg>
193
186
  )}
194
- {statePicked && !state.general.allowMapZoom && state.general.statePicked.fipsCode && (
187
+ {statePicked && !config.general.allowMapZoom && config.general.statePicked.fipsCode && (
195
188
  <svg
196
- viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
189
+ viewBox={SVG_VIEWBOX}
197
190
  preserveAspectRatio='xMinYMin'
198
191
  className='svg-container'
199
192
  role='img'
200
- aria-label={handleMapAriaLabels(state)}
193
+ aria-label={handleMapAriaLabels(config)}
201
194
  >
202
195
  <rect
203
196
  className='background center-container ocean'
204
- width={WIDTH}
205
- height={HEIGHT}
197
+ width={SVG_WIDTH}
198
+ height={SVG_HEIGHT}
206
199
  fillOpacity={1}
207
200
  fill='white'
208
201
  ></rect>
@@ -210,14 +203,14 @@ const SingleStateMap = props => {
210
203
  data={[
211
204
  {
212
205
  states: topoData?.states,
213
- counties: topoData.counties.filter(c => c.id.substring(0, 2) === state.general.statePicked.fipsCode)
206
+ counties: topoData.counties.filter(c => c.id.substring(0, 2) === config.general.statePicked.fipsCode)
214
207
  }
215
208
  ]}
216
209
  projection={geoAlbersUsaTerritories}
217
210
  fitExtent={[
218
211
  [
219
- [PADDING, PADDING],
220
- [WIDTH - PADDING, HEIGHT - PADDING]
212
+ [SVG_PADDING, SVG_PADDING],
213
+ [SVG_WIDTH - SVG_PADDING, SVG_HEIGHT - SVG_PADDING]
221
214
  ],
222
215
  stateToShow
223
216
  ]}
@@ -227,7 +220,7 @@ const SingleStateMap = props => {
227
220
  <g
228
221
  id='mapGroup'
229
222
  className={`countyMapGroup ${
230
- state.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
223
+ config.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
231
224
  }`}
232
225
  transform={`translate(${translate}) scale(${scale})`}
233
226
  data-scale=''
@@ -238,28 +231,28 @@ const SingleStateMap = props => {
238
231
  )
239
232
  }}
240
233
  </CustomProjection>
241
- {state.annotations.length > 0 && <Annotation.Draggable />}
234
+ {config.annotations.length > 0 && <Annotation.Draggable />}
242
235
  </svg>
243
236
  )}
244
237
 
245
238
  {checkForNoData() && (
246
239
  <svg
247
- viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
240
+ viewBox={SVG_VIEWBOX}
248
241
  preserveAspectRatio='xMinYMin'
249
242
  className='svg-container'
250
243
  role='img'
251
- aria-label={handleMapAriaLabels(state)}
244
+ aria-label={handleMapAriaLabels(config)}
252
245
  >
253
246
  <Text
254
247
  verticalAnchor='start'
255
248
  textAnchor='middle'
256
- x={WIDTH / 2}
257
- width={WIDTH}
258
- y={HEIGHT / 2}
249
+ x={SVG_WIDTH / 2}
250
+ width={SVG_WIDTH}
251
+ y={SVG_HEIGHT / 2}
259
252
  fontSize={18}
260
253
  style={{ fontSize: '28px', height: '18px' }}
261
254
  >
262
- {state.general.noStateFoundMessage}
255
+ {config.general.noStateFoundMessage}
263
256
  </Text>
264
257
  </svg>
265
258
  )}