@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,7 +1,10 @@
1
1
  import React, { useContext } from 'react'
2
2
  import ConfigContext from '../../../../context'
3
3
  import { MapContext } from '../../../../types/MapContext'
4
- import { getGeoFillColor } from '../../../../helpers/colors'
4
+ import { getGeoFillColor, displayGeoName } from '../../../../helpers'
5
+ import useApplyTooltipsToGeo from '../../../../hooks/useApplyTooltipsToGeo'
6
+ import { applyLegendToRow } from '../../../../helpers/applyLegendToRow'
7
+ import useGeoClickHandler, { geoClickHandler } from '././../../../../hooks/useGeoClickHandler'
5
8
 
6
9
  interface CountyOutputProps {
7
10
  counties: any[]
@@ -12,10 +15,11 @@ interface CountyOutputProps {
12
15
  }
13
16
 
14
17
  const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoStrokeColor, tooltipId }) => {
15
- const { applyTooltipsToGeo, applyLegendToRow, displayGeoName, state, data, geoClickHandler } =
16
- useContext<MapContext>(ConfigContext)
18
+ const { config, data, legendMemo, legendSpecialClassLastMemo, runtimeLegend } = useContext<MapContext>(ConfigContext)
19
+ const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
20
+ const geoFillColor = getGeoFillColor(config)
21
+ const { geoClickHandler } = useGeoClickHandler()
17
22
 
18
- const geoFillColor = getGeoFillColor(state)
19
23
  return (
20
24
  <>
21
25
  {counties.map(county => {
@@ -31,7 +35,7 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
31
35
 
32
36
  // Once we receive data for this geographic item, setup variables.
33
37
  if (geoData !== undefined) {
34
- legendColors = applyLegendToRow(geoData)
38
+ legendColors = applyLegendToRow(geoData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
35
39
  }
36
40
 
37
41
  const geoDisplayName = displayGeoName(geoKey)
@@ -55,8 +59,8 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
55
59
 
56
60
  // When to add pointer cursor
57
61
  if (
58
- (state.columns.navigate && geoData[state.columns.navigate.name]) ||
59
- state.tooltips.appearanceType === 'hover'
62
+ (config.columns.navigate && geoData[config.columns.navigate.name]) ||
63
+ config.tooltips.appearanceType === 'hover'
60
64
  ) {
61
65
  styles.cursor = 'pointer'
62
66
  }
@@ -65,7 +69,7 @@ const CountyOutput: React.FC<CountyOutputProps> = ({ path, counties, scale, geoS
65
69
  <g
66
70
  key={`key--${county.id}`}
67
71
  className={`county county--${geoDisplayName.split(' ').join('')} county--${
68
- geoData[state.columns.geo.name]
72
+ geoData[config.columns.geo.name]
69
73
  }`}
70
74
  style={styles}
71
75
  onClick={() => geoClickHandler(geoDisplayName, geoData)}
@@ -10,14 +10,14 @@ type StateOutputProps = {
10
10
  }
11
11
 
12
12
  const StateOutput: React.FC<StateOutputProps> = ({ topoData, path, scale, stateToShow }: StateOutputProps) => {
13
- const { state } = useContext(ConfigContext)
13
+ const { config } = useContext(ConfigContext)
14
14
  if (!topoData?.objects?.states) return null
15
15
  let geo = topoData.objects.states.geometries.filter(s => {
16
- return s.properties.name === state.general.statePicked.stateName
16
+ return s.properties.name === config.general.statePicked.stateName
17
17
  })
18
18
 
19
- const geoStrokeColor = getGeoStrokeColor(state)
20
- const geoFillColor = getGeoFillColor(state)
19
+ const geoStrokeColor = getGeoStrokeColor(config)
20
+ const geoFillColor = getGeoFillColor(config)
21
21
 
22
22
  let stateLines = path(mesh(topoData, geo[0]))
23
23
 
@@ -1,4 +1,7 @@
1
- import React from 'react'
1
+ import React, { useContext } from 'react'
2
+
3
+ import ConfigContext from '../../../context'
4
+ import { isMobileTerritoryViewport } from '@cdc/core/helpers/viewports'
2
5
 
3
6
  type TerritoriesSectionProps = {
4
7
  territories: JSX.Element[]
@@ -9,6 +12,8 @@ type TerritoriesSectionProps = {
9
12
  }
10
13
 
11
14
  const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, logo, config, territoriesData }) => {
15
+ const { currentViewport } = useContext<MapContext>(ConfigContext)
16
+
12
17
  // filter territioriesData into the two groups below
13
18
  const freelyAssociatedKeys = territoriesData.filter(territory => {
14
19
  return ['US-FM', 'US-MH', 'US-PW'].includes(territory)
@@ -33,6 +38,10 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
33
38
  return a.props.label.localeCompare(b.props.label)
34
39
  })
35
40
 
41
+ const isMobileViewport = isMobileTerritoryViewport(currentViewport)
42
+ const SVG_GAP = 9
43
+ const SVG_WIDTH = isMobileViewport ? 30 : 45
44
+
36
45
  return (
37
46
  territoriesData.length > 0 && (
38
47
  <>
@@ -43,18 +52,32 @@ const TerritoriesSection: React.FC<TerritoriesSectionProps> = ({ territories, lo
43
52
  <img src={logo} alt='' className='map-logo' style={{ maxWidth: '50px' }} />
44
53
  )}
45
54
  </div>
46
- <div>
55
+ <div className='d-flex flex-wrap' style={{ columnGap: '1.5rem' }}>
47
56
  {(usTerritories.length > 0 || config.general.territoriesAlwaysShow) && (
48
- <>
49
- <h5 className='territories-label'>U.S. Territories</h5>
50
- <span className='mt-1 mb-2 d-flex flex-wrap territories'>{usTerritories}</span>
51
- </>
57
+ <div>
58
+ <h5 className='territories-label'>U.S. territories</h5>
59
+ <span
60
+ className={`mt-2 ${isMobileViewport ? 'mb-3' : 'mb-4'} d-flex territories`}
61
+ style={{ minWidth: `${usTerritories.length * SVG_WIDTH + (usTerritories.length - 1) * SVG_GAP}px` }}
62
+ >
63
+ {usTerritories}
64
+ </span>
65
+ </div>
52
66
  )}
53
67
  {(freelyAssociatedStates.length > 0 || config.general.territoriesAlwaysShow) && (
54
- <>
55
- <h5 className='territories-label'>Freely Associated States</h5>
56
- <span className='mt-1 mb-2 d-flex flex-wrap territories'>{freelyAssociatedStates}</span>
57
- </>
68
+ <div>
69
+ <h5 className='territories-label'>Freely associated states</h5>
70
+ <span
71
+ className={`mt-2 ${isMobileViewport ? 'mb-3' : 'mb-4'} d-flex territories`}
72
+ style={{
73
+ minWidth: `${
74
+ freelyAssociatedStates.length * SVG_WIDTH + (freelyAssociatedStates.length - 1) * SVG_GAP
75
+ }px`
76
+ }}
77
+ >
78
+ {freelyAssociatedStates}
79
+ </span>
80
+ </div>
58
81
  )}
59
82
  </div>
60
83
  </div>
@@ -5,6 +5,7 @@ import { MapContext } from './../../../../types/MapContext'
5
5
  import HexIcon from '../HexIcon'
6
6
  import { Text } from '@visx/text'
7
7
  import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
8
+ import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
8
9
 
9
10
  const offsets = {
10
11
  'US-VT': [50, -8],
@@ -37,16 +38,16 @@ const TerritoryHexagon = ({
37
38
  handleShapeClick,
38
39
  label,
39
40
  stroke,
41
+ strokeColor,
40
42
  strokeWidth,
41
43
  territory,
42
44
  territoryData,
43
- text,
44
45
  textColor,
45
46
  ...props
46
47
  }) => {
47
- const { state } = useContext<MapContext>(ConfigContext)
48
+ const { config } = useContext<MapContext>(ConfigContext)
48
49
 
49
- const isHex = state.general.displayAsHex
50
+ const isHex = config.general.displayAsHex
50
51
 
51
52
  // Labels
52
53
  const hexagonLabel = (geo, bgColor = '#FFFFFF', projection) => {
@@ -61,7 +62,7 @@ const TerritoryHexagon = ({
61
62
 
62
63
  return (
63
64
  <>
64
- {state.hexMap.shapeGroups.map((group, groupIndex) => {
65
+ {config.hexMap.shapeGroups.map((group, groupIndex) => {
65
66
  return group.items.map((item, itemIndex) => {
66
67
  if (!geoData) return
67
68
  switch (item.operator) {
@@ -116,7 +117,7 @@ const TerritoryHexagon = ({
116
117
  }
117
118
 
118
119
  let x = 0,
119
- y = state.hexMap.type === 'shapes' ? -10 : 5
120
+ y = config.hexMap.type === 'shapes' ? -10 : 5
120
121
 
121
122
  // used to nudge/move some of the labels for better readability
122
123
  if (nudges[abbr] && false === isHex) {
@@ -125,14 +126,15 @@ const TerritoryHexagon = ({
125
126
  }
126
127
 
127
128
  if (undefined === offsets[abbr] || isHex) {
128
- let y = state.hexMap.type === 'shapes' ? '30%' : '50%'
129
+ let y = config.hexMap.type === 'shapes' ? '30%' : '50%'
129
130
  return (
130
131
  <>
131
132
  <Text
132
133
  fontSize={14}
133
134
  x={'50%'}
134
135
  y={y}
135
- style={{ fill: 'currentColor', stroke: 'initial', fontWeight: 400, opacity: 1, fillOpacity: 1 }}
136
+ style={{ fill: 'currentColor', stroke: strokeColor, fontWeight: 900, opacity: 1, fillOpacity: 1 }}
137
+ paintOrder='stroke'
136
138
  textAnchor='middle'
137
139
  verticalAnchor='middle'
138
140
  onClick={handleShapeClick}
@@ -141,7 +143,7 @@ const TerritoryHexagon = ({
141
143
  >
142
144
  {abbr.substring(3)}
143
145
  </Text>
144
- {state.general.displayAsHex && state.hexMap.type === 'shapes' && getArrowDirection(territoryData, geo, true)}
146
+ {config.general.displayAsHex && config.hexMap.type === 'shapes' && getArrowDirection(territoryData, geo, true)}
145
147
  </>
146
148
  )
147
149
  }
@@ -162,7 +164,7 @@ const TerritoryHexagon = ({
162
164
  x={4}
163
165
  strokeWidth='0'
164
166
  fontSize={13}
165
- style={{ fill: '#202020' }}
167
+ style={{ fill: APP_FONT_COLOR }}
166
168
  alignmentBaseline='middle'
167
169
  transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}
168
170
  onClick={handleShapeClick}
@@ -183,7 +185,7 @@ const TerritoryHexagon = ({
183
185
  strokeWidth={strokeWidth}
184
186
  points='22 0 44 12.702 44 38.105 22 50.807 0 38.105 0 12.702'
185
187
  />
186
- {state.general.displayAsHex && hexagonLabel(territoryData, stroke, false)}
188
+ {config.general.displayAsHex && hexagonLabel(territoryData, stroke, false)}
187
189
  </g>
188
190
  </svg>
189
191
  )
@@ -13,14 +13,14 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
13
13
  hasPattern,
14
14
  label,
15
15
  stroke,
16
+ strokeColor,
16
17
  strokeWidth,
17
18
  territory,
18
- text,
19
19
  textColor,
20
20
  backgroundColor,
21
21
  ...props
22
22
  }) => {
23
- const { state } = useContext<MapContext>(ConfigContext)
23
+ const { config } = useContext<MapContext>(ConfigContext)
24
24
  const { territoryData, ...otherProps } = props
25
25
  const rectanglePath =
26
26
  'M42,0.5 C42.8284271,0.5 43.5,1.17157288 43.5,2 L43.5,2 L43.5,26 C43.5,26.8284271 42.8284271,27.5 42,27.5 L42,27.5 L3,27.5 C2.17157288,27.5 1.5,26.8284271 1.5,26 L1.5,26 L1.5,2 C1.5,1.17157288 2.17157288,0.5 3,0.5 L3,0.5 Z'
@@ -41,8 +41,8 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
41
41
  dominantBaseline='middle'
42
42
  x='50%'
43
43
  y='54%'
44
- fill={text}
45
- style={{ stroke: 'none' }}
44
+ fill={textColor}
45
+ stroke={strokeColor}
46
46
  className='territory-text'
47
47
  paintOrder='stroke'
48
48
  onClick={handleShapeClick}
@@ -52,7 +52,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
52
52
  {label}
53
53
  </text>
54
54
 
55
- {state.map.patterns.map((patternData, patternIndex) => {
55
+ {config.map.patterns.map((patternData, patternIndex) => {
56
56
  const patternColor = patternData.color || getContrastColor('#FFF', backgroundColor)
57
57
  const hasMatchingValues = patternData.dataValue === territoryData?.[patternData.dataKey]
58
58
 
@@ -67,6 +67,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
67
67
  height={patternSizes[patternData?.size] ?? 10}
68
68
  width={patternSizes[patternData?.size] ?? 10}
69
69
  fill={patternColor}
70
+ strokeWidth={0.25}
70
71
  complement
71
72
  />
72
73
  )}
@@ -76,6 +77,8 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
76
77
  height={patternSizes[patternData?.size] ?? 10}
77
78
  width={patternSizes[patternData?.size] ?? 10}
78
79
  fill={patternColor}
80
+ stroke={patternColor}
81
+ radius={0.5}
79
82
  complement
80
83
  />
81
84
  )}
@@ -85,7 +88,7 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
85
88
  height={patternSizes[patternData?.size] ?? 6}
86
89
  width={patternSizes[patternData?.size] ?? 6}
87
90
  stroke={patternColor}
88
- strokeWidth={1}
91
+ strokeWidth={0.75}
89
92
  orientation={['diagonalRightToLeft']}
90
93
  />
91
94
  )}
@@ -94,7 +97,6 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
94
97
  strokeWidth={strokeWidth}
95
98
  d={rectanglePath}
96
99
  fill={`url(#territory-${territory}-${patternData?.dataKey}--${patternIndex})`}
97
- color={patternData ? 'white' : textColor}
98
100
  className={[
99
101
  `territory-pattern-${patternData?.dataKey}`,
100
102
  `territory-pattern-${patternData?.dataKey}--${patternData.dataValue}`
@@ -105,14 +107,10 @@ const TerritoryRectangle: React.FC<TerritoryShape> = ({
105
107
  dominantBaseline='middle'
106
108
  x='50%'
107
109
  y='54%'
108
- fill={text}
109
- style={{
110
- fill: patternData ? 'white' : 'black',
111
- stroke: patternData ? 'black' : textColor,
112
- strokeWidth: patternData ? 6 : 0
113
- }}
110
+ fill={textColor}
111
+ stroke={strokeColor}
114
112
  className='territory-text'
115
- paint-order='stroke'
113
+ paintOrder='stroke'
116
114
  onClick={handleShapeClick}
117
115
  data-tooltip-id={dataTooltipId}
118
116
  data-tooltip-html={dataTooltipHtml}
@@ -1,13 +1,14 @@
1
1
  export type TerritoryShape = {
2
2
  handleShapeClick: () => void
3
+ backgroundColor: string
3
4
  dataTooltipHtml: string
4
5
  dataTooltipId: string
5
6
  hasPattern: boolean
6
7
  label: string
7
8
  stroke: string
9
+ strokeColor: string
8
10
  strokeWidth: number
9
11
  territory: string
10
12
  territoryData: object
11
- text: string
12
13
  textColor: string
13
14
  }