@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
package/src/components/Geo.js
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import React, { memo } from 'react'
|
|
1
|
+
import React, { memo } from 'react'
|
|
2
2
|
|
|
3
|
-
const Geo = ({path, styles, stroke, strokeWidth, ...props}) => {
|
|
3
|
+
const Geo = ({ path, styles, stroke, strokeWidth, ...props }) => {
|
|
4
4
|
return (
|
|
5
|
-
<g
|
|
6
|
-
className=
|
|
7
|
-
css={styles}
|
|
8
|
-
{...props}
|
|
9
|
-
>
|
|
10
|
-
<path
|
|
11
|
-
tabIndex={-1}
|
|
12
|
-
className='single-geo'
|
|
13
|
-
stroke={stroke}
|
|
14
|
-
strokeWidth={strokeWidth}
|
|
15
|
-
d={path}
|
|
16
|
-
/>
|
|
5
|
+
<g className='geo-group' css={styles} {...props}>
|
|
6
|
+
<path tabIndex={-1} className='single-geo' stroke={stroke} strokeWidth={strokeWidth} d={path} />
|
|
17
7
|
</g>
|
|
18
8
|
)
|
|
19
9
|
}
|
package/src/components/Modal.js
CHANGED
|
@@ -1,32 +1,22 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import closeIcon from '../images/close.svg?inline'
|
|
3
|
-
import LegendCircle from '@cdc/core/components/LegendCircle'
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import closeIcon from '../images/close.svg?inline'
|
|
3
|
+
import LegendCircle from '@cdc/core/components/LegendCircle'
|
|
4
4
|
|
|
5
5
|
//TODO: Where is this being used? Transfer to new Modal component?
|
|
6
|
-
const Modal =
|
|
7
|
-
const {
|
|
8
|
-
applyTooltipsToGeo,
|
|
9
|
-
content,
|
|
10
|
-
capitalize,
|
|
11
|
-
applyLegendToRow,
|
|
12
|
-
viewport,
|
|
13
|
-
type
|
|
14
|
-
} = props;
|
|
6
|
+
const Modal = props => {
|
|
7
|
+
const { applyTooltipsToGeo, content, capitalize, applyLegendToRow, viewport, type } = props
|
|
15
8
|
|
|
16
|
-
const tooltip = applyTooltipsToGeo(content.geoName, content.keyedData, 'jsx')
|
|
9
|
+
const tooltip = applyTooltipsToGeo(content.geoName, content.keyedData, 'jsx')
|
|
17
10
|
|
|
18
|
-
const legendColors = applyLegendToRow(content.keyedData)
|
|
11
|
+
const legendColors = applyLegendToRow(content.keyedData)
|
|
19
12
|
|
|
20
13
|
return (
|
|
21
|
-
<section className={capitalize ? 'modal-content tooltip capitalize ' + viewport : 'modal-content tooltip ' + viewport} aria-hidden=
|
|
22
|
-
<img src={closeIcon} className=
|
|
14
|
+
<section className={capitalize ? 'modal-content tooltip capitalize ' + viewport : 'modal-content tooltip ' + viewport} aria-hidden='true'>
|
|
15
|
+
<img src={closeIcon} className='modal-close' alt='Close Modal' />
|
|
23
16
|
{type === 'data' && <LegendCircle fill={legendColors[0]} />}
|
|
24
|
-
<div className=
|
|
25
|
-
{tooltip}
|
|
26
|
-
</div>
|
|
17
|
+
<div className='content'>{tooltip}</div>
|
|
27
18
|
</section>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
19
|
+
)
|
|
20
|
+
}
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
export default Modal;
|
|
22
|
+
export default Modal
|
|
@@ -1,67 +1,71 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
2
|
|
|
3
|
-
const NavigationMenu = ({
|
|
4
|
-
|
|
5
|
-
}) => {
|
|
6
|
-
const [activeGeo, setActiveGeo] = useState('');
|
|
3
|
+
const NavigationMenu = ({ data, navigationHandler, options, columns, displayGeoName, mapTabbingID }) => {
|
|
4
|
+
const [activeGeo, setActiveGeo] = useState('')
|
|
7
5
|
|
|
8
|
-
const [dropdownItems, setDropdownItems] = useState({})
|
|
6
|
+
const [dropdownItems, setDropdownItems] = useState({})
|
|
9
7
|
|
|
10
|
-
const handleSubmit =
|
|
11
|
-
event.preventDefault()
|
|
8
|
+
const handleSubmit = event => {
|
|
9
|
+
event.preventDefault()
|
|
12
10
|
if (activeGeo !== '') {
|
|
13
|
-
const urlString = data[dropdownItems[activeGeo]][columns.navigate.name]
|
|
11
|
+
const urlString = data[dropdownItems[activeGeo]][columns.navigate.name]
|
|
14
12
|
|
|
15
|
-
navigationHandler(urlString)
|
|
13
|
+
navigationHandler(urlString)
|
|
16
14
|
}
|
|
17
|
-
}
|
|
15
|
+
}
|
|
18
16
|
|
|
19
|
-
let navSelect
|
|
20
|
-
|
|
17
|
+
let navSelect
|
|
18
|
+
let navGo
|
|
21
19
|
|
|
22
20
|
switch (options.language) {
|
|
23
21
|
case 'es':
|
|
24
|
-
navSelect = 'Selecciona un Artículo'
|
|
25
|
-
navGo = 'Ir'
|
|
26
|
-
break
|
|
22
|
+
navSelect = 'Selecciona un Artículo'
|
|
23
|
+
navGo = 'Ir'
|
|
24
|
+
break
|
|
27
25
|
default:
|
|
28
|
-
navSelect = 'Select an Item'
|
|
29
|
-
navGo = 'Go'
|
|
26
|
+
navSelect = 'Select an Item'
|
|
27
|
+
navGo = 'Go'
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
useEffect(() => {
|
|
33
|
-
const sortedOptions = {}
|
|
31
|
+
const sortedOptions = {}
|
|
34
32
|
|
|
35
|
-
const processedDropdown = {}
|
|
33
|
+
const processedDropdown = {}
|
|
36
34
|
|
|
37
|
-
Object.keys(data).forEach(
|
|
38
|
-
const fullName = displayGeoName(val)
|
|
35
|
+
Object.keys(data).forEach(val => {
|
|
36
|
+
const fullName = displayGeoName(val)
|
|
39
37
|
|
|
40
|
-
processedDropdown[fullName] = val
|
|
41
|
-
})
|
|
38
|
+
processedDropdown[fullName] = val
|
|
39
|
+
})
|
|
42
40
|
|
|
43
|
-
Object.keys(processedDropdown)
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
Object.keys(processedDropdown)
|
|
42
|
+
.sort()
|
|
43
|
+
.forEach(key => {
|
|
44
|
+
sortedOptions[key] = processedDropdown[key]
|
|
45
|
+
})
|
|
46
46
|
|
|
47
|
-
setDropdownItems(sortedOptions)
|
|
47
|
+
setDropdownItems(sortedOptions)
|
|
48
48
|
|
|
49
|
-
setActiveGeo(Object.keys(sortedOptions)[0])
|
|
50
|
-
}, [data, displayGeoName])
|
|
49
|
+
setActiveGeo(Object.keys(sortedOptions)[0])
|
|
50
|
+
}, [data, displayGeoName])
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
|
-
<section className=
|
|
54
|
-
<form onSubmit={handleSubmit} type=
|
|
53
|
+
<section className='navigation-menu'>
|
|
54
|
+
<form onSubmit={handleSubmit} type='get'>
|
|
55
55
|
<label htmlFor={mapTabbingID.replace('#', '')}>
|
|
56
|
-
<div className=
|
|
57
|
-
<select value={activeGeo} id={mapTabbingID.replace('#', '')} onChange={
|
|
58
|
-
{Object.keys(dropdownItems).map((key, i) =>
|
|
56
|
+
<div className='select-heading'>{navSelect}</div>
|
|
57
|
+
<select value={activeGeo} id={mapTabbingID.replace('#', '')} onChange={e => setActiveGeo(e.target.value)}>
|
|
58
|
+
{Object.keys(dropdownItems).map((key, i) => (
|
|
59
|
+
<option key={key} value={key}>
|
|
60
|
+
{key}
|
|
61
|
+
</option>
|
|
62
|
+
))}
|
|
59
63
|
</select>
|
|
60
64
|
</label>
|
|
61
|
-
<input type=
|
|
65
|
+
<input type='submit' value={navGo} className={`${options.headerColor} btn`} id='cdcnavmap-dropdown-go' />
|
|
62
66
|
</form>
|
|
63
67
|
</section>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
68
|
+
)
|
|
69
|
+
}
|
|
66
70
|
|
|
67
|
-
export default NavigationMenu
|
|
71
|
+
export default NavigationMenu
|
|
@@ -1,30 +1,17 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import parse from 'html-react-parser'
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import parse from 'html-react-parser'
|
|
3
3
|
|
|
4
4
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
5
5
|
import LegendCircle from '@cdc/core/components/LegendCircle'
|
|
6
6
|
|
|
7
|
-
const Sidebar =
|
|
8
|
-
const {
|
|
9
|
-
legend,
|
|
10
|
-
runtimeFilters,
|
|
11
|
-
columns,
|
|
12
|
-
setAccessibleStatus,
|
|
13
|
-
changeFilterActive,
|
|
14
|
-
resetLegendToggles,
|
|
15
|
-
runtimeLegend,
|
|
16
|
-
setRuntimeLegend,
|
|
17
|
-
prefix,
|
|
18
|
-
suffix,
|
|
19
|
-
viewport,
|
|
20
|
-
displayDataAsText
|
|
21
|
-
} = props;
|
|
7
|
+
const Sidebar = props => {
|
|
8
|
+
const { legend, runtimeFilters, columns, setAccessibleStatus, changeFilterActive, resetLegendToggles, runtimeLegend, setRuntimeLegend, prefix, suffix, viewport, displayDataAsText } = props
|
|
22
9
|
|
|
23
10
|
// Toggles if a legend is active and being applied to the map and data table.
|
|
24
11
|
const toggleLegendActive = (i, legendLabel) => {
|
|
25
|
-
const newValue = !runtimeLegend[i].disabled
|
|
12
|
+
const newValue = !runtimeLegend[i].disabled
|
|
26
13
|
|
|
27
|
-
runtimeLegend[i].disabled = newValue
|
|
14
|
+
runtimeLegend[i].disabled = newValue // Toggle!
|
|
28
15
|
|
|
29
16
|
let newLegend = [...runtimeLegend]
|
|
30
17
|
|
|
@@ -36,127 +23,130 @@ const Sidebar = (props) => {
|
|
|
36
23
|
|
|
37
24
|
setRuntimeLegend(newLegend)
|
|
38
25
|
|
|
39
|
-
setAccessibleStatus(`Disabled legend item ${legendLabel ?? ''}. Please reference the data table to see updated values.`)
|
|
40
|
-
}
|
|
26
|
+
setAccessibleStatus(`Disabled legend item ${legendLabel ?? ''}. Please reference the data table to see updated values.`)
|
|
27
|
+
}
|
|
41
28
|
|
|
42
29
|
const legendList = runtimeLegend.map((entry, idx) => {
|
|
30
|
+
const entryMax = displayDataAsText(entry.max, 'primary')
|
|
43
31
|
|
|
44
|
-
const
|
|
32
|
+
const entryMin = displayDataAsText(entry.min, 'primary')
|
|
45
33
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let formattedText = `${entryMin}${entryMax !== entryMin ? ` - ${entryMax}` : ''}`;
|
|
34
|
+
let formattedText = `${entryMin}${entryMax !== entryMin ? ` - ${entryMax}` : ''}`
|
|
49
35
|
|
|
50
36
|
// If interval, add some formatting
|
|
51
37
|
if (legend.type === 'equalinterval' && idx !== runtimeLegend.length - 1) {
|
|
52
|
-
formattedText = `${entryMin} - < ${entryMax}
|
|
38
|
+
formattedText = `${entryMin} - < ${entryMax}`
|
|
53
39
|
}
|
|
54
40
|
|
|
55
|
-
const { disabled } = entry
|
|
41
|
+
const { disabled } = entry
|
|
56
42
|
|
|
57
43
|
if (legend.type === 'category') {
|
|
58
|
-
formattedText = displayDataAsText(entry.value, 'primary')
|
|
44
|
+
formattedText = displayDataAsText(entry.value, 'primary')
|
|
59
45
|
}
|
|
60
46
|
|
|
61
47
|
if (entry.max === 0 && entry.min === 0) {
|
|
62
|
-
formattedText = '0'
|
|
48
|
+
formattedText = '0'
|
|
63
49
|
}
|
|
64
50
|
|
|
65
|
-
let legendLabel = formattedText
|
|
51
|
+
let legendLabel = formattedText
|
|
66
52
|
|
|
67
53
|
if (entry.hasOwnProperty('special')) {
|
|
68
|
-
legendLabel = entry.label || entry.value
|
|
54
|
+
legendLabel = entry.label || entry.value
|
|
69
55
|
}
|
|
70
56
|
|
|
71
57
|
return (
|
|
72
|
-
<li
|
|
58
|
+
<li
|
|
73
59
|
className={disabled ? 'disabled single-legend' : 'single-legend'}
|
|
74
60
|
key={idx}
|
|
75
61
|
title={`Legend item ${legendLabel} - Click to disable`}
|
|
76
|
-
onClick={() => {
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
onClick={() => {
|
|
63
|
+
toggleLegendActive(idx, legendLabel)
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<LegendCircle fill={entry.color} /> <span className='label'>{legendLabel}</span>
|
|
79
67
|
</li>
|
|
80
|
-
)
|
|
81
|
-
})
|
|
68
|
+
)
|
|
69
|
+
})
|
|
82
70
|
|
|
83
71
|
const filtersList = runtimeFilters.map((singleFilter, idx) => {
|
|
84
|
-
const values = []
|
|
72
|
+
const values = []
|
|
85
73
|
|
|
86
|
-
if(undefined === singleFilter.active) return null
|
|
74
|
+
if (undefined === singleFilter.active) return null
|
|
87
75
|
|
|
88
76
|
singleFilter.values.forEach((filterOption, idx) => {
|
|
89
|
-
values.push(
|
|
90
|
-
key={idx}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
})
|
|
77
|
+
values.push(
|
|
78
|
+
<option key={idx} value={filterOption}>
|
|
79
|
+
{filterOption}
|
|
80
|
+
</option>
|
|
81
|
+
)
|
|
82
|
+
})
|
|
95
83
|
|
|
96
84
|
return (
|
|
97
|
-
<section className=
|
|
85
|
+
<section className='filter-col' key={idx}>
|
|
98
86
|
{singleFilter.label.length > 0 && <label htmlFor={`filter-${idx}`}>{singleFilter.label}</label>}
|
|
99
87
|
<select
|
|
100
88
|
id={`filter-${idx}`}
|
|
101
|
-
className=
|
|
102
|
-
aria-label=
|
|
89
|
+
className='filter-select'
|
|
90
|
+
aria-label='select filter'
|
|
103
91
|
value={singleFilter.active}
|
|
104
|
-
onChange={
|
|
105
|
-
changeFilterActive(idx, val.target.value)
|
|
106
|
-
setAccessibleStatus(`Filter ${singleFilter.label} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
|
|
92
|
+
onChange={val => {
|
|
93
|
+
changeFilterActive(idx, val.target.value)
|
|
94
|
+
setAccessibleStatus(`Filter ${singleFilter.label} value has been changed to ${val.target.value}, please reference the data table to see updated values.`)
|
|
107
95
|
}}
|
|
108
96
|
>
|
|
109
97
|
{values}
|
|
110
98
|
</select>
|
|
111
99
|
</section>
|
|
112
|
-
)
|
|
113
|
-
})
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const columnLogic = legend.position === 'side' && legend.singleColumn ? 'single-column' : legend.position === 'bottom' && legend.singleRow ? 'single-row' : ''
|
|
104
|
+
|
|
105
|
+
const classNames = [`${legend.position}`, `${columnLogic}`, `cdcdataviz-sr-focusable`, `${viewport}`]
|
|
114
106
|
|
|
115
107
|
return (
|
|
116
|
-
<ErrorBoundary component=
|
|
117
|
-
<aside id=
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
(
|
|
108
|
+
<ErrorBoundary component='Sidebar'>
|
|
109
|
+
<aside id='legend' className={classNames.join(' ')} role='region' aria-label='Legend' tabIndex='0'>
|
|
110
|
+
<section className='legend-section' aria-label='Map Legend'>
|
|
111
|
+
{runtimeLegend.disabledAmt > 0 && (
|
|
121
112
|
<button
|
|
122
|
-
onClick={
|
|
123
|
-
e.preventDefault()
|
|
124
|
-
resetLegendToggles()
|
|
125
|
-
setAccessibleStatus('Legend has been reset, please reference the data table to see updated values.')
|
|
113
|
+
onClick={e => {
|
|
114
|
+
e.preventDefault()
|
|
115
|
+
resetLegendToggles()
|
|
116
|
+
setAccessibleStatus('Legend has been reset, please reference the data table to see updated values.')
|
|
126
117
|
}}
|
|
127
|
-
className=
|
|
128
|
-
>
|
|
118
|
+
className='clear btn'
|
|
119
|
+
>
|
|
120
|
+
Clear
|
|
129
121
|
</button>
|
|
130
122
|
)}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
</section>
|
|
149
|
-
{filtersList.length > 0 &&
|
|
150
|
-
<section className="filters-section" aria-label="Map Filters">
|
|
151
|
-
<span className="heading-3">Filters</span>
|
|
152
|
-
<form>
|
|
153
|
-
{filtersList}
|
|
154
|
-
</form>
|
|
123
|
+
{legend.title && <span className='heading-2'>{parse(legend.title)}</span>}
|
|
124
|
+
{legend.dynamicDescription === false && legend.description && <p>{parse(legend.description)}</p>}
|
|
125
|
+
{legend.dynamicDescription === true &&
|
|
126
|
+
runtimeFilters.map((filter, idx) => {
|
|
127
|
+
const lookupStr = `${idx},${filter.values.indexOf(String(filter.active))}`
|
|
128
|
+
|
|
129
|
+
// Do we have a custom description for this?
|
|
130
|
+
const desc = legend.descriptions[lookupStr] || ''
|
|
131
|
+
|
|
132
|
+
if (desc.length > 0) {
|
|
133
|
+
return <p key={`dynamic-description-${lookupStr}`}>{desc}</p>
|
|
134
|
+
}
|
|
135
|
+
return true
|
|
136
|
+
})}
|
|
137
|
+
<ul className={columnLogic} aria-label='Legend items'>
|
|
138
|
+
{legendList}
|
|
139
|
+
</ul>
|
|
155
140
|
</section>
|
|
156
|
-
|
|
157
|
-
|
|
141
|
+
{filtersList.length > 0 && (
|
|
142
|
+
<section className='filters-section' aria-label='Map Filters'>
|
|
143
|
+
<span className='heading-3'>Filters</span>
|
|
144
|
+
<form>{filtersList}</form>
|
|
145
|
+
</section>
|
|
146
|
+
)}
|
|
147
|
+
</aside>
|
|
158
148
|
</ErrorBoundary>
|
|
159
|
-
)
|
|
160
|
-
}
|
|
149
|
+
)
|
|
150
|
+
}
|
|
161
151
|
|
|
162
|
-
export default Sidebar
|
|
152
|
+
export default Sidebar
|