@cdc/map 4.26.3 → 4.26.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.
- package/CONFIG.md +268 -0
- package/README.md +74 -24
- package/dist/cdcmap-CY9IcPSi.es.js +6 -0
- package/dist/cdcmap-DlpiY3fQ.es.js +4 -0
- package/dist/cdcmap.js +29168 -27482
- package/examples/{testing-layer-2.json → __data__/testing-layer-2.json} +1 -1
- package/examples/{testing-layer.json → __data__/testing-layer.json} +1 -1
- package/examples/county-hsa-toggle.json +51993 -0
- package/examples/custom-map-layers.json +2 -2
- package/examples/default-county.json +6 -3
- package/examples/minimal-example.json +73 -0
- package/examples/private/annotation-bug.json +2 -2
- package/examples/private/css-issue.json +314 -0
- package/examples/private/region-breaking.json +1639 -0
- package/examples/private/test1.json +27247 -0
- package/package.json +4 -4
- package/src/CdcMapComponent.tsx +107 -14
- package/src/_stories/CdcMap.AltText.stories.tsx +122 -0
- package/src/_stories/CdcMap.Editor.ColumnsSectionTests.stories.tsx +600 -0
- package/src/_stories/CdcMap.Editor.DataTableSectionTests.stories.tsx +404 -0
- package/src/_stories/CdcMap.Editor.FiltersSectionTests.stories.tsx +229 -0
- package/src/_stories/CdcMap.Editor.GeneralSectionTests.stories.tsx +262 -0
- package/src/_stories/CdcMap.Editor.LegendSectionTests.stories.tsx +541 -0
- package/src/_stories/CdcMap.Editor.MultiCountryWorldMapTests.stories.tsx +359 -0
- package/src/_stories/CdcMap.Editor.PatternSettingsSectionTests.stories.tsx +516 -0
- package/src/_stories/CdcMap.Editor.SmallMultiplesSectionTests.stories.tsx +165 -0
- package/src/_stories/CdcMap.Editor.TextAnnotationsSectionTests.stories.tsx +145 -0
- package/src/_stories/CdcMap.Editor.TypeSectionTests.stories.tsx +312 -0
- package/src/_stories/CdcMap.Editor.VisualSectionTests.stories.tsx +359 -0
- package/src/_stories/CdcMap.Editor.ZoomControlsTests.stories.tsx +88 -0
- package/src/_stories/CdcMap.FocusVisibility.stories.tsx +87 -0
- package/src/_stories/CdcMap.HiddenMount.stories.tsx +69 -0
- package/src/_stories/CdcMap.ResetBehavior.stories.tsx +32 -0
- package/src/_stories/CdcMap.Zoom.stories.tsx +111 -0
- package/src/_stories/{CdcMap.stories.tsx → CdcMap.smoke.stories.tsx} +60 -0
- package/src/_stories/_mock/alt_text_metadata.json +65 -0
- package/src/_stories/_mock/legends/legend-tests.json +3 -3
- package/src/_stories/_mock/world-bubble-reset.json +138 -0
- package/src/_stories/_mock/world-data-zoom-filters.json +166 -0
- package/src/components/Annotation/AnnotationList.tsx +1 -1
- package/src/components/BubbleList.tsx +13 -0
- package/src/components/EditorPanel/components/EditorPanel.tsx +637 -382
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +112 -117
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +26 -13
- package/src/components/EditorPanel/components/editorPanel.styles.css +22 -2
- package/src/components/FilterControls.tsx +21 -0
- package/src/components/Legend/components/Legend.tsx +3 -3
- package/src/components/Legend/components/LegendItem.Hex.tsx +4 -2
- package/src/components/SmallMultiples/SmallMultiples.tsx +2 -2
- package/src/components/SmallMultiples/SynchronizedTooltip.tsx +1 -1
- package/src/components/UsaMap/components/UsaMap.County.tsx +309 -108
- package/src/components/UsaMap/components/UsaMap.Region.tsx +5 -2
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +33 -10
- package/src/components/UsaMap/components/UsaMap.State.tsx +10 -3
- package/src/components/UsaMap/data/cb_2019_us_county_20m.json +75817 -1
- package/src/components/UsaMap/data/hsa_fips_mapping.json +3144 -0
- package/src/components/WorldMap/WorldMap.tsx +37 -4
- package/src/components/WorldMap/data/world-topo.json +1 -1
- package/src/components/ZoomableGroup.tsx +23 -3
- package/src/components/filterControls.styles.css +6 -0
- package/src/data/initial-state.js +3 -0
- package/src/data/supported-counties.json +1 -1
- package/src/helpers/countyTerritories.ts +38 -0
- package/src/helpers/dataTableHelpers.ts +35 -6
- package/src/helpers/generateRuntimeFilters.ts +2 -1
- package/src/helpers/handleMapAriaLabels.ts +45 -30
- package/src/helpers/shouldAutoResetSingleStateZoom.ts +22 -0
- package/src/helpers/tests/countyTerritories.test.ts +87 -0
- package/src/helpers/tests/handleMapAriaLabels.test.ts +71 -0
- package/src/helpers/tests/shouldAutoResetSingleStateZoom.test.ts +71 -0
- package/src/hooks/useApplyTooltipsToGeo.tsx +7 -4
- package/src/hooks/useGeoClickHandler.ts +13 -1
- package/src/hooks/useMapLayers.tsx +1 -1
- package/src/hooks/useStateZoom.tsx +39 -20
- package/src/hooks/useTooltip.test.tsx +2 -16
- package/src/hooks/useTooltip.ts +18 -7
- package/src/index.jsx +5 -2
- package/src/scss/main.scss +6 -21
- package/src/scss/map.scss +20 -0
- package/src/store/map.actions.ts +5 -2
- package/src/store/map.reducer.ts +12 -3
- package/src/test/CdcMap.test.jsx +24 -0
- package/src/types/MapConfig.ts +11 -0
- package/src/types/MapContext.ts +6 -1
- package/topojson-updater/README.txt +1 -1
- package/dist/cdcmap-vr9HZwRt.es.js +0 -6
- package/examples/__data__/city-state-data.json +0 -668
- package/examples/city-state.json +0 -434
- package/examples/default-world-data.json +0 -1450
- package/examples/new-cities.json +0 -656
- package/src/_stories/CdcMap.Editor.stories.tsx +0 -3648
- package/topojson-updater/package-lock.json +0 -223
- /package/src/_stories/{CdcMap.ColumnWrap.stories.tsx → CdcMap.ColumnWrap.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Defaults.stories.tsx → CdcMap.Defaults.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.DistrictOfColumbia.stories.tsx → CdcMap.DistrictOfColumbia.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Filters.stories.tsx → CdcMap.Filters.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Legend.Gradient.stories.tsx → CdcMap.Legend.Gradient.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Legend.stories.tsx → CdcMap.Legend.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Patterns.stories.tsx → CdcMap.Patterns.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.SmallMultiples.stories.tsx → CdcMap.SmallMultiples.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Table.stories.tsx → CdcMap.Table.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.ZeroColor.stories.tsx → CdcMap.ZeroColor.smoke.stories.tsx} +0 -0
- /package/src/_stories/{GoogleMap.stories.tsx → GoogleMap.smoke.stories.tsx} +0 -0
- /package/src/_stories/{UsaMap.NoData.stories.tsx → UsaMap.NoData.smoke.stories.tsx} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useContext, useEffect, useState, useMemo, useRef } from 'react'
|
|
2
2
|
import { filterColorPalettes } from '@cdc/core/helpers/filterColorPalettes'
|
|
3
3
|
import { cloneConfig } from '@cdc/core/helpers/cloneConfig'
|
|
4
|
+
import { resolveAltTextDescription } from '@cdc/core/helpers/resolveAltTextDescription'
|
|
4
5
|
|
|
5
6
|
// Third Party
|
|
6
7
|
import {
|
|
@@ -29,6 +30,7 @@ import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel
|
|
|
29
30
|
import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
|
|
30
31
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
31
32
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
33
|
+
import GroupedList from '@cdc/core/components/EditorPanel/GroupedList'
|
|
32
34
|
import InputToggle from '@cdc/core/components/inputs/InputToggle'
|
|
33
35
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
34
36
|
import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
|
|
@@ -50,6 +52,8 @@ import { MapContext } from '../../../types/MapContext.js'
|
|
|
50
52
|
import Alert from '@cdc/core/components/Alert'
|
|
51
53
|
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
52
54
|
import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
|
|
55
|
+
import DownloadUrlControls from '@cdc/core/components/EditorPanel/DownloadUrlControls'
|
|
56
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
53
57
|
import StyleTreatmentSection from '@cdc/core/components/EditorPanel/sections/StyleTreatmentSection'
|
|
54
58
|
import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
|
|
55
59
|
import useColumnsRequiredChecker from '../../../hooks/useColumnsRequiredChecker'
|
|
@@ -1243,7 +1247,11 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1243
1247
|
))
|
|
1244
1248
|
}
|
|
1245
1249
|
|
|
1246
|
-
const isLoadedFromUrl =
|
|
1250
|
+
const isLoadedFromUrl =
|
|
1251
|
+
config?.dataFileSourceType === 'url' ||
|
|
1252
|
+
Boolean(config?.runtimeDataUrl || config?.dataUrl || config?.dataFileName) ||
|
|
1253
|
+
config?.dataKey?.includes('http://') ||
|
|
1254
|
+
config?.dataKey?.includes('https://')
|
|
1247
1255
|
|
|
1248
1256
|
// Custom convertStateToConfig for map with map-specific logic
|
|
1249
1257
|
const customConvertStateToConfig = () => {
|
|
@@ -1362,6 +1370,41 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1362
1370
|
}}
|
|
1363
1371
|
/>
|
|
1364
1372
|
)}
|
|
1373
|
+
{config.general.geoType === 'us-county' && (
|
|
1374
|
+
<>
|
|
1375
|
+
<CheckBox
|
|
1376
|
+
value={config.general.showNeighboringStates || false}
|
|
1377
|
+
fieldName='showNeighboringStates'
|
|
1378
|
+
label="Show Neighboring States' Data"
|
|
1379
|
+
updateField={updateField}
|
|
1380
|
+
section='general'
|
|
1381
|
+
/>
|
|
1382
|
+
<CheckBox
|
|
1383
|
+
value={config.general.showHSABoundaries || false}
|
|
1384
|
+
fieldName='showHSABoundaries'
|
|
1385
|
+
label='Show HSA Boundaries'
|
|
1386
|
+
updateField={updateField}
|
|
1387
|
+
section='general'
|
|
1388
|
+
tooltip={
|
|
1389
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1390
|
+
<Tooltip.Target>
|
|
1391
|
+
<Icon
|
|
1392
|
+
display='question'
|
|
1393
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
1394
|
+
/>
|
|
1395
|
+
</Tooltip.Target>
|
|
1396
|
+
<Tooltip.Content>
|
|
1397
|
+
<p>
|
|
1398
|
+
Health Service Areas (HSAs) are a county or cluster of contiguous counties which are
|
|
1399
|
+
relatively self-contained with respect to hospital care. Set HSA description in
|
|
1400
|
+
tooltip under the Columns accordion.
|
|
1401
|
+
</p>
|
|
1402
|
+
</Tooltip.Content>
|
|
1403
|
+
</Tooltip>
|
|
1404
|
+
}
|
|
1405
|
+
/>
|
|
1406
|
+
</>
|
|
1407
|
+
)}
|
|
1365
1408
|
{(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
|
|
1366
1409
|
<Select
|
|
1367
1410
|
label='County Census Year'
|
|
@@ -1599,14 +1642,26 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1599
1642
|
/>
|
|
1600
1643
|
)}
|
|
1601
1644
|
|
|
1602
|
-
{'us'
|
|
1645
|
+
{['us', 'us-county'].includes(config.general.geoType) && (
|
|
1603
1646
|
<CheckBox
|
|
1604
|
-
value={general.territoriesAlwaysShow
|
|
1647
|
+
value={general.territoriesAlwaysShow ?? true}
|
|
1605
1648
|
section='general'
|
|
1606
1649
|
subsection={null}
|
|
1607
1650
|
fieldName='territoriesAlwaysShow'
|
|
1608
|
-
label='Show
|
|
1609
|
-
updateField={
|
|
1651
|
+
label='Show Available Territories'
|
|
1652
|
+
updateField={() => {
|
|
1653
|
+
setConfig({
|
|
1654
|
+
...config,
|
|
1655
|
+
general: {
|
|
1656
|
+
...config.general,
|
|
1657
|
+
territoriesAlwaysShow: !(general.territoriesAlwaysShow ?? true)
|
|
1658
|
+
},
|
|
1659
|
+
migrations: {
|
|
1660
|
+
...config.migrations,
|
|
1661
|
+
showPuertoRico: false
|
|
1662
|
+
}
|
|
1663
|
+
})
|
|
1664
|
+
}}
|
|
1610
1665
|
/>
|
|
1611
1666
|
)}
|
|
1612
1667
|
</AccordionItemPanel>
|
|
@@ -1777,6 +1832,105 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1777
1832
|
</Tooltip>
|
|
1778
1833
|
}
|
|
1779
1834
|
/>
|
|
1835
|
+
|
|
1836
|
+
{/* Accessible Alt Text Description */}
|
|
1837
|
+
{(() => {
|
|
1838
|
+
const metadataKeys = Object.keys(config.dataMetadata || {})
|
|
1839
|
+
const hasMetadata = metadataKeys.length > 0
|
|
1840
|
+
const descType = config.altText?.type || ''
|
|
1841
|
+
const resolvedDescription = resolveAltTextDescription(config.altText, config.dataMetadata)
|
|
1842
|
+
return (
|
|
1843
|
+
<>
|
|
1844
|
+
<Select
|
|
1845
|
+
value={descType}
|
|
1846
|
+
fieldName='altTextType'
|
|
1847
|
+
label='Alt Text Description'
|
|
1848
|
+
options={[
|
|
1849
|
+
{ value: '', label: 'None' },
|
|
1850
|
+
{ value: 'static', label: 'Static (manual text)' },
|
|
1851
|
+
{ value: 'metadata', label: 'Data File Metadata' }
|
|
1852
|
+
]}
|
|
1853
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
1854
|
+
if (value === '') {
|
|
1855
|
+
updateField(null, null, 'altText', undefined)
|
|
1856
|
+
} else {
|
|
1857
|
+
updateField(null, null, 'altText', { type: value as 'static' | 'metadata' })
|
|
1858
|
+
}
|
|
1859
|
+
}}
|
|
1860
|
+
tooltip={
|
|
1861
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1862
|
+
<Tooltip.Target>
|
|
1863
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1864
|
+
</Tooltip.Target>
|
|
1865
|
+
<Tooltip.Content>
|
|
1866
|
+
<p>
|
|
1867
|
+
Add a longer description for screen readers. The map title is always auto-generated.
|
|
1868
|
+
Use "Static" for manually written text, or "Data File Metadata" to pull it from a
|
|
1869
|
+
key in your data file.
|
|
1870
|
+
</p>
|
|
1871
|
+
</Tooltip.Content>
|
|
1872
|
+
</Tooltip>
|
|
1873
|
+
}
|
|
1874
|
+
/>
|
|
1875
|
+
{descType === 'static' && (
|
|
1876
|
+
<TextField
|
|
1877
|
+
value={config.altText?.value || ''}
|
|
1878
|
+
fieldName='altTextValue'
|
|
1879
|
+
type='textarea'
|
|
1880
|
+
label='Description Text'
|
|
1881
|
+
placeholder='Longer interpretive description of map insights...'
|
|
1882
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
1883
|
+
updateField(null, null, 'altText', { ...config.altText, value })
|
|
1884
|
+
}}
|
|
1885
|
+
/>
|
|
1886
|
+
)}
|
|
1887
|
+
{descType === 'metadata' && (
|
|
1888
|
+
<>
|
|
1889
|
+
{hasMetadata ? (
|
|
1890
|
+
<Select
|
|
1891
|
+
value={config.altText?.metadataKey || ''}
|
|
1892
|
+
fieldName='altTextMetadataKey'
|
|
1893
|
+
label='Description Metadata Field'
|
|
1894
|
+
options={[
|
|
1895
|
+
{ value: '', label: 'Select Metadata Field...' },
|
|
1896
|
+
...metadataKeys.map(key => ({
|
|
1897
|
+
value: key,
|
|
1898
|
+
label: `${key}: ${config.dataMetadata[key]}`
|
|
1899
|
+
}))
|
|
1900
|
+
]}
|
|
1901
|
+
updateField={(_section, _subsection, _fieldName, value) => {
|
|
1902
|
+
updateField(null, null, 'altText', { ...config.altText, metadataKey: value })
|
|
1903
|
+
}}
|
|
1904
|
+
/>
|
|
1905
|
+
) : (
|
|
1906
|
+
<span className='subtext'>
|
|
1907
|
+
No metadata fields are available. Your data file must be a JSON object with a{' '}
|
|
1908
|
+
<code>data</code> array and sibling key-value pairs, for example:{' '}
|
|
1909
|
+
<code>{`{ "altDescription": "...", "data": [...] }`}</code>
|
|
1910
|
+
</span>
|
|
1911
|
+
)}
|
|
1912
|
+
</>
|
|
1913
|
+
)}
|
|
1914
|
+
{resolvedDescription && (
|
|
1915
|
+
<div
|
|
1916
|
+
style={{
|
|
1917
|
+
marginTop: '1em',
|
|
1918
|
+
padding: '0.75em',
|
|
1919
|
+
background: '#f5f5f5',
|
|
1920
|
+
borderRadius: '4px',
|
|
1921
|
+
fontSize: '0.8em',
|
|
1922
|
+
textTransform: 'none'
|
|
1923
|
+
}}
|
|
1924
|
+
>
|
|
1925
|
+
<strong style={{ display: 'block', marginBottom: '0.25em' }}>Preview:</strong>
|
|
1926
|
+
<p data-testid='alt-text-desc-preview' style={{ margin: 0, fontStyle: 'italic' }}>
|
|
1927
|
+
{resolvedDescription}
|
|
1928
|
+
</p>
|
|
1929
|
+
</div>
|
|
1930
|
+
)}
|
|
1931
|
+
</>
|
|
1932
|
+
)
|
|
1933
|
+
})()}
|
|
1780
1934
|
</AccordionItemPanel>
|
|
1781
1935
|
</AccordionItem>
|
|
1782
1936
|
<AccordionItem>
|
|
@@ -1923,6 +2077,26 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1923
2077
|
/>
|
|
1924
2078
|
</label>
|
|
1925
2079
|
</ColumnSection>
|
|
2080
|
+
{config.general.geoType === 'us-county' && config.general.showHSABoundaries && (
|
|
2081
|
+
<Select
|
|
2082
|
+
label='HSA Description Column'
|
|
2083
|
+
value={config.columns.hsa?.name}
|
|
2084
|
+
options={columnsOptions.map(c => c.key)}
|
|
2085
|
+
onChange={e => {
|
|
2086
|
+
editColumn('hsa', 'name', e.target.value)
|
|
2087
|
+
}}
|
|
2088
|
+
tooltip={
|
|
2089
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2090
|
+
<Tooltip.Target>
|
|
2091
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2092
|
+
</Tooltip.Target>
|
|
2093
|
+
<Tooltip.Content>
|
|
2094
|
+
<p>Select the source column containing the HSA description.</p>
|
|
2095
|
+
</Tooltip.Content>
|
|
2096
|
+
</Tooltip>
|
|
2097
|
+
}
|
|
2098
|
+
/>
|
|
2099
|
+
)}
|
|
1926
2100
|
{'navigation' !== config.general.type && (
|
|
1927
2101
|
<ColumnSection
|
|
1928
2102
|
fieldKey='primary'
|
|
@@ -2101,105 +2275,6 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2101
2275
|
</>
|
|
2102
2276
|
}
|
|
2103
2277
|
|
|
2104
|
-
{'navigation' !== config.general.type && (
|
|
2105
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
2106
|
-
<label>
|
|
2107
|
-
<span className='edit-label'>
|
|
2108
|
-
Special Classes
|
|
2109
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2110
|
-
<Tooltip.Target>
|
|
2111
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2112
|
-
</Tooltip.Target>
|
|
2113
|
-
<Tooltip.Content>
|
|
2114
|
-
<p>
|
|
2115
|
-
For secondary values such as "NA", the system can automatically color-code them in
|
|
2116
|
-
shades of gray, one shade for each special class.
|
|
2117
|
-
</p>
|
|
2118
|
-
</Tooltip.Content>
|
|
2119
|
-
</Tooltip>
|
|
2120
|
-
</span>
|
|
2121
|
-
</label>
|
|
2122
|
-
{config.legend.specialClasses.length === 2 && (
|
|
2123
|
-
<Alert
|
|
2124
|
-
type='info'
|
|
2125
|
-
message='If a third special class is needed you can apply a pattern to set it apart.'
|
|
2126
|
-
showCloseButton={false}
|
|
2127
|
-
/>
|
|
2128
|
-
)}
|
|
2129
|
-
{specialClasses.map((specialClass, i) => (
|
|
2130
|
-
<div className='edit-block' key={`special-class-${i}`}>
|
|
2131
|
-
<button
|
|
2132
|
-
className='remove-column'
|
|
2133
|
-
onClick={e => {
|
|
2134
|
-
e.preventDefault()
|
|
2135
|
-
editColumn('primary', 'specialClassDelete', i)
|
|
2136
|
-
}}
|
|
2137
|
-
>
|
|
2138
|
-
Remove
|
|
2139
|
-
</button>
|
|
2140
|
-
<p>Special Class {i + 1}</p>
|
|
2141
|
-
<Select
|
|
2142
|
-
label='Data Key'
|
|
2143
|
-
value={specialClass.key}
|
|
2144
|
-
options={columnsOptions.map(option => ({
|
|
2145
|
-
value: option.key,
|
|
2146
|
-
label: option.key
|
|
2147
|
-
}))}
|
|
2148
|
-
onChange={event => {
|
|
2149
|
-
editColumn('primary', 'specialClassEdit', {
|
|
2150
|
-
prop: 'key',
|
|
2151
|
-
index: i,
|
|
2152
|
-
value: event.target.value
|
|
2153
|
-
})
|
|
2154
|
-
}}
|
|
2155
|
-
/>
|
|
2156
|
-
<Select
|
|
2157
|
-
label='Value'
|
|
2158
|
-
value={specialClass.value}
|
|
2159
|
-
options={[
|
|
2160
|
-
{ value: '', label: '- Select Value -' },
|
|
2161
|
-
...(columnsByKey[specialClass.key] || [])
|
|
2162
|
-
.sort()
|
|
2163
|
-
.map(option => ({ value: option, label: option }))
|
|
2164
|
-
]}
|
|
2165
|
-
onChange={event => {
|
|
2166
|
-
editColumn('primary', 'specialClassEdit', {
|
|
2167
|
-
prop: 'value',
|
|
2168
|
-
index: i,
|
|
2169
|
-
value: event.target.value
|
|
2170
|
-
})
|
|
2171
|
-
}}
|
|
2172
|
-
/>
|
|
2173
|
-
<label>
|
|
2174
|
-
<span className='edit-label column-heading'>Label</span>
|
|
2175
|
-
<input
|
|
2176
|
-
type='text'
|
|
2177
|
-
value={specialClass.label}
|
|
2178
|
-
onChange={e => {
|
|
2179
|
-
editColumn('primary', 'specialClassEdit', {
|
|
2180
|
-
prop: 'label',
|
|
2181
|
-
index: i,
|
|
2182
|
-
value: e.target.value
|
|
2183
|
-
})
|
|
2184
|
-
}}
|
|
2185
|
-
/>
|
|
2186
|
-
</label>
|
|
2187
|
-
</div>
|
|
2188
|
-
))}
|
|
2189
|
-
{config.legend.specialClasses.length < 2 && (
|
|
2190
|
-
<button
|
|
2191
|
-
className='btn btn-primary full-width'
|
|
2192
|
-
onClick={e => {
|
|
2193
|
-
e.preventDefault()
|
|
2194
|
-
editColumn('primary', 'specialClassAdd', {})
|
|
2195
|
-
}}
|
|
2196
|
-
>
|
|
2197
|
-
Add Special Class
|
|
2198
|
-
</button>
|
|
2199
|
-
)}
|
|
2200
|
-
</fieldset>
|
|
2201
|
-
)}
|
|
2202
|
-
|
|
2203
2278
|
<label className='edit-block navigate column-heading'>
|
|
2204
2279
|
<span className='edit-label column-heading'>
|
|
2205
2280
|
Navigation
|
|
@@ -2227,144 +2302,261 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2227
2302
|
<fieldset className='primary-fieldset edit-block'>
|
|
2228
2303
|
<label>
|
|
2229
2304
|
<span className='edit-label'>
|
|
2230
|
-
|
|
2305
|
+
Special Classes
|
|
2231
2306
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
2232
2307
|
<Tooltip.Target>
|
|
2233
2308
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2234
2309
|
</Tooltip.Target>
|
|
2235
2310
|
<Tooltip.Content>
|
|
2236
2311
|
<p>
|
|
2237
|
-
|
|
2238
|
-
|
|
2312
|
+
For secondary values such as "NA", the system can automatically color-code them in
|
|
2313
|
+
shades of gray, one shade for each special class.
|
|
2239
2314
|
</p>
|
|
2240
2315
|
</Tooltip.Content>
|
|
2241
2316
|
</Tooltip>
|
|
2242
2317
|
</span>
|
|
2243
2318
|
</label>
|
|
2244
|
-
{
|
|
2245
|
-
<
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
<
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
</
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2319
|
+
{config.legend.specialClasses.length === 2 && (
|
|
2320
|
+
<Alert
|
|
2321
|
+
type='info'
|
|
2322
|
+
message='If a third special class is needed you can apply a pattern to set it apart.'
|
|
2323
|
+
showCloseButton={false}
|
|
2324
|
+
/>
|
|
2325
|
+
)}
|
|
2326
|
+
<GroupedList
|
|
2327
|
+
items={specialClasses}
|
|
2328
|
+
label='Special Classes'
|
|
2329
|
+
droppableId='map-special-classes'
|
|
2330
|
+
draggable={false}
|
|
2331
|
+
renderItem={(specialClass, i) => (
|
|
2332
|
+
<Accordion allowZeroExpanded key={`special-class-${i}`}>
|
|
2333
|
+
<AccordionItem className='series-item series-item--chart'>
|
|
2334
|
+
<AccordionItemHeading className='series-item__title'>
|
|
2335
|
+
<AccordionItemButton className='accordion__button'>
|
|
2336
|
+
{specialClass.label || specialClass.value || `Special Class ${i + 1}`}
|
|
2337
|
+
</AccordionItemButton>
|
|
2338
|
+
</AccordionItemHeading>
|
|
2339
|
+
<AccordionItemPanel>
|
|
2340
|
+
<div className='series-item__panel-actions'>
|
|
2341
|
+
<Button
|
|
2342
|
+
type='button'
|
|
2343
|
+
variant='danger'
|
|
2344
|
+
size='sm'
|
|
2345
|
+
className='grouped-list__remove'
|
|
2346
|
+
onClick={() => editColumn('primary', 'specialClassDelete', i)}
|
|
2347
|
+
>
|
|
2348
|
+
Remove
|
|
2349
|
+
</Button>
|
|
2350
|
+
</div>
|
|
2351
|
+
<Select
|
|
2352
|
+
label='Data Key'
|
|
2353
|
+
value={specialClass.key}
|
|
2354
|
+
options={columnsOptions.map(option => ({
|
|
2355
|
+
value: option.key,
|
|
2356
|
+
label: option.key
|
|
2357
|
+
}))}
|
|
2358
|
+
onChange={event => {
|
|
2359
|
+
editColumn('primary', 'specialClassEdit', {
|
|
2360
|
+
prop: 'key',
|
|
2361
|
+
index: i,
|
|
2362
|
+
value: event.target.value
|
|
2363
|
+
})
|
|
2364
|
+
}}
|
|
2365
|
+
/>
|
|
2366
|
+
<Select
|
|
2367
|
+
label='Value'
|
|
2368
|
+
value={specialClass.value}
|
|
2369
|
+
options={[
|
|
2370
|
+
{ value: '', label: '- Select Value -' },
|
|
2371
|
+
...(columnsByKey[specialClass.key] || [])
|
|
2372
|
+
.sort()
|
|
2373
|
+
.map(option => ({ value: option, label: option }))
|
|
2374
|
+
]}
|
|
2375
|
+
onChange={event => {
|
|
2376
|
+
editColumn('primary', 'specialClassEdit', {
|
|
2377
|
+
prop: 'value',
|
|
2378
|
+
index: i,
|
|
2379
|
+
value: event.target.value
|
|
2380
|
+
})
|
|
2381
|
+
}}
|
|
2382
|
+
/>
|
|
2383
|
+
<label>
|
|
2384
|
+
<span className='edit-label column-heading'>Label</span>
|
|
2385
|
+
<input
|
|
2386
|
+
type='text'
|
|
2387
|
+
value={specialClass.label}
|
|
2388
|
+
onChange={e => {
|
|
2389
|
+
editColumn('primary', 'specialClassEdit', {
|
|
2390
|
+
prop: 'label',
|
|
2391
|
+
index: i,
|
|
2392
|
+
value: e.target.value
|
|
2393
|
+
})
|
|
2394
|
+
}}
|
|
2395
|
+
/>
|
|
2396
|
+
</label>
|
|
2397
|
+
</AccordionItemPanel>
|
|
2398
|
+
</AccordionItem>
|
|
2399
|
+
</Accordion>
|
|
2400
|
+
)}
|
|
2401
|
+
/>
|
|
2402
|
+
{config.legend.specialClasses.length < 2 && (
|
|
2403
|
+
<Button
|
|
2404
|
+
type='button'
|
|
2405
|
+
variant='editor-primary'
|
|
2406
|
+
onClick={() => editColumn('primary', 'specialClassAdd', {})}
|
|
2407
|
+
>
|
|
2408
|
+
Add Special Class
|
|
2409
|
+
</Button>
|
|
2410
|
+
)}
|
|
2411
|
+
</fieldset>
|
|
2412
|
+
)}
|
|
2413
|
+
{'navigation' !== config.general.type && (
|
|
2414
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
2415
|
+
<GroupedList
|
|
2416
|
+
items={additionalColumns}
|
|
2417
|
+
label={
|
|
2418
|
+
<>
|
|
2419
|
+
Additional Columns
|
|
2420
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2421
|
+
<Tooltip.Target>
|
|
2422
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2423
|
+
</Tooltip.Target>
|
|
2424
|
+
<Tooltip.Content>
|
|
2425
|
+
<p>
|
|
2426
|
+
You can specify additional columns to display in tooltips and / or the supporting
|
|
2427
|
+
data table.
|
|
2428
|
+
</p>
|
|
2429
|
+
</Tooltip.Content>
|
|
2430
|
+
</Tooltip>
|
|
2431
|
+
</>
|
|
2432
|
+
}
|
|
2433
|
+
droppableId='map-additional-columns'
|
|
2434
|
+
draggable={false}
|
|
2435
|
+
renderItem={val => (
|
|
2436
|
+
<Accordion allowZeroExpanded key={val}>
|
|
2437
|
+
<AccordionItem className='series-item series-item--chart'>
|
|
2438
|
+
<AccordionItemHeading className='series-item__title'>
|
|
2439
|
+
<AccordionItemButton className='accordion__button'>
|
|
2440
|
+
{columns[val]?.label || config.columns[val]?.name || 'New Column'}
|
|
2441
|
+
</AccordionItemButton>
|
|
2442
|
+
</AccordionItemHeading>
|
|
2443
|
+
<AccordionItemPanel>
|
|
2444
|
+
<div className='series-item__panel-actions'>
|
|
2445
|
+
<Button
|
|
2446
|
+
type='button'
|
|
2447
|
+
variant='danger'
|
|
2448
|
+
size='sm'
|
|
2449
|
+
className='grouped-list__remove'
|
|
2450
|
+
onClick={() => removeAdditionalColumn(val)}
|
|
2451
|
+
>
|
|
2452
|
+
Remove
|
|
2453
|
+
</Button>
|
|
2454
|
+
</div>
|
|
2455
|
+
<Select
|
|
2456
|
+
label='Column'
|
|
2457
|
+
value={config.columns[val] ? config.columns[val].name : ''}
|
|
2458
|
+
options={columnsOptions.map(option => ({
|
|
2459
|
+
value: option.props.value,
|
|
2460
|
+
label: option.props.children
|
|
2461
|
+
}))}
|
|
2462
|
+
onChange={event => {
|
|
2463
|
+
editColumn(val, 'name', event.target.value)
|
|
2464
|
+
}}
|
|
2465
|
+
/>
|
|
2466
|
+
<TextField
|
|
2467
|
+
value={columns[val].label}
|
|
2468
|
+
section='columns'
|
|
2469
|
+
subsection={val}
|
|
2470
|
+
fieldName='label'
|
|
2471
|
+
label='Label'
|
|
2472
|
+
updateField={updateField}
|
|
2473
|
+
/>
|
|
2474
|
+
<ul className='column-edit'>
|
|
2475
|
+
<li className='three-col'>
|
|
2476
|
+
<TextField
|
|
2477
|
+
value={columns[val].prefix}
|
|
2478
|
+
section='columns'
|
|
2479
|
+
subsection={val}
|
|
2480
|
+
fieldName='prefix'
|
|
2481
|
+
label='Prefix'
|
|
2482
|
+
updateField={updateField}
|
|
2483
|
+
/>
|
|
2484
|
+
<TextField
|
|
2485
|
+
value={columns[val].suffix}
|
|
2486
|
+
section='columns'
|
|
2487
|
+
subsection={val}
|
|
2488
|
+
fieldName='suffix'
|
|
2489
|
+
label='Suffix'
|
|
2490
|
+
updateField={updateField}
|
|
2491
|
+
/>
|
|
2492
|
+
<TextField
|
|
2493
|
+
type='number'
|
|
2494
|
+
value={columns[val].roundToPlace}
|
|
2495
|
+
section='columns'
|
|
2496
|
+
subsection={val}
|
|
2497
|
+
fieldName='roundToPlace'
|
|
2498
|
+
label='Round'
|
|
2499
|
+
updateField={updateField}
|
|
2500
|
+
/>
|
|
2501
|
+
</li>
|
|
2502
|
+
<CheckBox
|
|
2503
|
+
value={config.columns[val].useCommas}
|
|
2504
|
+
section='columns'
|
|
2505
|
+
subsection={val}
|
|
2506
|
+
fieldName='useCommas'
|
|
2507
|
+
label='Add Commas to Numbers'
|
|
2508
|
+
updateField={updateField}
|
|
2509
|
+
onChange={event => {
|
|
2510
|
+
editColumn(val, 'useCommas', event.target.checked)
|
|
2511
|
+
}}
|
|
2512
|
+
/>
|
|
2513
|
+
<CheckBox
|
|
2514
|
+
value={config.columns[val].dataTable}
|
|
2515
|
+
section='columns'
|
|
2516
|
+
subsection={val}
|
|
2517
|
+
fieldName='dataTable'
|
|
2518
|
+
label='Show in Data Table'
|
|
2519
|
+
updateField={updateField}
|
|
2520
|
+
onChange={event => {
|
|
2521
|
+
editColumn(val, 'dataTable', event.target.checked)
|
|
2522
|
+
}}
|
|
2523
|
+
/>
|
|
2524
|
+
<CheckBox
|
|
2525
|
+
value={config.columns[val].tooltip}
|
|
2526
|
+
section='columns'
|
|
2527
|
+
subsection={val}
|
|
2528
|
+
fieldName='tooltip'
|
|
2529
|
+
label='Show in Tooltips'
|
|
2530
|
+
updateField={updateField}
|
|
2531
|
+
onChange={event => {
|
|
2532
|
+
editColumn(val, 'tooltip', event.target.checked)
|
|
2533
|
+
}}
|
|
2534
|
+
/>
|
|
2535
|
+
<label>
|
|
2536
|
+
<span className='edit-label column-heading'>Order</span>
|
|
2537
|
+
<input
|
|
2538
|
+
onWheel={e => e.currentTarget.blur()}
|
|
2539
|
+
type='number'
|
|
2540
|
+
min='1'
|
|
2541
|
+
value={config.columns[val]?.order ?? ''}
|
|
2542
|
+
onChange={event => {
|
|
2543
|
+
updateColumnOrder(val, event.target.value)
|
|
2544
|
+
}}
|
|
2545
|
+
/>
|
|
2546
|
+
</label>
|
|
2547
|
+
</ul>
|
|
2548
|
+
</AccordionItemPanel>
|
|
2549
|
+
</AccordionItem>
|
|
2550
|
+
</Accordion>
|
|
2551
|
+
)}
|
|
2552
|
+
/>
|
|
2553
|
+
<Button
|
|
2554
|
+
type='button'
|
|
2555
|
+
variant='editor-primary'
|
|
2556
|
+
onClick={() => addAdditionalColumn(additionalColumns.length + 1)}
|
|
2365
2557
|
>
|
|
2366
2558
|
Add Column
|
|
2367
|
-
</
|
|
2559
|
+
</Button>
|
|
2368
2560
|
</fieldset>
|
|
2369
2561
|
)}
|
|
2370
2562
|
{'category' === config.legend.type && (
|
|
@@ -2412,8 +2604,8 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2412
2604
|
</label>
|
|
2413
2605
|
</fieldset>
|
|
2414
2606
|
))}
|
|
2415
|
-
<
|
|
2416
|
-
className={'btn btn-primary full-width'}
|
|
2607
|
+
<Button
|
|
2608
|
+
className={'btn btn-primary full-width editor-panel-action-button'}
|
|
2417
2609
|
onClick={event => {
|
|
2418
2610
|
event.preventDefault()
|
|
2419
2611
|
const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
|
|
@@ -2422,7 +2614,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2422
2614
|
}}
|
|
2423
2615
|
>
|
|
2424
2616
|
Add Category
|
|
2425
|
-
</
|
|
2617
|
+
</Button>
|
|
2426
2618
|
</fieldset>
|
|
2427
2619
|
)}
|
|
2428
2620
|
</AccordionItemPanel>
|
|
@@ -2920,6 +3112,15 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2920
3112
|
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2921
3113
|
</AccordionItemHeading>
|
|
2922
3114
|
<AccordionItemPanel>
|
|
3115
|
+
{config.general.geoType === 'us-county' && (
|
|
3116
|
+
<CheckBox
|
|
3117
|
+
value={config.general.showStateDropdown || false}
|
|
3118
|
+
fieldName='showStateDropdown'
|
|
3119
|
+
label='Show State Dropdown'
|
|
3120
|
+
updateField={updateField}
|
|
3121
|
+
section='general'
|
|
3122
|
+
/>
|
|
3123
|
+
)}
|
|
2923
3124
|
<VizFilterEditor
|
|
2924
3125
|
config={config}
|
|
2925
3126
|
updateField={updateField}
|
|
@@ -3119,6 +3320,26 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3119
3320
|
label='Show collapse below table'
|
|
3120
3321
|
updateField={updateField}
|
|
3121
3322
|
/>
|
|
3323
|
+
<CheckBox
|
|
3324
|
+
value={config.table.search ?? false}
|
|
3325
|
+
section='table'
|
|
3326
|
+
subsection={null}
|
|
3327
|
+
fieldName='search'
|
|
3328
|
+
label='Enable Search'
|
|
3329
|
+
updateField={updateField}
|
|
3330
|
+
/>
|
|
3331
|
+
{config.table.search && (
|
|
3332
|
+
<div className='ms-4 mt-2' style={{ maxWidth: 'calc(100% - 1.5rem)' }}>
|
|
3333
|
+
<TextField
|
|
3334
|
+
value={config.table.searchPlaceholder || ''}
|
|
3335
|
+
section='table'
|
|
3336
|
+
fieldName='searchPlaceholder'
|
|
3337
|
+
label='Search Placeholder Text'
|
|
3338
|
+
placeholder='Filter...'
|
|
3339
|
+
updateField={updateField}
|
|
3340
|
+
/>
|
|
3341
|
+
</div>
|
|
3342
|
+
)}
|
|
3122
3343
|
<Select
|
|
3123
3344
|
value={config.table.defaultSort?.column || ''}
|
|
3124
3345
|
fieldName='column'
|
|
@@ -3242,16 +3463,12 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3242
3463
|
updateField={updateField}
|
|
3243
3464
|
/>
|
|
3244
3465
|
)}
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
label='Show URL to Automatically Updated Data'
|
|
3252
|
-
updateField={updateField}
|
|
3253
|
-
/>
|
|
3254
|
-
)}
|
|
3466
|
+
<DownloadUrlControls
|
|
3467
|
+
hasUrlBackedDataSource={Boolean(isLoadedFromUrl)}
|
|
3468
|
+
showDownloadUrl={config.table.showDownloadUrl}
|
|
3469
|
+
downloadUrlLabel={config.table.downloadUrlLabel}
|
|
3470
|
+
updateField={updateField}
|
|
3471
|
+
/>
|
|
3255
3472
|
<CheckBox
|
|
3256
3473
|
value={config.table.showFullGeoNameInCSV}
|
|
3257
3474
|
section='table'
|
|
@@ -3658,6 +3875,20 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3658
3875
|
<span className='edit-label'>Allow Map Zooming</span>
|
|
3659
3876
|
</label>
|
|
3660
3877
|
)}
|
|
3878
|
+
{config.general.geoType === 'us' && (
|
|
3879
|
+
<label className='checkbox'>
|
|
3880
|
+
<input
|
|
3881
|
+
type='checkbox'
|
|
3882
|
+
checked={config.general.showClearSelectionButton !== false}
|
|
3883
|
+
onChange={event => {
|
|
3884
|
+
const _newConfig = cloneConfig(config)
|
|
3885
|
+
_newConfig.general.showClearSelectionButton = event.target.checked
|
|
3886
|
+
setConfig(_newConfig)
|
|
3887
|
+
}}
|
|
3888
|
+
/>
|
|
3889
|
+
<span className='edit-label'>Show Clear Selection Button</span>
|
|
3890
|
+
</label>
|
|
3891
|
+
)}
|
|
3661
3892
|
{config.general.type === 'bubble' && (
|
|
3662
3893
|
<label className='checkbox'>
|
|
3663
3894
|
<input
|
|
@@ -3712,73 +3943,84 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3712
3943
|
)}
|
|
3713
3944
|
{/* <AdditionalCityStyles /> */}
|
|
3714
3945
|
<>
|
|
3715
|
-
|
|
3716
|
-
config.visual.additionalCityStyles
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
</
|
|
3728
|
-
<
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3946
|
+
<GroupedList
|
|
3947
|
+
items={config.visual.additionalCityStyles}
|
|
3948
|
+
label='Additional City Styles'
|
|
3949
|
+
droppableId='map-city-styles'
|
|
3950
|
+
draggable={false}
|
|
3951
|
+
renderItem={({ label, column, value, shape }, i) => (
|
|
3952
|
+
<Accordion allowZeroExpanded key={`additional-city-style-${i}`}>
|
|
3953
|
+
<AccordionItem className='series-item series-item--chart'>
|
|
3954
|
+
<AccordionItemHeading className='series-item__title'>
|
|
3955
|
+
<AccordionItemButton className='accordion__button'>
|
|
3956
|
+
{label || column || `City Style ${i + 1}`}
|
|
3957
|
+
</AccordionItemButton>
|
|
3958
|
+
</AccordionItemHeading>
|
|
3959
|
+
<AccordionItemPanel>
|
|
3960
|
+
<div className='series-item__panel-actions'>
|
|
3961
|
+
<Button
|
|
3962
|
+
type='button'
|
|
3963
|
+
variant='danger'
|
|
3964
|
+
size='sm'
|
|
3965
|
+
className='grouped-list__remove'
|
|
3966
|
+
onClick={() => editCityStyles('remove', i, '', '')}
|
|
3967
|
+
>
|
|
3968
|
+
Remove
|
|
3969
|
+
</Button>
|
|
3970
|
+
</div>
|
|
3971
|
+
<Select
|
|
3972
|
+
label='Column with configuration value'
|
|
3973
|
+
value={column}
|
|
3974
|
+
options={columnsOptions.map(c => c.key)}
|
|
3742
3975
|
onChange={e => {
|
|
3743
|
-
editCityStyles('update', i, '
|
|
3976
|
+
editCityStyles('update', i, 'column', e.target.value)
|
|
3744
3977
|
}}
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3978
|
+
/>
|
|
3979
|
+
<label>
|
|
3980
|
+
<span className='edit-label column-heading'>Value to Trigger</span>
|
|
3981
|
+
<input
|
|
3982
|
+
type='text'
|
|
3983
|
+
value={value}
|
|
3984
|
+
onChange={e => {
|
|
3985
|
+
editCityStyles('update', i, 'value', e.target.value)
|
|
3986
|
+
}}
|
|
3987
|
+
/>
|
|
3988
|
+
</label>
|
|
3989
|
+
<Select
|
|
3990
|
+
label='Shape'
|
|
3991
|
+
value={shape}
|
|
3992
|
+
options={[
|
|
3993
|
+
{ value: '', label: '- Select Option -' },
|
|
3994
|
+
...['Circle', 'Square', 'Triangle', 'Diamond', 'Star', 'Pin']
|
|
3995
|
+
.filter(
|
|
3996
|
+
val => String(config.visual.cityStyle).toLowerCase() !== val.toLowerCase()
|
|
3997
|
+
)
|
|
3998
|
+
.map(val => ({ value: val, label: val }))
|
|
3999
|
+
]}
|
|
3766
4000
|
onChange={e => {
|
|
3767
|
-
editCityStyles('update', i, '
|
|
4001
|
+
editCityStyles('update', i, 'shape', e.target.value)
|
|
3768
4002
|
}}
|
|
3769
4003
|
/>
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
4004
|
+
<label>
|
|
4005
|
+
<span className='edit-label column-heading'>Label</span>
|
|
4006
|
+
<input
|
|
4007
|
+
key={i}
|
|
4008
|
+
type='text'
|
|
4009
|
+
value={label}
|
|
4010
|
+
onChange={e => {
|
|
4011
|
+
editCityStyles('update', i, 'label', e.target.value)
|
|
4012
|
+
}}
|
|
4013
|
+
/>
|
|
4014
|
+
</label>
|
|
4015
|
+
</AccordionItemPanel>
|
|
4016
|
+
</AccordionItem>
|
|
4017
|
+
</Accordion>
|
|
4018
|
+
)}
|
|
4019
|
+
/>
|
|
3774
4020
|
|
|
3775
|
-
<button
|
|
3776
|
-
type='button'
|
|
3777
|
-
onClick={() => editCityStyles('add', 0, '', '')}
|
|
3778
|
-
className='btn btn-primary full-width'
|
|
3779
|
-
>
|
|
4021
|
+
<Button type='button' variant='editor-primary' onClick={() => editCityStyles('add', 0, '', '')}>
|
|
3780
4022
|
Add city style
|
|
3781
|
-
</
|
|
4023
|
+
</Button>
|
|
3782
4024
|
</>
|
|
3783
4025
|
<label htmlFor='opacity'>
|
|
3784
4026
|
<TextField
|
|
@@ -3821,87 +4063,100 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3821
4063
|
</AccordionItemHeading>
|
|
3822
4064
|
<AccordionItemPanel>
|
|
3823
4065
|
{config.map.layers.length === 0 && <p>There are currently no layers.</p>}
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
<
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
4066
|
+
<GroupedList
|
|
4067
|
+
items={config.map.layers}
|
|
4068
|
+
label='Custom Map Layers'
|
|
4069
|
+
droppableId='map-custom-layers'
|
|
4070
|
+
draggable={false}
|
|
4071
|
+
renderItem={(layer, index) => (
|
|
4072
|
+
<Accordion allowZeroExpanded key={`map-layer-${index}`}>
|
|
4073
|
+
<AccordionItem className='series-item series-item--chart map-layers-list'>
|
|
4074
|
+
<AccordionItemHeading className='series-item__title map-layers-list--title'>
|
|
4075
|
+
<AccordionItemButton className='accordion__button'>
|
|
4076
|
+
{`Layer ${index + 1}: ${layer.name}`}
|
|
4077
|
+
</AccordionItemButton>
|
|
4078
|
+
</AccordionItemHeading>
|
|
4079
|
+
<AccordionItemPanel>
|
|
4080
|
+
<div className='series-item__panel-actions'>
|
|
4081
|
+
<Button
|
|
4082
|
+
type='button'
|
|
4083
|
+
variant='danger'
|
|
4084
|
+
size='sm'
|
|
4085
|
+
className='grouped-list__remove'
|
|
4086
|
+
onClick={e => handleRemoveLayer(e, index)}
|
|
4087
|
+
>
|
|
4088
|
+
Remove Layer
|
|
4089
|
+
</Button>
|
|
4090
|
+
</div>
|
|
4091
|
+
<div className='map-layers-panel'>
|
|
4092
|
+
<label htmlFor='layerName'>Layer Name:</label>
|
|
4093
|
+
<input
|
|
4094
|
+
type='text'
|
|
4095
|
+
name='layerName'
|
|
4096
|
+
value={layer.name}
|
|
4097
|
+
onChange={e => handleMapLayer(e, index, 'name')}
|
|
4098
|
+
/>
|
|
4099
|
+
<label htmlFor='layerFilename'>File:</label>
|
|
4100
|
+
<input
|
|
4101
|
+
type='text'
|
|
4102
|
+
name='layerFilename'
|
|
4103
|
+
value={layer.url}
|
|
4104
|
+
onChange={e => handleMapLayer(e, index, 'url')}
|
|
4105
|
+
/>
|
|
4106
|
+
<label htmlFor='layerNamespace'>TOPOJSON Namespace:</label>
|
|
4107
|
+
<input
|
|
4108
|
+
type='text'
|
|
4109
|
+
name='layerNamespace'
|
|
4110
|
+
value={layer.namespace}
|
|
4111
|
+
onChange={e => handleMapLayer(e, index, 'namespace')}
|
|
4112
|
+
/>
|
|
4113
|
+
<label htmlFor='layerFill'>Fill Color:</label>
|
|
4114
|
+
<input
|
|
4115
|
+
type='text'
|
|
4116
|
+
name='layerFill'
|
|
4117
|
+
value={layer.fill}
|
|
4118
|
+
onChange={e => handleMapLayer(e, index, 'fill')}
|
|
4119
|
+
/>
|
|
4120
|
+
<label htmlFor='layerFill'>Fill Opacity (%):</label>
|
|
4121
|
+
<input
|
|
4122
|
+
type='number'
|
|
4123
|
+
min={0}
|
|
4124
|
+
max={100}
|
|
4125
|
+
name='layerFill'
|
|
4126
|
+
value={layer.fillOpacity ? layer.fillOpacity * 100 : ''}
|
|
4127
|
+
onChange={e => handleMapLayer(e, index, 'fillOpacity')}
|
|
4128
|
+
/>
|
|
4129
|
+
<label htmlFor='layerStroke'>Stroke Color:</label>
|
|
4130
|
+
<input
|
|
4131
|
+
type='text'
|
|
4132
|
+
name='layerStroke'
|
|
4133
|
+
value={layer.stroke}
|
|
4134
|
+
onChange={e => handleMapLayer(e, index, 'stroke')}
|
|
4135
|
+
/>
|
|
4136
|
+
<label htmlFor='layerStroke'>Stroke Width:</label>
|
|
4137
|
+
<input
|
|
4138
|
+
type='number'
|
|
4139
|
+
min={0}
|
|
4140
|
+
max={5}
|
|
4141
|
+
name='layerStrokeWidth'
|
|
4142
|
+
value={layer.strokeWidth}
|
|
4143
|
+
onChange={e => handleMapLayer(e, index, 'strokeWidth')}
|
|
4144
|
+
/>
|
|
4145
|
+
<label htmlFor='layerTooltip'>Tooltip:</label>
|
|
4146
|
+
<textarea
|
|
4147
|
+
name='layerTooltip'
|
|
4148
|
+
value={layer.tooltip}
|
|
4149
|
+
onChange={e => handleMapLayer(e, index, 'tooltip')}
|
|
4150
|
+
></textarea>
|
|
4151
|
+
</div>
|
|
4152
|
+
</AccordionItemPanel>
|
|
4153
|
+
</AccordionItem>
|
|
4154
|
+
</Accordion>
|
|
4155
|
+
)}
|
|
4156
|
+
/>
|
|
4157
|
+
<Button type='button' variant='editor-primary' onClick={handleAddLayer}>
|
|
3903
4158
|
Add Map Layer
|
|
3904
|
-
</
|
|
4159
|
+
</Button>
|
|
3905
4160
|
<p className='layer-purpose-details'>
|
|
3906
4161
|
Context should be added to your visualization or associated page to describe the significance of
|
|
3907
4162
|
layers that are added to maps.
|