@cdc/map 4.25.3 → 4.25.6

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 (119) hide show
  1. package/.idea/map.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/dist/cdcmap.js +31254 -32242
  5. package/examples/hex-colors.json +3 -3
  6. package/examples/m2.json +32904 -0
  7. package/examples/private/test.json +470 -1457
  8. package/examples/private/{mmr.json → wastewatermap.json} +86 -115
  9. package/index.html +36 -63
  10. package/package.json +7 -19
  11. package/src/CdcMap.tsx +56 -1552
  12. package/src/CdcMapComponent.tsx +608 -0
  13. package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +10 -0
  14. package/src/_stories/CdcMap.Legend.stories.tsx +67 -0
  15. package/src/_stories/CdcMap.Table.stories.tsx +19 -0
  16. package/src/_stories/CdcMap.stories.tsx +12 -1
  17. package/src/_stories/UsaMap.NoData.stories.tsx +4 -4
  18. package/src/_stories/_mock/default-patterns.json +8 -5
  19. package/src/_stories/_mock/legend-bins.json +428 -0
  20. package/{examples/private/default-patterns.json → src/_stories/_mock/legends/legend-tests.json} +36 -131
  21. package/src/cdcMapComponent.styles.css +9 -0
  22. package/src/components/Annotation/Annotation.Draggable.tsx +27 -26
  23. package/src/components/Annotation/AnnotationDropdown.tsx +5 -6
  24. package/src/components/BubbleList.tsx +135 -49
  25. package/src/components/CityList.tsx +89 -87
  26. package/src/components/DataTable.tsx +8 -8
  27. package/src/components/EditorPanel/components/EditorPanel.tsx +823 -885
  28. package/src/components/EditorPanel/components/Error.tsx +9 -2
  29. package/src/components/EditorPanel/components/HexShapeSettings.tsx +127 -141
  30. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +55 -86
  31. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +89 -75
  32. package/src/components/EditorPanel/components/editorPanel.styles.css +95 -0
  33. package/src/components/Geo.tsx +9 -1
  34. package/src/components/GoogleMap/components/GoogleMap.tsx +1 -1
  35. package/src/components/Legend/components/Legend.tsx +92 -87
  36. package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +128 -0
  37. package/src/components/Legend/components/LegendGroup/legend.group.css +27 -0
  38. package/src/components/Legend/components/LegendItem.Hex.tsx +4 -1
  39. package/src/components/Legend/components/index.scss +74 -17
  40. package/src/components/Modal.tsx +17 -7
  41. package/src/components/NavigationMenu.tsx +11 -9
  42. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +12 -8
  43. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +4 -4
  44. package/src/components/UsaMap/components/TerritoriesSection.tsx +33 -10
  45. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +12 -10
  46. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -14
  47. package/src/components/UsaMap/components/Territory/TerritoryShape.ts +2 -1
  48. package/src/components/UsaMap/components/UsaMap.County.tsx +138 -96
  49. package/src/components/UsaMap/components/UsaMap.Region.styles.css +72 -0
  50. package/src/components/UsaMap/components/UsaMap.Region.tsx +56 -103
  51. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +10 -0
  52. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +65 -74
  53. package/src/components/UsaMap/components/UsaMap.State.tsx +112 -91
  54. package/src/components/UsaMap/helpers/map.ts +1 -1
  55. package/src/components/UsaMap/helpers/shapes.ts +20 -7
  56. package/src/components/WorldMap/WorldMap.tsx +64 -118
  57. package/src/components/WorldMap/worldMap.styles.css +28 -0
  58. package/src/components/ZoomControls.tsx +15 -13
  59. package/src/components/zoomControls.styles.css +53 -0
  60. package/src/context.ts +17 -9
  61. package/src/data/initial-state.js +5 -2
  62. package/src/helpers/addUIDs.ts +150 -0
  63. package/src/helpers/applyColorToLegend.ts +39 -64
  64. package/src/helpers/applyLegendToRow.ts +51 -0
  65. package/src/helpers/colorDistributions.ts +12 -0
  66. package/src/helpers/constants.ts +44 -0
  67. package/src/helpers/displayGeoName.ts +9 -2
  68. package/src/helpers/formatLegendLocation.ts +3 -2
  69. package/src/helpers/generateColorsArray.ts +2 -1
  70. package/src/helpers/generateRuntimeData.ts +78 -0
  71. package/src/helpers/generateRuntimeFilters.ts +63 -0
  72. package/src/helpers/generateRuntimeLegend.ts +566 -0
  73. package/src/helpers/generateRuntimeLegendHash.ts +16 -15
  74. package/src/helpers/getColumnNames.ts +19 -0
  75. package/src/helpers/getMapContainerClasses.ts +23 -0
  76. package/src/helpers/getStatePicked.ts +8 -0
  77. package/src/helpers/handleMapTabbing.ts +31 -0
  78. package/src/helpers/hashObj.ts +1 -1
  79. package/src/helpers/index.ts +22 -0
  80. package/src/helpers/navigationHandler.ts +3 -3
  81. package/src/helpers/resetLegendToggles.ts +13 -0
  82. package/src/helpers/setBinNumbers.ts +5 -0
  83. package/src/helpers/sortSpecialClassesLast.ts +7 -0
  84. package/src/helpers/tests/getColumnNames.test.ts +52 -0
  85. package/src/helpers/titleCase.ts +1 -1
  86. package/src/helpers/toggleLegendActive.ts +25 -0
  87. package/src/hooks/useApplyTooltipsToGeo.tsx +51 -0
  88. package/src/hooks/useColumnsRequiredChecker.ts +51 -0
  89. package/src/hooks/useGeoClickHandler.ts +45 -0
  90. package/src/hooks/useLegendSeparators.ts +26 -0
  91. package/src/hooks/useMapLayers.tsx +34 -60
  92. package/src/hooks/useModal.ts +22 -0
  93. package/src/hooks/useResizeObserver.ts +4 -5
  94. package/src/hooks/useStateZoom.tsx +52 -75
  95. package/src/hooks/useTooltip.ts +2 -3
  96. package/src/index.jsx +3 -9
  97. package/src/scss/editor-panel.scss +3 -99
  98. package/src/scss/main.scss +1 -19
  99. package/src/scss/map.scss +15 -220
  100. package/src/store/map.actions.ts +46 -0
  101. package/src/store/map.reducer.ts +96 -0
  102. package/src/types/Annotations.ts +24 -0
  103. package/src/types/MapConfig.ts +23 -3
  104. package/src/types/MapContext.ts +36 -35
  105. package/src/types/Modal.ts +1 -0
  106. package/src/types/RuntimeData.ts +3 -0
  107. package/examples/private/DEV-9644.json +0 -184
  108. package/examples/private/DEV-9989.json +0 -229
  109. package/examples/private/ardi.json +0 -180
  110. package/examples/private/colors 2.json +0 -416
  111. package/examples/private/colors.json +0 -416
  112. package/examples/private/colors.json.zip +0 -0
  113. package/examples/private/customColors.json +0 -45348
  114. package/examples/test.json +0 -183
  115. package/src/helpers/closeModal.ts +0 -9
  116. package/src/scss/btn.scss +0 -69
  117. package/src/scss/filters.scss +0 -27
  118. package/src/scss/variables.scss +0 -1
  119. /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,71 @@
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
+ import _ from 'lodash'
27
+ import { getStatePicked } from '../../../helpers/getStatePicked'
28
+
29
+ const SingleStateMap: React.FC = () => {
27
30
  const {
28
- state,
29
- applyTooltipsToGeo,
30
- data,
31
- geoClickHandler,
32
- applyLegendToRow,
33
- displayGeoName,
31
+ config,
34
32
  setSharedFilterValue,
35
33
  isFilterValueSupported,
36
34
  runtimeFilters,
35
+ runtimeData,
37
36
  tooltipId,
38
37
  position,
39
- setPosition,
40
- stateToShow,
41
38
  topoData,
42
- setTopoData,
43
39
  scale,
44
- translate,
45
- setStateToShow
40
+ translate
46
41
  } = useContext<MapContext>(ConfigContext)
47
42
 
48
- const { handleMoveEnd, handleZoomIn, handleZoomOut, handleReset, projection, statePicked } = useStateZoom(topoData)
43
+ const dispatch = useContext(MapDispatchContext)
44
+ const { handleMoveEnd, handleZoomIn, handleZoomOut, handleReset, projection } = useStateZoom(topoData)
45
+ const statePicked = getStatePicked(config, runtimeData)
46
+ const stateToShow = topoData?.states?.find(s => s.properties.name === statePicked.stateName)
47
+
48
+ const { geoClickHandler } = useGeoClickHandler()
49
49
 
50
50
  const cityListProjection = geoAlbersUsaTerritories()
51
- .translate([WIDTH / 2, HEIGHT / 2])
51
+ .translate([SVG_WIDTH / 2, SVG_HEIGHT / 2])
52
52
  .scale(1)
53
- const geoStrokeColor = getGeoStrokeColor(state)
53
+ const geoStrokeColor = getGeoStrokeColor(config)
54
54
  const path = geoPath().projection(projection)
55
55
 
56
56
  useEffect(() => {
57
- setStateToShow(topoData?.states?.find(s => s.properties.name === state.general.statePicked.stateName))
58
- }, [statePicked])
59
-
60
- useEffect(() => {
61
- let currentYear = getCurrentTopoYear(state, runtimeFilters)
57
+ let currentYear = getCurrentTopoYear(config, runtimeFilters)
62
58
 
63
- if (currentYear !== topoData.year) {
59
+ if (currentYear !== topoData?.year) {
64
60
  getTopoData(currentYear).then(response => {
65
- setTopoData(response)
61
+ dispatch({ type: 'SET_TOPO_DATA', payload: response })
66
62
  })
67
63
  }
68
- }, [state.general.countyCensusYear, state.general.filterControlsCountyYear, JSON.stringify(runtimeFilters)])
64
+ }, [config.general.countyCensusYear, config.general.filterControlsCountyYear, JSON.stringify(runtimeFilters)])
69
65
 
70
- if (!isTopoReady(topoData, state, runtimeFilters)) {
66
+ if (!isTopoReady(topoData, config, runtimeFilters)) {
71
67
  return (
72
- <div style={{ height: `${HEIGHT}px` }}>
68
+ <div style={{ height: `${SVG_HEIGHT}px` }}>
73
69
  <Loading />
74
70
  </div>
75
71
  )
@@ -77,16 +73,16 @@ const SingleStateMap = props => {
77
73
 
78
74
  const checkForNoData = () => {
79
75
  // If no statePicked, return true
80
- if (!state.general.statePicked.fipsCode) return true
76
+ if (!statePicked.fipsCode) return true
81
77
  }
82
78
 
83
79
  // Constructs and displays markup for all geos on the map (except territories right now)
84
- const constructGeoJsx = (geographies, projection) => {
80
+ const constructGeoJsx = geographies => {
85
81
  const counties = geographies[0].feature.counties
86
82
 
87
83
  let geosJsx = []
88
84
 
89
- // Push state lines
85
+ // Push config lines
90
86
  geosJsx.push(
91
87
  // prettier-ignore
92
88
  <SingleState.StateOutput
@@ -113,12 +109,7 @@ const SingleStateMap = props => {
113
109
  <CityList
114
110
  projection={cityListProjection}
115
111
  key='cities'
116
- data={data}
117
- state={state}
118
112
  geoClickHandler={geoClickHandler}
119
- applyTooltipsToGeo={applyTooltipsToGeo}
120
- displayGeoName={displayGeoName}
121
- applyLegendToRow={applyLegendToRow}
122
113
  titleCase={titleCase}
123
114
  setSharedFilterValue={setSharedFilterValue}
124
115
  isFilterValueSupported={isFilterValueSupported}
@@ -130,28 +121,28 @@ const SingleStateMap = props => {
130
121
  }
131
122
  return (
132
123
  <ErrorBoundary component='SingleStateMap'>
133
- {statePicked && state.general.allowMapZoom && state.general.statePicked.fipsCode && (
124
+ {statePicked && config.general.allowMapZoom && statePicked.fipsCode && (
134
125
  <svg
135
- viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
126
+ viewBox={SVG_VIEWBOX}
136
127
  preserveAspectRatio='xMinYMin'
137
128
  className='svg-container'
138
129
  role='img'
139
- aria-label={handleMapAriaLabels(state)}
130
+ aria-label={handleMapAriaLabels(config)}
140
131
  >
141
132
  <ZoomableGroup
142
133
  center={position.coordinates}
143
134
  zoom={position.zoom}
144
135
  minZoom={1} // Adjust this value if needed
145
- maxZoom={4} // Adjust this value to limit the maximum zoom level
136
+ maxZoom={MAX_ZOOM_LEVEL}
146
137
  onMoveEnd={handleMoveEnd}
147
138
  projection={projection}
148
- width={880}
149
- height={500}
139
+ width={SVG_WIDTH}
140
+ height={SVG_HEIGHT}
150
141
  >
151
142
  <rect
152
143
  className='background center-container ocean'
153
- width={WIDTH}
154
- height={HEIGHT}
144
+ width={SVG_WIDTH}
145
+ height={SVG_HEIGHT}
155
146
  fillOpacity={1}
156
147
  fill='white'
157
148
  ></rect>
@@ -159,14 +150,14 @@ const SingleStateMap = props => {
159
150
  data={[
160
151
  {
161
152
  states: topoData?.states,
162
- counties: topoData.counties.filter(c => c.id.substring(0, 2) === state.general.statePicked.fipsCode)
153
+ counties: topoData.counties.filter(c => c.id.substring(0, 2) === statePicked.fipsCode)
163
154
  }
164
155
  ]}
165
156
  projection={geoAlbersUsaTerritories}
166
157
  fitExtent={[
167
158
  [
168
- [PADDING, PADDING],
169
- [WIDTH - PADDING, HEIGHT - PADDING]
159
+ [SVG_PADDING, SVG_PADDING],
160
+ [SVG_WIDTH - SVG_PADDING, SVG_HEIGHT - SVG_PADDING]
170
161
  ],
171
162
  stateToShow
172
163
  ]}
@@ -176,7 +167,7 @@ const SingleStateMap = props => {
176
167
  <g
177
168
  id='mapGroup'
178
169
  className={`countyMapGroup ${
179
- state.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
170
+ config.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
180
171
  }`}
181
172
  transform={`translate(${translate}) scale(${scale})`}
182
173
  data-scale=''
@@ -187,22 +178,22 @@ const SingleStateMap = props => {
187
178
  )
188
179
  }}
189
180
  </CustomProjection>
190
- {state.annotations.length > 0 && <Annotation.Draggable />}
181
+ {config.annotations.length > 0 && <Annotation.Draggable />}
191
182
  </ZoomableGroup>
192
183
  </svg>
193
184
  )}
194
- {statePicked && !state.general.allowMapZoom && state.general.statePicked.fipsCode && (
185
+ {statePicked && !config.general.allowMapZoom && statePicked.fipsCode && (
195
186
  <svg
196
- viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
187
+ viewBox={SVG_VIEWBOX}
197
188
  preserveAspectRatio='xMinYMin'
198
189
  className='svg-container'
199
190
  role='img'
200
- aria-label={handleMapAriaLabels(state)}
191
+ aria-label={handleMapAriaLabels(config)}
201
192
  >
202
193
  <rect
203
194
  className='background center-container ocean'
204
- width={WIDTH}
205
- height={HEIGHT}
195
+ width={SVG_WIDTH}
196
+ height={SVG_HEIGHT}
206
197
  fillOpacity={1}
207
198
  fill='white'
208
199
  ></rect>
@@ -210,56 +201,56 @@ const SingleStateMap = props => {
210
201
  data={[
211
202
  {
212
203
  states: topoData?.states,
213
- counties: topoData.counties.filter(c => c.id.substring(0, 2) === state.general.statePicked.fipsCode)
204
+ counties: topoData.counties.filter(c => c.id.substring(0, 2) === statePicked.fipsCode)
214
205
  }
215
206
  ]}
216
207
  projection={geoAlbersUsaTerritories}
217
208
  fitExtent={[
218
209
  [
219
- [PADDING, PADDING],
220
- [WIDTH - PADDING, HEIGHT - PADDING]
210
+ [SVG_PADDING, SVG_PADDING],
211
+ [SVG_WIDTH - SVG_PADDING, SVG_HEIGHT - SVG_PADDING]
221
212
  ],
222
213
  stateToShow
223
214
  ]}
224
215
  >
225
- {({ features, projection }) => {
216
+ {({ features }) => {
226
217
  return (
227
218
  <g
228
219
  id='mapGroup'
229
220
  className={`countyMapGroup ${
230
- state.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
221
+ config.general.geoType === 'single-state' ? `countyMapGroup--no-transition` : ''
231
222
  }`}
232
223
  transform={`translate(${translate}) scale(${scale})`}
233
224
  data-scale=''
234
225
  key='countyMapGroup'
235
226
  >
236
- {constructGeoJsx(features, projection)}
227
+ {constructGeoJsx(features)}
237
228
  </g>
238
229
  )
239
230
  }}
240
231
  </CustomProjection>
241
- {state.annotations.length > 0 && <Annotation.Draggable />}
232
+ {config.annotations.length > 0 && <Annotation.Draggable />}
242
233
  </svg>
243
234
  )}
244
235
 
245
236
  {checkForNoData() && (
246
237
  <svg
247
- viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
238
+ viewBox={SVG_VIEWBOX}
248
239
  preserveAspectRatio='xMinYMin'
249
240
  className='svg-container'
250
241
  role='img'
251
- aria-label={handleMapAriaLabels(state)}
242
+ aria-label={handleMapAriaLabels(config)}
252
243
  >
253
244
  <Text
254
245
  verticalAnchor='start'
255
246
  textAnchor='middle'
256
- x={WIDTH / 2}
257
- width={WIDTH}
258
- y={HEIGHT / 2}
247
+ x={SVG_WIDTH / 2}
248
+ width={SVG_WIDTH}
249
+ y={SVG_HEIGHT / 2}
259
250
  fontSize={18}
260
251
  style={{ fontSize: '28px', height: '18px' }}
261
252
  >
262
- {state.general.noStateFoundMessage}
253
+ {config.general.noStateFoundMessage}
263
254
  </Text>
264
255
  </svg>
265
256
  )}