@cdc/map 4.24.10 → 4.24.12-2
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 +33447 -32769
- package/examples/default-geocode.json +13 -4
- package/examples/default-usa-regions.json +267 -117
- package/examples/example-city-state.json +6 -3
- package/examples/pattern.json +861 -0
- package/examples/private/DEV-9644.json +184 -0
- 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/default-patterns.json +867 -0
- package/examples/private/test.json +1632 -0
- package/index.html +4 -5
- package/package.json +3 -3
- package/src/CdcMap.tsx +93 -83
- package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +67 -0
- package/src/_stories/CdcMap.Legend.stories.tsx +40 -0
- package/src/_stories/CdcMap.Patterns.stories.tsx +29 -0
- package/src/_stories/CdcMap.stories.tsx +59 -0
- package/src/_stories/UsaMap.NoData.stories.tsx +19 -0
- package/src/_stories/_mock/custom-layer-map.json +1117 -0
- package/src/_stories/_mock/default-patterns.json +865 -0
- package/src/_stories/_mock/example-city-state.json +858 -0
- package/src/_stories/_mock/usa-state-gradient.json +238 -0
- package/src/_stories/_mock/wastewater-map.json +208 -0
- package/src/components/CityList.tsx +5 -2
- package/src/components/EditorPanel/components/EditorPanel.tsx +68 -295
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +27 -23
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +75 -16
- package/src/components/Legend/components/Legend.tsx +42 -20
- package/src/components/Legend/components/index.scss +24 -24
- package/src/components/UsaMap/components/HexIcon.tsx +7 -1
- package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +40 -6
- package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +10 -2
- package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +57 -12
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +95 -21
- package/src/components/UsaMap/components/Territory/TerritoryShape.ts +13 -0
- package/src/components/UsaMap/components/UsaMap.County.tsx +11 -13
- package/src/components/UsaMap/components/UsaMap.Region.tsx +59 -16
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +2 -1
- package/src/components/UsaMap/components/UsaMap.State.tsx +61 -63
- package/src/components/UsaMap/helpers/shapes.ts +5 -4
- package/src/components/WorldMap/WorldMap.tsx +77 -16
- package/src/data/initial-state.js +2 -1
- package/src/helpers/applyColorToLegend.ts +80 -0
- package/src/helpers/colors.ts +23 -0
- package/src/hooks/useTooltip.ts +9 -6
- package/src/scss/editor-panel.scss +0 -3
- package/src/scss/filters.scss +1 -9
- package/src/scss/main.scss +0 -5
- package/src/scss/map.scss +11 -63
- package/src/types/MapConfig.ts +8 -2
- package/src/types/MapContext.ts +1 -0
- package/examples/default-patterns.json +0 -579
- package/src/scss/datatable.scss +0 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect,
|
|
1
|
+
import React, { useState, useEffect, useContext } from 'react'
|
|
2
2
|
|
|
3
3
|
// Third Party
|
|
4
4
|
import {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from 'react-accessible-accordion'
|
|
11
11
|
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
|
|
12
12
|
import { useDebounce } from 'use-debounce'
|
|
13
|
+
import _ from 'lodash'
|
|
13
14
|
// import ReactTags from 'react-tag-autocomplete'
|
|
14
15
|
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
|
15
16
|
import Panels from './Panels'
|
|
@@ -25,6 +26,7 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
|
25
26
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
26
27
|
import InputToggle from '@cdc/core/components/inputs/InputToggle'
|
|
27
28
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
29
|
+
import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
|
|
28
30
|
|
|
29
31
|
// Assets
|
|
30
32
|
import UsaGraphic from '@cdc/core/assets/icon-map-usa.svg'
|
|
@@ -36,35 +38,31 @@ import usaDefaultConfig from '../../../../examples/default-usa.json'
|
|
|
36
38
|
import countyDefaultConfig from '../../../../examples/default-county.json'
|
|
37
39
|
import useMapLayers from '../../../hooks/useMapLayers.tsx'
|
|
38
40
|
|
|
39
|
-
import { useFilters } from '@cdc/core/components/Filters'
|
|
40
|
-
|
|
41
41
|
import HexSetting from './HexShapeSettings.jsx'
|
|
42
42
|
import ConfigContext from '../../../context.ts'
|
|
43
43
|
import { MapContext } from '../../../types/MapContext.js'
|
|
44
44
|
import { TextField } from './Inputs'
|
|
45
|
+
import Alert from '@cdc/core/components/Alert'
|
|
46
|
+
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
45
47
|
|
|
46
48
|
// Todo: move to useReducer, seperate files out.
|
|
47
49
|
const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
48
50
|
// prettier-ignore
|
|
49
51
|
const {
|
|
50
|
-
changeFilterActive,
|
|
51
52
|
columnsInData = [],
|
|
52
53
|
isDashboard,
|
|
53
54
|
isDebug,
|
|
54
|
-
isEditor,
|
|
55
55
|
loadConfig,
|
|
56
56
|
runtimeFilters,
|
|
57
57
|
runtimeLegend,
|
|
58
58
|
setParentConfig,
|
|
59
|
-
setRuntimeFilters,
|
|
60
59
|
setState,
|
|
61
60
|
state,
|
|
62
61
|
tooltipId,
|
|
63
62
|
runtimeData,
|
|
64
63
|
setRuntimeData,
|
|
65
64
|
generateRuntimeData,
|
|
66
|
-
|
|
67
|
-
topoData,
|
|
65
|
+
|
|
68
66
|
|
|
69
67
|
} = useContext<MapContext>(ConfigContext)
|
|
70
68
|
|
|
@@ -78,13 +76,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
78
76
|
|
|
79
77
|
const [activeFilterValueForDescription, setActiveFilterValueForDescription] = useState([0, 0])
|
|
80
78
|
|
|
81
|
-
const { handleFilterOrder, filterOrderOptions, filterStyleOptions } = useFilters({
|
|
82
|
-
config: state,
|
|
83
|
-
setConfig: setState,
|
|
84
|
-
filteredData: runtimeFilters,
|
|
85
|
-
setFilteredData: setRuntimeFilters
|
|
86
|
-
})
|
|
87
|
-
|
|
88
79
|
const headerColors = [
|
|
89
80
|
'theme-blue',
|
|
90
81
|
'theme-purple',
|
|
@@ -109,12 +100,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
109
100
|
} = useMapLayers(state, setState, false, tooltipId)
|
|
110
101
|
|
|
111
102
|
const categoryMove = (idx1, idx2) => {
|
|
112
|
-
let categoryValuesOrder =
|
|
103
|
+
let categoryValuesOrder = getCategoryValuesOrder()
|
|
113
104
|
|
|
114
105
|
let [movedItem] = categoryValuesOrder.splice(idx1, 1)
|
|
115
106
|
|
|
116
107
|
categoryValuesOrder.splice(idx2, 0, movedItem)
|
|
117
108
|
|
|
109
|
+
state.legend.categoryValuesOrder?.forEach(value => {
|
|
110
|
+
if (categoryValuesOrder.indexOf(value) === -1) {
|
|
111
|
+
categoryValuesOrder.push(value)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
118
115
|
setState({
|
|
119
116
|
...state,
|
|
120
117
|
legend: {
|
|
@@ -371,7 +368,8 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
371
368
|
...state,
|
|
372
369
|
legend: {
|
|
373
370
|
...state.legend,
|
|
374
|
-
position: value
|
|
371
|
+
position: value,
|
|
372
|
+
hideBorder: _.includes(['top', 'bottom'], value)
|
|
375
373
|
}
|
|
376
374
|
})
|
|
377
375
|
break
|
|
@@ -1065,33 +1063,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1065
1063
|
})
|
|
1066
1064
|
}
|
|
1067
1065
|
|
|
1068
|
-
const MapFilters = () => {
|
|
1069
|
-
return (
|
|
1070
|
-
<>
|
|
1071
|
-
<label>
|
|
1072
|
-
Filter Behavior
|
|
1073
|
-
<select
|
|
1074
|
-
value={state.filterBehavior}
|
|
1075
|
-
onChange={e => {
|
|
1076
|
-
setState({
|
|
1077
|
-
...state,
|
|
1078
|
-
filterBehavior: e.target.value
|
|
1079
|
-
})
|
|
1080
|
-
}}
|
|
1081
|
-
>
|
|
1082
|
-
<option key='Apply Button' value='Apply Button'>
|
|
1083
|
-
Apply Button
|
|
1084
|
-
</option>
|
|
1085
|
-
<option key='Filter Change' value='Filter Change'>
|
|
1086
|
-
Filter Change
|
|
1087
|
-
</option>
|
|
1088
|
-
</select>
|
|
1089
|
-
</label>
|
|
1090
|
-
{filtersJSX}
|
|
1091
|
-
</>
|
|
1092
|
-
)
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
1066
|
const removeAdditionalColumn = columnName => {
|
|
1096
1067
|
const newColumns = state.columns
|
|
1097
1068
|
|
|
@@ -1219,40 +1190,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1219
1190
|
columnsRequiredChecker()
|
|
1220
1191
|
}, [state]) // eslint-disable-line
|
|
1221
1192
|
|
|
1222
|
-
useEffect(() => {
|
|
1223
|
-
//If a categorical map is used and the order is either not defined or incorrect, fix it
|
|
1224
|
-
if ('category' === state.legend.type && runtimeLegend && runtimeLegend.runtimeDataHash) {
|
|
1225
|
-
let valid = true
|
|
1226
|
-
if (state.legend.categoryValuesOrder) {
|
|
1227
|
-
runtimeLegend.forEach(item => {
|
|
1228
|
-
if (!item.special && state.legend.categoryValuesOrder.indexOf(item.value) === -1) {
|
|
1229
|
-
valid = false
|
|
1230
|
-
}
|
|
1231
|
-
})
|
|
1232
|
-
let runtimeLegendKeys = runtimeLegend.map(item => item.value)
|
|
1233
|
-
state.legend.categoryValuesOrder.forEach(category => {
|
|
1234
|
-
if (runtimeLegendKeys.indexOf(category) === -1) {
|
|
1235
|
-
valid = false
|
|
1236
|
-
}
|
|
1237
|
-
})
|
|
1238
|
-
} else {
|
|
1239
|
-
valid = false
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
if (!valid) {
|
|
1243
|
-
let arr = runtimeLegend.filter(item => !item.special).map(({ value }) => value)
|
|
1244
|
-
|
|
1245
|
-
setState({
|
|
1246
|
-
...state,
|
|
1247
|
-
legend: {
|
|
1248
|
-
...state.legend,
|
|
1249
|
-
categoryValuesOrder: arr
|
|
1250
|
-
}
|
|
1251
|
-
})
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
}, [runtimeLegend]) // eslint-disable-line
|
|
1255
|
-
|
|
1256
1193
|
const columnsOptions = [
|
|
1257
1194
|
<option value='' key={'Select Option'}>
|
|
1258
1195
|
- Select Option -
|
|
@@ -1288,30 +1225,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1288
1225
|
return true
|
|
1289
1226
|
})
|
|
1290
1227
|
|
|
1291
|
-
const updateField = (
|
|
1292
|
-
const isArray = Array.isArray(state[section])
|
|
1293
|
-
|
|
1294
|
-
let sectionValue = isArray ? [...state[section], newValue] : { ...state[section], [fieldName]: newValue }
|
|
1295
|
-
|
|
1296
|
-
if (null !== subsection) {
|
|
1297
|
-
if (isArray) {
|
|
1298
|
-
sectionValue = [...state[section]]
|
|
1299
|
-
sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
|
|
1300
|
-
} else {
|
|
1301
|
-
sectionValue = {
|
|
1302
|
-
...state[section],
|
|
1303
|
-
[subsection]: { ...state[section][subsection], [fieldName]: newValue }
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
let updatedState = {
|
|
1309
|
-
...state,
|
|
1310
|
-
[section]: sectionValue
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
setState(updatedState)
|
|
1314
|
-
}
|
|
1228
|
+
const updateField = updateFieldFactory(state, setState)
|
|
1315
1229
|
|
|
1316
1230
|
const onBackClick = () => {
|
|
1317
1231
|
setDisplayPanel(!displayPanel)
|
|
@@ -1323,163 +1237,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1323
1237
|
|
|
1324
1238
|
const usedFilterColumns = {}
|
|
1325
1239
|
|
|
1326
|
-
const filtersJSX = state.filters.map((filter, index) => {
|
|
1327
|
-
if (filter.type === 'url') return <></>
|
|
1328
|
-
|
|
1329
|
-
if (filter.columnName) {
|
|
1330
|
-
usedFilterColumns[filter.columnName] = true
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
return (
|
|
1334
|
-
<>
|
|
1335
|
-
<fieldset className='edit-block' key={`filter-${index}`}>
|
|
1336
|
-
<button
|
|
1337
|
-
className='remove-column'
|
|
1338
|
-
onClick={e => {
|
|
1339
|
-
e.preventDefault()
|
|
1340
|
-
changeFilter(index, 'remove')
|
|
1341
|
-
}}
|
|
1342
|
-
>
|
|
1343
|
-
Remove
|
|
1344
|
-
</button>
|
|
1345
|
-
<TextField
|
|
1346
|
-
value={state.filters[index].label}
|
|
1347
|
-
section='filters'
|
|
1348
|
-
subsection={index}
|
|
1349
|
-
fieldName='label'
|
|
1350
|
-
label='Label'
|
|
1351
|
-
updateField={updateField}
|
|
1352
|
-
/>
|
|
1353
|
-
<label>
|
|
1354
|
-
<span className='edit-label column-heading'>
|
|
1355
|
-
Filter Column
|
|
1356
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1357
|
-
<Tooltip.Target>
|
|
1358
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1359
|
-
</Tooltip.Target>
|
|
1360
|
-
<Tooltip.Content>
|
|
1361
|
-
<p>
|
|
1362
|
-
Selecting a column will add a dropdown menu below the map legend and allow users to filter based on
|
|
1363
|
-
the values in this column.
|
|
1364
|
-
</p>
|
|
1365
|
-
</Tooltip.Content>
|
|
1366
|
-
</Tooltip>
|
|
1367
|
-
</span>
|
|
1368
|
-
<select
|
|
1369
|
-
value={filter.columnName}
|
|
1370
|
-
onChange={event => {
|
|
1371
|
-
changeFilter(index, 'columnName', event.target.value)
|
|
1372
|
-
}}
|
|
1373
|
-
>
|
|
1374
|
-
{columnsOptions.filter(({ key }) => undefined === usedFilterColumns[key] || filter.columnName === key)}
|
|
1375
|
-
</select>
|
|
1376
|
-
</label>
|
|
1377
|
-
|
|
1378
|
-
<label>
|
|
1379
|
-
<span className='edit-showDropdown column-heading'>Show Filter Input</span>
|
|
1380
|
-
<input
|
|
1381
|
-
type='checkbox'
|
|
1382
|
-
checked={filter.showDropdown === undefined ? true : filter.showDropdown}
|
|
1383
|
-
onChange={e => {
|
|
1384
|
-
changeFilter(index, 'showDropdown', e.target.checked)
|
|
1385
|
-
}}
|
|
1386
|
-
/>
|
|
1387
|
-
</label>
|
|
1388
|
-
|
|
1389
|
-
<label>
|
|
1390
|
-
<span className='edit-filterOrder column-heading'>Filter Style</span>
|
|
1391
|
-
<select
|
|
1392
|
-
value={filter.filterStyle}
|
|
1393
|
-
onChange={e => {
|
|
1394
|
-
changeFilter(index, 'filterStyle', e.target.value)
|
|
1395
|
-
}}
|
|
1396
|
-
>
|
|
1397
|
-
{filterStyleOptions.map((option, index) => {
|
|
1398
|
-
return (
|
|
1399
|
-
<option value={option} key={`filter-${option}--${index}`}>
|
|
1400
|
-
{option}
|
|
1401
|
-
</option>
|
|
1402
|
-
)
|
|
1403
|
-
})}
|
|
1404
|
-
</select>
|
|
1405
|
-
</label>
|
|
1406
|
-
|
|
1407
|
-
<label>
|
|
1408
|
-
<span className='edit-filterOrder column-heading'>Filter Order</span>
|
|
1409
|
-
<select
|
|
1410
|
-
value={filter.order}
|
|
1411
|
-
onChange={e => {
|
|
1412
|
-
changeFilter(index, 'filterOrder', e.target.value)
|
|
1413
|
-
changeFilterActive(index, filter.values[0])
|
|
1414
|
-
}}
|
|
1415
|
-
>
|
|
1416
|
-
{filterOrderOptions.map((option, index) => {
|
|
1417
|
-
return (
|
|
1418
|
-
<option value={option.value} key={`filter-${index}`}>
|
|
1419
|
-
{option.label}
|
|
1420
|
-
</option>
|
|
1421
|
-
)
|
|
1422
|
-
})}
|
|
1423
|
-
</select>
|
|
1424
|
-
</label>
|
|
1425
|
-
|
|
1426
|
-
<TextField
|
|
1427
|
-
value={state.filters[index].setByQueryParameter}
|
|
1428
|
-
section='filters'
|
|
1429
|
-
subsection={index}
|
|
1430
|
-
fieldName='setByQueryParameter'
|
|
1431
|
-
label='Default Value Set By Query String Parameter'
|
|
1432
|
-
updateField={updateField}
|
|
1433
|
-
/>
|
|
1434
|
-
|
|
1435
|
-
{filter.order === 'cust' && (
|
|
1436
|
-
<DragDropContext
|
|
1437
|
-
onDragEnd={({ source, destination }) =>
|
|
1438
|
-
handleFilterOrder(source.index, destination.index, index, state.filters[index])
|
|
1439
|
-
}
|
|
1440
|
-
>
|
|
1441
|
-
<Droppable droppableId='filter_order'>
|
|
1442
|
-
{provided => (
|
|
1443
|
-
<ul
|
|
1444
|
-
{...provided.droppableProps}
|
|
1445
|
-
className='sort-list'
|
|
1446
|
-
ref={provided.innerRef}
|
|
1447
|
-
style={{ marginTop: '1em' }}
|
|
1448
|
-
>
|
|
1449
|
-
{state.filters[index]?.values.map((value, index) => {
|
|
1450
|
-
return (
|
|
1451
|
-
<Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
|
|
1452
|
-
{(provided, snapshot) => (
|
|
1453
|
-
<li>
|
|
1454
|
-
<div
|
|
1455
|
-
className={snapshot.isDragging ? 'currently-dragging' : ''}
|
|
1456
|
-
style={getItemStyle(
|
|
1457
|
-
snapshot.isDragging,
|
|
1458
|
-
provided.draggableProps.style,
|
|
1459
|
-
sortableItemStyles
|
|
1460
|
-
)}
|
|
1461
|
-
ref={provided.innerRef}
|
|
1462
|
-
{...provided.draggableProps}
|
|
1463
|
-
{...provided.dragHandleProps}
|
|
1464
|
-
>
|
|
1465
|
-
{value}
|
|
1466
|
-
</div>
|
|
1467
|
-
</li>
|
|
1468
|
-
)}
|
|
1469
|
-
</Draggable>
|
|
1470
|
-
)
|
|
1471
|
-
})}
|
|
1472
|
-
{provided.placeholder}
|
|
1473
|
-
</ul>
|
|
1474
|
-
)}
|
|
1475
|
-
</Droppable>
|
|
1476
|
-
</DragDropContext>
|
|
1477
|
-
)}
|
|
1478
|
-
</fieldset>
|
|
1479
|
-
</>
|
|
1480
|
-
)
|
|
1481
|
-
})
|
|
1482
|
-
|
|
1483
1240
|
const StateOptionList = () => {
|
|
1484
1241
|
const arrOfArrays = Object.entries(supportedStatesFipsCodes)
|
|
1485
1242
|
|
|
@@ -1530,9 +1287,29 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1530
1287
|
...draggableStyle
|
|
1531
1288
|
})
|
|
1532
1289
|
|
|
1290
|
+
const getCategoryValuesOrder = () => {
|
|
1291
|
+
let values = runtimeLegend
|
|
1292
|
+
? runtimeLegend.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value)
|
|
1293
|
+
: []
|
|
1294
|
+
|
|
1295
|
+
if (state.legend.cateogryValuesOrder) {
|
|
1296
|
+
return values.sort((a, b) => {
|
|
1297
|
+
let aVal = state.legend.cateogryValuesOrder.indexOf(a)
|
|
1298
|
+
let bVal = state.legend.cateogryValuesOrder.indexOf(b)
|
|
1299
|
+
if (aVal === bVal) return 0
|
|
1300
|
+
if (aVal === -1) return 1
|
|
1301
|
+
if (bVal === -1) return -1
|
|
1302
|
+
return aVal - bVal
|
|
1303
|
+
})
|
|
1304
|
+
} else {
|
|
1305
|
+
return values
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1533
1309
|
const CategoryList = () => {
|
|
1534
|
-
return
|
|
1535
|
-
|
|
1310
|
+
return getCategoryValuesOrder()
|
|
1311
|
+
.filter(item => !item?.special)
|
|
1312
|
+
.map((value, index) => (
|
|
1536
1313
|
<Draggable key={value} draggableId={`item-${value}`} index={index}>
|
|
1537
1314
|
{(provided, snapshot) => (
|
|
1538
1315
|
<li style={{ position: 'relative' }}>
|
|
@@ -1549,9 +1326,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
1549
1326
|
)}
|
|
1550
1327
|
</Draggable>
|
|
1551
1328
|
))
|
|
1552
|
-
) : (
|
|
1553
|
-
<></>
|
|
1554
|
-
)
|
|
1555
1329
|
}
|
|
1556
1330
|
|
|
1557
1331
|
const isLoadedFromUrl = state?.dataKey?.includes('http://') || state?.dataKey?.includes('https://')
|
|
@@ -2205,6 +1979,13 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2205
1979
|
</Tooltip>
|
|
2206
1980
|
</span>
|
|
2207
1981
|
</label>
|
|
1982
|
+
{state.legend.specialClasses.length === 2 && (
|
|
1983
|
+
<Alert
|
|
1984
|
+
type='info'
|
|
1985
|
+
message='If a third special class is needed you can apply a pattern to set it apart.'
|
|
1986
|
+
showCloseButton={false}
|
|
1987
|
+
/>
|
|
1988
|
+
)}
|
|
2208
1989
|
{specialClasses.map((specialClass, i) => (
|
|
2209
1990
|
<div className='edit-block' key={`special-class-${i}`}>
|
|
2210
1991
|
<button
|
|
@@ -2265,15 +2046,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2265
2046
|
</label>
|
|
2266
2047
|
</div>
|
|
2267
2048
|
))}
|
|
2268
|
-
<
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
e
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2049
|
+
{state.legend.specialClasses.length < 2 && (
|
|
2050
|
+
<button
|
|
2051
|
+
className='btn btn-primary full-width'
|
|
2052
|
+
onClick={e => {
|
|
2053
|
+
e.preventDefault()
|
|
2054
|
+
editColumn('primary', 'specialClassAdd', {})
|
|
2055
|
+
}}
|
|
2056
|
+
>
|
|
2057
|
+
Add Special Class
|
|
2058
|
+
</button>
|
|
2059
|
+
)}
|
|
2277
2060
|
</fieldset>
|
|
2278
2061
|
)}
|
|
2279
2062
|
|
|
@@ -2417,7 +2200,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2417
2200
|
</fieldset>
|
|
2418
2201
|
))}
|
|
2419
2202
|
<button
|
|
2420
|
-
className={'btn full-width'}
|
|
2203
|
+
className={'btn btn-primary full-width'}
|
|
2421
2204
|
onClick={event => {
|
|
2422
2205
|
event.preventDefault()
|
|
2423
2206
|
addAdditionalColumn(additionalColumns.length + 1)
|
|
@@ -2473,7 +2256,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2473
2256
|
</fieldset>
|
|
2474
2257
|
))}
|
|
2475
2258
|
<button
|
|
2476
|
-
className={'btn full-width'}
|
|
2259
|
+
className={'btn btn-primary full-width'}
|
|
2477
2260
|
onClick={event => {
|
|
2478
2261
|
event.preventDefault()
|
|
2479
2262
|
const updatedAdditionaCategories = [...(state.legend.additionalCategories || [])]
|
|
@@ -2784,7 +2567,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2784
2567
|
)}
|
|
2785
2568
|
</Droppable>
|
|
2786
2569
|
</DragDropContext>
|
|
2787
|
-
{
|
|
2570
|
+
{runtimeLegend && runtimeLegend.length >= 10 && (
|
|
2788
2571
|
<section className='error-box my-2'>
|
|
2789
2572
|
<div>
|
|
2790
2573
|
<strong className='pt-1'>Warning</strong>
|
|
@@ -2840,7 +2623,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2840
2623
|
</label>
|
|
2841
2624
|
</React.Fragment>
|
|
2842
2625
|
)}
|
|
2843
|
-
{
|
|
2626
|
+
{state.filters.length > 0 && (
|
|
2844
2627
|
<label className='checkbox'>
|
|
2845
2628
|
<input
|
|
2846
2629
|
type='checkbox'
|
|
@@ -2868,7 +2651,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2868
2651
|
</span>
|
|
2869
2652
|
</label>
|
|
2870
2653
|
)}
|
|
2871
|
-
{(
|
|
2654
|
+
{(state.filters.length > 0 || state.general.type === 'bubble' || state.general.geoType === 'us') && (
|
|
2872
2655
|
<label className='checkbox'>
|
|
2873
2656
|
<input
|
|
2874
2657
|
type='checkbox'
|
|
@@ -2905,20 +2688,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
2905
2688
|
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2906
2689
|
</AccordionItemHeading>
|
|
2907
2690
|
<AccordionItemPanel>
|
|
2908
|
-
{
|
|
2909
|
-
<MapFilters />
|
|
2910
|
-
) : (
|
|
2911
|
-
<p style={{ textAlign: 'center' }}>There are currently no filters.</p>
|
|
2912
|
-
)}
|
|
2913
|
-
<button
|
|
2914
|
-
className={'btn full-width'}
|
|
2915
|
-
onClick={event => {
|
|
2916
|
-
event.preventDefault()
|
|
2917
|
-
changeFilter(null, 'addNew')
|
|
2918
|
-
}}
|
|
2919
|
-
>
|
|
2920
|
-
Add Filter
|
|
2921
|
-
</button>
|
|
2691
|
+
<VizFilterEditor config={state} updateField={updateField} rawData={state.data} />
|
|
2922
2692
|
</AccordionItemPanel>
|
|
2923
2693
|
</AccordionItem>
|
|
2924
2694
|
)}
|
|
@@ -3243,7 +3013,6 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
3243
3013
|
<label>
|
|
3244
3014
|
<span className='edit-label'>Map Color Palette</span>
|
|
3245
3015
|
</label>
|
|
3246
|
-
{/* <InputCheckbox section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
|
|
3247
3016
|
<InputToggle
|
|
3248
3017
|
type='3d'
|
|
3249
3018
|
section='general'
|
|
@@ -3527,7 +3296,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
3527
3296
|
)
|
|
3528
3297
|
})}
|
|
3529
3298
|
|
|
3530
|
-
<button
|
|
3299
|
+
<button
|
|
3300
|
+
type='button'
|
|
3301
|
+
onClick={() => editCityStyles('add', 0, '', '')}
|
|
3302
|
+
className='btn btn-primary full-width'
|
|
3303
|
+
>
|
|
3531
3304
|
Add city style
|
|
3532
3305
|
</button>
|
|
3533
3306
|
</>
|
|
@@ -3629,7 +3402,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
|
|
|
3629
3402
|
</>
|
|
3630
3403
|
)
|
|
3631
3404
|
})}
|
|
3632
|
-
<button className={'btn full-width'} onClick={handleAddLayer}>
|
|
3405
|
+
<button className={'btn btn-primary full-width'} onClick={handleAddLayer}>
|
|
3633
3406
|
Add Map Layer
|
|
3634
3407
|
</button>
|
|
3635
3408
|
<p className='layer-purpose-details'>
|
|
@@ -11,7 +11,12 @@ import ConfigContext from '../../../../context'
|
|
|
11
11
|
// styles
|
|
12
12
|
|
|
13
13
|
const PanelAnnotate: React.FC = props => {
|
|
14
|
-
const {
|
|
14
|
+
const {
|
|
15
|
+
state: config,
|
|
16
|
+
setState: updateConfig,
|
|
17
|
+
dimensions,
|
|
18
|
+
isDraggingAnnotation
|
|
19
|
+
} = useContext<MapContext>(ConfigContext)
|
|
15
20
|
const getColumns = (filter = true) => {
|
|
16
21
|
const columns = {}
|
|
17
22
|
config.data.forEach(row => {
|
|
@@ -20,7 +25,10 @@ const PanelAnnotate: React.FC = props => {
|
|
|
20
25
|
|
|
21
26
|
if (filter) {
|
|
22
27
|
Object.keys(columns).forEach(key => {
|
|
23
|
-
if (
|
|
28
|
+
if (
|
|
29
|
+
(config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
|
|
30
|
+
(config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))
|
|
31
|
+
) {
|
|
24
32
|
delete columns[key]
|
|
25
33
|
}
|
|
26
34
|
})
|
|
@@ -41,7 +49,9 @@ const PanelAnnotate: React.FC = props => {
|
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
const handleAddAnnotation = () => {
|
|
44
|
-
const svgContainer = document
|
|
52
|
+
const svgContainer = document
|
|
53
|
+
.querySelector('.map-container > section > svg, .map-container > section > canvas')
|
|
54
|
+
?.getBoundingClientRect()
|
|
45
55
|
const newSvgDims = [svgContainer.width, svgContainer.height]
|
|
46
56
|
|
|
47
57
|
const newAnnotation = {
|
|
@@ -139,11 +149,17 @@ const PanelAnnotate: React.FC = props => {
|
|
|
139
149
|
{config?.annotations &&
|
|
140
150
|
config?.annotations.map((annotation, index) => (
|
|
141
151
|
<Accordion>
|
|
142
|
-
<Accordion.Section
|
|
152
|
+
<Accordion.Section
|
|
153
|
+
title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}
|
|
154
|
+
>
|
|
143
155
|
<div className='annotation-group'>
|
|
144
156
|
<label>
|
|
145
157
|
Annotation Text:
|
|
146
|
-
<textarea
|
|
158
|
+
<textarea
|
|
159
|
+
rows={5}
|
|
160
|
+
value={annotation.text}
|
|
161
|
+
onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)}
|
|
162
|
+
/>
|
|
147
163
|
</label>
|
|
148
164
|
{/* <label>
|
|
149
165
|
Vertical Anchor
|
|
@@ -304,30 +320,18 @@ const PanelAnnotate: React.FC = props => {
|
|
|
304
320
|
</select>
|
|
305
321
|
</label>
|
|
306
322
|
|
|
307
|
-
{
|
|
308
|
-
Snap to Nearest Point
|
|
309
|
-
<input
|
|
310
|
-
type='checkbox'
|
|
311
|
-
checked={config?.annotations[index]?.snapToNearestPoint}
|
|
312
|
-
onClick={e => {
|
|
313
|
-
const updatedAnnotations = [...config?.annotations]
|
|
314
|
-
updatedAnnotations[index].snapToNearestPoint = e.target.checked
|
|
315
|
-
updateConfig({
|
|
316
|
-
...config,
|
|
317
|
-
annotations: updatedAnnotations
|
|
318
|
-
})
|
|
319
|
-
}}
|
|
320
|
-
/>
|
|
321
|
-
</label> */}
|
|
322
|
-
|
|
323
|
-
<Button className='warn btn-warn btn btn-remove delete' onClick={() => handleRemoveAnnotation(index)}>
|
|
323
|
+
<Button className='btn btn-danger' onClick={() => handleRemoveAnnotation(index)}>
|
|
324
324
|
Delete Annotation
|
|
325
325
|
</Button>
|
|
326
326
|
</div>
|
|
327
327
|
</Accordion.Section>
|
|
328
328
|
</Accordion>
|
|
329
329
|
))}
|
|
330
|
-
{config?.annotations?.length < 3 &&
|
|
330
|
+
{config?.annotations?.length < 3 && (
|
|
331
|
+
<button className='btn btn-primary full-width' onClick={handleAddAnnotation}>
|
|
332
|
+
Add Annotation
|
|
333
|
+
</button>
|
|
334
|
+
)}
|
|
331
335
|
</Accordion.Section>
|
|
332
336
|
</Accordion>
|
|
333
337
|
)
|