@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.
- package/dist/cdcmap.js +10 -10
- package/examples/private/atsdr.json +19 -29
- package/examples/private/atsdr_new.json +1 -1
- package/examples/private/bubble.json +282 -284
- package/examples/private/city-state.json +427 -427
- package/examples/private/city-state2.json +433 -433
- package/examples/private/cty-issue.json +42765 -42768
- package/examples/private/default-usa.json +2 -5
- package/examples/private/default-world-data.json +1443 -1443
- package/examples/private/default.json +965 -965
- package/examples/private/diff.json +226 -0
- package/examples/private/filters.json +1 -0
- package/examples/private/legend-issue.json +3271 -1
- package/examples/private/map-issue.json +166 -0
- package/examples/private/map-rounding-error.json +42756 -42759
- package/examples/private/mdx.json +209 -209
- package/examples/private/monkeypox.json +375 -375
- package/examples/private/regions.json +51 -51
- package/examples/private/wcmsrd-13881-data.json +2856 -2856
- package/examples/private/wcmsrd-13881.json +5818 -5822
- package/examples/private/wcmsrd-14492-data.json +291 -291
- package/examples/private/wcmsrd-14492.json +103 -113
- package/examples/private/wcmsrd-test.json +264 -267
- package/examples/private/world.json +1579 -1579
- package/examples/private/worldmap.json +1489 -1489
- package/package.json +3 -3
- package/src/CdcMap.js +231 -315
- package/src/components/BubbleList.js +199 -240
- package/src/components/CityList.js +50 -96
- package/src/components/CountyMap.js +511 -600
- package/src/components/DataTable.js +218 -253
- package/src/components/EditorPanel.js +2338 -2551
- package/src/components/Geo.js +4 -14
- package/src/components/Modal.js +13 -23
- package/src/components/NavigationMenu.js +43 -39
- package/src/components/Sidebar.js +83 -93
- package/src/components/SingleStateMap.js +95 -151
- package/src/components/UsaMap.js +165 -214
- package/src/components/UsaRegionMap.js +122 -160
- package/src/components/WorldMap.js +96 -179
- package/src/components/ZoomableGroup.js +6 -26
- package/src/data/initial-state.js +1 -0
- package/src/hooks/useActiveElement.js +13 -13
- package/src/hooks/useColorPalette.ts +66 -74
- package/src/hooks/useZoomPan.js +22 -23
- package/src/index.html +1 -2
- package/src/scss/sidebar.scss +22 -0
|
@@ -1,43 +1,26 @@
|
|
|
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 { geoPath } from
|
|
6
|
-
import { feature, mesh } from
|
|
7
|
-
import { CustomProjection } from '@visx/geo'
|
|
8
|
-
import colorPalettes from '../../../core/data/colorPalettes'
|
|
9
|
-
import { geoAlbersUsaTerritories } from 'd3-composite-projections'
|
|
10
|
-
import testJSON from '../data/county-map.json'
|
|
11
|
-
import CityList from './CityList'
|
|
12
|
-
|
|
4
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
5
|
+
import { geoPath } from 'd3-geo'
|
|
6
|
+
import { feature, mesh } from 'topojson-client'
|
|
7
|
+
import { CustomProjection } from '@visx/geo'
|
|
8
|
+
import colorPalettes from '../../../core/data/colorPalettes'
|
|
9
|
+
import { geoAlbersUsaTerritories } from 'd3-composite-projections'
|
|
10
|
+
import testJSON from '../data/county-map.json'
|
|
11
|
+
import CityList from './CityList'
|
|
13
12
|
|
|
14
13
|
// SVG ITEMS
|
|
15
|
-
const WIDTH = 880
|
|
16
|
-
const HEIGHT = 500
|
|
17
|
-
const PADDING = 25
|
|
14
|
+
const WIDTH = 880
|
|
15
|
+
const HEIGHT = 500
|
|
16
|
+
const PADDING = 25
|
|
18
17
|
|
|
19
18
|
// DATA
|
|
20
19
|
let { features: counties } = feature(testJSON, testJSON.objects.counties)
|
|
21
|
-
let { features: states } = feature(testJSON, testJSON.objects.states)
|
|
22
|
-
|
|
23
|
-
const SingleStateMap =
|
|
24
|
-
|
|
25
|
-
const {
|
|
26
|
-
state,
|
|
27
|
-
applyTooltipsToGeo,
|
|
28
|
-
data,
|
|
29
|
-
geoClickHandler,
|
|
30
|
-
applyLegendToRow,
|
|
31
|
-
displayGeoName,
|
|
32
|
-
supportedTerritories,
|
|
33
|
-
rebuildTooltips,
|
|
34
|
-
runtimeLegend,
|
|
35
|
-
generateColorsArray,
|
|
36
|
-
handleMapAriaLabels,
|
|
37
|
-
titleCase,
|
|
38
|
-
setSharedFilterValue,
|
|
39
|
-
isFilterValueSupported
|
|
40
|
-
} = props;
|
|
20
|
+
let { features: states } = feature(testJSON, testJSON.objects.states)
|
|
21
|
+
|
|
22
|
+
const SingleStateMap = props => {
|
|
23
|
+
const { state, applyTooltipsToGeo, data, geoClickHandler, applyLegendToRow, displayGeoName, supportedTerritories, rebuildTooltips, runtimeLegend, generateColorsArray, handleMapAriaLabels, titleCase, setSharedFilterValue, isFilterValueSupported } = props
|
|
41
24
|
|
|
42
25
|
const projection = geoAlbersUsaTerritories().translate([WIDTH / 2, HEIGHT / 2])
|
|
43
26
|
const cityListProjection = geoAlbersUsaTerritories().translate([WIDTH / 2, HEIGHT / 2])
|
|
@@ -46,18 +29,18 @@ const SingleStateMap = (props) => {
|
|
|
46
29
|
const [countiesToShow, setCountiesToShow] = useState(null)
|
|
47
30
|
const [translate, setTranslate] = useState()
|
|
48
31
|
const [scale, setScale] = useState()
|
|
49
|
-
const [strokeWidth, setStrokeWidth] = useState(.75)
|
|
50
|
-
let mapColorPalette = colorPalettes[state.color] || '#fff'
|
|
51
|
-
let focusedBorderColor = mapColorPalette[3]
|
|
32
|
+
const [strokeWidth, setStrokeWidth] = useState(0.75)
|
|
33
|
+
let mapColorPalette = colorPalettes[state.color] || '#fff'
|
|
34
|
+
let focusedBorderColor = mapColorPalette[3]
|
|
52
35
|
|
|
53
|
-
useEffect(() => rebuildTooltips())
|
|
36
|
+
useEffect(() => rebuildTooltips())
|
|
54
37
|
|
|
55
38
|
const path = geoPath().projection(projection)
|
|
56
39
|
|
|
57
40
|
// When choosing a state changes...
|
|
58
41
|
useEffect(() => {
|
|
59
42
|
if (state.general.hasOwnProperty('statePicked')) {
|
|
60
|
-
let statePicked = state.general.statePicked.stateName
|
|
43
|
+
let statePicked = state.general.statePicked.stateName
|
|
61
44
|
let statePickedData = states.find(s => s.properties.name === statePicked)
|
|
62
45
|
setStateToShow(statePickedData)
|
|
63
46
|
|
|
@@ -66,29 +49,33 @@ const SingleStateMap = (props) => {
|
|
|
66
49
|
setCountiesToShow(countiesFound)
|
|
67
50
|
|
|
68
51
|
const projection = geoAlbersUsaTerritories().translate([WIDTH / 2, HEIGHT / 2])
|
|
69
|
-
const newProjection = projection.fitExtent(
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
const newProjection = projection.fitExtent(
|
|
53
|
+
[
|
|
54
|
+
[PADDING, PADDING],
|
|
55
|
+
[WIDTH - PADDING, HEIGHT - PADDING]
|
|
56
|
+
],
|
|
57
|
+
statePickedData
|
|
58
|
+
)
|
|
59
|
+
const newScale = newProjection.scale()
|
|
60
|
+
const newScaleWithHypot = newScale / 1070
|
|
72
61
|
|
|
73
62
|
let [x, y] = newProjection.translate()
|
|
74
|
-
x =
|
|
75
|
-
y =
|
|
63
|
+
x = x - WIDTH / 2
|
|
64
|
+
y = y - HEIGHT / 2
|
|
76
65
|
|
|
77
66
|
setTranslate([x, y])
|
|
78
67
|
setScale(newScaleWithHypot)
|
|
79
|
-
|
|
80
68
|
}
|
|
81
|
-
}, [state.general.statePicked])
|
|
69
|
+
}, [state.general.statePicked])
|
|
82
70
|
|
|
83
71
|
// Constructs and displays markup for all geos on the map (except territories right now)
|
|
84
72
|
const constructGeoJsx = (geographies, projection) => {
|
|
85
|
-
const statePassed = geographies[0].feature.states
|
|
86
|
-
const counties = geographies[0].feature.counties
|
|
73
|
+
const statePassed = geographies[0].feature.states
|
|
74
|
+
const counties = geographies[0].feature.counties
|
|
87
75
|
|
|
88
|
-
let geosJsx = []
|
|
76
|
+
let geosJsx = []
|
|
89
77
|
|
|
90
78
|
const StateOutput = () => {
|
|
91
|
-
|
|
92
79
|
let geo = testJSON.objects.states.geometries.filter(s => {
|
|
93
80
|
return s.id === statePassed.id
|
|
94
81
|
})
|
|
@@ -96,59 +83,46 @@ const SingleStateMap = (props) => {
|
|
|
96
83
|
// const stateLine = path(mesh(testJSON, lines ))
|
|
97
84
|
let stateLines = path(mesh(testJSON, geo[0]))
|
|
98
85
|
return (
|
|
99
|
-
<g
|
|
100
|
-
|
|
101
|
-
className="single-state"
|
|
102
|
-
style={{ fill: '#E6E6E6' }}
|
|
103
|
-
stroke={geoStrokeColor}
|
|
104
|
-
strokeWidth={.95 / scale}
|
|
105
|
-
>
|
|
106
|
-
<path
|
|
107
|
-
tabIndex={-1}
|
|
108
|
-
className='state-path'
|
|
109
|
-
d={stateLines}
|
|
110
|
-
/>
|
|
86
|
+
<g key={'single-state'} className='single-state' style={{ fill: '#E6E6E6' }} stroke={geoStrokeColor} strokeWidth={0.95 / scale}>
|
|
87
|
+
<path tabIndex={-1} className='state-path' d={stateLines} />
|
|
111
88
|
</g>
|
|
112
89
|
)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const countyOutput = (counties.map((county) => {
|
|
90
|
+
}
|
|
116
91
|
|
|
92
|
+
const countyOutput = counties.map(county => {
|
|
117
93
|
// Map the name from the geo data with the appropriate key for the processed data
|
|
118
|
-
let geoKey = county.id
|
|
94
|
+
let geoKey = county.id
|
|
119
95
|
|
|
120
|
-
if (!geoKey) return
|
|
96
|
+
if (!geoKey) return
|
|
121
97
|
|
|
122
|
-
let countyPath = path(county)
|
|
98
|
+
let countyPath = path(county)
|
|
123
99
|
|
|
124
|
-
let geoData = data[county.id]
|
|
125
|
-
let legendColors
|
|
100
|
+
let geoData = data[county.id]
|
|
101
|
+
let legendColors
|
|
126
102
|
|
|
127
103
|
// Once we receive data for this geographic item, setup variables.
|
|
128
104
|
if (geoData !== undefined) {
|
|
129
|
-
legendColors = applyLegendToRow(geoData)
|
|
105
|
+
legendColors = applyLegendToRow(geoData)
|
|
130
106
|
}
|
|
131
107
|
|
|
132
|
-
const geoDisplayName = displayGeoName(geoKey)
|
|
108
|
+
const geoDisplayName = displayGeoName(geoKey)
|
|
133
109
|
|
|
134
110
|
// For some reason, these two geos are breaking the display.
|
|
135
|
-
if (geoDisplayName === 'Franklin City' || geoDisplayName === 'Waynesboro') return null
|
|
111
|
+
if (geoDisplayName === 'Franklin City' || geoDisplayName === 'Waynesboro') return null
|
|
136
112
|
|
|
137
|
-
const tooltip = applyTooltipsToGeo(geoDisplayName, geoData)
|
|
113
|
+
const tooltip = applyTooltipsToGeo(geoDisplayName, geoData)
|
|
138
114
|
|
|
139
115
|
if (legendColors && legendColors[0] !== '#000000') {
|
|
140
|
-
|
|
141
|
-
|
|
142
116
|
let styles = {
|
|
143
117
|
fill: legendColors[0],
|
|
144
118
|
cursor: 'default',
|
|
145
119
|
'&:hover': {
|
|
146
|
-
fill: legendColors[1]
|
|
120
|
+
fill: legendColors[1]
|
|
147
121
|
},
|
|
148
122
|
'&:active': {
|
|
149
|
-
fill: legendColors[2]
|
|
150
|
-
}
|
|
151
|
-
}
|
|
123
|
+
fill: legendColors[2]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
152
126
|
|
|
153
127
|
// When to add pointer cursor
|
|
154
128
|
if ((state.columns.navigate && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'hover') {
|
|
@@ -156,100 +130,70 @@ const SingleStateMap = (props) => {
|
|
|
156
130
|
}
|
|
157
131
|
|
|
158
132
|
return (
|
|
159
|
-
<g
|
|
160
|
-
|
|
161
|
-
data-tip={tooltip}
|
|
162
|
-
key={`key--${county.id}`}
|
|
163
|
-
className={`county county--${geoDisplayName.split(" ").join("")} county--${geoData[state.columns.geo.name]}`}
|
|
164
|
-
css={styles}
|
|
165
|
-
onClick={() => geoClickHandler(geoDisplayName, geoData)}
|
|
166
|
-
>
|
|
167
|
-
<path
|
|
168
|
-
tabIndex={-1}
|
|
169
|
-
className={`county`}
|
|
170
|
-
stroke={geoStrokeColor}
|
|
171
|
-
d={countyPath}
|
|
172
|
-
strokeWidth={.75 / scale}
|
|
173
|
-
/>
|
|
133
|
+
<g data-for='tooltip' data-tip={tooltip} key={`key--${county.id}`} className={`county county--${geoDisplayName.split(' ').join('')} county--${geoData[state.columns.geo.name]}`} css={styles} onClick={() => geoClickHandler(geoDisplayName, geoData)}>
|
|
134
|
+
<path tabIndex={-1} className={`county`} stroke={geoStrokeColor} d={countyPath} strokeWidth={0.75 / scale} />
|
|
174
135
|
</g>
|
|
175
136
|
)
|
|
176
137
|
} else {
|
|
177
138
|
return (
|
|
178
|
-
<g
|
|
179
|
-
|
|
180
|
-
data-tip={tooltip}
|
|
181
|
-
key={`key--${county.id}`}
|
|
182
|
-
className={`county county--${geoDisplayName.split(" ").join("")}`}
|
|
183
|
-
style={{ fill: '#e6e6e6' }}
|
|
184
|
-
>
|
|
185
|
-
<path
|
|
186
|
-
tabIndex={-1}
|
|
187
|
-
className={`county`}
|
|
188
|
-
stroke={geoStrokeColor}
|
|
189
|
-
d={countyPath}
|
|
190
|
-
strokeWidth={.75 / scale}
|
|
191
|
-
/>
|
|
139
|
+
<g data-for='tooltip' data-tip={tooltip} key={`key--${county.id}`} className={`county county--${geoDisplayName.split(' ').join('')}`} style={{ fill: '#e6e6e6' }}>
|
|
140
|
+
<path tabIndex={-1} className={`county`} stroke={geoStrokeColor} d={countyPath} strokeWidth={0.75 / scale} />
|
|
192
141
|
</g>
|
|
193
142
|
)
|
|
194
143
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
geosJsx.push(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return geosJsx
|
|
217
|
-
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
geosJsx.push(<StateOutput />)
|
|
147
|
+
geosJsx.push(countyOutput)
|
|
148
|
+
geosJsx.push(
|
|
149
|
+
<CityList
|
|
150
|
+
projection={cityListProjection}
|
|
151
|
+
key='cities'
|
|
152
|
+
data={data}
|
|
153
|
+
state={state}
|
|
154
|
+
geoClickHandler={geoClickHandler}
|
|
155
|
+
applyTooltipsToGeo={applyTooltipsToGeo}
|
|
156
|
+
displayGeoName={displayGeoName}
|
|
157
|
+
applyLegendToRow={applyLegendToRow}
|
|
158
|
+
titleCase={titleCase}
|
|
159
|
+
setSharedFilterValue={setSharedFilterValue}
|
|
160
|
+
isFilterValueSupported={isFilterValueSupported}
|
|
161
|
+
isGeoCodeMap={state.general.type === 'us-geocode'}
|
|
162
|
+
/>
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
return geosJsx
|
|
166
|
+
}
|
|
218
167
|
|
|
219
168
|
return (
|
|
220
|
-
<ErrorBoundary component=
|
|
221
|
-
{stateToShow &&
|
|
222
|
-
<svg
|
|
223
|
-
|
|
224
|
-
preserveAspectRatio="xMinYMin"
|
|
225
|
-
className="svg-container"
|
|
226
|
-
role="img"
|
|
227
|
-
aria-label={handleMapAriaLabels(state)}
|
|
228
|
-
>
|
|
229
|
-
<rect className="background center-container ocean" width={WIDTH} height={HEIGHT} fillOpacity={1} fill="white"></rect>
|
|
169
|
+
<ErrorBoundary component='SingleStateMap'>
|
|
170
|
+
{stateToShow && (
|
|
171
|
+
<svg viewBox={`0 0 ${WIDTH} ${HEIGHT}`} preserveAspectRatio='xMinYMin' className='svg-container' role='img' aria-label={handleMapAriaLabels(state)}>
|
|
172
|
+
<rect className='background center-container ocean' width={WIDTH} height={HEIGHT} fillOpacity={1} fill='white'></rect>
|
|
230
173
|
<CustomProjection
|
|
231
174
|
data={[{ states: stateToShow, counties: countiesToShow }]}
|
|
232
175
|
projection={geoAlbersUsaTerritories}
|
|
233
|
-
fitExtent={[
|
|
176
|
+
fitExtent={[
|
|
177
|
+
[
|
|
178
|
+
[PADDING, PADDING],
|
|
179
|
+
[WIDTH - PADDING, HEIGHT - PADDING]
|
|
180
|
+
],
|
|
181
|
+
stateToShow
|
|
182
|
+
]}
|
|
234
183
|
>
|
|
235
184
|
{({ features, projection }) => {
|
|
236
185
|
return (
|
|
237
|
-
<g
|
|
238
|
-
id="mapGroup"
|
|
239
|
-
className="countyMapGroup"
|
|
240
|
-
transform={`translate(${translate}) scale(${scale})`}
|
|
241
|
-
data-scale=""
|
|
242
|
-
key="countyMapGroup">
|
|
186
|
+
<g id='mapGroup' className='countyMapGroup' transform={`translate(${translate}) scale(${scale})`} data-scale='' key='countyMapGroup'>
|
|
243
187
|
{constructGeoJsx(features, projection)}
|
|
244
188
|
</g>
|
|
245
189
|
)
|
|
246
190
|
}}
|
|
247
191
|
</CustomProjection>
|
|
248
192
|
</svg>
|
|
249
|
-
}
|
|
193
|
+
)}
|
|
250
194
|
{!stateToShow && 'No State Picked'}
|
|
251
195
|
</ErrorBoundary>
|
|
252
|
-
)
|
|
253
|
-
}
|
|
196
|
+
)
|
|
197
|
+
}
|
|
254
198
|
|
|
255
199
|
export default memo(SingleStateMap)
|