@cdc/map 4.25.5-1 → 4.25.6-1
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/LICENSE +201 -0
- package/dist/cdcmap.js +19455 -18752
- package/examples/private/m.json +427 -0
- package/index.html +33 -32
- package/package.json +7 -13
- package/src/CdcMap.tsx +10 -2
- package/src/CdcMapComponent.tsx +23 -9
- package/src/_stories/CdcMap.Table.stories.tsx +19 -0
- package/src/_stories/CdcMap.stories.tsx +8 -0
- package/src/_stories/_mock/default-patterns.json +8 -5
- package/src/_stories/_mock/legend-bins.json +428 -0
- package/src/components/EditorPanel/components/EditorPanel.tsx +120 -76
- package/src/components/Legend/components/index.scss +56 -11
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +16 -18
- package/src/helpers/addUIDs.ts +1 -2
- package/src/helpers/formatLegendLocation.ts +3 -2
- package/src/helpers/generateRuntimeData.ts +6 -2
- package/src/helpers/generateRuntimeLegend.ts +88 -59
- package/src/helpers/getStatePicked.ts +8 -0
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'
|
|
12
12
|
import { useDebounce } from 'use-debounce'
|
|
13
13
|
import _ from 'lodash'
|
|
14
|
-
// import ReactTags from 'react-tag-autocomplete'
|
|
15
14
|
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
|
16
15
|
import Panels from './Panels'
|
|
17
16
|
import Layout from '@cdc/core/components/Layout'
|
|
@@ -47,8 +46,14 @@ import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/In
|
|
|
47
46
|
import useColumnsRequiredChecker from '../../../hooks/useColumnsRequiredChecker'
|
|
48
47
|
import { addUIDs, HEADER_COLORS } from '../../../helpers'
|
|
49
48
|
import './editorPanel.styles.css'
|
|
49
|
+
import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
|
|
50
|
+
import { Datasets } from '@cdc/core/types/DataSet'
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
type MapEditorPanelProps = {
|
|
53
|
+
datasets?: Datasets
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
52
57
|
const {
|
|
53
58
|
setParentConfig,
|
|
54
59
|
isDashboard,
|
|
@@ -1099,9 +1104,8 @@ const EditorPanel = () => {
|
|
|
1099
1104
|
</span>
|
|
1100
1105
|
<ul className='geo-buttons d-grid' style={{ gridTemplateColumns: 'repeat(2, 1fr)', gap: '8px' }}>
|
|
1101
1106
|
<button
|
|
1102
|
-
className={`${
|
|
1103
|
-
|
|
1104
|
-
} full-width`}
|
|
1107
|
+
className={`${config.general.geoType === 'us' || config.general.geoType === 'us-county' ? 'active' : ''
|
|
1108
|
+
} full-width`}
|
|
1105
1109
|
onClick={e => {
|
|
1106
1110
|
e.preventDefault()
|
|
1107
1111
|
handleEditorChanges('geoType', 'us')
|
|
@@ -2236,7 +2240,7 @@ const EditorPanel = () => {
|
|
|
2236
2240
|
checked={legend.singleColumn}
|
|
2237
2241
|
onChange={event => {
|
|
2238
2242
|
const _newConfig = _.cloneDeep(config)
|
|
2239
|
-
_newConfig.legend.singleColumn =
|
|
2243
|
+
_newConfig.legend.singleColumn = event.target.checked
|
|
2240
2244
|
_newConfig.legend.singleRow = false
|
|
2241
2245
|
_newConfig.legend.verticalSorted = false
|
|
2242
2246
|
|
|
@@ -2253,7 +2257,7 @@ const EditorPanel = () => {
|
|
|
2253
2257
|
checked={legend.singleRow}
|
|
2254
2258
|
onChange={event => {
|
|
2255
2259
|
const _newConfig = _.cloneDeep(config)
|
|
2256
|
-
_newConfig.legend.singleRow =
|
|
2260
|
+
_newConfig.legend.singleRow = event.target.checked
|
|
2257
2261
|
_newConfig.legend.singleColumn = false
|
|
2258
2262
|
_newConfig.legend.verticalSorted = false
|
|
2259
2263
|
|
|
@@ -2454,20 +2458,17 @@ const EditorPanel = () => {
|
|
|
2454
2458
|
<DynamicDesc value={legend.descriptions[String(activeFilterValueForDescription)]} />
|
|
2455
2459
|
</label>
|
|
2456
2460
|
<label>
|
|
2457
|
-
<
|
|
2461
|
+
<Select
|
|
2462
|
+
label='Filter Value'
|
|
2458
2463
|
value={String(activeFilterValueForDescription)}
|
|
2464
|
+
options={filterValueOptionList.map(arr => ({
|
|
2465
|
+
value: arr,
|
|
2466
|
+
label: displayFilterLegendValue(arr)
|
|
2467
|
+
}))}
|
|
2459
2468
|
onChange={event => {
|
|
2460
2469
|
handleEditorChanges('changeActiveFilterValue', event.target.value)
|
|
2461
2470
|
}}
|
|
2462
|
-
|
|
2463
|
-
{filterValueOptionList.map((arr, i) => {
|
|
2464
|
-
return (
|
|
2465
|
-
<option value={arr} key={i}>
|
|
2466
|
-
{displayFilterLegendValue(arr)}
|
|
2467
|
-
</option>
|
|
2468
|
-
)
|
|
2469
|
-
})}
|
|
2470
|
-
</select>
|
|
2471
|
+
/>
|
|
2471
2472
|
</label>
|
|
2472
2473
|
</React.Fragment>
|
|
2473
2474
|
)}
|
|
@@ -2529,16 +2530,30 @@ const EditorPanel = () => {
|
|
|
2529
2530
|
</AccordionItem>
|
|
2530
2531
|
)}
|
|
2531
2532
|
{'navigation' !== config.general.type && (
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2533
|
+
<>
|
|
2534
|
+
<AccordionItem>
|
|
2535
|
+
{/* Filters */}
|
|
2536
|
+
<AccordionItemHeading>
|
|
2537
|
+
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2538
|
+
</AccordionItemHeading>
|
|
2539
|
+
<AccordionItemPanel>
|
|
2540
|
+
<VizFilterEditor
|
|
2541
|
+
config={config}
|
|
2542
|
+
updateField={updateField}
|
|
2543
|
+
rawData={config.data}
|
|
2544
|
+
hasFootnotes={isDashboard}
|
|
2545
|
+
/>
|
|
2546
|
+
</AccordionItemPanel>
|
|
2547
|
+
</AccordionItem>
|
|
2548
|
+
<AccordionItem>
|
|
2549
|
+
<AccordionItemHeading>
|
|
2550
|
+
<AccordionItemButton>Footnotes</AccordionItemButton>
|
|
2551
|
+
</AccordionItemHeading>
|
|
2552
|
+
<AccordionItemPanel>
|
|
2553
|
+
<FootnotesEditor config={config} updateField={updateField} datasets={datasets} />
|
|
2554
|
+
</AccordionItemPanel>
|
|
2555
|
+
</AccordionItem>
|
|
2556
|
+
</>
|
|
2542
2557
|
)}
|
|
2543
2558
|
{'navigation' !== config.general.type && (
|
|
2544
2559
|
<AccordionItem>
|
|
@@ -2609,6 +2624,35 @@ const EditorPanel = () => {
|
|
|
2609
2624
|
</Tooltip>
|
|
2610
2625
|
</span>
|
|
2611
2626
|
</label>
|
|
2627
|
+
<label className='checkbox'>
|
|
2628
|
+
<input
|
|
2629
|
+
type='checkbox'
|
|
2630
|
+
checked={config.table.showNonGeoData}
|
|
2631
|
+
onChange={event => {
|
|
2632
|
+
setConfig({
|
|
2633
|
+
...config,
|
|
2634
|
+
table: {
|
|
2635
|
+
...config.table,
|
|
2636
|
+
showNonGeoData: event.target.checked
|
|
2637
|
+
}
|
|
2638
|
+
})
|
|
2639
|
+
}}
|
|
2640
|
+
/>
|
|
2641
|
+
<span className='edit-label column-heading'>
|
|
2642
|
+
Show Non Geographic Data
|
|
2643
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2644
|
+
<Tooltip.Target>
|
|
2645
|
+
<Icon
|
|
2646
|
+
display='question'
|
|
2647
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2648
|
+
/>
|
|
2649
|
+
</Tooltip.Target>
|
|
2650
|
+
<Tooltip.Content>
|
|
2651
|
+
<p>Show any data not associated with a geographic location</p>
|
|
2652
|
+
</Tooltip.Content>
|
|
2653
|
+
</Tooltip>
|
|
2654
|
+
</span>
|
|
2655
|
+
</label>
|
|
2612
2656
|
<TextField
|
|
2613
2657
|
value={table.indexLabel || ''}
|
|
2614
2658
|
updateField={updateField}
|
|
@@ -3066,19 +3110,19 @@ const EditorPanel = () => {
|
|
|
3066
3110
|
)}
|
|
3067
3111
|
{(config.general.geoType === 'world' ||
|
|
3068
3112
|
(config.general.geoType === 'us' && config.general.type === 'bubble')) && (
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3113
|
+
<label className='checkbox'>
|
|
3114
|
+
<input
|
|
3115
|
+
type='checkbox'
|
|
3116
|
+
checked={config.visual.showBubbleZeros}
|
|
3117
|
+
onChange={event => {
|
|
3118
|
+
const _newConfig = _.cloneDeep(config)
|
|
3119
|
+
_newConfig.visual.showBubbleZeros = event.target.checked
|
|
3120
|
+
setConfig(_newConfig)
|
|
3121
|
+
}}
|
|
3122
|
+
/>
|
|
3123
|
+
<span className='edit-label'>Show Data with Zero's on Bubble Map</span>
|
|
3124
|
+
</label>
|
|
3125
|
+
)}
|
|
3082
3126
|
{(config.general.geoType === 'world' || config.general.geoType === 'single-state') && (
|
|
3083
3127
|
<label className='checkbox'>
|
|
3084
3128
|
<input
|
|
@@ -3112,42 +3156,42 @@ const EditorPanel = () => {
|
|
|
3112
3156
|
{(config.general.geoType === 'us' ||
|
|
3113
3157
|
config.general.geoType === 'us-county' ||
|
|
3114
3158
|
config.general.geoType === 'world') && (
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3159
|
+
<>
|
|
3160
|
+
<label>
|
|
3161
|
+
<span className='edit-label'>Default City Style</span>
|
|
3162
|
+
<select
|
|
3163
|
+
value={config.visual.cityStyle || false}
|
|
3164
|
+
onChange={event => {
|
|
3165
|
+
handleEditorChanges('handleCityStyle', event.target.value)
|
|
3166
|
+
}}
|
|
3167
|
+
>
|
|
3168
|
+
<option value='circle'>Circle</option>
|
|
3169
|
+
<option value='pin'>Pin</option>
|
|
3170
|
+
<option value='square'>Square</option>
|
|
3171
|
+
<option value='triangle'>Triangle</option>
|
|
3172
|
+
<option value='diamond'>Diamond</option>
|
|
3173
|
+
<option value='star'>Star</option>
|
|
3174
|
+
</select>
|
|
3175
|
+
</label>
|
|
3176
|
+
<TextField
|
|
3177
|
+
value={config.visual.cityStyleLabel}
|
|
3178
|
+
section='visual'
|
|
3179
|
+
fieldName='cityStyleLabel'
|
|
3180
|
+
label='Label (Optional) '
|
|
3181
|
+
updateField={updateField}
|
|
3182
|
+
tooltip={
|
|
3183
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
3184
|
+
<Tooltip.Target>
|
|
3185
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
3186
|
+
</Tooltip.Target>
|
|
3187
|
+
<Tooltip.Content>
|
|
3188
|
+
<p>When a label is provided, the default city style will appear in the legend.</p>
|
|
3189
|
+
</Tooltip.Content>
|
|
3190
|
+
</Tooltip>
|
|
3191
|
+
}
|
|
3192
|
+
/>
|
|
3193
|
+
</>
|
|
3194
|
+
)}
|
|
3151
3195
|
{/* <AdditionalCityStyles /> */}
|
|
3152
3196
|
<>
|
|
3153
3197
|
{config.visual.additionalCityStyles.length > 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
|
}
|
|
@@ -84,12 +89,15 @@
|
|
|
84
89
|
padding-bottom: 0;
|
|
85
90
|
display: inline-block;
|
|
86
91
|
}
|
|
92
|
+
|
|
87
93
|
.legend-container__description {
|
|
88
94
|
font-size: var(--legend-description-font-size);
|
|
89
95
|
}
|
|
96
|
+
|
|
90
97
|
.legend-container__reset-button {
|
|
91
98
|
margin-top: 1em;
|
|
92
99
|
}
|
|
100
|
+
|
|
93
101
|
p {
|
|
94
102
|
line-height: 1.4em;
|
|
95
103
|
}
|
|
@@ -99,7 +107,9 @@
|
|
|
99
107
|
row-gap: var(--space-between-legend-item-rows);
|
|
100
108
|
column-gap: var(--space-between-legend-item-columns);
|
|
101
109
|
}
|
|
102
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
.legend-container__ul:not(.single-row, .legend-container__ul--single-column) {
|
|
103
113
|
list-style: none;
|
|
104
114
|
display: grid !important;
|
|
105
115
|
grid-template-columns: 1fr;
|
|
@@ -114,12 +124,28 @@
|
|
|
114
124
|
}
|
|
115
125
|
|
|
116
126
|
&.vertical-sorted {
|
|
117
|
-
|
|
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
|
+
}
|
|
118
143
|
}
|
|
119
144
|
|
|
120
145
|
&:not(.vertical-sorted, .legend-container__ul--single-column, .single-row) {
|
|
121
146
|
width: 100%;
|
|
122
147
|
}
|
|
148
|
+
|
|
123
149
|
.legend-container__li {
|
|
124
150
|
display: flex;
|
|
125
151
|
align-items: center;
|
|
@@ -142,6 +168,7 @@
|
|
|
142
168
|
&:last-child {
|
|
143
169
|
margin-bottom: 0;
|
|
144
170
|
}
|
|
171
|
+
|
|
145
172
|
@include breakpoint(md) {
|
|
146
173
|
white-space: nowrap;
|
|
147
174
|
}
|
|
@@ -149,6 +176,7 @@
|
|
|
149
176
|
&.legend-container__li--disabled {
|
|
150
177
|
opacity: 0.4;
|
|
151
178
|
}
|
|
179
|
+
|
|
152
180
|
&.legend-container__li--not-disabled {
|
|
153
181
|
outline: 1px solid #005ea2;
|
|
154
182
|
outline-offset: 5px;
|
|
@@ -156,6 +184,7 @@
|
|
|
156
184
|
}
|
|
157
185
|
}
|
|
158
186
|
}
|
|
187
|
+
|
|
159
188
|
.legend-container__ul.single-row {
|
|
160
189
|
width: 100%;
|
|
161
190
|
cursor: pointer;
|
|
@@ -166,12 +195,13 @@
|
|
|
166
195
|
justify-content: flex-start;
|
|
167
196
|
flex-wrap: wrap;
|
|
168
197
|
|
|
169
|
-
|
|
198
|
+
&>li {
|
|
170
199
|
white-space: wrap;
|
|
171
200
|
display: flex;
|
|
172
201
|
justify-content: center;
|
|
173
202
|
align-items: center;
|
|
174
203
|
vertical-align: middle;
|
|
204
|
+
|
|
175
205
|
@include breakpoint(md) {
|
|
176
206
|
white-space: nowrap;
|
|
177
207
|
}
|
|
@@ -181,6 +211,7 @@
|
|
|
181
211
|
}
|
|
182
212
|
}
|
|
183
213
|
}
|
|
214
|
+
|
|
184
215
|
.legend-container__ul.patterns-only {
|
|
185
216
|
margin-top: 10px;
|
|
186
217
|
}
|
|
@@ -203,19 +234,24 @@
|
|
|
203
234
|
@include breakpointClass(md) {
|
|
204
235
|
width: 25%;
|
|
205
236
|
min-width: 200px;
|
|
237
|
+
|
|
206
238
|
.legend-section ul {
|
|
207
239
|
flex-direction: column;
|
|
240
|
+
|
|
208
241
|
li {
|
|
209
242
|
width: 100%;
|
|
243
|
+
|
|
210
244
|
&:nth-last-of-type(-n + 2) {
|
|
211
245
|
padding-bottom: 1em;
|
|
212
246
|
}
|
|
247
|
+
|
|
213
248
|
&:last-child {
|
|
214
249
|
padding-bottom: 0;
|
|
215
250
|
}
|
|
216
251
|
}
|
|
217
252
|
}
|
|
218
253
|
}
|
|
254
|
+
|
|
219
255
|
li {
|
|
220
256
|
width: 100%;
|
|
221
257
|
}
|
|
@@ -225,6 +261,7 @@
|
|
|
225
261
|
.legend-container ul:not(.single-row) {
|
|
226
262
|
align-items: flex-start;
|
|
227
263
|
justify-content: space-between;
|
|
264
|
+
|
|
228
265
|
li {
|
|
229
266
|
flex-grow: 1;
|
|
230
267
|
padding-right: 0.5em;
|
|
@@ -234,24 +271,29 @@
|
|
|
234
271
|
|
|
235
272
|
.filters-section {
|
|
236
273
|
padding: 0 1em 1em;
|
|
274
|
+
|
|
237
275
|
.heading-3 {
|
|
238
276
|
font-weight: bold;
|
|
239
277
|
margin-bottom: 0.5em;
|
|
240
278
|
}
|
|
279
|
+
|
|
241
280
|
form {
|
|
242
281
|
margin-top: 0.5em;
|
|
243
282
|
line-height: 2em;
|
|
244
283
|
display: flex;
|
|
245
284
|
align-items: flex-end;
|
|
246
|
-
|
|
285
|
+
|
|
286
|
+
section+section {
|
|
247
287
|
margin-left: 0.75em;
|
|
248
288
|
}
|
|
289
|
+
|
|
249
290
|
select {
|
|
250
291
|
display: block;
|
|
251
292
|
font-size: 1em;
|
|
252
293
|
}
|
|
253
294
|
}
|
|
254
295
|
}
|
|
296
|
+
|
|
255
297
|
& .shape-container {
|
|
256
298
|
&.single-row {
|
|
257
299
|
display: flex;
|
|
@@ -260,26 +302,29 @@
|
|
|
260
302
|
justify-content: flex-start;
|
|
261
303
|
flex-wrap: wrap;
|
|
262
304
|
|
|
263
|
-
|
|
305
|
+
&>div {
|
|
264
306
|
margin-right: 2em;
|
|
265
307
|
}
|
|
266
|
-
|
|
308
|
+
|
|
309
|
+
&>div:last-child {
|
|
267
310
|
margin-right: 0;
|
|
268
311
|
}
|
|
269
312
|
}
|
|
270
313
|
|
|
271
|
-
|
|
314
|
+
&>div {
|
|
272
315
|
display: flex;
|
|
273
316
|
flex-direction: row;
|
|
274
317
|
}
|
|
275
|
-
|
|
318
|
+
|
|
319
|
+
& div>svg {
|
|
276
320
|
width: 25px;
|
|
277
321
|
height: 32px;
|
|
278
322
|
}
|
|
279
|
-
|
|
323
|
+
|
|
324
|
+
& div>p {
|
|
280
325
|
white-space: nowrap;
|
|
281
326
|
margin-top: 1px;
|
|
282
327
|
}
|
|
283
328
|
}
|
|
284
329
|
}
|
|
285
|
-
}
|
|
330
|
+
}
|
|
@@ -23,25 +23,28 @@ import { titleCase, handleMapAriaLabels, getGeoStrokeColor, MAX_ZOOM_LEVEL } fro
|
|
|
23
23
|
import { getTopoData, getCurrentTopoYear, isTopoReady } from '../helpers/map'
|
|
24
24
|
import useGeoClickHandler from '../../../hooks/useGeoClickHandler'
|
|
25
25
|
import { SVG_WIDTH, SVG_HEIGHT, SVG_PADDING, SVG_VIEWBOX } from '../../../helpers'
|
|
26
|
+
import _ from 'lodash'
|
|
27
|
+
import { getStatePicked } from '../../../helpers/getStatePicked'
|
|
26
28
|
|
|
27
|
-
const SingleStateMap = () => {
|
|
29
|
+
const SingleStateMap: React.FC = () => {
|
|
28
30
|
const {
|
|
29
31
|
config,
|
|
30
32
|
setSharedFilterValue,
|
|
31
33
|
isFilterValueSupported,
|
|
32
34
|
runtimeFilters,
|
|
35
|
+
runtimeData,
|
|
33
36
|
tooltipId,
|
|
34
37
|
position,
|
|
35
|
-
stateToShow,
|
|
36
38
|
topoData,
|
|
37
39
|
scale,
|
|
38
|
-
translate
|
|
39
|
-
legendMemo,
|
|
40
|
-
legendSpecialClassLastMemo
|
|
40
|
+
translate
|
|
41
41
|
} = useContext<MapContext>(ConfigContext)
|
|
42
42
|
|
|
43
43
|
const dispatch = useContext(MapDispatchContext)
|
|
44
|
-
const { handleMoveEnd, handleZoomIn, handleZoomOut, handleReset, projection
|
|
44
|
+
const { handleMoveEnd, handleZoomIn, handleZoomOut, handleReset, projection } = useStateZoom(topoData)
|
|
45
|
+
const statePicked = getStatePicked(config, runtimeData)
|
|
46
|
+
const stateToShow = topoData?.states?.find(s => s.properties.name === statePicked.stateName)
|
|
47
|
+
|
|
45
48
|
const { geoClickHandler } = useGeoClickHandler()
|
|
46
49
|
|
|
47
50
|
const cityListProjection = geoAlbersUsaTerritories()
|
|
@@ -50,11 +53,6 @@ const SingleStateMap = () => {
|
|
|
50
53
|
const geoStrokeColor = getGeoStrokeColor(config)
|
|
51
54
|
const path = geoPath().projection(projection)
|
|
52
55
|
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const stateToShow = topoData?.states?.find(s => s.properties.name === config.general.statePicked.stateName)
|
|
55
|
-
dispatch({ type: 'SET_STATE_TO_SHOW', payload: stateToShow })
|
|
56
|
-
}, [statePicked])
|
|
57
|
-
|
|
58
56
|
useEffect(() => {
|
|
59
57
|
let currentYear = getCurrentTopoYear(config, runtimeFilters)
|
|
60
58
|
|
|
@@ -75,7 +73,7 @@ const SingleStateMap = () => {
|
|
|
75
73
|
|
|
76
74
|
const checkForNoData = () => {
|
|
77
75
|
// If no statePicked, return true
|
|
78
|
-
if (!
|
|
76
|
+
if (!statePicked.fipsCode) return true
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
// Constructs and displays markup for all geos on the map (except territories right now)
|
|
@@ -123,7 +121,7 @@ const SingleStateMap = () => {
|
|
|
123
121
|
}
|
|
124
122
|
return (
|
|
125
123
|
<ErrorBoundary component='SingleStateMap'>
|
|
126
|
-
{statePicked && config.general.allowMapZoom &&
|
|
124
|
+
{statePicked && config.general.allowMapZoom && statePicked.fipsCode && (
|
|
127
125
|
<svg
|
|
128
126
|
viewBox={SVG_VIEWBOX}
|
|
129
127
|
preserveAspectRatio='xMinYMin'
|
|
@@ -152,7 +150,7 @@ const SingleStateMap = () => {
|
|
|
152
150
|
data={[
|
|
153
151
|
{
|
|
154
152
|
states: topoData?.states,
|
|
155
|
-
counties: topoData.counties.filter(c => c.id.substring(0, 2) ===
|
|
153
|
+
counties: topoData.counties.filter(c => c.id.substring(0, 2) === statePicked.fipsCode)
|
|
156
154
|
}
|
|
157
155
|
]}
|
|
158
156
|
projection={geoAlbersUsaTerritories}
|
|
@@ -184,7 +182,7 @@ const SingleStateMap = () => {
|
|
|
184
182
|
</ZoomableGroup>
|
|
185
183
|
</svg>
|
|
186
184
|
)}
|
|
187
|
-
{statePicked && !config.general.allowMapZoom &&
|
|
185
|
+
{statePicked && !config.general.allowMapZoom && statePicked.fipsCode && (
|
|
188
186
|
<svg
|
|
189
187
|
viewBox={SVG_VIEWBOX}
|
|
190
188
|
preserveAspectRatio='xMinYMin'
|
|
@@ -203,7 +201,7 @@ const SingleStateMap = () => {
|
|
|
203
201
|
data={[
|
|
204
202
|
{
|
|
205
203
|
states: topoData?.states,
|
|
206
|
-
counties: topoData.counties.filter(c => c.id.substring(0, 2) ===
|
|
204
|
+
counties: topoData.counties.filter(c => c.id.substring(0, 2) === statePicked.fipsCode)
|
|
207
205
|
}
|
|
208
206
|
]}
|
|
209
207
|
projection={geoAlbersUsaTerritories}
|
|
@@ -215,7 +213,7 @@ const SingleStateMap = () => {
|
|
|
215
213
|
stateToShow
|
|
216
214
|
]}
|
|
217
215
|
>
|
|
218
|
-
{({ features
|
|
216
|
+
{({ features }) => {
|
|
219
217
|
return (
|
|
220
218
|
<g
|
|
221
219
|
id='mapGroup'
|
|
@@ -226,7 +224,7 @@ const SingleStateMap = () => {
|
|
|
226
224
|
data-scale=''
|
|
227
225
|
key='countyMapGroup'
|
|
228
226
|
>
|
|
229
|
-
{constructGeoJsx(features
|
|
227
|
+
{constructGeoJsx(features)}
|
|
230
228
|
</g>
|
|
231
229
|
)
|
|
232
230
|
}}
|
package/src/helpers/addUIDs.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
|
|
10
10
|
import { SUPPORTED_DC_NAMES, GEO_TYPES, GEOCODE_TYPES } from './constants'
|
|
11
11
|
import { DataRow, MapConfig } from '../types/MapConfig'
|
|
12
|
-
import { memoize } from 'lodash'
|
|
13
12
|
|
|
14
13
|
// Data props
|
|
15
14
|
const stateKeys = Object.keys(supportedStates)
|
|
@@ -65,8 +64,8 @@ const handleUSLocation = (row: DataRow, geoColumn: string, displayAsHex: boolean
|
|
|
65
64
|
uid = memoizedFindUID(geoName, 'territory')
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
if (!uid) uid = findCityUID(geoName)
|
|
69
67
|
if (!uid) uid = handleDCDisplay(geoName, displayAsHex)
|
|
68
|
+
if (!uid) uid = findCityUID(geoName)
|
|
70
69
|
|
|
71
70
|
return uid
|
|
72
71
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { stateFipsToTwoDigit, supportedCounties } from '../data/supported-geos'
|
|
2
2
|
import { titleCase } from './titleCase'
|
|
3
3
|
|
|
4
|
+
const countyKeySet = new Set(Object.keys(supportedCounties))
|
|
5
|
+
|
|
4
6
|
export const formatLegendLocation = (key, runtimeLookup) => {
|
|
5
7
|
let formattedName = ''
|
|
6
8
|
|
|
@@ -9,8 +11,7 @@ export const formatLegendLocation = (key, runtimeLookup) => {
|
|
|
9
11
|
formattedName += stateName
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
if (countyKeys.includes(key)) {
|
|
14
|
+
if (countyKeySet.has(key)) {
|
|
14
15
|
formattedName += ', ' + titleCase(supportedCounties[key])
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -8,7 +8,8 @@ const generateRuntimeData = (
|
|
|
8
8
|
configObj: MapConfig,
|
|
9
9
|
filters: VizFilter[],
|
|
10
10
|
hash: number,
|
|
11
|
-
isCategoryLegend: boolean
|
|
11
|
+
isCategoryLegend: boolean,
|
|
12
|
+
keepNoUidRows = false
|
|
12
13
|
): {
|
|
13
14
|
[uid: string]: DataRow
|
|
14
15
|
} => {
|
|
@@ -23,7 +24,10 @@ const generateRuntimeData = (
|
|
|
23
24
|
addUIDs(configObj, configObj.columns.geo.name)
|
|
24
25
|
|
|
25
26
|
configObj.data.forEach((row: DataRow) => {
|
|
26
|
-
if (
|
|
27
|
+
if (!row.uid) {
|
|
28
|
+
if (!keepNoUidRows) return false // No UID for this row, we can't use for mapping
|
|
29
|
+
row.uid = row[configObj.columns.geo.name]
|
|
30
|
+
}
|
|
27
31
|
const configPrimaryName = configObj.columns.primary.name
|
|
28
32
|
const value = row[configPrimaryName]
|
|
29
33
|
const categoryLegend = typeof value === 'string' && isCategoryLegend
|