@cdc/map 4.22.10-alpha.1 → 4.22.11

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 (47) hide show
  1. package/dist/cdcmap.js +10 -10
  2. package/examples/private/atsdr.json +19 -29
  3. package/examples/private/atsdr_new.json +1 -1
  4. package/examples/private/bubble.json +282 -284
  5. package/examples/private/city-state.json +427 -427
  6. package/examples/private/city-state2.json +433 -433
  7. package/examples/private/cty-issue.json +42765 -42768
  8. package/examples/private/default-usa.json +2 -5
  9. package/examples/private/default-world-data.json +1443 -1443
  10. package/examples/private/default.json +965 -965
  11. package/examples/private/diff.json +226 -0
  12. package/examples/private/filters.json +1 -0
  13. package/examples/private/legend-issue.json +3271 -1
  14. package/examples/private/map-issue.json +166 -0
  15. package/examples/private/map-rounding-error.json +42756 -42759
  16. package/examples/private/mdx.json +209 -209
  17. package/examples/private/monkeypox.json +375 -375
  18. package/examples/private/regions.json +51 -51
  19. package/examples/private/wcmsrd-13881-data.json +2856 -2856
  20. package/examples/private/wcmsrd-13881.json +5818 -5822
  21. package/examples/private/wcmsrd-14492-data.json +291 -291
  22. package/examples/private/wcmsrd-14492.json +103 -113
  23. package/examples/private/wcmsrd-test.json +264 -267
  24. package/examples/private/world.json +1579 -1579
  25. package/examples/private/worldmap.json +1489 -1489
  26. package/package.json +3 -3
  27. package/src/CdcMap.js +231 -315
  28. package/src/components/BubbleList.js +199 -240
  29. package/src/components/CityList.js +50 -96
  30. package/src/components/CountyMap.js +511 -600
  31. package/src/components/DataTable.js +218 -253
  32. package/src/components/EditorPanel.js +2338 -2551
  33. package/src/components/Geo.js +4 -14
  34. package/src/components/Modal.js +13 -23
  35. package/src/components/NavigationMenu.js +43 -39
  36. package/src/components/Sidebar.js +83 -93
  37. package/src/components/SingleStateMap.js +95 -151
  38. package/src/components/UsaMap.js +165 -214
  39. package/src/components/UsaRegionMap.js +122 -160
  40. package/src/components/WorldMap.js +96 -179
  41. package/src/components/ZoomableGroup.js +6 -26
  42. package/src/data/initial-state.js +1 -0
  43. package/src/hooks/useActiveElement.js +13 -13
  44. package/src/hooks/useColorPalette.ts +66 -74
  45. package/src/hooks/useZoomPan.js +22 -23
  46. package/src/index.html +1 -2
  47. package/src/scss/sidebar.scss +22 -0
@@ -1,102 +1,96 @@
1
- import React, { useState, useEffect, memo } from 'react';
1
+ import React, { useState, useEffect, memo } from 'react'
2
2
  /** @jsx jsx */
3
3
  import { jsx } from '@emotion/react'
4
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
5
- import { geoCentroid } from "d3-geo";
6
- import { feature } from "topojson-client";
7
- import topoJSON from '../data/us-regions-topo-2.json';
8
- import { Mercator } from '@visx/geo';
9
- import chroma from 'chroma-js';
4
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
5
+ import { geoCentroid } from 'd3-geo'
6
+ import { feature } from 'topojson-client'
7
+ import topoJSON from '../data/us-regions-topo-2.json'
8
+ import { Mercator } from '@visx/geo'
9
+ import chroma from 'chroma-js'
10
10
 
11
11
  const { features: unitedStates } = feature(topoJSON, topoJSON.objects.regions)
12
12
 
13
- const Rect = ({label, text, stroke, strokeWidth, ...props}) => {
13
+ const Rect = ({ label, text, stroke, strokeWidth, ...props }) => {
14
14
  return (
15
- <svg viewBox="0 0 45 28">
16
- <g {...props} strokeLinejoin="round">
17
- <path stroke={stroke} strokeWidth={strokeWidth} d="M40,0.5 C41.2426407,0.5 42.3676407,1.00367966 43.1819805,1.81801948 C43.9963203,2.63235931 44.5,3.75735931 44.5,5 L44.5,5 L44.5,23 C44.5,24.2426407 43.9963203,25.3676407 43.1819805,26.1819805 C42.3676407,26.9963203 41.2426407,27.5 40,27.5 L40,27.5 L5,27.5 C3.75735931,27.5 2.63235931,26.9963203 1.81801948,26.1819805 C1.00367966,25.3676407 0.5,24.2426407 0.5,23 L0.5,23 L0.5,5 C0.5,3.75735931 1.00367966,2.63235931 1.81801948,1.81801948 C2.63235931,1.00367966 3.75735931,0.5 5,0.5 L5,0.5 Z" />
18
- <text textAnchor="middle" dominantBaseline="middle" x="50%" y="54%" fill={text}>{label}</text>
15
+ <svg viewBox='0 0 45 28'>
16
+ <g {...props} strokeLinejoin='round'>
17
+ <path
18
+ stroke={stroke}
19
+ strokeWidth={strokeWidth}
20
+ d='M40,0.5 C41.2426407,0.5 42.3676407,1.00367966 43.1819805,1.81801948 C43.9963203,2.63235931 44.5,3.75735931 44.5,5 L44.5,5 L44.5,23 C44.5,24.2426407 43.9963203,25.3676407 43.1819805,26.1819805 C42.3676407,26.9963203 41.2426407,27.5 40,27.5 L40,27.5 L5,27.5 C3.75735931,27.5 2.63235931,26.9963203 1.81801948,26.1819805 C1.00367966,25.3676407 0.5,24.2426407 0.5,23 L0.5,23 L0.5,5 C0.5,3.75735931 1.00367966,2.63235931 1.81801948,1.81801948 C2.63235931,1.00367966 3.75735931,0.5 5,0.5 L5,0.5 Z'
21
+ />
22
+ <text textAnchor='middle' dominantBaseline='middle' x='50%' y='54%' fill={text}>
23
+ {label}
24
+ </text>
19
25
  </g>
20
26
  </svg>
21
27
  )
22
28
  }
23
29
 
24
- const UsaRegionMap = (props) => {
25
- const {
26
- state,
27
- applyTooltipsToGeo,
28
- data,
29
- geoClickHandler,
30
- applyLegendToRow,
31
- displayGeoName,
32
- supportedTerritories,
33
- rebuildTooltips,
34
- titleCase,
35
- handleCircleClick,
36
- handleMapAriaLabels
37
- } = props;
30
+ const UsaRegionMap = props => {
31
+ const { state, applyTooltipsToGeo, data, geoClickHandler, applyLegendToRow, displayGeoName, supportedTerritories, rebuildTooltips, titleCase, handleCircleClick, handleMapAriaLabels } = props
38
32
 
39
33
  // "Choose State" options
40
34
  const [extent, setExtent] = useState(null)
41
35
  const [focusedStates, setFocusedStates] = useState(unitedStates)
42
- const [translate, setTranslate] = useState([455,200])
36
+ const [translate, setTranslate] = useState([455, 200])
43
37
 
44
38
  // When returning from another map we want to reset the state
45
39
  useEffect(() => {
46
- setTranslate( [455,250] )
47
- setExtent( null )
48
- }, [state.general.geoType]);
40
+ setTranslate([455, 250])
41
+ setExtent(null)
42
+ }, [state.general.geoType])
49
43
 
50
44
  const isHex = state.general.displayAsHex
51
45
 
52
- const [territoriesData, setTerritoriesData] = useState([]);
46
+ const [territoriesData, setTerritoriesData] = useState([])
53
47
 
54
- const territoriesKeys = Object.keys(supportedTerritories); // data will have already mapped abbreviated territories to their full names
48
+ const territoriesKeys = Object.keys(supportedTerritories) // data will have already mapped abbreviated territories to their full names
55
49
 
56
50
  useEffect(() => {
57
51
  // 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
58
- const territoriesList = territoriesKeys.filter(key => data[key]);
52
+ const territoriesList = territoriesKeys.filter(key => data[key])
59
53
 
60
- setTerritoriesData(territoriesList);
61
- }, [data]);
54
+ setTerritoriesData(territoriesList)
55
+ }, [data])
62
56
 
63
- useEffect(() => rebuildTooltips());
57
+ useEffect(() => rebuildTooltips())
64
58
 
65
59
  const geoStrokeColor = state.general.geoBorderColor === 'darkGray' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255,255,255,0.7)'
66
60
 
67
61
  const territories = territoriesData.map(territory => {
68
62
  const Shape = Rect
69
63
 
70
- const territoryData = data[territory];
64
+ const territoryData = data[territory]
71
65
 
72
- let toolTip;
66
+ let toolTip
73
67
 
74
68
  let styles = {
75
69
  fill: '#E6E6E6',
76
- color: '#202020',
77
- };
70
+ color: '#202020'
71
+ }
78
72
 
79
73
  const label = supportedTerritories[territory][1]
80
74
 
81
- if(!territoryData) return <Shape key={label} label={label} css={styles} text={styles.color} />
75
+ if (!territoryData) return <Shape key={label} label={label} css={styles} text={styles.color} />
82
76
 
83
- toolTip = applyTooltipsToGeo(displayGeoName(territory), territoryData);
77
+ toolTip = applyTooltipsToGeo(displayGeoName(territory), territoryData)
84
78
 
85
- const legendColors = applyLegendToRow(territoryData);
79
+ const legendColors = applyLegendToRow(territoryData)
86
80
 
87
- let textColor = '#FFF';
81
+ let textColor = '#FFF'
88
82
 
89
83
  if (legendColors) {
90
84
  // Use white text if the background is dark, and dark grey if it's light
91
85
  if (chroma.contrast(textColor, legendColors[0]) < 3.5) {
92
- textColor = '#202020';
86
+ textColor = '#202020'
93
87
  }
94
88
 
95
- let needsPointer = false;
89
+ let needsPointer = false
96
90
 
97
91
  // If we need to add a pointer cursor
98
92
  if ((state.columns.navigate && territoryData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
99
- needsPointer = true;
93
+ needsPointer = true
100
94
  }
101
95
 
102
96
  styles = {
@@ -104,58 +98,48 @@ const UsaRegionMap = (props) => {
104
98
  fill: legendColors[0],
105
99
  cursor: needsPointer ? 'pointer' : 'default',
106
100
  '&:hover': {
107
- fill: legendColors[1],
101
+ fill: legendColors[1]
108
102
  },
109
103
  '&:active': {
110
- fill: legendColors[2],
104
+ fill: legendColors[2]
111
105
  }
112
- };
113
-
114
- return (<Shape
115
- key={label}
116
- label={label}
117
- css={styles}
118
- text={styles.color}
119
- data-tip={toolTip}
120
- data-for="tooltip"
121
- stroke={geoStrokeColor}
122
- strokeWidth={1.5}
123
- onClick={() => geoClickHandler(territory, territoryData)}
124
- />)
125
- }
126
- });
106
+ }
127
107
 
128
- const geoLabel = (geo, bgColor = "#FFFFFF", projection) => {
129
- let centroid = projection(geoCentroid(geo))
130
- let abbr = geo.properties.iso
108
+ return <Shape key={label} label={label} css={styles} text={styles.color} data-tip={toolTip} data-for='tooltip' stroke={geoStrokeColor} strokeWidth={1.5} onClick={() => geoClickHandler(territory, territoryData)} />
109
+ }
110
+ })
131
111
 
132
- if(undefined === abbr) return null
112
+ const geoLabel = (geo, bgColor = '#FFFFFF', projection) => {
113
+ let centroid = projection(geoCentroid(geo))
114
+ let abbr = geo.properties.iso
133
115
 
134
- let textColor = "#FFF"
116
+ if (undefined === abbr) return null
135
117
 
136
- // Dynamic text color
137
- if (chroma.contrast(textColor, bgColor) < 3.5 ) {
138
- textColor = '#202020';
139
- }
118
+ let textColor = '#FFF'
140
119
 
141
- let x = 0, y = 5
120
+ // Dynamic text color
121
+ if (chroma.contrast(textColor, bgColor) < 3.5) {
122
+ textColor = '#202020'
123
+ }
142
124
 
125
+ let x = 0,
126
+ y = 5
143
127
 
144
- return (
145
- <g>
146
- <line x1={centroid[0]} y1={centroid[1]} x2={centroid[0] + dx} y2={centroid[1] + dy} stroke="rgba(0,0,0,.5)" strokeWidth={1} />
147
- <text x={4} strokeWidth="0" fontSize={13} style={{fill: "#202020"}} alignmentBaseline="middle" transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}>
148
- {abbr.substring(3)}
149
- </text>
150
- </g>
151
- )
128
+ return (
129
+ <g>
130
+ <line x1={centroid[0]} y1={centroid[1]} x2={centroid[0] + dx} y2={centroid[1] + dy} stroke='rgba(0,0,0,.5)' strokeWidth={1} />
131
+ <text x={4} strokeWidth='0' fontSize={13} style={{ fill: '#202020' }} alignmentBaseline='middle' transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}>
132
+ {abbr.substring(3)}
133
+ </text>
134
+ </g>
135
+ )
152
136
  }
153
137
 
154
138
  // Constructs and displays markup for all geos on the map (except territories right now)
155
139
  const constructGeoJsx = (geographies, projection) => {
156
140
  let showLabel = state.general.displayStateLabels
157
141
 
158
- const geosJsx = geographies.map(( {feature: geo, path = '', index}) => {
142
+ const geosJsx = geographies.map(({ feature: geo, path = '', index }) => {
159
143
  const key = isHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
160
144
 
161
145
  let styles = {
@@ -164,58 +148,60 @@ const UsaRegionMap = (props) => {
164
148
  }
165
149
 
166
150
  // Map the name from the geo data with the appropriate key for the processed data
167
- let geoKey = geo.properties.iso;
151
+ let geoKey = geo.properties.iso
168
152
 
169
153
  // Manually add Washington D.C. in for Hex maps
170
154
 
171
- if(!geoKey) return
155
+ if (!geoKey) return
172
156
 
173
- const geoData = data[geoKey];
157
+ const geoData = data[geoKey]
174
158
 
175
- let legendColors;
159
+ let legendColors
176
160
  // Once we receive data for this geographic item, setup variables.
177
161
  if (geoData !== undefined) {
178
- legendColors = applyLegendToRow(geoData);
162
+ legendColors = applyLegendToRow(geoData)
179
163
  }
180
164
 
181
- const geoDisplayName = displayGeoName(geoKey);
165
+ const geoDisplayName = displayGeoName(geoKey)
182
166
 
183
167
  // If a legend applies, return it with appropriate information.
184
168
  if (legendColors && legendColors[0] !== '#000000') {
185
- const tooltip = applyTooltipsToGeo(geoDisplayName, geoData);
169
+ const tooltip = applyTooltipsToGeo(geoDisplayName, geoData)
186
170
 
187
171
  styles = {
188
172
  fill: state.general.type !== 'bubble' ? legendColors[0] : '#E6E6E6',
189
173
  cursor: 'default',
190
174
  '&:hover': {
191
- fill: state.general.type !== 'bubble' ? legendColors[1] : '#e6e6e6',
175
+ fill: state.general.type !== 'bubble' ? legendColors[1] : '#e6e6e6'
192
176
  },
193
177
  '&:active': {
194
- fill: state.general.type !== 'bubble' ? legendColors[2] : '#e6e6e6',
195
- },
196
- };
178
+ fill: state.general.type !== 'bubble' ? legendColors[2] : '#e6e6e6'
179
+ }
180
+ }
197
181
 
198
182
  // When to add pointer cursor
199
183
  if ((state.columns.navigate && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
200
184
  styles.cursor = 'pointer'
201
185
  }
202
186
 
203
- const TerratoryRect = (props) => {
187
+ const TerratoryRect = props => {
204
188
  const { posX = 0, tName } = props
205
- let textColor = "#fff"
189
+ let textColor = '#fff'
206
190
 
207
191
  if (chroma.contrast(textColor, legendColors[0]) < 4.5) {
208
- textColor = '#202020';
192
+ textColor = '#202020'
209
193
  }
210
194
  return (
211
195
  <>
212
- <rect x={posX} width="36" height="24" rx="6" stroke="#fff" strokeWidth="1" />
213
- <text x={posX + 8} y="17" fill={textColor}>{tName}</text>
196
+ <rect x={posX} width='36' height='24' rx='6' stroke='#fff' strokeWidth='1' />
197
+ <text x={posX + 8} y='17' fill={textColor}>
198
+ {tName}
199
+ </text>
214
200
  </>
215
201
  )
216
202
  }
217
203
 
218
- const circleRadius = 15;
204
+ const circleRadius = 15
219
205
 
220
206
  // SIDE CHART EXPERIMENT
221
207
  // const height = state.data[index].Change;
@@ -226,25 +212,13 @@ const UsaRegionMap = (props) => {
226
212
  // const barFill = barPositive ? "#fff" : "#fff";
227
213
 
228
214
  return (
229
- <g
230
- data-for="tooltip"
231
- data-tip={tooltip}
232
- key={key}
233
- className="geo-group"
234
- css={styles}
235
- onClick={() => geoClickHandler(geoDisplayName, geoData)}
236
- >
237
-
238
- <path
239
- tabIndex={-1}
240
- className='single-geo'
241
- stroke={geoStrokeColor}
242
- strokeWidth={1.3}
243
- d={path}
244
- />
245
- <g id={`region-${index+1}-label`}>
246
- <circle fill="#fff" stroke="#999" cx={circleRadius} cy={circleRadius} r={circleRadius}/>
247
- <text fill="#333" x="15px" y="20px" textAnchor="middle">{index+1}</text>
215
+ <g data-for='tooltip' data-tip={tooltip} key={key} className='geo-group' css={styles} onClick={() => geoClickHandler(geoDisplayName, geoData)}>
216
+ <path tabIndex={-1} className='single-geo' stroke={geoStrokeColor} strokeWidth={1.3} d={path} />
217
+ <g id={`region-${index + 1}-label`}>
218
+ <circle fill='#fff' stroke='#999' cx={circleRadius} cy={circleRadius} r={circleRadius} />
219
+ <text fill='#333' x='15px' y='20px' textAnchor='middle'>
220
+ {index + 1}
221
+ </text>
248
222
  {/* SIDE CHART EXPERIMENT */}
249
223
  {/*<g y={barY*20}>*/}
250
224
  {/* <rect x="-20" y={barY} width="10" height={barHeight} fill={barFill} stroke="#333"/>*/}
@@ -252,69 +226,57 @@ const UsaRegionMap = (props) => {
252
226
  {/*</g>*/}
253
227
  {/* / SIDE CHART EXPERIMENT */}
254
228
  </g>
255
- {geoKey === 'region 2' &&
256
- <g id="region-2-territories">
257
- <TerratoryRect tName="PR" />
258
- <TerratoryRect posX={45} tName="VI" />
229
+ {geoKey === 'region 2' && (
230
+ <g id='region-2-territories'>
231
+ <TerratoryRect tName='PR' />
232
+ <TerratoryRect posX={45} tName='VI' />
259
233
  </g>
260
- }
261
-
262
- { geoKey === 'region 9' &&
263
- <g id="region-9-territories">
264
- <g className="region-9-row1">
265
- <TerratoryRect tName="AS" />
266
- <TerratoryRect posX={45} tName="GU" />
267
- <TerratoryRect posX={90} tName="MP" />
234
+ )}
235
+
236
+ {geoKey === 'region 9' && (
237
+ <g id='region-9-territories'>
238
+ <g className='region-9-row1'>
239
+ <TerratoryRect tName='AS' />
240
+ <TerratoryRect posX={45} tName='GU' />
241
+ <TerratoryRect posX={90} tName='MP' />
268
242
  </g>
269
- <g className="region-9-row2">
270
- <TerratoryRect tName="FM" />
271
- <TerratoryRect posX={45} tName="PW" />
272
- <TerratoryRect posX={90} tName="MH" />
243
+ <g className='region-9-row2'>
244
+ <TerratoryRect tName='FM' />
245
+ <TerratoryRect posX={45} tName='PW' />
246
+ <TerratoryRect posX={90} tName='MH' />
273
247
  </g>
274
248
  </g>
275
- }
249
+ )}
276
250
  </g>
277
251
  )
278
252
  }
279
253
 
280
254
  // Default return state, just geo with no additional information
281
255
  return (
282
- <g
283
- key={key}
284
- className="geo-group"
285
- css={styles}
286
- >
287
- <path
288
- tabIndex={-1}
289
- className='single-geo'
290
- stroke={geoStrokeColor}
291
- strokeWidth={1.3}
292
- d={path}
293
- />
256
+ <g key={key} className='geo-group' css={styles}>
257
+ <path tabIndex={-1} className='single-geo' stroke={geoStrokeColor} strokeWidth={1.3} d={path} />
294
258
  {(isHex || showLabel) && geoLabel(geo, styles.fill, projection)}
295
259
  </g>
296
260
  )
297
- });
298
- return geosJsx;
299
- };
300
-
301
- return (
302
- <ErrorBoundary component="UsaRegionMap">
303
- <svg viewBox="0 0 880 500" role="img" aria-label={handleMapAriaLabels(state)}>
261
+ })
262
+ return geosJsx
263
+ }
304
264
 
265
+ return (
266
+ <ErrorBoundary component='UsaRegionMap'>
267
+ <svg viewBox='0 0 880 500' role='img' aria-label={handleMapAriaLabels(state)}>
305
268
  <Mercator data={focusedStates} scale={620} translate={[1500, 735]}>
306
269
  {({ features, projection }) => constructGeoJsx(features, projection)}
307
270
  </Mercator>
308
-
309
271
  </svg>
310
272
  {territories.length > 0 && (
311
- <section className="territories">
312
- <span className="label">{state.general.territoriesLabel}</span>
273
+ <section className='territories'>
274
+ <span className='label'>{state.general.territoriesLabel}</span>
313
275
  {territories}
314
276
  </section>
315
277
  )}
316
278
  </ErrorBoundary>
317
- );
318
- };
279
+ )
280
+ }
319
281
 
320
282
  export default memo(UsaRegionMap)