@cdc/map 2.6.2 → 2.6.4
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 +37 -29
- package/examples/bubble-us.json +363 -0
- package/examples/bubble-world.json +427 -0
- package/examples/default-county.json +105 -0
- package/examples/default-hex.json +475 -0
- package/examples/default-single-state.json +109 -0
- package/examples/default-usa-regions.json +118 -0
- package/examples/default-usa.json +744 -603
- package/examples/default-world-data.json +1450 -0
- package/examples/default-world.json +5 -3
- package/examples/example-city-state.json +510 -0
- package/examples/example-world-map.json +1596 -0
- package/examples/gender-rate-map.json +1 -0
- package/examples/private/atsdr.json +439 -0
- package/examples/private/atsdr_new.json +436 -0
- package/examples/private/bubble.json +285 -0
- package/examples/private/default-world-data.json +1444 -0
- package/examples/private/default.json +968 -0
- package/examples/private/map.csv +60 -0
- package/examples/private/mdx.json +210 -0
- package/examples/private/regions.json +52 -0
- package/examples/private/wcmsrd-13881-data.json +2858 -0
- package/examples/private/wcmsrd-13881.json +5823 -0
- package/examples/private/wcmsrd-test.json +268 -0
- package/examples/private/world.json +1580 -0
- package/examples/private/worldmap.json +1490 -0
- package/package.json +11 -7
- package/src/CdcMap.js +726 -202
- package/src/components/BubbleList.js +240 -0
- package/src/components/CityList.js +22 -3
- package/src/components/CountyMap.js +557 -0
- package/src/components/DataTable.js +85 -24
- package/src/components/EditorPanel.js +2455 -1204
- package/src/components/Geo.js +1 -1
- package/src/components/Sidebar.js +5 -5
- package/src/components/SingleStateMap.js +326 -0
- package/src/components/UsaMap.js +41 -9
- package/src/components/UsaRegionMap.js +319 -0
- package/src/components/WorldMap.js +112 -35
- package/src/data/abbreviations.js +57 -0
- package/src/data/country-coordinates.js +250 -0
- package/src/data/county-map-halfquality.json +58453 -0
- package/src/data/county-map-quarterquality.json +1 -0
- package/src/data/county-topo.json +1 -0
- package/src/data/dfc-map.json +1 -0
- package/src/data/initial-state.js +21 -4
- package/src/data/newtest.json +1 -0
- package/src/data/state-abbreviations.js +60 -0
- package/src/data/state-coordinates.js +55 -0
- package/src/data/supported-geos.js +3592 -163
- package/src/data/test.json +1 -0
- package/src/data/us-regions-topo-2.json +360525 -0
- package/src/data/us-regions-topo.json +37894 -0
- package/src/hooks/useActiveElement.js +19 -0
- package/src/hooks/useColorPalette.ts +96 -0
- package/src/index.html +35 -20
- package/src/index.js +8 -4
- package/src/scss/datatable.scss +2 -1
- package/src/scss/editor-panel.scss +76 -55
- package/src/scss/main.scss +10 -1
- package/src/scss/map.scss +257 -121
- package/src/scss/sidebar.scss +0 -1
- package/uploads/upload-example-city-state.json +392 -0
- package/uploads/upload-example-world-data.json +1490 -0
- package/LICENSE +0 -201
- package/src/data/color-palettes.js +0 -191
- package/src/images/map-folded.svg +0 -1
|
@@ -1,1253 +1,2504 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback } from 'react'
|
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Accordion,
|
|
4
|
+
AccordionItem,
|
|
5
|
+
AccordionItemHeading,
|
|
6
|
+
AccordionItemPanel,
|
|
7
|
+
AccordionItemButton,
|
|
8
8
|
} from 'react-accessible-accordion';
|
|
9
|
-
import ReactTooltip from 'react-tooltip'
|
|
9
|
+
import ReactTooltip from 'react-tooltip';
|
|
10
10
|
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
|
|
11
11
|
import { useDebounce } from 'use-debounce';
|
|
12
12
|
|
|
13
|
-
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
14
|
-
import Waiting from '@cdc/core/components/Waiting'
|
|
13
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
|
|
14
|
+
import Waiting from '@cdc/core/components/Waiting';
|
|
15
15
|
|
|
16
|
-
import MapIcon from '../images/map-folded.svg';
|
|
17
16
|
import UsaGraphic from '@cdc/core/assets/usa-graphic.svg';
|
|
18
17
|
import WorldGraphic from '@cdc/core/assets/world-graphic.svg';
|
|
19
|
-
import
|
|
18
|
+
import AlabamaGraphic from '@cdc/core/assets/alabama-graphic.svg';
|
|
19
|
+
import colorPalettes from '../../../core/data/colorPalettes';
|
|
20
20
|
import worldDefaultConfig from '../../examples/default-world.json';
|
|
21
21
|
import usaDefaultConfig from '../../examples/default-usa.json';
|
|
22
|
+
import countyDefaultConfig from '../../examples/default-county.json';
|
|
22
23
|
import QuestionIcon from '@cdc/core/assets/question-circle.svg';
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</span>
|
|
31
|
-
)
|
|
32
|
-
}
|
|
25
|
+
import { supportedStatesFipsCodes } from '../data/supported-geos';
|
|
26
|
+
import { GET_PALETTE,useColorPalette } from '../hooks/useColorPalette';
|
|
27
|
+
import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox';
|
|
28
|
+
import InputToggle from '@cdc/core/components/inputs/InputToggle';
|
|
29
|
+
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
30
|
+
import Icon from '@cdc/core/components/ui/Icon'
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
const [ value, setValue ] = useState(stateValue);
|
|
32
|
+
import AdvancedEditor from '@cdc/core/components/AdvancedEditor';
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
const ReactTags = require('react-tag-autocomplete'); // Future: Lazy
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
const TextField = ({
|
|
37
|
+
label,
|
|
38
|
+
section = null,
|
|
39
|
+
subsection = null,
|
|
40
|
+
fieldName,
|
|
41
|
+
updateField,
|
|
42
|
+
value: stateValue,
|
|
43
|
+
type = 'input',
|
|
44
|
+
tooltip,
|
|
45
|
+
...attributes
|
|
46
|
+
}) => {
|
|
47
|
+
const [value, setValue] = useState(stateValue);
|
|
48
|
+
|
|
49
|
+
const [debouncedValue] = useDebounce(value, 500);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
|
|
53
|
+
updateField(section, subsection, fieldName, debouncedValue);
|
|
54
|
+
}
|
|
55
|
+
}, [debouncedValue]);
|
|
56
|
+
|
|
57
|
+
let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`;
|
|
58
|
+
|
|
59
|
+
const onChange = (e) => setValue(e.target.value);
|
|
60
|
+
|
|
61
|
+
let formElement = <input type='text' name={name} onChange={onChange} {...attributes} value={value} />;
|
|
62
|
+
|
|
63
|
+
if ('textarea' === type) {
|
|
64
|
+
formElement = <textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if ('number' === type) {
|
|
68
|
+
formElement = <input type='number' name={name} onChange={onChange} {...attributes} value={value} />;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<label>
|
|
73
|
+
<span className='edit-label column-heading'>
|
|
74
|
+
{label}{tooltip}
|
|
75
|
+
</span>
|
|
76
|
+
{formElement}
|
|
77
|
+
</label>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
44
80
|
|
|
45
|
-
|
|
81
|
+
const EditorPanel = (props) => {
|
|
82
|
+
const {
|
|
83
|
+
state,
|
|
84
|
+
columnsInData = [],
|
|
85
|
+
loadConfig,
|
|
86
|
+
setState,
|
|
87
|
+
isDashboard,
|
|
88
|
+
setParentConfig,
|
|
89
|
+
setRuntimeFilters,
|
|
90
|
+
runtimeFilters,
|
|
91
|
+
runtimeLegend,
|
|
92
|
+
} = props;
|
|
46
93
|
|
|
47
|
-
|
|
94
|
+
const { general, columns, legend, dataTable, tooltips } = state;
|
|
48
95
|
|
|
49
|
-
|
|
96
|
+
const [requiredColumns, setRequiredColumns] = useState(null); // Simple state so we know if we need more information before parsing the map
|
|
50
97
|
|
|
51
|
-
|
|
52
|
-
formElement = (
|
|
53
|
-
<textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
98
|
+
const [configTextboxValue, setConfigTextbox] = useState({});
|
|
56
99
|
|
|
57
|
-
|
|
58
|
-
formElement = <input type="number" name={name} onChange={onChange} {...attributes} value={value} />
|
|
59
|
-
}
|
|
100
|
+
const [loadedDefault, setLoadedDefault] = useState(false);
|
|
60
101
|
|
|
61
|
-
|
|
62
|
-
<label>
|
|
63
|
-
<span className="edit-label column-heading">{label} {helper && <Helper text={helper} />}</span>
|
|
64
|
-
{formElement}
|
|
65
|
-
</label>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
102
|
+
const [displayPanel, setDisplayPanel] = useState(true);
|
|
68
103
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
104
|
+
const [advancedToggle, setAdvancedToggle] = useState(false);
|
|
105
|
+
|
|
106
|
+
const [activeFilterValueForDescription, setActiveFilterValueForDescription] = useState([0, 0]);
|
|
107
|
+
|
|
108
|
+
const {filteredPallets,filteredQualitative,isPaletteReversed,paletteName} = useColorPalette(colorPalettes,state);
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
const [editorCatOrder, setEditorCatOrder] = useState(state.legend.categoryValuesOrder || []);
|
|
112
|
+
|
|
113
|
+
const headerColors = [
|
|
114
|
+
'theme-blue',
|
|
115
|
+
'theme-purple',
|
|
116
|
+
'theme-brown',
|
|
117
|
+
'theme-teal',
|
|
118
|
+
'theme-pink',
|
|
119
|
+
'theme-orange',
|
|
120
|
+
'theme-slate',
|
|
121
|
+
'theme-indigo',
|
|
122
|
+
'theme-cyan',
|
|
123
|
+
'theme-green',
|
|
124
|
+
'theme-amber',
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const categoryMove = (idx1, idx2) => {
|
|
128
|
+
let categoryValuesOrder = [...editorCatOrder];
|
|
129
|
+
|
|
130
|
+
let [movedItem] = categoryValuesOrder.splice(idx1, 1);
|
|
131
|
+
|
|
132
|
+
categoryValuesOrder.splice(idx2, 0, movedItem);
|
|
133
|
+
|
|
134
|
+
setEditorCatOrder(categoryValuesOrder);
|
|
135
|
+
|
|
136
|
+
setState({
|
|
137
|
+
...state,
|
|
138
|
+
legend: {
|
|
139
|
+
...state.legend,
|
|
140
|
+
categoryValuesOrder,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
const handleFilterOrder = (idx1, idx2, filterIndex, filter) => {
|
|
147
|
+
|
|
148
|
+
let filterOrder = filter.values;
|
|
149
|
+
let [movedItem] = filterOrder.splice(idx1, 1);
|
|
150
|
+
filterOrder.splice(idx2, 0, movedItem);
|
|
151
|
+
let filters = [...runtimeFilters]
|
|
152
|
+
let filterItem= { ...runtimeFilters[filterIndex] };
|
|
153
|
+
filterItem.active = filter.values[0]
|
|
154
|
+
filterItem.values = filterOrder;
|
|
155
|
+
filterItem.order = 'cust'
|
|
156
|
+
filters[filterIndex] = filterItem
|
|
157
|
+
|
|
158
|
+
setState({
|
|
159
|
+
...state,
|
|
160
|
+
filters
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
const DynamicDesc = ({ label, fieldName, value: stateValue, type = 'input', ...attributes }) => {
|
|
167
|
+
const [value, setValue] = useState(stateValue);
|
|
168
|
+
|
|
169
|
+
const [debouncedValue] = useDebounce(value, 500);
|
|
170
|
+
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
|
|
173
|
+
handleEditorChanges('changeLegendDescription', [
|
|
174
|
+
String(activeFilterValueForDescription),
|
|
175
|
+
debouncedValue,
|
|
176
|
+
]);
|
|
177
|
+
}
|
|
178
|
+
}, [debouncedValue]);
|
|
179
|
+
|
|
180
|
+
const onChange = (e) => setValue(e.target.value);
|
|
181
|
+
|
|
182
|
+
return <textarea onChange={onChange} {...attributes} value={value}></textarea>;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const handleEditorChanges = async (property, value) => {
|
|
186
|
+
switch (property) {
|
|
187
|
+
|
|
188
|
+
// change these to be more generic.
|
|
189
|
+
// updateVisualPropertyValue
|
|
190
|
+
// updateGeneralPropertyValue, etc.
|
|
191
|
+
case 'showBubbleZeros':
|
|
192
|
+
setState({
|
|
193
|
+
...state,
|
|
194
|
+
visual: {
|
|
195
|
+
...state.visual,
|
|
196
|
+
showBubbleZeros: value
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
break;
|
|
200
|
+
|
|
201
|
+
case 'showEqualNumber':
|
|
202
|
+
setState({
|
|
203
|
+
...state,
|
|
204
|
+
general: {
|
|
205
|
+
...state.general,
|
|
206
|
+
equalNumberOptIn: value
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case 'hideGeoColumnInTooltip':
|
|
212
|
+
setState({
|
|
213
|
+
...state,
|
|
214
|
+
general: {
|
|
215
|
+
...state.general,
|
|
216
|
+
[property]: value
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
break;
|
|
220
|
+
|
|
221
|
+
case 'toggleExtraBubbleBorder':
|
|
222
|
+
setState({
|
|
223
|
+
...state,
|
|
224
|
+
visual: {
|
|
225
|
+
...state.visual,
|
|
226
|
+
extraBubbleBorder: value
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
break;
|
|
230
|
+
case 'allowMapZoom':
|
|
231
|
+
setState({
|
|
232
|
+
...state,
|
|
233
|
+
general: {
|
|
234
|
+
...state.general,
|
|
235
|
+
[property]: value
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
break;
|
|
239
|
+
case 'hidePrimaryColumnInTooltip':
|
|
240
|
+
setState({
|
|
241
|
+
...state,
|
|
242
|
+
general: {
|
|
243
|
+
...state.general,
|
|
244
|
+
[property]: value
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
break;
|
|
248
|
+
case 'showTitle':
|
|
249
|
+
setState({
|
|
250
|
+
...state,
|
|
251
|
+
general: {
|
|
252
|
+
...state.general,
|
|
253
|
+
showTitle: value,
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
break;
|
|
257
|
+
case 'showSidebar':
|
|
258
|
+
setState({
|
|
259
|
+
...state,
|
|
260
|
+
general: {
|
|
261
|
+
...state.general,
|
|
262
|
+
showSidebar: value,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
break;
|
|
266
|
+
case 'fullBorder':
|
|
267
|
+
setState({
|
|
268
|
+
...state,
|
|
269
|
+
general: {
|
|
270
|
+
...state.general,
|
|
271
|
+
fullBorder: value,
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
break;
|
|
275
|
+
case 'expandDataTable':
|
|
276
|
+
setState({
|
|
277
|
+
...state,
|
|
278
|
+
general: {
|
|
279
|
+
...state.general,
|
|
280
|
+
expandDataTable: value,
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
break;
|
|
284
|
+
case 'color':
|
|
285
|
+
setState({
|
|
286
|
+
...state,
|
|
287
|
+
color: value,
|
|
288
|
+
});
|
|
289
|
+
break;
|
|
290
|
+
case 'sidebarPosition':
|
|
291
|
+
setState({
|
|
292
|
+
...state,
|
|
293
|
+
legend: {
|
|
294
|
+
...state.legend,
|
|
295
|
+
position: value,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
break;
|
|
299
|
+
case 'geoBorderColor':
|
|
300
|
+
setState({
|
|
301
|
+
...state,
|
|
302
|
+
general: {
|
|
303
|
+
...state.general,
|
|
304
|
+
geoBorderColor: value,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
break;
|
|
308
|
+
case 'headerColor':
|
|
309
|
+
setState({
|
|
310
|
+
...state,
|
|
311
|
+
general: {
|
|
312
|
+
...state.general,
|
|
313
|
+
headerColor: value,
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
break;
|
|
317
|
+
case 'navigateColumn':
|
|
318
|
+
setState({
|
|
319
|
+
...state,
|
|
320
|
+
columns: {
|
|
321
|
+
...state.columns,
|
|
322
|
+
navigate: {
|
|
323
|
+
...state.columns.navigate,
|
|
324
|
+
name: value,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
break;
|
|
329
|
+
case 'legendDescription':
|
|
330
|
+
setState({
|
|
331
|
+
...state,
|
|
332
|
+
legend: {
|
|
333
|
+
...state.legend,
|
|
334
|
+
description: value,
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
break;
|
|
338
|
+
case 'legendType':
|
|
339
|
+
|
|
340
|
+
let testForType = typeof state.data[0][state.columns.primary.name];
|
|
341
|
+
let hasValue = state.data[0][state.columns.primary.name];
|
|
342
|
+
let messages = [];
|
|
343
|
+
|
|
344
|
+
if(!hasValue) {
|
|
345
|
+
messages.push(`There appears to be values missing for data in the primary column ${state.columns.primary.name}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (testForType === 'string' && value !== 'category') {
|
|
349
|
+
messages.push( 'Error with legend. Primary columns that are text must use a categorical legend type. Try changing the legend type to categorical.' );
|
|
350
|
+
} else {
|
|
351
|
+
messages = []
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
setState({
|
|
355
|
+
...state,
|
|
356
|
+
legend: {
|
|
357
|
+
...state.legend,
|
|
358
|
+
type: value,
|
|
359
|
+
},
|
|
360
|
+
runtime: {
|
|
361
|
+
...state.runtime,
|
|
362
|
+
editorErrorMessage: messages
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
break;
|
|
366
|
+
case 'legendNumber':
|
|
367
|
+
setState({
|
|
368
|
+
...state,
|
|
369
|
+
legend: {
|
|
370
|
+
...state.legend,
|
|
371
|
+
numberOfItems: parseInt(value),
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
break;
|
|
375
|
+
case 'changeActiveFilterValue':
|
|
376
|
+
const arrVal = value.split(',');
|
|
377
|
+
|
|
378
|
+
setActiveFilterValueForDescription(arrVal);
|
|
379
|
+
break;
|
|
380
|
+
case 'unifiedLegend':
|
|
381
|
+
setState({
|
|
382
|
+
...state,
|
|
383
|
+
legend: {
|
|
384
|
+
...state.legend,
|
|
385
|
+
unified: value,
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
break;
|
|
389
|
+
case 'separateZero':
|
|
390
|
+
setState({
|
|
391
|
+
...state,
|
|
392
|
+
legend: {
|
|
393
|
+
...state.legend,
|
|
394
|
+
separateZero: value,
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
break;
|
|
398
|
+
case 'toggleDownloadButton':
|
|
399
|
+
setState({
|
|
400
|
+
...state,
|
|
401
|
+
general: {
|
|
402
|
+
...state.general,
|
|
403
|
+
showDownloadButton: !state.general.showDownloadButton,
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
break;
|
|
407
|
+
case 'toggleDownloadMediaButton':
|
|
408
|
+
setState({
|
|
409
|
+
...state,
|
|
410
|
+
general: {
|
|
411
|
+
...state.general,
|
|
412
|
+
showDownloadMediaButton: !state.general.showDownloadMediaButton,
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
break;
|
|
416
|
+
case 'displayAsHex':
|
|
417
|
+
setState({
|
|
418
|
+
...state,
|
|
419
|
+
general: {
|
|
420
|
+
...state.general,
|
|
421
|
+
displayAsHex: value,
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
break;
|
|
425
|
+
case 'editorMapType':
|
|
426
|
+
switch (value) {
|
|
427
|
+
case 'data':
|
|
428
|
+
setState({
|
|
429
|
+
...state,
|
|
430
|
+
general: {
|
|
431
|
+
...state.general,
|
|
432
|
+
showSidebar: true,
|
|
433
|
+
type: 'data',
|
|
434
|
+
},
|
|
435
|
+
});
|
|
436
|
+
break;
|
|
437
|
+
case 'navigation':
|
|
438
|
+
setState({
|
|
439
|
+
...state,
|
|
440
|
+
general: {
|
|
441
|
+
...state.general,
|
|
442
|
+
showSidebar: false,
|
|
443
|
+
type: 'navigation',
|
|
444
|
+
},
|
|
445
|
+
tooltips: {
|
|
446
|
+
...state.tooltips,
|
|
447
|
+
appearanceType: 'hover',
|
|
448
|
+
},
|
|
449
|
+
});
|
|
450
|
+
break;
|
|
451
|
+
case 'bubble':
|
|
452
|
+
setState({
|
|
453
|
+
...state,
|
|
454
|
+
general: {
|
|
455
|
+
...state.general,
|
|
456
|
+
showSidebar: false,
|
|
457
|
+
type: 'bubble',
|
|
458
|
+
},
|
|
459
|
+
tooltips: {
|
|
460
|
+
...state.tooltips,
|
|
461
|
+
appearanceType: 'hover',
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
break;
|
|
465
|
+
default:
|
|
466
|
+
console.warn('Map type not set');
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
break;
|
|
470
|
+
case 'geoType':
|
|
471
|
+
// If we're still working with default data, switch to the world default to show it as an example
|
|
472
|
+
if (true === loadedDefault && 'world' === value) {
|
|
473
|
+
loadConfig(worldDefaultConfig);
|
|
474
|
+
ReactTooltip.rebuild();
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (true === loadedDefault && 'us' === value) {
|
|
479
|
+
loadConfig(usaDefaultConfig);
|
|
480
|
+
ReactTooltip.rebuild();
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (true === loadedDefault && 'us-county' === value) {
|
|
485
|
+
loadConfig(countyDefaultConfig);
|
|
486
|
+
ReactTooltip.rebuild();
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
switch (value) {
|
|
491
|
+
case 'us':
|
|
492
|
+
setState({
|
|
493
|
+
...state,
|
|
494
|
+
general: {
|
|
495
|
+
...state.general,
|
|
496
|
+
geoType: 'us',
|
|
497
|
+
},
|
|
498
|
+
dataTable: {
|
|
499
|
+
...state.dataTable,
|
|
500
|
+
forceDisplay: true,
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
ReactTooltip.rebuild();
|
|
504
|
+
break;
|
|
505
|
+
case 'world':
|
|
506
|
+
setState({
|
|
507
|
+
...state,
|
|
508
|
+
general: {
|
|
509
|
+
...state.general,
|
|
510
|
+
geoType: 'world',
|
|
511
|
+
},
|
|
512
|
+
dataTable: {
|
|
513
|
+
...state.dataTable,
|
|
514
|
+
forceDisplay: true,
|
|
515
|
+
},
|
|
516
|
+
});
|
|
517
|
+
break;
|
|
518
|
+
case 'us-county':
|
|
519
|
+
setState({
|
|
520
|
+
...state,
|
|
521
|
+
general: {
|
|
522
|
+
...state.general,
|
|
523
|
+
geoType: 'us-county',
|
|
524
|
+
expandDataTable: false,
|
|
525
|
+
},
|
|
526
|
+
dataTable: {
|
|
527
|
+
...state.dataTable,
|
|
528
|
+
forceDisplay: true,
|
|
529
|
+
},
|
|
530
|
+
});
|
|
531
|
+
break;
|
|
532
|
+
case 'single-state':
|
|
533
|
+
setState({
|
|
534
|
+
...state,
|
|
535
|
+
general: {
|
|
536
|
+
...state.general,
|
|
537
|
+
geoType: 'single-state',
|
|
538
|
+
expandDataTable: false,
|
|
539
|
+
},
|
|
540
|
+
dataTable: {
|
|
541
|
+
...state.dataTable,
|
|
542
|
+
forceDisplay: true,
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
break;
|
|
546
|
+
default:
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
ReactTooltip.rebuild();
|
|
551
|
+
break;
|
|
552
|
+
case 'singleColumnLegend':
|
|
553
|
+
setState({
|
|
554
|
+
...state,
|
|
555
|
+
legend: {
|
|
556
|
+
...state.legend,
|
|
557
|
+
singleColumn: !state.legend.singleColumn,
|
|
558
|
+
},
|
|
559
|
+
});
|
|
560
|
+
break;
|
|
561
|
+
case 'dynamicDescription':
|
|
562
|
+
setState({
|
|
563
|
+
...state,
|
|
564
|
+
editor: {
|
|
565
|
+
...state.editor,
|
|
566
|
+
activeFilterValueForDescription: value,
|
|
567
|
+
},
|
|
568
|
+
legend: {
|
|
569
|
+
...state.legend,
|
|
570
|
+
dynamicDescription: !state.legend.dynamicDescription,
|
|
571
|
+
},
|
|
572
|
+
});
|
|
573
|
+
break;
|
|
574
|
+
case 'changeLegendDescription':
|
|
575
|
+
const [filterValKey, filterValDesc] = value;
|
|
576
|
+
setState({
|
|
577
|
+
...state,
|
|
578
|
+
legend: {
|
|
579
|
+
...state.legend,
|
|
580
|
+
descriptions: {
|
|
581
|
+
...state.legend.descriptions,
|
|
582
|
+
[filterValKey]: [filterValDesc],
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
});
|
|
586
|
+
break;
|
|
587
|
+
case 'appearanceType':
|
|
588
|
+
setState({
|
|
589
|
+
...state,
|
|
590
|
+
tooltips: {
|
|
591
|
+
...state.tooltips,
|
|
592
|
+
appearanceType: value,
|
|
593
|
+
},
|
|
594
|
+
});
|
|
595
|
+
break;
|
|
596
|
+
case 'linkLabel':
|
|
597
|
+
setState({
|
|
598
|
+
...state,
|
|
599
|
+
tooltips: {
|
|
600
|
+
...state.tooltips,
|
|
601
|
+
linkLabel: value,
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
break;
|
|
605
|
+
case 'displayStateLabels':
|
|
606
|
+
setState({
|
|
607
|
+
...state,
|
|
608
|
+
general: {
|
|
609
|
+
...state.general,
|
|
610
|
+
displayStateLabels: !state.general.displayStateLabels,
|
|
611
|
+
},
|
|
612
|
+
});
|
|
613
|
+
break;
|
|
614
|
+
case 'capitalizeLabels':
|
|
615
|
+
setState({
|
|
616
|
+
...state,
|
|
617
|
+
tooltips: {
|
|
618
|
+
...state.tooltips,
|
|
619
|
+
capitalizeLabels: value,
|
|
620
|
+
},
|
|
621
|
+
});
|
|
622
|
+
break;
|
|
623
|
+
case 'showDataTable':
|
|
624
|
+
setState({
|
|
625
|
+
...state,
|
|
626
|
+
dataTable: {
|
|
627
|
+
...state.dataTable,
|
|
628
|
+
forceDisplay: value,
|
|
629
|
+
},
|
|
630
|
+
});
|
|
631
|
+
break;
|
|
632
|
+
case 'limitDataTableHeight':
|
|
633
|
+
setState({
|
|
634
|
+
...state,
|
|
635
|
+
dataTable: {
|
|
636
|
+
...state.dataTable,
|
|
637
|
+
limitHeight: value
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
break;
|
|
641
|
+
case 'chooseState':
|
|
642
|
+
let fipsCode = Object.keys(supportedStatesFipsCodes).find(
|
|
643
|
+
(key) => supportedStatesFipsCodes[key] === value
|
|
644
|
+
);
|
|
645
|
+
let stateName = value;
|
|
646
|
+
let stateData = { fipsCode, stateName };
|
|
647
|
+
|
|
648
|
+
setState({
|
|
649
|
+
...state,
|
|
650
|
+
general: {
|
|
651
|
+
...state.general,
|
|
652
|
+
statePicked: stateData,
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
break;
|
|
656
|
+
case "classificationType":
|
|
657
|
+
setState({
|
|
658
|
+
...state,
|
|
659
|
+
legend: {
|
|
660
|
+
...state.legend,
|
|
661
|
+
type: value,
|
|
662
|
+
},
|
|
663
|
+
});
|
|
664
|
+
break;
|
|
665
|
+
default:
|
|
666
|
+
console.warn(`Did not recognize editor property.`);
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const columnsRequiredChecker = useCallback(() => {
|
|
672
|
+
let columnList = [];
|
|
673
|
+
|
|
674
|
+
// Geo is always required
|
|
675
|
+
if ('' === state.columns.geo.name) {
|
|
676
|
+
columnList.push('Geography');
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Primary is required if we're on a data map or a point map
|
|
680
|
+
if ('navigation' !== state.general.type && '' === state.columns.primary.name) {
|
|
681
|
+
columnList.push('Primary');
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Navigate is required for navigation maps
|
|
685
|
+
if (
|
|
686
|
+
'navigation' === state.general.type &&
|
|
687
|
+
('' === state.columns.navigate.name || undefined === state.columns.navigate)
|
|
688
|
+
) {
|
|
689
|
+
columnList.push('Navigation');
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (columnList.length === 0) columnList = null;
|
|
693
|
+
|
|
694
|
+
setRequiredColumns(columnList);
|
|
695
|
+
}, [state.columns, state.general.type]);
|
|
696
|
+
|
|
697
|
+
const editColumn = async (columnName, editTarget, value) => {
|
|
698
|
+
let newSpecialClasses;
|
|
699
|
+
|
|
700
|
+
switch (editTarget) {
|
|
701
|
+
case 'specialClassEdit':
|
|
702
|
+
newSpecialClasses = Array.from(legend.specialClasses);
|
|
703
|
+
|
|
704
|
+
newSpecialClasses[value.index][value.prop] = value.value;
|
|
705
|
+
|
|
706
|
+
setState({
|
|
707
|
+
...state,
|
|
708
|
+
legend: {
|
|
709
|
+
...state.legend,
|
|
710
|
+
specialClasses: newSpecialClasses,
|
|
711
|
+
},
|
|
712
|
+
});
|
|
713
|
+
break;
|
|
714
|
+
case 'specialClassDelete':
|
|
715
|
+
newSpecialClasses = Array.from(legend.specialClasses);
|
|
716
|
+
|
|
717
|
+
newSpecialClasses.splice(value, 1);
|
|
718
|
+
|
|
719
|
+
setState({
|
|
720
|
+
...state,
|
|
721
|
+
legend: {
|
|
722
|
+
...state.legend,
|
|
723
|
+
specialClasses: newSpecialClasses,
|
|
724
|
+
},
|
|
725
|
+
});
|
|
726
|
+
break;
|
|
727
|
+
case 'specialClassAdd':
|
|
728
|
+
newSpecialClasses = legend.specialClasses;
|
|
729
|
+
|
|
730
|
+
newSpecialClasses.push(value);
|
|
731
|
+
|
|
732
|
+
setState({
|
|
733
|
+
...state,
|
|
734
|
+
legend: {
|
|
735
|
+
...state.legend,
|
|
736
|
+
specialClasses: newSpecialClasses,
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
break;
|
|
740
|
+
case 'name':
|
|
741
|
+
setState({
|
|
742
|
+
...state,
|
|
743
|
+
columns: {
|
|
744
|
+
...state.columns,
|
|
745
|
+
[columnName]: {
|
|
746
|
+
...state.columns[columnName],
|
|
747
|
+
[editTarget]: value,
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
break;
|
|
753
|
+
default:
|
|
754
|
+
setState({
|
|
755
|
+
...state,
|
|
756
|
+
columns: {
|
|
757
|
+
...state.columns,
|
|
758
|
+
[columnName]: {
|
|
759
|
+
...state.columns[columnName],
|
|
760
|
+
[editTarget]: value,
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
});
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
const changeFilter = async (idx, target, value) => {
|
|
769
|
+
|
|
770
|
+
let newFilters = [...state.filters];
|
|
771
|
+
|
|
772
|
+
switch (target) {
|
|
773
|
+
case 'addNew':
|
|
774
|
+
newFilters.push({
|
|
775
|
+
label: '',
|
|
776
|
+
values: [],
|
|
777
|
+
});
|
|
778
|
+
break;
|
|
779
|
+
case 'remove':
|
|
780
|
+
|
|
781
|
+
if(newFilters.length === 1) {
|
|
782
|
+
newFilters = []
|
|
783
|
+
} else {
|
|
784
|
+
newFilters.splice(idx, 1);
|
|
785
|
+
}
|
|
786
|
+
break;
|
|
787
|
+
case 'columnName':
|
|
788
|
+
newFilters[idx] = { ...newFilters[idx] };
|
|
789
|
+
newFilters[idx].columnName = value;
|
|
790
|
+
newFilters[idx].values = [] // when a column name changes knock the previous values out
|
|
791
|
+
break;
|
|
792
|
+
case 'filterOrder':
|
|
793
|
+
if(value === 'desc') {
|
|
794
|
+
newFilters[idx] = { ...runtimeFilters[idx]}
|
|
795
|
+
delete newFilters[idx].active;
|
|
796
|
+
newFilters[idx].order = 'desc';
|
|
797
|
+
}
|
|
798
|
+
if(value === 'asc') {
|
|
799
|
+
newFilters[idx] = { ...runtimeFilters[idx] }
|
|
800
|
+
delete newFilters[idx].active;
|
|
801
|
+
newFilters[idx].order = 'asc'
|
|
802
|
+
}
|
|
803
|
+
if(value === 'cust') {
|
|
804
|
+
newFilters[idx] = { ...runtimeFilters[idx] }
|
|
805
|
+
newFilters[idx].order = 'cust'
|
|
806
|
+
}
|
|
807
|
+
break;
|
|
808
|
+
default:
|
|
809
|
+
newFilters[idx][target] = value;
|
|
810
|
+
break;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
setState({
|
|
814
|
+
...state,
|
|
815
|
+
filters: newFilters,
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
const addAdditionalColumn = (number) => {
|
|
821
|
+
const columnKey = `additionalColumn${number}`;
|
|
822
|
+
|
|
823
|
+
setState({
|
|
824
|
+
...state,
|
|
825
|
+
columns: {
|
|
826
|
+
...state.columns,
|
|
827
|
+
[columnKey]: {
|
|
828
|
+
label: 'New Column',
|
|
829
|
+
dataTable: false,
|
|
830
|
+
tooltips: false,
|
|
831
|
+
prefix: '',
|
|
832
|
+
suffix: '',
|
|
833
|
+
},
|
|
834
|
+
},
|
|
835
|
+
});
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
const removeAdditionalColumn = (columnName) => {
|
|
839
|
+
const newColumns = state.columns;
|
|
840
|
+
|
|
841
|
+
delete newColumns[columnName];
|
|
842
|
+
|
|
843
|
+
setState({
|
|
844
|
+
...state,
|
|
845
|
+
columns: newColumns,
|
|
846
|
+
});
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
const displayFilterLegendValue = (arr) => {
|
|
850
|
+
const filterName = state.filters[arr[0]].label || `Unlabeled Legend`;
|
|
851
|
+
|
|
852
|
+
const filterValue = runtimeFilters[arr[0]];
|
|
853
|
+
|
|
854
|
+
if (filterValue) {
|
|
855
|
+
return filterName + ' - ' + filterValue.values[arr[1]];
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
const sortableItemStyles = {
|
|
860
|
+
display: 'block',
|
|
861
|
+
boxSizing: 'border-box',
|
|
862
|
+
border: '1px solid #D1D1D1',
|
|
863
|
+
borderRadius: '2px',
|
|
864
|
+
background: '#F1F1F1',
|
|
865
|
+
padding: '.4em .6em',
|
|
866
|
+
fontSize: '.8em',
|
|
867
|
+
marginRight: '.3em',
|
|
868
|
+
marginBottom: '.3em',
|
|
869
|
+
cursor: 'move',
|
|
870
|
+
zIndex: '999',
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
const convertStateToConfig = () => {
|
|
874
|
+
let strippedState = JSON.parse(JSON.stringify(state)); // Deep copy
|
|
875
|
+
|
|
876
|
+
// Strip ref
|
|
877
|
+
delete strippedState[''];
|
|
878
|
+
|
|
879
|
+
delete strippedState.newViz;
|
|
880
|
+
|
|
881
|
+
// Remove the legend
|
|
882
|
+
let strippedLegend = JSON.parse(JSON.stringify(state.legend));
|
|
883
|
+
|
|
884
|
+
delete strippedLegend.disabledAmt;
|
|
885
|
+
|
|
886
|
+
strippedState.legend = strippedLegend;
|
|
887
|
+
|
|
888
|
+
// Remove default data marker if the user started this map from default data
|
|
889
|
+
delete strippedState.defaultData;
|
|
890
|
+
|
|
891
|
+
// Remove tooltips if they're active in the editor
|
|
892
|
+
let strippedGeneral = JSON.parse(JSON.stringify(state.general));
|
|
893
|
+
|
|
894
|
+
strippedState.general = strippedGeneral;
|
|
895
|
+
|
|
896
|
+
// Add columns property back to data if it's there
|
|
897
|
+
if (state.data.columns) {
|
|
898
|
+
strippedState.data.columns = state.data.columns;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return strippedState;
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
useEffect(() => {
|
|
905
|
+
setLoadedDefault(state.defaultData);
|
|
906
|
+
|
|
907
|
+
columnsRequiredChecker();
|
|
908
|
+
}, [state]);
|
|
909
|
+
|
|
910
|
+
useEffect(() => {
|
|
911
|
+
if ('category' === state.legend.type) {
|
|
912
|
+
let arr = runtimeLegend.filter((item) => !item.special).map(({ value }) => value);
|
|
913
|
+
|
|
914
|
+
setEditorCatOrder(arr);
|
|
915
|
+
}
|
|
916
|
+
}, [runtimeLegend]);
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
// if no state choice by default show alabama
|
|
920
|
+
useEffect(() => {
|
|
921
|
+
if (!state.general.statePicked) {
|
|
922
|
+
setState({
|
|
923
|
+
...state,
|
|
924
|
+
general: {
|
|
925
|
+
...general,
|
|
926
|
+
statePicked: {
|
|
927
|
+
fipsCode: '01',
|
|
928
|
+
stateName: 'Alabama',
|
|
929
|
+
},
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
}, []);
|
|
934
|
+
|
|
935
|
+
const columnsOptions = [
|
|
936
|
+
<option value='' key={'Select Option'}>
|
|
937
|
+
- Select Option -
|
|
938
|
+
</option>,
|
|
939
|
+
];
|
|
940
|
+
|
|
941
|
+
columnsInData.map((colName) => {
|
|
942
|
+
columnsOptions.push(
|
|
943
|
+
<option value={colName} key={colName}>
|
|
944
|
+
{colName}
|
|
945
|
+
</option>
|
|
946
|
+
);
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
let columnsByKey = {};
|
|
950
|
+
state.data.forEach(datum => {
|
|
951
|
+
Object.keys(datum).forEach(key => {
|
|
952
|
+
columnsByKey[key] = columnsByKey[key] || [];
|
|
953
|
+
const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key];
|
|
954
|
+
|
|
955
|
+
if(columnsByKey[key].indexOf(value) === -1){
|
|
956
|
+
columnsByKey[key].push(value);
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
let specialClasses = [];
|
|
962
|
+
if(legend.specialClasses && legend.specialClasses.length && typeof legend.specialClasses[0] === 'string'){
|
|
963
|
+
legend.specialClasses.forEach(specialClass => {
|
|
964
|
+
specialClasses.push({
|
|
965
|
+
key: state.columns.primary && state.columns.primary.name ? state.columns.primary.name : columnsInData[0],
|
|
966
|
+
value: specialClass,
|
|
967
|
+
label: specialClass
|
|
968
|
+
});
|
|
969
|
+
});
|
|
970
|
+
} else {
|
|
971
|
+
specialClasses = legend.specialClasses || [];
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const additionalColumns = Object.keys(state.columns).filter((value) => {
|
|
975
|
+
const defaultCols = ['geo', 'navigate', 'primary'];
|
|
976
|
+
|
|
977
|
+
if (true === defaultCols.includes(value)) {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
return true;
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
const updateField = (section, subsection, fieldName, newValue) => {
|
|
984
|
+
const isArray = Array.isArray(state[section]);
|
|
985
|
+
let sectionValue = isArray ? [...state[section], newValue] : { ...state[section], [fieldName]: newValue };
|
|
986
|
+
|
|
987
|
+
if (null !== subsection) {
|
|
988
|
+
if (isArray) {
|
|
989
|
+
sectionValue = [...state[section]];
|
|
990
|
+
sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue };
|
|
991
|
+
} else {
|
|
992
|
+
sectionValue = {
|
|
993
|
+
...state[section],
|
|
994
|
+
[subsection]: { ...state[section][subsection], [fieldName]: newValue },
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
let updatedState = {
|
|
1000
|
+
...state,
|
|
1001
|
+
[section]: sectionValue,
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
setState(updatedState);
|
|
1005
|
+
};
|
|
1006
|
+
|
|
1007
|
+
const onBackClick = () => {
|
|
1008
|
+
setDisplayPanel(!displayPanel);
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
const usedFilterColumns = {};
|
|
1012
|
+
|
|
1013
|
+
const filtersJSX = state.filters.map((filter, index) => {
|
|
1014
|
+
if (filter.columnName) {
|
|
1015
|
+
usedFilterColumns[filter.columnName] = true;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
const filterOptions = [
|
|
1019
|
+
{
|
|
1020
|
+
label: 'Ascending Alphanumeric',
|
|
1021
|
+
value: 'asc'
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
label: 'Descending Alphanumeric',
|
|
1025
|
+
value: 'desc'
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
label: 'Custom',
|
|
1029
|
+
value: 'cust'
|
|
1030
|
+
}
|
|
1031
|
+
]
|
|
1032
|
+
|
|
1033
|
+
return (
|
|
1034
|
+
<fieldset className='edit-block' key={`filter-${index}`}>
|
|
1035
|
+
<button
|
|
1036
|
+
className='remove-column'
|
|
1037
|
+
onClick={(e) => {
|
|
1038
|
+
e.preventDefault();
|
|
1039
|
+
changeFilter(index, 'remove');
|
|
1040
|
+
}}
|
|
1041
|
+
>
|
|
1042
|
+
Remove
|
|
1043
|
+
</button>
|
|
1044
|
+
<TextField
|
|
1045
|
+
value={state.filters[index].label}
|
|
1046
|
+
section='filters'
|
|
1047
|
+
subsection={index}
|
|
1048
|
+
fieldName='label'
|
|
1049
|
+
label='Label'
|
|
1050
|
+
updateField={updateField}
|
|
1051
|
+
/>
|
|
1052
|
+
<label>
|
|
1053
|
+
<span className='edit-label column-heading'>
|
|
1054
|
+
Filter Column{' '}
|
|
1055
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1056
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1057
|
+
<Tooltip.Content>
|
|
1058
|
+
<p>Selecting a column will add a dropdown menu below the map legend and allow users to filter based on the values in this column.</p>
|
|
1059
|
+
</Tooltip.Content>
|
|
1060
|
+
</Tooltip>
|
|
1061
|
+
</span>
|
|
1062
|
+
<select
|
|
1063
|
+
value={filter.columnName}
|
|
1064
|
+
onChange={(event) => {
|
|
1065
|
+
changeFilter(index, 'columnName', event.target.value);
|
|
1066
|
+
}}
|
|
1067
|
+
>
|
|
1068
|
+
{columnsOptions.filter(
|
|
1069
|
+
({ key }) => undefined === usedFilterColumns[key] || filter.columnName === key
|
|
1070
|
+
)}
|
|
1071
|
+
</select>
|
|
1072
|
+
</label>
|
|
1073
|
+
|
|
1074
|
+
<label>
|
|
1075
|
+
<span className="edit-filterOrder column-heading">Filter Order</span>
|
|
1076
|
+
<select value={filter.order} onChange={ (e) => {
|
|
1077
|
+
changeFilter(index, 'filterOrder', e.target.value)
|
|
1078
|
+
}}>
|
|
1079
|
+
{filterOptions.map( (option, index) => {
|
|
1080
|
+
return <option value={option.value} key={`filter-${index}`}>{option.label}</option>
|
|
1081
|
+
})}
|
|
1082
|
+
</select>
|
|
1083
|
+
</label>
|
|
1084
|
+
|
|
1085
|
+
{filter.order === 'cust' &&
|
|
1086
|
+
<DragDropContext
|
|
1087
|
+
onDragEnd={({ source, destination }) =>
|
|
1088
|
+
handleFilterOrder(source.index, destination.index, index, runtimeFilters[index])
|
|
1089
|
+
}>
|
|
1090
|
+
<Droppable droppableId='filter_order'>
|
|
1091
|
+
{(provided) => (
|
|
1092
|
+
<ul
|
|
1093
|
+
{...provided.droppableProps}
|
|
1094
|
+
className='sort-list'
|
|
1095
|
+
ref={provided.innerRef}
|
|
1096
|
+
style={{ marginTop: '1em' }}
|
|
1097
|
+
>
|
|
1098
|
+
{runtimeFilters[index]?.values.map( (value, index) => {
|
|
1099
|
+
return (
|
|
1100
|
+
<Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
|
|
1101
|
+
{(provided, snapshot) => (
|
|
1102
|
+
<li>
|
|
1103
|
+
<div className={snapshot.isDragging ? 'currently-dragging' : ''}
|
|
1104
|
+
style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
|
|
1105
|
+
ref={provided.innerRef}
|
|
1106
|
+
{...provided.draggableProps}
|
|
1107
|
+
{...provided.dragHandleProps}>
|
|
1108
|
+
{value}
|
|
1109
|
+
</div>
|
|
1110
|
+
</li>
|
|
1111
|
+
) }
|
|
1112
|
+
</Draggable>
|
|
1113
|
+
)
|
|
1114
|
+
})}
|
|
1115
|
+
{provided.placeholder}
|
|
1116
|
+
</ul>
|
|
1117
|
+
)}
|
|
1118
|
+
</Droppable>
|
|
1119
|
+
</DragDropContext>
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
</fieldset>
|
|
1123
|
+
);
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
const StateOptionList = () => {
|
|
1127
|
+
const arrOfArrays = Object.entries(supportedStatesFipsCodes);
|
|
1128
|
+
|
|
1129
|
+
let sorted = arrOfArrays.sort((a, b) => {
|
|
1130
|
+
return a[0].localeCompare(b[0]);
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
let options = [];
|
|
1134
|
+
sorted.forEach((state) => {
|
|
1135
|
+
options.push(
|
|
1136
|
+
<option key={state[0]} value={state[1]}>
|
|
1137
|
+
{state[1]}
|
|
1138
|
+
</option>
|
|
1139
|
+
);
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
return options;
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
const filterValueOptionList = [];
|
|
1146
|
+
|
|
1147
|
+
if (runtimeFilters.length > 0) {
|
|
1148
|
+
runtimeFilters.forEach((filter, index) => {
|
|
1149
|
+
runtimeFilters[index].values.forEach((value, valueNum) => {
|
|
1150
|
+
filterValueOptionList.push([index, valueNum]);
|
|
1151
|
+
});
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
useEffect(()=>{
|
|
1157
|
+
if(paletteName) handleEditorChanges('color',paletteName)
|
|
1158
|
+
},[paletteName]) // dont add handleEditorChanges as a dependency even if it requires
|
|
1159
|
+
|
|
1160
|
+
useEffect(() => {
|
|
1161
|
+
const parsedData = convertStateToConfig();
|
|
1162
|
+
const formattedData = JSON.stringify(parsedData, undefined, 2);
|
|
1163
|
+
|
|
1164
|
+
setConfigTextbox(formattedData);
|
|
1165
|
+
}, [state]);
|
|
1166
|
+
|
|
1167
|
+
useEffect(() => {
|
|
1168
|
+
// Pass up to Editor if needed
|
|
1169
|
+
if (setParentConfig) {
|
|
1170
|
+
const newConfig = convertStateToConfig();
|
|
1171
|
+
setParentConfig(newConfig);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
}, [state]);
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
let numberOfItemsLimit = 8;
|
|
1178
|
+
|
|
1179
|
+
const getItemStyle = (isDragging, draggableStyle) => ({
|
|
1180
|
+
...draggableStyle,
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
const CategoryList = () => {
|
|
1184
|
+
return editorCatOrder.map((value, index) => (
|
|
1185
|
+
<Draggable key={value} draggableId={`item-${value}`} index={index}>
|
|
1186
|
+
{(provided, snapshot) => (
|
|
1187
|
+
<li style={{ position: 'relative' }}>
|
|
1188
|
+
<div
|
|
1189
|
+
className={snapshot.isDragging ? 'currently-dragging' : ''}
|
|
1190
|
+
style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
|
|
1191
|
+
ref={provided.innerRef}
|
|
1192
|
+
{...provided.draggableProps}
|
|
1193
|
+
{...provided.dragHandleProps}
|
|
1194
|
+
>
|
|
1195
|
+
{value}
|
|
1196
|
+
</div>
|
|
1197
|
+
</li>
|
|
1198
|
+
)}
|
|
1199
|
+
</Draggable>
|
|
1200
|
+
));
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
const Error = () => {
|
|
1204
|
+
return (
|
|
1205
|
+
<section className="waiting">
|
|
1206
|
+
<section className="waiting-container">
|
|
1207
|
+
<h3>Error With Configuration</h3>
|
|
1208
|
+
<p>{state.runtime.editorErrorMessage}</p>
|
|
1209
|
+
</section>
|
|
1210
|
+
</section>
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
return (
|
|
1215
|
+
<ErrorBoundary component='EditorPanel'>
|
|
1216
|
+
{state?.runtime?.editorErrorMessage.length > 0 && <Error />}
|
|
1217
|
+
{requiredColumns && (
|
|
1218
|
+
<Waiting requiredColumns={requiredColumns} className={displayPanel ? `waiting` : `waiting collapsed`} />
|
|
1219
|
+
)}
|
|
1220
|
+
<button
|
|
1221
|
+
className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`}
|
|
1222
|
+
title={displayPanel ? `Collapse Editor` : `Expand Editor`}
|
|
1223
|
+
onClick={onBackClick}
|
|
1224
|
+
data-html2canvas-ignore
|
|
1225
|
+
></button>
|
|
1226
|
+
|
|
1227
|
+
<section className={displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'} data-html2canvas-ignore>
|
|
1228
|
+
<ReactTooltip html={true} multiline={true} />
|
|
1229
|
+
<span className='base-label'>Configure Map</span>
|
|
1230
|
+
<section className='form-container'>
|
|
1231
|
+
<form>
|
|
1232
|
+
<Accordion allowZeroExpanded={true}>
|
|
1233
|
+
<AccordionItem>
|
|
1234
|
+
{' '}
|
|
1235
|
+
{/* Type */}
|
|
1236
|
+
<AccordionItemHeading>
|
|
1237
|
+
<AccordionItemButton>Type</AccordionItemButton>
|
|
1238
|
+
</AccordionItemHeading>
|
|
1239
|
+
<AccordionItemPanel>
|
|
1240
|
+
{/* Geography */}
|
|
1241
|
+
<label>
|
|
1242
|
+
<span className='edit-label column-heading'>
|
|
1243
|
+
<span>Geography</span>
|
|
1244
|
+
</span>
|
|
1245
|
+
<ul className='geo-buttons'>
|
|
1246
|
+
<li
|
|
1247
|
+
className={
|
|
1248
|
+
state.general.geoType === 'us' ||
|
|
1249
|
+
state.general.geoType === 'us-county'
|
|
1250
|
+
? 'active'
|
|
1251
|
+
: ''
|
|
1252
|
+
}
|
|
1253
|
+
onClick={() => handleEditorChanges('geoType', 'us')}
|
|
1254
|
+
>
|
|
1255
|
+
<UsaGraphic />
|
|
1256
|
+
<span>United States</span>
|
|
1257
|
+
</li>
|
|
1258
|
+
<li
|
|
1259
|
+
className={state.general.geoType === 'world' ? 'active' : ''}
|
|
1260
|
+
onClick={() => handleEditorChanges('geoType', 'world')}
|
|
1261
|
+
>
|
|
1262
|
+
<WorldGraphic />
|
|
1263
|
+
<span>World</span>
|
|
1264
|
+
</li>
|
|
1265
|
+
<li
|
|
1266
|
+
className={state.general.geoType === 'single-state' ? 'active' : ''}
|
|
1267
|
+
onClick={() => handleEditorChanges('geoType', 'single-state')}
|
|
1268
|
+
>
|
|
1269
|
+
<AlabamaGraphic />
|
|
1270
|
+
<span>U.S. State</span>
|
|
1271
|
+
</li>
|
|
1272
|
+
</ul>
|
|
1273
|
+
</label>
|
|
1274
|
+
{/* Select > State or County Map */}
|
|
1275
|
+
{(state.general.geoType === 'us' || state.general.geoType === 'us-county') && (
|
|
1276
|
+
<label>
|
|
1277
|
+
<span className='edit-label column-heading'>
|
|
1278
|
+
Map Type
|
|
1279
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1280
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1281
|
+
<Tooltip.Content>
|
|
1282
|
+
<p>Select "Data" to create a color-coded data map. To create a navigation-only map, select "Navigation."</p>
|
|
1283
|
+
</Tooltip.Content>
|
|
1284
|
+
</Tooltip>
|
|
1285
|
+
</span>
|
|
1286
|
+
<select
|
|
1287
|
+
value={state.general.geoType}
|
|
1288
|
+
onChange={(event) => {
|
|
1289
|
+
handleEditorChanges('geoType', event.target.value);
|
|
1290
|
+
}}
|
|
1291
|
+
>
|
|
1292
|
+
<option value='us'>US State-Level</option>
|
|
1293
|
+
<option value='us-county'>US County-Level</option>
|
|
1294
|
+
</select>
|
|
1295
|
+
</label>
|
|
1296
|
+
)}
|
|
1297
|
+
{/* Type */}
|
|
1298
|
+
{/* Select > Filter a state */}
|
|
1299
|
+
{state.general.geoType === 'single-state' && (
|
|
1300
|
+
<label>
|
|
1301
|
+
<span className='edit-label column-heading'>State Selector</span>
|
|
1302
|
+
<select
|
|
1303
|
+
value={
|
|
1304
|
+
state.general.hasOwnProperty('statePicked')
|
|
1305
|
+
? state.general.statePicked.stateName
|
|
1306
|
+
: { fipsCode: '04', stateName: 'Alabama' }
|
|
1307
|
+
}
|
|
1308
|
+
onChange={(event) => {
|
|
1309
|
+
handleEditorChanges('chooseState', event.target.value);
|
|
1310
|
+
}}
|
|
1311
|
+
>
|
|
1312
|
+
<StateOptionList />
|
|
1313
|
+
</select>
|
|
1314
|
+
</label>
|
|
1315
|
+
)}
|
|
1316
|
+
{/* Type */}
|
|
1317
|
+
<label>
|
|
1318
|
+
<span className='edit-label column-heading'>Map Type</span>
|
|
1319
|
+
<select
|
|
1320
|
+
value={state.general.type}
|
|
1321
|
+
onChange={(event) => {
|
|
1322
|
+
handleEditorChanges('editorMapType', event.target.value);
|
|
1323
|
+
}}
|
|
1324
|
+
>
|
|
1325
|
+
<option value='data'>Data</option>
|
|
1326
|
+
<option value='navigation'>Navigation</option>
|
|
1327
|
+
{ (state.general.geoType === 'world' || state.general.geoType === 'us') && <option value="bubble">Bubble</option>}
|
|
1328
|
+
</select>
|
|
1329
|
+
</label>
|
|
1330
|
+
{/* SubType */}
|
|
1331
|
+
{'us' === state.general.geoType && 'data' === state.general.type && (
|
|
1332
|
+
<label className='checkbox mt-4'>
|
|
1333
|
+
<input
|
|
1334
|
+
type='checkbox'
|
|
1335
|
+
checked={state.general.displayAsHex}
|
|
1336
|
+
onChange={(event) => {
|
|
1337
|
+
handleEditorChanges('displayAsHex', event.target.checked);
|
|
1338
|
+
}}
|
|
1339
|
+
/>
|
|
1340
|
+
<span className='edit-label'>Display As Hex Map</span>
|
|
1341
|
+
</label>
|
|
1342
|
+
)}
|
|
1343
|
+
{'us' === state.general.geoType &&
|
|
1344
|
+
'data' === state.general.type &&
|
|
1345
|
+
false === state.general.displayAsHex && (
|
|
1346
|
+
<label className='checkbox'>
|
|
1347
|
+
<input
|
|
1348
|
+
type='checkbox'
|
|
1349
|
+
checked={state.general.displayStateLabels}
|
|
1350
|
+
onChange={(event) => {
|
|
1351
|
+
handleEditorChanges('displayStateLabels', event.target.checked);
|
|
1352
|
+
}}
|
|
1353
|
+
/>
|
|
1354
|
+
<span className='edit-label'>Display state labels</span>
|
|
1355
|
+
</label>
|
|
1356
|
+
)}
|
|
1357
|
+
</AccordionItemPanel>
|
|
1358
|
+
</AccordionItem>
|
|
1359
|
+
<AccordionItem>
|
|
1360
|
+
{' '}
|
|
1361
|
+
{/* General */}
|
|
1362
|
+
<AccordionItemHeading>
|
|
1363
|
+
<AccordionItemButton>General</AccordionItemButton>
|
|
1364
|
+
</AccordionItemHeading>
|
|
1365
|
+
<AccordionItemPanel>
|
|
1366
|
+
<TextField
|
|
1367
|
+
value={state.general.title}
|
|
1368
|
+
updateField={updateField}
|
|
1369
|
+
section='general'
|
|
1370
|
+
fieldName='title'
|
|
1371
|
+
label='Title'
|
|
1372
|
+
placeholder='Map Title'
|
|
1373
|
+
tooltip={
|
|
1374
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1375
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1376
|
+
<Tooltip.Content>
|
|
1377
|
+
<p>For accessibility reasons, you should enter a title even if you are not planning on displaying it.</p>
|
|
1378
|
+
</Tooltip.Content>
|
|
1379
|
+
</Tooltip>
|
|
1380
|
+
}
|
|
1381
|
+
/>
|
|
1382
|
+
<TextField
|
|
1383
|
+
type='textarea'
|
|
1384
|
+
value={general.subtext}
|
|
1385
|
+
updateField={updateField}
|
|
1386
|
+
section='general'
|
|
1387
|
+
fieldName='subtext'
|
|
1388
|
+
label='Subtext'
|
|
1389
|
+
tooltip={
|
|
1390
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1391
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1392
|
+
<Tooltip.Content>
|
|
1393
|
+
<p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
|
|
1394
|
+
</Tooltip.Content>
|
|
1395
|
+
</Tooltip>
|
|
1396
|
+
}
|
|
1397
|
+
/>
|
|
1398
|
+
{'us' === state.general.geoType && (
|
|
1399
|
+
<TextField
|
|
1400
|
+
value={general.territoriesLabel}
|
|
1401
|
+
updateField={updateField}
|
|
1402
|
+
section='general'
|
|
1403
|
+
fieldName='territoriesLabel'
|
|
1404
|
+
label='Territories Label'
|
|
1405
|
+
placeholder='Territories'
|
|
1406
|
+
/>
|
|
1407
|
+
)}
|
|
1408
|
+
<label>
|
|
1409
|
+
<span className="edit-label">Data Classification Type</span>
|
|
1410
|
+
<div>
|
|
1411
|
+
<label>
|
|
1412
|
+
<input
|
|
1413
|
+
type="radio"
|
|
1414
|
+
name="equalnumber"
|
|
1415
|
+
value="equalnumber"
|
|
1416
|
+
checked={state.legend.type === "equalnumber"}
|
|
1417
|
+
onChange={(e) =>
|
|
1418
|
+
handleEditorChanges(
|
|
1419
|
+
"classificationType",
|
|
1420
|
+
e.target.value
|
|
1421
|
+
)
|
|
1422
|
+
}
|
|
1423
|
+
/>
|
|
1424
|
+
Numeric/Quantitative
|
|
1425
|
+
</label>
|
|
1426
|
+
<label>
|
|
1427
|
+
<input
|
|
1428
|
+
type="radio"
|
|
1429
|
+
name="category"
|
|
1430
|
+
value="category"
|
|
1431
|
+
checked={state.legend.type === "category"}
|
|
1432
|
+
onChange={(e) =>
|
|
1433
|
+
handleEditorChanges(
|
|
1434
|
+
"classificationType",
|
|
1435
|
+
e.target.value
|
|
1436
|
+
)
|
|
1437
|
+
}
|
|
1438
|
+
/>
|
|
1439
|
+
Categorical
|
|
1440
|
+
</label>
|
|
1441
|
+
</div>
|
|
1442
|
+
</label>
|
|
1443
|
+
{/* <label className="checkbox mt-4">
|
|
856
1444
|
<input type="checkbox" checked={ state.general.showDownloadMediaButton } onChange={(event) => { handleEditorChanges("toggleDownloadMediaButton", event.target.checked) }} />
|
|
857
1445
|
<span className="edit-label">Enable Media Download</span>
|
|
858
1446
|
</label> */}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
{
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
<
|
|
890
|
-
<label className="checkbox">
|
|
891
|
-
<input type="checkbox" checked={ state.columns.primary.useCommas } onChange={(event) => { editColumn("primary", "useCommas", event.target.checked) }} />
|
|
892
|
-
<span className="edit-label">Add Commas to Numbers</span>
|
|
893
|
-
</label>
|
|
894
|
-
</li>
|
|
895
|
-
<li>
|
|
896
|
-
<label className="checkbox">
|
|
897
|
-
<input type="checkbox" checked={ state.columns.primary.dataTable || false} onChange={(event) => { editColumn("primary", "dataTable", event.target.checked) }} />
|
|
898
|
-
<span className="edit-label">Display in Data Table</span>
|
|
899
|
-
</label>
|
|
900
|
-
</li>
|
|
901
|
-
<li>
|
|
902
|
-
<label className="checkbox">
|
|
903
|
-
<input type="checkbox" checked={ state.columns.primary.tooltip || false} onChange={(event) => { editColumn("primary", "tooltip", event.target.checked) }} />
|
|
904
|
-
<span className="edit-label">Display in Tooltips</span>
|
|
905
|
-
</label>
|
|
906
|
-
</li>
|
|
907
|
-
<li>
|
|
1447
|
+
</AccordionItemPanel>
|
|
1448
|
+
</AccordionItem>
|
|
1449
|
+
<AccordionItem>
|
|
1450
|
+
{' '}
|
|
1451
|
+
{/* Columns */}
|
|
1452
|
+
<AccordionItemHeading>
|
|
1453
|
+
<AccordionItemButton>Columns</AccordionItemButton>
|
|
1454
|
+
</AccordionItemHeading>
|
|
1455
|
+
<AccordionItemPanel>
|
|
1456
|
+
<label className='edit-block geo'>
|
|
1457
|
+
<span className='edit-label column-heading'>
|
|
1458
|
+
Geography
|
|
1459
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1460
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1461
|
+
<Tooltip.Content>
|
|
1462
|
+
<p>Select the source column containing the map location names or, for county-level maps, the FIPS codes.</p>
|
|
1463
|
+
</Tooltip.Content>
|
|
1464
|
+
</Tooltip>
|
|
1465
|
+
</span>
|
|
1466
|
+
<select
|
|
1467
|
+
value={state.columns.geo ? state.columns.geo.name : columnsOptions[0]}
|
|
1468
|
+
onChange={(event) => {
|
|
1469
|
+
editColumn('geo', 'name', event.target.value);
|
|
1470
|
+
}}
|
|
1471
|
+
>
|
|
1472
|
+
{columnsOptions}
|
|
1473
|
+
</select>
|
|
1474
|
+
</label>
|
|
1475
|
+
|
|
1476
|
+
{'navigation' !== state.general.type && (
|
|
1477
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
908
1478
|
<label>
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
<
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
</label>
|
|
929
|
-
{"navigation" !== state.general.type && additionalColumns.map((val) => (
|
|
930
|
-
<fieldset className="edit-block" key={val}>
|
|
931
|
-
<button className="remove-column" onClick={(event) => { event.preventDefault(); removeAdditionalColumn(val)}}>Remove</button>
|
|
932
|
-
<label>
|
|
933
|
-
<span className="edit-label column-heading">Column</span>
|
|
934
|
-
<select value={state.columns[val] ? state.columns[val].name : columnsOptions[0] } onChange={(event) => { editColumn(val, "name", event.target.value) }}>
|
|
1479
|
+
<span className='edit-label column-heading'>
|
|
1480
|
+
Data Column
|
|
1481
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1482
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1483
|
+
<Tooltip.Content>
|
|
1484
|
+
<p>Select the source column containing the categorical or numeric values to be mapped.</p>
|
|
1485
|
+
</Tooltip.Content>
|
|
1486
|
+
</Tooltip>
|
|
1487
|
+
</span>
|
|
1488
|
+
<select
|
|
1489
|
+
value={
|
|
1490
|
+
state.columns.primary
|
|
1491
|
+
? state.columns.primary.name
|
|
1492
|
+
: columnsOptions[0]
|
|
1493
|
+
}
|
|
1494
|
+
onChange={(event) => {
|
|
1495
|
+
editColumn('primary', 'name', event.target.value);
|
|
1496
|
+
}}
|
|
1497
|
+
>
|
|
935
1498
|
{columnsOptions}
|
|
936
1499
|
</select>
|
|
937
1500
|
</label>
|
|
938
|
-
<TextField
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1501
|
+
<TextField
|
|
1502
|
+
value={columns.primary.label}
|
|
1503
|
+
section='columns'
|
|
1504
|
+
subsection='primary'
|
|
1505
|
+
fieldName='label'
|
|
1506
|
+
label='Label'
|
|
1507
|
+
updateField={updateField}
|
|
1508
|
+
tooltip={
|
|
1509
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1510
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1511
|
+
<Tooltip.Content>
|
|
1512
|
+
<p>Enter a data label for use in tooltips and the data table.</p>
|
|
1513
|
+
</Tooltip.Content>
|
|
1514
|
+
</Tooltip>
|
|
1515
|
+
}
|
|
1516
|
+
/>
|
|
1517
|
+
<ul className='column-edit'>
|
|
1518
|
+
<li className='three-col'>
|
|
1519
|
+
<TextField
|
|
1520
|
+
value={columns.primary.prefix}
|
|
1521
|
+
section='columns'
|
|
1522
|
+
subsection='primary'
|
|
1523
|
+
fieldName='prefix'
|
|
1524
|
+
label='Prefix'
|
|
1525
|
+
updateField={updateField}
|
|
1526
|
+
/>
|
|
1527
|
+
<TextField
|
|
1528
|
+
value={columns.primary.suffix}
|
|
1529
|
+
section='columns'
|
|
1530
|
+
subsection='primary'
|
|
1531
|
+
fieldName='suffix'
|
|
1532
|
+
label='Suffix'
|
|
1533
|
+
updateField={updateField}
|
|
1534
|
+
/>
|
|
1535
|
+
<TextField
|
|
1536
|
+
type='number'
|
|
1537
|
+
value={columns.primary.roundToPlace}
|
|
1538
|
+
section='columns'
|
|
1539
|
+
subsection='primary'
|
|
1540
|
+
fieldName='roundToPlace'
|
|
1541
|
+
label='Round'
|
|
1542
|
+
updateField={updateField}
|
|
1543
|
+
/>
|
|
944
1544
|
</li>
|
|
945
1545
|
<li>
|
|
946
|
-
<label className=
|
|
947
|
-
<input
|
|
948
|
-
|
|
1546
|
+
<label className='checkbox'>
|
|
1547
|
+
<input
|
|
1548
|
+
type='checkbox'
|
|
1549
|
+
checked={state.columns.primary.useCommas}
|
|
1550
|
+
onChange={(event) => {
|
|
1551
|
+
editColumn(
|
|
1552
|
+
'primary',
|
|
1553
|
+
'useCommas',
|
|
1554
|
+
event.target.checked
|
|
1555
|
+
);
|
|
1556
|
+
}}
|
|
1557
|
+
/>
|
|
1558
|
+
<span className='edit-label'>Add Commas to Numbers</span>
|
|
949
1559
|
</label>
|
|
950
1560
|
</li>
|
|
951
1561
|
<li>
|
|
952
|
-
<label className=
|
|
953
|
-
<input
|
|
954
|
-
|
|
1562
|
+
<label className='checkbox'>
|
|
1563
|
+
<input
|
|
1564
|
+
type='checkbox'
|
|
1565
|
+
checked={state.columns.primary.dataTable || false}
|
|
1566
|
+
onChange={(event) => {
|
|
1567
|
+
editColumn(
|
|
1568
|
+
'primary',
|
|
1569
|
+
'dataTable',
|
|
1570
|
+
event.target.checked
|
|
1571
|
+
);
|
|
1572
|
+
}}
|
|
1573
|
+
/>
|
|
1574
|
+
<span className='edit-label'>Display in Data Table</span>
|
|
955
1575
|
</label>
|
|
956
1576
|
</li>
|
|
957
1577
|
<li>
|
|
958
|
-
<label className=
|
|
959
|
-
<input
|
|
960
|
-
|
|
1578
|
+
<label className='checkbox'>
|
|
1579
|
+
<input
|
|
1580
|
+
type='checkbox'
|
|
1581
|
+
checked={state.columns.primary.tooltip || false}
|
|
1582
|
+
onChange={(event) => {
|
|
1583
|
+
editColumn('primary', 'tooltip', event.target.checked);
|
|
1584
|
+
}}
|
|
1585
|
+
/>
|
|
1586
|
+
<span className='edit-label'>Display in Tooltips</span>
|
|
961
1587
|
</label>
|
|
962
1588
|
</li>
|
|
963
1589
|
</ul>
|
|
964
1590
|
</fieldset>
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1591
|
+
)}
|
|
1592
|
+
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
{ (state.general.type === 'bubble') && state.legend.type === 'category' && (
|
|
1596
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
1597
|
+
<label>
|
|
1598
|
+
<span className='edit-label column-heading'>
|
|
1599
|
+
Category Column
|
|
1600
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1601
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1602
|
+
<Tooltip.Content>
|
|
1603
|
+
<p>Select the source column containing the categorical bubble values to be mapped.</p>
|
|
1604
|
+
</Tooltip.Content>
|
|
1605
|
+
</Tooltip>
|
|
1606
|
+
</span>
|
|
1607
|
+
<select
|
|
1608
|
+
value={
|
|
1609
|
+
state.columns.categorical
|
|
1610
|
+
? state.columns.categorical.name
|
|
1611
|
+
: columnsOptions[0]
|
|
1612
|
+
}
|
|
1613
|
+
onChange={(event) => {
|
|
1614
|
+
editColumn('categorical', 'name', event.target.value);
|
|
1615
|
+
}}
|
|
1616
|
+
>
|
|
1617
|
+
{columnsOptions}
|
|
1618
|
+
</select>
|
|
1619
|
+
</label>
|
|
1620
|
+
</fieldset>
|
|
1621
|
+
)}
|
|
1622
|
+
|
|
1623
|
+
{'navigation' !== state.general.type && (
|
|
1624
|
+
<fieldset className="primary-fieldset edit-block">
|
|
1625
|
+
<label>
|
|
1626
|
+
<span className='edit-label'>
|
|
1627
|
+
Special Classes
|
|
1628
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1629
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1630
|
+
<Tooltip.Content>
|
|
1631
|
+
<p>For secondary values such as "NA", the system can automatically color-code them in shades of gray, one shade for each special class.</p>
|
|
1632
|
+
</Tooltip.Content>
|
|
1633
|
+
</Tooltip>
|
|
1634
|
+
</span>
|
|
1635
|
+
</label>
|
|
1636
|
+
{specialClasses.map((specialClass, i) => (
|
|
1637
|
+
<div className="edit-block" key={`special-class-${i}`}>
|
|
1638
|
+
<button className="remove-column"
|
|
1639
|
+
onClick={(e) => {
|
|
1640
|
+
e.preventDefault();
|
|
1641
|
+
editColumn('primary', 'specialClassDelete', i);
|
|
1642
|
+
}}
|
|
1643
|
+
>Remove</button>
|
|
1644
|
+
<p>Special Class {i + 1}</p>
|
|
1645
|
+
<label>
|
|
1646
|
+
<span className="edit-label column-heading">Data Key</span>
|
|
1647
|
+
<select value={specialClass.key} onChange={(e) => {
|
|
1648
|
+
editColumn('primary', 'specialClassEdit', {prop: 'key', index: i, value: e.target.value});
|
|
1649
|
+
}}>
|
|
1650
|
+
{columnsOptions}
|
|
1651
|
+
</select>
|
|
1652
|
+
</label>
|
|
1653
|
+
<label>
|
|
1654
|
+
<span className="edit-label column-heading">Value</span>
|
|
1655
|
+
<select value={specialClass.value} onChange={(e) => {
|
|
1656
|
+
editColumn('primary', 'specialClassEdit', {prop: 'value', index: i, value: e.target.value});
|
|
1657
|
+
}}>
|
|
1658
|
+
<option value="">- Select Value -</option>
|
|
1659
|
+
{columnsByKey[specialClass.key] && columnsByKey[specialClass.key].sort().map(option => (
|
|
1660
|
+
<option key={`special-class-value-option-${i}-${option}`}>{option}</option>
|
|
1661
|
+
))}
|
|
1662
|
+
</select>
|
|
1663
|
+
</label>
|
|
1664
|
+
<label>
|
|
1665
|
+
<span className="edit-label column-heading">Label</span>
|
|
1666
|
+
<input type="text" value={specialClass.label} onChange={(e) => {
|
|
1667
|
+
editColumn('primary', 'specialClassEdit', {prop: 'label', index: i, value: e.target.value});
|
|
1668
|
+
}} />
|
|
1669
|
+
</label>
|
|
1670
|
+
</div>
|
|
1671
|
+
))}
|
|
1672
|
+
<button className="btn full-width" onClick={(e) => {
|
|
1673
|
+
e.preventDefault();
|
|
1674
|
+
editColumn('primary', 'specialClassAdd', {});
|
|
1675
|
+
}}>
|
|
1676
|
+
Add Special Class
|
|
1677
|
+
</button>
|
|
1678
|
+
</fieldset>
|
|
1679
|
+
)}
|
|
1680
|
+
|
|
1681
|
+
<label className='edit-block navigate column-heading'>
|
|
1682
|
+
<span className='edit-label column-heading'>
|
|
1683
|
+
Navigation
|
|
1684
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1685
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1686
|
+
<Tooltip.Content>
|
|
1687
|
+
<p>To provide end users with navigation functionality, select the source column containing the navigation URLs.</p>
|
|
1688
|
+
</Tooltip.Content>
|
|
1689
|
+
</Tooltip>
|
|
1690
|
+
</span>
|
|
1691
|
+
<select
|
|
1692
|
+
value={
|
|
1693
|
+
state.columns.navigate ? state.columns.navigate.name : columnsOptions[0]
|
|
1694
|
+
}
|
|
1695
|
+
onChange={(event) => {
|
|
1696
|
+
editColumn('navigate', 'name', event.target.value);
|
|
1697
|
+
}}
|
|
1698
|
+
>
|
|
1699
|
+
{columnsOptions}
|
|
1700
|
+
</select>
|
|
1701
|
+
</label>
|
|
1702
|
+
{'navigation' !== state.general.type &&
|
|
1703
|
+
<fieldset className="primary-fieldset edit-block">
|
|
1004
1704
|
<label>
|
|
1005
|
-
<span className="edit-label">
|
|
1705
|
+
<span className="edit-label">
|
|
1706
|
+
Additional Columns
|
|
1707
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1708
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1709
|
+
<Tooltip.Content>
|
|
1710
|
+
<p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
|
|
1711
|
+
</Tooltip.Content>
|
|
1712
|
+
</Tooltip>
|
|
1713
|
+
</span>
|
|
1006
1714
|
</label>
|
|
1007
|
-
{
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1715
|
+
{additionalColumns.map((val) => (
|
|
1716
|
+
<fieldset className="edit-block" key={val}>
|
|
1717
|
+
<button
|
|
1718
|
+
className="remove-column"
|
|
1719
|
+
onClick={(event) => {
|
|
1720
|
+
event.preventDefault()
|
|
1721
|
+
removeAdditionalColumn(val)
|
|
1722
|
+
}}
|
|
1723
|
+
>
|
|
1724
|
+
Remove
|
|
1725
|
+
</button>
|
|
1726
|
+
<label>
|
|
1727
|
+
<span className="edit-label column-heading">Column</span>
|
|
1728
|
+
<select
|
|
1729
|
+
value={
|
|
1730
|
+
state.columns[val]
|
|
1731
|
+
? state.columns[val].name
|
|
1732
|
+
: columnsOptions[0]
|
|
1733
|
+
}
|
|
1734
|
+
onChange={(event) => {
|
|
1735
|
+
editColumn(val, 'name', event.target.value)
|
|
1736
|
+
}}
|
|
1015
1737
|
>
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
/>
|
|
1055
|
-
<span className="edit-label">Unified Legend</span>
|
|
1056
|
-
</label>
|
|
1057
|
-
}
|
|
1058
|
-
</AccordionItemPanel>
|
|
1059
|
-
</AccordionItem>}
|
|
1060
|
-
{"navigation" !== state.general.type && <AccordionItem> {/* Filters */}
|
|
1061
|
-
<AccordionItemHeading>
|
|
1062
|
-
<AccordionItemButton>
|
|
1063
|
-
Filters
|
|
1064
|
-
</AccordionItemButton>
|
|
1065
|
-
</AccordionItemHeading>
|
|
1066
|
-
<AccordionItemPanel>
|
|
1067
|
-
{filtersJSX.length > 0 ? filtersJSX : (<p style={{textAlign: "center"}}>There are currently no filters.</p>) }
|
|
1068
|
-
<button className={"btn full-width"} onClick={(event) => {event.preventDefault(); changeFilter(null, "addNew")}}>Add Filter</button>
|
|
1069
|
-
</AccordionItemPanel>
|
|
1070
|
-
</AccordionItem>}
|
|
1071
|
-
{"navigation" !== state.general.type && (
|
|
1072
|
-
<AccordionItem> {/* Data Table */}
|
|
1073
|
-
<AccordionItemHeading>
|
|
1074
|
-
<AccordionItemButton>
|
|
1075
|
-
Data Table
|
|
1076
|
-
</AccordionItemButton>
|
|
1077
|
-
</AccordionItemHeading>
|
|
1078
|
-
<AccordionItemPanel>
|
|
1079
|
-
<TextField value={dataTable.title} updateField={updateField} section="dataTable" fieldName="title" label="Data Table Title" placeholder="Data Table" />
|
|
1080
|
-
<TextField value={dataTable.indexTitle} updateField={updateField} section="dataTable" fieldName="indexTitle" label="Index Column Title" placeholder="Location" />
|
|
1081
|
-
<label className="checkbox">
|
|
1082
|
-
<input type="checkbox" checked={ state.dataTable.forceDisplay !== undefined ? state.dataTable.forceDisplay : !isDashboard } onChange={(event) => { handleEditorChanges("showDataTable", event.target.checked) }} />
|
|
1083
|
-
<span className="edit-label">Show Table</span>
|
|
1084
|
-
<Helper text="Data tables are required for 508 compliance. When choosing to hide this data table, replace with your own version." />
|
|
1085
|
-
</label>
|
|
1086
|
-
<label className="checkbox">
|
|
1087
|
-
<input type="checkbox" checked={ state.general.expandDataTable || false } onChange={(event) => { handleEditorChanges("expandDataTable", event.target.checked) }} />
|
|
1088
|
-
<span className="edit-label">Map loads with data table expanded</span>
|
|
1089
|
-
</label>
|
|
1090
|
-
<label className="checkbox">
|
|
1091
|
-
<input type="checkbox" checked={ state.general.showDownloadButton } onChange={(event) => { handleEditorChanges("toggleDownloadButton", event.target.checked) }} />
|
|
1092
|
-
<span className="edit-label">Enable Download CSV Button</span>
|
|
1093
|
-
</label>
|
|
1094
|
-
</AccordionItemPanel>
|
|
1095
|
-
</AccordionItem>)}
|
|
1096
|
-
<AccordionItem> {/* Tooltips */}
|
|
1097
|
-
<AccordionItemHeading>
|
|
1098
|
-
<AccordionItemButton>
|
|
1099
|
-
Interactivity
|
|
1100
|
-
</AccordionItemButton>
|
|
1101
|
-
</AccordionItemHeading>
|
|
1102
|
-
<AccordionItemPanel>
|
|
1103
|
-
<label>
|
|
1104
|
-
<span className="edit-label">Detail displays on <Helper text="At mobile sizes, information always appears in a popover modal when a user taps on an item." /></span>
|
|
1105
|
-
<select value={state.tooltips.appearanceType } onChange={(event) => { handleEditorChanges("appearanceType", event.target.value) }}>
|
|
1106
|
-
<option value="hover">Hover - Tooltip</option>
|
|
1107
|
-
<option value="click">Click - Popover Modal</option>
|
|
1108
|
-
</select>
|
|
1109
|
-
</label>
|
|
1110
|
-
{'click' === state.tooltips.appearanceType &&
|
|
1111
|
-
<TextField value={tooltips.linkLabel} section="tooltips" fieldName="linkLabel" label="Tooltips Link Label" updateField={updateField} />
|
|
1112
|
-
}
|
|
1113
|
-
<label className="checkbox">
|
|
1114
|
-
<input type="checkbox" checked={state.tooltips.capitalizeLabels} onChange={(event) => { handleEditorChanges("capitalizeLabels", event.target.checked) }} />
|
|
1115
|
-
<span className="edit-label">Capitalize text inside tooltip</span>
|
|
1116
|
-
</label>
|
|
1117
|
-
</AccordionItemPanel>
|
|
1118
|
-
</AccordionItem>
|
|
1119
|
-
<AccordionItem> {/* Visual */}
|
|
1120
|
-
<AccordionItemHeading>
|
|
1121
|
-
<AccordionItemButton>
|
|
1122
|
-
Visual
|
|
1123
|
-
</AccordionItemButton>
|
|
1124
|
-
</AccordionItemHeading>
|
|
1125
|
-
<AccordionItemPanel>
|
|
1126
|
-
<label className="header">
|
|
1127
|
-
<span className="edit-label">Header Theme</span>
|
|
1128
|
-
<ul className="color-palette">
|
|
1129
|
-
{headerColors.map( (palette) => {
|
|
1130
|
-
|
|
1131
|
-
return (
|
|
1132
|
-
<li title={ palette } key={ palette } onClick={ () => { handleEditorChanges("headerColor", palette) }} className={ state.general.headerColor === palette ? "selected " + palette : palette}>
|
|
1738
|
+
{columnsOptions}
|
|
1739
|
+
</select>
|
|
1740
|
+
</label>
|
|
1741
|
+
<TextField
|
|
1742
|
+
value={columns[val].label}
|
|
1743
|
+
section="columns"
|
|
1744
|
+
subsection={val}
|
|
1745
|
+
fieldName="label"
|
|
1746
|
+
label="Label"
|
|
1747
|
+
updateField={updateField}
|
|
1748
|
+
/>
|
|
1749
|
+
<ul className="column-edit">
|
|
1750
|
+
<li className="three-col">
|
|
1751
|
+
<TextField
|
|
1752
|
+
value={columns[val].prefix}
|
|
1753
|
+
section="columns"
|
|
1754
|
+
subsection={val}
|
|
1755
|
+
fieldName="prefix"
|
|
1756
|
+
label="Prefix"
|
|
1757
|
+
updateField={updateField}
|
|
1758
|
+
/>
|
|
1759
|
+
<TextField
|
|
1760
|
+
value={columns[val].suffix}
|
|
1761
|
+
section="columns"
|
|
1762
|
+
subsection={val}
|
|
1763
|
+
fieldName="suffix"
|
|
1764
|
+
label="Suffix"
|
|
1765
|
+
updateField={updateField}
|
|
1766
|
+
/>
|
|
1767
|
+
<TextField
|
|
1768
|
+
type="number"
|
|
1769
|
+
value={columns[val].roundToPlace}
|
|
1770
|
+
section="columns"
|
|
1771
|
+
subsection={val}
|
|
1772
|
+
fieldName="roundToPlace"
|
|
1773
|
+
label="Round"
|
|
1774
|
+
updateField={updateField}
|
|
1775
|
+
/>
|
|
1133
1776
|
</li>
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1777
|
+
<li>
|
|
1778
|
+
<label className="checkbox">
|
|
1779
|
+
<input
|
|
1780
|
+
type="checkbox"
|
|
1781
|
+
checked={state.columns[val].useCommas}
|
|
1782
|
+
onChange={(event) => {
|
|
1783
|
+
editColumn(val, 'useCommas', event.target.checked)
|
|
1784
|
+
}}
|
|
1785
|
+
/>
|
|
1786
|
+
<span className="edit-label">Add Commas to Numbers</span>
|
|
1787
|
+
</label>
|
|
1788
|
+
</li>
|
|
1789
|
+
<li>
|
|
1790
|
+
<label className="checkbox">
|
|
1791
|
+
<input
|
|
1792
|
+
type="checkbox"
|
|
1793
|
+
checked={state.columns[val].dataTable}
|
|
1794
|
+
onChange={(event) => {
|
|
1795
|
+
editColumn(val, 'dataTable', event.target.checked)
|
|
1796
|
+
}}
|
|
1797
|
+
/>
|
|
1798
|
+
<span className="edit-label">Display in Data Table</span>
|
|
1799
|
+
</label>
|
|
1800
|
+
</li>
|
|
1801
|
+
<li>
|
|
1802
|
+
<label className="checkbox">
|
|
1803
|
+
<input
|
|
1804
|
+
type="checkbox"
|
|
1805
|
+
checked={state.columns[val].tooltip}
|
|
1806
|
+
onChange={(event) => {
|
|
1807
|
+
editColumn(val, 'tooltip', event.target.checked)
|
|
1808
|
+
}}
|
|
1809
|
+
/>
|
|
1810
|
+
<span className="edit-label">Display in Tooltips</span>
|
|
1811
|
+
</label>
|
|
1812
|
+
</li>
|
|
1813
|
+
</ul>
|
|
1814
|
+
</fieldset>
|
|
1815
|
+
))}
|
|
1816
|
+
<button
|
|
1817
|
+
className={'btn full-width'}
|
|
1818
|
+
onClick={(event) => {
|
|
1819
|
+
event.preventDefault();
|
|
1820
|
+
addAdditionalColumn(additionalColumns.length + 1);
|
|
1821
|
+
}}
|
|
1822
|
+
>
|
|
1823
|
+
Add Column
|
|
1824
|
+
</button>
|
|
1825
|
+
</fieldset>
|
|
1826
|
+
}
|
|
1827
|
+
</AccordionItemPanel>
|
|
1828
|
+
</AccordionItem>{' '}
|
|
1829
|
+
{/* Columns */}
|
|
1830
|
+
{'navigation' !== state.general.type && (
|
|
1831
|
+
<AccordionItem>
|
|
1832
|
+
{' '}
|
|
1833
|
+
{/* Legend */}
|
|
1834
|
+
<AccordionItemHeading>
|
|
1835
|
+
<AccordionItemButton>Legend</AccordionItemButton>
|
|
1836
|
+
</AccordionItemHeading>
|
|
1837
|
+
<AccordionItemPanel>
|
|
1838
|
+
{(state.legend.type === "equalnumber" || state.legend.type === 'equalinterval') && (
|
|
1839
|
+
<label>
|
|
1840
|
+
<span className='edit-label'>Legend Type</span>
|
|
1841
|
+
<select
|
|
1842
|
+
value={legend.type}
|
|
1843
|
+
onChange={(event) => {
|
|
1844
|
+
handleEditorChanges('legendType', event.target.value);
|
|
1845
|
+
}}
|
|
1846
|
+
>
|
|
1847
|
+
<option value='equalnumber'>Equal Number</option>
|
|
1848
|
+
<option value='equalinterval'>Equal Interval</option>
|
|
1849
|
+
<option value='category'>Categorical</option>
|
|
1850
|
+
</select>
|
|
1851
|
+
</label>
|
|
1852
|
+
)}
|
|
1853
|
+
{'category' !== legend.type && (
|
|
1854
|
+
<label className='checkbox'>
|
|
1855
|
+
<input
|
|
1856
|
+
type='checkbox'
|
|
1857
|
+
checked={legend.separateZero || false}
|
|
1858
|
+
onChange={(event) =>
|
|
1859
|
+
handleEditorChanges('separateZero', event.target.checked)
|
|
1860
|
+
}
|
|
1861
|
+
/>
|
|
1862
|
+
<span className='edit-label'>
|
|
1863
|
+
Separate Zero
|
|
1864
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1865
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1866
|
+
<Tooltip.Content>
|
|
1867
|
+
<p>For numeric data, you can separate the zero value as its own data class.</p>
|
|
1868
|
+
</Tooltip.Content>
|
|
1869
|
+
</Tooltip>
|
|
1870
|
+
</span>
|
|
1871
|
+
|
|
1872
|
+
</label>
|
|
1873
|
+
)}
|
|
1874
|
+
{/* Temp Checkbox */}
|
|
1875
|
+
{state.legend.type === 'equalnumber' &&
|
|
1876
|
+
<label className="checkbox mt-4">
|
|
1877
|
+
<input type="checkbox" checked={ state.general.equalNumberOptIn } onChange={(event) => { handleEditorChanges("showEqualNumber", event.target.checked) }} />
|
|
1878
|
+
<span className="edit-label">Use new quantile legend</span>
|
|
1879
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1880
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1881
|
+
<Tooltip.Content>
|
|
1882
|
+
<p>This prevents numbers from being used in more than one category (ie. 0-1, 1-2, 2-3) </p>
|
|
1883
|
+
</Tooltip.Content>
|
|
1884
|
+
</Tooltip>
|
|
1885
|
+
</label>
|
|
1886
|
+
}
|
|
1887
|
+
{'category' !== legend.type && (
|
|
1888
|
+
<label>
|
|
1889
|
+
<span className='edit-label'>
|
|
1890
|
+
Number of Items
|
|
1891
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1892
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1893
|
+
<Tooltip.Content>
|
|
1894
|
+
<p>For numeric maps, select the number of data classes. Do not include designated special classes.</p>
|
|
1895
|
+
</Tooltip.Content>
|
|
1896
|
+
</Tooltip>
|
|
1897
|
+
</span>
|
|
1898
|
+
<select
|
|
1899
|
+
value={legend.numberOfItems}
|
|
1900
|
+
onChange={(event) => {
|
|
1901
|
+
handleEditorChanges('legendNumber', event.target.value);
|
|
1902
|
+
}}
|
|
1903
|
+
>
|
|
1904
|
+
{[...Array(numberOfItemsLimit).keys()].map((num) => {
|
|
1905
|
+
return (
|
|
1906
|
+
<option value={num + 1} key={num + 1}>
|
|
1907
|
+
{num + 1}
|
|
1908
|
+
</option>
|
|
1909
|
+
);
|
|
1910
|
+
})}
|
|
1911
|
+
</select>
|
|
1912
|
+
</label>
|
|
1913
|
+
)}
|
|
1914
|
+
{'category' === legend.type && (
|
|
1915
|
+
<React.Fragment>
|
|
1916
|
+
<label>
|
|
1917
|
+
<span className='edit-label'>
|
|
1918
|
+
Category Order
|
|
1919
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
1920
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
1921
|
+
<Tooltip.Content>
|
|
1922
|
+
<p>Drag map categories into preferred legend order. </p>
|
|
1923
|
+
</Tooltip.Content>
|
|
1924
|
+
</Tooltip>
|
|
1925
|
+
</span>
|
|
1926
|
+
</label>
|
|
1927
|
+
{/* TODO: Swap out this drag and drop library back to something simpler. I had to remove the old one because it hadn't been updated and wouldn't work with Webpack 5. This is overkill for our needs. */}
|
|
1928
|
+
<DragDropContext
|
|
1929
|
+
onDragEnd={({ source, destination }) =>
|
|
1930
|
+
categoryMove(source.index, destination.index)
|
|
1931
|
+
}
|
|
1932
|
+
>
|
|
1933
|
+
<Droppable droppableId='category_order'>
|
|
1934
|
+
{(provided) => (
|
|
1935
|
+
<ul
|
|
1936
|
+
{...provided.droppableProps}
|
|
1937
|
+
className='sort-list'
|
|
1938
|
+
ref={provided.innerRef}
|
|
1939
|
+
>
|
|
1940
|
+
<CategoryList />
|
|
1941
|
+
{provided.placeholder}
|
|
1942
|
+
</ul>
|
|
1943
|
+
)}
|
|
1944
|
+
</Droppable>
|
|
1945
|
+
</DragDropContext>
|
|
1946
|
+
{editorCatOrder.length >= 10 && (
|
|
1947
|
+
<section className='error-box my-2'>
|
|
1948
|
+
<div>
|
|
1949
|
+
<strong className='pt-1'>Warning</strong>
|
|
1950
|
+
<p>
|
|
1951
|
+
The maximum number of categorical legend items is 10. If
|
|
1952
|
+
your data has more than 10 categories your map will not
|
|
1953
|
+
display properly.
|
|
1954
|
+
</p>
|
|
1955
|
+
</div>
|
|
1956
|
+
</section>
|
|
1957
|
+
)}
|
|
1958
|
+
</React.Fragment>
|
|
1959
|
+
)}
|
|
1960
|
+
<TextField
|
|
1961
|
+
value={legend.title}
|
|
1962
|
+
updateField={updateField}
|
|
1963
|
+
section='legend'
|
|
1964
|
+
fieldName='title'
|
|
1965
|
+
label='Legend Title'
|
|
1966
|
+
placeholder='Legend Title'
|
|
1967
|
+
/>
|
|
1968
|
+
{false === legend.dynamicDescription && (
|
|
1969
|
+
<TextField
|
|
1970
|
+
type='textarea'
|
|
1971
|
+
value={legend.description}
|
|
1972
|
+
updateField={updateField}
|
|
1973
|
+
section='legend'
|
|
1974
|
+
fieldName='description'
|
|
1975
|
+
label='Legend Description'
|
|
1976
|
+
/>
|
|
1977
|
+
)}
|
|
1978
|
+
{true === legend.dynamicDescription && (
|
|
1979
|
+
<React.Fragment>
|
|
1980
|
+
<label>
|
|
1981
|
+
<span>Legend Description</span>
|
|
1982
|
+
<span className='subtext'>
|
|
1983
|
+
For {displayFilterLegendValue(activeFilterValueForDescription)}
|
|
1984
|
+
</span>
|
|
1985
|
+
<DynamicDesc
|
|
1986
|
+
value={
|
|
1987
|
+
legend.descriptions[String(activeFilterValueForDescription)]
|
|
1988
|
+
}
|
|
1989
|
+
/>
|
|
1990
|
+
</label>
|
|
1991
|
+
<label>
|
|
1992
|
+
<select
|
|
1993
|
+
value={String(activeFilterValueForDescription)}
|
|
1994
|
+
onChange={(event) => {
|
|
1995
|
+
handleEditorChanges(
|
|
1996
|
+
'changeActiveFilterValue',
|
|
1997
|
+
event.target.value
|
|
1998
|
+
);
|
|
1999
|
+
}}
|
|
2000
|
+
>
|
|
2001
|
+
{filterValueOptionList.map((arr, i) => {
|
|
2002
|
+
return (
|
|
2003
|
+
<option value={arr} key={i}>
|
|
2004
|
+
{displayFilterLegendValue(arr)}
|
|
2005
|
+
</option>
|
|
2006
|
+
);
|
|
2007
|
+
})}
|
|
2008
|
+
</select>
|
|
2009
|
+
</label>
|
|
2010
|
+
</React.Fragment>
|
|
2011
|
+
)}
|
|
2012
|
+
{filtersJSX.length > 0 && (
|
|
2013
|
+
<label className='checkbox'>
|
|
2014
|
+
<input
|
|
2015
|
+
type='checkbox'
|
|
2016
|
+
checked={legend.dynamicDescription}
|
|
2017
|
+
onChange={() => {
|
|
2018
|
+
handleEditorChanges(
|
|
2019
|
+
'dynamicDescription',
|
|
2020
|
+
filterValueOptionList[0]
|
|
2021
|
+
);
|
|
2022
|
+
}}
|
|
2023
|
+
/>
|
|
2024
|
+
<span className='edit-label'>
|
|
2025
|
+
Dynamic Legend Description
|
|
2026
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
2027
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
2028
|
+
<Tooltip.Content>
|
|
2029
|
+
<p>Check this option if the map has multiple filter controls and you want to specify a description for each filter selection.</p>
|
|
2030
|
+
</Tooltip.Content>
|
|
2031
|
+
</Tooltip>
|
|
2032
|
+
</span>
|
|
2033
|
+
</label>
|
|
2034
|
+
)}
|
|
2035
|
+
{filtersJSX.length > 0 || state.general.type === 'bubble' && (
|
|
2036
|
+
<label className='checkbox'>
|
|
2037
|
+
<input
|
|
2038
|
+
type='checkbox'
|
|
2039
|
+
checked={legend.unified}
|
|
2040
|
+
onChange={(event) =>
|
|
2041
|
+
handleEditorChanges('unifiedLegend', event.target.checked)
|
|
2042
|
+
}
|
|
2043
|
+
/>
|
|
2044
|
+
<span className='edit-label'>
|
|
2045
|
+
Unified Legend
|
|
2046
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
2047
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
2048
|
+
<Tooltip.Content>
|
|
2049
|
+
<p>For a map with filters, check this option if you want the high and low values in the legend to be based on <em>all</em> mapped values.</p>
|
|
2050
|
+
</Tooltip.Content>
|
|
2051
|
+
</Tooltip>
|
|
2052
|
+
</span>
|
|
2053
|
+
</label>
|
|
2054
|
+
)}
|
|
2055
|
+
</AccordionItemPanel>
|
|
2056
|
+
</AccordionItem>
|
|
2057
|
+
)}
|
|
2058
|
+
{'navigation' !== state.general.type && (
|
|
2059
|
+
<AccordionItem>
|
|
2060
|
+
{' '}
|
|
2061
|
+
{/* Filters */}
|
|
2062
|
+
<AccordionItemHeading>
|
|
2063
|
+
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2064
|
+
</AccordionItemHeading>
|
|
2065
|
+
<AccordionItemPanel>
|
|
2066
|
+
{filtersJSX.length > 0 ? (
|
|
2067
|
+
filtersJSX
|
|
2068
|
+
) : (
|
|
2069
|
+
<p style={{ textAlign: 'center' }}>There are currently no filters.</p>
|
|
2070
|
+
)}
|
|
2071
|
+
<button
|
|
2072
|
+
className={'btn full-width'}
|
|
2073
|
+
onClick={(event) => {
|
|
2074
|
+
event.preventDefault();
|
|
2075
|
+
changeFilter(null, 'addNew');
|
|
2076
|
+
}}
|
|
2077
|
+
>
|
|
2078
|
+
Add Filter
|
|
2079
|
+
</button>
|
|
2080
|
+
</AccordionItemPanel>
|
|
2081
|
+
</AccordionItem>
|
|
2082
|
+
)}
|
|
2083
|
+
{'navigation' !== state.general.type && (
|
|
2084
|
+
<AccordionItem>
|
|
2085
|
+
{' '}
|
|
2086
|
+
{/* Data Table */}
|
|
2087
|
+
<AccordionItemHeading>
|
|
2088
|
+
<AccordionItemButton>Data Table</AccordionItemButton>
|
|
2089
|
+
</AccordionItemHeading>
|
|
2090
|
+
<AccordionItemPanel>
|
|
2091
|
+
<TextField
|
|
2092
|
+
value={dataTable.title}
|
|
2093
|
+
updateField={updateField}
|
|
2094
|
+
section='dataTable'
|
|
2095
|
+
fieldName='title'
|
|
2096
|
+
label='Data Table Title'
|
|
2097
|
+
placeholder='Data Table'
|
|
2098
|
+
/>
|
|
2099
|
+
<TextField
|
|
2100
|
+
value={dataTable.indexLabel || ''}
|
|
2101
|
+
updateField={updateField}
|
|
2102
|
+
section='dataTable'
|
|
2103
|
+
fieldName='indexLabel'
|
|
2104
|
+
label='Index Column Header'
|
|
2105
|
+
placeholder='Location'
|
|
2106
|
+
tooltip={
|
|
2107
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
2108
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
2109
|
+
<Tooltip.Content>
|
|
2110
|
+
<p>To comply with 508 standards, if the first column in the data table has no header, enter a brief one here.</p>
|
|
2111
|
+
</Tooltip.Content>
|
|
2112
|
+
</Tooltip>
|
|
1210
2113
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
2114
|
+
/>
|
|
2115
|
+
<TextField
|
|
2116
|
+
value={dataTable.caption}
|
|
2117
|
+
updateField={updateField}
|
|
2118
|
+
section='dataTable'
|
|
2119
|
+
fieldName='caption'
|
|
2120
|
+
label='Data Table Caption'
|
|
2121
|
+
placeholder='Data Table'
|
|
2122
|
+
tooltip={
|
|
2123
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
2124
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
2125
|
+
<Tooltip.Content>
|
|
2126
|
+
<p>Enter a description of the data table to be read by screen readers.</p>
|
|
2127
|
+
</Tooltip.Content>
|
|
2128
|
+
</Tooltip>
|
|
1214
2129
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
2130
|
+
type="textarea"
|
|
2131
|
+
/>
|
|
2132
|
+
<label className='checkbox'>
|
|
2133
|
+
<input
|
|
2134
|
+
type='checkbox'
|
|
2135
|
+
checked={
|
|
2136
|
+
state.dataTable.forceDisplay !== undefined
|
|
2137
|
+
? state.dataTable.forceDisplay
|
|
2138
|
+
: !isDashboard
|
|
2139
|
+
}
|
|
2140
|
+
onChange={(event) => {
|
|
2141
|
+
handleEditorChanges('showDataTable', event.target.checked);
|
|
2142
|
+
}}
|
|
2143
|
+
/>
|
|
2144
|
+
<span className='edit-label'>
|
|
2145
|
+
Show Table
|
|
2146
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
2147
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
2148
|
+
<Tooltip.Content>
|
|
2149
|
+
<p>Data tables are required for 508 compliance. When choosing to hide this data table, replace with your own version.</p>
|
|
2150
|
+
</Tooltip.Content>
|
|
2151
|
+
</Tooltip>
|
|
2152
|
+
</span>
|
|
2153
|
+
</label>
|
|
2154
|
+
<label className='checkbox'>
|
|
2155
|
+
<input
|
|
2156
|
+
type='checkbox'
|
|
2157
|
+
checked={ state.dataTable.limitHeight }
|
|
2158
|
+
onChange={(event) => {
|
|
2159
|
+
handleEditorChanges('limitDataTableHeight', event.target.checked);
|
|
2160
|
+
}}
|
|
2161
|
+
/>
|
|
2162
|
+
<span className='edit-label'>Limit Table Height</span>
|
|
2163
|
+
</label>
|
|
2164
|
+
{state.dataTable.limitHeight &&
|
|
2165
|
+
<TextField
|
|
2166
|
+
value={dataTable.height}
|
|
2167
|
+
updateField={updateField}
|
|
2168
|
+
section='dataTable'
|
|
2169
|
+
fieldName='height'
|
|
2170
|
+
label='Data Table Height'
|
|
2171
|
+
placeholder='Height(px)'
|
|
2172
|
+
type="number"
|
|
2173
|
+
min="0"
|
|
2174
|
+
max="500"
|
|
2175
|
+
/>
|
|
2176
|
+
}
|
|
2177
|
+
<label className='checkbox'>
|
|
2178
|
+
<input
|
|
2179
|
+
type='checkbox'
|
|
2180
|
+
checked={state.general.expandDataTable || false}
|
|
2181
|
+
onChange={(event) => {
|
|
2182
|
+
handleEditorChanges('expandDataTable', event.target.checked);
|
|
2183
|
+
}}
|
|
2184
|
+
/>
|
|
2185
|
+
<span className='edit-label'>Map loads with data table expanded</span>
|
|
2186
|
+
</label>
|
|
2187
|
+
<label className='checkbox'>
|
|
2188
|
+
<input
|
|
2189
|
+
type='checkbox'
|
|
2190
|
+
checked={state.general.showDownloadButton}
|
|
2191
|
+
onChange={(event) => {
|
|
2192
|
+
handleEditorChanges('toggleDownloadButton', event.target.checked);
|
|
2193
|
+
}}
|
|
2194
|
+
/>
|
|
2195
|
+
<span className='edit-label'>Enable Download CSV Button</span>
|
|
2196
|
+
</label>
|
|
2197
|
+
</AccordionItemPanel>
|
|
2198
|
+
</AccordionItem>
|
|
2199
|
+
)}
|
|
2200
|
+
<AccordionItem>
|
|
2201
|
+
{' '}
|
|
2202
|
+
{/* Tooltips */}
|
|
2203
|
+
<AccordionItemHeading>
|
|
2204
|
+
<AccordionItemButton>Interactivity</AccordionItemButton>
|
|
2205
|
+
</AccordionItemHeading>
|
|
2206
|
+
<AccordionItemPanel>
|
|
2207
|
+
<label>
|
|
2208
|
+
<span className='edit-label'>
|
|
2209
|
+
Detail displays on{' '}
|
|
2210
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
2211
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
2212
|
+
<Tooltip.Content>
|
|
2213
|
+
<p>At mobile sizes, information always appears in a popover modal when a user taps on an item.</p>
|
|
2214
|
+
</Tooltip.Content>
|
|
2215
|
+
</Tooltip>
|
|
2216
|
+
</span>
|
|
2217
|
+
<select
|
|
2218
|
+
value={state.tooltips.appearanceType}
|
|
2219
|
+
onChange={(event) => {
|
|
2220
|
+
handleEditorChanges('appearanceType', event.target.value);
|
|
2221
|
+
}}
|
|
2222
|
+
>
|
|
2223
|
+
<option value='hover'>Hover - Tooltip</option>
|
|
2224
|
+
<option value='click'>Click - Popover Modal</option>
|
|
2225
|
+
</select>
|
|
2226
|
+
</label>
|
|
2227
|
+
{'click' === state.tooltips.appearanceType && (
|
|
2228
|
+
<TextField
|
|
2229
|
+
value={tooltips.linkLabel}
|
|
2230
|
+
section='tooltips'
|
|
2231
|
+
fieldName='linkLabel'
|
|
2232
|
+
label='Tooltips Link Label'
|
|
2233
|
+
updateField={updateField}
|
|
2234
|
+
/>
|
|
2235
|
+
)}
|
|
2236
|
+
<label className='checkbox'>
|
|
2237
|
+
<input
|
|
2238
|
+
type='checkbox'
|
|
2239
|
+
checked={state.tooltips.capitalizeLabels}
|
|
2240
|
+
onChange={(event) => {
|
|
2241
|
+
handleEditorChanges('capitalizeLabels', event.target.checked);
|
|
2242
|
+
}}
|
|
2243
|
+
/>
|
|
2244
|
+
<span className='edit-label'>Capitalize text inside tooltip</span>
|
|
2245
|
+
</label>
|
|
2246
|
+
</AccordionItemPanel>
|
|
2247
|
+
</AccordionItem>
|
|
2248
|
+
<AccordionItem>
|
|
2249
|
+
{' '}
|
|
2250
|
+
{/* Visual */}
|
|
2251
|
+
<AccordionItemHeading>
|
|
2252
|
+
<AccordionItemButton>Visual</AccordionItemButton>
|
|
2253
|
+
</AccordionItemHeading>
|
|
2254
|
+
<AccordionItemPanel>
|
|
2255
|
+
<label>
|
|
2256
|
+
<span className='edit-label'>Header Theme</span>
|
|
2257
|
+
<ul className='color-palette'>
|
|
2258
|
+
{headerColors.map((palette) => {
|
|
2259
|
+
return (
|
|
2260
|
+
<li
|
|
2261
|
+
title={palette}
|
|
2262
|
+
key={palette}
|
|
2263
|
+
onClick={() => {
|
|
2264
|
+
handleEditorChanges('headerColor', palette);
|
|
2265
|
+
}}
|
|
2266
|
+
className={
|
|
2267
|
+
state.general.headerColor === palette
|
|
2268
|
+
? 'selected ' + palette
|
|
2269
|
+
: palette
|
|
2270
|
+
}
|
|
2271
|
+
></li>
|
|
2272
|
+
);
|
|
2273
|
+
})}
|
|
2274
|
+
</ul>
|
|
2275
|
+
</label>
|
|
2276
|
+
<label className='checkbox'>
|
|
2277
|
+
<input
|
|
2278
|
+
type='checkbox'
|
|
2279
|
+
checked={state.general.showTitle || false}
|
|
2280
|
+
onChange={(event) => {
|
|
2281
|
+
handleEditorChanges('showTitle', event.target.checked);
|
|
2282
|
+
}}
|
|
2283
|
+
/>
|
|
2284
|
+
<span className='edit-label'>Show Title</span>
|
|
2285
|
+
</label>
|
|
2286
|
+
|
|
2287
|
+
<label className='checkbox'>
|
|
2288
|
+
<input
|
|
2289
|
+
type='checkbox'
|
|
2290
|
+
checked={state.general.hideGeoColumnInTooltip || false}
|
|
2291
|
+
onChange={(event) => {
|
|
2292
|
+
handleEditorChanges('hideGeoColumnInTooltip', event.target.checked);
|
|
2293
|
+
}}
|
|
2294
|
+
/>
|
|
2295
|
+
<span className='edit-label'>Hide Geography Column Name in Tooltip</span>
|
|
2296
|
+
</label>
|
|
2297
|
+
|
|
2298
|
+
<label className='checkbox'>
|
|
2299
|
+
<input
|
|
2300
|
+
type='checkbox'
|
|
2301
|
+
checked={state.general.hidePrimaryColumnInTooltip || false}
|
|
2302
|
+
onChange={(event) => {
|
|
2303
|
+
handleEditorChanges('hidePrimaryColumnInTooltip', event.target.checked);
|
|
2304
|
+
}}
|
|
2305
|
+
/>
|
|
2306
|
+
<span className='edit-label'>Hide Primary Column Name in Tooltip</span>
|
|
2307
|
+
</label>
|
|
2308
|
+
|
|
2309
|
+
{'navigation' !== state.general.type && (
|
|
2310
|
+
<label className='checkbox'>
|
|
2311
|
+
<input
|
|
2312
|
+
type='checkbox'
|
|
2313
|
+
checked={state.general.showSidebar || false}
|
|
2314
|
+
onChange={(event) => {
|
|
2315
|
+
handleEditorChanges('showSidebar', event.target.checked);
|
|
2316
|
+
}}
|
|
2317
|
+
/>
|
|
2318
|
+
<span className='edit-label'>Show Legend</span>
|
|
2319
|
+
</label>
|
|
2320
|
+
)}
|
|
2321
|
+
{'navigation' !== state.general.type && (
|
|
2322
|
+
<label>
|
|
2323
|
+
<span className='edit-label'>Legend Position</span>
|
|
2324
|
+
<select
|
|
2325
|
+
value={legend.position || false}
|
|
2326
|
+
onChange={(event) => {
|
|
2327
|
+
handleEditorChanges('sidebarPosition', event.target.value);
|
|
2328
|
+
}}
|
|
2329
|
+
>
|
|
2330
|
+
<option value='side'>Side</option>
|
|
2331
|
+
<option value='bottom'>Bottom</option>
|
|
2332
|
+
</select>
|
|
2333
|
+
</label>
|
|
2334
|
+
)}
|
|
2335
|
+
{'side' === legend.position && (
|
|
2336
|
+
<label className='checkbox'>
|
|
2337
|
+
<input
|
|
2338
|
+
type='checkbox'
|
|
2339
|
+
checked={legend.singleColumn}
|
|
2340
|
+
onChange={(event) => {
|
|
2341
|
+
handleEditorChanges('singleColumnLegend', event.target.checked);
|
|
2342
|
+
}}
|
|
2343
|
+
/>
|
|
2344
|
+
<span className='edit-label'>Single Column Legend</span>
|
|
2345
|
+
</label>
|
|
2346
|
+
)}
|
|
2347
|
+
{'navigation' === state.general.type && (
|
|
2348
|
+
<label className='checkbox'>
|
|
2349
|
+
<input
|
|
2350
|
+
type='checkbox'
|
|
2351
|
+
checked={state.general.fullBorder || false}
|
|
2352
|
+
onChange={(event) => {
|
|
2353
|
+
handleEditorChanges('fullBorder', event.target.checked);
|
|
2354
|
+
}}
|
|
2355
|
+
/>
|
|
2356
|
+
<span className='edit-label'>Add border around map</span>
|
|
2357
|
+
</label>
|
|
2358
|
+
)}
|
|
2359
|
+
<label>
|
|
2360
|
+
<span className='edit-label'>Geo Border Color</span>
|
|
2361
|
+
<select
|
|
2362
|
+
value={state.general.geoBorderColor || false}
|
|
2363
|
+
onChange={(event) => {
|
|
2364
|
+
handleEditorChanges('geoBorderColor', event.target.value);
|
|
2365
|
+
}}
|
|
2366
|
+
>
|
|
2367
|
+
<option value='darkGray'>Dark Gray (Default)</option>
|
|
2368
|
+
<option value='sameAsBackground'>White</option>
|
|
2369
|
+
</select>
|
|
2370
|
+
</label>
|
|
2371
|
+
<label>
|
|
2372
|
+
<span className='edit-label'>Map Color Palette</span>
|
|
2373
|
+
</label>
|
|
2374
|
+
{/* <InputCheckbox section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
|
|
2375
|
+
<InputToggle type='3d' section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} />
|
|
2376
|
+
<span>Sequential</span>
|
|
2377
|
+
<ul className='color-palette'>
|
|
2378
|
+
{filteredPallets
|
|
2379
|
+
.map((palette) => {
|
|
2380
|
+
const colorOne = {
|
|
2381
|
+
backgroundColor: colorPalettes[palette][2],
|
|
2382
|
+
};
|
|
2383
|
+
|
|
2384
|
+
const colorTwo = {
|
|
2385
|
+
backgroundColor: colorPalettes[palette][4],
|
|
2386
|
+
};
|
|
2387
|
+
|
|
2388
|
+
const colorThree = {
|
|
2389
|
+
backgroundColor: colorPalettes[palette][6],
|
|
2390
|
+
};
|
|
2391
|
+
|
|
2392
|
+
return (
|
|
2393
|
+
<li
|
|
2394
|
+
title={palette}
|
|
2395
|
+
key={palette}
|
|
2396
|
+
onClick={() => {
|
|
2397
|
+
handleEditorChanges('color', palette);
|
|
2398
|
+
}}
|
|
2399
|
+
className={state.color === palette ? 'selected' : ''}
|
|
2400
|
+
>
|
|
2401
|
+
<span style={colorOne}></span>
|
|
2402
|
+
<span style={colorTwo}></span>
|
|
2403
|
+
<span style={colorThree}></span>
|
|
2404
|
+
</li>
|
|
2405
|
+
);
|
|
2406
|
+
})}
|
|
2407
|
+
</ul>
|
|
2408
|
+
<span>Non-Sequential</span>
|
|
2409
|
+
<ul className='color-palette'>
|
|
2410
|
+
{filteredQualitative
|
|
2411
|
+
.map((palette) => {
|
|
2412
|
+
const colorOne = {
|
|
2413
|
+
backgroundColor: colorPalettes[palette][2],
|
|
2414
|
+
};
|
|
2415
|
+
|
|
2416
|
+
const colorTwo = {
|
|
2417
|
+
backgroundColor: colorPalettes[palette][4],
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2420
|
+
const colorThree = {
|
|
2421
|
+
backgroundColor: colorPalettes[palette][6],
|
|
2422
|
+
};
|
|
2423
|
+
|
|
2424
|
+
return (
|
|
2425
|
+
<li
|
|
2426
|
+
title={palette}
|
|
2427
|
+
key={palette}
|
|
2428
|
+
onClick={() => {
|
|
2429
|
+
handleEditorChanges('color', palette);
|
|
2430
|
+
}}
|
|
2431
|
+
className={state.color === palette ? 'selected' : ''}
|
|
2432
|
+
>
|
|
2433
|
+
<span style={colorOne}></span>
|
|
2434
|
+
<span style={colorTwo}></span>
|
|
2435
|
+
<span style={colorThree}></span>
|
|
2436
|
+
</li>
|
|
2437
|
+
);
|
|
2438
|
+
})}
|
|
2439
|
+
</ul>
|
|
2440
|
+
<TextField
|
|
2441
|
+
type='number'
|
|
2442
|
+
value={state.visual.minBubbleSize}
|
|
2443
|
+
section='visual'
|
|
2444
|
+
fieldName='minBubbleSize'
|
|
2445
|
+
label='Minimum Bubble Size'
|
|
2446
|
+
updateField={updateField}
|
|
2447
|
+
/>
|
|
2448
|
+
<TextField
|
|
2449
|
+
type='number'
|
|
2450
|
+
value={state.visual.maxBubbleSize}
|
|
2451
|
+
section='visual'
|
|
2452
|
+
fieldName='maxBubbleSize'
|
|
2453
|
+
label='Maximum Bubble Size'
|
|
2454
|
+
updateField={updateField}
|
|
2455
|
+
/>
|
|
2456
|
+
{ (state.general.geoType === 'world' || state.general.geoType === 'us') &&
|
|
2457
|
+
<label className='checkbox'>
|
|
2458
|
+
<input
|
|
2459
|
+
type='checkbox'
|
|
2460
|
+
checked={state.visual.showBubbleZeros}
|
|
2461
|
+
onChange={(event) => {
|
|
2462
|
+
handleEditorChanges('showBubbleZeros', event.target.checked);
|
|
2463
|
+
}}
|
|
2464
|
+
/>
|
|
2465
|
+
<span className='edit-label'>Show Data with Zero's on Bubble Map</span>
|
|
2466
|
+
</label>
|
|
2467
|
+
}
|
|
2468
|
+
{state.general.geoType === 'world' &&
|
|
2469
|
+
<label className='checkbox'>
|
|
2470
|
+
<input
|
|
2471
|
+
type='checkbox'
|
|
2472
|
+
checked={state.general.allowMapZoom}
|
|
2473
|
+
onChange={(event) => {
|
|
2474
|
+
handleEditorChanges('allowMapZoom', event.target.checked);
|
|
2475
|
+
}}
|
|
2476
|
+
/>
|
|
2477
|
+
<span className='edit-label'>Allow Map Zooming</span>
|
|
2478
|
+
</label>
|
|
2479
|
+
}
|
|
2480
|
+
{state.general.type === 'bubble' &&
|
|
2481
|
+
<label className='checkbox'>
|
|
2482
|
+
<input
|
|
2483
|
+
type='checkbox'
|
|
2484
|
+
checked={state.visual.extraBubbleBorder}
|
|
2485
|
+
onChange={(event) => {
|
|
2486
|
+
handleEditorChanges('toggleExtraBubbleBorder', event.target.checked);
|
|
2487
|
+
}}
|
|
2488
|
+
/>
|
|
2489
|
+
<span className='edit-label'>Bubble Map has extra border</span>
|
|
2490
|
+
</label>
|
|
2491
|
+
}
|
|
2492
|
+
</AccordionItemPanel>
|
|
2493
|
+
</AccordionItem>
|
|
2494
|
+
</Accordion>
|
|
2495
|
+
</form>
|
|
2496
|
+
<AdvancedEditor loadConfig={loadConfig} state={state} convertStateToConfig={convertStateToConfig} />
|
|
2497
|
+
|
|
2498
|
+
</section>
|
|
2499
|
+
</section>
|
|
2500
|
+
</ErrorBoundary>
|
|
2501
|
+
);
|
|
2502
|
+
};
|
|
1252
2503
|
|
|
1253
2504
|
export default EditorPanel;
|