@cdc/map 4.25.3 → 4.25.6
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/.idea/map.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/dist/cdcmap.js +31254 -32242
- package/examples/hex-colors.json +3 -3
- package/examples/m2.json +32904 -0
- package/examples/private/test.json +470 -1457
- package/examples/private/{mmr.json → wastewatermap.json} +86 -115
- package/index.html +36 -63
- package/package.json +7 -19
- package/src/CdcMap.tsx +56 -1552
- package/src/CdcMapComponent.tsx +608 -0
- package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +10 -0
- package/src/_stories/CdcMap.Legend.stories.tsx +67 -0
- package/src/_stories/CdcMap.Table.stories.tsx +19 -0
- package/src/_stories/CdcMap.stories.tsx +12 -1
- package/src/_stories/UsaMap.NoData.stories.tsx +4 -4
- package/src/_stories/_mock/default-patterns.json +8 -5
- package/src/_stories/_mock/legend-bins.json +428 -0
- package/{examples/private/default-patterns.json → src/_stories/_mock/legends/legend-tests.json} +36 -131
- package/src/cdcMapComponent.styles.css +9 -0
- package/src/components/Annotation/Annotation.Draggable.tsx +27 -26
- package/src/components/Annotation/AnnotationDropdown.tsx +5 -6
- package/src/components/BubbleList.tsx +135 -49
- package/src/components/CityList.tsx +89 -87
- package/src/components/DataTable.tsx +8 -8
- package/src/components/EditorPanel/components/EditorPanel.tsx +823 -885
- package/src/components/EditorPanel/components/Error.tsx +9 -2
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +127 -141
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +55 -86
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +89 -75
- package/src/components/EditorPanel/components/editorPanel.styles.css +95 -0
- package/src/components/Geo.tsx +9 -1
- package/src/components/GoogleMap/components/GoogleMap.tsx +1 -1
- package/src/components/Legend/components/Legend.tsx +92 -87
- package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +128 -0
- package/src/components/Legend/components/LegendGroup/legend.group.css +27 -0
- package/src/components/Legend/components/LegendItem.Hex.tsx +4 -1
- package/src/components/Legend/components/index.scss +74 -17
- package/src/components/Modal.tsx +17 -7
- package/src/components/NavigationMenu.tsx +11 -9
- package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +12 -8
- package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +4 -4
- package/src/components/UsaMap/components/TerritoriesSection.tsx +33 -10
- package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +12 -10
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -14
- package/src/components/UsaMap/components/Territory/TerritoryShape.ts +2 -1
- package/src/components/UsaMap/components/UsaMap.County.tsx +138 -96
- package/src/components/UsaMap/components/UsaMap.Region.styles.css +72 -0
- package/src/components/UsaMap/components/UsaMap.Region.tsx +56 -103
- package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +10 -0
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +65 -74
- package/src/components/UsaMap/components/UsaMap.State.tsx +112 -91
- package/src/components/UsaMap/helpers/map.ts +1 -1
- package/src/components/UsaMap/helpers/shapes.ts +20 -7
- package/src/components/WorldMap/WorldMap.tsx +64 -118
- package/src/components/WorldMap/worldMap.styles.css +28 -0
- package/src/components/ZoomControls.tsx +15 -13
- package/src/components/zoomControls.styles.css +53 -0
- package/src/context.ts +17 -9
- package/src/data/initial-state.js +5 -2
- package/src/helpers/addUIDs.ts +150 -0
- package/src/helpers/applyColorToLegend.ts +39 -64
- package/src/helpers/applyLegendToRow.ts +51 -0
- package/src/helpers/colorDistributions.ts +12 -0
- package/src/helpers/constants.ts +44 -0
- package/src/helpers/displayGeoName.ts +9 -2
- package/src/helpers/formatLegendLocation.ts +3 -2
- package/src/helpers/generateColorsArray.ts +2 -1
- package/src/helpers/generateRuntimeData.ts +78 -0
- package/src/helpers/generateRuntimeFilters.ts +63 -0
- package/src/helpers/generateRuntimeLegend.ts +566 -0
- package/src/helpers/generateRuntimeLegendHash.ts +16 -15
- package/src/helpers/getColumnNames.ts +19 -0
- package/src/helpers/getMapContainerClasses.ts +23 -0
- package/src/helpers/getStatePicked.ts +8 -0
- package/src/helpers/handleMapTabbing.ts +31 -0
- package/src/helpers/hashObj.ts +1 -1
- package/src/helpers/index.ts +22 -0
- package/src/helpers/navigationHandler.ts +3 -3
- package/src/helpers/resetLegendToggles.ts +13 -0
- package/src/helpers/setBinNumbers.ts +5 -0
- package/src/helpers/sortSpecialClassesLast.ts +7 -0
- package/src/helpers/tests/getColumnNames.test.ts +52 -0
- package/src/helpers/titleCase.ts +1 -1
- package/src/helpers/toggleLegendActive.ts +25 -0
- package/src/hooks/useApplyTooltipsToGeo.tsx +51 -0
- package/src/hooks/useColumnsRequiredChecker.ts +51 -0
- package/src/hooks/useGeoClickHandler.ts +45 -0
- package/src/hooks/useLegendSeparators.ts +26 -0
- package/src/hooks/useMapLayers.tsx +34 -60
- package/src/hooks/useModal.ts +22 -0
- package/src/hooks/useResizeObserver.ts +4 -5
- package/src/hooks/useStateZoom.tsx +52 -75
- package/src/hooks/useTooltip.ts +2 -3
- package/src/index.jsx +3 -9
- package/src/scss/editor-panel.scss +3 -99
- package/src/scss/main.scss +1 -19
- package/src/scss/map.scss +15 -220
- package/src/store/map.actions.ts +46 -0
- package/src/store/map.reducer.ts +96 -0
- package/src/types/Annotations.ts +24 -0
- package/src/types/MapConfig.ts +23 -3
- package/src/types/MapContext.ts +36 -35
- package/src/types/Modal.ts +1 -0
- package/src/types/RuntimeData.ts +3 -0
- package/examples/private/DEV-9644.json +0 -184
- package/examples/private/DEV-9989.json +0 -229
- package/examples/private/ardi.json +0 -180
- package/examples/private/colors 2.json +0 -416
- package/examples/private/colors.json +0 -416
- package/examples/private/colors.json.zip +0 -0
- package/examples/private/customColors.json +0 -45348
- package/examples/test.json +0 -183
- package/src/helpers/closeModal.ts +0 -9
- package/src/scss/btn.scss +0 -69
- package/src/scss/filters.scss +0 -27
- package/src/scss/variables.scss +0 -1
- /package/src/hooks/{useActiveElement.js → useActiveElement.ts} +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
.map-container.world aside.side {
|
|
5
5
|
border-top: 0;
|
|
6
6
|
}
|
|
7
|
+
|
|
7
8
|
@include breakpointClass(md) {
|
|
8
9
|
.map-container.world aside.side {
|
|
9
10
|
border-top: var(--cool-gray-10) 1px solid;
|
|
@@ -19,10 +20,12 @@
|
|
|
19
20
|
border-radius: 6px;
|
|
20
21
|
|
|
21
22
|
@include breakpointClass(md) {
|
|
23
|
+
|
|
22
24
|
&.bottom,
|
|
23
25
|
&.top {
|
|
24
26
|
border: var(--cool-gray-10) 1px solid;
|
|
25
27
|
}
|
|
28
|
+
|
|
26
29
|
&.side {
|
|
27
30
|
z-index: 1;
|
|
28
31
|
box-sizing: content-box;
|
|
@@ -40,7 +43,8 @@
|
|
|
40
43
|
display: block;
|
|
41
44
|
column-count: 2;
|
|
42
45
|
column-fill: balance;
|
|
43
|
-
|
|
46
|
+
|
|
47
|
+
&>li {
|
|
44
48
|
white-space: nowrap;
|
|
45
49
|
}
|
|
46
50
|
}
|
|
@@ -53,6 +57,7 @@
|
|
|
53
57
|
flex-wrap: wrap;
|
|
54
58
|
}
|
|
55
59
|
}
|
|
60
|
+
|
|
56
61
|
&.no-border {
|
|
57
62
|
border: none;
|
|
58
63
|
}
|
|
@@ -70,6 +75,10 @@
|
|
|
70
75
|
.legend-container {
|
|
71
76
|
position: relative;
|
|
72
77
|
|
|
78
|
+
.legend-container__li--disabled {
|
|
79
|
+
opacity: 0.4;
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
.tspan {
|
|
74
83
|
font-size: var(--legend-item-font-size) !important;
|
|
75
84
|
}
|
|
@@ -79,14 +88,16 @@
|
|
|
79
88
|
font-weight: var(--legend-title-font-weight);
|
|
80
89
|
padding-bottom: 0;
|
|
81
90
|
display: inline-block;
|
|
82
|
-
color: black;
|
|
83
91
|
}
|
|
92
|
+
|
|
84
93
|
.legend-container__description {
|
|
85
94
|
font-size: var(--legend-description-font-size);
|
|
86
95
|
}
|
|
96
|
+
|
|
87
97
|
.legend-container__reset-button {
|
|
88
98
|
margin-top: 1em;
|
|
89
99
|
}
|
|
100
|
+
|
|
90
101
|
p {
|
|
91
102
|
line-height: 1.4em;
|
|
92
103
|
}
|
|
@@ -96,9 +107,11 @@
|
|
|
96
107
|
row-gap: var(--space-between-legend-item-rows);
|
|
97
108
|
column-gap: var(--space-between-legend-item-columns);
|
|
98
109
|
}
|
|
99
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
.legend-container__ul:not(.single-row, .legend-container__ul--single-column) {
|
|
100
113
|
list-style: none;
|
|
101
|
-
display: grid;
|
|
114
|
+
display: grid !important;
|
|
102
115
|
grid-template-columns: 1fr;
|
|
103
116
|
|
|
104
117
|
@include breakpoint(md) {
|
|
@@ -111,25 +124,51 @@
|
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
&.vertical-sorted {
|
|
114
|
-
|
|
127
|
+
// Remove the grid overrides - let the existing column rules handle this
|
|
128
|
+
display: block !important; // Switch from grid to block to enable columns
|
|
129
|
+
|
|
130
|
+
@include breakpoint(md) {
|
|
131
|
+
column-count: 2;
|
|
132
|
+
column-fill: balance;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Add spacing between legend items in vertical sorted mode
|
|
136
|
+
.legend-container__li {
|
|
137
|
+
margin-bottom: var(--space-between-legend-item-rows);
|
|
138
|
+
|
|
139
|
+
&:last-child {
|
|
140
|
+
margin-bottom: 0; // Remove margin from last item
|
|
141
|
+
}
|
|
142
|
+
}
|
|
115
143
|
}
|
|
116
144
|
|
|
117
145
|
&:not(.vertical-sorted, .legend-container__ul--single-column, .single-row) {
|
|
118
146
|
width: 100%;
|
|
119
147
|
}
|
|
148
|
+
|
|
120
149
|
.legend-container__li {
|
|
121
|
-
|
|
122
|
-
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 0.5em;
|
|
153
|
+
width: 100%;
|
|
123
154
|
padding-right: 1em;
|
|
124
155
|
vertical-align: middle;
|
|
125
156
|
transition: 0.1s opacity;
|
|
126
|
-
display: flex;
|
|
127
157
|
cursor: pointer;
|
|
128
|
-
white-space: wrap;
|
|
129
158
|
flex-grow: 1;
|
|
159
|
+
white-space: nowrap; // Prevents label wrapping
|
|
160
|
+
|
|
161
|
+
.legend-item {
|
|
162
|
+
display: flex;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
align-items: center;
|
|
165
|
+
flex-shrink: 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
130
168
|
&:last-child {
|
|
131
169
|
margin-bottom: 0;
|
|
132
170
|
}
|
|
171
|
+
|
|
133
172
|
@include breakpoint(md) {
|
|
134
173
|
white-space: nowrap;
|
|
135
174
|
}
|
|
@@ -137,6 +176,7 @@
|
|
|
137
176
|
&.legend-container__li--disabled {
|
|
138
177
|
opacity: 0.4;
|
|
139
178
|
}
|
|
179
|
+
|
|
140
180
|
&.legend-container__li--not-disabled {
|
|
141
181
|
outline: 1px solid #005ea2;
|
|
142
182
|
outline-offset: 5px;
|
|
@@ -144,6 +184,7 @@
|
|
|
144
184
|
}
|
|
145
185
|
}
|
|
146
186
|
}
|
|
187
|
+
|
|
147
188
|
.legend-container__ul.single-row {
|
|
148
189
|
width: 100%;
|
|
149
190
|
cursor: pointer;
|
|
@@ -154,12 +195,13 @@
|
|
|
154
195
|
justify-content: flex-start;
|
|
155
196
|
flex-wrap: wrap;
|
|
156
197
|
|
|
157
|
-
|
|
198
|
+
&>li {
|
|
158
199
|
white-space: wrap;
|
|
159
200
|
display: flex;
|
|
160
201
|
justify-content: center;
|
|
161
202
|
align-items: center;
|
|
162
203
|
vertical-align: middle;
|
|
204
|
+
|
|
163
205
|
@include breakpoint(md) {
|
|
164
206
|
white-space: nowrap;
|
|
165
207
|
}
|
|
@@ -169,6 +211,7 @@
|
|
|
169
211
|
}
|
|
170
212
|
}
|
|
171
213
|
}
|
|
214
|
+
|
|
172
215
|
.legend-container__ul.patterns-only {
|
|
173
216
|
margin-top: 10px;
|
|
174
217
|
}
|
|
@@ -191,19 +234,24 @@
|
|
|
191
234
|
@include breakpointClass(md) {
|
|
192
235
|
width: 25%;
|
|
193
236
|
min-width: 200px;
|
|
237
|
+
|
|
194
238
|
.legend-section ul {
|
|
195
239
|
flex-direction: column;
|
|
240
|
+
|
|
196
241
|
li {
|
|
197
242
|
width: 100%;
|
|
243
|
+
|
|
198
244
|
&:nth-last-of-type(-n + 2) {
|
|
199
245
|
padding-bottom: 1em;
|
|
200
246
|
}
|
|
247
|
+
|
|
201
248
|
&:last-child {
|
|
202
249
|
padding-bottom: 0;
|
|
203
250
|
}
|
|
204
251
|
}
|
|
205
252
|
}
|
|
206
253
|
}
|
|
254
|
+
|
|
207
255
|
li {
|
|
208
256
|
width: 100%;
|
|
209
257
|
}
|
|
@@ -213,6 +261,7 @@
|
|
|
213
261
|
.legend-container ul:not(.single-row) {
|
|
214
262
|
align-items: flex-start;
|
|
215
263
|
justify-content: space-between;
|
|
264
|
+
|
|
216
265
|
li {
|
|
217
266
|
flex-grow: 1;
|
|
218
267
|
padding-right: 0.5em;
|
|
@@ -222,24 +271,29 @@
|
|
|
222
271
|
|
|
223
272
|
.filters-section {
|
|
224
273
|
padding: 0 1em 1em;
|
|
274
|
+
|
|
225
275
|
.heading-3 {
|
|
226
276
|
font-weight: bold;
|
|
227
277
|
margin-bottom: 0.5em;
|
|
228
278
|
}
|
|
279
|
+
|
|
229
280
|
form {
|
|
230
281
|
margin-top: 0.5em;
|
|
231
282
|
line-height: 2em;
|
|
232
283
|
display: flex;
|
|
233
284
|
align-items: flex-end;
|
|
234
|
-
|
|
285
|
+
|
|
286
|
+
section+section {
|
|
235
287
|
margin-left: 0.75em;
|
|
236
288
|
}
|
|
289
|
+
|
|
237
290
|
select {
|
|
238
291
|
display: block;
|
|
239
292
|
font-size: 1em;
|
|
240
293
|
}
|
|
241
294
|
}
|
|
242
295
|
}
|
|
296
|
+
|
|
243
297
|
& .shape-container {
|
|
244
298
|
&.single-row {
|
|
245
299
|
display: flex;
|
|
@@ -248,26 +302,29 @@
|
|
|
248
302
|
justify-content: flex-start;
|
|
249
303
|
flex-wrap: wrap;
|
|
250
304
|
|
|
251
|
-
|
|
305
|
+
&>div {
|
|
252
306
|
margin-right: 2em;
|
|
253
307
|
}
|
|
254
|
-
|
|
308
|
+
|
|
309
|
+
&>div:last-child {
|
|
255
310
|
margin-right: 0;
|
|
256
311
|
}
|
|
257
312
|
}
|
|
258
313
|
|
|
259
|
-
|
|
314
|
+
&>div {
|
|
260
315
|
display: flex;
|
|
261
316
|
flex-direction: row;
|
|
262
317
|
}
|
|
263
|
-
|
|
318
|
+
|
|
319
|
+
& div>svg {
|
|
264
320
|
width: 25px;
|
|
265
321
|
height: 32px;
|
|
266
322
|
}
|
|
267
|
-
|
|
323
|
+
|
|
324
|
+
& div>p {
|
|
268
325
|
white-space: nowrap;
|
|
269
326
|
margin-top: 1px;
|
|
270
327
|
}
|
|
271
328
|
}
|
|
272
329
|
}
|
|
273
|
-
}
|
|
330
|
+
}
|
package/src/components/Modal.tsx
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { useContext } from 'react'
|
|
2
|
-
import
|
|
3
|
-
import ConfigContext from '../context'
|
|
2
|
+
import ConfigContext, { MapDispatchContext } from '../context'
|
|
4
3
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
4
|
+
import useApplyTooltipsToGeo from '../hooks/useApplyTooltipsToGeo'
|
|
5
|
+
import { MapContext } from '../types/MapContext'
|
|
5
6
|
|
|
6
7
|
const Modal = () => {
|
|
7
|
-
const {
|
|
8
|
-
const { capitalizeLabels } =
|
|
8
|
+
const { content, config, currentViewport: viewport } = useContext<MapContext>(ConfigContext)
|
|
9
|
+
const { capitalizeLabels } = config.tooltips
|
|
10
|
+
const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
|
|
9
11
|
const tooltip = applyTooltipsToGeo(content.geoName, content.keyedData, 'jsx')
|
|
10
|
-
const
|
|
11
|
-
const legendColors = applyLegendToRow(content.keyedData)
|
|
12
|
+
const dispatch = useContext(MapDispatchContext)
|
|
12
13
|
|
|
13
14
|
return (
|
|
14
15
|
<section
|
|
@@ -18,7 +19,16 @@ const Modal = () => {
|
|
|
18
19
|
aria-hidden='true'
|
|
19
20
|
>
|
|
20
21
|
<div className='content'>{tooltip}</div>
|
|
21
|
-
<Icon
|
|
22
|
+
<Icon
|
|
23
|
+
display='close'
|
|
24
|
+
alt='Close Modal'
|
|
25
|
+
size={20}
|
|
26
|
+
color='#000'
|
|
27
|
+
className='modal-close'
|
|
28
|
+
onClick={() => {
|
|
29
|
+
dispatch({ type: 'SET_MODAL', payload: null })
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
22
32
|
</section>
|
|
23
33
|
)
|
|
24
34
|
}
|
|
@@ -24,7 +24,7 @@ const NavigationMenu = ({ data, navigationHandler, options, columns, displayGeoN
|
|
|
24
24
|
navGo = 'Ir'
|
|
25
25
|
break
|
|
26
26
|
default:
|
|
27
|
-
navSelect = 'Select
|
|
27
|
+
navSelect = 'Select a Location'
|
|
28
28
|
navGo = 'Go'
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -55,15 +55,17 @@ const NavigationMenu = ({ data, navigationHandler, options, columns, displayGeoN
|
|
|
55
55
|
<form onSubmit={handleSubmit} type='get'>
|
|
56
56
|
<label htmlFor={mapTabbingID.replace('#', '')}>
|
|
57
57
|
<div className='select-heading'>{navSelect}</div>
|
|
58
|
-
<
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
{key}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
<div className='d-flex'>
|
|
59
|
+
<select value={activeGeo} id={mapTabbingID.replace('#', '')} onChange={e => setActiveGeo(e.target.value)}>
|
|
60
|
+
{Object.keys(dropdownItems).map(key => (
|
|
61
|
+
<option key={key} value={key}>
|
|
62
|
+
{key}
|
|
63
|
+
</option>
|
|
64
|
+
))}
|
|
65
|
+
</select>
|
|
66
|
+
<input type='submit' value={navGo} className={`${options.headerColor} btn`} id='cdcnavmap-dropdown-go' />
|
|
67
|
+
</div>
|
|
65
68
|
</label>
|
|
66
|
-
<input type='submit' value={navGo} className={`${options.headerColor} btn`} id='cdcnavmap-dropdown-go' />
|
|
67
69
|
</form>
|
|
68
70
|
</section>
|
|
69
71
|
)
|
|
@@ -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
|
|
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 {
|
|
16
|
-
|
|
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
|
-
(
|
|
59
|
-
|
|
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[
|
|
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 {
|
|
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 ===
|
|
16
|
+
return s.properties.name === config.general.statePicked.stateName
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
const geoStrokeColor = getGeoStrokeColor(
|
|
20
|
-
const geoFillColor = getGeoFillColor(
|
|
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.
|
|
50
|
-
<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
|
|
56
|
-
<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 {
|
|
48
|
+
const { config } = useContext<MapContext>(ConfigContext)
|
|
48
49
|
|
|
49
|
-
const isHex =
|
|
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
|
-
{
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
-
{
|
|
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:
|
|
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
|
-
{
|
|
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 {
|
|
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={
|
|
45
|
-
|
|
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
|
-
{
|
|
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={
|
|
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={
|
|
109
|
-
|
|
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
|
-
|
|
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
|
}
|