@cdc/map 4.25.7 → 4.25.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.claude/settings.local.json +30 -0
  2. package/CLAUDE.local.md +0 -0
  3. package/dist/cdcmap.js +54785 -53159
  4. package/examples/private/c.json +290 -0
  5. package/examples/private/canvas-city-hover.json +787 -0
  6. package/examples/private/d.json +345 -0
  7. package/examples/private/filter-map.json +909 -0
  8. package/examples/private/g.json +1 -0
  9. package/examples/private/h.json +105911 -0
  10. package/examples/private/measles-data.json +378 -0
  11. package/examples/private/measles.json +211 -0
  12. package/examples/private/north-dakota.json +1132 -0
  13. package/examples/private/rsv-data.json +532 -0
  14. package/examples/private/state-with-pattern.json +883 -0
  15. package/examples/private/test.json +222 -640
  16. package/index.html +1 -1
  17. package/package.json +26 -5
  18. package/src/CdcMap.tsx +28 -8
  19. package/src/CdcMapComponent.tsx +230 -306
  20. package/src/_stories/CdcMap.Filters.stories.tsx +2 -2
  21. package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +3 -3
  22. package/src/_stories/CdcMap.Legend.stories.tsx +7 -4
  23. package/src/_stories/CdcMap.Patterns.stories.tsx +2 -2
  24. package/src/_stories/CdcMap.Table.stories.tsx +2 -2
  25. package/src/_stories/CdcMap.stories.tsx +18 -11
  26. package/src/_stories/GoogleMap.stories.tsx +2 -2
  27. package/src/_stories/UsaMap.NoData.stories.tsx +2 -2
  28. package/src/_stories/_mock/equal-number.json +1109 -0
  29. package/src/_stories/_mock/multi-state.json +21389 -0
  30. package/src/_stories/_mock/us-bubble-cities.json +306 -0
  31. package/src/components/BubbleList.tsx +16 -12
  32. package/src/components/CityList.tsx +88 -110
  33. package/src/components/DataTable.tsx +44 -12
  34. package/src/components/EditorPanel/components/EditorPanel.tsx +201 -203
  35. package/src/components/EditorPanel/components/HexShapeSettings.tsx +3 -2
  36. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +7 -5
  37. package/src/components/Geo.tsx +2 -0
  38. package/src/components/Legend/components/Legend.tsx +117 -93
  39. package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +10 -7
  40. package/src/components/MapContainer.tsx +52 -0
  41. package/src/components/MapControls.tsx +44 -0
  42. package/src/components/Modal.tsx +2 -8
  43. package/src/components/NavigationMenu.tsx +13 -1
  44. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +24 -7
  45. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +21 -15
  46. package/src/components/UsaMap/components/TerritoriesSection.tsx +2 -2
  47. package/src/components/UsaMap/components/UsaMap.County.tsx +112 -33
  48. package/src/components/UsaMap/components/UsaMap.Region.tsx +23 -5
  49. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +38 -26
  50. package/src/components/UsaMap/components/UsaMap.State.tsx +28 -10
  51. package/src/components/UsaMap/helpers/map.ts +16 -8
  52. package/src/components/WorldMap/WorldMap.tsx +116 -11
  53. package/src/components/ZoomControls.tsx +6 -9
  54. package/src/context/LegendMemoContext.tsx +30 -0
  55. package/src/context.ts +1 -39
  56. package/src/data/initial-state.js +143 -128
  57. package/src/data/supported-geos.js +202 -4
  58. package/src/helpers/addUIDs.ts +8 -8
  59. package/src/helpers/applyColorToLegend.ts +122 -45
  60. package/src/helpers/applyLegendToRow.ts +15 -13
  61. package/src/helpers/componentHelpers.ts +8 -0
  62. package/src/helpers/constants.ts +12 -0
  63. package/src/helpers/dataTableHelpers.ts +6 -0
  64. package/src/helpers/displayGeoName.ts +12 -7
  65. package/src/helpers/formatLegendLocation.ts +1 -3
  66. package/src/helpers/generateRuntimeLegend.ts +192 -340
  67. package/src/helpers/generateRuntimeLegendHash.ts +4 -2
  68. package/src/helpers/getColumnNames.ts +1 -1
  69. package/src/helpers/getPatternForRow.ts +36 -0
  70. package/src/helpers/getStatesPicked.ts +14 -0
  71. package/src/helpers/handleMapAriaLabels.ts +2 -2
  72. package/src/helpers/index.ts +11 -3
  73. package/src/helpers/isLegendItemDisabled.ts +16 -0
  74. package/src/helpers/mapObserverHelpers.ts +40 -0
  75. package/src/helpers/resetLegendToggles.ts +3 -2
  76. package/src/helpers/toggleLegendActive.ts +6 -11
  77. package/src/helpers/urlDataHelpers.ts +70 -0
  78. package/src/hooks/useGeoClickHandler.ts +35 -1
  79. package/src/hooks/useLegendMemo.ts +17 -0
  80. package/src/hooks/useMapLayers.tsx +5 -4
  81. package/src/hooks/useStateZoom.tsx +137 -88
  82. package/src/hooks/useTooltip.ts +1 -2
  83. package/src/index.jsx +6 -3
  84. package/src/scss/main.scss +23 -12
  85. package/src/store/map.actions.ts +2 -2
  86. package/src/store/map.reducer.ts +21 -10
  87. package/src/test/CdcMap.test.jsx +11 -0
  88. package/src/types/MapConfig.ts +25 -17
  89. package/src/types/MapContext.ts +2 -8
  90. package/src/types/runtimeLegend.ts +12 -10
  91. package/vite.config.js +2 -7
  92. package/vitest.config.ts +16 -0
  93. package/src/_stories/_mock/floating-point.json +0 -427
  94. package/src/coreStyles_map.scss +0 -3
  95. package/src/helpers/colorDistributions.ts +0 -12
  96. package/src/helpers/generateColorsArray.ts +0 -14
  97. package/src/helpers/getStatePicked.ts +0 -8
  98. package/src/helpers/tests/generateColorsArray.test.ts +0 -18
  99. package/src/helpers/tests/generateRuntimeLegendHash.test.ts +0 -11
@@ -0,0 +1,306 @@
1
+ {
2
+ "annotations": [],
3
+ "general": {
4
+ "title": "US Cities Bubble Map - CityList Test",
5
+ "subtext": "This bubble map uses CityList component to render bubble sizes based on data values",
6
+ "type": "bubble",
7
+ "geoType": "us",
8
+ "headerColor": "theme-green",
9
+ "showSidebar": true,
10
+ "showTitle": true,
11
+ "showDownloadButton": true,
12
+ "expandDataTable": false,
13
+ "backgroundColor": "#ffffff",
14
+ "geoBorderColor": "darkGray",
15
+ "territoriesLabel": "Territories",
16
+ "language": "en",
17
+ "hasRegions": false,
18
+ "showDownloadMediaButton": false,
19
+ "displayAsHex": false,
20
+ "displayStateLabels": false,
21
+ "fullBorder": false,
22
+ "palette": {
23
+ "isReversed": false
24
+ },
25
+ "allowMapZoom": true,
26
+ "hideGeoColumnInTooltip": false,
27
+ "hidePrimaryColumnInTooltip": false,
28
+ "territoriesAlwaysShow": false,
29
+ "geoLabelOverride": "",
30
+ "noDataFoundMessage": "No data found",
31
+ "convertFipsCodes": false
32
+ },
33
+ "type": "map",
34
+ "color": "orangered",
35
+ "columns": {
36
+ "geo": {
37
+ "name": "city",
38
+ "label": "City",
39
+ "tooltip": true,
40
+ "dataTable": true
41
+ },
42
+ "primary": {
43
+ "dataTable": true,
44
+ "tooltip": true,
45
+ "prefix": "",
46
+ "suffix": " cases",
47
+ "name": "covid_cases",
48
+ "label": "COVID-19 Cases"
49
+ },
50
+ "latitude": {
51
+ "name": "latitude",
52
+ "label": "Latitude"
53
+ },
54
+ "longitude": {
55
+ "name": "longitude",
56
+ "label": "Longitude"
57
+ },
58
+ "navigate": {
59
+ "name": ""
60
+ }
61
+ },
62
+ "legend": {
63
+ "descriptions": {},
64
+ "specialClasses": [],
65
+ "unified": false,
66
+ "singleColumn": true,
67
+ "dynamicDescription": false,
68
+ "type": "equalinterval",
69
+ "numberOfItems": 5,
70
+ "position": "side",
71
+ "title": "COVID-19 Cases",
72
+ "showTitle": true,
73
+ "reversedOrder": false,
74
+ "singleColumnLegend": false,
75
+ "hideBorder": false
76
+ },
77
+ "filters": [],
78
+ "table": {
79
+ "label": "Data Table",
80
+ "expanded": false,
81
+ "limitHeight": false,
82
+ "height": "",
83
+ "caption": "",
84
+ "showDownloadUrl": false,
85
+ "showDataTableLink": true,
86
+ "showFullGeoNameInCSV": false,
87
+ "forceDisplay": true,
88
+ "download": true,
89
+ "indexLabel": "",
90
+ "wrapColumns": false,
91
+ "showDownloadLinkBelow": true
92
+ },
93
+ "tooltips": {
94
+ "appearanceType": "hover",
95
+ "linkLabel": "Learn More",
96
+ "capitalizeLabels": true,
97
+ "opacity": 90
98
+ },
99
+ "runtime": {
100
+ "editorErrorMessage": []
101
+ },
102
+ "visual": {
103
+ "minBubbleSize": 5,
104
+ "maxBubbleSize": 40,
105
+ "extraBubbleBorder": true,
106
+ "cityStyle": "circle",
107
+ "geoCodeCircleSize": 12,
108
+ "showBubbleZeros": true,
109
+ "cityStyleLabel": "City Bubbles",
110
+ "additionalCityStyles": []
111
+ },
112
+ "mapPosition": {
113
+ "coordinates": [0, 39],
114
+ "zoom": 1
115
+ },
116
+ "map": {
117
+ "layers": [],
118
+ "patterns": []
119
+ },
120
+ "hexMap": {
121
+ "type": "",
122
+ "shapeGroups": []
123
+ },
124
+ "data": [
125
+ {
126
+ "city": "New York",
127
+ "latitude": 40.7128,
128
+ "longitude": -74.0060,
129
+ "covid_cases": 2845
130
+ },
131
+ {
132
+ "city": "Los Angeles",
133
+ "latitude": 34.0522,
134
+ "longitude": -118.2437,
135
+ "covid_cases": 2234
136
+ },
137
+ {
138
+ "city": "Chicago",
139
+ "latitude": 41.8781,
140
+ "longitude": -87.6298,
141
+ "covid_cases": 1567
142
+ },
143
+ {
144
+ "city": "Houston",
145
+ "latitude": 29.7604,
146
+ "longitude": -95.3698,
147
+ "covid_cases": 1890
148
+ },
149
+ {
150
+ "city": "Phoenix",
151
+ "latitude": 33.4484,
152
+ "longitude": -112.0740,
153
+ "covid_cases": 1234
154
+ },
155
+ {
156
+ "city": "Philadelphia",
157
+ "latitude": 39.9526,
158
+ "longitude": -75.1652,
159
+ "covid_cases": 1678
160
+ },
161
+ {
162
+ "city": "San Antonio",
163
+ "latitude": 29.4241,
164
+ "longitude": -98.4936,
165
+ "covid_cases": 987
166
+ },
167
+ {
168
+ "city": "San Diego",
169
+ "latitude": 32.7157,
170
+ "longitude": -117.1611,
171
+ "covid_cases": 1456
172
+ },
173
+ {
174
+ "city": "Dallas",
175
+ "latitude": 32.7767,
176
+ "longitude": -96.7970,
177
+ "covid_cases": 1789
178
+ },
179
+ {
180
+ "city": "San Jose",
181
+ "latitude": 37.3382,
182
+ "longitude": -121.8863,
183
+ "covid_cases": 934
184
+ },
185
+ {
186
+ "city": "Austin",
187
+ "latitude": 30.2672,
188
+ "longitude": -97.7431,
189
+ "covid_cases": 876
190
+ },
191
+ {
192
+ "city": "Jacksonville",
193
+ "latitude": 30.3322,
194
+ "longitude": -81.6557,
195
+ "covid_cases": 743
196
+ },
197
+ {
198
+ "city": "Fort Worth",
199
+ "latitude": 32.7555,
200
+ "longitude": -97.3308,
201
+ "covid_cases": 654
202
+ },
203
+ {
204
+ "city": "Columbus",
205
+ "latitude": 39.9612,
206
+ "longitude": -82.9988,
207
+ "covid_cases": 567
208
+ },
209
+ {
210
+ "city": "Charlotte",
211
+ "latitude": 35.2271,
212
+ "longitude": -80.8431,
213
+ "covid_cases": 789
214
+ },
215
+ {
216
+ "city": "San Francisco",
217
+ "latitude": 37.7749,
218
+ "longitude": -122.4194,
219
+ "covid_cases": 1123
220
+ },
221
+ {
222
+ "city": "Indianapolis",
223
+ "latitude": 39.7684,
224
+ "longitude": -86.1581,
225
+ "covid_cases": 445
226
+ },
227
+ {
228
+ "city": "Seattle",
229
+ "latitude": 47.6062,
230
+ "longitude": -122.3321,
231
+ "covid_cases": 823
232
+ },
233
+ {
234
+ "city": "Denver",
235
+ "latitude": 39.7392,
236
+ "longitude": -104.9903,
237
+ "covid_cases": 634
238
+ },
239
+ {
240
+ "city": "Boston",
241
+ "latitude": 42.3601,
242
+ "longitude": -71.0589,
243
+ "covid_cases": 976
244
+ },
245
+ {
246
+ "city": "El Paso",
247
+ "latitude": 31.7619,
248
+ "longitude": -106.4850,
249
+ "covid_cases": 312
250
+ },
251
+ {
252
+ "city": "Nashville",
253
+ "latitude": 36.1627,
254
+ "longitude": -86.7816,
255
+ "covid_cases": 456
256
+ },
257
+ {
258
+ "city": "Detroit",
259
+ "latitude": 42.3314,
260
+ "longitude": -83.0458,
261
+ "covid_cases": 578
262
+ },
263
+ {
264
+ "city": "Oklahoma City",
265
+ "latitude": 35.4676,
266
+ "longitude": -97.5164,
267
+ "covid_cases": 289
268
+ },
269
+ {
270
+ "city": "Portland",
271
+ "latitude": 45.5152,
272
+ "longitude": -122.6784,
273
+ "covid_cases": 387
274
+ },
275
+ {
276
+ "city": "Las Vegas",
277
+ "latitude": 36.1699,
278
+ "longitude": -115.1398,
279
+ "covid_cases": 534
280
+ },
281
+ {
282
+ "city": "Memphis",
283
+ "latitude": 35.1495,
284
+ "longitude": -90.0490,
285
+ "covid_cases": 267
286
+ },
287
+ {
288
+ "city": "Louisville",
289
+ "latitude": 38.2527,
290
+ "longitude": -85.7585,
291
+ "covid_cases": 189
292
+ },
293
+ {
294
+ "city": "Baltimore",
295
+ "latitude": 39.2904,
296
+ "longitude": -76.6122,
297
+ "covid_cases": 445
298
+ },
299
+ {
300
+ "city": "Milwaukee",
301
+ "latitude": 43.0389,
302
+ "longitude": -87.9065,
303
+ "covid_cases": 334
304
+ }
305
+ ]
306
+ }
@@ -3,6 +3,7 @@ import { scaleLinear } from 'd3-scale'
3
3
  import { countryCoordinates } from '../data/country-coordinates'
4
4
  import stateCoordinates from '../data/state-coordinates'
5
5
  import ConfigContext, { MapDispatchContext } from '../context'
6
+ import { useLegendMemoContext } from '../context/LegendMemoContext'
6
7
  import { type Coordinate, DataRow } from '../types/MapConfig'
7
8
  import useApplyTooltipsToGeo from '../hooks/useApplyTooltipsToGeo'
8
9
  import { applyLegendToRow } from '../helpers/applyLegendToRow'
@@ -17,8 +18,8 @@ type BubbleListProps = {
17
18
  }
18
19
 
19
20
  export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
20
- const { config, tooltipId, legendMemo, legendSpecialClassLastMemo, setRuntimeData, runtimeData, runtimeLegend } =
21
- useContext<MapContext>(ConfigContext)
21
+ const { config, tooltipId, runtimeData, runtimeLegend } = useContext<MapContext>(ConfigContext)
22
+ const { legendMemo, legendSpecialClassLastMemo } = useLegendMemoContext()
22
23
  const { columns, data, general, visual } = config
23
24
  const { geoType, allowMapZoom } = general
24
25
  const { minBubbleSize, maxBubbleSize, showBubbleZeros, extraBubbleBorder } = visual
@@ -65,7 +66,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
65
66
  dispatch({ type: 'SET_POSITION', payload: { coordinates: reversedCoordinates, zoom: 3 } })
66
67
 
67
68
  // ...and show the data for the clicked country
68
- setRuntimeData(_tempRuntimeData)
69
+ dispatch({ type: 'SET_RUNTIME_DATA', payload: _tempRuntimeData })
69
70
  }
70
71
 
71
72
  const sortedRuntimeData: DataRow = Object.values(runtimeData).sort((a, b) =>
@@ -77,7 +78,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
77
78
  if (geoType === 'world') {
78
79
  return (
79
80
  sortedRuntimeData &&
80
- sortedRuntimeData.map(country => {
81
+ sortedRuntimeData.map((country, index) => {
81
82
  let coordinates = countryCoordinates[country.uid]
82
83
 
83
84
  if (!coordinates) return true
@@ -99,10 +100,9 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
99
100
  if (!projection(coordinates)) return true
100
101
 
101
102
  const circle = (
102
- <>
103
+ <React.Fragment key={`circle-fragment-${countryName.replace(' ', '')}`}>
103
104
  <circle
104
105
  tabIndex={-1}
105
- key={`circle-${countryName.replace(' ', '')}`}
106
106
  className={`bubble country--${countryName}`}
107
107
  cx={Number(projection(coordinates[1], coordinates[0])[0]) || 0}
108
108
  cy={Number(projection(coordinates[1], coordinates[0])[1]) || 0}
@@ -111,6 +111,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
111
111
  stroke={legendColors[0]}
112
112
  strokeWidth={1.25}
113
113
  fillOpacity={0.4}
114
+ onMouseEnter={() => {}}
114
115
  onPointerDown={e => {
115
116
  pointerX = e.clientX
116
117
  pointerY = e.clientY
@@ -138,7 +139,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
138
139
  {extraBubbleBorder && (
139
140
  <circle
140
141
  tabIndex={-1}
141
- key={`circle-${countryName.replace(' ', '')}`}
142
+ key={`circle-border-${countryName.replace(' ', '')}`}
142
143
  className='bubble'
143
144
  cx={Number(projection(coordinates[1], coordinates[0])[0]) || 0}
144
145
  cy={Number(projection(coordinates[1], coordinates[0])[1]) || 0}
@@ -146,6 +147,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
146
147
  fill={'transparent'}
147
148
  stroke={'white'}
148
149
  strokeWidth={0.5}
150
+ onMouseEnter={() => {}}
149
151
  onPointerDown={e => {
150
152
  pointerX = e.clientX
151
153
  pointerY = e.clientY
@@ -170,11 +172,11 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
170
172
  data-tooltip-html={toolTip}
171
173
  />
172
174
  )}
173
- </>
175
+ </React.Fragment>
174
176
  )
175
177
 
176
178
  return (
177
- <g key={`group-${countryName.replace(' ', '')}`} tabIndex={-1}>
179
+ <g key={`group-${index}-${countryName.replace(' ', '')}`} tabIndex={-1}>
178
180
  {circle}
179
181
  </g>
180
182
  )
@@ -185,7 +187,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
185
187
  if (geoType === 'us') {
186
188
  return (
187
189
  sortedRuntimeData &&
188
- sortedRuntimeData.map(item => {
190
+ sortedRuntimeData.map((item, index) => {
189
191
  let stateData = stateCoordinates[item.uid]
190
192
  if (Number(size(item[primaryColumnName])) === 0) return
191
193
 
@@ -223,6 +225,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
223
225
  stroke={legendColors[0]}
224
226
  strokeWidth={1.25}
225
227
  fillOpacity={0.4}
228
+ onMouseEnter={() => {}}
226
229
  onPointerDown={e => {
227
230
  pointerX = e.clientX
228
231
  pointerY = e.clientY
@@ -249,7 +252,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
249
252
  {extraBubbleBorder && (
250
253
  <circle
251
254
  tabIndex={-1}
252
- key={`circle-${stateName.replace(' ', '')}`}
255
+ key={`circle-border-${stateName.replace(' ', '')}`}
253
256
  className='bubble'
254
257
  cx={projection(coordinates)[0] || 0}
255
258
  cy={projection(coordinates)[1] || 0}
@@ -258,6 +261,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
258
261
  stroke={'white'}
259
262
  strokeWidth={0.5}
260
263
  fillOpacity={0.4}
264
+ onMouseEnter={() => {}}
261
265
  onPointerDown={e => {
262
266
  pointerX = e.clientX
263
267
  pointerY = e.clientY
@@ -285,7 +289,7 @@ export const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
285
289
  </>
286
290
  )
287
291
 
288
- return <g key={`group-${stateName.replace(' ', '')}`}>{circle}</g>
292
+ return <g key={`group-${index}-${stateName.replace(' ', '')}`}>{circle}</g>
289
293
  })
290
294
  )
291
295
  }