@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 React, { useState, useEffect, memo, useContext } from 'react'
1
+ import React, { useState, useEffect, useContext, useRef } from 'react'
2
2
 
3
3
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
4
4
 
@@ -19,27 +19,40 @@ import { patternSizes } from '../helpers/patternSizes'
19
19
  import Annotation from '../../Annotation'
20
20
  import Territory from './Territory'
21
21
 
22
- import useMapLayers from '../../../hooks/useMapLayers'
23
- import ConfigContext from '../../../context'
22
+ import ConfigContext, { MapDispatchContext } from '../../../context'
24
23
  import { MapContext } from '../../../types/MapContext'
25
24
  import { checkColorContrast, getContrastColor, outlinedTextColor } from '@cdc/core/helpers/cove/accessibility'
26
- import { getGeoFillColor, getGeoStrokeColor } from '../../../helpers/colors'
27
- import { handleMapAriaLabels } from '../../../helpers/handleMapAriaLabels'
28
- import { titleCase } from '../../../helpers/titleCase'
29
25
  import TerritoriesSection from './TerritoriesSection'
30
- import { displayGeoName } from '../../../helpers/displayGeoName'
31
26
 
27
+ import { isMobileStateLabelViewport } from '@cdc/core/helpers/viewports'
28
+ import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
29
+
30
+ import useMapLayers from '../../../hooks/useMapLayers'
31
+ import useGeoClickHandler from '../../../hooks/useGeoClickHandler'
32
+ import { applyLegendToRow } from '../../../helpers/applyLegendToRow'
33
+ import useApplyTooltipsToGeo from '../../../hooks/useApplyTooltipsToGeo'
34
+ import {
35
+ getGeoFillColor,
36
+ getGeoStrokeColor,
37
+ handleMapAriaLabels,
38
+ titleCase,
39
+ displayGeoName,
40
+ SVG_HEIGHT,
41
+ SVG_VIEWBOX,
42
+ SVG_WIDTH,
43
+ hashObj
44
+ } from '../../../helpers'
32
45
  const { features: unitedStatesHex } = topoFeature(hexTopoJSON, hexTopoJSON.objects.states)
33
46
 
34
47
  const offsets = {
35
- 'US-VT': [50, -8],
36
- 'US-NH': [34, 2],
37
- 'US-MA': [30, -1],
38
- 'US-RI': [28, 2],
39
- 'US-CT': [35, 10],
40
- 'US-NJ': [42, 1],
48
+ 'US-VT': [53, -7],
49
+ 'US-NH': [38, 7],
50
+ 'US-MA': [34, -1],
51
+ 'US-RI': [29, 7],
52
+ 'US-CT': [43, 20],
53
+ 'US-NJ': [26, 7],
41
54
  'US-DE': [33, 0],
42
- 'US-MD': [47, 10]
55
+ 'US-MD': [51, 16]
43
56
  }
44
57
 
45
58
  const nudges = {
@@ -55,22 +68,31 @@ const nudges = {
55
68
  }
56
69
 
57
70
  const UsaMap = () => {
58
- // prettier-ignore
59
71
  const {
60
- applyLegendToRow,
61
- applyTooltipsToGeo,
62
- data,
63
- geoClickHandler,
64
- setSharedFilterValue,
65
- state,
66
- tooltipId,
67
- handleDragStateChange,
68
- mapId,
69
- logo,
70
- } = useContext<MapContext>(ConfigContext)
72
+ data,
73
+ setSharedFilterValue,
74
+ config,
75
+ setConfig,
76
+ tooltipId,
77
+ mapId,
78
+ logo,
79
+ legendMemo,
80
+ legendSpecialClassLastMemo,
81
+ currentViewport,
82
+ translate,
83
+ runtimeLegend
84
+ } = useContext<MapContext>(ConfigContext)
71
85
 
72
86
  let isFilterValueSupported = false
73
- const { general, columns, feature, tooltips, hexMap, map, annotations } = state
87
+ const { general, columns, tooltips, hexMap, map, annotations } = config
88
+ const { displayAsHex } = general
89
+ const { geoClickHandler } = useGeoClickHandler()
90
+ const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
91
+ const dispatch = useContext(MapDispatchContext)
92
+
93
+ const handleDragStateChange = (dragState: any) => {
94
+ dispatch({ type: 'SET_IS_DRAGGING_ANNOTATION', payload: dragState })
95
+ }
74
96
 
75
97
  if (setSharedFilterValue) {
76
98
  Object.keys(supportedStates).forEach(supportedState => {
@@ -92,9 +114,20 @@ const UsaMap = () => {
92
114
  }
93
115
 
94
116
  // "Choose State" options
95
- const [extent, setExtent] = useState(null)
96
117
  const [focusedStates, setFocusedStates] = useState(null)
97
- const [translate, setTranslate] = useState([455, 200])
118
+
119
+ const dataRef = useRef(null)
120
+
121
+ const legendMemoUpdated = focusedStates?.every(geo => {
122
+ const geoKey = geo.properties.iso
123
+ const geoData = data[geoKey]
124
+ const hash = hashObj(geoData)
125
+ return legendMemo.current.has(hash)
126
+ })
127
+
128
+ // we use dataRef so that we can use the old data when legendMemo has not been updated yet
129
+ // prevents flickering of the map when filter is changed
130
+ if (legendMemoUpdated) dataRef.current = data
98
131
 
99
132
  useEffect(() => {
100
133
  const fetchData = async () => {
@@ -107,12 +140,9 @@ const UsaMap = () => {
107
140
 
108
141
  // When returning from another map we want to reset the state
109
142
  useEffect(() => {
110
- setTranslate([455, 250])
111
- setExtent(null)
143
+ dispatch({ type: 'SET_TRANSLATE', payload: [SVG_WIDTH / 2, SVG_HEIGHT / 2] })
112
144
  }, [general.geoType])
113
145
 
114
- const isHex = general.displayAsHex
115
-
116
146
  const [territoriesData, setTerritoriesData] = useState([])
117
147
 
118
148
  const territoriesKeys = Object.keys(supportedTerritories) // data will have already mapped abbreviated territories to their full names
@@ -123,25 +153,25 @@ const UsaMap = () => {
123
153
  setTerritoriesData(territoriesKeys)
124
154
  } else {
125
155
  // 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
126
- const territoriesList = territoriesKeys.filter(key => data[key])
156
+ const territoriesList = territoriesKeys.filter(key => data?.[key])
127
157
  setTerritoriesData(territoriesList)
128
158
  }
129
- }, [data, general.territoriesAlwaysShow])
159
+ }, [data, dataRef.current, general.territoriesAlwaysShow])
130
160
 
131
- const geoStrokeColor = getGeoStrokeColor(state)
132
- const geoFillColor = getGeoFillColor(state)
161
+ const geoStrokeColor = getGeoStrokeColor(config)
162
+ const geoFillColor = getGeoFillColor(config)
133
163
 
134
164
  const territories = territoriesData.map((territory, territoryIndex) => {
135
- const Shape = isHex ? Territory.Hexagon : Territory.Rectangle
165
+ const Shape = displayAsHex ? Territory.Hexagon : Territory.Rectangle
136
166
 
137
- const territoryData = data[territory]
167
+ const territoryData = data?.[territory]
138
168
 
139
169
  let toolTip
140
170
 
141
171
  let styles = {
142
172
  fill: geoFillColor,
143
173
  stroke: geoStrokeColor,
144
- color: '#202020'
174
+ color: APP_FONT_COLOR
145
175
  }
146
176
 
147
177
  const label = supportedTerritories[territory][1]
@@ -152,7 +182,8 @@ const UsaMap = () => {
152
182
  key={label}
153
183
  label={label}
154
184
  style={styles}
155
- text={styles.color}
185
+ textColor={styles.color}
186
+ strokeColor='#fff'
156
187
  territoryData={territoryData}
157
188
  backgroundColor={styles.fill}
158
189
  />
@@ -160,11 +191,9 @@ const UsaMap = () => {
160
191
 
161
192
  toolTip = applyTooltipsToGeo(displayGeoName(territory), territoryData)
162
193
 
163
- const legendColors = applyLegendToRow(territoryData)
194
+ const legendColors = applyLegendToRow(territoryData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
164
195
 
165
196
  if (legendColors) {
166
- const textColor = getContrastColor('#FFF', legendColors[0])
167
-
168
197
  let needsPointer = false
169
198
 
170
199
  // If we need to add a pointer cursor
@@ -172,6 +201,8 @@ const UsaMap = () => {
172
201
  needsPointer = true
173
202
  }
174
203
 
204
+ const { textColor, strokeColor } = outlinedTextColor(legendColors[0])
205
+
175
206
  styles = {
176
207
  color: textColor,
177
208
  fill: legendColors[0],
@@ -197,9 +228,9 @@ const UsaMap = () => {
197
228
  key={`label__${territoryIndex}`}
198
229
  label={label}
199
230
  style={styles}
200
- text={styles.color}
201
231
  strokeWidth={1}
202
232
  textColor={textColor}
233
+ strokeColor={strokeColor}
203
234
  handleShapeClick={() => geoClickHandler(territory, territoryData)}
204
235
  dataTooltipId={`tooltip__${tooltipId}`}
205
236
  dataTooltipHtml={toolTip}
@@ -214,8 +245,8 @@ const UsaMap = () => {
214
245
 
215
246
  let pathGenerator = geoPath().projection(geoAlbersUsa().translate(translate))
216
247
 
217
- // Note: Layers are different than patterns
218
- const { pathArray } = useMapLayers(state, '', pathGenerator, tooltipId)
248
+ // Note: Layers are different from patterns
249
+ const { pathArray } = useMapLayers(config, setConfig, pathGenerator, tooltipId)
219
250
 
220
251
  if (!focusedStates) {
221
252
  return <></>
@@ -246,7 +277,7 @@ const UsaMap = () => {
246
277
  })
247
278
 
248
279
  const geosJsx = geographies.map(({ feature: geo, path = '' }, geoIndex) => {
249
- const key = isHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
280
+ const key = displayAsHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
250
281
 
251
282
  let styles = {
252
283
  fill: geoFillColor,
@@ -259,13 +290,13 @@ const UsaMap = () => {
259
290
 
260
291
  if (!geoKey) return
261
292
 
262
- const geoData = data[geoKey]
293
+ const geoData = data?.[geoKey]
263
294
 
264
295
  let legendColors
265
296
 
266
297
  // Once we receive data for this geographic item, setup variables.
267
298
  if (geoData !== undefined) {
268
- legendColors = applyLegendToRow(geoData)
299
+ legendColors = applyLegendToRow(geoData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
269
300
  }
270
301
 
271
302
  const geoDisplayName = displayGeoName(geoKey)
@@ -275,7 +306,7 @@ const UsaMap = () => {
275
306
  const tooltip = applyTooltipsToGeo(geoDisplayName, geoData)
276
307
 
277
308
  styles = {
278
- fill: state.general.type !== 'bubble' ? legendColors[0] : geoFillColor,
309
+ fill: config.general.type !== 'bubble' ? legendColors[0] : geoFillColor,
279
310
  opacity:
280
311
  setSharedFilterValue && isFilterValueSupported && setSharedFilterValue !== geoData[columns.geo.name]
281
312
  ? 0.5
@@ -286,10 +317,10 @@ const UsaMap = () => {
286
317
  : geoStrokeColor,
287
318
  cursor: 'default',
288
319
  '&:hover': {
289
- fill: state.general.type !== 'bubble' ? legendColors[1] : geoFillColor
320
+ fill: config.general.type !== 'bubble' ? legendColors[1] : geoFillColor
290
321
  },
291
322
  '&:active': {
292
- fill: state.general.type !== 'bubble' ? legendColors[2] : geoFillColor
323
+ fill: config.general.type !== 'bubble' ? legendColors[2] : geoFillColor
293
324
  }
294
325
  }
295
326
 
@@ -307,7 +338,7 @@ const UsaMap = () => {
307
338
 
308
339
  return (
309
340
  <>
310
- {hexMap.shapeGroups.map((group, groupIndex) => {
341
+ {hexMap.shapeGroups.map((group, _groupIndex) => {
311
342
  return group.items.map((item, itemIndex) => {
312
343
  switch (item.operator) {
313
344
  case '=':
@@ -414,7 +445,7 @@ const UsaMap = () => {
414
445
  <path tabIndex={-1} className='single-geo' strokeWidth={1} d={path} />
415
446
 
416
447
  {/* apply patterns on top of state path*/}
417
- {map.patterns.map((patternData, patternIndex) => {
448
+ {map?.patterns?.map((patternData, _patternIndex) => {
418
449
  const { pattern, dataKey, size } = patternData
419
450
  const currentFill = styles.fill
420
451
  const hasMatchingValues = patternData.dataValue === geoData?.[patternData.dataKey]
@@ -431,6 +462,7 @@ const UsaMap = () => {
431
462
  height={patternSizes[size] ?? 10}
432
463
  width={patternSizes[size] ?? 10}
433
464
  fill={patternColor}
465
+ strokeWidth={0.25}
434
466
  />
435
467
  )}
436
468
  {pattern === 'circles' && (
@@ -439,6 +471,8 @@ const UsaMap = () => {
439
471
  height={patternSizes[size] ?? 10}
440
472
  width={patternSizes[size] ?? 10}
441
473
  fill={patternColor}
474
+ stroke={patternColor}
475
+ radius={0.5}
442
476
  />
443
477
  )}
444
478
  {pattern === 'lines' && (
@@ -447,7 +481,7 @@ const UsaMap = () => {
447
481
  height={patternSizes[size] ?? 6}
448
482
  width={patternSizes[size] ?? 6}
449
483
  stroke={patternColor}
450
- strokeWidth={1}
484
+ strokeWidth={0.75}
451
485
  orientation={['diagonalRightToLeft']}
452
486
  />
453
487
  )}
@@ -461,8 +495,8 @@ const UsaMap = () => {
461
495
  </>
462
496
  )
463
497
  })}
464
- {(isHex || showLabel) && geoLabel(geo, legendColors[0], projection)}
465
- {isHex && hexMap.type === 'shapes' && getArrowDirection(geoData, geo, legendColors[0])}
498
+ {(displayAsHex || showLabel) && geoLabel(geo, legendColors[0], projection)}
499
+ {displayAsHex && hexMap.type === 'shapes' && getArrowDirection(geoData, geo, legendColors[0])}
466
500
  </g>
467
501
  </g>
468
502
  )
@@ -473,27 +507,24 @@ const UsaMap = () => {
473
507
  <g data-name={geoName} key={key} tabIndex={-1}>
474
508
  <g className='geo-group' style={styles} tabIndex={-1}>
475
509
  <path tabIndex={-1} className='single-geo' stroke={geoStrokeColor} strokeWidth={1.3} d={path} />
476
- {(isHex || showLabel) && geoLabel(geo, styles.fill, projection)}
510
+ {(displayAsHex || showLabel) && geoLabel(geo, styles.fill, projection)}
477
511
  </g>
478
512
  </g>
479
513
  )
480
514
  })
481
515
 
482
- if (isHex) return geosJsx
516
+ if (displayAsHex) return geosJsx
483
517
 
484
518
  // Cities
485
519
  geosJsx.push(
486
520
  <CityList
487
521
  applyLegendToRow={applyLegendToRow}
488
522
  applyTooltipsToGeo={applyTooltipsToGeo}
489
- data={data}
490
- displayGeoName={displayGeoName}
491
523
  geoClickHandler={geoClickHandler}
492
524
  isFilterValueSupported={isFilterValueSupported}
493
525
  key='cities'
494
526
  projection={projection}
495
527
  setSharedFilterValue={setSharedFilterValue}
496
- state={state}
497
528
  titleCase={titleCase}
498
529
  tooltipId={tooltipId}
499
530
  />
@@ -501,18 +532,7 @@ const UsaMap = () => {
501
532
 
502
533
  // Bubbles
503
534
  if (general.type === 'bubble') {
504
- geosJsx.push(
505
- <BubbleList
506
- key='bubbles'
507
- data={state.data}
508
- runtimeData={data}
509
- state={state}
510
- projection={projection}
511
- applyLegendToRow={applyLegendToRow}
512
- applyTooltipsToGeo={applyTooltipsToGeo}
513
- displayGeoName={displayGeoName}
514
- />
515
- )
535
+ geosJsx.push(<BubbleList runtimeData={dataRef.current} projection={projection} />)
516
536
  }
517
537
 
518
538
  // })
@@ -526,13 +546,13 @@ const UsaMap = () => {
526
546
  }
527
547
 
528
548
  const geoLabel = (geo, bgColor = '#FFFFFF', projection) => {
529
- let centroid = projection ? projection(geoCentroid(geo)) : [22, 17.5]
530
- let abbr = geo.properties.iso
549
+ const centroid = projection ? projection(geoCentroid(geo)) : [22, 17.5]
550
+ const abbr = geo.properties.iso
531
551
 
532
552
  if (undefined === abbr) return null
533
553
 
534
554
  // HI background is always white since it is off to the side
535
- if (abbr === 'US-HI' && !general.displayAsHex) {
555
+ if ((abbr === 'US-HI' && !general.displayAsHex) || (Object.keys(offsets).includes(abbr) && !general.displayAsHex)) {
536
556
  bgColor = '#FFF'
537
557
  }
538
558
  const { textColor, strokeColor } = outlinedTextColor(bgColor)
@@ -541,21 +561,22 @@ const UsaMap = () => {
541
561
  y = hexMap.type === 'shapes' && general.displayAsHex ? -10 : 5
542
562
 
543
563
  // used to nudge/move some of the labels for better readability
544
- if (nudges[abbr] && false === isHex) {
564
+ if (nudges[abbr] && false === displayAsHex) {
545
565
  x += nudges[abbr][0]
546
566
  y += nudges[abbr][1]
547
567
  }
548
568
 
549
- if (undefined === offsets[abbr] || isHex) {
569
+ if (undefined === offsets[abbr] || displayAsHex) {
550
570
  return (
551
571
  <g transform={`translate(${centroid})`} tabIndex={-1}>
552
572
  <text
553
573
  x={x}
554
574
  y={y}
555
- fontSize={14}
556
- strokeWidth='0'
557
- // paintOrder='stroke' // PENDING DEV-9278: Adds a stroke around the text potentially for 508 compliance
558
- // stroke={strokeColor}
575
+ fontSize={isMobileStateLabelViewport(currentViewport) ? 16 : 13}
576
+ fontWeight={900}
577
+ strokeWidth='1'
578
+ paintOrder='stroke'
579
+ stroke={strokeColor}
559
580
  style={{ fill: textColor }}
560
581
  textAnchor='middle'
561
582
  >
@@ -580,9 +601,9 @@ const UsaMap = () => {
580
601
  <text
581
602
  x={4}
582
603
  strokeWidth='0'
583
- // paintOrder='stroke' // PENDING DEV-9278: Adds a stroke around the text potentially for 508 compliance
584
- // stroke={strokeColor}
585
- fontSize={13}
604
+ stroke={APP_FONT_COLOR}
605
+ fontSize={isMobileStateLabelViewport(currentViewport) ? 16 : 13}
606
+ fontWeight={900}
586
607
  style={{ fill: textColor }}
587
608
  alignmentBaseline='middle'
588
609
  transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}
@@ -595,20 +616,20 @@ const UsaMap = () => {
595
616
 
596
617
  return (
597
618
  <ErrorBoundary component='UsaMap'>
598
- <svg viewBox='0 0 880 500' role='img' aria-label={handleMapAriaLabels(state)}>
619
+ <svg viewBox={SVG_VIEWBOX} role='img' aria-label={handleMapAriaLabels(config)}>
599
620
  {general.displayAsHex ? (
600
621
  <Mercator data={unitedStatesHex} scale={650} translate={[1600, 775]}>
601
622
  {({ features, projection }) => constructGeoJsx(features, projection)}
602
623
  </Mercator>
603
624
  ) : (
604
- <AlbersUsa data={focusedStates} translate={translate} fitExtent={extent}>
625
+ <AlbersUsa data={focusedStates} translate={translate}>
605
626
  {({ features, projection }) => constructGeoJsx(features, projection)}
606
627
  </AlbersUsa>
607
628
  )}
608
- {annotations.length > 0 && <Annotation.Draggable onDragStateChange={handleDragStateChange} />}
629
+ {annotations?.length > 0 && <Annotation.Draggable onDragStateChange={handleDragStateChange} />}
609
630
  </svg>
610
631
 
611
- <TerritoriesSection territories={territories} logo={logo} config={state} territoriesData={territoriesData} />
632
+ <TerritoriesSection territories={territories} logo={logo} config={config} territoriesData={territoriesData} />
612
633
  </ErrorBoundary>
613
634
  )
614
635
  }
@@ -82,7 +82,7 @@ export const getCurrentTopoYear = (state, runtimeFilters) => {
82
82
  export const isTopoReady = (topoData, state, runtimeFilters) => {
83
83
  let currentYear = getCurrentTopoYear(state, runtimeFilters)
84
84
 
85
- return topoData.year && (!currentYear || currentYear === topoData.year)
85
+ return topoData?.year && (!currentYear || currentYear === topoData?.year)
86
86
  }
87
87
 
88
88
  export const hasMoreThanFromHash = (data: { [key: string]: any }): boolean => {
@@ -109,34 +109,47 @@ export const drawStar = (star, context, state) => {
109
109
  const outerRadius = star.outerRadius * scaleVal
110
110
  const innerRadius = star.innerRadius * scaleVal
111
111
 
112
+ // Adjust for zoom (based on your existing logic)
112
113
  const adjustedOuterRadius = state.mapPosition.zoom > 1 ? outerRadius * percentOfOriginalSize : outerRadius
113
114
  const adjustedInnerRadius = state.mapPosition.zoom > 1 ? innerRadius * percentOfOriginalSize : innerRadius
114
115
 
116
+ // Set line width and color
115
117
  context.lineWidth = star.lineWidth
116
118
  context.fillStyle = star.color
117
119
  context.beginPath()
118
120
 
119
- let rot = (Math.PI / 2) * 3
120
- let step = Math.PI / spikes
121
+ // Start drawing the star from the top (no rotation)
122
+ const startAngle = Math.PI / 2 // 90 degrees (points upwards)
123
+ let rot = startAngle
124
+ const step = Math.PI / spikes // angle between each spike
121
125
 
122
- // Starting coordinates for the first point
123
- let x = star.x
124
- let y = star.y
125
- context.moveTo(x, y - adjustedOuterRadius)
126
+ // Starting coordinates for the first point of the star
127
+ let x = star.x + Math.cos(rot) * adjustedOuterRadius
128
+ let y = star.y + Math.sin(rot) * adjustedOuterRadius
129
+ context.moveTo(x, y)
126
130
 
131
+ // Draw the star
127
132
  for (let i = 0; i < spikes; i++) {
133
+ // Outer points of the star
128
134
  x = star.x + Math.cos(rot) * adjustedOuterRadius
129
135
  y = star.y + Math.sin(rot) * adjustedOuterRadius
130
136
  context.lineTo(x, y)
131
137
  rot += step
132
138
 
139
+ // Inner points of the star
133
140
  x = star.x + Math.cos(rot) * adjustedInnerRadius
134
141
  y = star.y + Math.sin(rot) * adjustedInnerRadius
135
142
  context.lineTo(x, y)
136
143
  rot += step
137
144
  }
138
145
 
139
- context.lineTo(star.x, star.y - adjustedOuterRadius)
146
+ // Close the path by returning to the starting outer point
147
+ // This fixes the gap issue by making sure the first outer point is exactly the same
148
+ x = star.x + Math.cos(startAngle) * adjustedOuterRadius
149
+ y = star.y + Math.sin(startAngle) * adjustedOuterRadius
150
+ context.lineTo(x, y)
151
+
152
+ // Apply fill and stroke
140
153
  context.closePath()
141
154
  context.fill()
142
155
  context.stroke()