@cdc/map 4.24.3 → 4.24.5

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.
Files changed (28) hide show
  1. package/dist/cdcmap.js +29115 -28828
  2. package/examples/example-city-state.json +51 -17
  3. package/examples/hex-colors.json +507 -0
  4. package/index.html +8 -8
  5. package/package.json +3 -3
  6. package/src/CdcMap.tsx +151 -115
  7. package/src/components/BubbleList.jsx +8 -5
  8. package/src/components/CityList.jsx +5 -5
  9. package/src/components/EditorPanel/components/EditorPanel.tsx +1390 -1436
  10. package/src/components/EditorPanel/components/Error.tsx +12 -0
  11. package/src/components/EditorPanel/components/Panel.PatternSettings-style.css +5 -0
  12. package/src/components/EditorPanel/components/Panel.PatternSettings.tsx +18 -1
  13. package/src/components/Legend/components/Legend.tsx +18 -7
  14. package/src/components/Legend/components/LegendItem.Hex.tsx +1 -1
  15. package/src/components/UsaMap/components/HexIcon.tsx +2 -2
  16. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +1 -1
  17. package/src/components/UsaMap/components/UsaMap.County.tsx +7 -4
  18. package/src/components/UsaMap/components/UsaMap.Region.tsx +3 -2
  19. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +5 -3
  20. package/src/components/UsaMap/components/UsaMap.State.tsx +25 -10
  21. package/src/components/WorldMap/{components/WorldMap.jsx → WorldMap.tsx} +26 -12
  22. package/src/components/WorldMap/index.tsx +1 -1
  23. package/src/context.ts +2 -1
  24. package/src/data/supported-geos.js +1 -0
  25. package/src/hooks/useMapLayers.tsx +2 -2
  26. package/src/scss/editor-panel.scss +1 -12
  27. package/src/scss/main.scss +2 -1
  28. package/src/scss/map.scss +1 -1
@@ -7,6 +7,7 @@ import { useDebounce } from 'use-debounce'
7
7
  // import ReactTags from 'react-tag-autocomplete'
8
8
  import { Tooltip as ReactTooltip } from 'react-tooltip'
9
9
  import Panels from './Panels.tsx'
10
+ import Layout from '@cdc/core/components/Layout'
10
11
 
11
12
  // Data
12
13
  import colorPalettes from '@cdc/core/data/colorPalettes'
@@ -18,7 +19,6 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
18
19
  import Icon from '@cdc/core/components/ui/Icon'
19
20
  import InputToggle from '@cdc/core/components/inputs/InputToggle'
20
21
  import Tooltip from '@cdc/core/components/ui/Tooltip'
21
- import Waiting from '@cdc/core/components/Waiting'
22
22
 
23
23
  // Assets
24
24
  import UsaGraphic from '@cdc/core/assets/icon-map-usa.svg'
@@ -38,7 +38,7 @@ import { MapContext } from '../../../types/MapContext.js'
38
38
  import { Checkbox, TextField } from './Inputs'
39
39
 
40
40
  // Todo: move to useReducer, seperate files out.
41
- const EditorPanel = props => {
41
+ const EditorPanel = ({ columnsRequiredChecker }) => {
42
42
  // prettier-ignore
43
43
  const {
44
44
  changeFilterActive,
@@ -53,12 +53,11 @@ const EditorPanel = props => {
53
53
  setRuntimeFilters,
54
54
  setState,
55
55
  state,
56
+ tooltipId
56
57
  } = useContext<MapContext>(ConfigContext)
57
58
 
58
59
  const { general, columns, legend, table, tooltips } = state
59
60
 
60
- const [requiredColumns, setRequiredColumns] = useState(null) // Simple state so we know if we need more information before parsing the map
61
-
62
61
  const [configTextboxValue, setConfigTextbox] = useState({}) // eslint-disable-line
63
62
 
64
63
  const [loadedDefault, setLoadedDefault] = useState(false)
@@ -78,7 +77,7 @@ const EditorPanel = props => {
78
77
  handleAddLayer,
79
78
  handleRemoveLayer
80
79
  }
81
- } = useMapLayers(state, setState, false, true)
80
+ } = useMapLayers(state, setState, false, tooltipId)
82
81
 
83
82
  const categoryMove = (idx1, idx2) => {
84
83
  let categoryValuesOrder = [...state.legend.categoryValuesOrder]
@@ -822,37 +821,6 @@ const EditorPanel = props => {
822
821
  }
823
822
  }
824
823
 
825
- const columnsRequiredChecker = useCallback(() => {
826
- let columnList = []
827
-
828
- // Geo is always required
829
- if ('' === state.columns.geo.name) {
830
- columnList.push('Geography')
831
- }
832
-
833
- // Primary is required if we're on a data map or a point map
834
- if ('navigation' !== state.general.type && '' === state.columns.primary.name) {
835
- columnList.push('Primary')
836
- }
837
-
838
- // Navigate is required for navigation maps
839
- if ('navigation' === state.general.type && ('' === state.columns.navigate.name || undefined === state.columns.navigate)) {
840
- columnList.push('Navigation')
841
- }
842
-
843
- if (('us-geocode' === state.general.type || 'world-geocode' === state.general.type) && '' === state.columns.latitude.name) {
844
- columnList.push('Latitude')
845
- }
846
-
847
- if (('us-geocode' === state.general.type || 'world-geocode' === state.general.type) && '' === state.columns.longitude.name) {
848
- columnList.push('Longitude')
849
- }
850
-
851
- if (columnList.length === 0) columnList = null
852
-
853
- setRequiredColumns(columnList)
854
- }, [state.columns, state.general.type])
855
-
856
824
  const editColumn = async (columnName, editTarget, value) => {
857
825
  let newSpecialClasses
858
826
  switch (editTarget) {
@@ -1250,6 +1218,10 @@ const EditorPanel = props => {
1250
1218
 
1251
1219
  const onBackClick = () => {
1252
1220
  setDisplayPanel(!displayPanel)
1221
+ setState({
1222
+ ...state,
1223
+ showEditorPanel: !displayPanel
1224
+ })
1253
1225
  }
1254
1226
 
1255
1227
  const usedFilterColumns = {}
@@ -1443,17 +1415,6 @@ const EditorPanel = props => {
1443
1415
  )
1444
1416
  }
1445
1417
 
1446
- const Error = () => {
1447
- return (
1448
- <section className='waiting'>
1449
- <section className='waiting-container'>
1450
- <h3>Error With Configuration</h3>
1451
- <p>{state.runtime.editorErrorMessage}</p>
1452
- </section>
1453
- </section>
1454
- )
1455
- }
1456
-
1457
1418
  const isLoadedFromUrl = state?.dataKey?.includes('http://') || state?.dataKey?.includes('https://')
1458
1419
 
1459
1420
  // if isDebug = true, then try to set the Geography Col and Data col to reduce clicking
@@ -1474,382 +1435,428 @@ const EditorPanel = props => {
1474
1435
 
1475
1436
  return (
1476
1437
  <ErrorBoundary component='EditorPanel'>
1477
- {state?.runtime?.editorErrorMessage.length > 0 && <Error />}
1478
- {requiredColumns && <Waiting requiredColumns={requiredColumns} className={displayPanel ? `waiting` : `waiting collapsed`} />}
1479
- <button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick} data-html2canvas-ignore></button>
1480
-
1481
- <section className={displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'} data-html2canvas-ignore>
1438
+ <Layout.Sidebar isDashboard={isDashboard} displayPanel={displayPanel} title='Configure Map' onBackClick={onBackClick}>
1482
1439
  <ReactTooltip multiline={true} />
1483
- <span className='base-label'>Configure Map</span>
1484
- <section className='form-container'>
1485
- <Accordion allowZeroExpanded={true}>
1486
- <AccordionItem>
1487
- {' '}
1440
+ <Accordion allowZeroExpanded={true}>
1441
+ <AccordionItem>
1442
+ {' '}
1443
+ {/* Type */}
1444
+ <AccordionItemHeading>
1445
+ <AccordionItemButton>Type</AccordionItemButton>
1446
+ </AccordionItemHeading>
1447
+ <AccordionItemPanel>
1448
+ {/* Geography */}
1449
+ <label>
1450
+ <span className='edit-label column-heading'>
1451
+ <span>Geography</span>
1452
+ </span>
1453
+ <ul className='geo-buttons'>
1454
+ <button
1455
+ className={state.general.geoType === 'us' || state.general.geoType === 'us-county' ? 'active' : ''}
1456
+ onClick={e => {
1457
+ e.preventDefault()
1458
+ handleEditorChanges('geoType', 'us')
1459
+ }}
1460
+ >
1461
+ <UsaGraphic />
1462
+ <span>United States</span>
1463
+ </button>
1464
+ <button
1465
+ className={state.general.geoType === 'us-region' ? 'active' : ''}
1466
+ onClick={e => {
1467
+ e.preventDefault()
1468
+ handleEditorChanges('geoType', 'us-region')
1469
+ }}
1470
+ >
1471
+ <UsaRegionGraphic />
1472
+ <span>U.S. Region</span>
1473
+ </button>
1474
+ <button
1475
+ className={state.general.geoType === 'world' ? 'active' : ''}
1476
+ onClick={e => {
1477
+ e.preventDefault()
1478
+ handleEditorChanges('geoType', 'world')
1479
+ }}
1480
+ >
1481
+ <WorldGraphic />
1482
+ <span>World</span>
1483
+ </button>
1484
+ <button
1485
+ className={state.general.geoType === 'single-state' ? 'active' : ''}
1486
+ onClick={e => {
1487
+ e.preventDefault()
1488
+ handleEditorChanges('geoType', 'single-state')
1489
+ }}
1490
+ >
1491
+ <AlabamaGraphic />
1492
+ <span>U.S. State</span>
1493
+ </button>
1494
+ </ul>
1495
+ </label>
1496
+ {/* Select > State or County Map */}
1497
+ {(state.general.geoType === 'us' || state.general.geoType === 'us-county') && (
1498
+ <label>
1499
+ <span className='edit-label column-heading'>Geography Subtype</span>
1500
+ <select
1501
+ value={state.general.geoType}
1502
+ onChange={event => {
1503
+ handleEditorChanges('geoType', event.target.value)
1504
+ }}
1505
+ >
1506
+ <option value='us'>US State-Level</option>
1507
+ <option value='us-county'>US County-Level</option>
1508
+ </select>
1509
+ </label>
1510
+ )}
1511
+ {(state.general.geoType === 'us-county' || state.general.geoType === 'single-state') && (
1512
+ <label>
1513
+ <span className='edit-label column-heading'>County Census Year</span>
1514
+ <select
1515
+ value={state.general.countyCensusYear || '2019'}
1516
+ onChange={event => {
1517
+ handleEditorChanges('countyCensusYear', event.target.value)
1518
+ }}
1519
+ >
1520
+ <option value='2022'>2022</option>
1521
+ <option value='2021'>2021</option>
1522
+ <option value='2020'>2020</option>
1523
+ <option value='2019'>2019</option>
1524
+ <option value='2015'>2015</option>
1525
+ <option value='2014'>2014</option>
1526
+ <option value='2013'>2013</option>
1527
+ </select>
1528
+ </label>
1529
+ )}
1530
+ {(state.general.geoType === 'us-county' || state.general.geoType === 'single-state') && (
1531
+ <label>
1532
+ <span className='edit-label column-heading'>Filter Controlling County Census Year</span>
1533
+ <select
1534
+ value={state.general.filterControlsCountyYear || ''}
1535
+ onChange={event => {
1536
+ handleEditorChanges('filterControlsCountyYear', event.target.value)
1537
+ }}
1538
+ >
1539
+ <option value=''>None</option>
1540
+ {state.filters && state.filters.map(filter => <option>{filter.columnName}</option>)}
1541
+ </select>
1542
+ </label>
1543
+ )}
1488
1544
  {/* Type */}
1489
- <AccordionItemHeading>
1490
- <AccordionItemButton>Type</AccordionItemButton>
1491
- </AccordionItemHeading>
1492
- <AccordionItemPanel>
1493
- {/* Geography */}
1545
+ {/* Select > Filter a state */}
1546
+ {state.general.geoType === 'single-state' && (
1494
1547
  <label>
1495
- <span className='edit-label column-heading'>
1496
- <span>Geography</span>
1497
- </span>
1498
- <ul className='geo-buttons'>
1499
- <button
1500
- className={state.general.geoType === 'us' || state.general.geoType === 'us-county' ? 'active' : ''}
1501
- onClick={e => {
1502
- e.preventDefault()
1503
- handleEditorChanges('geoType', 'us')
1504
- }}
1505
- >
1506
- <UsaGraphic />
1507
- <span>United States</span>
1508
- </button>
1509
- <button
1510
- className={state.general.geoType === 'us-region' ? 'active' : ''}
1511
- onClick={e => {
1512
- e.preventDefault()
1513
- handleEditorChanges('geoType', 'us-region')
1514
- }}
1515
- >
1516
- <UsaRegionGraphic />
1517
- <span>U.S. Region</span>
1518
- </button>
1519
- <button
1520
- className={state.general.geoType === 'world' ? 'active' : ''}
1521
- onClick={e => {
1522
- e.preventDefault()
1523
- handleEditorChanges('geoType', 'world')
1524
- }}
1525
- >
1526
- <WorldGraphic />
1527
- <span>World</span>
1528
- </button>
1529
- <button
1530
- className={state.general.geoType === 'single-state' ? 'active' : ''}
1531
- onClick={e => {
1532
- e.preventDefault()
1533
- handleEditorChanges('geoType', 'single-state')
1534
- }}
1535
- >
1536
- <AlabamaGraphic />
1537
- <span>U.S. State</span>
1538
- </button>
1539
- </ul>
1548
+ <span className='edit-label column-heading'>State Selector</span>
1549
+ <select
1550
+ value={state.general.statePicked.stateName}
1551
+ onChange={event => {
1552
+ handleEditorChanges('chooseState', event.target.value)
1553
+ }}
1554
+ >
1555
+ <StateOptionList />
1556
+ </select>
1540
1557
  </label>
1541
- {/* Select > State or County Map */}
1542
- {(state.general.geoType === 'us' || state.general.geoType === 'us-county') && (
1543
- <label>
1544
- <span className='edit-label column-heading'>Geography Subtype</span>
1545
- <select
1546
- value={state.general.geoType}
1547
- onChange={event => {
1548
- handleEditorChanges('geoType', event.target.value)
1549
- }}
1550
- >
1551
- <option value='us'>US State-Level</option>
1552
- <option value='us-county'>US County-Level</option>
1553
- </select>
1554
- </label>
1555
- )}
1556
- {(state.general.geoType === 'us-county' || state.general.geoType === 'single-state') && (
1557
- <label>
1558
- <span className='edit-label column-heading'>County Census Year</span>
1559
- <select
1560
- value={state.general.countyCensusYear || '2019'}
1561
- onChange={event => {
1562
- handleEditorChanges('countyCensusYear', event.target.value)
1563
- }}
1564
- >
1565
- <option value='2022'>2022</option>
1566
- <option value='2021'>2021</option>
1567
- <option value='2020'>2020</option>
1568
- <option value='2019'>2019</option>
1569
- <option value='2015'>2015</option>
1570
- <option value='2014'>2014</option>
1571
- <option value='2013'>2013</option>
1572
- </select>
1573
- </label>
1574
- )}
1575
- {(state.general.geoType === 'us-county' || state.general.geoType === 'single-state') && (
1558
+ )}
1559
+ {/* Type */}
1560
+ <label>
1561
+ <span className='edit-label column-heading'>
1562
+ Map Type
1563
+ <Tooltip style={{ textTransform: 'none' }}>
1564
+ <Tooltip.Target>
1565
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1566
+ </Tooltip.Target>
1567
+ <Tooltip.Content>
1568
+ <p>Select "Data" to create a color-coded data map. To create a navigation-only map, select "Navigation."</p>
1569
+ </Tooltip.Content>
1570
+ </Tooltip>
1571
+ </span>
1572
+ <select
1573
+ value={state.general.type}
1574
+ onChange={event => {
1575
+ handleEditorChanges('editorMapType', event.target.value)
1576
+ }}
1577
+ >
1578
+ <option value='data'>Data</option>
1579
+ {state.general.geoType === 'us-county' && <option value='us-geocode'>Geocode</option>}
1580
+ {state.general.geoType === 'world' && <option value='world-geocode'>Geocode</option>}
1581
+ {state.general.geoType !== 'us-county' && <option value='navigation'>Navigation</option>}
1582
+ {(state.general.geoType === 'world' || state.general.geoType === 'us') && <option value='bubble'>Bubble</option>}
1583
+ </select>
1584
+ </label>
1585
+ <label>
1586
+ <span className='edit-label'>Data Classification Type</span>
1587
+ <div>
1576
1588
  <label>
1577
- <span className='edit-label column-heading'>Filter Controlling County Census Year</span>
1578
- <select
1579
- value={state.general.filterControlsCountyYear || ''}
1580
- onChange={event => {
1581
- handleEditorChanges('filterControlsCountyYear', event.target.value)
1582
- }}
1583
- >
1584
- <option value=''>None</option>
1585
- {state.filters && state.filters.map(filter => <option>{filter.columnName}</option>)}
1586
- </select>
1589
+ <input type='radio' name='equalnumber' value='equalnumber' checked={state.legend.type === 'equalnumber'} onChange={e => handleEditorChanges('classificationType', e.target.value)} />
1590
+ Numeric/Quantitative
1587
1591
  </label>
1588
- )}
1589
- {/* Type */}
1590
- {/* Select > Filter a state */}
1591
- {state.general.geoType === 'single-state' && (
1592
1592
  <label>
1593
- <span className='edit-label column-heading'>State Selector</span>
1594
- <select
1595
- value={state.general.statePicked.stateName}
1596
- onChange={event => {
1597
- handleEditorChanges('chooseState', event.target.value)
1598
- }}
1599
- >
1600
- <StateOptionList />
1601
- </select>
1593
+ <input type='radio' name='category' value='category' checked={state.legend.type === 'category'} onChange={e => handleEditorChanges('classificationType', e.target.value)} />
1594
+ Categorical
1602
1595
  </label>
1603
- )}
1604
- {/* Type */}
1596
+ </div>
1597
+ </label>
1598
+
1599
+ <HexSetting.DisplayAsHexMap state={state} setState={setState} handleEditorChanges={handleEditorChanges} />
1600
+ <HexSetting.DisplayShapesOnHex state={state} setState={setState} />
1601
+ <HexSetting.ShapeColumns state={state} setState={setState} columnsOptions={columnsOptions} />
1602
+
1603
+ {'us' === state.general.geoType && 'bubble' !== state.general.type && false === state.general.displayAsHex && (
1604
+ <label className='checkbox'>
1605
+ <input
1606
+ type='checkbox'
1607
+ checked={state.general.displayStateLabels}
1608
+ onChange={event => {
1609
+ handleEditorChanges('displayStateLabels', event.target.checked)
1610
+ }}
1611
+ />
1612
+ <span className='edit-label'>Show state labels</span>
1613
+ </label>
1614
+ )}
1615
+ </AccordionItemPanel>
1616
+ </AccordionItem>
1617
+ <AccordionItem>
1618
+ {' '}
1619
+ {/* General */}
1620
+ <AccordionItemHeading>
1621
+ <AccordionItemButton>General</AccordionItemButton>
1622
+ </AccordionItemHeading>
1623
+ <AccordionItemPanel>
1624
+ <TextField
1625
+ value={general.title}
1626
+ data-testid='title-input'
1627
+ updateField={updateField}
1628
+ section='general'
1629
+ fieldName='title'
1630
+ id='title'
1631
+ label='Title'
1632
+ placeholder='Map Title'
1633
+ tooltip={
1634
+ <Tooltip style={{ textTransform: 'none' }}>
1635
+ <Tooltip.Target>
1636
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1637
+ </Tooltip.Target>
1638
+ <Tooltip.Content>
1639
+ <p>Title is required to set the name of the download file but can be hidden using the option below.</p>
1640
+ </Tooltip.Content>
1641
+ </Tooltip>
1642
+ }
1643
+ />
1644
+ <label className='checkbox'>
1645
+ <input
1646
+ type='checkbox'
1647
+ checked={state.general.showTitle || false}
1648
+ onChange={event => {
1649
+ handleEditorChanges('showTitle', event.target.checked)
1650
+ }}
1651
+ />
1652
+ <span className='edit-label'>Show Title</span>
1653
+ </label>
1654
+ <TextField
1655
+ value={general.superTitle || ''}
1656
+ updateField={updateField}
1657
+ section='general'
1658
+ fieldName='superTitle'
1659
+ label='Super Title'
1660
+ tooltip={
1661
+ <Tooltip style={{ textTransform: 'none' }}>
1662
+ <Tooltip.Target>
1663
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1664
+ </Tooltip.Target>
1665
+ <Tooltip.Content>
1666
+ <p>Super Title</p>
1667
+ </Tooltip.Content>
1668
+ </Tooltip>
1669
+ }
1670
+ />
1671
+ <TextField
1672
+ type='textarea'
1673
+ value={general.introText}
1674
+ updateField={updateField}
1675
+ section='general'
1676
+ fieldName='introText'
1677
+ label='Message'
1678
+ tooltip={
1679
+ <Tooltip style={{ textTransform: 'none' }}>
1680
+ <Tooltip.Target>
1681
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1682
+ </Tooltip.Target>
1683
+ <Tooltip.Content>
1684
+ <p>Intro Text</p>
1685
+ </Tooltip.Content>
1686
+ </Tooltip>
1687
+ }
1688
+ />
1689
+ <TextField
1690
+ type='textarea'
1691
+ value={general.subtext}
1692
+ updateField={updateField}
1693
+ section='general'
1694
+ fieldName='subtext'
1695
+ label='Subtext'
1696
+ tooltip={
1697
+ <Tooltip style={{ textTransform: 'none' }}>
1698
+ <Tooltip.Target>
1699
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1700
+ </Tooltip.Target>
1701
+ <Tooltip.Content>
1702
+ <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
1703
+ </Tooltip.Content>
1704
+ </Tooltip>
1705
+ }
1706
+ />
1707
+ <TextField
1708
+ type='textarea'
1709
+ value={general.footnotes}
1710
+ updateField={updateField}
1711
+ section='general'
1712
+ fieldName='footnotes'
1713
+ label='Footnotes'
1714
+ tooltip={
1715
+ <Tooltip style={{ textTransform: 'none' }}>
1716
+ <Tooltip.Target>
1717
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1718
+ </Tooltip.Target>
1719
+ <Tooltip.Content>
1720
+ <p>Footnotes</p>
1721
+ </Tooltip.Content>
1722
+ </Tooltip>
1723
+ }
1724
+ />
1725
+ {'us' === state.general.geoType && <TextField value={general.territoriesLabel} updateField={updateField} section='general' fieldName='territoriesLabel' label='Territories Label' placeholder='Territories' />}
1726
+ {'us' === state.general.geoType && (
1727
+ <label className='checkbox'>
1728
+ <input
1729
+ type='checkbox'
1730
+ checked={general.territoriesAlwaysShow || false}
1731
+ onChange={event => {
1732
+ handleEditorChanges('territoriesAlwaysShow', event.target.checked)
1733
+ }}
1734
+ />
1735
+ <span className='edit-label'>Show All Territories</span>
1736
+ </label>
1737
+ )}
1738
+ {/* <label className="checkbox mt-4">
1739
+ <input type="checkbox" checked={ state.general.showDownloadMediaButton } onChange={(event) => { handleEditorChanges("toggleDownloadMediaButton", event.target.checked) }} />
1740
+ <span className="edit-label">Enable Media Download</span>
1741
+ </label> */}
1742
+ </AccordionItemPanel>
1743
+ </AccordionItem>
1744
+ <AccordionItem>
1745
+ {' '}
1746
+ {/* Columns */}
1747
+ <AccordionItemHeading>
1748
+ <AccordionItemButton>Columns</AccordionItemButton>
1749
+ </AccordionItemHeading>
1750
+ <AccordionItemPanel>
1751
+ <fieldset className='primary-fieldset edit-block'>
1605
1752
  <label>
1606
1753
  <span className='edit-label column-heading'>
1607
- Map Type
1754
+ Geography
1608
1755
  <Tooltip style={{ textTransform: 'none' }}>
1609
1756
  <Tooltip.Target>
1610
1757
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1611
1758
  </Tooltip.Target>
1612
1759
  <Tooltip.Content>
1613
- <p>Select "Data" to create a color-coded data map. To create a navigation-only map, select "Navigation."</p>
1760
+ <p>Select the source column containing the map location names or, for county-level maps, the FIPS codes.</p>
1614
1761
  </Tooltip.Content>
1615
1762
  </Tooltip>
1616
1763
  </span>
1617
1764
  <select
1618
- value={state.general.type}
1765
+ value={state.columns.geo ? state.columns.geo.name : columnsOptions[0]}
1619
1766
  onChange={event => {
1620
- handleEditorChanges('editorMapType', event.target.value)
1767
+ editColumn('geo', 'name', event.target.value)
1621
1768
  }}
1622
1769
  >
1623
- <option value='data'>Data</option>
1624
- {state.general.geoType === 'us-county' && <option value='us-geocode'>Geocode</option>}
1625
- {state.general.geoType === 'world' && <option value='world-geocode'>Geocode</option>}
1626
- {state.general.geoType !== 'us-county' && <option value='navigation'>Navigation</option>}
1627
- {(state.general.geoType === 'world' || state.general.geoType === 'us') && <option value='bubble'>Bubble</option>}
1770
+ {columnsOptions}
1628
1771
  </select>
1629
1772
  </label>
1630
- <label>
1631
- <span className='edit-label'>Data Classification Type</span>
1632
- <div>
1633
- <label>
1634
- <input type='radio' name='equalnumber' value='equalnumber' checked={state.legend.type === 'equalnumber'} onChange={e => handleEditorChanges('classificationType', e.target.value)} />
1635
- Numeric/Quantitative
1636
- </label>
1637
- <label>
1638
- <input type='radio' name='category' value='category' checked={state.legend.type === 'category'} onChange={e => handleEditorChanges('classificationType', e.target.value)} />
1639
- Categorical
1640
- </label>
1641
- </div>
1642
- </label>
1643
-
1644
- <HexSetting.DisplayAsHexMap state={state} setState={setState} handleEditorChanges={handleEditorChanges} />
1645
- <HexSetting.DisplayShapesOnHex state={state} setState={setState} />
1646
- <HexSetting.ShapeColumns state={state} setState={setState} columnsOptions={columnsOptions} />
1647
-
1648
- {'us' === state.general.geoType && 'bubble' !== state.general.type && false === state.general.displayAsHex && (
1773
+ {state.general.type === 'us-geocode' && (
1649
1774
  <label className='checkbox'>
1650
1775
  <input
1651
1776
  type='checkbox'
1652
- checked={state.general.displayStateLabels}
1777
+ checked={state.general.convertFipsCodes}
1653
1778
  onChange={event => {
1654
- handleEditorChanges('displayStateLabels', event.target.checked)
1779
+ setState({
1780
+ ...state,
1781
+ general: {
1782
+ ...state.general,
1783
+ convertFipsCodes: event.target.checked
1784
+ }
1785
+ })
1655
1786
  }}
1656
1787
  />
1657
- <span className='edit-label'>Show state labels</span>
1788
+ <span className='edit-label'>Convert FIPS Codes to Geography Name</span>
1658
1789
  </label>
1659
1790
  )}
1660
- </AccordionItemPanel>
1661
- </AccordionItem>
1662
- <AccordionItem>
1663
- {' '}
1664
- {/* General */}
1665
- <AccordionItemHeading>
1666
- <AccordionItemButton>General</AccordionItemButton>
1667
- </AccordionItemHeading>
1668
- <AccordionItemPanel>
1669
- <TextField
1670
- value={general.title}
1671
- data-testid='title-input'
1672
- updateField={updateField}
1673
- section='general'
1674
- fieldName='title'
1675
- id='title'
1676
- label='Title'
1677
- placeholder='Map Title'
1678
- tooltip={
1679
- <Tooltip style={{ textTransform: 'none' }}>
1680
- <Tooltip.Target>
1681
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1682
- </Tooltip.Target>
1683
- <Tooltip.Content>
1684
- <p>Title is required to set the name of the download file but can be hidden using the option below.</p>
1685
- </Tooltip.Content>
1686
- </Tooltip>
1687
- }
1688
- />
1791
+
1689
1792
  <label className='checkbox'>
1690
1793
  <input
1691
1794
  type='checkbox'
1692
- checked={state.general.showTitle || false}
1795
+ checked={state.general.hideGeoColumnInTooltip || false}
1693
1796
  onChange={event => {
1694
- handleEditorChanges('showTitle', event.target.checked)
1797
+ handleEditorChanges('hideGeoColumnInTooltip', event.target.checked)
1695
1798
  }}
1696
1799
  />
1697
- <span className='edit-label'>Show Title</span>
1800
+ <span className='edit-label'>Hide Geography Column Name in Tooltip</span>
1698
1801
  </label>
1699
1802
  <TextField
1700
- value={general.superTitle || ''}
1701
- updateField={updateField}
1702
- section='general'
1703
- fieldName='superTitle'
1704
- label='Super Title'
1705
- tooltip={
1706
- <Tooltip style={{ textTransform: 'none' }}>
1707
- <Tooltip.Target>
1708
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1709
- </Tooltip.Target>
1710
- <Tooltip.Content>
1711
- <p>Super Title</p>
1712
- </Tooltip.Content>
1713
- </Tooltip>
1714
- }
1715
- />
1716
- <TextField
1717
- type='textarea'
1718
- value={general.introText}
1719
- updateField={updateField}
1720
- section='general'
1721
- fieldName='introText'
1722
- label='Message'
1723
- tooltip={
1724
- <Tooltip style={{ textTransform: 'none' }}>
1725
- <Tooltip.Target>
1726
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1727
- </Tooltip.Target>
1728
- <Tooltip.Content>
1729
- <p>Intro Text</p>
1730
- </Tooltip.Content>
1731
- </Tooltip>
1732
- }
1733
- />
1734
- <TextField
1735
- type='textarea'
1736
- value={general.subtext}
1737
- updateField={updateField}
1803
+ value={state.general.geoLabelOverride}
1738
1804
  section='general'
1739
- fieldName='subtext'
1740
- label='Subtext'
1741
- tooltip={
1742
- <Tooltip style={{ textTransform: 'none' }}>
1743
- <Tooltip.Target>
1744
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1745
- </Tooltip.Target>
1746
- <Tooltip.Content>
1747
- <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
1748
- </Tooltip.Content>
1749
- </Tooltip>
1750
- }
1751
- />
1752
- <TextField
1753
- type='textarea'
1754
- value={general.footnotes}
1805
+ fieldName='geoLabelOverride'
1806
+ label='Geography Label'
1807
+ className='edit-label'
1755
1808
  updateField={updateField}
1756
- section='general'
1757
- fieldName='footnotes'
1758
- label='Footnotes'
1759
1809
  tooltip={
1760
1810
  <Tooltip style={{ textTransform: 'none' }}>
1761
1811
  <Tooltip.Target>
1762
1812
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1763
1813
  </Tooltip.Target>
1764
1814
  <Tooltip.Content>
1765
- <p>Footnotes</p>
1815
+ <p>Enter a geography label for use in tooltips.</p>
1766
1816
  </Tooltip.Content>
1767
1817
  </Tooltip>
1768
1818
  }
1769
1819
  />
1770
- {'us' === state.general.geoType && <TextField value={general.territoriesLabel} updateField={updateField} section='general' fieldName='territoriesLabel' label='Territories Label' placeholder='Territories' />}
1771
- {'us' === state.general.geoType && (
1772
- <label className='checkbox'>
1773
- <input
1774
- type='checkbox'
1775
- checked={general.territoriesAlwaysShow || false}
1776
- onChange={event => {
1777
- handleEditorChanges('territoriesAlwaysShow', event.target.checked)
1778
- }}
1779
- />
1780
- <span className='edit-label'>Show All Territories</span>
1781
- </label>
1782
- )}
1783
- {/* <label className="checkbox mt-4">
1784
- <input type="checkbox" checked={ state.general.showDownloadMediaButton } onChange={(event) => { handleEditorChanges("toggleDownloadMediaButton", event.target.checked) }} />
1785
- <span className="edit-label">Enable Media Download</span>
1786
- </label> */}
1787
- </AccordionItemPanel>
1788
- </AccordionItem>
1789
- <AccordionItem>
1790
- {' '}
1791
- {/* Columns */}
1792
- <AccordionItemHeading>
1793
- <AccordionItemButton>Columns</AccordionItemButton>
1794
- </AccordionItemHeading>
1795
- <AccordionItemPanel>
1820
+ </fieldset>
1821
+ {'navigation' !== state.general.type && (
1796
1822
  <fieldset className='primary-fieldset edit-block'>
1797
1823
  <label>
1798
1824
  <span className='edit-label column-heading'>
1799
- Geography
1825
+ Data Column
1800
1826
  <Tooltip style={{ textTransform: 'none' }}>
1801
1827
  <Tooltip.Target>
1802
1828
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1803
1829
  </Tooltip.Target>
1804
1830
  <Tooltip.Content>
1805
- <p>Select the source column containing the map location names or, for county-level maps, the FIPS codes.</p>
1831
+ <p>Select the source column containing the categorical or numeric values to be mapped.</p>
1806
1832
  </Tooltip.Content>
1807
1833
  </Tooltip>
1808
1834
  </span>
1809
1835
  <select
1810
- value={state.columns.geo ? state.columns.geo.name : columnsOptions[0]}
1836
+ value={state.columns.primary ? state.columns.primary.name : columnsOptions[0]}
1811
1837
  onChange={event => {
1812
- editColumn('geo', 'name', event.target.value)
1838
+ editColumn('primary', 'name', event.target.value)
1813
1839
  }}
1814
1840
  >
1815
1841
  {columnsOptions}
1816
1842
  </select>
1817
1843
  </label>
1818
- {state.general.type === 'us-geocode' && (
1819
- <label className='checkbox'>
1820
- <input
1821
- type='checkbox'
1822
- checked={state.general.convertFipsCodes}
1823
- onChange={event => {
1824
- setState({
1825
- ...state,
1826
- general: {
1827
- ...state.general,
1828
- convertFipsCodes: event.target.checked
1829
- }
1830
- })
1831
- }}
1832
- />
1833
- <span className='edit-label'>Convert FIPS Codes to Geography Name</span>
1834
- </label>
1835
- )}
1836
-
1837
1844
  <label className='checkbox'>
1838
1845
  <input
1839
1846
  type='checkbox'
1840
- checked={state.general.hideGeoColumnInTooltip || false}
1847
+ checked={state.general.hidePrimaryColumnInTooltip || false}
1841
1848
  onChange={event => {
1842
- handleEditorChanges('hideGeoColumnInTooltip', event.target.checked)
1849
+ handleEditorChanges('hidePrimaryColumnInTooltip', event.target.checked)
1843
1850
  }}
1844
1851
  />
1845
- <span className='edit-label'>Hide Geography Column Name in Tooltip</span>
1852
+ <span className='edit-label'>Hide Data Column Name in Tooltip</span>
1846
1853
  </label>
1847
1854
  <TextField
1848
- value={state.general.geoLabelOverride}
1849
- section='general'
1850
- fieldName='geoLabelOverride'
1851
- label='Geography Label'
1852
- className='edit-label'
1855
+ value={columns.primary.label}
1856
+ section='columns'
1857
+ subsection='primary'
1858
+ fieldName='label'
1859
+ label='Data Label'
1853
1860
  updateField={updateField}
1854
1861
  tooltip={
1855
1862
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1857,1253 +1864,1200 @@ const EditorPanel = props => {
1857
1864
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1858
1865
  </Tooltip.Target>
1859
1866
  <Tooltip.Content>
1860
- <p>Enter a geography label for use in tooltips.</p>
1867
+ <p>Enter a data label for use in tooltips and the data table.</p>
1861
1868
  </Tooltip.Content>
1862
1869
  </Tooltip>
1863
1870
  }
1864
1871
  />
1872
+ <ul className='column-edit'>
1873
+ <li className='three-col'>
1874
+ <TextField value={columns.primary.prefix} section='columns' subsection='primary' fieldName='prefix' label='Prefix' updateField={updateField} />
1875
+ <TextField value={columns.primary.suffix} section='columns' subsection='primary' fieldName='suffix' label='Suffix' updateField={updateField} />
1876
+ <TextField type='number' value={columns.primary.roundToPlace} section='columns' subsection='primary' fieldName='roundToPlace' label='Round' updateField={updateField} min={0} />
1877
+ </li>
1878
+ <li>
1879
+ <label className='checkbox'>
1880
+ <input
1881
+ type='checkbox'
1882
+ checked={state.columns.primary.useCommas}
1883
+ onChange={event => {
1884
+ editColumn('primary', 'useCommas', event.target.checked)
1885
+ }}
1886
+ />
1887
+ <span className='edit-label'>Add Commas to Numbers</span>
1888
+ </label>
1889
+ </li>
1890
+ <li>
1891
+ <label className='checkbox'>
1892
+ <input
1893
+ type='checkbox'
1894
+ checked={state.columns.primary.dataTable || false}
1895
+ onChange={event => {
1896
+ editColumn('primary', 'dataTable', event.target.checked)
1897
+ }}
1898
+ />
1899
+ <span className='edit-label'>Show in Data Table</span>
1900
+ </label>
1901
+ </li>
1902
+ <li>
1903
+ <label className='checkbox'>
1904
+ <input
1905
+ type='checkbox'
1906
+ checked={state.columns.primary.tooltip || false}
1907
+ onChange={event => {
1908
+ editColumn('primary', 'tooltip', event.target.checked)
1909
+ }}
1910
+ />
1911
+ <span className='edit-label'>Show in Tooltips</span>
1912
+ </label>
1913
+ </li>
1914
+ </ul>
1865
1915
  </fieldset>
1866
- {'navigation' !== state.general.type && (
1867
- <fieldset className='primary-fieldset edit-block'>
1868
- <label>
1869
- <span className='edit-label column-heading'>
1870
- Data Column
1871
- <Tooltip style={{ textTransform: 'none' }}>
1872
- <Tooltip.Target>
1873
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1874
- </Tooltip.Target>
1875
- <Tooltip.Content>
1876
- <p>Select the source column containing the categorical or numeric values to be mapped.</p>
1877
- </Tooltip.Content>
1878
- </Tooltip>
1879
- </span>
1880
- <select
1881
- value={state.columns.primary ? state.columns.primary.name : columnsOptions[0]}
1882
- onChange={event => {
1883
- editColumn('primary', 'name', event.target.value)
1884
- }}
1885
- >
1886
- {columnsOptions}
1887
- </select>
1888
- </label>
1889
- <label className='checkbox'>
1890
- <input
1891
- type='checkbox'
1892
- checked={state.general.hidePrimaryColumnInTooltip || false}
1893
- onChange={event => {
1894
- handleEditorChanges('hidePrimaryColumnInTooltip', event.target.checked)
1895
- }}
1896
- />
1897
- <span className='edit-label'>Hide Data Column Name in Tooltip</span>
1898
- </label>
1899
- <TextField
1900
- value={columns.primary.label}
1901
- section='columns'
1902
- subsection='primary'
1903
- fieldName='label'
1904
- label='Data Label'
1905
- updateField={updateField}
1906
- tooltip={
1907
- <Tooltip style={{ textTransform: 'none' }}>
1908
- <Tooltip.Target>
1909
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1910
- </Tooltip.Target>
1911
- <Tooltip.Content>
1912
- <p>Enter a data label for use in tooltips and the data table.</p>
1913
- </Tooltip.Content>
1914
- </Tooltip>
1915
- }
1916
- />
1917
- <ul className='column-edit'>
1918
- <li className='three-col'>
1919
- <TextField value={columns.primary.prefix} section='columns' subsection='primary' fieldName='prefix' label='Prefix' updateField={updateField} />
1920
- <TextField value={columns.primary.suffix} section='columns' subsection='primary' fieldName='suffix' label='Suffix' updateField={updateField} />
1921
- <TextField type='number' value={columns.primary.roundToPlace} section='columns' subsection='primary' fieldName='roundToPlace' label='Round' updateField={updateField} min={0} />
1922
- </li>
1923
- <li>
1924
- <label className='checkbox'>
1925
- <input
1926
- type='checkbox'
1927
- checked={state.columns.primary.useCommas}
1928
- onChange={event => {
1929
- editColumn('primary', 'useCommas', event.target.checked)
1930
- }}
1931
- />
1932
- <span className='edit-label'>Add Commas to Numbers</span>
1933
- </label>
1934
- </li>
1935
- <li>
1936
- <label className='checkbox'>
1937
- <input
1938
- type='checkbox'
1939
- checked={state.columns.primary.dataTable || false}
1940
- onChange={event => {
1941
- editColumn('primary', 'dataTable', event.target.checked)
1942
- }}
1943
- />
1944
- <span className='edit-label'>Show in Data Table</span>
1945
- </label>
1946
- </li>
1947
- <li>
1948
- <label className='checkbox'>
1949
- <input
1950
- type='checkbox'
1951
- checked={state.columns.primary.tooltip || false}
1952
- onChange={event => {
1953
- editColumn('primary', 'tooltip', event.target.checked)
1954
- }}
1955
- />
1956
- <span className='edit-label'>Show in Tooltips</span>
1957
- </label>
1958
- </li>
1959
- </ul>
1960
- </fieldset>
1961
- )}
1916
+ )}
1962
1917
 
1963
- {state.general.type === 'bubble' && state.legend.type === 'category' && (
1964
- <fieldset className='primary-fieldset edit-block'>
1965
- <label>
1966
- <span className='edit-label column-heading'>
1967
- Category Column
1968
- <Tooltip style={{ textTransform: 'none' }}>
1969
- <Tooltip.Target>
1970
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1971
- </Tooltip.Target>
1972
- <Tooltip.Content>
1973
- <p>Select the source column containing the categorical bubble values to be mapped.</p>
1974
- </Tooltip.Content>
1975
- </Tooltip>
1976
- </span>
1977
- <select
1978
- value={state.columns.categorical ? state.columns.categorical.name : columnsOptions[0]}
1979
- onChange={event => {
1980
- editColumn('categorical', 'name', event.target.value)
1981
- }}
1982
- >
1983
- {columnsOptions}
1984
- </select>
1985
- </label>
1986
- </fieldset>
1987
- )}
1988
- {
1989
- <>
1990
- <label>Latitude Column</label>
1991
- <select
1992
- value={state.columns.latitude.name ? state.columns.latitude.name : ''}
1993
- onChange={e => {
1994
- editColumn('latitude', 'name', e.target.value)
1995
- }}
1996
- >
1997
- {columnsOptions}
1998
- </select>
1999
- <label>Longitude Column</label>
1918
+ {state.general.type === 'bubble' && state.legend.type === 'category' && (
1919
+ <fieldset className='primary-fieldset edit-block'>
1920
+ <label>
1921
+ <span className='edit-label column-heading'>
1922
+ Category Column
1923
+ <Tooltip style={{ textTransform: 'none' }}>
1924
+ <Tooltip.Target>
1925
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1926
+ </Tooltip.Target>
1927
+ <Tooltip.Content>
1928
+ <p>Select the source column containing the categorical bubble values to be mapped.</p>
1929
+ </Tooltip.Content>
1930
+ </Tooltip>
1931
+ </span>
2000
1932
  <select
2001
- value={state.columns.longitude.name ? state.columns.longitude.name : ''}
2002
- onChange={e => {
2003
- editColumn('longitude', 'name', e.target.value)
1933
+ value={state.columns.categorical ? state.columns.categorical.name : columnsOptions[0]}
1934
+ onChange={event => {
1935
+ editColumn('categorical', 'name', event.target.value)
2004
1936
  }}
2005
1937
  >
2006
1938
  {columnsOptions}
2007
1939
  </select>
2008
- </>
2009
- }
2010
-
2011
- {'navigation' !== state.general.type && (
2012
- <fieldset className='primary-fieldset edit-block'>
2013
- <label>
2014
- <span className='edit-label'>
2015
- Special Classes
2016
- <Tooltip style={{ textTransform: 'none' }}>
2017
- <Tooltip.Target>
2018
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2019
- </Tooltip.Target>
2020
- <Tooltip.Content>
2021
- <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>
2022
- </Tooltip.Content>
2023
- </Tooltip>
2024
- </span>
2025
- </label>
2026
- {specialClasses.map((specialClass, i) => (
2027
- <div className='edit-block' key={`special-class-${i}`}>
2028
- <button
2029
- className='remove-column'
2030
- onClick={e => {
2031
- e.preventDefault()
2032
- editColumn('primary', 'specialClassDelete', i)
2033
- }}
2034
- >
2035
- Remove
2036
- </button>
2037
- <p>Special Class {i + 1}</p>
2038
- <label>
2039
- <span className='edit-label column-heading'>Data Key</span>
2040
- <select
2041
- value={specialClass.key}
2042
- onChange={e => {
2043
- editColumn('primary', 'specialClassEdit', { prop: 'key', index: i, value: e.target.value })
2044
- }}
2045
- >
2046
- {columnsOptions}
2047
- </select>
2048
- </label>
2049
- <label>
2050
- <span className='edit-label column-heading'>Value</span>
2051
- <select
2052
- value={specialClass.value}
2053
- onChange={e => {
2054
- editColumn('primary', 'specialClassEdit', { prop: 'value', index: i, value: e.target.value })
2055
- }}
2056
- >
2057
- <option value=''>- Select Value -</option>
2058
- {columnsByKey[specialClass.key] && columnsByKey[specialClass.key].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2059
- </select>
2060
- </label>
2061
- <label>
2062
- <span className='edit-label column-heading'>Label</span>
2063
- <input
2064
- type='text'
2065
- value={specialClass.label}
2066
- onChange={e => {
2067
- editColumn('primary', 'specialClassEdit', { prop: 'label', index: i, value: e.target.value })
2068
- }}
2069
- />
2070
- </label>
2071
- </div>
2072
- ))}
2073
- <button
2074
- className='btn full-width'
2075
- onClick={e => {
2076
- e.preventDefault()
2077
- editColumn('primary', 'specialClassAdd', {})
2078
- }}
2079
- >
2080
- Add Special Class
2081
- </button>
2082
- </fieldset>
2083
- )}
2084
-
2085
- <label className='edit-block navigate column-heading'>
2086
- <span className='edit-label column-heading'>
2087
- Navigation
2088
- <Tooltip style={{ textTransform: 'none' }}>
2089
- <Tooltip.Target>
2090
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2091
- </Tooltip.Target>
2092
- <Tooltip.Content>
2093
- <p>To provide end users with navigation functionality, select the source column containing the navigation URLs.</p>
2094
- </Tooltip.Content>
2095
- </Tooltip>
2096
- </span>
1940
+ </label>
1941
+ </fieldset>
1942
+ )}
1943
+ {
1944
+ <>
1945
+ <label>Latitude Column</label>
2097
1946
  <select
2098
- value={state.columns.navigate ? state.columns.navigate.name : columnsOptions[0]}
2099
- onChange={event => {
2100
- editColumn('navigate', 'name', event.target.value)
1947
+ value={state.columns.latitude.name ? state.columns.latitude.name : ''}
1948
+ onChange={e => {
1949
+ editColumn('latitude', 'name', e.target.value)
2101
1950
  }}
2102
1951
  >
2103
1952
  {columnsOptions}
2104
1953
  </select>
2105
- </label>
2106
- {'navigation' !== state.general.type && (
2107
- <fieldset className='primary-fieldset edit-block'>
2108
- <label>
2109
- <span className='edit-label'>
2110
- Additional Columns
2111
- <Tooltip style={{ textTransform: 'none' }}>
2112
- <Tooltip.Target>
2113
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2114
- </Tooltip.Target>
2115
- <Tooltip.Content>
2116
- <p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
2117
- </Tooltip.Content>
2118
- </Tooltip>
2119
- </span>
2120
- </label>
2121
- {additionalColumns.map(val => (
1954
+ <label>Longitude Column</label>
1955
+ <select
1956
+ value={state.columns.longitude.name ? state.columns.longitude.name : ''}
1957
+ onChange={e => {
1958
+ editColumn('longitude', 'name', e.target.value)
1959
+ }}
1960
+ >
1961
+ {columnsOptions}
1962
+ </select>
1963
+ </>
1964
+ }
1965
+
1966
+ {'navigation' !== state.general.type && (
1967
+ <fieldset className='primary-fieldset edit-block'>
1968
+ <label>
1969
+ <span className='edit-label'>
1970
+ Special Classes
1971
+ <Tooltip style={{ textTransform: 'none' }}>
1972
+ <Tooltip.Target>
1973
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1974
+ </Tooltip.Target>
1975
+ <Tooltip.Content>
1976
+ <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>
1977
+ </Tooltip.Content>
1978
+ </Tooltip>
1979
+ </span>
1980
+ </label>
1981
+ {specialClasses.map((specialClass, i) => (
1982
+ <div className='edit-block' key={`special-class-${i}`}>
1983
+ <button
1984
+ className='remove-column'
1985
+ onClick={e => {
1986
+ e.preventDefault()
1987
+ editColumn('primary', 'specialClassDelete', i)
1988
+ }}
1989
+ >
1990
+ Remove
1991
+ </button>
1992
+ <p>Special Class {i + 1}</p>
1993
+ <label>
1994
+ <span className='edit-label column-heading'>Data Key</span>
1995
+ <select
1996
+ value={specialClass.key}
1997
+ onChange={e => {
1998
+ editColumn('primary', 'specialClassEdit', { prop: 'key', index: i, value: e.target.value })
1999
+ }}
2000
+ >
2001
+ {columnsOptions}
2002
+ </select>
2003
+ </label>
2004
+ <label>
2005
+ <span className='edit-label column-heading'>Value</span>
2006
+ <select
2007
+ value={specialClass.value}
2008
+ onChange={e => {
2009
+ editColumn('primary', 'specialClassEdit', { prop: 'value', index: i, value: e.target.value })
2010
+ }}
2011
+ >
2012
+ <option value=''>- Select Value -</option>
2013
+ {columnsByKey[specialClass.key] && columnsByKey[specialClass.key].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2014
+ </select>
2015
+ </label>
2016
+ <label>
2017
+ <span className='edit-label column-heading'>Label</span>
2018
+ <input
2019
+ type='text'
2020
+ value={specialClass.label}
2021
+ onChange={e => {
2022
+ editColumn('primary', 'specialClassEdit', { prop: 'label', index: i, value: e.target.value })
2023
+ }}
2024
+ />
2025
+ </label>
2026
+ </div>
2027
+ ))}
2028
+ <button
2029
+ className='btn full-width'
2030
+ onClick={e => {
2031
+ e.preventDefault()
2032
+ editColumn('primary', 'specialClassAdd', {})
2033
+ }}
2034
+ >
2035
+ Add Special Class
2036
+ </button>
2037
+ </fieldset>
2038
+ )}
2039
+
2040
+ <label className='edit-block navigate column-heading'>
2041
+ <span className='edit-label column-heading'>
2042
+ Navigation
2043
+ <Tooltip style={{ textTransform: 'none' }}>
2044
+ <Tooltip.Target>
2045
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2046
+ </Tooltip.Target>
2047
+ <Tooltip.Content>
2048
+ <p>To provide end users with navigation functionality, select the source column containing the navigation URLs.</p>
2049
+ </Tooltip.Content>
2050
+ </Tooltip>
2051
+ </span>
2052
+ <select
2053
+ value={state.columns.navigate ? state.columns.navigate.name : columnsOptions[0]}
2054
+ onChange={event => {
2055
+ editColumn('navigate', 'name', event.target.value)
2056
+ }}
2057
+ >
2058
+ {columnsOptions}
2059
+ </select>
2060
+ </label>
2061
+ {'navigation' !== state.general.type && (
2062
+ <fieldset className='primary-fieldset edit-block'>
2063
+ <label>
2064
+ <span className='edit-label'>
2065
+ Additional Columns
2066
+ <Tooltip style={{ textTransform: 'none' }}>
2067
+ <Tooltip.Target>
2068
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2069
+ </Tooltip.Target>
2070
+ <Tooltip.Content>
2071
+ <p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
2072
+ </Tooltip.Content>
2073
+ </Tooltip>
2074
+ </span>
2075
+ </label>
2076
+ {additionalColumns.map(val => (
2077
+ <fieldset className='edit-block' key={val}>
2078
+ <button
2079
+ className='remove-column'
2080
+ onClick={event => {
2081
+ event.preventDefault()
2082
+ removeAdditionalColumn(val)
2083
+ }}
2084
+ >
2085
+ Remove
2086
+ </button>
2087
+ <label>
2088
+ <span className='edit-label column-heading'>Column</span>
2089
+ <select
2090
+ value={state.columns[val] ? state.columns[val].name : columnsOptions[0]}
2091
+ onChange={event => {
2092
+ editColumn(val, 'name', event.target.value)
2093
+ }}
2094
+ >
2095
+ {columnsOptions}
2096
+ </select>
2097
+ </label>
2098
+ <TextField value={columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
2099
+ <ul className='column-edit'>
2100
+ <li className='three-col'>
2101
+ <TextField value={columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
2102
+ <TextField value={columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
2103
+ <TextField type='number' value={columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
2104
+ </li>
2105
+ <li>
2106
+ <label className='checkbox'>
2107
+ <input
2108
+ type='checkbox'
2109
+ checked={state.columns[val].useCommas}
2110
+ onChange={event => {
2111
+ editColumn(val, 'useCommas', event.target.checked)
2112
+ }}
2113
+ />
2114
+ <span className='edit-label'>Add Commas to Numbers</span>
2115
+ </label>
2116
+ </li>
2117
+ <li>
2118
+ <label className='checkbox'>
2119
+ <input
2120
+ type='checkbox'
2121
+ checked={state.columns[val].dataTable}
2122
+ onChange={event => {
2123
+ editColumn(val, 'dataTable', event.target.checked)
2124
+ }}
2125
+ />
2126
+ <span className='edit-label'>Show in Data Table</span>
2127
+ </label>
2128
+ </li>
2129
+ <li>
2130
+ <label className='checkbox'>
2131
+ <input
2132
+ type='checkbox'
2133
+ checked={state.columns[val].tooltip}
2134
+ onChange={event => {
2135
+ editColumn(val, 'tooltip', event.target.checked)
2136
+ }}
2137
+ />
2138
+ <span className='edit-label'>Show in Tooltips</span>
2139
+ </label>
2140
+ </li>
2141
+ </ul>
2142
+ </fieldset>
2143
+ ))}
2144
+ <button
2145
+ className={'btn full-width'}
2146
+ onClick={event => {
2147
+ event.preventDefault()
2148
+ addAdditionalColumn(additionalColumns.length + 1)
2149
+ }}
2150
+ >
2151
+ Add Column
2152
+ </button>
2153
+ </fieldset>
2154
+ )}
2155
+ {'category' === state.legend.type && (
2156
+ <fieldset className='primary-fieldset edit-block'>
2157
+ <label>
2158
+ <span className='edit-label'>
2159
+ Additional Category
2160
+ <Tooltip style={{ textTransform: 'none' }}>
2161
+ <Tooltip.Target>
2162
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2163
+ </Tooltip.Target>
2164
+ <Tooltip.Content>
2165
+ <p>You can provide additional categories to ensure they appear in the legend</p>
2166
+ </Tooltip.Content>
2167
+ </Tooltip>
2168
+ </span>
2169
+ </label>
2170
+ {state.legend.additionalCategories &&
2171
+ state.legend.additionalCategories.map((val, i) => (
2122
2172
  <fieldset className='edit-block' key={val}>
2123
2173
  <button
2124
2174
  className='remove-column'
2125
2175
  onClick={event => {
2126
2176
  event.preventDefault()
2127
- removeAdditionalColumn(val)
2177
+ const updatedAdditionaCategories = [...state.legend.additionalCategories]
2178
+ updatedAdditionaCategories.splice(i, 1)
2179
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2128
2180
  }}
2129
2181
  >
2130
2182
  Remove
2131
2183
  </button>
2132
2184
  <label>
2133
- <span className='edit-label column-heading'>Column</span>
2134
- <select
2135
- value={state.columns[val] ? state.columns[val].name : columnsOptions[0]}
2136
- onChange={event => {
2137
- editColumn(val, 'name', event.target.value)
2185
+ <span className='edit-label column-heading'>Category</span>
2186
+ <TextField
2187
+ value={val}
2188
+ section='legend'
2189
+ subsection={null}
2190
+ fieldName='additionalCategories'
2191
+ updateField={(section, subsection, fieldName, value) => {
2192
+ const updatedAdditionaCategories = [...state.legend.additionalCategories]
2193
+ updatedAdditionaCategories[i] = value
2194
+ updateField(section, subsection, fieldName, updatedAdditionaCategories)
2138
2195
  }}
2139
- >
2140
- {columnsOptions}
2141
- </select>
2196
+ />
2142
2197
  </label>
2143
- <TextField value={columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
2144
- <ul className='column-edit'>
2145
- <li className='three-col'>
2146
- <TextField value={columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
2147
- <TextField value={columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
2148
- <TextField type='number' value={columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
2149
- </li>
2150
- <li>
2151
- <label className='checkbox'>
2152
- <input
2153
- type='checkbox'
2154
- checked={state.columns[val].useCommas}
2155
- onChange={event => {
2156
- editColumn(val, 'useCommas', event.target.checked)
2157
- }}
2158
- />
2159
- <span className='edit-label'>Add Commas to Numbers</span>
2160
- </label>
2161
- </li>
2162
- <li>
2163
- <label className='checkbox'>
2164
- <input
2165
- type='checkbox'
2166
- checked={state.columns[val].dataTable}
2167
- onChange={event => {
2168
- editColumn(val, 'dataTable', event.target.checked)
2169
- }}
2170
- />
2171
- <span className='edit-label'>Show in Data Table</span>
2172
- </label>
2173
- </li>
2174
- <li>
2175
- <label className='checkbox'>
2176
- <input
2177
- type='checkbox'
2178
- checked={state.columns[val].tooltip}
2179
- onChange={event => {
2180
- editColumn(val, 'tooltip', event.target.checked)
2181
- }}
2182
- />
2183
- <span className='edit-label'>Show in Tooltips</span>
2184
- </label>
2185
- </li>
2186
- </ul>
2187
2198
  </fieldset>
2188
2199
  ))}
2189
- <button
2190
- className={'btn full-width'}
2191
- onClick={event => {
2192
- event.preventDefault()
2193
- addAdditionalColumn(additionalColumns.length + 1)
2200
+ <button
2201
+ className={'btn full-width'}
2202
+ onClick={event => {
2203
+ event.preventDefault()
2204
+ const updatedAdditionaCategories = [...(state.legend.additionalCategories || [])]
2205
+ updatedAdditionaCategories.push('')
2206
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2207
+ }}
2208
+ >
2209
+ Add Category
2210
+ </button>
2211
+ </fieldset>
2212
+ )}
2213
+ </AccordionItemPanel>
2214
+ </AccordionItem>{' '}
2215
+ {/* Columns */}
2216
+ {'navigation' !== state.general.type && (
2217
+ <AccordionItem>
2218
+ {' '}
2219
+ {/* Legend */}
2220
+ <AccordionItemHeading>
2221
+ <AccordionItemButton>Legend</AccordionItemButton>
2222
+ </AccordionItemHeading>
2223
+ <AccordionItemPanel>
2224
+ {(state.legend.type === 'equalnumber' || state.legend.type === 'equalinterval') && (
2225
+ <label>
2226
+ <span className='edit-label'>Legend Type</span>
2227
+ <select
2228
+ value={legend.type}
2229
+ onChange={event => {
2230
+ handleEditorChanges('legendType', event.target.value)
2194
2231
  }}
2195
2232
  >
2196
- Add Column
2197
- </button>
2198
- </fieldset>
2233
+ <option value='equalnumber'>Equal Number (Quantiles)</option>
2234
+ <option value='equalinterval'>Equal Interval</option>
2235
+ </select>
2236
+ </label>
2199
2237
  )}
2200
- {'category' === state.legend.type && (
2201
- <fieldset className='primary-fieldset edit-block'>
2202
- <label>
2203
- <span className='edit-label'>
2204
- Additional Category
2205
- <Tooltip style={{ textTransform: 'none' }}>
2206
- <Tooltip.Target>
2207
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2208
- </Tooltip.Target>
2209
- <Tooltip.Content>
2210
- <p>You can provide additional categories to ensure they appear in the legend</p>
2211
- </Tooltip.Content>
2212
- </Tooltip>
2213
- </span>
2214
- </label>
2215
- {state.legend.additionalCategories &&
2216
- state.legend.additionalCategories.map((val, i) => (
2217
- <fieldset className='edit-block' key={val}>
2218
- <button
2219
- className='remove-column'
2220
- onClick={event => {
2221
- event.preventDefault()
2222
- const updatedAdditionaCategories = [...state.legend.additionalCategories]
2223
- updatedAdditionaCategories.splice(i, 1)
2224
- updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2225
- }}
2226
- >
2227
- Remove
2228
- </button>
2229
- <label>
2230
- <span className='edit-label column-heading'>Category</span>
2231
- <TextField
2232
- value={val}
2233
- section='legend'
2234
- subsection={null}
2235
- fieldName='additionalCategories'
2236
- updateField={(section, subsection, fieldName, value) => {
2237
- const updatedAdditionaCategories = [...state.legend.additionalCategories]
2238
- updatedAdditionaCategories[i] = value
2239
- updateField(section, subsection, fieldName, updatedAdditionaCategories)
2240
- }}
2241
- />
2242
- </label>
2243
- </fieldset>
2244
- ))}
2245
- <button
2246
- className={'btn full-width'}
2247
- onClick={event => {
2248
- event.preventDefault()
2249
- const updatedAdditionaCategories = [...(state.legend.additionalCategories || [])]
2250
- updatedAdditionaCategories.push('')
2251
- updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2238
+ {'navigation' !== state.general.type && (
2239
+ <label className='checkbox'>
2240
+ <input
2241
+ type='checkbox'
2242
+ checked={state.general.showSidebar || false}
2243
+ onChange={event => {
2244
+ handleEditorChanges('showSidebar', event.target.checked)
2245
+ }}
2246
+ />
2247
+ <span className='edit-label'>Show Legend</span>
2248
+ </label>
2249
+ )}
2250
+ {'navigation' !== state.general.type && (
2251
+ <label>
2252
+ <span className='edit-label'>Legend Position</span>
2253
+ <select
2254
+ value={legend.position || false}
2255
+ onChange={event => {
2256
+ handleEditorChanges('sidebarPosition', event.target.value)
2252
2257
  }}
2253
2258
  >
2254
- Add Category
2255
- </button>
2256
- </fieldset>
2259
+ <option value='side'>Side</option>
2260
+ <option value='bottom'>Bottom</option>
2261
+ </select>
2262
+ </label>
2257
2263
  )}
2258
- </AccordionItemPanel>
2259
- </AccordionItem>{' '}
2260
- {/* Columns */}
2261
- {'navigation' !== state.general.type && (
2262
- <AccordionItem>
2263
- {' '}
2264
- {/* Legend */}
2265
- <AccordionItemHeading>
2266
- <AccordionItemButton>Legend</AccordionItemButton>
2267
- </AccordionItemHeading>
2268
- <AccordionItemPanel>
2269
- {(state.legend.type === 'equalnumber' || state.legend.type === 'equalinterval') && (
2270
- <label>
2271
- <span className='edit-label'>Legend Type</span>
2272
- <select
2273
- value={legend.type}
2274
- onChange={event => {
2275
- handleEditorChanges('legendType', event.target.value)
2276
- }}
2277
- >
2278
- <option value='equalnumber'>Equal Number (Quantiles)</option>
2279
- <option value='equalinterval'>Equal Interval</option>
2280
- </select>
2281
- </label>
2282
- )}
2283
- {'navigation' !== state.general.type && (
2284
- <label className='checkbox'>
2285
- <input
2286
- type='checkbox'
2287
- checked={state.general.showSidebar || false}
2288
- onChange={event => {
2289
- handleEditorChanges('showSidebar', event.target.checked)
2290
- }}
2291
- />
2292
- <span className='edit-label'>Show Legend</span>
2293
- </label>
2294
- )}
2295
- {'navigation' !== state.general.type && (
2296
- <label>
2297
- <span className='edit-label'>Legend Position</span>
2298
- <select
2299
- value={legend.position || false}
2300
- onChange={event => {
2301
- handleEditorChanges('sidebarPosition', event.target.value)
2302
- }}
2303
- >
2304
- <option value='side'>Side</option>
2305
- <option value='bottom'>Bottom</option>
2306
- </select>
2307
- </label>
2308
- )}
2309
- {'side' === legend.position && (
2310
- <label className='checkbox'>
2311
- <input
2312
- type='checkbox'
2313
- checked={legend.singleColumn}
2314
- onChange={event => {
2315
- handleEditorChanges('singleColumnLegend', event.target.checked)
2316
- }}
2317
- />
2318
- <span className='edit-label'>Single Column Legend</span>
2319
- </label>
2320
- )}
2321
- {'bottom' === legend.position && (
2322
- <label className='checkbox'>
2323
- <input
2324
- type='checkbox'
2325
- checked={legend.singleRow}
2326
- onChange={event => {
2327
- handleEditorChanges('singleRowLegend', event.target.checked)
2328
- }}
2329
- />
2330
- <span className='edit-label'>Single Row Legend</span>
2331
- </label>
2332
- )}
2264
+ {'side' === legend.position && (
2265
+ <label className='checkbox'>
2266
+ <input
2267
+ type='checkbox'
2268
+ checked={legend.singleColumn}
2269
+ onChange={event => {
2270
+ handleEditorChanges('singleColumnLegend', event.target.checked)
2271
+ }}
2272
+ />
2273
+ <span className='edit-label'>Single Column Legend</span>
2274
+ </label>
2275
+ )}
2276
+ {'bottom' === legend.position && (
2277
+ <label className='checkbox'>
2278
+ <input
2279
+ type='checkbox'
2280
+ checked={legend.singleRow}
2281
+ onChange={event => {
2282
+ handleEditorChanges('singleRowLegend', event.target.checked)
2283
+ }}
2284
+ />
2285
+ <span className='edit-label'>Single Row Legend</span>
2286
+ </label>
2287
+ )}
2288
+ <label className='checkbox'>
2289
+ <input
2290
+ type='checkbox'
2291
+ checked={legend.verticalSorted}
2292
+ onChange={event => {
2293
+ handleEditorChanges('verticalSortedLegend', event.target.checked)
2294
+ }}
2295
+ />
2296
+ <span className='edit-label'>Vertical sorted legend</span>
2297
+ </label>
2298
+ {/* always show */}
2299
+ {
2300
+ <label className='checkbox'>
2301
+ <input
2302
+ type='checkbox'
2303
+ checked={legend.showSpecialClassesLast}
2304
+ onChange={event => {
2305
+ handleEditorChanges('legendShowSpecialClassesLast', event.target.checked)
2306
+ }}
2307
+ />
2308
+ <span className='edit-label'>Show Special Classes Last</span>
2309
+ </label>
2310
+ }
2311
+ {'category' !== legend.type && (
2312
+ <label className='checkbox'>
2313
+ <input type='checkbox' checked={legend.separateZero || false} onChange={event => handleEditorChanges('separateZero', event.target.checked)} />
2314
+ <span className='edit-label column-heading'>
2315
+ Separate Zero
2316
+ <Tooltip style={{ textTransform: 'none' }}>
2317
+ <Tooltip.Target>
2318
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2319
+ </Tooltip.Target>
2320
+ <Tooltip.Content>
2321
+ <p>For numeric data, you can separate the zero value as its own data class.</p>
2322
+ </Tooltip.Content>
2323
+ </Tooltip>
2324
+ </span>
2325
+ </label>
2326
+ )}
2327
+ {/* Temp Checkbox */}
2328
+ {state.legend.type === 'equalnumber' && (
2333
2329
  <label className='checkbox'>
2334
2330
  <input
2335
2331
  type='checkbox'
2336
- checked={legend.verticalSorted}
2332
+ checked={state.general.equalNumberOptIn}
2337
2333
  onChange={event => {
2338
- handleEditorChanges('verticalSortedLegend', event.target.checked)
2334
+ handleEditorChanges('showEqualNumber', event.target.checked)
2339
2335
  }}
2340
2336
  />
2341
- <span className='edit-label'>Vertical sorted legend</span>
2337
+ <span className='edit-label column-heading'>Use new quantile legend</span>
2338
+ <Tooltip style={{ textTransform: 'none' }}>
2339
+ <Tooltip.Target>
2340
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2341
+ </Tooltip.Target>
2342
+ <Tooltip.Content>
2343
+ <p>This prevents numbers from being used in more than one category (ie. 0-1, 1-2, 2-3) </p>
2344
+ </Tooltip.Content>
2345
+ </Tooltip>
2342
2346
  </label>
2343
- {/* always show */}
2344
- {
2345
- <label className='checkbox'>
2346
- <input
2347
- type='checkbox'
2348
- checked={legend.showSpecialClassesLast}
2349
- onChange={event => {
2350
- handleEditorChanges('legendShowSpecialClassesLast', event.target.checked)
2351
- }}
2352
- />
2353
- <span className='edit-label'>Show Special Classes Last</span>
2354
- </label>
2355
- }
2356
- {'category' !== legend.type && (
2357
- <label className='checkbox'>
2358
- <input type='checkbox' checked={legend.separateZero || false} onChange={event => handleEditorChanges('separateZero', event.target.checked)} />
2359
- <span className='edit-label column-heading'>
2360
- Separate Zero
2361
- <Tooltip style={{ textTransform: 'none' }}>
2362
- <Tooltip.Target>
2363
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2364
- </Tooltip.Target>
2365
- <Tooltip.Content>
2366
- <p>For numeric data, you can separate the zero value as its own data class.</p>
2367
- </Tooltip.Content>
2368
- </Tooltip>
2369
- </span>
2370
- </label>
2371
- )}
2372
- {/* Temp Checkbox */}
2373
- {state.legend.type === 'equalnumber' && (
2374
- <label className='checkbox'>
2375
- <input
2376
- type='checkbox'
2377
- checked={state.general.equalNumberOptIn}
2378
- onChange={event => {
2379
- handleEditorChanges('showEqualNumber', event.target.checked)
2380
- }}
2381
- />
2382
- <span className='edit-label column-heading'>Use new quantile legend</span>
2347
+ )}
2348
+ {'category' !== legend.type && (
2349
+ <label>
2350
+ <span className='edit-label'>
2351
+ Number of Items
2383
2352
  <Tooltip style={{ textTransform: 'none' }}>
2384
2353
  <Tooltip.Target>
2385
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2354
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2386
2355
  </Tooltip.Target>
2387
2356
  <Tooltip.Content>
2388
- <p>This prevents numbers from being used in more than one category (ie. 0-1, 1-2, 2-3) </p>
2357
+ <p>For numeric maps, select the number of data classes. Do not include designated special classes.</p>
2389
2358
  </Tooltip.Content>
2390
2359
  </Tooltip>
2391
- </label>
2392
- )}
2393
- {'category' !== legend.type && (
2360
+ </span>
2361
+ <select
2362
+ value={legend.numberOfItems}
2363
+ onChange={event => {
2364
+ handleEditorChanges('legendNumber', event.target.value)
2365
+ }}
2366
+ >
2367
+ {[...Array(numberOfItemsLimit).keys()].map(num => {
2368
+ return (
2369
+ <option value={num + 1} key={num + 1}>
2370
+ {num + 1}
2371
+ </option>
2372
+ )
2373
+ })}
2374
+ </select>
2375
+ </label>
2376
+ )}
2377
+ {'category' === legend.type && (
2378
+ <React.Fragment>
2394
2379
  <label>
2395
2380
  <span className='edit-label'>
2396
- Number of Items
2381
+ Category Order
2397
2382
  <Tooltip style={{ textTransform: 'none' }}>
2398
2383
  <Tooltip.Target>
2399
2384
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2400
2385
  </Tooltip.Target>
2401
2386
  <Tooltip.Content>
2402
- <p>For numeric maps, select the number of data classes. Do not include designated special classes.</p>
2387
+ <p>Drag map categories into preferred legend order. </p>
2403
2388
  </Tooltip.Content>
2404
2389
  </Tooltip>
2405
2390
  </span>
2391
+ </label>
2392
+ {/* 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. */}
2393
+ <DragDropContext onDragEnd={({ source, destination }) => categoryMove(source.index, destination.index)}>
2394
+ <Droppable droppableId='category_order'>
2395
+ {provided => (
2396
+ <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef}>
2397
+ <CategoryList />
2398
+ {provided.placeholder}
2399
+ </ul>
2400
+ )}
2401
+ </Droppable>
2402
+ </DragDropContext>
2403
+ {state.legend.categoryValuesOrder && state.legend.categoryValuesOrder.length >= 10 && (
2404
+ <section className='error-box my-2'>
2405
+ <div>
2406
+ <strong className='pt-1'>Warning</strong>
2407
+ <p>The maximum number of categorical legend items is 10. If your data has more than 10 categories your map will not display properly.</p>
2408
+ </div>
2409
+ </section>
2410
+ )}
2411
+ </React.Fragment>
2412
+ )}
2413
+ <TextField value={legend.title} updateField={updateField} section='legend' fieldName='title' label='Legend Title' placeholder='Legend Title' />
2414
+ {false === legend.dynamicDescription && <TextField type='textarea' value={legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />}
2415
+ {true === legend.dynamicDescription && (
2416
+ <React.Fragment>
2417
+ <label>
2418
+ <span>Legend Description</span>
2419
+ <span className='subtext'>For {displayFilterLegendValue(activeFilterValueForDescription)}</span>
2420
+ <DynamicDesc value={legend.descriptions[String(activeFilterValueForDescription)]} />
2421
+ </label>
2422
+ <label>
2406
2423
  <select
2407
- value={legend.numberOfItems}
2424
+ value={String(activeFilterValueForDescription)}
2408
2425
  onChange={event => {
2409
- handleEditorChanges('legendNumber', event.target.value)
2426
+ handleEditorChanges('changeActiveFilterValue', event.target.value)
2410
2427
  }}
2411
2428
  >
2412
- {[...Array(numberOfItemsLimit).keys()].map(num => {
2429
+ {filterValueOptionList.map((arr, i) => {
2413
2430
  return (
2414
- <option value={num + 1} key={num + 1}>
2415
- {num + 1}
2431
+ <option value={arr} key={i}>
2432
+ {displayFilterLegendValue(arr)}
2416
2433
  </option>
2417
2434
  )
2418
2435
  })}
2419
2436
  </select>
2420
2437
  </label>
2421
- )}
2422
- {'category' === legend.type && (
2423
- <React.Fragment>
2424
- <label>
2425
- <span className='edit-label'>
2426
- Category Order
2427
- <Tooltip style={{ textTransform: 'none' }}>
2428
- <Tooltip.Target>
2429
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2430
- </Tooltip.Target>
2431
- <Tooltip.Content>
2432
- <p>Drag map categories into preferred legend order. </p>
2433
- </Tooltip.Content>
2434
- </Tooltip>
2435
- </span>
2436
- </label>
2437
- {/* 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. */}
2438
- <DragDropContext onDragEnd={({ source, destination }) => categoryMove(source.index, destination.index)}>
2439
- <Droppable droppableId='category_order'>
2440
- {provided => (
2441
- <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef}>
2442
- <CategoryList />
2443
- {provided.placeholder}
2444
- </ul>
2445
- )}
2446
- </Droppable>
2447
- </DragDropContext>
2448
- {state.legend.categoryValuesOrder && state.legend.categoryValuesOrder.length >= 10 && (
2449
- <section className='error-box my-2'>
2450
- <div>
2451
- <strong className='pt-1'>Warning</strong>
2452
- <p>The maximum number of categorical legend items is 10. If your data has more than 10 categories your map will not display properly.</p>
2453
- </div>
2454
- </section>
2455
- )}
2456
- </React.Fragment>
2457
- )}
2458
- <TextField value={legend.title} updateField={updateField} section='legend' fieldName='title' label='Legend Title' placeholder='Legend Title' />
2459
- {false === legend.dynamicDescription && <TextField type='textarea' value={legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />}
2460
- {true === legend.dynamicDescription && (
2461
- <React.Fragment>
2462
- <label>
2463
- <span>Legend Description</span>
2464
- <span className='subtext'>For {displayFilterLegendValue(activeFilterValueForDescription)}</span>
2465
- <DynamicDesc value={legend.descriptions[String(activeFilterValueForDescription)]} />
2466
- </label>
2467
- <label>
2468
- <select
2469
- value={String(activeFilterValueForDescription)}
2470
- onChange={event => {
2471
- handleEditorChanges('changeActiveFilterValue', event.target.value)
2472
- }}
2473
- >
2474
- {filterValueOptionList.map((arr, i) => {
2475
- return (
2476
- <option value={arr} key={i}>
2477
- {displayFilterLegendValue(arr)}
2478
- </option>
2479
- )
2480
- })}
2481
- </select>
2482
- </label>
2483
- </React.Fragment>
2484
- )}
2485
- {filtersJSX.length > 0 && (
2486
- <label className='checkbox'>
2487
- <input
2488
- type='checkbox'
2489
- checked={legend.dynamicDescription}
2490
- onChange={() => {
2491
- handleEditorChanges('dynamicDescription', filterValueOptionList[0])
2492
- }}
2493
- />
2494
- <span className='edit-label column-heading'>
2495
- Dynamic Legend Description
2496
- <Tooltip style={{ textTransform: 'none' }}>
2497
- <Tooltip.Target>
2498
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2499
- </Tooltip.Target>
2500
- <Tooltip.Content>
2501
- <p>Check this option if the map has multiple filter controls and you want to specify a description for each filter selection.</p>
2502
- </Tooltip.Content>
2503
- </Tooltip>
2504
- </span>
2505
- </label>
2506
- )}
2507
- {(filtersJSX.length > 0 || state.general.type === 'bubble' || state.general.geoType === 'us') && (
2508
- <label className='checkbox'>
2509
- <input type='checkbox' checked={legend.unified} onChange={event => handleEditorChanges('unifiedLegend', event.target.checked)} />
2510
- <span className='edit-label column-heading'>
2511
- Unified Legend
2512
- <Tooltip style={{ textTransform: 'none' }}>
2513
- <Tooltip.Target>
2514
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2515
- </Tooltip.Target>
2516
- <Tooltip.Content>
2517
- <p>
2518
- 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.
2519
- </p>
2520
- </Tooltip.Content>
2521
- </Tooltip>
2522
- </span>
2523
- </label>
2524
- )}
2525
- </AccordionItemPanel>
2526
- </AccordionItem>
2527
- )}
2528
- {'navigation' !== state.general.type && (
2529
- <AccordionItem>
2530
- {' '}
2531
- {/* Filters */}
2532
- <AccordionItemHeading>
2533
- <AccordionItemButton>Filters</AccordionItemButton>
2534
- </AccordionItemHeading>
2535
- <AccordionItemPanel>
2536
- {filtersJSX.length > 0 ? <MapFilters /> : <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2537
- <button
2538
- className={'btn full-width'}
2539
- onClick={event => {
2540
- event.preventDefault()
2541
- changeFilter(null, 'addNew')
2542
- }}
2543
- >
2544
- Add Filter
2545
- </button>
2546
- </AccordionItemPanel>
2547
- </AccordionItem>
2548
- )}
2549
- {'navigation' !== state.general.type && (
2550
- <AccordionItem>
2551
- {' '}
2552
- {/* Data Table */}
2553
- <AccordionItemHeading>
2554
- <AccordionItemButton>Data Table</AccordionItemButton>
2555
- </AccordionItemHeading>
2556
- <AccordionItemPanel>
2557
- <TextField
2558
- value={table.label}
2559
- updateField={updateField}
2560
- section='table'
2561
- fieldName='label'
2562
- id='dataTableTitle'
2563
- label='Data Table Title'
2564
- placeholder='Data Table'
2565
- tooltip={
2566
- <Tooltip style={{ textTransform: 'none' }}>
2567
- <Tooltip.Target>
2568
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2569
- </Tooltip.Target>
2570
- <Tooltip.Content>
2571
- <p>Label is required for Data Table for 508 Compliance</p>
2572
- </Tooltip.Content>
2573
- </Tooltip>
2574
- }
2575
- />
2576
- <label className='checkbox'>
2577
- <input
2578
- type='checkbox'
2579
- checked={state.table.wrapColumns}
2580
- onChange={event => {
2581
- setState({
2582
- ...state,
2583
- table: {
2584
- ...state.table,
2585
- wrapColumns: event.target.checked
2586
- }
2587
- })
2588
- }}
2589
- />
2590
- <span className='edit-label column-heading'>WRAP DATA TABLE COLUMNS</span>
2591
- </label>
2438
+ </React.Fragment>
2439
+ )}
2440
+ {filtersJSX.length > 0 && (
2592
2441
  <label className='checkbox'>
2593
2442
  <input
2594
2443
  type='checkbox'
2595
- checked={state.table.forceDisplay !== undefined ? state.table.forceDisplay : !isDashboard}
2596
- onChange={event => {
2597
- handleEditorChanges('showDataTable', event.target.checked)
2444
+ checked={legend.dynamicDescription}
2445
+ onChange={() => {
2446
+ handleEditorChanges('dynamicDescription', filterValueOptionList[0])
2598
2447
  }}
2599
2448
  />
2600
2449
  <span className='edit-label column-heading'>
2601
- Show Data Table
2450
+ Dynamic Legend Description
2602
2451
  <Tooltip style={{ textTransform: 'none' }}>
2603
2452
  <Tooltip.Target>
2604
2453
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2605
2454
  </Tooltip.Target>
2606
2455
  <Tooltip.Content>
2607
- <p>Data tables are required for 508 compliance. When choosing to hide this data table, replace with your own version.</p>
2456
+ <p>Check this option if the map has multiple filter controls and you want to specify a description for each filter selection.</p>
2608
2457
  </Tooltip.Content>
2609
2458
  </Tooltip>
2610
2459
  </span>
2611
2460
  </label>
2612
- <TextField
2613
- value={table.indexLabel || ''}
2614
- updateField={updateField}
2615
- section='table'
2616
- fieldName='indexLabel'
2617
- label='Index Column Header'
2618
- placeholder='Location'
2619
- tooltip={
2620
- <Tooltip style={{ textTransform: 'none' }}>
2621
- <Tooltip.Target>
2622
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2623
- </Tooltip.Target>
2624
- <Tooltip.Content>
2625
- <p>To comply with 508 standards, if the first column in the data table has no header, enter a brief one here.</p>
2626
- </Tooltip.Content>
2627
- </Tooltip>
2628
- }
2629
- />
2630
- <TextField
2631
- value={state.table.caption}
2632
- updateField={updateField}
2633
- section='table'
2634
- fieldName='caption'
2635
- label='Screen Reader Description'
2636
- placeholder='Data Table'
2637
- tooltip={
2461
+ )}
2462
+ {(filtersJSX.length > 0 || state.general.type === 'bubble' || state.general.geoType === 'us') && (
2463
+ <label className='checkbox'>
2464
+ <input type='checkbox' checked={legend.unified} onChange={event => handleEditorChanges('unifiedLegend', event.target.checked)} />
2465
+ <span className='edit-label column-heading'>
2466
+ Unified Legend
2638
2467
  <Tooltip style={{ textTransform: 'none' }}>
2639
2468
  <Tooltip.Target>
2640
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2469
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2641
2470
  </Tooltip.Target>
2642
2471
  <Tooltip.Content>
2643
- <p>Enter a description of the data table to be read by screen readers.</p>
2472
+ <p>
2473
+ 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.
2474
+ </p>
2644
2475
  </Tooltip.Content>
2645
2476
  </Tooltip>
2646
- }
2647
- type='textarea'
2648
- />
2649
- <label className='checkbox'>
2650
- <input
2651
- type='checkbox'
2652
- checked={state.table.limitHeight}
2653
- onChange={event => {
2654
- handleEditorChanges('limitDataTableHeight', event.target.checked)
2655
- }}
2656
- />
2657
- <span className='edit-label'>Limit Table Height</span>
2658
- </label>
2659
- {state.table.limitHeight && <TextField value={table.height} updateField={updateField} section='table' fieldName='height' label='Data Table Height' placeholder='Height(px)' type='number' min='0' max='500' />}
2660
- <label className='checkbox'>
2661
- <input
2662
- type='checkbox'
2663
- checked={state.table.expanded || false}
2664
- onChange={event => {
2665
- handleEditorChanges('expandDataTable', event.target.checked)
2666
- }}
2667
- />
2668
- <span className='edit-label'>Map loads with data table expanded</span>
2669
- </label>
2670
- {isDashboard && (
2671
- <label className='checkbox'>
2672
- <input
2673
- type='checkbox'
2674
- checked={state.table.showDataTableLink}
2675
- onChange={event => {
2676
- handleEditorChanges('toggleDataTableLink', event.target.checked)
2677
- }}
2678
- />
2679
- <span className='edit-label'>Show Data Table Name & Link</span>
2680
- </label>
2681
- )}
2682
- {isLoadedFromUrl && (
2683
- <label className='checkbox'>
2684
- <input
2685
- type='checkbox'
2686
- checked={state.table.showDownloadUrl}
2687
- onChange={event => {
2688
- handleEditorChanges('toggleDataUrl', event.target.checked)
2689
- }}
2690
- />
2691
- <span className='edit-label'>Show URL to Automatically Updated Data</span>
2692
- </label>
2693
- )}
2694
- <label className='checkbox'>
2695
- <input
2696
- type='checkbox'
2697
- checked={state.general.showFullGeoNameInCSV}
2698
- onChange={event => {
2699
- handleEditorChanges('toggleShowFullGeoNameInCSV', event.target.checked)
2700
- }}
2701
- />
2702
- <span className='edit-label'>Include Full Geo Name in CSV Download</span>
2703
- </label>
2704
- <label className='checkbox'>
2705
- <input
2706
- type='checkbox'
2707
- checked={state.general.showDownloadImgButton}
2708
- onChange={event => {
2709
- handleEditorChanges('toggleDownloadImgButton', event.target.checked)
2710
- }}
2711
- />
2712
- <span className='edit-label'>Enable Image Download</span>
2477
+ </span>
2713
2478
  </label>
2714
- {/* <label className='checkbox'>
2715
- <input
2716
- type='checkbox'
2717
- checked={state.general.showDownloadPdfButton}
2718
- onChange={event => {
2719
- handleEditorChanges('toggleDownloadPdfButton', event.target.checked)
2720
- }}
2721
- />
2722
- <span className='edit-label'>Enable Pdf Download</span>
2723
- </label> */}
2724
- </AccordionItemPanel>
2725
- </AccordionItem>
2726
- )}
2479
+ )}
2480
+ </AccordionItemPanel>
2481
+ </AccordionItem>
2482
+ )}
2483
+ {'navigation' !== state.general.type && (
2727
2484
  <AccordionItem>
2728
2485
  {' '}
2729
- {/* Tooltips */}
2486
+ {/* Filters */}
2730
2487
  <AccordionItemHeading>
2731
- <AccordionItemButton>Interactivity</AccordionItemButton>
2488
+ <AccordionItemButton>Filters</AccordionItemButton>
2732
2489
  </AccordionItemHeading>
2733
2490
  <AccordionItemPanel>
2734
- <label>
2735
- <span className='edit-label'>
2736
- Detail displays on{' '}
2491
+ {filtersJSX.length > 0 ? <MapFilters /> : <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2492
+ <button
2493
+ className={'btn full-width'}
2494
+ onClick={event => {
2495
+ event.preventDefault()
2496
+ changeFilter(null, 'addNew')
2497
+ }}
2498
+ >
2499
+ Add Filter
2500
+ </button>
2501
+ </AccordionItemPanel>
2502
+ </AccordionItem>
2503
+ )}
2504
+ {'navigation' !== state.general.type && (
2505
+ <AccordionItem>
2506
+ {' '}
2507
+ {/* Data Table */}
2508
+ <AccordionItemHeading>
2509
+ <AccordionItemButton>Data Table</AccordionItemButton>
2510
+ </AccordionItemHeading>
2511
+ <AccordionItemPanel>
2512
+ <TextField
2513
+ value={table.label}
2514
+ updateField={updateField}
2515
+ section='table'
2516
+ fieldName='label'
2517
+ id='dataTableTitle'
2518
+ label='Data Table Title'
2519
+ placeholder='Data Table'
2520
+ tooltip={
2737
2521
  <Tooltip style={{ textTransform: 'none' }}>
2738
2522
  <Tooltip.Target>
2739
2523
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2740
2524
  </Tooltip.Target>
2741
2525
  <Tooltip.Content>
2742
- <p>At mobile sizes, information always appears in a popover modal when a user taps on an item.</p>
2526
+ <p>Label is required for Data Table for 508 Compliance</p>
2743
2527
  </Tooltip.Content>
2744
2528
  </Tooltip>
2745
- </span>
2746
- <select
2747
- value={state.tooltips.appearanceType}
2529
+ }
2530
+ />
2531
+ <label className='checkbox'>
2532
+ <input
2533
+ type='checkbox'
2534
+ checked={state.table.wrapColumns}
2748
2535
  onChange={event => {
2749
- handleEditorChanges('appearanceType', event.target.value)
2536
+ setState({
2537
+ ...state,
2538
+ table: {
2539
+ ...state.table,
2540
+ wrapColumns: event.target.checked
2541
+ }
2542
+ })
2750
2543
  }}
2751
- >
2752
- <option value='hover'>Hover - Tooltip</option>
2753
- <option value='click'>Click - Popover Modal</option>
2754
- </select>
2544
+ />
2545
+ <span className='edit-label column-heading'>WRAP DATA TABLE COLUMNS</span>
2755
2546
  </label>
2756
- {'click' === state.tooltips.appearanceType && <TextField value={tooltips.linkLabel} section='tooltips' fieldName='linkLabel' label='Tooltips Link Label' updateField={updateField} />}
2757
2547
  <label className='checkbox'>
2758
2548
  <input
2759
2549
  type='checkbox'
2760
- checked={state.tooltips.capitalizeLabels}
2550
+ checked={state.table.forceDisplay !== undefined ? state.table.forceDisplay : !isDashboard}
2761
2551
  onChange={event => {
2762
- handleEditorChanges('capitalizeLabels', event.target.checked)
2552
+ handleEditorChanges('showDataTable', event.target.checked)
2763
2553
  }}
2764
2554
  />
2765
- <span className='edit-label'>Capitalize text inside tooltip</span>
2555
+ <span className='edit-label column-heading'>
2556
+ Show Data Table
2557
+ <Tooltip style={{ textTransform: 'none' }}>
2558
+ <Tooltip.Target>
2559
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2560
+ </Tooltip.Target>
2561
+ <Tooltip.Content>
2562
+ <p>Data tables are required for 508 compliance. When choosing to hide this data table, replace with your own version.</p>
2563
+ </Tooltip.Content>
2564
+ </Tooltip>
2565
+ </span>
2766
2566
  </label>
2767
- </AccordionItemPanel>
2768
- </AccordionItem>
2769
- <AccordionItem>
2770
- {' '}
2771
- {/* Visual */}
2772
- <AccordionItemHeading>
2773
- <AccordionItemButton>Visual</AccordionItemButton>
2774
- </AccordionItemHeading>
2775
- <AccordionItemPanel>
2776
- <label>
2777
- <span className='edit-label'>Header Theme</span>
2778
- <ul className='color-palette'>
2779
- {headerColors.map(palette => {
2780
- return (
2781
- <li
2782
- title={palette}
2783
- key={palette}
2784
- onClick={() => {
2785
- handleEditorChanges('headerColor', palette)
2786
- }}
2787
- className={state.general.headerColor === palette ? 'selected ' + palette : palette}
2788
- ></li>
2789
- )
2790
- })}
2791
- </ul>
2567
+ <TextField
2568
+ value={table.indexLabel || ''}
2569
+ updateField={updateField}
2570
+ section='table'
2571
+ fieldName='indexLabel'
2572
+ label='Index Column Header'
2573
+ placeholder='Location'
2574
+ tooltip={
2575
+ <Tooltip style={{ textTransform: 'none' }}>
2576
+ <Tooltip.Target>
2577
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2578
+ </Tooltip.Target>
2579
+ <Tooltip.Content>
2580
+ <p>To comply with 508 standards, if the first column in the data table has no header, enter a brief one here.</p>
2581
+ </Tooltip.Content>
2582
+ </Tooltip>
2583
+ }
2584
+ />
2585
+ <TextField
2586
+ value={state.table.caption}
2587
+ updateField={updateField}
2588
+ section='table'
2589
+ fieldName='caption'
2590
+ label='Screen Reader Description'
2591
+ placeholder='Data Table'
2592
+ tooltip={
2593
+ <Tooltip style={{ textTransform: 'none' }}>
2594
+ <Tooltip.Target>
2595
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2596
+ </Tooltip.Target>
2597
+ <Tooltip.Content>
2598
+ <p>Enter a description of the data table to be read by screen readers.</p>
2599
+ </Tooltip.Content>
2600
+ </Tooltip>
2601
+ }
2602
+ type='textarea'
2603
+ />
2604
+ <label className='checkbox'>
2605
+ <input
2606
+ type='checkbox'
2607
+ checked={state.table.limitHeight}
2608
+ onChange={event => {
2609
+ handleEditorChanges('limitDataTableHeight', event.target.checked)
2610
+ }}
2611
+ />
2612
+ <span className='edit-label'>Limit Table Height</span>
2792
2613
  </label>
2614
+ {state.table.limitHeight && <TextField value={table.height} updateField={updateField} section='table' fieldName='height' label='Data Table Height' placeholder='Height(px)' type='number' min='0' max='500' />}
2793
2615
  <label className='checkbox'>
2794
2616
  <input
2795
2617
  type='checkbox'
2796
- checked={state.general.showTitle || false}
2618
+ checked={state.table.expanded || false}
2797
2619
  onChange={event => {
2798
- handleEditorChanges('showTitle', event.target.checked)
2620
+ handleEditorChanges('expandDataTable', event.target.checked)
2799
2621
  }}
2800
2622
  />
2801
- <span className='edit-label'>Show Title</span>
2623
+ <span className='edit-label'>Map loads with data table expanded</span>
2802
2624
  </label>
2803
-
2804
- {'navigation' === state.general.type && (
2625
+ {isDashboard && (
2805
2626
  <label className='checkbox'>
2806
2627
  <input
2807
2628
  type='checkbox'
2808
- checked={state.general.fullBorder || false}
2629
+ checked={state.table.showDataTableLink}
2809
2630
  onChange={event => {
2810
- handleEditorChanges('fullBorder', event.target.checked)
2631
+ handleEditorChanges('toggleDataTableLink', event.target.checked)
2811
2632
  }}
2812
2633
  />
2813
- <span className='edit-label'>Add border around map</span>
2634
+ <span className='edit-label'>Show Data Table Name & Link</span>
2814
2635
  </label>
2815
2636
  )}
2816
- <label>
2817
- <span className='edit-label'>Geo Border Color</span>
2818
- <select
2819
- value={state.general.geoBorderColor || false}
2637
+ {isLoadedFromUrl && (
2638
+ <label className='checkbox'>
2639
+ <input
2640
+ type='checkbox'
2641
+ checked={state.table.showDownloadUrl}
2642
+ onChange={event => {
2643
+ handleEditorChanges('toggleDataUrl', event.target.checked)
2644
+ }}
2645
+ />
2646
+ <span className='edit-label'>Show URL to Automatically Updated Data</span>
2647
+ </label>
2648
+ )}
2649
+ <label className='checkbox'>
2650
+ <input
2651
+ type='checkbox'
2652
+ checked={state.general.showFullGeoNameInCSV}
2820
2653
  onChange={event => {
2821
- handleEditorChanges('geoBorderColor', event.target.value)
2654
+ handleEditorChanges('toggleShowFullGeoNameInCSV', event.target.checked)
2822
2655
  }}
2823
- >
2824
- <option value='darkGray'>Dark Gray (Default)</option>
2825
- <option value='sameAsBackground'>White</option>
2826
- </select>
2656
+ />
2657
+ <span className='edit-label'>Include Full Geo Name in CSV Download</span>
2827
2658
  </label>
2828
- <label>
2829
- <span className='edit-label'>Map Color Palette</span>
2659
+ <label className='checkbox'>
2660
+ <input
2661
+ type='checkbox'
2662
+ checked={state.general.showDownloadImgButton}
2663
+ onChange={event => {
2664
+ handleEditorChanges('toggleDownloadImgButton', event.target.checked)
2665
+ }}
2666
+ />
2667
+ <span className='edit-label'>Enable Image Download</span>
2830
2668
  </label>
2831
- {/* <InputCheckbox section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
2832
- <InputToggle type='3d' section='general' subsection='palette' fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={state.general.palette.isReversed} />
2833
- <span>Sequential</span>
2669
+ {/* <label className='checkbox'>
2670
+ <input
2671
+ type='checkbox'
2672
+ checked={state.general.showDownloadPdfButton}
2673
+ onChange={event => {
2674
+ handleEditorChanges('toggleDownloadPdfButton', event.target.checked)
2675
+ }}
2676
+ />
2677
+ <span className='edit-label'>Enable Pdf Download</span>
2678
+ </label> */}
2679
+ </AccordionItemPanel>
2680
+ </AccordionItem>
2681
+ )}
2682
+ <AccordionItem>
2683
+ {' '}
2684
+ {/* Tooltips */}
2685
+ <AccordionItemHeading>
2686
+ <AccordionItemButton>Interactivity</AccordionItemButton>
2687
+ </AccordionItemHeading>
2688
+ <AccordionItemPanel>
2689
+ <label>
2690
+ <span className='edit-label'>
2691
+ Detail displays on{' '}
2692
+ <Tooltip style={{ textTransform: 'none' }}>
2693
+ <Tooltip.Target>
2694
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2695
+ </Tooltip.Target>
2696
+ <Tooltip.Content>
2697
+ <p>At mobile sizes, information always appears in a popover modal when a user taps on an item.</p>
2698
+ </Tooltip.Content>
2699
+ </Tooltip>
2700
+ </span>
2701
+ <select
2702
+ value={state.tooltips.appearanceType}
2703
+ onChange={event => {
2704
+ handleEditorChanges('appearanceType', event.target.value)
2705
+ }}
2706
+ >
2707
+ <option value='hover'>Hover - Tooltip</option>
2708
+ <option value='click'>Click - Popover Modal</option>
2709
+ </select>
2710
+ </label>
2711
+ {'click' === state.tooltips.appearanceType && <TextField value={tooltips.linkLabel} section='tooltips' fieldName='linkLabel' label='Tooltips Link Label' updateField={updateField} />}
2712
+ <label className='checkbox'>
2713
+ <input
2714
+ type='checkbox'
2715
+ checked={state.tooltips.capitalizeLabels}
2716
+ onChange={event => {
2717
+ handleEditorChanges('capitalizeLabels', event.target.checked)
2718
+ }}
2719
+ />
2720
+ <span className='edit-label'>Capitalize text inside tooltip</span>
2721
+ </label>
2722
+ </AccordionItemPanel>
2723
+ </AccordionItem>
2724
+ <AccordionItem>
2725
+ {' '}
2726
+ {/* Visual */}
2727
+ <AccordionItemHeading>
2728
+ <AccordionItemButton>Visual</AccordionItemButton>
2729
+ </AccordionItemHeading>
2730
+ <AccordionItemPanel>
2731
+ <label>
2732
+ <span className='edit-label'>Header Theme</span>
2834
2733
  <ul className='color-palette'>
2835
- {sequential.map(palette => {
2836
- const colorOne = {
2837
- backgroundColor: colorPalettes[palette][2]
2838
- }
2839
-
2840
- const colorTwo = {
2841
- backgroundColor: colorPalettes[palette][4]
2842
- }
2843
-
2844
- const colorThree = {
2845
- backgroundColor: colorPalettes[palette][6]
2846
- }
2847
-
2734
+ {headerColors.map(palette => {
2848
2735
  return (
2849
2736
  <li
2850
2737
  title={palette}
2851
2738
  key={palette}
2852
2739
  onClick={() => {
2853
- handleEditorChanges('color', palette)
2740
+ handleEditorChanges('headerColor', palette)
2854
2741
  }}
2855
- className={state.color === palette ? 'selected' : ''}
2856
- >
2857
- <span style={colorOne}></span>
2858
- <span style={colorTwo}></span>
2859
- <span style={colorThree}></span>
2860
- </li>
2742
+ className={state.general.headerColor === palette ? 'selected ' + palette : palette}
2743
+ ></li>
2861
2744
  )
2862
2745
  })}
2863
2746
  </ul>
2864
- <span>Non-Sequential</span>
2865
- <ul className='color-palette'>
2866
- {nonSequential.map(palette => {
2867
- const colorOne = {
2868
- backgroundColor: colorPalettes[palette][2]
2869
- }
2747
+ </label>
2748
+ <label className='checkbox'>
2749
+ <input
2750
+ type='checkbox'
2751
+ checked={state.general.showTitle || false}
2752
+ onChange={event => {
2753
+ handleEditorChanges('showTitle', event.target.checked)
2754
+ }}
2755
+ />
2756
+ <span className='edit-label'>Show Title</span>
2757
+ </label>
2870
2758
 
2871
- const colorTwo = {
2872
- backgroundColor: colorPalettes[palette][4]
2873
- }
2759
+ {'navigation' === state.general.type && (
2760
+ <label className='checkbox'>
2761
+ <input
2762
+ type='checkbox'
2763
+ checked={state.general.fullBorder || false}
2764
+ onChange={event => {
2765
+ handleEditorChanges('fullBorder', event.target.checked)
2766
+ }}
2767
+ />
2768
+ <span className='edit-label'>Add border around map</span>
2769
+ </label>
2770
+ )}
2771
+ <label>
2772
+ <span className='edit-label'>Geo Border Color</span>
2773
+ <select
2774
+ value={state.general.geoBorderColor || false}
2775
+ onChange={event => {
2776
+ handleEditorChanges('geoBorderColor', event.target.value)
2777
+ }}
2778
+ >
2779
+ <option value='darkGray'>Dark Gray (Default)</option>
2780
+ <option value='sameAsBackground'>White</option>
2781
+ </select>
2782
+ </label>
2783
+ <label>
2784
+ <span className='edit-label'>Map Color Palette</span>
2785
+ </label>
2786
+ {/* <InputCheckbox section="general" subsection="palette" fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
2787
+ <InputToggle type='3d' section='general' subsection='palette' fieldName='isReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={state.general.palette.isReversed} />
2788
+ <span>Sequential</span>
2789
+ <ul className='color-palette'>
2790
+ {sequential.map(palette => {
2791
+ const colorOne = {
2792
+ backgroundColor: colorPalettes[palette][2]
2793
+ }
2874
2794
 
2875
- const colorThree = {
2876
- backgroundColor: colorPalettes[palette][6]
2877
- }
2795
+ const colorTwo = {
2796
+ backgroundColor: colorPalettes[palette][4]
2797
+ }
2878
2798
 
2879
- // hide palettes with too few colors for region maps
2880
- if (colorPalettes[palette].length <= 8 && state.general.geoType === 'us-region') {
2881
- return ''
2882
- }
2883
- return (
2884
- <li
2885
- title={palette}
2886
- key={palette}
2887
- onClick={() => {
2888
- handleEditorChanges('color', palette)
2889
- }}
2890
- className={state.color === palette ? 'selected' : ''}
2891
- >
2892
- <span style={colorOne}></span>
2893
- <span style={colorTwo}></span>
2894
- <span style={colorThree}></span>
2895
- </li>
2896
- )
2897
- })}
2898
- </ul>
2899
- <label>
2900
- Geocode Settings
2901
- <TextField type='number' value={state.visual.geoCodeCircleSize} section='visual' max='10' fieldName='geoCodeCircleSize' label='Geocode Circle Size' updateField={updateField} />
2902
- </label>
2799
+ const colorThree = {
2800
+ backgroundColor: colorPalettes[palette][6]
2801
+ }
2903
2802
 
2904
- {state.general.type === 'bubble' && (
2905
- <>
2906
- <TextField type='number' value={state.visual.minBubbleSize} section='visual' fieldName='minBubbleSize' label='Minimum Bubble Size' updateField={updateField} />
2907
- <TextField type='number' value={state.visual.maxBubbleSize} section='visual' fieldName='maxBubbleSize' label='Maximum Bubble Size' updateField={updateField} />
2908
- </>
2909
- )}
2910
- {(state.general.geoType === 'world' || (state.general.geoType === 'us' && state.general.type === 'bubble')) && (
2911
- <label className='checkbox'>
2912
- <input
2913
- type='checkbox'
2914
- checked={state.visual.showBubbleZeros}
2915
- onChange={event => {
2916
- handleEditorChanges('showBubbleZeros', event.target.checked)
2803
+ return (
2804
+ <li
2805
+ title={palette}
2806
+ key={palette}
2807
+ onClick={() => {
2808
+ handleEditorChanges('color', palette)
2917
2809
  }}
2918
- />
2919
- <span className='edit-label'>Show Data with Zero's on Bubble Map</span>
2920
- </label>
2921
- )}
2922
- {state.general.geoType === 'world' && (
2923
- <label className='checkbox'>
2924
- <input
2925
- type='checkbox'
2926
- checked={state.general.allowMapZoom}
2927
- onChange={event => {
2928
- handleEditorChanges('allowMapZoom', event.target.checked)
2810
+ className={state.color === palette ? 'selected' : ''}
2811
+ >
2812
+ <span style={colorOne}></span>
2813
+ <span style={colorTwo}></span>
2814
+ <span style={colorThree}></span>
2815
+ </li>
2816
+ )
2817
+ })}
2818
+ </ul>
2819
+ <span>Non-Sequential</span>
2820
+ <ul className='color-palette'>
2821
+ {nonSequential.map(palette => {
2822
+ const colorOne = {
2823
+ backgroundColor: colorPalettes[palette][2]
2824
+ }
2825
+
2826
+ const colorTwo = {
2827
+ backgroundColor: colorPalettes[palette][4]
2828
+ }
2829
+
2830
+ const colorThree = {
2831
+ backgroundColor: colorPalettes[palette][6]
2832
+ }
2833
+
2834
+ // hide palettes with too few colors for region maps
2835
+ if (colorPalettes[palette].length <= 8 && state.general.geoType === 'us-region') {
2836
+ return ''
2837
+ }
2838
+ return (
2839
+ <li
2840
+ title={palette}
2841
+ key={palette}
2842
+ onClick={() => {
2843
+ handleEditorChanges('color', palette)
2929
2844
  }}
2930
- />
2931
- <span className='edit-label'>Allow Map Zooming</span>
2932
- </label>
2933
- )}
2934
- {state.general.type === 'bubble' && (
2935
- <label className='checkbox'>
2936
- <input
2937
- type='checkbox'
2938
- checked={state.visual.extraBubbleBorder}
2845
+ className={state.color === palette ? 'selected' : ''}
2846
+ >
2847
+ <span style={colorOne}></span>
2848
+ <span style={colorTwo}></span>
2849
+ <span style={colorThree}></span>
2850
+ </li>
2851
+ )
2852
+ })}
2853
+ </ul>
2854
+ <label>
2855
+ Geocode Settings
2856
+ <TextField type='number' value={state.visual.geoCodeCircleSize} section='visual' max='10' fieldName='geoCodeCircleSize' label='Geocode Circle Size' updateField={updateField} />
2857
+ </label>
2858
+
2859
+ {state.general.type === 'bubble' && (
2860
+ <>
2861
+ <TextField type='number' value={state.visual.minBubbleSize} section='visual' fieldName='minBubbleSize' label='Minimum Bubble Size' updateField={updateField} />
2862
+ <TextField type='number' value={state.visual.maxBubbleSize} section='visual' fieldName='maxBubbleSize' label='Maximum Bubble Size' updateField={updateField} />
2863
+ </>
2864
+ )}
2865
+ {(state.general.geoType === 'world' || (state.general.geoType === 'us' && state.general.type === 'bubble')) && (
2866
+ <label className='checkbox'>
2867
+ <input
2868
+ type='checkbox'
2869
+ checked={state.visual.showBubbleZeros}
2870
+ onChange={event => {
2871
+ handleEditorChanges('showBubbleZeros', event.target.checked)
2872
+ }}
2873
+ />
2874
+ <span className='edit-label'>Show Data with Zero's on Bubble Map</span>
2875
+ </label>
2876
+ )}
2877
+ {state.general.geoType === 'world' && (
2878
+ <label className='checkbox'>
2879
+ <input
2880
+ type='checkbox'
2881
+ checked={state.general.allowMapZoom}
2882
+ onChange={event => {
2883
+ handleEditorChanges('allowMapZoom', event.target.checked)
2884
+ }}
2885
+ />
2886
+ <span className='edit-label'>Allow Map Zooming</span>
2887
+ </label>
2888
+ )}
2889
+ {state.general.type === 'bubble' && (
2890
+ <label className='checkbox'>
2891
+ <input
2892
+ type='checkbox'
2893
+ checked={state.visual.extraBubbleBorder}
2894
+ onChange={event => {
2895
+ handleEditorChanges('toggleExtraBubbleBorder', event.target.checked)
2896
+ }}
2897
+ />
2898
+ <span className='edit-label'>Bubble Map has extra border</span>
2899
+ </label>
2900
+ )}
2901
+ {(state.general.geoType === 'us' || state.general.geoType === 'us-county' || state.general.geoType === 'world') && (
2902
+ <>
2903
+ <label>
2904
+ <span className='edit-label'>Default City Style</span>
2905
+ <select
2906
+ value={state.visual.cityStyle || false}
2939
2907
  onChange={event => {
2940
- handleEditorChanges('toggleExtraBubbleBorder', event.target.checked)
2908
+ handleEditorChanges('handleCityStyle', event.target.value)
2941
2909
  }}
2942
- />
2943
- <span className='edit-label'>Bubble Map has extra border</span>
2910
+ >
2911
+ <option value='circle'>Circle</option>
2912
+ <option value='pin'>Pin</option>
2913
+ <option value='square'>Square</option>
2914
+ <option value='triangle'>Triangle</option>
2915
+ <option value='diamond'>Diamond</option>
2916
+ <option value='star'>Star</option>
2917
+ </select>
2944
2918
  </label>
2945
- )}
2946
- {(state.general.geoType === 'us' || state.general.geoType === 'us-county' || state.general.geoType === 'world') && (
2947
- <>
2948
- <label>
2949
- <span className='edit-label'>Default City Style</span>
2950
- <select
2951
- value={state.visual.cityStyle || false}
2952
- onChange={event => {
2953
- handleEditorChanges('handleCityStyle', event.target.value)
2954
- }}
2955
- >
2956
- <option value='circle'>Circle</option>
2957
- <option value='pin'>Pin</option>
2958
- <option value='square'>Square</option>
2959
- <option value='triangle'>Triangle</option>
2960
- <option value='diamond'>Diamond</option>
2961
- <option value='star'>Star</option>
2962
- </select>
2963
- </label>
2964
- <TextField
2965
- value={state.visual.cityStyleLabel}
2966
- section='visual'
2967
- fieldName='cityStyleLabel'
2968
- label='Label (Optional) '
2969
- updateField={updateField}
2970
- tooltip={
2971
- <Tooltip style={{ textTransform: 'none' }}>
2972
- <Tooltip.Target>
2973
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2974
- </Tooltip.Target>
2975
- <Tooltip.Content>
2976
- <p>When a label is provided, the default city style will appear in the legend.</p>
2977
- </Tooltip.Content>
2978
- </Tooltip>
2979
- }
2980
- />
2981
- </>
2982
- )}
2983
- {/* <AdditionalCityStyles /> */}
2984
- <>
2985
- {state.visual.additionalCityStyles.length > 0 &&
2986
- state.visual.additionalCityStyles.map(({ label, column, value, shape }, i) => {
2987
- return (
2988
- <div className='edit-block' key={`additional-city-style-${i}`}>
2989
- <button
2990
- className='remove-column'
2991
- onClick={e => {
2992
- e.preventDefault()
2993
- editCityStyles('remove', i, '', '')
2919
+ <TextField
2920
+ value={state.visual.cityStyleLabel}
2921
+ section='visual'
2922
+ fieldName='cityStyleLabel'
2923
+ label='Label (Optional) '
2924
+ updateField={updateField}
2925
+ tooltip={
2926
+ <Tooltip style={{ textTransform: 'none' }}>
2927
+ <Tooltip.Target>
2928
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2929
+ </Tooltip.Target>
2930
+ <Tooltip.Content>
2931
+ <p>When a label is provided, the default city style will appear in the legend.</p>
2932
+ </Tooltip.Content>
2933
+ </Tooltip>
2934
+ }
2935
+ />
2936
+ </>
2937
+ )}
2938
+ {/* <AdditionalCityStyles /> */}
2939
+ <>
2940
+ {state.visual.additionalCityStyles.length > 0 &&
2941
+ state.visual.additionalCityStyles.map(({ label, column, value, shape }, i) => {
2942
+ return (
2943
+ <div className='edit-block' key={`additional-city-style-${i}`}>
2944
+ <button
2945
+ className='remove-column'
2946
+ onClick={e => {
2947
+ e.preventDefault()
2948
+ editCityStyles('remove', i, '', '')
2949
+ }}
2950
+ >
2951
+ Remove
2952
+ </button>
2953
+ <p>City Style {i + 1}</p>
2954
+ <label>
2955
+ <span className='edit-label column-heading'>Column with configuration value</span>
2956
+ <select
2957
+ value={column}
2958
+ onChange={e => {
2959
+ editCityStyles('update', i, 'column', e.target.value)
2994
2960
  }}
2995
2961
  >
2996
- Remove
2997
- </button>
2998
- <p>City Style {i + 1}</p>
2999
- <label>
3000
- <span className='edit-label column-heading'>Column with configuration value</span>
3001
- <select
3002
- value={column}
3003
- onChange={e => {
3004
- editCityStyles('update', i, 'column', e.target.value)
3005
- }}
3006
- >
3007
- {columnsOptions}
3008
- </select>
3009
- </label>
3010
- <label>
3011
- <span className='edit-label column-heading'>Value to Trigger</span>
3012
- <input
3013
- type='text'
3014
- value={value}
3015
- onChange={e => {
3016
- editCityStyles('update', i, 'value', e.target.value)
3017
- }}
3018
- ></input>
3019
- </label>
3020
- <label>
3021
- <span className='edit-label column-heading'>Shape</span>
3022
- <select
3023
- value={shape}
3024
- onChange={e => {
3025
- editCityStyles('update', i, 'shape', e.target.value)
3026
- }}
3027
- >
3028
- {getCityStyleOptions('value')}
3029
- </select>
3030
- </label>
3031
- <label>
3032
- <span className='edit-label column-heading'>Label</span>
3033
- <input
3034
- key={i}
3035
- type='text'
3036
- value={label}
3037
- onChange={e => {
3038
- editCityStyles('update', i, 'label', e.target.value)
3039
- }}
3040
- />
3041
- </label>
3042
- </div>
3043
- )
3044
- })}
3045
-
3046
- <button type='button' onClick={() => editCityStyles('add', 0, '', '')} className='btn full-width'>
3047
- Add city style
3048
- </button>
3049
- </>
3050
- <label htmlFor='opacity'>
3051
- <TextField type='number' min={0} max={100} value={state.tooltips.opacity ? state.tooltips.opacity : 100} section='tooltips' fieldName='opacity' label='Tooltip Opacity (%)' updateField={updateField} />
3052
- </label>
3053
- </AccordionItemPanel>
3054
- </AccordionItem>
3055
- <AccordionItem>
3056
- <AccordionItemHeading>
3057
- <AccordionItemButton>Custom Map Layers</AccordionItemButton>
3058
- </AccordionItemHeading>
3059
- <AccordionItemPanel>
3060
- {state.map.layers.length === 0 && <p>There are currently no layers.</p>}
2962
+ {columnsOptions}
2963
+ </select>
2964
+ </label>
2965
+ <label>
2966
+ <span className='edit-label column-heading'>Value to Trigger</span>
2967
+ <input
2968
+ type='text'
2969
+ value={value}
2970
+ onChange={e => {
2971
+ editCityStyles('update', i, 'value', e.target.value)
2972
+ }}
2973
+ ></input>
2974
+ </label>
2975
+ <label>
2976
+ <span className='edit-label column-heading'>Shape</span>
2977
+ <select
2978
+ value={shape}
2979
+ onChange={e => {
2980
+ editCityStyles('update', i, 'shape', e.target.value)
2981
+ }}
2982
+ >
2983
+ {getCityStyleOptions('value')}
2984
+ </select>
2985
+ </label>
2986
+ <label>
2987
+ <span className='edit-label column-heading'>Label</span>
2988
+ <input
2989
+ key={i}
2990
+ type='text'
2991
+ value={label}
2992
+ onChange={e => {
2993
+ editCityStyles('update', i, 'label', e.target.value)
2994
+ }}
2995
+ />
2996
+ </label>
2997
+ </div>
2998
+ )
2999
+ })}
3061
3000
 
3062
- {state.map.layers.map((layer, index) => {
3063
- return (
3064
- <>
3065
- <Accordion allowZeroExpanded>
3066
- <AccordionItem className='series-item map-layers-list'>
3067
- <AccordionItemHeading className='series-item__title map-layers-list--title'>
3068
- <AccordionItemButton>{`Layer ${index + 1}: ${layer.name}`}</AccordionItemButton>
3069
- </AccordionItemHeading>
3070
- <AccordionItemPanel>
3071
- <div className='map-layers-panel'>
3072
- <label htmlFor='layerName'>Layer Name:</label>
3073
- <input type='text' name='layerName' value={layer.name} onChange={e => handleMapLayer(e, index, 'name')} />
3074
- <label htmlFor='layerFilename'>File:</label>
3075
- <input type='text' name='layerFilename' value={layer.url} onChange={e => handleMapLayer(e, index, 'url')} />
3076
- <label htmlFor='layerNamespace'>TOPOJSON Namespace:</label>
3077
- <input type='text' name='layerNamespace' value={layer.namespace} onChange={e => handleMapLayer(e, index, 'namespace')} />
3078
- <label htmlFor='layerFill'>Fill Color:</label>
3079
- <input type='text' name='layerFill' value={layer.fill} onChange={e => handleMapLayer(e, index, 'fill')} />
3080
- <label htmlFor='layerFill'>Fill Opacity (%):</label>
3081
- <input type='number' min={0} max={100} name='layerFill' value={layer.fillOpacity ? layer.fillOpacity * 100 : ''} onChange={e => handleMapLayer(e, index, 'fillOpacity')} />
3082
- <label htmlFor='layerStroke'>Stroke Color:</label>
3083
- <input type='text' name='layerStroke' value={layer.stroke} onChange={e => handleMapLayer(e, index, 'stroke')} />
3084
- <label htmlFor='layerStroke'>Stroke Width:</label>
3085
- <input type='number' min={0} max={5} name='layerStrokeWidth' value={layer.strokeWidth} onChange={e => handleMapLayer(e, index, 'strokeWidth')} />
3086
- <label htmlFor='layerTooltip'>Tooltip:</label>
3087
- <textarea name='layerTooltip' value={layer.tooltip} onChange={e => handleMapLayer(e, index, 'tooltip')}></textarea>
3088
- <button onClick={e => handleRemoveLayer(e, index)}>Remove Layer</button>
3089
- </div>
3090
- </AccordionItemPanel>
3091
- </AccordionItem>
3092
- </Accordion>
3093
- </>
3094
- )
3095
- })}
3096
- <button className={'btn full-width'} onClick={handleAddLayer}>
3097
- Add Map Layer
3001
+ <button type='button' onClick={() => editCityStyles('add', 0, '', '')} className='btn full-width'>
3002
+ Add city style
3098
3003
  </button>
3099
- <p className='layer-purpose-details'>Context should be added to your visualization or associated page to describe the significance of layers that are added to maps.</p>
3100
- </AccordionItemPanel>
3101
- </AccordionItem>
3102
- {state.general.geoType === 'us' && <Panels.PatternSettings name='Pattern Settings' />}
3103
- </Accordion>
3104
- <AdvancedEditor loadConfig={loadConfig} state={state} convertStateToConfig={convertStateToConfig} />
3105
- </section>
3106
- </section>
3004
+ </>
3005
+ <label htmlFor='opacity'>
3006
+ <TextField type='number' min={0} max={100} value={state.tooltips.opacity ? state.tooltips.opacity : 100} section='tooltips' fieldName='opacity' label='Tooltip Opacity (%)' updateField={updateField} />
3007
+ </label>
3008
+ </AccordionItemPanel>
3009
+ </AccordionItem>
3010
+ <AccordionItem>
3011
+ <AccordionItemHeading>
3012
+ <AccordionItemButton>Custom Map Layers</AccordionItemButton>
3013
+ </AccordionItemHeading>
3014
+ <AccordionItemPanel>
3015
+ {state.map.layers.length === 0 && <p>There are currently no layers.</p>}
3016
+
3017
+ {state.map.layers.map((layer, index) => {
3018
+ return (
3019
+ <>
3020
+ <Accordion allowZeroExpanded>
3021
+ <AccordionItem className='series-item map-layers-list'>
3022
+ <AccordionItemHeading className='series-item__title map-layers-list--title'>
3023
+ <AccordionItemButton>{`Layer ${index + 1}: ${layer.name}`}</AccordionItemButton>
3024
+ </AccordionItemHeading>
3025
+ <AccordionItemPanel>
3026
+ <div className='map-layers-panel'>
3027
+ <label htmlFor='layerName'>Layer Name:</label>
3028
+ <input type='text' name='layerName' value={layer.name} onChange={e => handleMapLayer(e, index, 'name')} />
3029
+ <label htmlFor='layerFilename'>File:</label>
3030
+ <input type='text' name='layerFilename' value={layer.url} onChange={e => handleMapLayer(e, index, 'url')} />
3031
+ <label htmlFor='layerNamespace'>TOPOJSON Namespace:</label>
3032
+ <input type='text' name='layerNamespace' value={layer.namespace} onChange={e => handleMapLayer(e, index, 'namespace')} />
3033
+ <label htmlFor='layerFill'>Fill Color:</label>
3034
+ <input type='text' name='layerFill' value={layer.fill} onChange={e => handleMapLayer(e, index, 'fill')} />
3035
+ <label htmlFor='layerFill'>Fill Opacity (%):</label>
3036
+ <input type='number' min={0} max={100} name='layerFill' value={layer.fillOpacity ? layer.fillOpacity * 100 : ''} onChange={e => handleMapLayer(e, index, 'fillOpacity')} />
3037
+ <label htmlFor='layerStroke'>Stroke Color:</label>
3038
+ <input type='text' name='layerStroke' value={layer.stroke} onChange={e => handleMapLayer(e, index, 'stroke')} />
3039
+ <label htmlFor='layerStroke'>Stroke Width:</label>
3040
+ <input type='number' min={0} max={5} name='layerStrokeWidth' value={layer.strokeWidth} onChange={e => handleMapLayer(e, index, 'strokeWidth')} />
3041
+ <label htmlFor='layerTooltip'>Tooltip:</label>
3042
+ <textarea name='layerTooltip' value={layer.tooltip} onChange={e => handleMapLayer(e, index, 'tooltip')}></textarea>
3043
+ <button onClick={e => handleRemoveLayer(e, index)}>Remove Layer</button>
3044
+ </div>
3045
+ </AccordionItemPanel>
3046
+ </AccordionItem>
3047
+ </Accordion>
3048
+ </>
3049
+ )
3050
+ })}
3051
+ <button className={'btn full-width'} onClick={handleAddLayer}>
3052
+ Add Map Layer
3053
+ </button>
3054
+ <p className='layer-purpose-details'>Context should be added to your visualization or associated page to describe the significance of layers that are added to maps.</p>
3055
+ </AccordionItemPanel>
3056
+ </AccordionItem>
3057
+ {state.general.geoType === 'us' && <Panels.PatternSettings name='Pattern Settings' />}
3058
+ </Accordion>
3059
+ <AdvancedEditor loadConfig={loadConfig} state={state} convertStateToConfig={convertStateToConfig} />
3060
+ </Layout.Sidebar>
3107
3061
  </ErrorBoundary>
3108
3062
  )
3109
3063
  }