@cdc/map 4.24.12 → 4.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdcmap.js +51010 -49337
- package/examples/annotation/index.json +1 -1
- package/examples/custom-map-layers.json +1 -1
- package/examples/default-geocode.json +2 -2
- package/examples/private/DEV-9989.json +229 -0
- package/examples/private/ardi.json +180 -0
- package/examples/private/colors 2.json +416 -0
- package/examples/private/colors.json +416 -0
- package/examples/private/colors.json.zip +0 -0
- package/examples/private/customColors.json +45348 -0
- package/examples/private/mmr.json +246 -0
- package/examples/private/test.json +1632 -0
- package/index.html +12 -14
- package/package.json +8 -3
- package/src/CdcMap.tsx +126 -394
- package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +9 -0
- package/src/_stories/CdcMap.stories.tsx +1 -1
- package/src/_stories/GoogleMap.stories.tsx +19 -0
- package/src/_stories/_mock/DEV-10148.json +859 -0
- package/src/_stories/_mock/DEV-9989.json +229 -0
- package/src/_stories/_mock/example-city-state.json +1 -1
- package/src/_stories/_mock/google-map.json +819 -0
- package/src/components/Annotation/Annotation.Draggable.tsx +34 -43
- package/src/components/Annotation/AnnotationDropdown.tsx +4 -4
- package/src/components/CityList.tsx +2 -2
- package/src/components/DataTable.tsx +8 -9
- package/src/components/EditorPanel/components/EditorPanel.tsx +96 -270
- package/src/components/GoogleMap/components/GoogleMap.tsx +67 -0
- package/src/components/GoogleMap/index.tsx +3 -0
- package/src/components/Legend/components/Legend.tsx +40 -30
- package/src/components/Legend/components/LegendItem.Hex.tsx +7 -3
- package/src/components/Legend/components/index.scss +22 -16
- package/src/components/Modal.tsx +6 -5
- package/src/components/NavigationMenu.tsx +5 -4
- package/src/components/UsaMap/components/TerritoriesSection.tsx +56 -0
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +3 -3
- package/src/components/UsaMap/components/UsaMap.County.tsx +1 -1
- package/src/components/UsaMap/components/UsaMap.Region.tsx +12 -8
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +2 -2
- package/src/components/UsaMap/components/UsaMap.State.tsx +23 -29
- package/src/components/WorldMap/WorldMap.tsx +3 -5
- package/src/context.ts +0 -12
- package/src/data/initial-state.js +2 -2
- package/src/data/supported-geos.js +23 -3
- package/src/helpers/applyColorToLegend.ts +3 -3
- package/src/helpers/closeModal.ts +9 -0
- package/src/helpers/handleMapAriaLabels.ts +38 -0
- package/src/helpers/indexOfIgnoreType.ts +8 -0
- package/src/helpers/navigationHandler.ts +21 -0
- package/src/helpers/toTitleCase.ts +44 -0
- package/src/helpers/validateFipsCodeLength.ts +30 -0
- package/src/hooks/useResizeObserver.ts +42 -0
- package/src/hooks/useTooltip.ts +4 -2
- package/src/index.jsx +1 -0
- package/src/scss/editor-panel.scss +2 -1
- package/src/scss/filters.scss +0 -5
- package/src/scss/main.scss +57 -61
- package/src/scss/map.scss +1 -13
- package/src/types/MapConfig.ts +20 -11
- package/src/types/MapContext.ts +4 -12
|
@@ -26,6 +26,7 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
|
26
26
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
27
27
|
import InputToggle from '@cdc/core/components/inputs/InputToggle'
|
|
28
28
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
29
|
+
import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
|
|
29
30
|
|
|
30
31
|
// Assets
|
|
31
32
|
import UsaGraphic from '@cdc/core/assets/icon-map-usa.svg'
|
|
@@ -37,28 +38,24 @@ import usaDefaultConfig from '../../../../examples/default-usa.json'
|
|
|
37
38
|
import countyDefaultConfig from '../../../../examples/default-county.json'
|
|
38
39
|
import useMapLayers from '../../../hooks/useMapLayers.tsx'
|
|
39
40
|
|
|
40
|
-
import { useFilters } from '@cdc/core/components/Filters'
|
|
41
|
-
|
|
42
41
|
import HexSetting from './HexShapeSettings.jsx'
|
|
43
42
|
import ConfigContext from '../../../context.ts'
|
|
44
43
|
import { MapContext } from '../../../types/MapContext.js'
|
|
45
44
|
import { TextField } from './Inputs'
|
|
46
45
|
import Alert from '@cdc/core/components/Alert'
|
|
46
|
+
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
47
|
+
import { Select } from '@cdc/core/components/EditorPanel/Inputs'
|
|
47
48
|
|
|
48
49
|
// Todo: move to useReducer, seperate files out.
|
|
49
50
|
const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
50
51
|
// prettier-ignore
|
|
51
52
|
const {
|
|
52
|
-
changeFilterActive,
|
|
53
|
-
columnsInData = [],
|
|
54
53
|
isDashboard,
|
|
55
54
|
isDebug,
|
|
56
|
-
isEditor,
|
|
57
55
|
loadConfig,
|
|
58
56
|
runtimeFilters,
|
|
59
57
|
runtimeLegend,
|
|
60
58
|
setParentConfig,
|
|
61
|
-
setRuntimeFilters,
|
|
62
59
|
setState,
|
|
63
60
|
state,
|
|
64
61
|
tooltipId,
|
|
@@ -70,6 +67,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
70
67
|
} = useContext<MapContext>(ConfigContext)
|
|
71
68
|
|
|
72
69
|
const { general, columns, legend, table, tooltips } = state
|
|
70
|
+
const columnsInData = state?.data?.[0] ? Object.keys(state.data[0]) : []
|
|
73
71
|
|
|
74
72
|
const [configTextboxValue, setConfigTextbox] = useState({}) // eslint-disable-line
|
|
75
73
|
|
|
@@ -79,13 +77,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
79
77
|
|
|
80
78
|
const [activeFilterValueForDescription, setActiveFilterValueForDescription] = useState([0, 0])
|
|
81
79
|
|
|
82
|
-
const { handleFilterOrder, filterOrderOptions, filterStyleOptions } = useFilters({
|
|
83
|
-
config: state,
|
|
84
|
-
setConfig: setState,
|
|
85
|
-
filteredData: runtimeFilters,
|
|
86
|
-
setFilteredData: setRuntimeFilters
|
|
87
|
-
})
|
|
88
|
-
|
|
89
80
|
const headerColors = [
|
|
90
81
|
'theme-blue',
|
|
91
82
|
'theme-purple',
|
|
@@ -241,6 +232,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
241
232
|
|
|
242
233
|
const handleEditorChanges = async (property, value) => {
|
|
243
234
|
switch (property) {
|
|
235
|
+
case 'navigationTarget':
|
|
236
|
+
setState({
|
|
237
|
+
...state,
|
|
238
|
+
general: {
|
|
239
|
+
...state.general,
|
|
240
|
+
navigationTarget: value
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
break
|
|
244
244
|
// change these to be more generic.
|
|
245
245
|
// updateVisualPropertyValue
|
|
246
246
|
// updateGeneralPropertyValue, etc.
|
|
@@ -725,6 +725,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
725
725
|
}
|
|
726
726
|
})
|
|
727
727
|
break
|
|
728
|
+
case 'google-map':
|
|
729
|
+
setState({
|
|
730
|
+
...state,
|
|
731
|
+
general: {
|
|
732
|
+
...state.general,
|
|
733
|
+
geoType: 'google-map'
|
|
734
|
+
}
|
|
735
|
+
})
|
|
728
736
|
default:
|
|
729
737
|
break
|
|
730
738
|
}
|
|
@@ -1073,42 +1081,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1073
1081
|
})
|
|
1074
1082
|
}
|
|
1075
1083
|
|
|
1076
|
-
const MapFilters = () => {
|
|
1077
|
-
return (
|
|
1078
|
-
<>
|
|
1079
|
-
<label>
|
|
1080
|
-
Filter Behavior
|
|
1081
|
-
<select
|
|
1082
|
-
value={state.filterBehavior}
|
|
1083
|
-
onChange={e => {
|
|
1084
|
-
setState({
|
|
1085
|
-
...state,
|
|
1086
|
-
filterBehavior: e.target.value
|
|
1087
|
-
})
|
|
1088
|
-
}}
|
|
1089
|
-
>
|
|
1090
|
-
<option key='Apply Button' value='Apply Button'>
|
|
1091
|
-
Apply Button
|
|
1092
|
-
</option>
|
|
1093
|
-
<option key='Filter Change' value='Filter Change'>
|
|
1094
|
-
Filter Change
|
|
1095
|
-
</option>
|
|
1096
|
-
</select>
|
|
1097
|
-
</label>
|
|
1098
|
-
<label>
|
|
1099
|
-
<TextField
|
|
1100
|
-
type='textarea'
|
|
1101
|
-
value={state.filterIntro}
|
|
1102
|
-
fieldName='filterIntro'
|
|
1103
|
-
label='Filter Intro text'
|
|
1104
|
-
updateField={updateField}
|
|
1105
|
-
/>
|
|
1106
|
-
</label>
|
|
1107
|
-
{filtersJSX}
|
|
1108
|
-
</>
|
|
1109
|
-
)
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
1084
|
const removeAdditionalColumn = columnName => {
|
|
1113
1085
|
const newColumns = state.columns
|
|
1114
1086
|
|
|
@@ -1271,38 +1243,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1271
1243
|
return true
|
|
1272
1244
|
})
|
|
1273
1245
|
|
|
1274
|
-
const updateField = (
|
|
1275
|
-
if (!section) {
|
|
1276
|
-
setState({
|
|
1277
|
-
...state,
|
|
1278
|
-
[fieldName]: newValue
|
|
1279
|
-
})
|
|
1280
|
-
return
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
const isArray = Array.isArray(state[section])
|
|
1284
|
-
|
|
1285
|
-
let sectionValue = isArray ? [...state[section], newValue] : { ...state[section], [fieldName]: newValue }
|
|
1286
|
-
|
|
1287
|
-
if (null !== subsection) {
|
|
1288
|
-
if (isArray) {
|
|
1289
|
-
sectionValue = [...state[section]]
|
|
1290
|
-
sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
|
|
1291
|
-
} else {
|
|
1292
|
-
sectionValue = {
|
|
1293
|
-
...state[section],
|
|
1294
|
-
[subsection]: { ...state[section][subsection], [fieldName]: newValue }
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
let updatedState = {
|
|
1300
|
-
...state,
|
|
1301
|
-
[section]: sectionValue
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
setState(updatedState)
|
|
1305
|
-
}
|
|
1246
|
+
const updateField = updateFieldFactory(state, setState)
|
|
1306
1247
|
|
|
1307
1248
|
const onBackClick = () => {
|
|
1308
1249
|
setDisplayPanel(!displayPanel)
|
|
@@ -1314,163 +1255,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1314
1255
|
|
|
1315
1256
|
const usedFilterColumns = {}
|
|
1316
1257
|
|
|
1317
|
-
const filtersJSX = state.filters.map((filter, index) => {
|
|
1318
|
-
if (filter.type === 'url') return <></>
|
|
1319
|
-
|
|
1320
|
-
if (filter.columnName) {
|
|
1321
|
-
usedFilterColumns[filter.columnName] = true
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
return (
|
|
1325
|
-
<>
|
|
1326
|
-
<fieldset className='edit-block' key={`filter-${index}`}>
|
|
1327
|
-
<button
|
|
1328
|
-
className='remove-column'
|
|
1329
|
-
onClick={e => {
|
|
1330
|
-
e.preventDefault()
|
|
1331
|
-
changeFilter(index, 'remove')
|
|
1332
|
-
}}
|
|
1333
|
-
>
|
|
1334
|
-
Remove
|
|
1335
|
-
</button>
|
|
1336
|
-
<TextField
|
|
1337
|
-
value={state.filters[index].label}
|
|
1338
|
-
section='filters'
|
|
1339
|
-
subsection={index}
|
|
1340
|
-
fieldName='label'
|
|
1341
|
-
label='Label'
|
|
1342
|
-
updateField={updateField}
|
|
1343
|
-
/>
|
|
1344
|
-
<label>
|
|
1345
|
-
<span className='edit-label column-heading'>
|
|
1346
|
-
Filter Column
|
|
1347
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1348
|
-
<Tooltip.Target>
|
|
1349
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1350
|
-
</Tooltip.Target>
|
|
1351
|
-
<Tooltip.Content>
|
|
1352
|
-
<p>
|
|
1353
|
-
Selecting a column will add a dropdown menu below the map legend and allow users to filter based on
|
|
1354
|
-
the values in this column.
|
|
1355
|
-
</p>
|
|
1356
|
-
</Tooltip.Content>
|
|
1357
|
-
</Tooltip>
|
|
1358
|
-
</span>
|
|
1359
|
-
<select
|
|
1360
|
-
value={filter.columnName}
|
|
1361
|
-
onChange={event => {
|
|
1362
|
-
changeFilter(index, 'columnName', event.target.value)
|
|
1363
|
-
}}
|
|
1364
|
-
>
|
|
1365
|
-
{columnsOptions.filter(({ key }) => undefined === usedFilterColumns[key] || filter.columnName === key)}
|
|
1366
|
-
</select>
|
|
1367
|
-
</label>
|
|
1368
|
-
|
|
1369
|
-
<label>
|
|
1370
|
-
<span className='edit-showDropdown column-heading'>Show Filter Input</span>
|
|
1371
|
-
<input
|
|
1372
|
-
type='checkbox'
|
|
1373
|
-
checked={filter.showDropdown === undefined ? true : filter.showDropdown}
|
|
1374
|
-
onChange={e => {
|
|
1375
|
-
changeFilter(index, 'showDropdown', e.target.checked)
|
|
1376
|
-
}}
|
|
1377
|
-
/>
|
|
1378
|
-
</label>
|
|
1379
|
-
|
|
1380
|
-
<label>
|
|
1381
|
-
<span className='edit-filterOrder column-heading'>Filter Style</span>
|
|
1382
|
-
<select
|
|
1383
|
-
value={filter.filterStyle}
|
|
1384
|
-
onChange={e => {
|
|
1385
|
-
changeFilter(index, 'filterStyle', e.target.value)
|
|
1386
|
-
}}
|
|
1387
|
-
>
|
|
1388
|
-
{filterStyleOptions.map((option, index) => {
|
|
1389
|
-
return (
|
|
1390
|
-
<option value={option} key={`filter-${option}--${index}`}>
|
|
1391
|
-
{option}
|
|
1392
|
-
</option>
|
|
1393
|
-
)
|
|
1394
|
-
})}
|
|
1395
|
-
</select>
|
|
1396
|
-
</label>
|
|
1397
|
-
|
|
1398
|
-
<label>
|
|
1399
|
-
<span className='edit-filterOrder column-heading'>Filter Order</span>
|
|
1400
|
-
<select
|
|
1401
|
-
value={filter.order}
|
|
1402
|
-
onChange={e => {
|
|
1403
|
-
changeFilter(index, 'filterOrder', e.target.value)
|
|
1404
|
-
changeFilterActive(index, filter.values[0])
|
|
1405
|
-
}}
|
|
1406
|
-
>
|
|
1407
|
-
{filterOrderOptions.map((option, index) => {
|
|
1408
|
-
return (
|
|
1409
|
-
<option value={option.value} key={`filter-${index}`}>
|
|
1410
|
-
{option.label}
|
|
1411
|
-
</option>
|
|
1412
|
-
)
|
|
1413
|
-
})}
|
|
1414
|
-
</select>
|
|
1415
|
-
</label>
|
|
1416
|
-
|
|
1417
|
-
<TextField
|
|
1418
|
-
value={state.filters[index].setByQueryParameter}
|
|
1419
|
-
section='filters'
|
|
1420
|
-
subsection={index}
|
|
1421
|
-
fieldName='setByQueryParameter'
|
|
1422
|
-
label='Default Value Set By Query String Parameter'
|
|
1423
|
-
updateField={updateField}
|
|
1424
|
-
/>
|
|
1425
|
-
|
|
1426
|
-
{filter.order === 'cust' && (
|
|
1427
|
-
<DragDropContext
|
|
1428
|
-
onDragEnd={({ source, destination }) =>
|
|
1429
|
-
handleFilterOrder(source.index, destination?.index, index, state.filters?.[index])
|
|
1430
|
-
}
|
|
1431
|
-
>
|
|
1432
|
-
<Droppable droppableId='filter_order'>
|
|
1433
|
-
{provided => (
|
|
1434
|
-
<ul
|
|
1435
|
-
{...provided.droppableProps}
|
|
1436
|
-
className='sort-list'
|
|
1437
|
-
ref={provided.innerRef}
|
|
1438
|
-
style={{ marginTop: '1em' }}
|
|
1439
|
-
>
|
|
1440
|
-
{state.filters[index]?.values.map((value, index) => {
|
|
1441
|
-
return (
|
|
1442
|
-
<Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
|
|
1443
|
-
{(provided, snapshot) => (
|
|
1444
|
-
<li>
|
|
1445
|
-
<div
|
|
1446
|
-
className={snapshot.isDragging ? 'currently-dragging' : ''}
|
|
1447
|
-
style={getItemStyle(
|
|
1448
|
-
snapshot.isDragging,
|
|
1449
|
-
provided.draggableProps.style,
|
|
1450
|
-
sortableItemStyles
|
|
1451
|
-
)}
|
|
1452
|
-
ref={provided.innerRef}
|
|
1453
|
-
{...provided.draggableProps}
|
|
1454
|
-
{...provided.dragHandleProps}
|
|
1455
|
-
>
|
|
1456
|
-
{value}
|
|
1457
|
-
</div>
|
|
1458
|
-
</li>
|
|
1459
|
-
)}
|
|
1460
|
-
</Draggable>
|
|
1461
|
-
)
|
|
1462
|
-
})}
|
|
1463
|
-
{provided.placeholder}
|
|
1464
|
-
</ul>
|
|
1465
|
-
)}
|
|
1466
|
-
</Droppable>
|
|
1467
|
-
</DragDropContext>
|
|
1468
|
-
)}
|
|
1469
|
-
</fieldset>
|
|
1470
|
-
</>
|
|
1471
|
-
)
|
|
1472
|
-
})
|
|
1473
|
-
|
|
1474
1258
|
const StateOptionList = () => {
|
|
1475
1259
|
const arrOfArrays = Object.entries(supportedStatesFipsCodes)
|
|
1476
1260
|
|
|
@@ -1603,13 +1387,29 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1603
1387
|
</AccordionItemHeading>
|
|
1604
1388
|
<AccordionItemPanel>
|
|
1605
1389
|
{/* Geography */}
|
|
1390
|
+
{/*<Select*/}
|
|
1391
|
+
{/* options={[*/}
|
|
1392
|
+
{/* { value: 'us', label: 'United States' },*/}
|
|
1393
|
+
{/* { value: 'us-region', label: 'U.S. Region' },*/}
|
|
1394
|
+
{/* { value: 'world', label: 'World' },*/}
|
|
1395
|
+
{/* { value: 'single-state', label: 'U.S. State' },*/}
|
|
1396
|
+
{/* { value: 'google-map', label: 'Google Map API' }*/}
|
|
1397
|
+
{/* ]}*/}
|
|
1398
|
+
{/* section={'general'}*/}
|
|
1399
|
+
{/* fieldName={'geoType'}*/}
|
|
1400
|
+
{/* label='Geography'*/}
|
|
1401
|
+
{/* updateField={updateField}*/}
|
|
1402
|
+
{/*/>*/}
|
|
1403
|
+
|
|
1606
1404
|
<label>
|
|
1607
1405
|
<span className='edit-label column-heading'>
|
|
1608
1406
|
<span>Geography</span>
|
|
1609
1407
|
</span>
|
|
1610
|
-
<ul className='geo-buttons'>
|
|
1408
|
+
<ul className='geo-buttons d-grid' style={{ gridTemplateColumns: 'repeat(2, 1fr)', gap: '8px' }}>
|
|
1611
1409
|
<button
|
|
1612
|
-
className={
|
|
1410
|
+
className={`${
|
|
1411
|
+
state.general.geoType === 'us' || state.general.geoType === 'us-county' ? 'active' : ''
|
|
1412
|
+
} full-width`}
|
|
1613
1413
|
onClick={e => {
|
|
1614
1414
|
e.preventDefault()
|
|
1615
1415
|
handleEditorChanges('geoType', 'us')
|
|
@@ -1619,7 +1419,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1619
1419
|
<span>United States</span>
|
|
1620
1420
|
</button>
|
|
1621
1421
|
<button
|
|
1622
|
-
className={state.general.geoType === 'us-region' ? 'active' : ''}
|
|
1422
|
+
className={`${state.general.geoType === 'us-region' ? 'active' : ''} full-width`}
|
|
1623
1423
|
onClick={e => {
|
|
1624
1424
|
e.preventDefault()
|
|
1625
1425
|
handleEditorChanges('geoType', 'us-region')
|
|
@@ -1629,7 +1429,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1629
1429
|
<span>U.S. Region</span>
|
|
1630
1430
|
</button>
|
|
1631
1431
|
<button
|
|
1632
|
-
className={state.general.geoType === 'world' ? 'active' : ''}
|
|
1432
|
+
className={`${state.general.geoType === 'world' ? 'active' : ''} full-width`}
|
|
1633
1433
|
onClick={e => {
|
|
1634
1434
|
e.preventDefault()
|
|
1635
1435
|
handleEditorChanges('geoType', 'world')
|
|
@@ -1639,7 +1439,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1639
1439
|
<span>World</span>
|
|
1640
1440
|
</button>
|
|
1641
1441
|
<button
|
|
1642
|
-
className={state.general.geoType === 'single-state' ? 'active' : ''}
|
|
1442
|
+
className={`${state.general.geoType === 'single-state' ? 'active' : ''} full-width`}
|
|
1643
1443
|
onClick={e => {
|
|
1644
1444
|
e.preventDefault()
|
|
1645
1445
|
handleEditorChanges('geoType', 'single-state')
|
|
@@ -1648,6 +1448,16 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1648
1448
|
<AlabamaGraphic />
|
|
1649
1449
|
<span>U.S. State</span>
|
|
1650
1450
|
</button>
|
|
1451
|
+
{/* <button
|
|
1452
|
+
className={`${state.general.geoType === 'google-map' ? 'active' : ''} full-width`}
|
|
1453
|
+
onClick={e => {
|
|
1454
|
+
e.preventDefault()
|
|
1455
|
+
handleEditorChanges('geoType', 'google-map')
|
|
1456
|
+
}}
|
|
1457
|
+
>
|
|
1458
|
+
<UsaGraphic />
|
|
1459
|
+
<span>Google Map Api</span>
|
|
1460
|
+
</button> */}
|
|
1651
1461
|
</ul>
|
|
1652
1462
|
</label>
|
|
1653
1463
|
{/* Select > State or County Map */}
|
|
@@ -1760,6 +1570,23 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1760
1570
|
)}
|
|
1761
1571
|
</select>
|
|
1762
1572
|
</label>
|
|
1573
|
+
|
|
1574
|
+
{/* Navigation Behavior */}
|
|
1575
|
+
{(state.general.type === 'navigation' || state.general.type === 'data') && (
|
|
1576
|
+
<label>
|
|
1577
|
+
<span className='edit-label column-heading'>Navigation Behavior</span>
|
|
1578
|
+
<select
|
|
1579
|
+
value={state.general.navigationTarget}
|
|
1580
|
+
onChange={event => {
|
|
1581
|
+
event.preventDefault()
|
|
1582
|
+
handleEditorChanges('navigationTarget', event.target.value)
|
|
1583
|
+
}}
|
|
1584
|
+
>
|
|
1585
|
+
<option value='_self'>Same Window</option>
|
|
1586
|
+
<option value='_blank'>New Window</option>
|
|
1587
|
+
</select>
|
|
1588
|
+
</label>
|
|
1589
|
+
)}
|
|
1763
1590
|
<label>
|
|
1764
1591
|
<span className='edit-label'>Data Classification Type</span>
|
|
1765
1592
|
<div>
|
|
@@ -1801,7 +1628,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1801
1628
|
handleEditorChanges('displayStateLabels', event.target.checked)
|
|
1802
1629
|
}}
|
|
1803
1630
|
/>
|
|
1804
|
-
<span className='edit-label'>
|
|
1631
|
+
<span className='edit-label'>
|
|
1632
|
+
Show state labels
|
|
1633
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1634
|
+
<Tooltip.Target>
|
|
1635
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1636
|
+
</Tooltip.Target>
|
|
1637
|
+
<Tooltip.Content>
|
|
1638
|
+
<p>Recommended set to display for Section 508 compliance.</p>
|
|
1639
|
+
</Tooltip.Content>
|
|
1640
|
+
</Tooltip>
|
|
1641
|
+
</span>
|
|
1805
1642
|
</label>
|
|
1806
1643
|
)}
|
|
1807
1644
|
</AccordionItemPanel>
|
|
@@ -1919,16 +1756,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1919
1756
|
</Tooltip>
|
|
1920
1757
|
}
|
|
1921
1758
|
/>
|
|
1922
|
-
{'us' === state.general.geoType && (
|
|
1923
|
-
<TextField
|
|
1924
|
-
value={general.territoriesLabel}
|
|
1925
|
-
updateField={updateField}
|
|
1926
|
-
section='general'
|
|
1927
|
-
fieldName='territoriesLabel'
|
|
1928
|
-
label='Territories Label'
|
|
1929
|
-
placeholder='Territories'
|
|
1930
|
-
/>
|
|
1931
|
-
)}
|
|
1932
1759
|
{'us' === state.general.geoType && (
|
|
1933
1760
|
<label className='checkbox'>
|
|
1934
1761
|
<input
|
|
@@ -2857,7 +2684,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2857
2684
|
</label>
|
|
2858
2685
|
</React.Fragment>
|
|
2859
2686
|
)}
|
|
2860
|
-
{
|
|
2687
|
+
{state.filters.length > 0 && (
|
|
2861
2688
|
<label className='checkbox'>
|
|
2862
2689
|
<input
|
|
2863
2690
|
type='checkbox'
|
|
@@ -2885,7 +2712,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2885
2712
|
</span>
|
|
2886
2713
|
</label>
|
|
2887
2714
|
)}
|
|
2888
|
-
{(
|
|
2715
|
+
{(state.filters.length > 0 || state.general.type === 'bubble' || state.general.geoType === 'us') && (
|
|
2889
2716
|
<label className='checkbox'>
|
|
2890
2717
|
<input
|
|
2891
2718
|
type='checkbox'
|
|
@@ -2922,20 +2749,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2922
2749
|
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2923
2750
|
</AccordionItemHeading>
|
|
2924
2751
|
<AccordionItemPanel>
|
|
2925
|
-
{
|
|
2926
|
-
<MapFilters />
|
|
2927
|
-
) : (
|
|
2928
|
-
<p style={{ textAlign: 'center' }}>There are currently no filters.</p>
|
|
2929
|
-
)}
|
|
2930
|
-
<button
|
|
2931
|
-
className={'btn btn-primary full-width'}
|
|
2932
|
-
onClick={event => {
|
|
2933
|
-
event.preventDefault()
|
|
2934
|
-
changeFilter(null, 'addNew')
|
|
2935
|
-
}}
|
|
2936
|
-
>
|
|
2937
|
-
Add Filter
|
|
2938
|
-
</button>
|
|
2752
|
+
<VizFilterEditor config={state} updateField={updateField} rawData={state.data} />
|
|
2939
2753
|
</AccordionItemPanel>
|
|
2940
2754
|
</AccordionItem>
|
|
2941
2755
|
)}
|
|
@@ -3563,6 +3377,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
3563
3377
|
updateField={updateField}
|
|
3564
3378
|
/>
|
|
3565
3379
|
</label>
|
|
3380
|
+
{/* Leaflet Map Type */}
|
|
3381
|
+
{state.general.geoType === 'leaflet' && (
|
|
3382
|
+
<>
|
|
3383
|
+
<Select
|
|
3384
|
+
label='Leaflet Theme'
|
|
3385
|
+
options={layerOptions}
|
|
3386
|
+
section={'leaflet'}
|
|
3387
|
+
fieldName='theme'
|
|
3388
|
+
updateField={updateField}
|
|
3389
|
+
/>
|
|
3390
|
+
</>
|
|
3391
|
+
)}
|
|
3566
3392
|
</AccordionItemPanel>
|
|
3567
3393
|
</AccordionItem>
|
|
3568
3394
|
<AccordionItem>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { useContext, useEffect, useRef } from 'react'
|
|
2
|
+
import { Loader } from '@googlemaps/js-api-loader'
|
|
3
|
+
import { MarkerClusterer } from '@googlemaps/markerclusterer'
|
|
4
|
+
import ConfigContext from '../../../context'
|
|
5
|
+
|
|
6
|
+
// center on USA
|
|
7
|
+
const center = {
|
|
8
|
+
lat: 37.09024,
|
|
9
|
+
lng: -95.712891
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type GoogleMapComponentProps = {
|
|
13
|
+
apiKey?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const GoogleMapComponent: React.FC<GoogleMapComponentProps> = ({ apiKey = '' }) => {
|
|
17
|
+
const mapRef = useRef(null)
|
|
18
|
+
const { state } = useContext(ConfigContext)
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const loader = new Loader({
|
|
22
|
+
apiKey: apiKey,
|
|
23
|
+
version: 'weekly'
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
loader
|
|
27
|
+
.load()
|
|
28
|
+
.then(() => {
|
|
29
|
+
if (mapRef.current) {
|
|
30
|
+
const map = new window.google.maps.Map(mapRef.current, {
|
|
31
|
+
center: center,
|
|
32
|
+
zoom: 4
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const markers = state.data.map(d => {
|
|
36
|
+
const markerContent = document.createElement('div')
|
|
37
|
+
markerContent.style.backgroundColor = 'orange' // Set the background color
|
|
38
|
+
markerContent.style.width = '25px'
|
|
39
|
+
markerContent.style.height = '25px'
|
|
40
|
+
markerContent.style.borderRadius = '50%'
|
|
41
|
+
markerContent.style.display = 'flex'
|
|
42
|
+
markerContent.style.alignItems = 'center'
|
|
43
|
+
markerContent.style.justifyContent = 'center'
|
|
44
|
+
markerContent.style.color = 'white'
|
|
45
|
+
markerContent.innerText = d[state.columns.geo.name]
|
|
46
|
+
|
|
47
|
+
const marker = new google.maps.Marker({
|
|
48
|
+
position: { lat: Number(d[state.columns.latitude.name]), lng: Number(d[state.columns.longitude.name]) },
|
|
49
|
+
title: d[state.columns.geo.name],
|
|
50
|
+
map: map
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return marker
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
new MarkerClusterer({ markers, map })
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
.catch(e => {
|
|
60
|
+
console.error('Error loading Google Maps API:', e)
|
|
61
|
+
})
|
|
62
|
+
}, [apiKey, state])
|
|
63
|
+
|
|
64
|
+
return <div ref={mapRef} style={{ height: '500px', width: '100%' }} />
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default GoogleMapComponent
|