@cdc/map 4.25.10 → 4.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/typescript-organizer.md +118 -0
- package/dist/{cdcmap-fce76882.es.js → cdcmap-BnB1QM5d.es.js} +6 -13
- package/dist/{cdcmap-c55ac1ea.es.js → cdcmap-D6CG2-Hb.es.js} +5 -12
- package/dist/{cdcmap-31a33da1.es.js → cdcmap-MXgURbdZ.es.js} +6 -13
- package/dist/{cdcmap-1a1724a1.es.js → cdcmap-dgT_1dIT.es.js} +136 -151
- package/dist/cdcmap.js +58397 -55987
- package/examples/example-city-state.json +9 -1
- package/examples/multi-country-centering.json +45 -0
- package/examples/private/city_styles_variable.json +877 -0
- package/examples/private/colors-2.json +221 -0
- package/examples/private/colors.json +221 -0
- package/examples/private/map-filter-issue.json +2260 -0
- package/examples/private/map-legend.json +5303 -0
- package/index.html +27 -36
- package/package.json +6 -5
- package/src/CdcMapComponent.tsx +86 -26
- package/src/_stories/CdcMap.ColumnWrap.stories.tsx +31 -0
- package/src/_stories/CdcMap.DistrictOfColumbia.stories.tsx +320 -0
- package/src/_stories/CdcMap.Editor.stories.tsx +3426 -0
- package/src/_stories/CdcMap.SmallMultiples.stories.tsx +35 -0
- package/src/_stories/CdcMap.stories.tsx +116 -4
- package/src/_stories/_mock/column-wrap-test.json +265 -0
- package/src/_stories/_mock/multi-country-hide.json +78 -0
- package/src/_stories/_mock/multi-country.json +95 -0
- package/src/_stories/_mock/multi-state.json +887 -20403
- package/src/_stories/_mock/small_multiples/multi-state-small-multiples.json +8399 -0
- package/src/_stories/_mock/small_multiples/region-small-multiples.json +657 -0
- package/src/_stories/_mock/small_multiples/wastewater-map-small-multiples.json +221 -0
- package/src/_stories/_mock/usa-state-gradient.json +3 -4
- package/src/components/BubbleList.tsx +1 -1
- package/src/components/CityList.tsx +24 -18
- package/src/components/EditorPanel/components/EditorPanel.tsx +2380 -2206
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +55 -93
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +0 -19
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +27 -37
- package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +351 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/Geo.tsx +20 -3
- package/src/components/Legend/components/Legend.tsx +58 -75
- package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +1 -1
- package/src/components/Legend/components/index.scss +23 -6
- package/src/components/NavigationMenu.tsx +16 -13
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +163 -0
- package/src/components/SmallMultiples/SmallMultiples.css +32 -0
- package/src/components/SmallMultiples/SmallMultiples.tsx +150 -0
- package/src/components/SmallMultiples/SynchronizedTooltip.tsx +105 -0
- package/src/components/SmallMultiples/index.tsx +3 -0
- package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +18 -3
- package/src/components/UsaMap/components/TerritoriesSection.tsx +26 -12
- package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +30 -4
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +29 -9
- package/src/components/UsaMap/components/Territory/TerritoryShape.ts +7 -0
- package/src/components/UsaMap/components/UsaMap.County.tsx +16 -4
- package/src/components/UsaMap/components/UsaMap.Region.tsx +14 -1
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +29 -12
- package/src/components/UsaMap/components/UsaMap.State.tsx +30 -5
- package/src/components/UsaMap/helpers/map.ts +2 -2
- package/src/components/UsaMap/helpers/shapes.ts +9 -6
- package/src/components/WorldMap/WorldMap.tsx +81 -11
- package/src/data/initial-state.js +11 -0
- package/src/data/supported-geos.js +8 -76
- package/src/helpers/addUIDs.ts +13 -2
- package/src/helpers/applyColorToLegend.ts +25 -1
- package/src/helpers/applyLegendToRow.ts +5 -3
- package/src/helpers/constants.ts +3 -15
- package/src/helpers/displayGeoName.ts +22 -4
- package/src/helpers/generateRuntimeFilters.ts +1 -1
- package/src/helpers/generateRuntimeLegend.ts +1 -3
- package/src/helpers/generateRuntimeLegendHash.ts +1 -1
- package/src/helpers/getCountriesPicked.ts +103 -0
- package/src/helpers/getMapContainerClasses.ts +7 -0
- package/src/helpers/getPatternForRow.ts +2 -5
- package/src/helpers/index.ts +2 -4
- package/src/helpers/isLegendItemDisabled.ts +2 -2
- package/src/helpers/resetLegendToggles.ts +1 -0
- package/src/helpers/smallMultiplesHelpers.ts +359 -0
- package/src/helpers/tests/hashObj.test.ts +1 -1
- package/src/helpers/tests/titleCase.test.ts +76 -0
- package/src/helpers/titleCase.ts +13 -13
- package/src/helpers/toggleLegendActive.ts +76 -8
- package/src/helpers/urlDataHelpers.ts +1 -1
- package/src/hooks/useCountryZoom.tsx +241 -0
- package/src/hooks/useGeoClickHandler.ts +1 -1
- package/src/hooks/useProgrammaticMapTooltip.ts +110 -0
- package/src/hooks/useResizeObserver.ts +8 -2
- package/src/hooks/useStateZoom.tsx +7 -4
- package/src/hooks/useSynchronizedGeographies.ts +56 -0
- package/src/index.jsx +1 -0
- package/src/scss/editor-panel.scss +4 -440
- package/src/scss/main.scss +1 -1
- package/src/scss/map.scss +12 -15
- package/src/store/map.actions.ts +7 -7
- package/src/test/CdcMap.test.jsx +1 -1
- package/src/types/MapConfig.ts +32 -11
- package/src/types/MapContext.ts +6 -0
- package/src/types/runtimeLegend.ts +2 -1
- package/LICENSE +0 -201
- package/src/components/DataTable.tsx +0 -413
- package/src/components/EditorPanel/components/Inputs.tsx +0 -59
- package/src/components/MapControls.tsx +0 -44
- package/src/helpers/getUniqueValues.ts +0 -19
- package/src/helpers/hashObj.ts +0 -25
- package/src/hooks/useActiveElement.ts +0 -19
- package/src/hooks/useLegendSeparators.ts +0 -26
- package/src/scss/mixins.scss +0 -47
- package/src/types/Annotations.ts +0 -24
- /package/dist/{cdcmap-548642e6.es.js → cdcmap-Ct2SB0vL.es.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext, useEffect, useState, useMemo } from 'react'
|
|
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
4
|
|
|
@@ -20,9 +20,11 @@ import Layout from '@cdc/core/components/Layout'
|
|
|
20
20
|
|
|
21
21
|
// Data
|
|
22
22
|
import { mapColorPalettes as colorPalettes } from '@cdc/core/data/colorPalettes'
|
|
23
|
-
import { supportedStatesFipsCodes } from '../../../data/supported-geos.js'
|
|
23
|
+
import { supportedStatesFipsCodes, supportedCountries } from '../../../data/supported-geos.js'
|
|
24
|
+
import { getSupportedCountryOptions } from '../../../helpers/getCountriesPicked'
|
|
24
25
|
|
|
25
26
|
// Components - Core
|
|
27
|
+
import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel/EditorPanel'
|
|
26
28
|
import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
|
|
27
29
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
28
30
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
@@ -47,8 +49,12 @@ import { MapContext } from '../../../types/MapContext.js'
|
|
|
47
49
|
import Alert from '@cdc/core/components/Alert'
|
|
48
50
|
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
49
51
|
import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
|
|
52
|
+
import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
|
|
50
53
|
import useColumnsRequiredChecker from '../../../hooks/useColumnsRequiredChecker'
|
|
51
|
-
import { addUIDs
|
|
54
|
+
import { addUIDs } from '../../../helpers'
|
|
55
|
+
import generateRuntimeData from '../../../helpers/generateRuntimeData'
|
|
56
|
+
|
|
57
|
+
import '@cdc/core/styles/v2/components/editor.scss'
|
|
52
58
|
import './editorPanel.styles.css'
|
|
53
59
|
import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
|
|
54
60
|
import { Datasets } from '@cdc/core/types/DataSet'
|
|
@@ -56,8 +62,10 @@ import MultiSelect from '@cdc/core/components/MultiSelect'
|
|
|
56
62
|
import { paletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
57
63
|
import { isV1Palette, getCurrentPaletteName, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
|
|
58
64
|
import { USE_V2_MIGRATION } from '@cdc/core/helpers/constants'
|
|
65
|
+
import { isCoveDeveloperMode } from '@cdc/core/helpers/queryStringUtils'
|
|
59
66
|
import { PaletteSelector, DeveloperPaletteRollback } from '@cdc/core/components/PaletteSelector'
|
|
60
67
|
import PaletteConversionModal from '@cdc/core/components/PaletteConversionModal'
|
|
68
|
+
import { CustomColorsEditor } from '@cdc/core/components/CustomColorsEditor'
|
|
61
69
|
|
|
62
70
|
type MapEditorPanelProps = {
|
|
63
71
|
datasets?: Datasets
|
|
@@ -80,10 +88,30 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
80
88
|
const { columnsRequiredChecker } = useColumnsRequiredChecker()
|
|
81
89
|
const dispatch = useContext(MapDispatchContext)
|
|
82
90
|
const { general, columns, legend, table, tooltips } = config
|
|
83
|
-
|
|
91
|
+
|
|
92
|
+
// Get columns from data with fallback to datasets (for dashboard context)
|
|
93
|
+
const columnsInData = useMemo(() => {
|
|
94
|
+
// First try config.data
|
|
95
|
+
if (config?.data?.[0]) {
|
|
96
|
+
return Object.keys(config.data[0])
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Fallback to datasets using config.dataKey (for dashboard visualizations)
|
|
100
|
+
if (datasets && config?.dataKey) {
|
|
101
|
+
const assignedDataset = datasets[config.dataKey]
|
|
102
|
+
if (assignedDataset?.data?.[0]) {
|
|
103
|
+
return Object.keys(assignedDataset.data[0])
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return []
|
|
108
|
+
}, [
|
|
109
|
+
config?.data?.length > 0 ? JSON.stringify(Object.keys(config.data[0])) : null,
|
|
110
|
+
datasets?.[config?.dataKey as string]?.data?.length,
|
|
111
|
+
config?.dataKey
|
|
112
|
+
])
|
|
84
113
|
|
|
85
114
|
const [loadedDefault, setLoadedDefault] = useState(false)
|
|
86
|
-
const [displayPanel, setDisplayPanel] = useState(true)
|
|
87
115
|
const [activeFilterValueForDescription, setActiveFilterValueForDescription] = useState([0, 0])
|
|
88
116
|
const [showConversionModal, setShowConversionModal] = useState(false)
|
|
89
117
|
const [pendingPaletteSelection, setPendingPaletteSelection] = useState<{
|
|
@@ -95,13 +123,6 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
95
123
|
MapLayerHandlers: { handleMapLayer, handleAddLayer, handleRemoveLayer }
|
|
96
124
|
} = useMapLayers(config, setConfig, false, tooltipId)
|
|
97
125
|
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
// Pass up to Editor if needed
|
|
100
|
-
if (setParentConfig) {
|
|
101
|
-
setParentConfig(convertStateToConfig())
|
|
102
|
-
}
|
|
103
|
-
}, [config])
|
|
104
|
-
|
|
105
126
|
const categoryMove = (idx1, idx2) => {
|
|
106
127
|
let categoryValuesOrder = getCategoryValuesOrder()
|
|
107
128
|
let [movedItem] = categoryValuesOrder.splice(idx1, 1)
|
|
@@ -703,7 +724,26 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
703
724
|
})
|
|
704
725
|
|
|
705
726
|
if (config) {
|
|
706
|
-
const newData = generateRuntimeData(config)
|
|
727
|
+
const newData = generateRuntimeData(config, [], 0, legend.type === 'category')
|
|
728
|
+
dispatch({ type: 'SET_RUNTIME_DATA', payload: newData })
|
|
729
|
+
}
|
|
730
|
+
break
|
|
731
|
+
case 'chooseCountry':
|
|
732
|
+
let countryData = value.map(countryName => ({
|
|
733
|
+
iso: Object.keys(supportedCountries).find(key => supportedCountries[key][0] === countryName),
|
|
734
|
+
name: countryName
|
|
735
|
+
}))
|
|
736
|
+
|
|
737
|
+
setConfig({
|
|
738
|
+
...config,
|
|
739
|
+
general: {
|
|
740
|
+
...config.general,
|
|
741
|
+
countriesPicked: countryData
|
|
742
|
+
}
|
|
743
|
+
})
|
|
744
|
+
|
|
745
|
+
if (config) {
|
|
746
|
+
const newData = generateRuntimeData(config, [], 0, legend.type === 'category')
|
|
707
747
|
dispatch({ type: 'SET_RUNTIME_DATA', payload: newData })
|
|
708
748
|
}
|
|
709
749
|
break
|
|
@@ -988,13 +1028,6 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
988
1028
|
columnsRequiredChecker()
|
|
989
1029
|
}, [config])
|
|
990
1030
|
|
|
991
|
-
useEffect(() => {
|
|
992
|
-
const newConfig = convertStateToConfig()
|
|
993
|
-
if (isEditor && setParentConfig) {
|
|
994
|
-
setParentConfig(newConfig)
|
|
995
|
-
}
|
|
996
|
-
}, [config])
|
|
997
|
-
|
|
998
1031
|
const columnsOptions = [
|
|
999
1032
|
<option value='' key={'Select Option'}>
|
|
1000
1033
|
- Select Option -
|
|
@@ -1029,14 +1062,6 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1029
1062
|
|
|
1030
1063
|
const updateField = updateFieldFactory(config, setConfig)
|
|
1031
1064
|
|
|
1032
|
-
const onBackClick = () => {
|
|
1033
|
-
setDisplayPanel(!displayPanel)
|
|
1034
|
-
setConfig({
|
|
1035
|
-
...config,
|
|
1036
|
-
showEditorPanel: !displayPanel
|
|
1037
|
-
})
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
1065
|
const StateOptionList = () => {
|
|
1041
1066
|
const arrOfArrays = Object.entries(supportedStatesFipsCodes)
|
|
1042
1067
|
|
|
@@ -1056,6 +1081,16 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1056
1081
|
return options
|
|
1057
1082
|
}
|
|
1058
1083
|
|
|
1084
|
+
const CountryOptionList = () => {
|
|
1085
|
+
const countryOptions = getSupportedCountryOptions()
|
|
1086
|
+
|
|
1087
|
+
return countryOptions.map(({ value, label }) => (
|
|
1088
|
+
<option key={value} value={label}>
|
|
1089
|
+
{label}
|
|
1090
|
+
</option>
|
|
1091
|
+
))
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1059
1094
|
const filterValueOptionList = []
|
|
1060
1095
|
|
|
1061
1096
|
if (runtimeFilters.length > 0) {
|
|
@@ -1116,2267 +1151,2406 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1116
1151
|
|
|
1117
1152
|
const isLoadedFromUrl = config?.dataKey?.includes('http://') || config?.dataKey?.includes('https://')
|
|
1118
1153
|
|
|
1154
|
+
// Custom convertStateToConfig for map with map-specific logic
|
|
1155
|
+
const customConvertStateToConfig = () => {
|
|
1156
|
+
let strippedState = cloneConfig(config) // Deep copy
|
|
1157
|
+
|
|
1158
|
+
// Strip ref
|
|
1159
|
+
delete strippedState['']
|
|
1160
|
+
|
|
1161
|
+
if (strippedState.columns.geo.name && strippedState.columns.primary.name) {
|
|
1162
|
+
delete strippedState.newViz
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// Remove the legend
|
|
1166
|
+
let strippedLegend = _.cloneDeep(config.legend)
|
|
1167
|
+
|
|
1168
|
+
delete strippedLegend.disabledAmt
|
|
1169
|
+
|
|
1170
|
+
strippedState.legend = strippedLegend
|
|
1171
|
+
|
|
1172
|
+
// Remove default data marker if the user started this map from default data
|
|
1173
|
+
delete strippedState.defaultData
|
|
1174
|
+
|
|
1175
|
+
// Remove tooltips if they're active in the editor
|
|
1176
|
+
strippedState.general = _.cloneDeep(config.general)
|
|
1177
|
+
|
|
1178
|
+
strippedState.general.showSidebar = 'hidden'
|
|
1179
|
+
|
|
1180
|
+
return strippedState
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1119
1183
|
return (
|
|
1120
|
-
<
|
|
1121
|
-
<
|
|
1184
|
+
<React.Fragment>
|
|
1185
|
+
<BaseEditorPanel
|
|
1186
|
+
config={config}
|
|
1187
|
+
updateConfig={setConfig as (config: any) => void}
|
|
1188
|
+
loading={false}
|
|
1189
|
+
setParentConfig={setParentConfig as ((config: any) => void) | undefined}
|
|
1122
1190
|
isDashboard={isDashboard}
|
|
1123
|
-
displayPanel={displayPanel}
|
|
1124
1191
|
title='Configure Map'
|
|
1125
|
-
onBackClick={onBackClick}
|
|
1126
1192
|
>
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
{' '}
|
|
1131
|
-
{/* Type */}
|
|
1132
|
-
<AccordionItemHeading>
|
|
1133
|
-
<AccordionItemButton>Type</AccordionItemButton>
|
|
1134
|
-
</AccordionItemHeading>
|
|
1135
|
-
<AccordionItemPanel>
|
|
1136
|
-
<label>
|
|
1137
|
-
<span className='edit-label column-heading'>
|
|
1138
|
-
<span>Geography</span>
|
|
1139
|
-
</span>
|
|
1140
|
-
<ul className='geo-buttons d-grid' style={{ gridTemplateColumns: 'repeat(2, 1fr)', gap: '8px' }}>
|
|
1141
|
-
<button
|
|
1142
|
-
className={`${
|
|
1143
|
-
config.general.geoType === 'us' || config.general.geoType === 'us-county' ? 'active' : ''
|
|
1144
|
-
} full-width`}
|
|
1145
|
-
onClick={e => {
|
|
1146
|
-
e.preventDefault()
|
|
1147
|
-
handleEditorChanges('geoType', 'us')
|
|
1148
|
-
}}
|
|
1149
|
-
>
|
|
1150
|
-
<UsaGraphic />
|
|
1151
|
-
<span>United States</span>
|
|
1152
|
-
</button>
|
|
1153
|
-
<button
|
|
1154
|
-
className={`${config.general.geoType === 'us-region' ? 'active' : ''} full-width`}
|
|
1155
|
-
onClick={e => {
|
|
1156
|
-
e.preventDefault()
|
|
1157
|
-
handleEditorChanges('geoType', 'us-region')
|
|
1158
|
-
}}
|
|
1159
|
-
>
|
|
1160
|
-
<UsaRegionGraphic />
|
|
1161
|
-
<span>U.S. Region</span>
|
|
1162
|
-
</button>
|
|
1163
|
-
<button
|
|
1164
|
-
className={`${config.general.geoType === 'world' ? 'active' : ''} full-width`}
|
|
1165
|
-
onClick={e => {
|
|
1166
|
-
e.preventDefault()
|
|
1167
|
-
handleEditorChanges('geoType', 'world')
|
|
1168
|
-
}}
|
|
1169
|
-
>
|
|
1170
|
-
<WorldGraphic />
|
|
1171
|
-
<span>World</span>
|
|
1172
|
-
</button>
|
|
1173
|
-
<button
|
|
1174
|
-
className={`${config.general.geoType === 'single-state' ? 'active' : ''} full-width`}
|
|
1175
|
-
onClick={e => {
|
|
1176
|
-
e.preventDefault()
|
|
1177
|
-
handleEditorChanges('geoType', 'single-state')
|
|
1178
|
-
}}
|
|
1179
|
-
>
|
|
1180
|
-
<AlabamaGraphic />
|
|
1181
|
-
<span>U.S. State</span>
|
|
1182
|
-
</button>
|
|
1183
|
-
</ul>
|
|
1184
|
-
</label>
|
|
1185
|
-
{/* Select > State or County Map */}
|
|
1186
|
-
{(config.general.geoType === 'us' || config.general.geoType === 'us-county') && (
|
|
1187
|
-
<Select
|
|
1188
|
-
label='Geography Subtype'
|
|
1189
|
-
value={config.general.geoType}
|
|
1190
|
-
options={[
|
|
1191
|
-
{ value: 'us', label: 'US State-Level' },
|
|
1192
|
-
{ value: 'us-county', label: 'US County-Level' }
|
|
1193
|
-
]}
|
|
1194
|
-
onChange={event => {
|
|
1195
|
-
handleEditorChanges('geoType', event.target.value)
|
|
1196
|
-
}}
|
|
1197
|
-
/>
|
|
1198
|
-
)}
|
|
1199
|
-
{(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
|
|
1200
|
-
<Select
|
|
1201
|
-
label='County Census Year'
|
|
1202
|
-
value={config.general.countyCensusYear || '2019'}
|
|
1203
|
-
options={[
|
|
1204
|
-
{ value: '2022', label: '2022' },
|
|
1205
|
-
{ value: '2021', label: '2021' },
|
|
1206
|
-
{ value: '2020', label: '2020' },
|
|
1207
|
-
{ value: '2019', label: '2019' },
|
|
1208
|
-
{ value: '2015', label: '2015' },
|
|
1209
|
-
{ value: '2014', label: '2014' },
|
|
1210
|
-
{ value: '2013', label: '2013' }
|
|
1211
|
-
]}
|
|
1212
|
-
onChange={event => {
|
|
1213
|
-
handleEditorChanges('countyCensusYear', event.target.value)
|
|
1214
|
-
}}
|
|
1215
|
-
/>
|
|
1216
|
-
)}
|
|
1217
|
-
{(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
|
|
1218
|
-
<Select
|
|
1219
|
-
label='Filter Controlling County Census Year'
|
|
1220
|
-
value={config.general.filterControlsCountyYear || ''}
|
|
1221
|
-
options={[
|
|
1222
|
-
{ value: '', label: 'None' },
|
|
1223
|
-
...(config.filters
|
|
1224
|
-
? config.filters.map(filter => ({ value: filter.columnName, label: filter.columnName }))
|
|
1225
|
-
: [])
|
|
1226
|
-
]}
|
|
1227
|
-
onChange={event => {
|
|
1228
|
-
handleEditorChanges('filterControlsCountyYear', event.target.value)
|
|
1229
|
-
}}
|
|
1230
|
-
/>
|
|
1231
|
-
)}
|
|
1232
|
-
|
|
1233
|
-
{config.general.geoType === 'single-state' && runtimeData && (
|
|
1234
|
-
<Select
|
|
1235
|
-
label='Filter Controlling State Picked'
|
|
1236
|
-
value={config.general.filterControlsStatesPicked || ''}
|
|
1237
|
-
options={[
|
|
1238
|
-
{ value: '', label: 'None' },
|
|
1239
|
-
...(runtimeData && columnsInData?.map(col => ({ value: col, label: col })))
|
|
1240
|
-
]}
|
|
1241
|
-
onChange={event => {
|
|
1242
|
-
handleEditorChanges('filterControlsStatesPicked', event.target.value)
|
|
1243
|
-
}}
|
|
1244
|
-
/>
|
|
1245
|
-
)}
|
|
1246
|
-
|
|
1247
|
-
{/* Type */}
|
|
1248
|
-
{/* Select > Filter a state */}
|
|
1249
|
-
{config.general.geoType === 'single-state' && (
|
|
1250
|
-
<label>
|
|
1251
|
-
<span>States Selector</span>
|
|
1252
|
-
<MultiSelect
|
|
1253
|
-
selected={config.general.statesPicked.map(state => state.stateName)}
|
|
1254
|
-
options={StateOptionList().map(option => ({
|
|
1255
|
-
value: option.props.value,
|
|
1256
|
-
label: option.props.children
|
|
1257
|
-
}))}
|
|
1258
|
-
fieldName={'statesPicked'}
|
|
1259
|
-
updateField={(_, __, ___, selectedOptions) => {
|
|
1260
|
-
handleEditorChanges('chooseState', selectedOptions)
|
|
1261
|
-
}}
|
|
1262
|
-
/>
|
|
1263
|
-
</label>
|
|
1264
|
-
)}
|
|
1265
|
-
{/* Type */}
|
|
1266
|
-
<Select
|
|
1267
|
-
label={
|
|
1268
|
-
<>
|
|
1269
|
-
Map Type
|
|
1270
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1271
|
-
<Tooltip.Target>
|
|
1272
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1273
|
-
</Tooltip.Target>
|
|
1274
|
-
<Tooltip.Content>
|
|
1275
|
-
<p>
|
|
1276
|
-
Select "Data" to create a color-coded data map. To create a navigation-only map, select
|
|
1277
|
-
"Navigation."
|
|
1278
|
-
</p>
|
|
1279
|
-
</Tooltip.Content>
|
|
1280
|
-
</Tooltip>
|
|
1281
|
-
</>
|
|
1282
|
-
}
|
|
1283
|
-
value={config.general.type}
|
|
1284
|
-
options={[
|
|
1285
|
-
{ value: 'data', label: 'Data' },
|
|
1286
|
-
...(config.general.geoType === 'us-county' ? [{ value: 'us-geocode', label: 'Geocode' }] : []),
|
|
1287
|
-
...(config.general.geoType === 'world' ? [{ value: 'world-geocode', label: 'Geocode' }] : []),
|
|
1288
|
-
...(config.general.geoType !== 'us-county' ? [{ value: 'navigation', label: 'Navigation' }] : []),
|
|
1289
|
-
...(config.general.geoType === 'world' || config.general.geoType === 'us'
|
|
1290
|
-
? [{ value: 'bubble', label: 'Bubble' }]
|
|
1291
|
-
: [])
|
|
1292
|
-
]}
|
|
1293
|
-
onChange={event => {
|
|
1294
|
-
handleEditorChanges('editorMapType', event.target.value)
|
|
1295
|
-
}}
|
|
1296
|
-
/>
|
|
1297
|
-
|
|
1298
|
-
{/* Navigation Behavior */}
|
|
1299
|
-
{(config.general.type === 'navigation' || config.general.type === 'data') && (
|
|
1300
|
-
<Select
|
|
1301
|
-
label='Navigation Behavior'
|
|
1302
|
-
value={config.general.navigationTarget}
|
|
1303
|
-
options={[
|
|
1304
|
-
{ value: '_self', label: 'Same Window' },
|
|
1305
|
-
{ value: '_blank', label: 'New Window' }
|
|
1306
|
-
]}
|
|
1307
|
-
onChange={event => {
|
|
1308
|
-
const _newConfig = cloneConfig(config)
|
|
1309
|
-
_newConfig.general.navigationTarget = event.target.value
|
|
1310
|
-
setConfig(_newConfig)
|
|
1311
|
-
}}
|
|
1312
|
-
/>
|
|
1313
|
-
)}
|
|
1314
|
-
<label>
|
|
1315
|
-
<span className='edit-label'>Data Classification Type</span>
|
|
1316
|
-
<div>
|
|
1317
|
-
<label>
|
|
1318
|
-
<input
|
|
1319
|
-
type='radio'
|
|
1320
|
-
name='equalnumber'
|
|
1321
|
-
value='equalnumber'
|
|
1322
|
-
checked={config.legend.type === 'equalnumber' || config.legend.type === 'equalinterval'}
|
|
1323
|
-
onChange={e => handleEditorChanges('classificationType', e.target.value)}
|
|
1324
|
-
/>
|
|
1325
|
-
Numeric/Quantitative
|
|
1326
|
-
</label>
|
|
1327
|
-
<label>
|
|
1328
|
-
<input
|
|
1329
|
-
type='radio'
|
|
1330
|
-
name='category'
|
|
1331
|
-
value='category'
|
|
1332
|
-
checked={config.legend.type === 'category'}
|
|
1333
|
-
onChange={e => handleEditorChanges('classificationType', e.target.value)}
|
|
1334
|
-
/>
|
|
1335
|
-
Categorical
|
|
1336
|
-
</label>
|
|
1337
|
-
</div>
|
|
1338
|
-
</label>
|
|
1339
|
-
|
|
1340
|
-
{/* Display as Hex */}
|
|
1341
|
-
{general.geoType === 'us' && general.type !== 'navigation' && general.type !== 'bubble' && (
|
|
1342
|
-
<label className='checkbox mt-4'>
|
|
1343
|
-
<input
|
|
1344
|
-
type='checkbox'
|
|
1345
|
-
checked={config.general.displayAsHex}
|
|
1346
|
-
onChange={event => {
|
|
1347
|
-
const _newConfig = cloneConfig(config)
|
|
1348
|
-
_newConfig.general.displayAsHex = event.target.checked
|
|
1349
|
-
setConfig(_newConfig)
|
|
1350
|
-
}}
|
|
1351
|
-
/>
|
|
1352
|
-
<span className='edit-label'>Display As Hex Map</span>
|
|
1353
|
-
</label>
|
|
1354
|
-
)}
|
|
1355
|
-
|
|
1356
|
-
{/* Shapes on Hex */}
|
|
1357
|
-
<label className='checkbox mt-4'>
|
|
1358
|
-
<input
|
|
1359
|
-
type='checkbox'
|
|
1360
|
-
checked={config.hexMap.type === 'shapes'}
|
|
1361
|
-
onChange={event => {
|
|
1362
|
-
setConfig({
|
|
1363
|
-
...config,
|
|
1364
|
-
hexMap: {
|
|
1365
|
-
...config.hexMap,
|
|
1366
|
-
type: event.target.checked ? 'shapes' : 'standard'
|
|
1367
|
-
}
|
|
1368
|
-
})
|
|
1369
|
-
}}
|
|
1370
|
-
/>
|
|
1371
|
-
<span className='edit-label'>Display Shapes on Hex Map</span>
|
|
1372
|
-
</label>
|
|
1373
|
-
<HexSetting.ShapeColumns columnsOptions={columnsOptions} />
|
|
1374
|
-
|
|
1375
|
-
{'us' === config.general.geoType &&
|
|
1376
|
-
'bubble' !== config.general.type &&
|
|
1377
|
-
false === config.general.displayAsHex && (
|
|
1378
|
-
<CheckBox
|
|
1379
|
-
label='Show state labels'
|
|
1380
|
-
checked={config.general.displayStateLabels}
|
|
1381
|
-
onChange={event => {
|
|
1382
|
-
handleEditorChanges('displayStateLabels', event.target.checked)
|
|
1383
|
-
}}
|
|
1384
|
-
tooltip={
|
|
1385
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1386
|
-
<Tooltip.Target>
|
|
1387
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1388
|
-
</Tooltip.Target>
|
|
1389
|
-
<Tooltip.Content>
|
|
1390
|
-
<p>Recommended set to display for Section 508 compliance.</p>
|
|
1391
|
-
</Tooltip.Content>
|
|
1392
|
-
</Tooltip>
|
|
1393
|
-
}
|
|
1394
|
-
/>
|
|
1395
|
-
)}
|
|
1396
|
-
|
|
1397
|
-
{'us' === config.general.geoType && (
|
|
1398
|
-
<label className='checkbox'>
|
|
1399
|
-
<input
|
|
1400
|
-
type='checkbox'
|
|
1401
|
-
checked={general.territoriesAlwaysShow || false}
|
|
1402
|
-
onChange={event => {
|
|
1403
|
-
const _newConfig = cloneConfig(config)
|
|
1404
|
-
_newConfig.general.territoriesAlwaysShow = event.target.checked
|
|
1405
|
-
setConfig(_newConfig)
|
|
1406
|
-
}}
|
|
1407
|
-
/>
|
|
1408
|
-
<span className='edit-label'>Show All Territories</span>
|
|
1409
|
-
</label>
|
|
1410
|
-
)}
|
|
1411
|
-
</AccordionItemPanel>
|
|
1412
|
-
</AccordionItem>
|
|
1413
|
-
<AccordionItem>
|
|
1414
|
-
{' '}
|
|
1415
|
-
{/* General */}
|
|
1416
|
-
<AccordionItemHeading>
|
|
1417
|
-
<AccordionItemButton>General</AccordionItemButton>
|
|
1418
|
-
</AccordionItemHeading>
|
|
1419
|
-
<AccordionItemPanel>
|
|
1420
|
-
<TextField
|
|
1421
|
-
value={general.title}
|
|
1422
|
-
data-testid='title-input'
|
|
1423
|
-
updateField={updateField}
|
|
1424
|
-
section='general'
|
|
1425
|
-
fieldName='title'
|
|
1426
|
-
id='title'
|
|
1427
|
-
label='Title'
|
|
1428
|
-
placeholder='Map Title'
|
|
1429
|
-
tooltip={
|
|
1430
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1431
|
-
<Tooltip.Target>
|
|
1432
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1433
|
-
</Tooltip.Target>
|
|
1434
|
-
<Tooltip.Content>
|
|
1435
|
-
<p>
|
|
1436
|
-
Title is required to set the name of the download file but can be hidden using the option below.
|
|
1437
|
-
</p>
|
|
1438
|
-
</Tooltip.Content>
|
|
1439
|
-
</Tooltip>
|
|
1440
|
-
}
|
|
1441
|
-
/>
|
|
1442
|
-
<label className='checkbox'>
|
|
1443
|
-
<input
|
|
1444
|
-
type='checkbox'
|
|
1445
|
-
checked={config.general.showTitle || false}
|
|
1446
|
-
onChange={event => {
|
|
1447
|
-
const _newConfig = cloneConfig(config)
|
|
1448
|
-
_newConfig.general.showTitle = event.target.checked
|
|
1449
|
-
setConfig(_newConfig)
|
|
1450
|
-
}}
|
|
1451
|
-
/>
|
|
1452
|
-
<span className='edit-label'>Show Title</span>
|
|
1453
|
-
</label>
|
|
1454
|
-
<TextField
|
|
1455
|
-
value={general.superTitle || ''}
|
|
1456
|
-
updateField={updateField}
|
|
1457
|
-
section='general'
|
|
1458
|
-
fieldName='superTitle'
|
|
1459
|
-
label='Super Title'
|
|
1460
|
-
tooltip={
|
|
1461
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1462
|
-
<Tooltip.Target>
|
|
1463
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1464
|
-
</Tooltip.Target>
|
|
1465
|
-
<Tooltip.Content>
|
|
1466
|
-
<p>Super Title</p>
|
|
1467
|
-
</Tooltip.Content>
|
|
1468
|
-
</Tooltip>
|
|
1469
|
-
}
|
|
1470
|
-
/>
|
|
1471
|
-
<TextField
|
|
1472
|
-
type='textarea'
|
|
1473
|
-
value={general.introText}
|
|
1474
|
-
updateField={updateField}
|
|
1475
|
-
section='general'
|
|
1476
|
-
fieldName='introText'
|
|
1477
|
-
label='Message'
|
|
1478
|
-
tooltip={
|
|
1479
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1480
|
-
<Tooltip.Target>
|
|
1481
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1482
|
-
</Tooltip.Target>
|
|
1483
|
-
<Tooltip.Content>
|
|
1484
|
-
<p>Intro Text</p>
|
|
1485
|
-
</Tooltip.Content>
|
|
1486
|
-
</Tooltip>
|
|
1487
|
-
}
|
|
1488
|
-
/>
|
|
1489
|
-
<TextField
|
|
1490
|
-
type='textarea'
|
|
1491
|
-
value={general.subtext}
|
|
1492
|
-
updateField={updateField}
|
|
1493
|
-
section='general'
|
|
1494
|
-
fieldName='subtext'
|
|
1495
|
-
label='Subtext'
|
|
1496
|
-
tooltip={
|
|
1497
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1498
|
-
<Tooltip.Target>
|
|
1499
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1500
|
-
</Tooltip.Target>
|
|
1501
|
-
<Tooltip.Content>
|
|
1502
|
-
<p>
|
|
1503
|
-
Enter supporting text to display below the data visualization, if applicable. The following HTML
|
|
1504
|
-
tags are supported: strong, em, sup, and sub.
|
|
1505
|
-
</p>
|
|
1506
|
-
</Tooltip.Content>
|
|
1507
|
-
</Tooltip>
|
|
1508
|
-
}
|
|
1509
|
-
/>
|
|
1510
|
-
<TextField
|
|
1511
|
-
type='textarea'
|
|
1512
|
-
value={general.footnotes}
|
|
1513
|
-
updateField={updateField}
|
|
1514
|
-
section='general'
|
|
1515
|
-
fieldName='footnotes'
|
|
1516
|
-
label='Footnotes'
|
|
1517
|
-
tooltip={
|
|
1518
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1519
|
-
<Tooltip.Target>
|
|
1520
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1521
|
-
</Tooltip.Target>
|
|
1522
|
-
<Tooltip.Content>
|
|
1523
|
-
<p>Footnotes</p>
|
|
1524
|
-
</Tooltip.Content>
|
|
1525
|
-
</Tooltip>
|
|
1526
|
-
}
|
|
1527
|
-
/>
|
|
1528
|
-
|
|
1529
|
-
{/* <label className="checkbox mt-4">
|
|
1530
|
-
<input type="checkbox" checked={ state.general.showDownloadMediaButton } onChange={(event) => { handleEditorChanges("toggleDownloadMediaButton", event.target.checked) }} />
|
|
1531
|
-
<span className="edit-label">Enable Media Download</span>
|
|
1532
|
-
</label> */}
|
|
1533
|
-
</AccordionItemPanel>
|
|
1534
|
-
</AccordionItem>
|
|
1535
|
-
<AccordionItem>
|
|
1536
|
-
{' '}
|
|
1537
|
-
{/* Columns */}
|
|
1538
|
-
<AccordionItemHeading>
|
|
1539
|
-
<AccordionItemButton>Columns</AccordionItemButton>
|
|
1540
|
-
</AccordionItemHeading>
|
|
1541
|
-
<AccordionItemPanel>
|
|
1542
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
1543
|
-
<label>
|
|
1544
|
-
<span className='edit-label column-heading'>
|
|
1545
|
-
Geography
|
|
1546
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1547
|
-
<Tooltip.Target>
|
|
1548
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1549
|
-
</Tooltip.Target>
|
|
1550
|
-
<Tooltip.Content>
|
|
1551
|
-
<p>
|
|
1552
|
-
Select the source column containing the map location names or, for county-level maps, the FIPS
|
|
1553
|
-
codes.
|
|
1554
|
-
</p>
|
|
1555
|
-
</Tooltip.Content>
|
|
1556
|
-
</Tooltip>
|
|
1557
|
-
</span>
|
|
1558
|
-
<Select
|
|
1559
|
-
value={config.columns.geo ? config.columns.geo.name : columnsOptions[0]}
|
|
1560
|
-
options={columnsOptions.map(c => c.key)}
|
|
1561
|
-
onChange={event => {
|
|
1562
|
-
editColumn('geo', 'name', event.target.value)
|
|
1563
|
-
checkConfigurationNeeded(config)
|
|
1564
|
-
}}
|
|
1565
|
-
/>
|
|
1566
|
-
</label>
|
|
1567
|
-
{config.general.type === 'us-geocode' && (
|
|
1568
|
-
<label className='checkbox'>
|
|
1569
|
-
<input
|
|
1570
|
-
type='checkbox'
|
|
1571
|
-
checked={config.general.convertFipsCodes}
|
|
1572
|
-
onChange={event => {
|
|
1573
|
-
setConfig({
|
|
1574
|
-
...config,
|
|
1575
|
-
general: {
|
|
1576
|
-
...config.general,
|
|
1577
|
-
convertFipsCodes: event.target.checked
|
|
1578
|
-
}
|
|
1579
|
-
})
|
|
1580
|
-
}}
|
|
1581
|
-
/>
|
|
1582
|
-
<span className='edit-label'>Convert FIPS Codes to Geography Name</span>
|
|
1583
|
-
</label>
|
|
1584
|
-
)}
|
|
1193
|
+
{({ displayPanel, convertStateToConfig }) => {
|
|
1194
|
+
// Use custom convertStateToConfig for map-specific logic
|
|
1195
|
+
const mapConvertStateToConfig = customConvertStateToConfig
|
|
1585
1196
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
<
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
</Tooltip.Target>
|
|
1610
|
-
<Tooltip.Content>
|
|
1611
|
-
<p>Enter a geography label for use in tooltips.</p>
|
|
1612
|
-
</Tooltip.Content>
|
|
1613
|
-
</Tooltip>
|
|
1614
|
-
}
|
|
1615
|
-
/>
|
|
1616
|
-
</fieldset>
|
|
1617
|
-
{'navigation' !== config.general.type && (
|
|
1618
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
1619
|
-
<Select
|
|
1620
|
-
label='Data Column'
|
|
1621
|
-
value={columns.primary.name}
|
|
1622
|
-
options={columnsOptions.map(c => c.key)}
|
|
1623
|
-
onChange={event => {
|
|
1624
|
-
const _state = cloneConfig(config)
|
|
1625
|
-
_state.columns.primary.name = event.target.value
|
|
1626
|
-
_state.columns.primary.label = event.target.value
|
|
1627
|
-
setConfig(_state)
|
|
1628
|
-
checkConfigurationNeeded(_state)
|
|
1629
|
-
}}
|
|
1630
|
-
tooltip={
|
|
1631
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1632
|
-
<Tooltip.Target>
|
|
1633
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1634
|
-
</Tooltip.Target>
|
|
1635
|
-
<Tooltip.Content>
|
|
1636
|
-
<p>Select the source column containing the categorical or numeric values to be mapped.</p>
|
|
1637
|
-
</Tooltip.Content>
|
|
1638
|
-
</Tooltip>
|
|
1639
|
-
}
|
|
1640
|
-
/>
|
|
1641
|
-
<label className='checkbox'>
|
|
1642
|
-
<input
|
|
1643
|
-
type='checkbox'
|
|
1644
|
-
checked={config.general.hidePrimaryColumnInTooltip || false}
|
|
1645
|
-
onChange={event => {
|
|
1646
|
-
handleEditorChanges('hidePrimaryColumnInTooltip', event.target.checked)
|
|
1647
|
-
}}
|
|
1648
|
-
/>
|
|
1649
|
-
<span className='edit-label'>Hide Data Column Name in Tooltip</span>
|
|
1650
|
-
</label>
|
|
1651
|
-
<TextField
|
|
1652
|
-
value={columns.primary.label}
|
|
1653
|
-
section='columns'
|
|
1654
|
-
subsection='primary'
|
|
1655
|
-
fieldName='label'
|
|
1656
|
-
label='Data Label'
|
|
1657
|
-
updateField={updateField}
|
|
1658
|
-
tooltip={
|
|
1659
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1660
|
-
<Tooltip.Target>
|
|
1661
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1662
|
-
</Tooltip.Target>
|
|
1663
|
-
<Tooltip.Content>
|
|
1664
|
-
<p>Enter a data label for use in tooltips and the data table.</p>
|
|
1665
|
-
</Tooltip.Content>
|
|
1666
|
-
</Tooltip>
|
|
1667
|
-
}
|
|
1668
|
-
/>
|
|
1669
|
-
<ul className='column-edit'>
|
|
1670
|
-
<li className='three-col'>
|
|
1671
|
-
<TextField
|
|
1672
|
-
value={columns.primary.prefix}
|
|
1673
|
-
section='columns'
|
|
1674
|
-
subsection='primary'
|
|
1675
|
-
fieldName='prefix'
|
|
1676
|
-
label='Prefix'
|
|
1677
|
-
updateField={updateField}
|
|
1678
|
-
/>
|
|
1679
|
-
<TextField
|
|
1680
|
-
value={columns.primary.suffix}
|
|
1681
|
-
section='columns'
|
|
1682
|
-
subsection='primary'
|
|
1683
|
-
fieldName='suffix'
|
|
1684
|
-
label='Suffix'
|
|
1685
|
-
updateField={updateField}
|
|
1686
|
-
/>
|
|
1687
|
-
<TextField
|
|
1688
|
-
type='number'
|
|
1689
|
-
value={columns.primary.roundToPlace}
|
|
1690
|
-
section='columns'
|
|
1691
|
-
subsection='primary'
|
|
1692
|
-
fieldName='roundToPlace'
|
|
1693
|
-
label='Round'
|
|
1694
|
-
updateField={updateField}
|
|
1695
|
-
min={0}
|
|
1696
|
-
/>
|
|
1697
|
-
</li>
|
|
1698
|
-
<li>
|
|
1699
|
-
<label className='checkbox'>
|
|
1700
|
-
<input
|
|
1701
|
-
type='checkbox'
|
|
1702
|
-
checked={config.columns.primary.useCommas}
|
|
1703
|
-
onChange={event => {
|
|
1704
|
-
editColumn('primary', 'useCommas', event.target.checked)
|
|
1197
|
+
return (
|
|
1198
|
+
<>
|
|
1199
|
+
<ReactTooltip multiline={true} />
|
|
1200
|
+
<Accordion allowZeroExpanded={true}>
|
|
1201
|
+
<AccordionItem>
|
|
1202
|
+
{' '}
|
|
1203
|
+
{/* Type */}
|
|
1204
|
+
<AccordionItemHeading>
|
|
1205
|
+
<AccordionItemButton>Type</AccordionItemButton>
|
|
1206
|
+
</AccordionItemHeading>
|
|
1207
|
+
<AccordionItemPanel>
|
|
1208
|
+
<label>
|
|
1209
|
+
<span className='edit-label column-heading'>
|
|
1210
|
+
<span>Geography</span>
|
|
1211
|
+
</span>
|
|
1212
|
+
<ul className='geo-buttons d-grid' style={{ gridTemplateColumns: 'repeat(2, 1fr)', gap: '8px' }}>
|
|
1213
|
+
<button
|
|
1214
|
+
className={`${
|
|
1215
|
+
config.general.geoType === 'us' || config.general.geoType === 'us-county' ? 'active' : ''
|
|
1216
|
+
} full-width`}
|
|
1217
|
+
onClick={e => {
|
|
1218
|
+
e.preventDefault()
|
|
1219
|
+
handleEditorChanges('geoType', 'us')
|
|
1705
1220
|
}}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
onChange={event => {
|
|
1716
|
-
editColumn('primary', 'dataTable', event.target.checked)
|
|
1221
|
+
>
|
|
1222
|
+
<UsaGraphic />
|
|
1223
|
+
<span>United States</span>
|
|
1224
|
+
</button>
|
|
1225
|
+
<button
|
|
1226
|
+
className={`${config.general.geoType === 'us-region' ? 'active' : ''} full-width`}
|
|
1227
|
+
onClick={e => {
|
|
1228
|
+
e.preventDefault()
|
|
1229
|
+
handleEditorChanges('geoType', 'us-region')
|
|
1717
1230
|
}}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
onChange={event => {
|
|
1728
|
-
editColumn('primary', 'tooltip', event.target.checked)
|
|
1231
|
+
>
|
|
1232
|
+
<UsaRegionGraphic />
|
|
1233
|
+
<span>U.S. Region</span>
|
|
1234
|
+
</button>
|
|
1235
|
+
<button
|
|
1236
|
+
className={`${config.general.geoType === 'world' ? 'active' : ''} full-width`}
|
|
1237
|
+
onClick={e => {
|
|
1238
|
+
e.preventDefault()
|
|
1239
|
+
handleEditorChanges('geoType', 'world')
|
|
1729
1240
|
}}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
<p>Select the source column containing the categorical bubble values to be mapped.</p>
|
|
1749
|
-
</Tooltip.Content>
|
|
1750
|
-
</Tooltip>
|
|
1751
|
-
</span>
|
|
1752
|
-
<select
|
|
1753
|
-
value={config.columns.categorical ? config.columns.categorical.name : columnsOptions[0]}
|
|
1754
|
-
onChange={event => {
|
|
1755
|
-
editColumn('categorical', 'name', event.target.value)
|
|
1756
|
-
}}
|
|
1757
|
-
>
|
|
1758
|
-
{columnsOptions}
|
|
1759
|
-
</select>
|
|
1760
|
-
</label>
|
|
1761
|
-
</fieldset>
|
|
1762
|
-
)}
|
|
1763
|
-
{
|
|
1764
|
-
<>
|
|
1765
|
-
<Select
|
|
1766
|
-
label='Latitude Column'
|
|
1767
|
-
value={config.columns.latitude.name}
|
|
1768
|
-
options={columnsOptions.map(c => c.key)}
|
|
1769
|
-
onChange={e => {
|
|
1770
|
-
editColumn('latitude', 'name', e.target.value)
|
|
1771
|
-
}}
|
|
1772
|
-
/>
|
|
1773
|
-
<Select
|
|
1774
|
-
label='Longitude Column'
|
|
1775
|
-
value={config.columns.longitude.name}
|
|
1776
|
-
options={columnsOptions.map(c => c.key)}
|
|
1777
|
-
onChange={e => {
|
|
1778
|
-
editColumn('longitude', 'name', e.target.value)
|
|
1779
|
-
}}
|
|
1780
|
-
/>
|
|
1781
|
-
</>
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
{'navigation' !== config.general.type && (
|
|
1785
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
1786
|
-
<label>
|
|
1787
|
-
<span className='edit-label'>
|
|
1788
|
-
Special Classes
|
|
1789
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1790
|
-
<Tooltip.Target>
|
|
1791
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1792
|
-
</Tooltip.Target>
|
|
1793
|
-
<Tooltip.Content>
|
|
1794
|
-
<p>
|
|
1795
|
-
For secondary values such as "NA", the system can automatically color-code them in shades of
|
|
1796
|
-
gray, one shade for each special class.
|
|
1797
|
-
</p>
|
|
1798
|
-
</Tooltip.Content>
|
|
1799
|
-
</Tooltip>
|
|
1800
|
-
</span>
|
|
1801
|
-
</label>
|
|
1802
|
-
{config.legend.specialClasses.length === 2 && (
|
|
1803
|
-
<Alert
|
|
1804
|
-
type='info'
|
|
1805
|
-
message='If a third special class is needed you can apply a pattern to set it apart.'
|
|
1806
|
-
showCloseButton={false}
|
|
1807
|
-
/>
|
|
1808
|
-
)}
|
|
1809
|
-
{specialClasses.map((specialClass, i) => (
|
|
1810
|
-
<div className='edit-block' key={`special-class-${i}`}>
|
|
1811
|
-
<button
|
|
1812
|
-
className='remove-column'
|
|
1813
|
-
onClick={e => {
|
|
1814
|
-
e.preventDefault()
|
|
1815
|
-
editColumn('primary', 'specialClassDelete', i)
|
|
1816
|
-
}}
|
|
1817
|
-
>
|
|
1818
|
-
Remove
|
|
1819
|
-
</button>
|
|
1820
|
-
<p>Special Class {i + 1}</p>
|
|
1241
|
+
>
|
|
1242
|
+
<WorldGraphic />
|
|
1243
|
+
<span>World</span>
|
|
1244
|
+
</button>
|
|
1245
|
+
<button
|
|
1246
|
+
className={`${config.general.geoType === 'single-state' ? 'active' : ''} full-width`}
|
|
1247
|
+
onClick={e => {
|
|
1248
|
+
e.preventDefault()
|
|
1249
|
+
handleEditorChanges('geoType', 'single-state')
|
|
1250
|
+
}}
|
|
1251
|
+
>
|
|
1252
|
+
<AlabamaGraphic />
|
|
1253
|
+
<span>U.S. State</span>
|
|
1254
|
+
</button>
|
|
1255
|
+
</ul>
|
|
1256
|
+
</label>
|
|
1257
|
+
{/* Select > State or County Map */}
|
|
1258
|
+
{(config.general.geoType === 'us' || config.general.geoType === 'us-county') && (
|
|
1821
1259
|
<Select
|
|
1822
|
-
label='
|
|
1823
|
-
value={
|
|
1824
|
-
options={
|
|
1825
|
-
value:
|
|
1826
|
-
label:
|
|
1827
|
-
}
|
|
1260
|
+
label='Geography Subtype'
|
|
1261
|
+
value={config.general.geoType}
|
|
1262
|
+
options={[
|
|
1263
|
+
{ value: 'us', label: 'US State-Level' },
|
|
1264
|
+
{ value: 'us-county', label: 'US County-Level' }
|
|
1265
|
+
]}
|
|
1828
1266
|
onChange={event => {
|
|
1829
|
-
|
|
1830
|
-
prop: 'key',
|
|
1831
|
-
index: i,
|
|
1832
|
-
value: event.target.value
|
|
1833
|
-
})
|
|
1267
|
+
handleEditorChanges('geoType', event.target.value)
|
|
1834
1268
|
}}
|
|
1835
1269
|
/>
|
|
1270
|
+
)}
|
|
1271
|
+
{(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
|
|
1836
1272
|
<Select
|
|
1837
|
-
label='
|
|
1838
|
-
value={
|
|
1273
|
+
label='County Census Year'
|
|
1274
|
+
value={config.general.countyCensusYear || '2019'}
|
|
1839
1275
|
options={[
|
|
1840
|
-
{ value: '', label: '
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1276
|
+
{ value: '2022', label: '2022' },
|
|
1277
|
+
{ value: '2021', label: '2021' },
|
|
1278
|
+
{ value: '2020', label: '2020' },
|
|
1279
|
+
{ value: '2019', label: '2019' },
|
|
1280
|
+
{ value: '2015', label: '2015' },
|
|
1281
|
+
{ value: '2014', label: '2014' },
|
|
1282
|
+
{ value: '2013', label: '2013' }
|
|
1844
1283
|
]}
|
|
1845
1284
|
onChange={event => {
|
|
1846
|
-
|
|
1847
|
-
prop: 'value',
|
|
1848
|
-
index: i,
|
|
1849
|
-
value: event.target.value
|
|
1850
|
-
})
|
|
1285
|
+
handleEditorChanges('countyCensusYear', event.target.value)
|
|
1851
1286
|
}}
|
|
1852
1287
|
/>
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
<input
|
|
1856
|
-
type='text'
|
|
1857
|
-
value={specialClass.label}
|
|
1858
|
-
onChange={e => {
|
|
1859
|
-
editColumn('primary', 'specialClassEdit', {
|
|
1860
|
-
prop: 'label',
|
|
1861
|
-
index: i,
|
|
1862
|
-
value: e.target.value
|
|
1863
|
-
})
|
|
1864
|
-
}}
|
|
1865
|
-
/>
|
|
1866
|
-
</label>
|
|
1867
|
-
</div>
|
|
1868
|
-
))}
|
|
1869
|
-
{config.legend.specialClasses.length < 2 && (
|
|
1870
|
-
<button
|
|
1871
|
-
className='btn btn-primary full-width'
|
|
1872
|
-
onClick={e => {
|
|
1873
|
-
e.preventDefault()
|
|
1874
|
-
editColumn('primary', 'specialClassAdd', {})
|
|
1875
|
-
}}
|
|
1876
|
-
>
|
|
1877
|
-
Add Special Class
|
|
1878
|
-
</button>
|
|
1879
|
-
)}
|
|
1880
|
-
</fieldset>
|
|
1881
|
-
)}
|
|
1882
|
-
|
|
1883
|
-
<label className='edit-block navigate column-heading'>
|
|
1884
|
-
<span className='edit-label column-heading'>
|
|
1885
|
-
Navigation
|
|
1886
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1887
|
-
<Tooltip.Target>
|
|
1888
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1889
|
-
</Tooltip.Target>
|
|
1890
|
-
<Tooltip.Content>
|
|
1891
|
-
<p>
|
|
1892
|
-
To provide end users with navigation functionality, select the source column containing the
|
|
1893
|
-
navigation URLs.
|
|
1894
|
-
</p>
|
|
1895
|
-
</Tooltip.Content>
|
|
1896
|
-
</Tooltip>
|
|
1897
|
-
</span>
|
|
1898
|
-
<Select
|
|
1899
|
-
value={config.columns.navigate ? config.columns.navigate.name : ''}
|
|
1900
|
-
options={columnsOptions.map(c => c.key)}
|
|
1901
|
-
onChange={event => {
|
|
1902
|
-
editColumn('navigate', 'name', event.target.value)
|
|
1903
|
-
}}
|
|
1904
|
-
/>
|
|
1905
|
-
</label>
|
|
1906
|
-
{'navigation' !== config.general.type && (
|
|
1907
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
1908
|
-
<label>
|
|
1909
|
-
<span className='edit-label'>
|
|
1910
|
-
Additional Columns
|
|
1911
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
1912
|
-
<Tooltip.Target>
|
|
1913
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1914
|
-
</Tooltip.Target>
|
|
1915
|
-
<Tooltip.Content>
|
|
1916
|
-
<p>
|
|
1917
|
-
You can specify additional columns to display in tooltips and / or the supporting data
|
|
1918
|
-
table.
|
|
1919
|
-
</p>
|
|
1920
|
-
</Tooltip.Content>
|
|
1921
|
-
</Tooltip>
|
|
1922
|
-
</span>
|
|
1923
|
-
</label>
|
|
1924
|
-
{additionalColumns.map(val => (
|
|
1925
|
-
<fieldset className='edit-block' key={val}>
|
|
1926
|
-
<button
|
|
1927
|
-
className='remove-column'
|
|
1928
|
-
onClick={event => {
|
|
1929
|
-
event.preventDefault()
|
|
1930
|
-
removeAdditionalColumn(val)
|
|
1931
|
-
}}
|
|
1932
|
-
>
|
|
1933
|
-
Remove
|
|
1934
|
-
</button>
|
|
1288
|
+
)}
|
|
1289
|
+
{(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
|
|
1935
1290
|
<Select
|
|
1936
|
-
label='
|
|
1937
|
-
value={config.
|
|
1938
|
-
options={
|
|
1939
|
-
value:
|
|
1940
|
-
|
|
1941
|
-
|
|
1291
|
+
label='Filter Controlling County Census Year'
|
|
1292
|
+
value={config.general.filterControlsCountyYear || ''}
|
|
1293
|
+
options={[
|
|
1294
|
+
{ value: '', label: 'None' },
|
|
1295
|
+
...(config.filters
|
|
1296
|
+
? config.filters.map(filter => ({ value: filter.columnName, label: filter.columnName }))
|
|
1297
|
+
: [])
|
|
1298
|
+
]}
|
|
1942
1299
|
onChange={event => {
|
|
1943
|
-
|
|
1300
|
+
handleEditorChanges('filterControlsCountyYear', event.target.value)
|
|
1944
1301
|
}}
|
|
1945
1302
|
/>
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1303
|
+
)}
|
|
1304
|
+
|
|
1305
|
+
{config.general.geoType === 'single-state' && runtimeData && (
|
|
1306
|
+
<Select
|
|
1307
|
+
label='Filter Controlling State Picked'
|
|
1308
|
+
value={config.general.filterControlsStatesPicked || ''}
|
|
1309
|
+
options={[
|
|
1310
|
+
{ value: '', label: 'None' },
|
|
1311
|
+
...(runtimeData && columnsInData?.map(col => ({ value: col, label: col })))
|
|
1312
|
+
]}
|
|
1313
|
+
onChange={event => {
|
|
1314
|
+
handleEditorChanges('filterControlsStatesPicked', event.target.value)
|
|
1315
|
+
}}
|
|
1953
1316
|
/>
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
updateField={updateField}
|
|
1971
|
-
/>
|
|
1972
|
-
<TextField
|
|
1973
|
-
type='number'
|
|
1974
|
-
value={columns[val].roundToPlace}
|
|
1975
|
-
section='columns'
|
|
1976
|
-
subsection={val}
|
|
1977
|
-
fieldName='roundToPlace'
|
|
1978
|
-
label='Round'
|
|
1979
|
-
updateField={updateField}
|
|
1980
|
-
/>
|
|
1981
|
-
</li>
|
|
1982
|
-
<li>
|
|
1983
|
-
<label className='checkbox'>
|
|
1984
|
-
<input
|
|
1985
|
-
type='checkbox'
|
|
1986
|
-
checked={config.columns[val].useCommas}
|
|
1987
|
-
onChange={event => {
|
|
1988
|
-
editColumn(val, 'useCommas', event.target.checked)
|
|
1989
|
-
}}
|
|
1990
|
-
/>
|
|
1991
|
-
<span className='edit-label'>Add Commas to Numbers</span>
|
|
1992
|
-
</label>
|
|
1993
|
-
</li>
|
|
1994
|
-
<li>
|
|
1995
|
-
<label className='checkbox'>
|
|
1996
|
-
<input
|
|
1997
|
-
type='checkbox'
|
|
1998
|
-
checked={config.columns[val].dataTable}
|
|
1999
|
-
onChange={event => {
|
|
2000
|
-
editColumn(val, 'dataTable', event.target.checked)
|
|
2001
|
-
}}
|
|
2002
|
-
/>
|
|
2003
|
-
<span className='edit-label'>Show in Data Table</span>
|
|
2004
|
-
</label>
|
|
2005
|
-
</li>
|
|
2006
|
-
<li>
|
|
2007
|
-
<label className='checkbox'>
|
|
2008
|
-
<input
|
|
2009
|
-
type='checkbox'
|
|
2010
|
-
checked={config.columns[val].tooltip}
|
|
2011
|
-
onChange={event => {
|
|
2012
|
-
editColumn(val, 'tooltip', event.target.checked)
|
|
2013
|
-
}}
|
|
2014
|
-
/>
|
|
2015
|
-
<span className='edit-label'>Show in Tooltips</span>
|
|
2016
|
-
</label>
|
|
2017
|
-
</li>
|
|
2018
|
-
</ul>
|
|
2019
|
-
</fieldset>
|
|
2020
|
-
))}
|
|
2021
|
-
<button
|
|
2022
|
-
className={'btn btn-primary full-width'}
|
|
2023
|
-
onClick={event => {
|
|
2024
|
-
event.preventDefault()
|
|
2025
|
-
addAdditionalColumn(additionalColumns.length + 1)
|
|
2026
|
-
}}
|
|
2027
|
-
>
|
|
2028
|
-
Add Column
|
|
2029
|
-
</button>
|
|
2030
|
-
</fieldset>
|
|
2031
|
-
)}
|
|
2032
|
-
{'category' === config.legend.type && (
|
|
2033
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
2034
|
-
<label>
|
|
2035
|
-
<span className='edit-label'>
|
|
2036
|
-
Additional Category
|
|
2037
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2038
|
-
<Tooltip.Target>
|
|
2039
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2040
|
-
</Tooltip.Target>
|
|
2041
|
-
<Tooltip.Content>
|
|
2042
|
-
<p>You can provide additional categories to ensure they appear in the legend</p>
|
|
2043
|
-
</Tooltip.Content>
|
|
2044
|
-
</Tooltip>
|
|
2045
|
-
</span>
|
|
2046
|
-
</label>
|
|
2047
|
-
{config.legend.additionalCategories &&
|
|
2048
|
-
config.legend.additionalCategories.map((val, i) => (
|
|
2049
|
-
<fieldset className='edit-block' key={val}>
|
|
2050
|
-
<button
|
|
2051
|
-
className='remove-column'
|
|
2052
|
-
onClick={event => {
|
|
2053
|
-
event.preventDefault()
|
|
2054
|
-
const updatedAdditionaCategories = [...config.legend.additionalCategories]
|
|
2055
|
-
updatedAdditionaCategories.splice(i, 1)
|
|
2056
|
-
updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
|
|
1317
|
+
)}
|
|
1318
|
+
|
|
1319
|
+
{/* Type */}
|
|
1320
|
+
{/* Select > Filter a state */}
|
|
1321
|
+
{config.general.geoType === 'single-state' && (
|
|
1322
|
+
<label>
|
|
1323
|
+
<span>States Selector</span>
|
|
1324
|
+
<MultiSelect
|
|
1325
|
+
selected={config.general.statesPicked.map(state => state.stateName)}
|
|
1326
|
+
options={StateOptionList().map(option => ({
|
|
1327
|
+
value: option.props.value,
|
|
1328
|
+
label: option.props.children
|
|
1329
|
+
}))}
|
|
1330
|
+
fieldName={'statesPicked'}
|
|
1331
|
+
updateField={(_, __, ___, selectedOptions) => {
|
|
1332
|
+
handleEditorChanges('chooseState', selectedOptions)
|
|
2057
1333
|
}}
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
1334
|
+
/>
|
|
1335
|
+
</label>
|
|
1336
|
+
)}
|
|
1337
|
+
{/* Country Selection for World Maps */}
|
|
1338
|
+
{config.general.geoType === 'world' && (
|
|
1339
|
+
<>
|
|
2061
1340
|
<label>
|
|
2062
|
-
<span
|
|
2063
|
-
<
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
1341
|
+
<span>Countries Selector</span>
|
|
1342
|
+
<MultiSelect
|
|
1343
|
+
selected={(config.general.countriesPicked || []).map(country => country.name)}
|
|
1344
|
+
options={CountryOptionList().map(option => ({
|
|
1345
|
+
value: option.props.value,
|
|
1346
|
+
label: option.props.children
|
|
1347
|
+
}))}
|
|
1348
|
+
fieldName={'countriesPicked'}
|
|
1349
|
+
updateField={(_, __, ___, selectedOptions) => {
|
|
1350
|
+
handleEditorChanges('chooseCountry', selectedOptions)
|
|
2072
1351
|
}}
|
|
2073
1352
|
/>
|
|
2074
1353
|
</label>
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
</button>
|
|
2088
|
-
</fieldset>
|
|
2089
|
-
)}
|
|
2090
|
-
</AccordionItemPanel>
|
|
2091
|
-
</AccordionItem>{' '}
|
|
2092
|
-
{/* Columns */}
|
|
2093
|
-
{'navigation' !== config.general.type && (
|
|
2094
|
-
<AccordionItem>
|
|
2095
|
-
{' '}
|
|
2096
|
-
{/* Legend */}
|
|
2097
|
-
<AccordionItemHeading>
|
|
2098
|
-
<AccordionItemButton>Legend</AccordionItemButton>
|
|
2099
|
-
</AccordionItemHeading>
|
|
2100
|
-
<AccordionItemPanel>
|
|
2101
|
-
{(config.legend.type === 'equalnumber' || config.legend.type === 'equalinterval') && (
|
|
2102
|
-
<Select
|
|
2103
|
-
label='Legend Type'
|
|
2104
|
-
value={legend.type}
|
|
2105
|
-
options={[
|
|
2106
|
-
{ value: 'equalnumber', label: 'Equal Number (Quantiles)' },
|
|
2107
|
-
{ value: 'equalinterval', label: 'Equal Interval' }
|
|
2108
|
-
]}
|
|
2109
|
-
onChange={event => {
|
|
2110
|
-
let testForType = Number(typeof config.data[0][config.columns.primary.name])
|
|
2111
|
-
let hasValue = config.data[0][config.columns.primary.name]
|
|
2112
|
-
let messages = []
|
|
2113
|
-
|
|
2114
|
-
if (!hasValue) {
|
|
2115
|
-
messages.push(
|
|
2116
|
-
`There appears to be values missing for data in the primary column ${config.columns.primary.name}`
|
|
2117
|
-
)
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
if (testForType === 'string' && isNaN(testForType) && value !== 'category') {
|
|
2121
|
-
messages.push(
|
|
2122
|
-
'Error with legend. Primary columns that are text must use a categorical legend type. Try changing the legend type to DEV-12345categorical.'
|
|
2123
|
-
)
|
|
2124
|
-
} else {
|
|
2125
|
-
messages = []
|
|
2126
|
-
}
|
|
2127
|
-
|
|
2128
|
-
const _newConfig = cloneConfig(config)
|
|
2129
|
-
_newConfig.legend.type = event.target.value
|
|
2130
|
-
_newConfig.runtime.editorErrorMessage = messages
|
|
2131
|
-
setConfig(_newConfig)
|
|
2132
|
-
}}
|
|
2133
|
-
/>
|
|
2134
|
-
)}
|
|
2135
|
-
{'navigation' !== config.general.type && (
|
|
2136
|
-
<label className='checkbox'>
|
|
2137
|
-
<input
|
|
2138
|
-
type='checkbox'
|
|
2139
|
-
checked={config.general.showSidebar || false}
|
|
2140
|
-
onChange={event => {
|
|
2141
|
-
const _newConfig = cloneConfig(config)
|
|
2142
|
-
_newConfig.general.showSidebar = event.target.checked
|
|
2143
|
-
setConfig(_newConfig)
|
|
2144
|
-
}}
|
|
2145
|
-
/>
|
|
2146
|
-
<span className='edit-label'>Show Legend</span>
|
|
2147
|
-
</label>
|
|
2148
|
-
)}
|
|
2149
|
-
{'navigation' !== config.general.type && (
|
|
2150
|
-
<>
|
|
1354
|
+
{config.general.countriesPicked && config.general.countriesPicked.length > 0 && (
|
|
1355
|
+
<CheckBox
|
|
1356
|
+
value={config.general.hideUnselectedCountries || false}
|
|
1357
|
+
fieldName='hideUnselectedCountries'
|
|
1358
|
+
label='Hide Unselected Countries'
|
|
1359
|
+
updateField={updateField}
|
|
1360
|
+
section='general'
|
|
1361
|
+
/>
|
|
1362
|
+
)}
|
|
1363
|
+
</>
|
|
1364
|
+
)}
|
|
1365
|
+
{/* Type */}
|
|
2151
1366
|
<Select
|
|
2152
|
-
label=
|
|
2153
|
-
|
|
1367
|
+
label={
|
|
1368
|
+
<>
|
|
1369
|
+
Map Type
|
|
1370
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1371
|
+
<Tooltip.Target>
|
|
1372
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1373
|
+
</Tooltip.Target>
|
|
1374
|
+
<Tooltip.Content>
|
|
1375
|
+
<p>
|
|
1376
|
+
Select "Data" to create a color-coded data map. To create a navigation-only map, select
|
|
1377
|
+
"Navigation."
|
|
1378
|
+
</p>
|
|
1379
|
+
</Tooltip.Content>
|
|
1380
|
+
</Tooltip>
|
|
1381
|
+
</>
|
|
1382
|
+
}
|
|
1383
|
+
value={config.general.type}
|
|
2154
1384
|
options={[
|
|
2155
|
-
{ value: '
|
|
2156
|
-
{ value: '
|
|
2157
|
-
{ value: '
|
|
1385
|
+
{ value: 'data', label: 'Data' },
|
|
1386
|
+
...(config.general.geoType === 'us-county' ? [{ value: 'us-geocode', label: 'Geocode' }] : []),
|
|
1387
|
+
...(config.general.geoType === 'world' ? [{ value: 'world-geocode', label: 'Geocode' }] : []),
|
|
1388
|
+
...(config.general.geoType !== 'us-county'
|
|
1389
|
+
? [{ value: 'navigation', label: 'Navigation' }]
|
|
1390
|
+
: []),
|
|
1391
|
+
...(config.general.geoType === 'world' || config.general.geoType === 'us'
|
|
1392
|
+
? [{ value: 'bubble', label: 'Bubble' }]
|
|
1393
|
+
: [])
|
|
2158
1394
|
]}
|
|
2159
1395
|
onChange={event => {
|
|
2160
|
-
handleEditorChanges('
|
|
1396
|
+
handleEditorChanges('editorMapType', event.target.value)
|
|
2161
1397
|
}}
|
|
2162
1398
|
/>
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
1399
|
+
|
|
1400
|
+
{/* Navigation Behavior */}
|
|
1401
|
+
{(config.general.type === 'navigation' || config.general.type === 'data') && (
|
|
1402
|
+
<Select
|
|
1403
|
+
label='Navigation Behavior'
|
|
1404
|
+
value={config.general.navigationTarget}
|
|
1405
|
+
options={[
|
|
1406
|
+
{ value: '_self', label: 'Same Window' },
|
|
1407
|
+
{ value: '_blank', label: 'New Window' }
|
|
1408
|
+
]}
|
|
1409
|
+
onChange={event => {
|
|
1410
|
+
const _newConfig = cloneConfig(config)
|
|
1411
|
+
_newConfig.general.navigationTarget = event.target.value
|
|
1412
|
+
setConfig(_newConfig)
|
|
1413
|
+
}}
|
|
1414
|
+
/>
|
|
1415
|
+
)}
|
|
1416
|
+
<label>
|
|
1417
|
+
<span className='edit-label'>Data Classification Type</span>
|
|
1418
|
+
<div>
|
|
1419
|
+
<label>
|
|
1420
|
+
<input
|
|
1421
|
+
type='radio'
|
|
1422
|
+
name='equalnumber'
|
|
1423
|
+
value='equalnumber'
|
|
1424
|
+
checked={config.legend.type === 'equalnumber' || config.legend.type === 'equalinterval'}
|
|
1425
|
+
onChange={e => handleEditorChanges('classificationType', e.target.value)}
|
|
1426
|
+
/>
|
|
1427
|
+
Numeric/Quantitative
|
|
1428
|
+
</label>
|
|
1429
|
+
<label>
|
|
1430
|
+
<input
|
|
1431
|
+
type='radio'
|
|
1432
|
+
name='category'
|
|
1433
|
+
value='category'
|
|
1434
|
+
checked={config.legend.type === 'category'}
|
|
1435
|
+
onChange={e => handleEditorChanges('classificationType', e.target.value)}
|
|
1436
|
+
/>
|
|
1437
|
+
Categorical
|
|
1438
|
+
</label>
|
|
1439
|
+
</div>
|
|
1440
|
+
</label>
|
|
1441
|
+
|
|
1442
|
+
{/* Display as Hex */}
|
|
1443
|
+
{general.geoType === 'us' && general.type !== 'navigation' && general.type !== 'bubble' && (
|
|
1444
|
+
<CheckBox
|
|
1445
|
+
value={config.general.displayAsHex}
|
|
1446
|
+
section='general'
|
|
1447
|
+
subsection={null}
|
|
1448
|
+
fieldName='displayAsHex'
|
|
1449
|
+
label='Display As Hex Map'
|
|
1450
|
+
updateField={updateField}
|
|
1451
|
+
className=''
|
|
1452
|
+
/>
|
|
1453
|
+
)}
|
|
1454
|
+
|
|
1455
|
+
{/* Shapes on Hex */}
|
|
1456
|
+
<CheckBox
|
|
1457
|
+
value={config.hexMap.type === 'shapes'}
|
|
1458
|
+
section='hexMap'
|
|
1459
|
+
subsection={null}
|
|
1460
|
+
fieldName='type'
|
|
1461
|
+
label='Display Shapes on Hex Map'
|
|
1462
|
+
updateField={updateField}
|
|
1463
|
+
onChange={event => {
|
|
1464
|
+
setConfig({
|
|
1465
|
+
...config,
|
|
1466
|
+
hexMap: {
|
|
1467
|
+
...config.hexMap,
|
|
1468
|
+
type: event.target.checked ? 'shapes' : 'standard'
|
|
1469
|
+
}
|
|
1470
|
+
})
|
|
1471
|
+
}}
|
|
1472
|
+
/>
|
|
1473
|
+
<HexSetting.ShapeColumns columnsOptions={columnsOptions} />
|
|
1474
|
+
|
|
1475
|
+
{'us' === config.general.geoType &&
|
|
1476
|
+
'bubble' !== config.general.type &&
|
|
1477
|
+
false === config.general.displayAsHex && (
|
|
1478
|
+
<CheckBox
|
|
1479
|
+
label='Show state labels'
|
|
1480
|
+
checked={config.general.displayStateLabels}
|
|
1481
|
+
onChange={event => {
|
|
1482
|
+
handleEditorChanges('displayStateLabels', event.target.checked)
|
|
1483
|
+
}}
|
|
1484
|
+
tooltip={
|
|
1485
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1486
|
+
<Tooltip.Target>
|
|
1487
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1488
|
+
</Tooltip.Target>
|
|
1489
|
+
<Tooltip.Content>
|
|
1490
|
+
<p>Recommended set to display for Section 508 compliance.</p>
|
|
1491
|
+
</Tooltip.Content>
|
|
1492
|
+
</Tooltip>
|
|
1493
|
+
}
|
|
1494
|
+
/>
|
|
2168
1495
|
)}
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
1496
|
+
|
|
1497
|
+
{'us' === config.general.geoType && (
|
|
1498
|
+
<CheckBox
|
|
1499
|
+
value={general.territoriesAlwaysShow || false}
|
|
1500
|
+
section='general'
|
|
1501
|
+
subsection={null}
|
|
1502
|
+
fieldName='territoriesAlwaysShow'
|
|
1503
|
+
label='Show All Territories'
|
|
1504
|
+
updateField={updateField}
|
|
1505
|
+
/>
|
|
1506
|
+
)}
|
|
1507
|
+
</AccordionItemPanel>
|
|
1508
|
+
</AccordionItem>
|
|
1509
|
+
<AccordionItem>
|
|
1510
|
+
{' '}
|
|
1511
|
+
{/* General */}
|
|
1512
|
+
<AccordionItemHeading>
|
|
1513
|
+
<AccordionItemButton>General</AccordionItemButton>
|
|
1514
|
+
</AccordionItemHeading>
|
|
1515
|
+
<AccordionItemPanel>
|
|
1516
|
+
<TextField
|
|
1517
|
+
value={general.title}
|
|
1518
|
+
data-testid='title-input'
|
|
1519
|
+
updateField={updateField}
|
|
1520
|
+
section='general'
|
|
1521
|
+
fieldName='title'
|
|
1522
|
+
id='title'
|
|
1523
|
+
label='Title'
|
|
1524
|
+
placeholder='Map Title'
|
|
1525
|
+
tooltip={
|
|
2176
1526
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
2177
1527
|
<Tooltip.Target>
|
|
2178
|
-
<Icon
|
|
2179
|
-
display='question'
|
|
2180
|
-
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2181
|
-
/>
|
|
1528
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2182
1529
|
</Tooltip.Target>
|
|
2183
1530
|
<Tooltip.Content>
|
|
2184
1531
|
<p>
|
|
2185
|
-
|
|
2186
|
-
|
|
1532
|
+
Title is required to set the name of the download file but can be hidden using the option
|
|
1533
|
+
below.
|
|
2187
1534
|
</p>
|
|
2188
1535
|
</Tooltip.Content>
|
|
2189
1536
|
</Tooltip>
|
|
2190
|
-
|
|
2191
|
-
}
|
|
2192
|
-
value={legend.style || ''}
|
|
2193
|
-
options={[
|
|
2194
|
-
{ value: 'circles', label: 'circles' },
|
|
2195
|
-
{ value: 'boxes', label: 'boxes' },
|
|
2196
|
-
...(legend.position !== 'side' ? [{ value: 'gradient', label: 'gradient' }] : [])
|
|
2197
|
-
]}
|
|
2198
|
-
onChange={event => {
|
|
2199
|
-
handleEditorChanges('legendStyle', event.target.value)
|
|
2200
|
-
}}
|
|
2201
|
-
/>
|
|
2202
|
-
)}
|
|
2203
|
-
{'navigation' !== config.general.type && config.legend.style === 'gradient' && (
|
|
2204
|
-
<label>
|
|
2205
|
-
<span className='edit-label'>Gradient Style</span>
|
|
2206
|
-
<select
|
|
2207
|
-
value={legend.subStyle || ''}
|
|
2208
|
-
onChange={event => {
|
|
2209
|
-
handleEditorChanges('legendSubStyle', event.target.value)
|
|
2210
|
-
}}
|
|
2211
|
-
>
|
|
2212
|
-
<option value='linear blocks'>linear blocks</option>
|
|
2213
|
-
<option value='smooth'>smooth</option>
|
|
2214
|
-
</select>
|
|
2215
|
-
</label>
|
|
2216
|
-
)}
|
|
2217
|
-
{allowLegendSeparators && (
|
|
2218
|
-
<TextField
|
|
2219
|
-
value={legend.separators}
|
|
2220
|
-
updateField={updateField}
|
|
2221
|
-
section='legend'
|
|
2222
|
-
fieldName='separators'
|
|
2223
|
-
label='Legend Separators'
|
|
2224
|
-
placeholder='ex: 1,4'
|
|
2225
|
-
tooltip={
|
|
2226
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2227
|
-
<Tooltip.Target>
|
|
2228
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2229
|
-
</Tooltip.Target>
|
|
2230
|
-
<Tooltip.Content>
|
|
2231
|
-
<p>
|
|
2232
|
-
Separators between legend items represented by the legend item numbers separated by commas.
|
|
2233
|
-
</p>
|
|
2234
|
-
</Tooltip.Content>
|
|
2235
|
-
</Tooltip>
|
|
2236
|
-
}
|
|
2237
|
-
/>
|
|
2238
|
-
)}
|
|
2239
|
-
{'navigation' !== config.general.type && config.legend.style === 'gradient' && (
|
|
2240
|
-
<label>
|
|
2241
|
-
<span className='edit-label'>Tick Rotation (Degrees)</span>
|
|
2242
|
-
<input
|
|
2243
|
-
type='number'
|
|
2244
|
-
className='number-narrow'
|
|
2245
|
-
value={legend.tickRotation || ''}
|
|
2246
|
-
onChange={event => {
|
|
2247
|
-
handleEditorChanges('legendTickRotation', event.target.value)
|
|
2248
|
-
}}
|
|
2249
|
-
></input>
|
|
2250
|
-
</label>
|
|
2251
|
-
)}
|
|
2252
|
-
{
|
|
2253
|
-
<label className='checkbox'>
|
|
2254
|
-
<input
|
|
2255
|
-
type='checkbox'
|
|
2256
|
-
checked={legend.hideBorder}
|
|
2257
|
-
onChange={event => {
|
|
2258
|
-
handleEditorChanges('legendBorder', event.target.checked)
|
|
2259
|
-
}}
|
|
2260
|
-
/>
|
|
2261
|
-
<span className='edit-label column-heading'>Hide Legend Box</span>
|
|
2262
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2263
|
-
<Tooltip.Target>
|
|
2264
|
-
<Icon
|
|
2265
|
-
display='question'
|
|
2266
|
-
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2267
|
-
/>
|
|
2268
|
-
</Tooltip.Target>
|
|
2269
|
-
<Tooltip.Content>
|
|
2270
|
-
<p> Default option for top and bottom legends is ‘No Box.’</p>
|
|
2271
|
-
</Tooltip.Content>
|
|
2272
|
-
</Tooltip>
|
|
2273
|
-
</label>
|
|
2274
|
-
}
|
|
2275
|
-
{'side' === legend.position && (
|
|
2276
|
-
<label className='checkbox'>
|
|
2277
|
-
<input
|
|
2278
|
-
type='checkbox'
|
|
2279
|
-
checked={legend.singleColumn}
|
|
2280
|
-
onChange={event => {
|
|
2281
|
-
const _newConfig = cloneConfig(config)
|
|
2282
|
-
_newConfig.legend.singleColumn = event.target.checked
|
|
2283
|
-
_newConfig.legend.singleRow = false
|
|
2284
|
-
_newConfig.legend.verticalSorted = false
|
|
2285
|
-
|
|
2286
|
-
setConfig(_newConfig)
|
|
2287
|
-
}}
|
|
2288
|
-
/>
|
|
2289
|
-
<span className='edit-label'>Single Column Legend</span>
|
|
2290
|
-
</label>
|
|
2291
|
-
)}
|
|
2292
|
-
{'side' !== legend.position && legend.style !== 'gradient' && (
|
|
2293
|
-
<label className='checkbox'>
|
|
2294
|
-
<input
|
|
2295
|
-
type='checkbox'
|
|
2296
|
-
checked={legend.singleRow}
|
|
2297
|
-
onChange={event => {
|
|
2298
|
-
const _newConfig = cloneConfig(config)
|
|
2299
|
-
_newConfig.legend.singleRow = event.target.checked
|
|
2300
|
-
_newConfig.legend.singleColumn = false
|
|
2301
|
-
_newConfig.legend.verticalSorted = false
|
|
2302
|
-
|
|
2303
|
-
setConfig(_newConfig)
|
|
2304
|
-
}}
|
|
1537
|
+
}
|
|
2305
1538
|
/>
|
|
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
|
-
}}
|
|
1539
|
+
<Select
|
|
1540
|
+
value={general.titleStyle}
|
|
1541
|
+
section='general'
|
|
1542
|
+
fieldName='titleStyle'
|
|
1543
|
+
label='Title Style'
|
|
1544
|
+
updateField={updateField}
|
|
1545
|
+
options={[
|
|
1546
|
+
{ value: 'small', label: 'Small (h3)' },
|
|
1547
|
+
{ value: 'large', label: 'Large (h2)' },
|
|
1548
|
+
{ value: 'legacy', label: 'Legacy' }
|
|
1549
|
+
]}
|
|
1550
|
+
tooltip={
|
|
1551
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1552
|
+
<Tooltip.Target>
|
|
1553
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1554
|
+
</Tooltip.Target>
|
|
1555
|
+
<Tooltip.Content>
|
|
1556
|
+
<p>
|
|
1557
|
+
Choose the visual style for the map title. Consider heading order on your page when
|
|
1558
|
+
selecting the title style. For 508 reasons, ensure your page follows a proper heading
|
|
1559
|
+
order.
|
|
1560
|
+
</p>
|
|
1561
|
+
</Tooltip.Content>
|
|
1562
|
+
</Tooltip>
|
|
1563
|
+
}
|
|
2332
1564
|
/>
|
|
2333
|
-
<
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
<input
|
|
2341
|
-
type='checkbox'
|
|
2342
|
-
checked={legend.showSpecialClassesLast}
|
|
2343
|
-
onChange={event => {
|
|
2344
|
-
handleEditorChanges('legendShowSpecialClassesLast', event.target.checked)
|
|
2345
|
-
}}
|
|
1565
|
+
<CheckBox
|
|
1566
|
+
value={config.general.showTitle || false}
|
|
1567
|
+
section='general'
|
|
1568
|
+
subsection={null}
|
|
1569
|
+
fieldName='showTitle'
|
|
1570
|
+
label='Show Title'
|
|
1571
|
+
updateField={updateField}
|
|
2346
1572
|
/>
|
|
2347
|
-
<
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
1573
|
+
<TextField
|
|
1574
|
+
value={general.superTitle || ''}
|
|
1575
|
+
updateField={updateField}
|
|
1576
|
+
section='general'
|
|
1577
|
+
fieldName='superTitle'
|
|
1578
|
+
label='Super Title'
|
|
1579
|
+
tooltip={
|
|
1580
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1581
|
+
<Tooltip.Target>
|
|
1582
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1583
|
+
</Tooltip.Target>
|
|
1584
|
+
<Tooltip.Content>
|
|
1585
|
+
<p>Super Title</p>
|
|
1586
|
+
</Tooltip.Content>
|
|
1587
|
+
</Tooltip>
|
|
1588
|
+
}
|
|
2360
1589
|
/>
|
|
2361
|
-
<
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
{/* Temp Checkbox */}
|
|
2379
|
-
{config.legend.type === 'equalnumber' && (
|
|
2380
|
-
<label className='checkbox'>
|
|
2381
|
-
<input
|
|
2382
|
-
type='checkbox'
|
|
2383
|
-
checked={config.general.equalNumberOptIn}
|
|
2384
|
-
onChange={event => {
|
|
2385
|
-
const _newConfig = _.clone(config)
|
|
2386
|
-
_newConfig.general.equalNumberOptIn = event.target.checked
|
|
2387
|
-
setConfig(_newConfig)
|
|
2388
|
-
}}
|
|
1590
|
+
<TextField
|
|
1591
|
+
type='textarea'
|
|
1592
|
+
value={general.introText}
|
|
1593
|
+
updateField={updateField}
|
|
1594
|
+
section='general'
|
|
1595
|
+
fieldName='introText'
|
|
1596
|
+
label='Message'
|
|
1597
|
+
tooltip={
|
|
1598
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1599
|
+
<Tooltip.Target>
|
|
1600
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1601
|
+
</Tooltip.Target>
|
|
1602
|
+
<Tooltip.Content>
|
|
1603
|
+
<p>Intro Text</p>
|
|
1604
|
+
</Tooltip.Content>
|
|
1605
|
+
</Tooltip>
|
|
1606
|
+
}
|
|
2389
1607
|
/>
|
|
2390
|
-
<
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
<Tooltip.Content>
|
|
2399
|
-
<p>This prevents numbers from being used in more than one category (ie. 0-1, 1-2, 2-3) </p>
|
|
2400
|
-
</Tooltip.Content>
|
|
2401
|
-
</Tooltip>
|
|
2402
|
-
</label>
|
|
2403
|
-
)}
|
|
2404
|
-
|
|
2405
|
-
{'category' !== legend.type && (
|
|
2406
|
-
<Select
|
|
2407
|
-
label={
|
|
2408
|
-
<>
|
|
2409
|
-
Number of Items
|
|
1608
|
+
<TextField
|
|
1609
|
+
type='textarea'
|
|
1610
|
+
value={general.subtext}
|
|
1611
|
+
updateField={updateField}
|
|
1612
|
+
section='general'
|
|
1613
|
+
fieldName='subtext'
|
|
1614
|
+
label='Subtext'
|
|
1615
|
+
tooltip={
|
|
2410
1616
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
2411
1617
|
<Tooltip.Target>
|
|
2412
1618
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2413
1619
|
</Tooltip.Target>
|
|
2414
1620
|
<Tooltip.Content>
|
|
2415
1621
|
<p>
|
|
2416
|
-
|
|
2417
|
-
|
|
1622
|
+
Enter supporting text to display below the data visualization, if applicable. The
|
|
1623
|
+
following HTML tags are supported: strong, em, sup, and sub.
|
|
2418
1624
|
</p>
|
|
2419
1625
|
</Tooltip.Content>
|
|
2420
1626
|
</Tooltip>
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
value
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
/>
|
|
2432
|
-
)}
|
|
2433
|
-
{'category' === legend.type && (
|
|
2434
|
-
<React.Fragment>
|
|
2435
|
-
<label>
|
|
2436
|
-
<span className='edit-label'>
|
|
2437
|
-
Category Order
|
|
1627
|
+
}
|
|
1628
|
+
/>
|
|
1629
|
+
<TextField
|
|
1630
|
+
type='textarea'
|
|
1631
|
+
value={general.footnotes}
|
|
1632
|
+
updateField={updateField}
|
|
1633
|
+
section='general'
|
|
1634
|
+
fieldName='footnotes'
|
|
1635
|
+
label='Footnotes'
|
|
1636
|
+
tooltip={
|
|
2438
1637
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
2439
1638
|
<Tooltip.Target>
|
|
2440
1639
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2441
1640
|
</Tooltip.Target>
|
|
2442
1641
|
<Tooltip.Content>
|
|
2443
|
-
<p>
|
|
1642
|
+
<p>Footnotes</p>
|
|
2444
1643
|
</Tooltip.Content>
|
|
2445
1644
|
</Tooltip>
|
|
2446
|
-
|
|
2447
|
-
</label>
|
|
2448
|
-
{/* 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. */}
|
|
2449
|
-
<DragDropContext
|
|
2450
|
-
onDragEnd={({ source, destination }) => categoryMove(source.index, destination.index)}
|
|
2451
|
-
>
|
|
2452
|
-
<Droppable droppableId='category_order'>
|
|
2453
|
-
{provided => (
|
|
2454
|
-
<ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef}>
|
|
2455
|
-
<CategoryList />
|
|
2456
|
-
{provided.placeholder}
|
|
2457
|
-
</ul>
|
|
2458
|
-
)}
|
|
2459
|
-
</Droppable>
|
|
2460
|
-
</DragDropContext>
|
|
2461
|
-
{runtimeLegend && runtimeLegend.length >= 10 && (
|
|
2462
|
-
<section className='error-box my-2'>
|
|
2463
|
-
<div>
|
|
2464
|
-
<strong className='pt-1'>Warning</strong>
|
|
2465
|
-
<p>
|
|
2466
|
-
The maximum number of categorical legend items is 10. If your data has more than 10
|
|
2467
|
-
categories your map will not display properly.
|
|
2468
|
-
</p>
|
|
2469
|
-
</div>
|
|
2470
|
-
</section>
|
|
2471
|
-
)}
|
|
2472
|
-
</React.Fragment>
|
|
2473
|
-
)}
|
|
2474
|
-
<TextField
|
|
2475
|
-
value={legend.title}
|
|
2476
|
-
updateField={updateField}
|
|
2477
|
-
section='legend'
|
|
2478
|
-
fieldName='title'
|
|
2479
|
-
label='Legend Title'
|
|
2480
|
-
placeholder='Legend Title'
|
|
2481
|
-
/>
|
|
2482
|
-
{false === legend.dynamicDescription && (
|
|
2483
|
-
<TextField
|
|
2484
|
-
type='textarea'
|
|
2485
|
-
value={legend.description}
|
|
2486
|
-
updateField={updateField}
|
|
2487
|
-
section='legend'
|
|
2488
|
-
fieldName='description'
|
|
2489
|
-
label='Legend Description'
|
|
2490
|
-
/>
|
|
2491
|
-
)}
|
|
2492
|
-
{true === legend.dynamicDescription && (
|
|
2493
|
-
<React.Fragment>
|
|
2494
|
-
<label>
|
|
2495
|
-
<span>Legend Description</span>
|
|
2496
|
-
<span className='subtext'>For {displayFilterLegendValue(activeFilterValueForDescription)}</span>
|
|
2497
|
-
<DynamicDesc value={legend.descriptions[String(activeFilterValueForDescription)]} />
|
|
2498
|
-
</label>
|
|
2499
|
-
<label>
|
|
2500
|
-
<Select
|
|
2501
|
-
label='Filter Value'
|
|
2502
|
-
value={String(activeFilterValueForDescription)}
|
|
2503
|
-
options={filterValueOptionList.map(arr => ({
|
|
2504
|
-
value: arr,
|
|
2505
|
-
label: displayFilterLegendValue(arr)
|
|
2506
|
-
}))}
|
|
2507
|
-
onChange={event => {
|
|
2508
|
-
handleEditorChanges('changeActiveFilterValue', event.target.value)
|
|
2509
|
-
}}
|
|
2510
|
-
/>
|
|
2511
|
-
</label>
|
|
2512
|
-
</React.Fragment>
|
|
2513
|
-
)}
|
|
2514
|
-
{config.filters.length > 0 && (
|
|
2515
|
-
<label className='checkbox'>
|
|
2516
|
-
<input
|
|
2517
|
-
type='checkbox'
|
|
2518
|
-
checked={legend.dynamicDescription}
|
|
2519
|
-
onChange={() => {
|
|
2520
|
-
handleEditorChanges('dynamicDescription', filterValueOptionList[0])
|
|
2521
|
-
}}
|
|
2522
|
-
/>
|
|
2523
|
-
<span className='edit-label column-heading'>
|
|
2524
|
-
Dynamic Legend Description
|
|
2525
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2526
|
-
<Tooltip.Target>
|
|
2527
|
-
<Icon
|
|
2528
|
-
display='question'
|
|
2529
|
-
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2530
|
-
/>
|
|
2531
|
-
</Tooltip.Target>
|
|
2532
|
-
<Tooltip.Content>
|
|
2533
|
-
<p>
|
|
2534
|
-
Check this option if the map has multiple filter controls and you want to specify a
|
|
2535
|
-
description for each filter selection.
|
|
2536
|
-
</p>
|
|
2537
|
-
</Tooltip.Content>
|
|
2538
|
-
</Tooltip>
|
|
2539
|
-
</span>
|
|
2540
|
-
</label>
|
|
2541
|
-
)}
|
|
2542
|
-
{(config.filters.length > 0 || config.general.type === 'bubble' || config.general.geoType === 'us') && (
|
|
2543
|
-
<label className='checkbox'>
|
|
2544
|
-
<input
|
|
2545
|
-
type='checkbox'
|
|
2546
|
-
checked={legend.unified}
|
|
2547
|
-
onChange={event => handleEditorChanges('unifiedLegend', event.target.checked)}
|
|
1645
|
+
}
|
|
2548
1646
|
/>
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
</AccordionItemPanel>
|
|
2586
|
-
</AccordionItem>
|
|
2587
|
-
<AccordionItem>
|
|
2588
|
-
<AccordionItemHeading>
|
|
2589
|
-
<AccordionItemButton>Footnotes</AccordionItemButton>
|
|
2590
|
-
</AccordionItemHeading>
|
|
2591
|
-
<AccordionItemPanel>
|
|
2592
|
-
<FootnotesEditor config={config} updateField={updateField} datasets={datasets} />
|
|
2593
|
-
</AccordionItemPanel>
|
|
2594
|
-
</AccordionItem>
|
|
2595
|
-
</>
|
|
2596
|
-
)}
|
|
2597
|
-
{'navigation' !== config.general.type && (
|
|
2598
|
-
<AccordionItem>
|
|
2599
|
-
{' '}
|
|
2600
|
-
{/* Data Table */}
|
|
2601
|
-
<AccordionItemHeading>
|
|
2602
|
-
<AccordionItemButton>Data Table</AccordionItemButton>
|
|
2603
|
-
</AccordionItemHeading>
|
|
2604
|
-
<AccordionItemPanel>
|
|
2605
|
-
<TextField
|
|
2606
|
-
value={table.label}
|
|
2607
|
-
updateField={updateField}
|
|
2608
|
-
section='table'
|
|
2609
|
-
fieldName='label'
|
|
2610
|
-
id='dataTableTitle'
|
|
2611
|
-
label='Data Table Title'
|
|
2612
|
-
placeholder='Data Table'
|
|
2613
|
-
tooltip={
|
|
2614
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2615
|
-
<Tooltip.Target>
|
|
2616
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2617
|
-
</Tooltip.Target>
|
|
2618
|
-
<Tooltip.Content>
|
|
2619
|
-
<p>Label is required for Data Table for 508 Compliance</p>
|
|
2620
|
-
</Tooltip.Content>
|
|
2621
|
-
</Tooltip>
|
|
2622
|
-
}
|
|
2623
|
-
/>
|
|
2624
|
-
<label className='checkbox'>
|
|
2625
|
-
<input
|
|
2626
|
-
type='checkbox'
|
|
2627
|
-
checked={config.table.wrapColumns}
|
|
2628
|
-
onChange={event => {
|
|
2629
|
-
setConfig({
|
|
2630
|
-
...config,
|
|
2631
|
-
table: {
|
|
2632
|
-
...config.table,
|
|
2633
|
-
wrapColumns: event.target.checked
|
|
2634
|
-
}
|
|
2635
|
-
})
|
|
2636
|
-
}}
|
|
2637
|
-
/>
|
|
2638
|
-
<span className='edit-label column-heading'>WRAP DATA TABLE COLUMNS</span>
|
|
2639
|
-
</label>
|
|
2640
|
-
<label className='checkbox'>
|
|
2641
|
-
<input
|
|
2642
|
-
type='checkbox'
|
|
2643
|
-
checked={config.table.forceDisplay !== undefined ? config.table.forceDisplay : !isDashboard}
|
|
2644
|
-
onChange={event => {
|
|
2645
|
-
handleEditorChanges('showDataTable', event.target.checked)
|
|
2646
|
-
}}
|
|
2647
|
-
/>
|
|
2648
|
-
<span className='edit-label column-heading'>
|
|
2649
|
-
Show Data Table
|
|
2650
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2651
|
-
<Tooltip.Target>
|
|
2652
|
-
<Icon
|
|
2653
|
-
display='question'
|
|
2654
|
-
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
1647
|
+
|
|
1648
|
+
{/* <label className="checkbox mt-4">
|
|
1649
|
+
<input type="checkbox" checked={ state.general.showDownloadMediaButton } onChange={(event) => { handleEditorChanges("toggleDownloadMediaButton", event.target.checked) }} />
|
|
1650
|
+
<span className="edit-label">Enable Media Download</span>
|
|
1651
|
+
</label> */}
|
|
1652
|
+
</AccordionItemPanel>
|
|
1653
|
+
</AccordionItem>
|
|
1654
|
+
<AccordionItem>
|
|
1655
|
+
{' '}
|
|
1656
|
+
{/* Columns */}
|
|
1657
|
+
<AccordionItemHeading>
|
|
1658
|
+
<AccordionItemButton>Columns</AccordionItemButton>
|
|
1659
|
+
</AccordionItemHeading>
|
|
1660
|
+
<AccordionItemPanel>
|
|
1661
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
1662
|
+
<label>
|
|
1663
|
+
<span className='edit-label column-heading'>
|
|
1664
|
+
Geography
|
|
1665
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1666
|
+
<Tooltip.Target>
|
|
1667
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1668
|
+
</Tooltip.Target>
|
|
1669
|
+
<Tooltip.Content>
|
|
1670
|
+
<p>
|
|
1671
|
+
Select the source column containing the map location names or, for county-level maps,
|
|
1672
|
+
the FIPS codes.
|
|
1673
|
+
</p>
|
|
1674
|
+
</Tooltip.Content>
|
|
1675
|
+
</Tooltip>
|
|
1676
|
+
</span>
|
|
1677
|
+
<Select
|
|
1678
|
+
value={config.columns.geo ? config.columns.geo.name : columnsOptions[0]}
|
|
1679
|
+
options={columnsOptions.map(c => c.key)}
|
|
1680
|
+
onChange={event => {
|
|
1681
|
+
editColumn('geo', 'name', event.target.value)
|
|
1682
|
+
}}
|
|
2655
1683
|
/>
|
|
2656
|
-
</
|
|
2657
|
-
|
|
2658
|
-
<
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
</label>
|
|
2666
|
-
<label className='checkbox'>
|
|
2667
|
-
<input
|
|
2668
|
-
type='checkbox'
|
|
2669
|
-
checked={config.table.showNonGeoData}
|
|
2670
|
-
onChange={event => {
|
|
2671
|
-
setConfig({
|
|
2672
|
-
...config,
|
|
2673
|
-
table: {
|
|
2674
|
-
...config.table,
|
|
2675
|
-
showNonGeoData: event.target.checked
|
|
2676
|
-
}
|
|
2677
|
-
})
|
|
2678
|
-
}}
|
|
2679
|
-
/>
|
|
2680
|
-
<span className='edit-label column-heading'>
|
|
2681
|
-
Show Non Geographic Data
|
|
2682
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2683
|
-
<Tooltip.Target>
|
|
2684
|
-
<Icon
|
|
2685
|
-
display='question'
|
|
2686
|
-
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
1684
|
+
</label>
|
|
1685
|
+
{config.general.type === 'us-geocode' && (
|
|
1686
|
+
<CheckBox
|
|
1687
|
+
value={config.general.convertFipsCodes}
|
|
1688
|
+
section='general'
|
|
1689
|
+
subsection={null}
|
|
1690
|
+
fieldName='convertFipsCodes'
|
|
1691
|
+
label='Convert FIPS Codes to Geography Name'
|
|
1692
|
+
updateField={updateField}
|
|
2687
1693
|
/>
|
|
2688
|
-
|
|
2689
|
-
<Tooltip.Content>
|
|
2690
|
-
<p>Show any data not associated with a geographic location</p>
|
|
2691
|
-
</Tooltip.Content>
|
|
2692
|
-
</Tooltip>
|
|
2693
|
-
</span>
|
|
2694
|
-
</label>
|
|
2695
|
-
<TextField
|
|
2696
|
-
value={table.indexLabel || ''}
|
|
2697
|
-
updateField={updateField}
|
|
2698
|
-
section='table'
|
|
2699
|
-
fieldName='indexLabel'
|
|
2700
|
-
label='Index Column Header'
|
|
2701
|
-
placeholder='Location'
|
|
2702
|
-
tooltip={
|
|
2703
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2704
|
-
<Tooltip.Target>
|
|
2705
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2706
|
-
</Tooltip.Target>
|
|
2707
|
-
<Tooltip.Content>
|
|
2708
|
-
<p>
|
|
2709
|
-
To comply with 508 standards, if the first column in the data table has no header, enter a
|
|
2710
|
-
brief one here.
|
|
2711
|
-
</p>
|
|
2712
|
-
</Tooltip.Content>
|
|
2713
|
-
</Tooltip>
|
|
2714
|
-
}
|
|
2715
|
-
/>
|
|
2716
|
-
<TextField
|
|
2717
|
-
value={config.table.caption}
|
|
2718
|
-
updateField={updateField}
|
|
2719
|
-
section='table'
|
|
2720
|
-
fieldName='caption'
|
|
2721
|
-
label='Screen Reader Description'
|
|
2722
|
-
placeholder='Data Table'
|
|
2723
|
-
tooltip={
|
|
2724
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2725
|
-
<Tooltip.Target>
|
|
2726
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2727
|
-
</Tooltip.Target>
|
|
2728
|
-
<Tooltip.Content>
|
|
2729
|
-
<p>Enter a description of the data table to be read by screen readers.</p>
|
|
2730
|
-
</Tooltip.Content>
|
|
2731
|
-
</Tooltip>
|
|
2732
|
-
}
|
|
2733
|
-
type='textarea'
|
|
2734
|
-
/>
|
|
2735
|
-
<label className='checkbox'>
|
|
2736
|
-
<input
|
|
2737
|
-
type='checkbox'
|
|
2738
|
-
checked={config.table.limitHeight}
|
|
2739
|
-
onChange={event => {
|
|
2740
|
-
handleEditorChanges('limitDataTableHeight', event.target.checked)
|
|
2741
|
-
}}
|
|
2742
|
-
/>
|
|
2743
|
-
<span className='edit-label'>Limit Table Height</span>
|
|
2744
|
-
</label>
|
|
2745
|
-
{config.table.limitHeight && (
|
|
2746
|
-
<TextField
|
|
2747
|
-
value={table.height}
|
|
2748
|
-
updateField={updateField}
|
|
2749
|
-
section='table'
|
|
2750
|
-
fieldName='height'
|
|
2751
|
-
label='Data Table Height'
|
|
2752
|
-
placeholder='Height(px)'
|
|
2753
|
-
type='number'
|
|
2754
|
-
min='0'
|
|
2755
|
-
max='500'
|
|
2756
|
-
/>
|
|
2757
|
-
)}
|
|
2758
|
-
|
|
2759
|
-
<TextField
|
|
2760
|
-
value={table.cellMinWidth}
|
|
2761
|
-
updateField={updateField}
|
|
2762
|
-
section='table'
|
|
2763
|
-
fieldName='cellMinWidth'
|
|
2764
|
-
label='Table Cell Min Width'
|
|
2765
|
-
type='number'
|
|
2766
|
-
min='0'
|
|
2767
|
-
max='500'
|
|
2768
|
-
/>
|
|
1694
|
+
)}
|
|
2769
1695
|
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
/>
|
|
2778
|
-
<span className='edit-label'>Map loads with data table expanded</span>
|
|
2779
|
-
</label>
|
|
2780
|
-
<CheckBox
|
|
2781
|
-
value={config.table.download}
|
|
2782
|
-
fieldName='download'
|
|
2783
|
-
label='Show Download CSV Link'
|
|
2784
|
-
section='table'
|
|
2785
|
-
updateField={updateField}
|
|
2786
|
-
/>
|
|
2787
|
-
{config.table.download && (
|
|
2788
|
-
<>
|
|
2789
|
-
<label className='checkbox'>
|
|
2790
|
-
<input
|
|
2791
|
-
type='checkbox'
|
|
2792
|
-
className='ms-4'
|
|
2793
|
-
checked={config.table.showDownloadLinkBelow}
|
|
2794
|
-
onChange={event => {
|
|
2795
|
-
handleEditorChanges('toggleDownloadLinkBelow', event.target.checked)
|
|
2796
|
-
}}
|
|
1696
|
+
<CheckBox
|
|
1697
|
+
value={config.general.hideGeoColumnInTooltip || false}
|
|
1698
|
+
section='general'
|
|
1699
|
+
subsection={null}
|
|
1700
|
+
fieldName='hideGeoColumnInTooltip'
|
|
1701
|
+
label='Hide Geography Column Name in Tooltip'
|
|
1702
|
+
updateField={updateField}
|
|
2797
1703
|
/>
|
|
2798
|
-
<
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
onChange={event => {
|
|
2816
|
-
const _newConfig = cloneConfig(config)
|
|
2817
|
-
_newConfig.table.showDataTableLink = event.target.checked
|
|
2818
|
-
setConfig(_newConfig)
|
|
2819
|
-
}}
|
|
2820
|
-
/>
|
|
2821
|
-
<span className='edit-label'>Show Data Table Name & Link</span>
|
|
2822
|
-
</label>
|
|
2823
|
-
)}
|
|
2824
|
-
{isLoadedFromUrl && (
|
|
2825
|
-
<label className='checkbox'>
|
|
2826
|
-
<input
|
|
2827
|
-
type='checkbox'
|
|
2828
|
-
checked={config.table.showDownloadUrl}
|
|
2829
|
-
onChange={event => {
|
|
2830
|
-
const _newConfig = cloneConfig(config)
|
|
2831
|
-
_newConfig.table.showDownloadUrl = event.target.checked
|
|
2832
|
-
setConfig(_newConfig)
|
|
2833
|
-
}}
|
|
2834
|
-
/>
|
|
2835
|
-
<span className='edit-label'>Show URL to Automatically Updated Data</span>
|
|
2836
|
-
</label>
|
|
2837
|
-
)}
|
|
2838
|
-
<label className='checkbox'>
|
|
2839
|
-
<input
|
|
2840
|
-
type='checkbox'
|
|
2841
|
-
checked={config.table.showFullGeoNameInCSV}
|
|
2842
|
-
onChange={event => {
|
|
2843
|
-
handleEditorChanges('toggleShowFullGeoNameInCSV', event.target.checked)
|
|
2844
|
-
}}
|
|
2845
|
-
/>
|
|
2846
|
-
<span className='edit-label'>Include Full Geo Name in CSV Download</span>
|
|
2847
|
-
</label>
|
|
2848
|
-
<label className='checkbox'>
|
|
2849
|
-
<input
|
|
2850
|
-
type='checkbox'
|
|
2851
|
-
checked={config.general.showDownloadImgButton}
|
|
2852
|
-
onChange={event => {
|
|
2853
|
-
handleEditorChanges('toggleDownloadImgButton', event.target.checked)
|
|
2854
|
-
}}
|
|
2855
|
-
/>
|
|
2856
|
-
<span className='edit-label'>Enable Image Download</span>
|
|
2857
|
-
</label>
|
|
2858
|
-
|
|
2859
|
-
{/* <label className='checkbox'>
|
|
2860
|
-
<input
|
|
2861
|
-
type='checkbox'
|
|
2862
|
-
checked={state.general.showDownloadPdfButton}
|
|
2863
|
-
onChange={event => {
|
|
2864
|
-
handleEditorChanges('toggleDownloadPdfButton', event.target.checked)
|
|
2865
|
-
}}
|
|
1704
|
+
<TextField
|
|
1705
|
+
value={config.general.geoLabelOverride}
|
|
1706
|
+
section='general'
|
|
1707
|
+
fieldName='geoLabelOverride'
|
|
1708
|
+
label='Geography Label'
|
|
1709
|
+
className='edit-label'
|
|
1710
|
+
updateField={updateField}
|
|
1711
|
+
tooltip={
|
|
1712
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1713
|
+
<Tooltip.Target>
|
|
1714
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1715
|
+
</Tooltip.Target>
|
|
1716
|
+
<Tooltip.Content>
|
|
1717
|
+
<p>Enter a geography label for use in tooltips.</p>
|
|
1718
|
+
</Tooltip.Content>
|
|
1719
|
+
</Tooltip>
|
|
1720
|
+
}
|
|
2866
1721
|
/>
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
<Select
|
|
2880
|
-
label={
|
|
2881
|
-
<>
|
|
2882
|
-
Detail displays on{' '}
|
|
2883
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2884
|
-
<Tooltip.Target>
|
|
2885
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2886
|
-
</Tooltip.Target>
|
|
2887
|
-
<Tooltip.Content>
|
|
2888
|
-
<p>
|
|
2889
|
-
At mobile sizes, information always appears in a popover modal when a user taps on an item.
|
|
2890
|
-
</p>
|
|
2891
|
-
</Tooltip.Content>
|
|
2892
|
-
</Tooltip>
|
|
2893
|
-
</>
|
|
2894
|
-
}
|
|
2895
|
-
value={config.tooltips.appearanceType}
|
|
2896
|
-
options={[
|
|
2897
|
-
{ value: 'hover', label: 'Hover - Tooltip' },
|
|
2898
|
-
{ value: 'click', label: 'Click - Popover Modal' }
|
|
2899
|
-
]}
|
|
2900
|
-
onChange={event => {
|
|
2901
|
-
handleEditorChanges('appearanceType', event.target.value)
|
|
2902
|
-
}}
|
|
2903
|
-
/>
|
|
2904
|
-
{'click' === config.tooltips.appearanceType && (
|
|
2905
|
-
<TextField
|
|
2906
|
-
value={tooltips.linkLabel}
|
|
2907
|
-
section='tooltips'
|
|
2908
|
-
fieldName='linkLabel'
|
|
2909
|
-
label='Tooltips Link Label'
|
|
2910
|
-
updateField={updateField}
|
|
2911
|
-
/>
|
|
2912
|
-
)}
|
|
2913
|
-
</AccordionItemPanel>
|
|
2914
|
-
</AccordionItem>
|
|
2915
|
-
<AccordionItem>
|
|
2916
|
-
{' '}
|
|
2917
|
-
{/* Visual */}
|
|
2918
|
-
<AccordionItemHeading>
|
|
2919
|
-
<AccordionItemButton>Visual</AccordionItemButton>
|
|
2920
|
-
</AccordionItemHeading>
|
|
2921
|
-
<AccordionItemPanel>
|
|
2922
|
-
<label>
|
|
2923
|
-
<span className='edit-label'>Header Theme</span>
|
|
2924
|
-
<ul className='color-palette'>
|
|
2925
|
-
{HEADER_COLORS.map(palette => {
|
|
2926
|
-
return (
|
|
2927
|
-
<li
|
|
2928
|
-
title={palette}
|
|
2929
|
-
key={palette}
|
|
2930
|
-
onClick={() => {
|
|
2931
|
-
handleEditorChanges('headerColor', palette)
|
|
2932
|
-
}}
|
|
2933
|
-
className={config.general.headerColor === palette ? 'selected ' + palette : palette}
|
|
2934
|
-
></li>
|
|
2935
|
-
)
|
|
2936
|
-
})}
|
|
2937
|
-
</ul>
|
|
2938
|
-
</label>
|
|
2939
|
-
<label className='checkbox'>
|
|
2940
|
-
<input
|
|
2941
|
-
type='checkbox'
|
|
2942
|
-
checked={config.general.showTitle || false}
|
|
2943
|
-
onChange={event => {
|
|
2944
|
-
handleEditorChanges('showTitle', event.target.checked)
|
|
2945
|
-
}}
|
|
2946
|
-
/>
|
|
2947
|
-
<span className='edit-label'>Show Title</span>
|
|
2948
|
-
</label>
|
|
2949
|
-
|
|
2950
|
-
{'navigation' === config.general.type && (
|
|
2951
|
-
<label className='checkbox'>
|
|
2952
|
-
<input
|
|
2953
|
-
type='checkbox'
|
|
2954
|
-
checked={config.general.fullBorder || false}
|
|
2955
|
-
onChange={event => {
|
|
2956
|
-
const _newConfig = cloneConfig(config)
|
|
2957
|
-
_newConfig.general.fullBorder = event.target.checked
|
|
2958
|
-
setConfig(_newConfig)
|
|
2959
|
-
}}
|
|
2960
|
-
/>
|
|
2961
|
-
<span className='edit-label'>Add border around map</span>
|
|
2962
|
-
</label>
|
|
2963
|
-
)}
|
|
2964
|
-
<Select
|
|
2965
|
-
label='Geo Border Color'
|
|
2966
|
-
value={config.general.geoBorderColor || ''}
|
|
2967
|
-
options={[
|
|
2968
|
-
{ value: 'darkGray', label: 'Dark Gray (Default)' },
|
|
2969
|
-
{ value: 'sameAsBackground', label: 'White' }
|
|
2970
|
-
]}
|
|
2971
|
-
onChange={event => {
|
|
2972
|
-
handleEditorChanges('geoBorderColor', event.target.value)
|
|
2973
|
-
}}
|
|
2974
|
-
/>
|
|
2975
|
-
<label>
|
|
2976
|
-
<span className='edit-label'>Map Color Palette</span>
|
|
2977
|
-
</label>
|
|
2978
|
-
<div className='mb-2'>
|
|
2979
|
-
<small className='text-muted'>
|
|
2980
|
-
Review color contrasts{' '}
|
|
2981
|
-
<a href='https://webaim.org/resources/contrastchecker/' target='_blank' rel='noopener noreferrer'>
|
|
2982
|
-
here
|
|
2983
|
-
</a>
|
|
2984
|
-
</small>
|
|
2985
|
-
</div>
|
|
2986
|
-
<DeveloperPaletteRollback config={config} updateConfig={setConfig} />
|
|
2987
|
-
<InputToggle
|
|
2988
|
-
type='3d'
|
|
2989
|
-
section='general'
|
|
2990
|
-
subsection='palette'
|
|
2991
|
-
fieldName='isReversed'
|
|
2992
|
-
size='small'
|
|
2993
|
-
label='Use selected palette in reverse order'
|
|
2994
|
-
onClick={() => {
|
|
2995
|
-
const _state = cloneConfig(config)
|
|
2996
|
-
const currentPaletteName = config.general.palette?.name || ''
|
|
2997
|
-
_state.general.palette.isReversed = !_state.general.palette.isReversed
|
|
2998
|
-
let paletteName = ''
|
|
2999
|
-
if (_state.general.palette.isReversed && !currentPaletteName.endsWith('reverse')) {
|
|
3000
|
-
paletteName = currentPaletteName + 'reverse'
|
|
3001
|
-
}
|
|
3002
|
-
if (!_state.general.palette.isReversed && currentPaletteName.endsWith('reverse')) {
|
|
3003
|
-
paletteName = currentPaletteName.slice(0, -7)
|
|
3004
|
-
}
|
|
3005
|
-
if (paletteName) {
|
|
3006
|
-
_state.general.palette.name = paletteName
|
|
3007
|
-
}
|
|
3008
|
-
setConfig(_state)
|
|
3009
|
-
}}
|
|
3010
|
-
value={config.general.palette.isReversed}
|
|
3011
|
-
/>
|
|
3012
|
-
<span>Sequential</span>
|
|
3013
|
-
<PaletteSelector
|
|
3014
|
-
palettes={sequential}
|
|
3015
|
-
colorPalettes={colorPalettes}
|
|
3016
|
-
config={config}
|
|
3017
|
-
onPaletteSelect={handlePaletteSelection}
|
|
3018
|
-
selectedPalette={getCurrentPaletteName(config)}
|
|
3019
|
-
colorIndices={[2, 3, 5]}
|
|
3020
|
-
className='color-palette'
|
|
3021
|
-
element='li'
|
|
3022
|
-
getItemClassName={getPaletteClassName}
|
|
3023
|
-
/>
|
|
3024
|
-
<span>Non-Sequential</span>
|
|
3025
|
-
<PaletteSelector
|
|
3026
|
-
palettes={nonSequential}
|
|
3027
|
-
colorPalettes={colorPalettes}
|
|
3028
|
-
config={config}
|
|
3029
|
-
onPaletteSelect={handlePaletteSelection}
|
|
3030
|
-
selectedPalette={getCurrentPaletteName(config)}
|
|
3031
|
-
colorIndices={[2, 3, 5]}
|
|
3032
|
-
className='color-palette'
|
|
3033
|
-
element='li'
|
|
3034
|
-
getItemClassName={getPaletteClassName}
|
|
3035
|
-
minColorsForFilter={(_, paletteAccessor, config) => {
|
|
3036
|
-
if (paletteAccessor.length <= 8 && config.general.geoType === 'us-region') {
|
|
3037
|
-
return false
|
|
3038
|
-
}
|
|
3039
|
-
return true
|
|
3040
|
-
}}
|
|
3041
|
-
/>
|
|
3042
|
-
<span>Colorblind Safe</span>
|
|
3043
|
-
<PaletteSelector
|
|
3044
|
-
palettes={accessibleColors}
|
|
3045
|
-
colorPalettes={colorPalettes}
|
|
3046
|
-
config={config}
|
|
3047
|
-
onPaletteSelect={handlePaletteSelection}
|
|
3048
|
-
selectedPalette={getCurrentPaletteName(config)}
|
|
3049
|
-
colorIndices={[2, 3, 5]}
|
|
3050
|
-
className='color-palette'
|
|
3051
|
-
element='li'
|
|
3052
|
-
getItemClassName={getPaletteClassName}
|
|
3053
|
-
minColorsForFilter={(_, paletteAccessor, config) => {
|
|
3054
|
-
if (paletteAccessor.length <= 8 && config.general.geoType === 'us-region') {
|
|
3055
|
-
return false
|
|
3056
|
-
}
|
|
3057
|
-
return true
|
|
3058
|
-
}}
|
|
3059
|
-
/>
|
|
3060
|
-
<label>
|
|
3061
|
-
Geocode Settings
|
|
3062
|
-
<TextField
|
|
3063
|
-
type='number'
|
|
3064
|
-
value={config.visual.geoCodeCircleSize}
|
|
3065
|
-
section='visual'
|
|
3066
|
-
max='10'
|
|
3067
|
-
fieldName='geoCodeCircleSize'
|
|
3068
|
-
label='Geocode Circle Size'
|
|
3069
|
-
updateField={updateField}
|
|
3070
|
-
/>
|
|
3071
|
-
</label>
|
|
3072
|
-
|
|
3073
|
-
{config.general.type === 'bubble' && (
|
|
3074
|
-
<>
|
|
3075
|
-
<TextField
|
|
3076
|
-
type='number'
|
|
3077
|
-
value={config.visual.minBubbleSize}
|
|
3078
|
-
section='visual'
|
|
3079
|
-
fieldName='minBubbleSize'
|
|
3080
|
-
label='Minimum Bubble Size'
|
|
3081
|
-
updateField={updateField}
|
|
3082
|
-
/>
|
|
3083
|
-
<TextField
|
|
3084
|
-
type='number'
|
|
3085
|
-
value={config.visual.maxBubbleSize}
|
|
3086
|
-
section='visual'
|
|
3087
|
-
fieldName='maxBubbleSize'
|
|
3088
|
-
label='Maximum Bubble Size'
|
|
3089
|
-
updateField={updateField}
|
|
3090
|
-
/>
|
|
3091
|
-
</>
|
|
3092
|
-
)}
|
|
3093
|
-
{(config.general.geoType === 'world' ||
|
|
3094
|
-
(config.general.geoType === 'us' && config.general.type === 'bubble')) && (
|
|
3095
|
-
<label className='checkbox'>
|
|
3096
|
-
<input
|
|
3097
|
-
type='checkbox'
|
|
3098
|
-
checked={config.visual.showBubbleZeros}
|
|
3099
|
-
onChange={event => {
|
|
3100
|
-
const _newConfig = _.cloneDeep(config)
|
|
3101
|
-
_newConfig.visual.showBubbleZeros = event.target.checked
|
|
3102
|
-
setConfig(_newConfig)
|
|
3103
|
-
}}
|
|
3104
|
-
/>
|
|
3105
|
-
<span className='edit-label'>Show Data with Zero's on Bubble Map</span>
|
|
3106
|
-
</label>
|
|
3107
|
-
)}
|
|
3108
|
-
{(config.general.geoType === 'world' || config.general.geoType === 'single-state') && (
|
|
3109
|
-
<label className='checkbox'>
|
|
3110
|
-
<input
|
|
3111
|
-
type='checkbox'
|
|
3112
|
-
checked={config.general.allowMapZoom}
|
|
3113
|
-
onChange={event => {
|
|
3114
|
-
const _newConfig = cloneConfig(config)
|
|
3115
|
-
_newConfig.general.allowMapZoom = event.target.checked
|
|
3116
|
-
_newConfig.mapPosition.coordinates = config.general.geoType === 'world' ? [0, 30] : [0, 0]
|
|
3117
|
-
_newConfig.mapPosition.zoom = 1
|
|
3118
|
-
setConfig(_newConfig)
|
|
3119
|
-
}}
|
|
3120
|
-
/>
|
|
3121
|
-
<span className='edit-label'>Allow Map Zooming</span>
|
|
3122
|
-
</label>
|
|
3123
|
-
)}
|
|
3124
|
-
{config.general.type === 'bubble' && (
|
|
3125
|
-
<label className='checkbox'>
|
|
3126
|
-
<input
|
|
3127
|
-
type='checkbox'
|
|
3128
|
-
checked={config.visual.extraBubbleBorder}
|
|
3129
|
-
onChange={event => {
|
|
3130
|
-
const _newConfig = cloneConfig(config)
|
|
3131
|
-
_newConfig.visual.extraBubbleBorder = event.target.checked
|
|
3132
|
-
setConfig(_newConfig)
|
|
3133
|
-
}}
|
|
3134
|
-
/>
|
|
3135
|
-
<span className='edit-label'>Bubble Map has extra border</span>
|
|
3136
|
-
</label>
|
|
3137
|
-
)}
|
|
3138
|
-
{(config.general.geoType === 'us' ||
|
|
3139
|
-
config.general.geoType === 'us-county' ||
|
|
3140
|
-
config.general.geoType === 'world') && (
|
|
3141
|
-
<>
|
|
3142
|
-
<label>
|
|
3143
|
-
<span className='edit-label'>Default City Style</span>
|
|
3144
|
-
<select
|
|
3145
|
-
value={config.visual.cityStyle || false}
|
|
3146
|
-
onChange={event => {
|
|
3147
|
-
handleEditorChanges('handleCityStyle', event.target.value)
|
|
3148
|
-
}}
|
|
3149
|
-
>
|
|
3150
|
-
<option value='circle'>Circle</option>
|
|
3151
|
-
<option value='pin'>Pin</option>
|
|
3152
|
-
<option value='square'>Square</option>
|
|
3153
|
-
<option value='triangle'>Triangle</option>
|
|
3154
|
-
<option value='diamond'>Diamond</option>
|
|
3155
|
-
<option value='star'>Star</option>
|
|
3156
|
-
</select>
|
|
3157
|
-
</label>
|
|
3158
|
-
<TextField
|
|
3159
|
-
value={config.visual.cityStyleLabel}
|
|
3160
|
-
section='visual'
|
|
3161
|
-
fieldName='cityStyleLabel'
|
|
3162
|
-
label='Label (Optional) '
|
|
3163
|
-
updateField={updateField}
|
|
3164
|
-
tooltip={
|
|
3165
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
3166
|
-
<Tooltip.Target>
|
|
3167
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
3168
|
-
</Tooltip.Target>
|
|
3169
|
-
<Tooltip.Content>
|
|
3170
|
-
<p>When a label is provided, the default city style will appear in the legend.</p>
|
|
3171
|
-
</Tooltip.Content>
|
|
3172
|
-
</Tooltip>
|
|
3173
|
-
}
|
|
3174
|
-
/>
|
|
3175
|
-
</>
|
|
3176
|
-
)}
|
|
3177
|
-
{/* <AdditionalCityStyles /> */}
|
|
3178
|
-
<>
|
|
3179
|
-
{config.visual.additionalCityStyles.length > 0 &&
|
|
3180
|
-
config.visual.additionalCityStyles.map(({ label, column, value, shape }, i) => {
|
|
3181
|
-
return (
|
|
3182
|
-
<div className='edit-block' key={`additional-city-style-${i}`}>
|
|
3183
|
-
<button
|
|
3184
|
-
className='remove-column'
|
|
3185
|
-
onClick={e => {
|
|
3186
|
-
e.preventDefault()
|
|
3187
|
-
editCityStyles('remove', i, '', '')
|
|
1722
|
+
</fieldset>
|
|
1723
|
+
{'navigation' !== config.general.type && (
|
|
1724
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
1725
|
+
<Select
|
|
1726
|
+
label='Data Column'
|
|
1727
|
+
value={columns.primary.name}
|
|
1728
|
+
options={columnsOptions.map(c => c.key)}
|
|
1729
|
+
onChange={event => {
|
|
1730
|
+
const _state = cloneConfig(config)
|
|
1731
|
+
_state.columns.primary.name = event.target.value
|
|
1732
|
+
_state.columns.primary.label = event.target.value
|
|
1733
|
+
setConfig(_state)
|
|
3188
1734
|
}}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
</select>
|
|
3203
|
-
</label>
|
|
3204
|
-
<label>
|
|
3205
|
-
<span className='edit-label column-heading'>Value to Trigger</span>
|
|
3206
|
-
<input
|
|
3207
|
-
type='text'
|
|
3208
|
-
value={value}
|
|
3209
|
-
onChange={e => {
|
|
3210
|
-
editCityStyles('update', i, 'value', e.target.value)
|
|
3211
|
-
}}
|
|
3212
|
-
></input>
|
|
3213
|
-
</label>
|
|
3214
|
-
<label>
|
|
3215
|
-
<span className='edit-label column-heading'>Shape</span>
|
|
3216
|
-
<select
|
|
3217
|
-
value={shape}
|
|
3218
|
-
onChange={e => {
|
|
3219
|
-
editCityStyles('update', i, 'shape', e.target.value)
|
|
3220
|
-
}}
|
|
3221
|
-
>
|
|
3222
|
-
{getCityStyleOptions('value')}
|
|
3223
|
-
</select>
|
|
3224
|
-
</label>
|
|
1735
|
+
tooltip={
|
|
1736
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1737
|
+
<Tooltip.Target>
|
|
1738
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1739
|
+
</Tooltip.Target>
|
|
1740
|
+
<Tooltip.Content>
|
|
1741
|
+
<p>
|
|
1742
|
+
Select the source column containing the categorical or numeric values to be mapped.
|
|
1743
|
+
</p>
|
|
1744
|
+
</Tooltip.Content>
|
|
1745
|
+
</Tooltip>
|
|
1746
|
+
}
|
|
1747
|
+
/>
|
|
3225
1748
|
<label>
|
|
3226
|
-
<
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
1749
|
+
<CheckBox
|
|
1750
|
+
value={config.general.hidePrimaryColumnInTooltip || false}
|
|
1751
|
+
section='general'
|
|
1752
|
+
subsection={null}
|
|
1753
|
+
fieldName='hidePrimaryColumnInTooltip'
|
|
1754
|
+
label='Hide Data Column Name in Tooltip'
|
|
1755
|
+
updateField={updateField}
|
|
1756
|
+
onChange={event => {
|
|
1757
|
+
handleEditorChanges('hidePrimaryColumnInTooltip', event.target.checked)
|
|
3233
1758
|
}}
|
|
3234
1759
|
/>
|
|
3235
1760
|
</label>
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
<Select
|
|
3264
|
-
label='Leaflet Theme'
|
|
3265
|
-
options={layerOptions}
|
|
3266
|
-
section={'leaflet'}
|
|
3267
|
-
fieldName='theme'
|
|
3268
|
-
updateField={updateField}
|
|
3269
|
-
/>
|
|
3270
|
-
</>
|
|
3271
|
-
)}
|
|
3272
|
-
</AccordionItemPanel>
|
|
3273
|
-
</AccordionItem>
|
|
3274
|
-
<AccordionItem>
|
|
3275
|
-
<AccordionItemHeading>
|
|
3276
|
-
<AccordionItemButton>Custom Map Layers</AccordionItemButton>
|
|
3277
|
-
</AccordionItemHeading>
|
|
3278
|
-
<AccordionItemPanel>
|
|
3279
|
-
{config.map.layers.length === 0 && <p>There are currently no layers.</p>}
|
|
3280
|
-
|
|
3281
|
-
{config.map.layers.map((layer, index) => {
|
|
3282
|
-
return (
|
|
3283
|
-
<>
|
|
3284
|
-
<Accordion allowZeroExpanded>
|
|
3285
|
-
<AccordionItem className='series-item map-layers-list'>
|
|
3286
|
-
<AccordionItemHeading className='series-item__title map-layers-list--title'>
|
|
3287
|
-
<AccordionItemButton>{`Layer ${index + 1}: ${layer.name}`}</AccordionItemButton>
|
|
3288
|
-
</AccordionItemHeading>
|
|
3289
|
-
<AccordionItemPanel>
|
|
3290
|
-
<div className='map-layers-panel'>
|
|
3291
|
-
<label htmlFor='layerName'>Layer Name:</label>
|
|
3292
|
-
<input
|
|
3293
|
-
type='text'
|
|
3294
|
-
name='layerName'
|
|
3295
|
-
value={layer.name}
|
|
3296
|
-
onChange={e => handleMapLayer(e, index, 'name')}
|
|
3297
|
-
/>
|
|
3298
|
-
<label htmlFor='layerFilename'>File:</label>
|
|
3299
|
-
<input
|
|
3300
|
-
type='text'
|
|
3301
|
-
name='layerFilename'
|
|
3302
|
-
value={layer.url}
|
|
3303
|
-
onChange={e => handleMapLayer(e, index, 'url')}
|
|
3304
|
-
/>
|
|
3305
|
-
<label htmlFor='layerNamespace'>TOPOJSON Namespace:</label>
|
|
3306
|
-
<input
|
|
3307
|
-
type='text'
|
|
3308
|
-
name='layerNamespace'
|
|
3309
|
-
value={layer.namespace}
|
|
3310
|
-
onChange={e => handleMapLayer(e, index, 'namespace')}
|
|
1761
|
+
<TextField
|
|
1762
|
+
value={columns.primary.label}
|
|
1763
|
+
section='columns'
|
|
1764
|
+
subsection='primary'
|
|
1765
|
+
fieldName='label'
|
|
1766
|
+
label='Data Label'
|
|
1767
|
+
updateField={updateField}
|
|
1768
|
+
tooltip={
|
|
1769
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1770
|
+
<Tooltip.Target>
|
|
1771
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1772
|
+
</Tooltip.Target>
|
|
1773
|
+
<Tooltip.Content>
|
|
1774
|
+
<p>Enter a data label for use in tooltips and the data table.</p>
|
|
1775
|
+
</Tooltip.Content>
|
|
1776
|
+
</Tooltip>
|
|
1777
|
+
}
|
|
1778
|
+
/>
|
|
1779
|
+
<ul className='column-edit'>
|
|
1780
|
+
<li className='three-col'>
|
|
1781
|
+
<TextField
|
|
1782
|
+
value={columns.primary.prefix}
|
|
1783
|
+
section='columns'
|
|
1784
|
+
subsection='primary'
|
|
1785
|
+
fieldName='prefix'
|
|
1786
|
+
label='Prefix'
|
|
1787
|
+
updateField={updateField}
|
|
3311
1788
|
/>
|
|
3312
|
-
<
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
1789
|
+
<TextField
|
|
1790
|
+
value={columns.primary.suffix}
|
|
1791
|
+
section='columns'
|
|
1792
|
+
subsection='primary'
|
|
1793
|
+
fieldName='suffix'
|
|
1794
|
+
label='Suffix'
|
|
1795
|
+
updateField={updateField}
|
|
3318
1796
|
/>
|
|
3319
|
-
<
|
|
3320
|
-
<input
|
|
1797
|
+
<TextField
|
|
3321
1798
|
type='number'
|
|
1799
|
+
value={columns.primary.roundToPlace}
|
|
1800
|
+
section='columns'
|
|
1801
|
+
subsection='primary'
|
|
1802
|
+
fieldName='roundToPlace'
|
|
1803
|
+
label='Round'
|
|
1804
|
+
updateField={updateField}
|
|
3322
1805
|
min={0}
|
|
3323
|
-
max={100}
|
|
3324
|
-
name='layerFill'
|
|
3325
|
-
value={layer.fillOpacity ? layer.fillOpacity * 100 : ''}
|
|
3326
|
-
onChange={e => handleMapLayer(e, index, 'fillOpacity')}
|
|
3327
1806
|
/>
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
1807
|
+
</li>
|
|
1808
|
+
<CheckBox
|
|
1809
|
+
value={config.columns.primary.useCommas}
|
|
1810
|
+
section='columns'
|
|
1811
|
+
subsection='primary'
|
|
1812
|
+
fieldName='useCommas'
|
|
1813
|
+
label='Add Commas to Numbers'
|
|
1814
|
+
updateField={updateField}
|
|
1815
|
+
/>
|
|
1816
|
+
<CheckBox
|
|
1817
|
+
value={config.columns.primary.dataTable || false}
|
|
1818
|
+
section='columns'
|
|
1819
|
+
subsection='primary'
|
|
1820
|
+
fieldName='dataTable'
|
|
1821
|
+
label='Show in Data Table'
|
|
1822
|
+
updateField={updateField}
|
|
1823
|
+
/>
|
|
1824
|
+
<CheckBox
|
|
1825
|
+
value={config.columns.primary.tooltip || false}
|
|
1826
|
+
section='columns'
|
|
1827
|
+
subsection='primary'
|
|
1828
|
+
fieldName='tooltip'
|
|
1829
|
+
label='Show in Tooltips'
|
|
1830
|
+
updateField={updateField}
|
|
1831
|
+
/>
|
|
1832
|
+
</ul>
|
|
1833
|
+
</fieldset>
|
|
1834
|
+
)}
|
|
1835
|
+
|
|
1836
|
+
{config.general.type === 'bubble' && config.legend.type === 'category' && (
|
|
1837
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
1838
|
+
<label>
|
|
1839
|
+
<span className='edit-label column-heading'>
|
|
1840
|
+
Category Column
|
|
1841
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1842
|
+
<Tooltip.Target>
|
|
1843
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1844
|
+
</Tooltip.Target>
|
|
1845
|
+
<Tooltip.Content>
|
|
1846
|
+
<p>Select the source column containing the categorical bubble values to be mapped.</p>
|
|
1847
|
+
</Tooltip.Content>
|
|
1848
|
+
</Tooltip>
|
|
1849
|
+
</span>
|
|
1850
|
+
<Select
|
|
1851
|
+
label=''
|
|
1852
|
+
value={
|
|
1853
|
+
config.columns.categorical ? config.columns.categorical.name : columnsOptions[0]?.key
|
|
1854
|
+
}
|
|
1855
|
+
options={columnsOptions.map(c => c.key)}
|
|
1856
|
+
onChange={event => {
|
|
1857
|
+
editColumn('categorical', 'name', event.target.value)
|
|
1858
|
+
}}
|
|
1859
|
+
/>
|
|
1860
|
+
</label>
|
|
1861
|
+
</fieldset>
|
|
1862
|
+
)}
|
|
1863
|
+
{
|
|
1864
|
+
<>
|
|
1865
|
+
<Select
|
|
1866
|
+
label='Latitude Column'
|
|
1867
|
+
value={config.columns.latitude.name}
|
|
1868
|
+
options={columnsOptions.map(c => c.key)}
|
|
1869
|
+
onChange={e => {
|
|
1870
|
+
editColumn('latitude', 'name', e.target.value)
|
|
1871
|
+
}}
|
|
1872
|
+
/>
|
|
1873
|
+
<Select
|
|
1874
|
+
label='Longitude Column'
|
|
1875
|
+
value={config.columns.longitude.name}
|
|
1876
|
+
options={columnsOptions.map(c => c.key)}
|
|
1877
|
+
onChange={e => {
|
|
1878
|
+
editColumn('longitude', 'name', e.target.value)
|
|
1879
|
+
}}
|
|
1880
|
+
/>
|
|
1881
|
+
</>
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
{'navigation' !== config.general.type && (
|
|
1885
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
1886
|
+
<label>
|
|
1887
|
+
<span className='edit-label'>
|
|
1888
|
+
Special Classes
|
|
1889
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1890
|
+
<Tooltip.Target>
|
|
1891
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1892
|
+
</Tooltip.Target>
|
|
1893
|
+
<Tooltip.Content>
|
|
1894
|
+
<p>
|
|
1895
|
+
For secondary values such as "NA", the system can automatically color-code them in
|
|
1896
|
+
shades of gray, one shade for each special class.
|
|
1897
|
+
</p>
|
|
1898
|
+
</Tooltip.Content>
|
|
1899
|
+
</Tooltip>
|
|
1900
|
+
</span>
|
|
1901
|
+
</label>
|
|
1902
|
+
{config.legend.specialClasses.length === 2 && (
|
|
1903
|
+
<Alert
|
|
1904
|
+
type='info'
|
|
1905
|
+
message='If a third special class is needed you can apply a pattern to set it apart.'
|
|
1906
|
+
showCloseButton={false}
|
|
1907
|
+
/>
|
|
1908
|
+
)}
|
|
1909
|
+
{specialClasses.map((specialClass, i) => (
|
|
1910
|
+
<div className='edit-block' key={`special-class-${i}`}>
|
|
1911
|
+
<button
|
|
1912
|
+
className='remove-column'
|
|
1913
|
+
onClick={e => {
|
|
1914
|
+
e.preventDefault()
|
|
1915
|
+
editColumn('primary', 'specialClassDelete', i)
|
|
1916
|
+
}}
|
|
1917
|
+
>
|
|
1918
|
+
Remove
|
|
1919
|
+
</button>
|
|
1920
|
+
<p>Special Class {i + 1}</p>
|
|
1921
|
+
<Select
|
|
1922
|
+
label='Data Key'
|
|
1923
|
+
value={specialClass.key}
|
|
1924
|
+
options={columnsOptions.map(option => ({
|
|
1925
|
+
value: option.key,
|
|
1926
|
+
label: option.key
|
|
1927
|
+
}))}
|
|
1928
|
+
onChange={event => {
|
|
1929
|
+
editColumn('primary', 'specialClassEdit', {
|
|
1930
|
+
prop: 'key',
|
|
1931
|
+
index: i,
|
|
1932
|
+
value: event.target.value
|
|
1933
|
+
})
|
|
1934
|
+
}}
|
|
3334
1935
|
/>
|
|
3335
|
-
<
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
1936
|
+
<Select
|
|
1937
|
+
label='Value'
|
|
1938
|
+
value={specialClass.value}
|
|
1939
|
+
options={[
|
|
1940
|
+
{ value: '', label: '- Select Value -' },
|
|
1941
|
+
...(columnsByKey[specialClass.key] || [])
|
|
1942
|
+
.sort()
|
|
1943
|
+
.map(option => ({ value: option, label: option }))
|
|
1944
|
+
]}
|
|
1945
|
+
onChange={event => {
|
|
1946
|
+
editColumn('primary', 'specialClassEdit', {
|
|
1947
|
+
prop: 'value',
|
|
1948
|
+
index: i,
|
|
1949
|
+
value: event.target.value
|
|
1950
|
+
})
|
|
1951
|
+
}}
|
|
3343
1952
|
/>
|
|
3344
|
-
<label
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
1953
|
+
<label>
|
|
1954
|
+
<span className='edit-label column-heading'>Label</span>
|
|
1955
|
+
<input
|
|
1956
|
+
type='text'
|
|
1957
|
+
value={specialClass.label}
|
|
1958
|
+
onChange={e => {
|
|
1959
|
+
editColumn('primary', 'specialClassEdit', {
|
|
1960
|
+
prop: 'label',
|
|
1961
|
+
index: i,
|
|
1962
|
+
value: e.target.value
|
|
1963
|
+
})
|
|
1964
|
+
}}
|
|
1965
|
+
/>
|
|
1966
|
+
</label>
|
|
3351
1967
|
</div>
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
1968
|
+
))}
|
|
1969
|
+
{config.legend.specialClasses.length < 2 && (
|
|
1970
|
+
<button
|
|
1971
|
+
className='btn btn-primary full-width'
|
|
1972
|
+
onClick={e => {
|
|
1973
|
+
e.preventDefault()
|
|
1974
|
+
editColumn('primary', 'specialClassAdd', {})
|
|
1975
|
+
}}
|
|
1976
|
+
>
|
|
1977
|
+
Add Special Class
|
|
1978
|
+
</button>
|
|
1979
|
+
)}
|
|
1980
|
+
</fieldset>
|
|
1981
|
+
)}
|
|
1982
|
+
|
|
1983
|
+
<label className='edit-block navigate column-heading'>
|
|
1984
|
+
<span className='edit-label column-heading'>
|
|
1985
|
+
Navigation
|
|
1986
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1987
|
+
<Tooltip.Target>
|
|
1988
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1989
|
+
</Tooltip.Target>
|
|
1990
|
+
<Tooltip.Content>
|
|
1991
|
+
<p>
|
|
1992
|
+
To provide end users with navigation functionality, select the source column containing
|
|
1993
|
+
the navigation URLs.
|
|
1994
|
+
</p>
|
|
1995
|
+
</Tooltip.Content>
|
|
1996
|
+
</Tooltip>
|
|
1997
|
+
</span>
|
|
1998
|
+
<Select
|
|
1999
|
+
value={config.columns.navigate ? config.columns.navigate.name : ''}
|
|
2000
|
+
options={columnsOptions.map(c => c.key)}
|
|
2001
|
+
onChange={event => {
|
|
2002
|
+
editColumn('navigate', 'name', event.target.value)
|
|
2003
|
+
}}
|
|
2004
|
+
/>
|
|
2005
|
+
</label>
|
|
2006
|
+
{'navigation' !== config.general.type && (
|
|
2007
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
2008
|
+
<label>
|
|
2009
|
+
<span className='edit-label'>
|
|
2010
|
+
Additional Columns
|
|
2011
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2012
|
+
<Tooltip.Target>
|
|
2013
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2014
|
+
</Tooltip.Target>
|
|
2015
|
+
<Tooltip.Content>
|
|
2016
|
+
<p>
|
|
2017
|
+
You can specify additional columns to display in tooltips and / or the supporting data
|
|
2018
|
+
table.
|
|
2019
|
+
</p>
|
|
2020
|
+
</Tooltip.Content>
|
|
2021
|
+
</Tooltip>
|
|
2022
|
+
</span>
|
|
2023
|
+
</label>
|
|
2024
|
+
{additionalColumns.map(val => (
|
|
2025
|
+
<fieldset className='edit-block' key={val}>
|
|
2026
|
+
<button
|
|
2027
|
+
className='remove-column'
|
|
2028
|
+
onClick={event => {
|
|
2029
|
+
event.preventDefault()
|
|
2030
|
+
removeAdditionalColumn(val)
|
|
2031
|
+
}}
|
|
2032
|
+
>
|
|
2033
|
+
Remove
|
|
2034
|
+
</button>
|
|
2035
|
+
<Select
|
|
2036
|
+
label='Column'
|
|
2037
|
+
value={config.columns[val] ? config.columns[val].name : ''}
|
|
2038
|
+
options={columnsOptions.map(option => ({
|
|
2039
|
+
value: option.props.value,
|
|
2040
|
+
label: option.props.children
|
|
2041
|
+
}))}
|
|
2042
|
+
onChange={event => {
|
|
2043
|
+
editColumn(val, 'name', event.target.value)
|
|
2044
|
+
}}
|
|
2045
|
+
/>
|
|
2046
|
+
<TextField
|
|
2047
|
+
value={columns[val].label}
|
|
2048
|
+
section='columns'
|
|
2049
|
+
subsection={val}
|
|
2050
|
+
fieldName='label'
|
|
2051
|
+
label='Label'
|
|
2052
|
+
updateField={updateField}
|
|
2053
|
+
/>
|
|
2054
|
+
<ul className='column-edit'>
|
|
2055
|
+
<li className='three-col'>
|
|
2056
|
+
<TextField
|
|
2057
|
+
value={columns[val].prefix}
|
|
2058
|
+
section='columns'
|
|
2059
|
+
subsection={val}
|
|
2060
|
+
fieldName='prefix'
|
|
2061
|
+
label='Prefix'
|
|
2062
|
+
updateField={updateField}
|
|
2063
|
+
/>
|
|
2064
|
+
<TextField
|
|
2065
|
+
value={columns[val].suffix}
|
|
2066
|
+
section='columns'
|
|
2067
|
+
subsection={val}
|
|
2068
|
+
fieldName='suffix'
|
|
2069
|
+
label='Suffix'
|
|
2070
|
+
updateField={updateField}
|
|
2071
|
+
/>
|
|
2072
|
+
<TextField
|
|
2073
|
+
type='number'
|
|
2074
|
+
value={columns[val].roundToPlace}
|
|
2075
|
+
section='columns'
|
|
2076
|
+
subsection={val}
|
|
2077
|
+
fieldName='roundToPlace'
|
|
2078
|
+
label='Round'
|
|
2079
|
+
updateField={updateField}
|
|
2080
|
+
/>
|
|
2081
|
+
</li>
|
|
2082
|
+
<CheckBox
|
|
2083
|
+
value={config.columns[val].useCommas}
|
|
2084
|
+
section='columns'
|
|
2085
|
+
subsection={val}
|
|
2086
|
+
fieldName='useCommas'
|
|
2087
|
+
label='Add Commas to Numbers'
|
|
2088
|
+
updateField={updateField}
|
|
2089
|
+
onChange={event => {
|
|
2090
|
+
editColumn(val, 'useCommas', event.target.checked)
|
|
2091
|
+
}}
|
|
2092
|
+
/>
|
|
2093
|
+
<CheckBox
|
|
2094
|
+
value={config.columns[val].dataTable}
|
|
2095
|
+
section='columns'
|
|
2096
|
+
subsection={val}
|
|
2097
|
+
fieldName='dataTable'
|
|
2098
|
+
label='Show in Data Table'
|
|
2099
|
+
updateField={updateField}
|
|
2100
|
+
onChange={event => {
|
|
2101
|
+
editColumn(val, 'dataTable', event.target.checked)
|
|
2102
|
+
}}
|
|
2103
|
+
/>
|
|
2104
|
+
<CheckBox
|
|
2105
|
+
value={config.columns[val].tooltip}
|
|
2106
|
+
section='columns'
|
|
2107
|
+
subsection={val}
|
|
2108
|
+
fieldName='tooltip'
|
|
2109
|
+
label='Show in Tooltips'
|
|
2110
|
+
updateField={updateField}
|
|
2111
|
+
onChange={event => {
|
|
2112
|
+
editColumn(val, 'tooltip', event.target.checked)
|
|
2113
|
+
}}
|
|
2114
|
+
/>
|
|
2115
|
+
</ul>
|
|
2116
|
+
</fieldset>
|
|
2117
|
+
))}
|
|
2118
|
+
<button
|
|
2119
|
+
className={'btn btn-primary full-width'}
|
|
2120
|
+
onClick={event => {
|
|
2121
|
+
event.preventDefault()
|
|
2122
|
+
addAdditionalColumn(additionalColumns.length + 1)
|
|
2123
|
+
}}
|
|
2124
|
+
>
|
|
2125
|
+
Add Column
|
|
2126
|
+
</button>
|
|
2127
|
+
</fieldset>
|
|
2128
|
+
)}
|
|
2129
|
+
{'category' === config.legend.type && (
|
|
2130
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
2131
|
+
<label>
|
|
2132
|
+
<span className='edit-label'>
|
|
2133
|
+
Additional Category
|
|
2134
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2135
|
+
<Tooltip.Target>
|
|
2136
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2137
|
+
</Tooltip.Target>
|
|
2138
|
+
<Tooltip.Content>
|
|
2139
|
+
<p>You can provide additional categories to ensure they appear in the legend</p>
|
|
2140
|
+
</Tooltip.Content>
|
|
2141
|
+
</Tooltip>
|
|
2142
|
+
</span>
|
|
2143
|
+
</label>
|
|
2144
|
+
{config.legend.additionalCategories &&
|
|
2145
|
+
config.legend.additionalCategories.map((val, i) => (
|
|
2146
|
+
<fieldset className='edit-block' key={val}>
|
|
2147
|
+
<button
|
|
2148
|
+
className='remove-column'
|
|
2149
|
+
onClick={event => {
|
|
2150
|
+
event.preventDefault()
|
|
2151
|
+
const updatedAdditionaCategories = [...config.legend.additionalCategories]
|
|
2152
|
+
updatedAdditionaCategories.splice(i, 1)
|
|
2153
|
+
updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
|
|
2154
|
+
}}
|
|
2155
|
+
>
|
|
2156
|
+
Remove
|
|
2157
|
+
</button>
|
|
2158
|
+
<label>
|
|
2159
|
+
<span className='edit-label column-heading'>Category</span>
|
|
2160
|
+
<TextField
|
|
2161
|
+
value={val}
|
|
2162
|
+
section='legend'
|
|
2163
|
+
subsection={null}
|
|
2164
|
+
fieldName='additionalCategories'
|
|
2165
|
+
updateField={(section, subsection, fieldName, value) => {
|
|
2166
|
+
const updatedAdditionaCategories = [...config.legend.additionalCategories]
|
|
2167
|
+
updatedAdditionaCategories[i] = value
|
|
2168
|
+
updateField(section, subsection, fieldName, updatedAdditionaCategories)
|
|
2169
|
+
}}
|
|
2170
|
+
/>
|
|
2171
|
+
</label>
|
|
2172
|
+
</fieldset>
|
|
2173
|
+
))}
|
|
2174
|
+
<button
|
|
2175
|
+
className={'btn btn-primary full-width'}
|
|
2176
|
+
onClick={event => {
|
|
2177
|
+
event.preventDefault()
|
|
2178
|
+
const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
|
|
2179
|
+
updatedAdditionaCategories.push('')
|
|
2180
|
+
updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
|
|
2181
|
+
}}
|
|
2182
|
+
>
|
|
2183
|
+
Add Category
|
|
2184
|
+
</button>
|
|
2185
|
+
</fieldset>
|
|
2186
|
+
)}
|
|
2187
|
+
</AccordionItemPanel>
|
|
2188
|
+
</AccordionItem>{' '}
|
|
2189
|
+
{/* Columns */}
|
|
2190
|
+
{'navigation' !== config.general.type && (
|
|
2191
|
+
<AccordionItem>
|
|
2192
|
+
{' '}
|
|
2193
|
+
{/* Legend */}
|
|
2194
|
+
<AccordionItemHeading>
|
|
2195
|
+
<AccordionItemButton>Legend</AccordionItemButton>
|
|
2196
|
+
</AccordionItemHeading>
|
|
2197
|
+
<AccordionItemPanel>
|
|
2198
|
+
{(config.legend.type === 'equalnumber' || config.legend.type === 'equalinterval') && (
|
|
2199
|
+
<Select
|
|
2200
|
+
label='Legend Type'
|
|
2201
|
+
value={legend.type}
|
|
2202
|
+
options={[
|
|
2203
|
+
{ value: 'equalnumber', label: 'Equal Number (Quantiles)' },
|
|
2204
|
+
{ value: 'equalinterval', label: 'Equal Interval' }
|
|
2205
|
+
]}
|
|
2206
|
+
onChange={event => {
|
|
2207
|
+
let testForType = Number(typeof config.data[0][config.columns.primary.name])
|
|
2208
|
+
let hasValue = config.data[0][config.columns.primary.name]
|
|
2209
|
+
let messages = []
|
|
2210
|
+
|
|
2211
|
+
if (!hasValue) {
|
|
2212
|
+
messages.push(
|
|
2213
|
+
`There appears to be values missing for data in the primary column ${config.columns.primary.name}`
|
|
2214
|
+
)
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
if (testForType === 'string' && isNaN(testForType) && value !== 'category') {
|
|
2218
|
+
messages.push(
|
|
2219
|
+
'Error with legend. Primary columns that are text must use a categorical legend type. Try changing the legend type to DEV-12345categorical.'
|
|
2220
|
+
)
|
|
2221
|
+
} else {
|
|
2222
|
+
messages = []
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
const _newConfig = cloneConfig(config)
|
|
2226
|
+
_newConfig.legend.type = event.target.value
|
|
2227
|
+
_newConfig.runtime.editorErrorMessage = messages
|
|
2228
|
+
setConfig(_newConfig)
|
|
2229
|
+
}}
|
|
2230
|
+
/>
|
|
2231
|
+
)}
|
|
2232
|
+
{'navigation' !== config.general.type && (
|
|
2233
|
+
<CheckBox
|
|
2234
|
+
value={config.general.showSidebar || false}
|
|
2235
|
+
section='general'
|
|
2236
|
+
subsection={null}
|
|
2237
|
+
fieldName='showSidebar'
|
|
2238
|
+
label='Show Legend'
|
|
2239
|
+
updateField={updateField}
|
|
2240
|
+
/>
|
|
2241
|
+
)}
|
|
2242
|
+
{'navigation' !== config.general.type && (
|
|
2243
|
+
<>
|
|
2244
|
+
<Select
|
|
2245
|
+
label='Legend Position'
|
|
2246
|
+
value={legend.position || ''}
|
|
2247
|
+
options={[
|
|
2248
|
+
{ value: 'side', label: 'Side' },
|
|
2249
|
+
{ value: 'bottom', label: 'Bottom' },
|
|
2250
|
+
{ value: 'top', label: 'Top' }
|
|
2251
|
+
]}
|
|
2252
|
+
onChange={event => {
|
|
2253
|
+
handleEditorChanges('sidebarPosition', event.target.value)
|
|
2254
|
+
}}
|
|
2255
|
+
/>
|
|
2256
|
+
{(config.legend.position === 'side' || !config.legend.position) &&
|
|
2257
|
+
config.legend.style === 'gradient' && (
|
|
2258
|
+
<span style={{ color: 'red', fontSize: '14px' }}>
|
|
2259
|
+
Position must be set to top or bottom to use gradient style.
|
|
2260
|
+
</span>
|
|
2261
|
+
)}
|
|
2262
|
+
</>
|
|
2263
|
+
)}
|
|
2264
|
+
{'navigation' !== config.general.type && (
|
|
2265
|
+
<Select
|
|
2266
|
+
label={
|
|
2267
|
+
<>
|
|
2268
|
+
Legend Style
|
|
2269
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2270
|
+
<Tooltip.Target>
|
|
2271
|
+
<Icon
|
|
2272
|
+
display='question'
|
|
2273
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2274
|
+
/>
|
|
2275
|
+
</Tooltip.Target>
|
|
2276
|
+
<Tooltip.Content>
|
|
2277
|
+
<p>
|
|
2278
|
+
If using gradient style, limit the legend to five items for better mobile
|
|
2279
|
+
visibility, and position the legend at the top or bottom.
|
|
2280
|
+
</p>
|
|
2281
|
+
</Tooltip.Content>
|
|
2282
|
+
</Tooltip>
|
|
2283
|
+
</>
|
|
2284
|
+
}
|
|
2285
|
+
value={legend.style || ''}
|
|
2286
|
+
options={[
|
|
2287
|
+
{ value: 'circles', label: 'circles' },
|
|
2288
|
+
{ value: 'boxes', label: 'boxes' },
|
|
2289
|
+
...(legend.position !== 'side' ? [{ value: 'gradient', label: 'gradient' }] : [])
|
|
2290
|
+
]}
|
|
2291
|
+
onChange={event => {
|
|
2292
|
+
handleEditorChanges('legendStyle', event.target.value)
|
|
2293
|
+
}}
|
|
2294
|
+
/>
|
|
2295
|
+
)}
|
|
2296
|
+
{'navigation' !== config.general.type && config.legend.style === 'gradient' && (
|
|
2297
|
+
<Select
|
|
2298
|
+
label='Gradient Style'
|
|
2299
|
+
value={legend.subStyle || ''}
|
|
2300
|
+
options={['linear blocks', 'smooth']}
|
|
2301
|
+
onChange={event => {
|
|
2302
|
+
handleEditorChanges('legendSubStyle', event.target.value)
|
|
2303
|
+
}}
|
|
2304
|
+
/>
|
|
2305
|
+
)}
|
|
2306
|
+
{allowLegendSeparators && (
|
|
2307
|
+
<TextField
|
|
2308
|
+
value={legend.separators}
|
|
2309
|
+
updateField={updateField}
|
|
2310
|
+
section='legend'
|
|
2311
|
+
fieldName='separators'
|
|
2312
|
+
label='Legend Separators'
|
|
2313
|
+
placeholder='ex: 1,4'
|
|
2314
|
+
tooltip={
|
|
2315
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2316
|
+
<Tooltip.Target>
|
|
2317
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2318
|
+
</Tooltip.Target>
|
|
2319
|
+
<Tooltip.Content>
|
|
2320
|
+
<p>
|
|
2321
|
+
Separators between legend items represented by the legend item numbers separated by
|
|
2322
|
+
commas.
|
|
2323
|
+
</p>
|
|
2324
|
+
</Tooltip.Content>
|
|
2325
|
+
</Tooltip>
|
|
2326
|
+
}
|
|
2327
|
+
/>
|
|
2328
|
+
)}
|
|
2329
|
+
{'navigation' !== config.general.type && config.legend.style === 'gradient' && (
|
|
2330
|
+
<label>
|
|
2331
|
+
<span className='edit-label'>Tick Rotation (Degrees)</span>
|
|
2332
|
+
<input
|
|
2333
|
+
type='number'
|
|
2334
|
+
className='number-narrow'
|
|
2335
|
+
value={legend.tickRotation || ''}
|
|
2336
|
+
onChange={event => {
|
|
2337
|
+
handleEditorChanges('legendTickRotation', event.target.value)
|
|
2338
|
+
}}
|
|
2339
|
+
></input>
|
|
2340
|
+
</label>
|
|
2341
|
+
)}
|
|
2342
|
+
{
|
|
2343
|
+
// TODO: DEV-7271 Follow-up to implement option to isolate on legend click. For now, always highlight.
|
|
2344
|
+
/*
|
|
2345
|
+
<Select
|
|
2346
|
+
value={config.legend.behavior}
|
|
2347
|
+
section='legend'
|
|
2348
|
+
fieldName='behavior'
|
|
2349
|
+
label='Legend Behavior (When clicked)'
|
|
2350
|
+
updateField={updateField}
|
|
2351
|
+
options={['highlight', 'isolate']}
|
|
2352
|
+
/>
|
|
2353
|
+
*/
|
|
2354
|
+
}
|
|
2355
|
+
{
|
|
2356
|
+
<CheckBox
|
|
2357
|
+
value={legend.hideBorder}
|
|
2358
|
+
section='legend'
|
|
2359
|
+
subsection={null}
|
|
2360
|
+
fieldName='hideBorder'
|
|
2361
|
+
label='Hide Legend Box'
|
|
2362
|
+
updateField={updateField}
|
|
2363
|
+
onChange={event => {
|
|
2364
|
+
handleEditorChanges('legendBorder', event.target.checked)
|
|
2365
|
+
}}
|
|
2366
|
+
tooltip={
|
|
2367
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2368
|
+
<Tooltip.Target>
|
|
2369
|
+
<Icon
|
|
2370
|
+
display='question'
|
|
2371
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2372
|
+
/>
|
|
2373
|
+
</Tooltip.Target>
|
|
2374
|
+
<Tooltip.Content>
|
|
2375
|
+
<p> Default option for top and bottom legends is 'No Box.'</p>
|
|
2376
|
+
</Tooltip.Content>
|
|
2377
|
+
</Tooltip>
|
|
2378
|
+
}
|
|
2379
|
+
/>
|
|
2380
|
+
}
|
|
2381
|
+
{'side' === legend.position && (
|
|
2382
|
+
<CheckBox
|
|
2383
|
+
value={legend.singleColumn}
|
|
2384
|
+
section='legend'
|
|
2385
|
+
subsection={null}
|
|
2386
|
+
fieldName='singleColumn'
|
|
2387
|
+
label='Single Column Legend'
|
|
2388
|
+
updateField={updateField}
|
|
2389
|
+
onChange={event => {
|
|
2390
|
+
const _newConfig = cloneConfig(config)
|
|
2391
|
+
_newConfig.legend.singleColumn = event.target.checked
|
|
2392
|
+
_newConfig.legend.singleRow = false
|
|
2393
|
+
_newConfig.legend.verticalSorted = false
|
|
2394
|
+
|
|
2395
|
+
setConfig(_newConfig)
|
|
2396
|
+
}}
|
|
2397
|
+
/>
|
|
2398
|
+
)}
|
|
2399
|
+
{'side' !== legend.position && legend.style !== 'gradient' && (
|
|
2400
|
+
<CheckBox
|
|
2401
|
+
value={legend.singleRow}
|
|
2402
|
+
section='legend'
|
|
2403
|
+
subsection={null}
|
|
2404
|
+
fieldName='singleRow'
|
|
2405
|
+
label='Single Row Legend'
|
|
2406
|
+
updateField={updateField}
|
|
2407
|
+
onChange={event => {
|
|
2408
|
+
const _newConfig = cloneConfig(config)
|
|
2409
|
+
_newConfig.legend.singleRow = event.target.checked
|
|
2410
|
+
_newConfig.legend.singleColumn = false
|
|
2411
|
+
_newConfig.legend.verticalSorted = false
|
|
2412
|
+
|
|
2413
|
+
setConfig(_newConfig)
|
|
2414
|
+
}}
|
|
2415
|
+
/>
|
|
2416
|
+
)}
|
|
2417
|
+
|
|
2418
|
+
{'navigation' !== config.general.type && config.legend.type === 'category' && (
|
|
2419
|
+
<Select
|
|
2420
|
+
label='Legend Group By :'
|
|
2421
|
+
value={legend.groupBy || ''}
|
|
2422
|
+
options={columnsOptions.map(c => c.key)}
|
|
2423
|
+
onChange={event => {
|
|
2424
|
+
const _newConfig = cloneConfig(config)
|
|
2425
|
+
_newConfig.legend.groupBy = event.target.value
|
|
2426
|
+
setConfig(_newConfig)
|
|
2427
|
+
}}
|
|
2428
|
+
/>
|
|
2429
|
+
)}
|
|
2430
|
+
{config.legend.style !== 'gradient' && (
|
|
2431
|
+
<CheckBox
|
|
2432
|
+
value={legend.verticalSorted}
|
|
2433
|
+
section='legend'
|
|
2434
|
+
subsection={null}
|
|
2435
|
+
fieldName='verticalSorted'
|
|
2436
|
+
label='Vertical sorted legend'
|
|
2437
|
+
updateField={updateField}
|
|
2438
|
+
/>
|
|
2439
|
+
)}
|
|
2440
|
+
|
|
2441
|
+
{/* always show */}
|
|
2442
|
+
{
|
|
2443
|
+
<CheckBox
|
|
2444
|
+
value={legend.showSpecialClassesLast}
|
|
2445
|
+
section='legend'
|
|
2446
|
+
subsection={null}
|
|
2447
|
+
fieldName='showSpecialClassesLast'
|
|
2448
|
+
label='Show Special Classes Last'
|
|
2449
|
+
updateField={updateField}
|
|
2450
|
+
onChange={event => {
|
|
2451
|
+
handleEditorChanges('legendShowSpecialClassesLast', event.target.checked)
|
|
2452
|
+
}}
|
|
2453
|
+
/>
|
|
2454
|
+
}
|
|
2455
|
+
{'category' !== legend.type && (
|
|
2456
|
+
<CheckBox
|
|
2457
|
+
value={legend.separateZero || false}
|
|
2458
|
+
section='legend'
|
|
2459
|
+
subsection={null}
|
|
2460
|
+
fieldName='separateZero'
|
|
2461
|
+
label='Separate Zero'
|
|
2462
|
+
updateField={updateField}
|
|
2463
|
+
tooltip={
|
|
2464
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2465
|
+
<Tooltip.Target>
|
|
2466
|
+
<Icon
|
|
2467
|
+
display='question'
|
|
2468
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2469
|
+
/>
|
|
2470
|
+
</Tooltip.Target>
|
|
2471
|
+
<Tooltip.Content>
|
|
2472
|
+
<p>For numeric data, you can separate the zero value as its own data class.</p>
|
|
2473
|
+
</Tooltip.Content>
|
|
2474
|
+
</Tooltip>
|
|
2475
|
+
}
|
|
2476
|
+
/>
|
|
2477
|
+
)}
|
|
2478
|
+
|
|
2479
|
+
{/* Temp Checkbox */}
|
|
2480
|
+
{config.legend.type === 'equalnumber' && (
|
|
2481
|
+
<CheckBox
|
|
2482
|
+
value={config.general.equalNumberOptIn}
|
|
2483
|
+
section='general'
|
|
2484
|
+
subsection={null}
|
|
2485
|
+
fieldName='equalNumberOptIn'
|
|
2486
|
+
label='Use new quantile legend'
|
|
2487
|
+
updateField={updateField}
|
|
2488
|
+
tooltip={
|
|
2489
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2490
|
+
<Tooltip.Target>
|
|
2491
|
+
<Icon
|
|
2492
|
+
display='question'
|
|
2493
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2494
|
+
/>
|
|
2495
|
+
</Tooltip.Target>
|
|
2496
|
+
<Tooltip.Content>
|
|
2497
|
+
<p>
|
|
2498
|
+
This prevents numbers from being used in more than one category (ie. 0-1, 1-2, 2-3){' '}
|
|
2499
|
+
</p>
|
|
2500
|
+
</Tooltip.Content>
|
|
2501
|
+
</Tooltip>
|
|
2502
|
+
}
|
|
2503
|
+
/>
|
|
2504
|
+
)}
|
|
2505
|
+
|
|
2506
|
+
{'category' !== legend.type && (
|
|
2507
|
+
<Select
|
|
2508
|
+
label={
|
|
2509
|
+
<>
|
|
2510
|
+
Number of Items
|
|
2511
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2512
|
+
<Tooltip.Target>
|
|
2513
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2514
|
+
</Tooltip.Target>
|
|
2515
|
+
<Tooltip.Content>
|
|
2516
|
+
<p>
|
|
2517
|
+
For numeric maps, select the number of data classes. Do not include designated
|
|
2518
|
+
special classes.
|
|
2519
|
+
</p>
|
|
2520
|
+
</Tooltip.Content>
|
|
2521
|
+
</Tooltip>
|
|
2522
|
+
</>
|
|
2523
|
+
}
|
|
2524
|
+
value={legend.numberOfItems}
|
|
2525
|
+
options={[...Array(numberOfItemsLimit).keys()].map(num => ({
|
|
2526
|
+
value: num + 1,
|
|
2527
|
+
label: num + 1
|
|
2528
|
+
}))}
|
|
2529
|
+
onChange={event => {
|
|
2530
|
+
handleEditorChanges('legendNumber', event.target.value)
|
|
2531
|
+
}}
|
|
2532
|
+
/>
|
|
2533
|
+
)}
|
|
2534
|
+
{'category' === legend.type && (
|
|
2535
|
+
<React.Fragment>
|
|
2536
|
+
<label>
|
|
2537
|
+
<span className='edit-label'>
|
|
2538
|
+
Category Order
|
|
2539
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2540
|
+
<Tooltip.Target>
|
|
2541
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2542
|
+
</Tooltip.Target>
|
|
2543
|
+
<Tooltip.Content>
|
|
2544
|
+
<p>Drag map categories into preferred legend order. </p>
|
|
2545
|
+
</Tooltip.Content>
|
|
2546
|
+
</Tooltip>
|
|
2547
|
+
</span>
|
|
2548
|
+
</label>
|
|
2549
|
+
{/* 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. */}
|
|
2550
|
+
<DragDropContext
|
|
2551
|
+
onDragEnd={({ source, destination }) => categoryMove(source.index, destination.index)}
|
|
2552
|
+
>
|
|
2553
|
+
<Droppable droppableId='category_order'>
|
|
2554
|
+
{provided => (
|
|
2555
|
+
<ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef}>
|
|
2556
|
+
<CategoryList />
|
|
2557
|
+
{provided.placeholder}
|
|
2558
|
+
</ul>
|
|
2559
|
+
)}
|
|
2560
|
+
</Droppable>
|
|
2561
|
+
</DragDropContext>
|
|
2562
|
+
{runtimeLegend && runtimeLegend.length >= 10 && (
|
|
2563
|
+
<section className='error-box my-2'>
|
|
2564
|
+
<div>
|
|
2565
|
+
<strong className='pt-1'>Warning</strong>
|
|
2566
|
+
<p>
|
|
2567
|
+
The maximum number of categorical legend items is 10. If your data has more than 10
|
|
2568
|
+
categories your map will not display properly.
|
|
2569
|
+
</p>
|
|
2570
|
+
</div>
|
|
2571
|
+
</section>
|
|
2572
|
+
)}
|
|
2573
|
+
</React.Fragment>
|
|
2574
|
+
)}
|
|
2575
|
+
<TextField
|
|
2576
|
+
value={legend.title}
|
|
2577
|
+
updateField={updateField}
|
|
2578
|
+
section='legend'
|
|
2579
|
+
fieldName='title'
|
|
2580
|
+
label='Legend Title'
|
|
2581
|
+
placeholder='Legend Title'
|
|
2582
|
+
/>
|
|
2583
|
+
{false === legend.dynamicDescription && (
|
|
2584
|
+
<TextField
|
|
2585
|
+
type='textarea'
|
|
2586
|
+
value={legend.description}
|
|
2587
|
+
updateField={updateField}
|
|
2588
|
+
section='legend'
|
|
2589
|
+
fieldName='description'
|
|
2590
|
+
label='Legend Description'
|
|
2591
|
+
/>
|
|
2592
|
+
)}
|
|
2593
|
+
{true === legend.dynamicDescription && (
|
|
2594
|
+
<React.Fragment>
|
|
2595
|
+
<label>
|
|
2596
|
+
<span>Legend Description</span>
|
|
2597
|
+
<span className='subtext'>
|
|
2598
|
+
For {displayFilterLegendValue(activeFilterValueForDescription)}
|
|
2599
|
+
</span>
|
|
2600
|
+
<DynamicDesc value={legend.descriptions[String(activeFilterValueForDescription)]} />
|
|
2601
|
+
</label>
|
|
2602
|
+
<label>
|
|
2603
|
+
<Select
|
|
2604
|
+
label='Filter Value'
|
|
2605
|
+
value={String(activeFilterValueForDescription)}
|
|
2606
|
+
options={filterValueOptionList.map(arr => ({
|
|
2607
|
+
value: arr,
|
|
2608
|
+
label: displayFilterLegendValue(arr)
|
|
2609
|
+
}))}
|
|
2610
|
+
onChange={event => {
|
|
2611
|
+
handleEditorChanges('changeActiveFilterValue', event.target.value)
|
|
2612
|
+
}}
|
|
2613
|
+
/>
|
|
2614
|
+
</label>
|
|
2615
|
+
</React.Fragment>
|
|
2616
|
+
)}
|
|
2617
|
+
{config.filters.length > 0 && (
|
|
2618
|
+
<label className='checkbox column-heading'>
|
|
2619
|
+
<CheckBox
|
|
2620
|
+
value={legend.dynamicDescription}
|
|
2621
|
+
section='legend'
|
|
2622
|
+
subsection={null}
|
|
2623
|
+
fieldName='dynamicDescription'
|
|
2624
|
+
label='Dynamic Legend Description'
|
|
2625
|
+
updateField={updateField}
|
|
2626
|
+
onChange={() => {
|
|
2627
|
+
handleEditorChanges('dynamicDescription', filterValueOptionList[0])
|
|
2628
|
+
}}
|
|
2629
|
+
/>
|
|
2630
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2631
|
+
<Tooltip.Target>
|
|
2632
|
+
<Icon
|
|
2633
|
+
display='question'
|
|
2634
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2635
|
+
/>
|
|
2636
|
+
</Tooltip.Target>
|
|
2637
|
+
<Tooltip.Content>
|
|
2638
|
+
<p>
|
|
2639
|
+
Check this option if the map has multiple filter controls and you want to specify a
|
|
2640
|
+
description for each filter selection.
|
|
2641
|
+
</p>
|
|
2642
|
+
</Tooltip.Content>
|
|
2643
|
+
</Tooltip>
|
|
2644
|
+
</label>
|
|
2645
|
+
)}
|
|
2646
|
+
<span className='d-flex mt-2'>
|
|
2647
|
+
<CheckBox
|
|
2648
|
+
value={legend.unified}
|
|
2649
|
+
section='legend'
|
|
2650
|
+
subsection={null}
|
|
2651
|
+
fieldName='unified'
|
|
2652
|
+
label='Unified Legend'
|
|
2653
|
+
updateField={updateField}
|
|
2654
|
+
onChange={event => handleEditorChanges('unifiedLegend', event.target.checked)}
|
|
2655
|
+
/>
|
|
2656
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2657
|
+
<Tooltip.Target>
|
|
2658
|
+
<Icon
|
|
2659
|
+
display='question'
|
|
2660
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2661
|
+
/>
|
|
2662
|
+
</Tooltip.Target>
|
|
2663
|
+
<Tooltip.Content>
|
|
2664
|
+
<p>
|
|
2665
|
+
Check this option if you want the high and low values in the legend to be based on{' '}
|
|
2666
|
+
<em>all</em> mapped values (useful for maps with filters or small multiples).
|
|
2667
|
+
</p>
|
|
2668
|
+
</Tooltip.Content>
|
|
2669
|
+
</Tooltip>
|
|
2670
|
+
</span>
|
|
2671
|
+
</AccordionItemPanel>
|
|
2672
|
+
</AccordionItem>
|
|
2673
|
+
)}
|
|
2674
|
+
{'navigation' !== config.general.type && (
|
|
2675
|
+
<>
|
|
2676
|
+
<AccordionItem>
|
|
2677
|
+
{/* Filters */}
|
|
2678
|
+
<AccordionItemHeading>
|
|
2679
|
+
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2680
|
+
</AccordionItemHeading>
|
|
2681
|
+
<AccordionItemPanel>
|
|
2682
|
+
<VizFilterEditor
|
|
2683
|
+
config={config}
|
|
2684
|
+
updateField={updateField}
|
|
2685
|
+
rawData={config.data}
|
|
2686
|
+
hasFootnotes={isDashboard}
|
|
2687
|
+
/>
|
|
2688
|
+
</AccordionItemPanel>
|
|
2689
|
+
</AccordionItem>
|
|
2690
|
+
<AccordionItem>
|
|
2691
|
+
<AccordionItemHeading>
|
|
2692
|
+
<AccordionItemButton>Footnotes</AccordionItemButton>
|
|
2693
|
+
</AccordionItemHeading>
|
|
2694
|
+
<AccordionItemPanel>
|
|
2695
|
+
<FootnotesEditor config={config} updateField={updateField} datasets={datasets} />
|
|
2696
|
+
</AccordionItemPanel>
|
|
2697
|
+
</AccordionItem>
|
|
3355
2698
|
</>
|
|
3356
|
-
)
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
2699
|
+
)}
|
|
2700
|
+
{'navigation' !== config.general.type && (
|
|
2701
|
+
<AccordionItem>
|
|
2702
|
+
{' '}
|
|
2703
|
+
{/* Data Table */}
|
|
2704
|
+
<AccordionItemHeading>
|
|
2705
|
+
<AccordionItemButton>Data Table</AccordionItemButton>
|
|
2706
|
+
</AccordionItemHeading>
|
|
2707
|
+
<AccordionItemPanel>
|
|
2708
|
+
<TextField
|
|
2709
|
+
value={table.label}
|
|
2710
|
+
updateField={updateField}
|
|
2711
|
+
section='table'
|
|
2712
|
+
fieldName='label'
|
|
2713
|
+
id='dataTableTitle'
|
|
2714
|
+
label='Data Table Title'
|
|
2715
|
+
placeholder='Data Table'
|
|
2716
|
+
tooltip={
|
|
2717
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2718
|
+
<Tooltip.Target>
|
|
2719
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2720
|
+
</Tooltip.Target>
|
|
2721
|
+
<Tooltip.Content>
|
|
2722
|
+
<p>Label is required for Data Table for 508 Compliance</p>
|
|
2723
|
+
</Tooltip.Content>
|
|
2724
|
+
</Tooltip>
|
|
2725
|
+
}
|
|
2726
|
+
/>
|
|
2727
|
+
<CheckBox
|
|
2728
|
+
value={config.table.wrapColumns}
|
|
2729
|
+
section='table'
|
|
2730
|
+
subsection={null}
|
|
2731
|
+
fieldName='wrapColumns'
|
|
2732
|
+
label='WRAP DATA TABLE COLUMNS'
|
|
2733
|
+
updateField={updateField}
|
|
2734
|
+
className='column-heading'
|
|
2735
|
+
/>
|
|
2736
|
+
<CheckBox
|
|
2737
|
+
value={config.table.forceDisplay !== undefined ? config.table.forceDisplay : !isDashboard}
|
|
2738
|
+
section='table'
|
|
2739
|
+
subsection={null}
|
|
2740
|
+
fieldName='forceDisplay'
|
|
2741
|
+
label='Show Data Table'
|
|
2742
|
+
updateField={updateField}
|
|
2743
|
+
onChange={event => {
|
|
2744
|
+
handleEditorChanges('showDataTable', event.target.checked)
|
|
2745
|
+
}}
|
|
2746
|
+
tooltip={
|
|
2747
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2748
|
+
<Tooltip.Target>
|
|
2749
|
+
<Icon
|
|
2750
|
+
display='question'
|
|
2751
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2752
|
+
/>
|
|
2753
|
+
</Tooltip.Target>
|
|
2754
|
+
<Tooltip.Content>
|
|
2755
|
+
<p>
|
|
2756
|
+
Data tables are required for 508 compliance. When choosing to hide this data table,
|
|
2757
|
+
replace with your own version.
|
|
2758
|
+
</p>
|
|
2759
|
+
</Tooltip.Content>
|
|
2760
|
+
</Tooltip>
|
|
2761
|
+
}
|
|
2762
|
+
/>
|
|
2763
|
+
|
|
2764
|
+
<CheckBox
|
|
2765
|
+
value={config.table.showNonGeoData}
|
|
2766
|
+
section='table'
|
|
2767
|
+
subsection={null}
|
|
2768
|
+
fieldName='showNonGeoData'
|
|
2769
|
+
label='Show Non Geographic Data'
|
|
2770
|
+
updateField={updateField}
|
|
2771
|
+
tooltip={
|
|
2772
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2773
|
+
<Tooltip.Target>
|
|
2774
|
+
<Icon
|
|
2775
|
+
display='question'
|
|
2776
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
2777
|
+
/>
|
|
2778
|
+
</Tooltip.Target>
|
|
2779
|
+
<Tooltip.Content>
|
|
2780
|
+
<p>Show any data not associated with a geographic location</p>
|
|
2781
|
+
</Tooltip.Content>
|
|
2782
|
+
</Tooltip>
|
|
2783
|
+
}
|
|
2784
|
+
/>
|
|
2785
|
+
|
|
2786
|
+
<TextField
|
|
2787
|
+
value={table.indexLabel || ''}
|
|
2788
|
+
updateField={updateField}
|
|
2789
|
+
section='table'
|
|
2790
|
+
fieldName='indexLabel'
|
|
2791
|
+
label='Index Column Header'
|
|
2792
|
+
placeholder='Location'
|
|
2793
|
+
tooltip={
|
|
2794
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2795
|
+
<Tooltip.Target>
|
|
2796
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2797
|
+
</Tooltip.Target>
|
|
2798
|
+
<Tooltip.Content>
|
|
2799
|
+
<p>
|
|
2800
|
+
To comply with 508 standards, if the first column in the data table has no header, enter
|
|
2801
|
+
a brief one here.
|
|
2802
|
+
</p>
|
|
2803
|
+
</Tooltip.Content>
|
|
2804
|
+
</Tooltip>
|
|
2805
|
+
}
|
|
2806
|
+
/>
|
|
2807
|
+
<TextField
|
|
2808
|
+
value={config.table.caption}
|
|
2809
|
+
updateField={updateField}
|
|
2810
|
+
section='table'
|
|
2811
|
+
fieldName='caption'
|
|
2812
|
+
label='Screen Reader Description'
|
|
2813
|
+
placeholder='Data Table'
|
|
2814
|
+
tooltip={
|
|
2815
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2816
|
+
<Tooltip.Target>
|
|
2817
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2818
|
+
</Tooltip.Target>
|
|
2819
|
+
<Tooltip.Content>
|
|
2820
|
+
<p>Enter a description of the data table to be read by screen readers.</p>
|
|
2821
|
+
</Tooltip.Content>
|
|
2822
|
+
</Tooltip>
|
|
2823
|
+
}
|
|
2824
|
+
type='textarea'
|
|
2825
|
+
/>
|
|
2826
|
+
<CheckBox
|
|
2827
|
+
value={config.table.limitHeight}
|
|
2828
|
+
section='table'
|
|
2829
|
+
subsection={null}
|
|
2830
|
+
fieldName='limitHeight'
|
|
2831
|
+
label='Limit Table Height'
|
|
2832
|
+
updateField={updateField}
|
|
2833
|
+
onChange={event => {
|
|
2834
|
+
handleEditorChanges('limitDataTableHeight', event.target.checked)
|
|
2835
|
+
}}
|
|
2836
|
+
/>
|
|
2837
|
+
{config.table.limitHeight && (
|
|
2838
|
+
<TextField
|
|
2839
|
+
value={table.height}
|
|
2840
|
+
updateField={updateField}
|
|
2841
|
+
section='table'
|
|
2842
|
+
fieldName='height'
|
|
2843
|
+
label='Data Table Height'
|
|
2844
|
+
placeholder='Height(px)'
|
|
2845
|
+
type='number'
|
|
2846
|
+
min='0'
|
|
2847
|
+
max='500'
|
|
2848
|
+
/>
|
|
2849
|
+
)}
|
|
2850
|
+
|
|
2851
|
+
<TextField
|
|
2852
|
+
value={table.cellMinWidth}
|
|
2853
|
+
updateField={updateField}
|
|
2854
|
+
section='table'
|
|
2855
|
+
fieldName='cellMinWidth'
|
|
2856
|
+
label='Table Cell Min Width'
|
|
2857
|
+
type='number'
|
|
2858
|
+
min='0'
|
|
2859
|
+
max='500'
|
|
2860
|
+
/>
|
|
2861
|
+
|
|
2862
|
+
<CheckBox
|
|
2863
|
+
value={config.table.expanded || false}
|
|
2864
|
+
section='table'
|
|
2865
|
+
subsection={null}
|
|
2866
|
+
fieldName='expanded'
|
|
2867
|
+
label='Map loads with data table expanded'
|
|
2868
|
+
updateField={updateField}
|
|
2869
|
+
onChange={event => {
|
|
2870
|
+
handleEditorChanges('expandDataTable', event.target.checked)
|
|
2871
|
+
}}
|
|
2872
|
+
/>
|
|
2873
|
+
<CheckBox
|
|
2874
|
+
value={config.table.download}
|
|
2875
|
+
fieldName='download'
|
|
2876
|
+
label='Show Download CSV Link'
|
|
2877
|
+
section='table'
|
|
2878
|
+
updateField={updateField}
|
|
2879
|
+
/>
|
|
2880
|
+
{config.table.download && (
|
|
2881
|
+
<>
|
|
2882
|
+
<CheckBox
|
|
2883
|
+
value={config.table.showDownloadLinkBelow}
|
|
2884
|
+
section='table'
|
|
2885
|
+
subsection={null}
|
|
2886
|
+
fieldName='showDownloadLinkBelow'
|
|
2887
|
+
label='Show Link Below Table'
|
|
2888
|
+
updateField={updateField}
|
|
2889
|
+
className='ms-4'
|
|
2890
|
+
onChange={event => {
|
|
2891
|
+
handleEditorChanges('toggleDownloadLinkBelow', event.target.checked)
|
|
2892
|
+
}}
|
|
2893
|
+
/>
|
|
2894
|
+
<CheckBox
|
|
2895
|
+
value={config.table.downloadVisibleDataOnly}
|
|
2896
|
+
fieldName='downloadVisibleDataOnly'
|
|
2897
|
+
className='ms-4'
|
|
2898
|
+
label='Download only visible data'
|
|
2899
|
+
section='table'
|
|
2900
|
+
updateField={updateField}
|
|
2901
|
+
/>
|
|
2902
|
+
</>
|
|
2903
|
+
)}
|
|
2904
|
+
{isDashboard && (
|
|
2905
|
+
<CheckBox
|
|
2906
|
+
value={config.table.showDataTableLink}
|
|
2907
|
+
section='table'
|
|
2908
|
+
subsection={null}
|
|
2909
|
+
fieldName='showDataTableLink'
|
|
2910
|
+
label='Show Data Table Name & Link'
|
|
2911
|
+
updateField={updateField}
|
|
2912
|
+
/>
|
|
2913
|
+
)}
|
|
2914
|
+
{isLoadedFromUrl && (
|
|
2915
|
+
<CheckBox
|
|
2916
|
+
value={config.table.showDownloadUrl}
|
|
2917
|
+
section='table'
|
|
2918
|
+
subsection={null}
|
|
2919
|
+
fieldName='showDownloadUrl'
|
|
2920
|
+
label='Show URL to Automatically Updated Data'
|
|
2921
|
+
updateField={updateField}
|
|
2922
|
+
/>
|
|
2923
|
+
)}
|
|
2924
|
+
<CheckBox
|
|
2925
|
+
value={config.table.showFullGeoNameInCSV}
|
|
2926
|
+
section='table'
|
|
2927
|
+
subsection={null}
|
|
2928
|
+
fieldName='showFullGeoNameInCSV'
|
|
2929
|
+
label='Include Full Geo Name in CSV Download'
|
|
2930
|
+
updateField={updateField}
|
|
2931
|
+
onChange={event => {
|
|
2932
|
+
handleEditorChanges('toggleShowFullGeoNameInCSV', event.target.checked)
|
|
2933
|
+
}}
|
|
2934
|
+
/>
|
|
2935
|
+
<CheckBox
|
|
2936
|
+
value={config.general.showDownloadImgButton}
|
|
2937
|
+
section='general'
|
|
2938
|
+
subsection={null}
|
|
2939
|
+
fieldName='showDownloadImgButton'
|
|
2940
|
+
label='Enable Image Download'
|
|
2941
|
+
updateField={updateField}
|
|
2942
|
+
onChange={event => {
|
|
2943
|
+
handleEditorChanges('toggleDownloadImgButton', event.target.checked)
|
|
2944
|
+
}}
|
|
2945
|
+
/>
|
|
2946
|
+
{config.general.showDownloadImgButton && (
|
|
2947
|
+
<CheckBox
|
|
2948
|
+
value={config.general.includeContextInDownload}
|
|
2949
|
+
section='general'
|
|
2950
|
+
subsection={null}
|
|
2951
|
+
className='ms-4'
|
|
2952
|
+
fieldName='includeContextInDownload'
|
|
2953
|
+
label='Include Heading & Context'
|
|
2954
|
+
updateField={updateField}
|
|
2955
|
+
tooltip={
|
|
2956
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2957
|
+
<Tooltip.Target>
|
|
2958
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2959
|
+
</Tooltip.Target>
|
|
2960
|
+
<Tooltip.Content>
|
|
2961
|
+
<p>
|
|
2962
|
+
When enabled, the image download will include the section heading (H2 or H3) and any
|
|
2963
|
+
explanatory paragraphs that appear before the visualization
|
|
2964
|
+
</p>
|
|
2965
|
+
</Tooltip.Content>
|
|
2966
|
+
</Tooltip>
|
|
2967
|
+
}
|
|
2968
|
+
/>
|
|
2969
|
+
)}
|
|
2970
|
+
|
|
2971
|
+
{/* <label className='checkbox'>
|
|
2972
|
+
<input
|
|
2973
|
+
type='checkbox'
|
|
2974
|
+
checked={state.general.showDownloadPdfButton}
|
|
2975
|
+
onChange={event => {
|
|
2976
|
+
handleEditorChanges('toggleDownloadPdfButton', event.target.checked)
|
|
2977
|
+
}}
|
|
2978
|
+
/>
|
|
2979
|
+
<span className='edit-label'>Enable Pdf Download</span>
|
|
2980
|
+
</label> */}
|
|
2981
|
+
</AccordionItemPanel>
|
|
2982
|
+
</AccordionItem>
|
|
2983
|
+
)}
|
|
2984
|
+
<AccordionItem>
|
|
2985
|
+
{' '}
|
|
2986
|
+
{/* Tooltips */}
|
|
2987
|
+
<AccordionItemHeading>
|
|
2988
|
+
<AccordionItemButton>Interactivity</AccordionItemButton>
|
|
2989
|
+
</AccordionItemHeading>
|
|
2990
|
+
<AccordionItemPanel>
|
|
2991
|
+
<Select
|
|
2992
|
+
label={
|
|
2993
|
+
<>
|
|
2994
|
+
Detail displays on{' '}
|
|
2995
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2996
|
+
<Tooltip.Target>
|
|
2997
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2998
|
+
</Tooltip.Target>
|
|
2999
|
+
<Tooltip.Content>
|
|
3000
|
+
<p>
|
|
3001
|
+
At mobile sizes, information always appears in a popover modal when a user taps on an
|
|
3002
|
+
item.
|
|
3003
|
+
</p>
|
|
3004
|
+
</Tooltip.Content>
|
|
3005
|
+
</Tooltip>
|
|
3006
|
+
</>
|
|
3007
|
+
}
|
|
3008
|
+
value={config.tooltips.appearanceType}
|
|
3009
|
+
options={[
|
|
3010
|
+
{ value: 'hover', label: 'Hover - Tooltip' },
|
|
3011
|
+
{ value: 'click', label: 'Click - Popover Modal' }
|
|
3012
|
+
]}
|
|
3013
|
+
onChange={event => {
|
|
3014
|
+
handleEditorChanges('appearanceType', event.target.value)
|
|
3015
|
+
}}
|
|
3016
|
+
/>
|
|
3017
|
+
{'click' === config.tooltips.appearanceType && (
|
|
3018
|
+
<TextField
|
|
3019
|
+
value={tooltips.linkLabel}
|
|
3020
|
+
section='tooltips'
|
|
3021
|
+
fieldName='linkLabel'
|
|
3022
|
+
label='Tooltips Link Label'
|
|
3023
|
+
updateField={updateField}
|
|
3024
|
+
/>
|
|
3025
|
+
)}
|
|
3026
|
+
</AccordionItemPanel>
|
|
3027
|
+
</AccordionItem>
|
|
3028
|
+
<AccordionItem>
|
|
3029
|
+
{' '}
|
|
3030
|
+
{/* Visual */}
|
|
3031
|
+
<AccordionItemHeading>
|
|
3032
|
+
<AccordionItemButton>Visual</AccordionItemButton>
|
|
3033
|
+
</AccordionItemHeading>
|
|
3034
|
+
<AccordionItemPanel>
|
|
3035
|
+
<HeaderThemeSelector
|
|
3036
|
+
selectedTheme={config.general.headerColor}
|
|
3037
|
+
onThemeSelect={palette => handleEditorChanges('headerColor', palette)}
|
|
3038
|
+
label='Header Theme'
|
|
3039
|
+
/>
|
|
3040
|
+
<CheckBox
|
|
3041
|
+
value={config.general.showTitle || false}
|
|
3042
|
+
section='general'
|
|
3043
|
+
subsection={null}
|
|
3044
|
+
fieldName='showTitle'
|
|
3045
|
+
label='Show Title'
|
|
3046
|
+
updateField={updateField}
|
|
3047
|
+
onChange={event => {
|
|
3048
|
+
handleEditorChanges('showTitle', event.target.checked)
|
|
3049
|
+
}}
|
|
3050
|
+
/>
|
|
3051
|
+
|
|
3052
|
+
{'navigation' === config.general.type && (
|
|
3053
|
+
<CheckBox
|
|
3054
|
+
value={config.general.fullBorder || false}
|
|
3055
|
+
section='general'
|
|
3056
|
+
subsection={null}
|
|
3057
|
+
fieldName='fullBorder'
|
|
3058
|
+
label='Add border around map'
|
|
3059
|
+
updateField={updateField}
|
|
3060
|
+
/>
|
|
3061
|
+
)}
|
|
3062
|
+
<Select
|
|
3063
|
+
label='Geo Border Color'
|
|
3064
|
+
value={config.general.geoBorderColor || ''}
|
|
3065
|
+
options={[
|
|
3066
|
+
{ value: 'darkGray', label: 'Dark Gray (Default)' },
|
|
3067
|
+
{ value: 'sameAsBackground', label: 'White' }
|
|
3068
|
+
]}
|
|
3069
|
+
onChange={event => {
|
|
3070
|
+
handleEditorChanges('geoBorderColor', event.target.value)
|
|
3071
|
+
}}
|
|
3072
|
+
/>
|
|
3073
|
+
<label>
|
|
3074
|
+
<span className='edit-label'>Map Color Palette</span>
|
|
3075
|
+
</label>
|
|
3076
|
+
<div className='mb-2'>
|
|
3077
|
+
<small className='text-muted'>
|
|
3078
|
+
Review color contrasts{' '}
|
|
3079
|
+
<a
|
|
3080
|
+
href='https://webaim.org/resources/contrastchecker/'
|
|
3081
|
+
target='_blank'
|
|
3082
|
+
rel='noopener noreferrer'
|
|
3083
|
+
>
|
|
3084
|
+
here
|
|
3085
|
+
</a>
|
|
3086
|
+
</small>
|
|
3087
|
+
</div>
|
|
3088
|
+
<DeveloperPaletteRollback config={config} updateConfig={setConfig} />
|
|
3089
|
+
<InputToggle
|
|
3090
|
+
type='3d'
|
|
3091
|
+
section='general'
|
|
3092
|
+
subsection='palette'
|
|
3093
|
+
fieldName='isReversed'
|
|
3094
|
+
size='small'
|
|
3095
|
+
label='Use selected palette in reverse order'
|
|
3096
|
+
onClick={() => {
|
|
3097
|
+
const _state = cloneConfig(config)
|
|
3098
|
+
const currentPaletteName = config.general.palette?.name || ''
|
|
3099
|
+
_state.general.palette.isReversed = !_state.general.palette.isReversed
|
|
3100
|
+
let paletteName = ''
|
|
3101
|
+
if (_state.general.palette.isReversed && !currentPaletteName.endsWith('reverse')) {
|
|
3102
|
+
paletteName = currentPaletteName + 'reverse'
|
|
3103
|
+
}
|
|
3104
|
+
if (!_state.general.palette.isReversed && currentPaletteName.endsWith('reverse')) {
|
|
3105
|
+
paletteName = currentPaletteName.slice(0, -7)
|
|
3106
|
+
}
|
|
3107
|
+
if (paletteName) {
|
|
3108
|
+
_state.general.palette.name = paletteName
|
|
3109
|
+
}
|
|
3110
|
+
setConfig(_state)
|
|
3111
|
+
}}
|
|
3112
|
+
value={config.general.palette.isReversed}
|
|
3113
|
+
/>
|
|
3114
|
+
<span>Sequential</span>
|
|
3115
|
+
<PaletteSelector
|
|
3116
|
+
palettes={sequential}
|
|
3117
|
+
colorPalettes={colorPalettes}
|
|
3118
|
+
config={config}
|
|
3119
|
+
onPaletteSelect={handlePaletteSelection}
|
|
3120
|
+
selectedPalette={getCurrentPaletteName(config)}
|
|
3121
|
+
colorIndices={[2, 3, 5]}
|
|
3122
|
+
className='color-palette'
|
|
3123
|
+
element='button'
|
|
3124
|
+
getItemClassName={getPaletteClassName}
|
|
3125
|
+
/>
|
|
3126
|
+
<span>Non-Sequential</span>
|
|
3127
|
+
<PaletteSelector
|
|
3128
|
+
palettes={nonSequential}
|
|
3129
|
+
colorPalettes={colorPalettes}
|
|
3130
|
+
config={config}
|
|
3131
|
+
onPaletteSelect={handlePaletteSelection}
|
|
3132
|
+
selectedPalette={getCurrentPaletteName(config)}
|
|
3133
|
+
colorIndices={[2, 3, 5]}
|
|
3134
|
+
className='color-palette'
|
|
3135
|
+
element='button'
|
|
3136
|
+
getItemClassName={getPaletteClassName}
|
|
3137
|
+
minColorsForFilter={(_, paletteAccessor, config) => {
|
|
3138
|
+
if (paletteAccessor.length <= 8 && config.general.geoType === 'us-region') {
|
|
3139
|
+
return false
|
|
3140
|
+
}
|
|
3141
|
+
return true
|
|
3142
|
+
}}
|
|
3143
|
+
/>
|
|
3144
|
+
<span>Colorblind Safe</span>
|
|
3145
|
+
<PaletteSelector
|
|
3146
|
+
palettes={accessibleColors}
|
|
3147
|
+
colorPalettes={colorPalettes}
|
|
3148
|
+
config={config}
|
|
3149
|
+
onPaletteSelect={handlePaletteSelection}
|
|
3150
|
+
selectedPalette={getCurrentPaletteName(config)}
|
|
3151
|
+
colorIndices={[2, 3, 5]}
|
|
3152
|
+
className='color-palette'
|
|
3153
|
+
element='button'
|
|
3154
|
+
getItemClassName={getPaletteClassName}
|
|
3155
|
+
minColorsForFilter={(_, paletteAccessor, config) => {
|
|
3156
|
+
if (paletteAccessor.length <= 8 && config.general.geoType === 'us-region') {
|
|
3157
|
+
return false
|
|
3158
|
+
}
|
|
3159
|
+
return true
|
|
3160
|
+
}}
|
|
3161
|
+
/>
|
|
3162
|
+
|
|
3163
|
+
{isCoveDeveloperMode() && (
|
|
3164
|
+
<>
|
|
3165
|
+
<div className='mt-3'>
|
|
3166
|
+
<label className='checkbox'>
|
|
3167
|
+
<input
|
|
3168
|
+
type='checkbox'
|
|
3169
|
+
checked={!!config.general.palette.customColorsOrdered}
|
|
3170
|
+
onChange={e => {
|
|
3171
|
+
const _state = cloneConfig(config)
|
|
3172
|
+
if (e.target.checked) {
|
|
3173
|
+
// Extract actual colors from runtime legend if available
|
|
3174
|
+
if (runtimeLegend?.items && runtimeLegend.items.length > 0) {
|
|
3175
|
+
const extractedColors = []
|
|
3176
|
+
for (const item of runtimeLegend.items) {
|
|
3177
|
+
// Skip special classes (like "No Data")
|
|
3178
|
+
if (item.special) continue
|
|
3179
|
+
// Add the color if it exists and hasn't been added yet
|
|
3180
|
+
if (item.color && !extractedColors.includes(item.color)) {
|
|
3181
|
+
extractedColors.push(item.color)
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
_state.general.palette.customColorsOrdered =
|
|
3185
|
+
extractedColors.length > 0
|
|
3186
|
+
? extractedColors
|
|
3187
|
+
: ['#3366cc', '#5588dd', '#77aaee', '#99ccff']
|
|
3188
|
+
} else {
|
|
3189
|
+
// Fallback to default colors if runtime legend not available
|
|
3190
|
+
_state.general.palette.customColorsOrdered = [
|
|
3191
|
+
'#3366cc',
|
|
3192
|
+
'#5588dd',
|
|
3193
|
+
'#77aaee',
|
|
3194
|
+
'#99ccff'
|
|
3195
|
+
]
|
|
3196
|
+
}
|
|
3197
|
+
} else {
|
|
3198
|
+
// Remove custom colors and revert to default palette
|
|
3199
|
+
delete _state.general.palette.customColorsOrdered
|
|
3200
|
+
delete _state.general.palette.customColors
|
|
3201
|
+
// Set default palette if none exists
|
|
3202
|
+
if (!_state.general.palette.name) {
|
|
3203
|
+
_state.general.palette.name = 'sequential_blue_green'
|
|
3204
|
+
_state.general.palette.version = '2.0'
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
setConfig(_state)
|
|
3208
|
+
}}
|
|
3209
|
+
/>
|
|
3210
|
+
Use Custom Colors
|
|
3211
|
+
</label>
|
|
3212
|
+
</div>
|
|
3213
|
+
|
|
3214
|
+
{config.general.palette.customColorsOrdered && (
|
|
3215
|
+
<div className='mt-2'>
|
|
3216
|
+
<CustomColorsEditor
|
|
3217
|
+
colors={config.general.palette.customColorsOrdered}
|
|
3218
|
+
onChange={newColors => {
|
|
3219
|
+
const _state = cloneConfig(config)
|
|
3220
|
+
_state.general.palette.customColorsOrdered = newColors
|
|
3221
|
+
setConfig(_state)
|
|
3222
|
+
}}
|
|
3223
|
+
label='Custom Color Order'
|
|
3224
|
+
minColors={1}
|
|
3225
|
+
maxColors={20}
|
|
3226
|
+
/>
|
|
3227
|
+
</div>
|
|
3228
|
+
)}
|
|
3229
|
+
</>
|
|
3230
|
+
)}
|
|
3231
|
+
|
|
3232
|
+
<label>
|
|
3233
|
+
Geocode Settings
|
|
3234
|
+
<TextField
|
|
3235
|
+
type='number'
|
|
3236
|
+
value={config.visual.geoCodeCircleSize}
|
|
3237
|
+
section='visual'
|
|
3238
|
+
max='10'
|
|
3239
|
+
fieldName='geoCodeCircleSize'
|
|
3240
|
+
label='Geocode Circle Size'
|
|
3241
|
+
updateField={updateField}
|
|
3242
|
+
/>
|
|
3243
|
+
</label>
|
|
3244
|
+
|
|
3245
|
+
{config.general.type === 'bubble' && (
|
|
3246
|
+
<>
|
|
3247
|
+
<TextField
|
|
3248
|
+
type='number'
|
|
3249
|
+
value={config.visual.minBubbleSize}
|
|
3250
|
+
section='visual'
|
|
3251
|
+
fieldName='minBubbleSize'
|
|
3252
|
+
label='Minimum Bubble Size'
|
|
3253
|
+
updateField={updateField}
|
|
3254
|
+
/>
|
|
3255
|
+
<TextField
|
|
3256
|
+
type='number'
|
|
3257
|
+
value={config.visual.maxBubbleSize}
|
|
3258
|
+
section='visual'
|
|
3259
|
+
fieldName='maxBubbleSize'
|
|
3260
|
+
label='Maximum Bubble Size'
|
|
3261
|
+
updateField={updateField}
|
|
3262
|
+
/>
|
|
3263
|
+
</>
|
|
3264
|
+
)}
|
|
3265
|
+
{(config.general.geoType === 'world' ||
|
|
3266
|
+
(config.general.geoType === 'us' && config.general.type === 'bubble')) && (
|
|
3267
|
+
<label className='checkbox'>
|
|
3268
|
+
<input
|
|
3269
|
+
type='checkbox'
|
|
3270
|
+
checked={config.visual.showBubbleZeros}
|
|
3271
|
+
onChange={event => {
|
|
3272
|
+
const _newConfig = _.cloneDeep(config)
|
|
3273
|
+
_newConfig.visual.showBubbleZeros = event.target.checked
|
|
3274
|
+
setConfig(_newConfig)
|
|
3275
|
+
}}
|
|
3276
|
+
/>
|
|
3277
|
+
<span className='edit-label'>Show Data with Zero's on Bubble Map</span>
|
|
3278
|
+
</label>
|
|
3279
|
+
)}
|
|
3280
|
+
{(config.general.geoType === 'world' || config.general.geoType === 'single-state') && (
|
|
3281
|
+
<label className='checkbox'>
|
|
3282
|
+
<input
|
|
3283
|
+
type='checkbox'
|
|
3284
|
+
checked={config.general.allowMapZoom}
|
|
3285
|
+
onChange={event => {
|
|
3286
|
+
const _newConfig = cloneConfig(config)
|
|
3287
|
+
_newConfig.general.allowMapZoom = event.target.checked
|
|
3288
|
+
_newConfig.mapPosition.coordinates = config.general.geoType === 'world' ? [0, 30] : [0, 0]
|
|
3289
|
+
_newConfig.mapPosition.zoom = 1
|
|
3290
|
+
setConfig(_newConfig)
|
|
3291
|
+
}}
|
|
3292
|
+
/>
|
|
3293
|
+
<span className='edit-label'>Allow Map Zooming</span>
|
|
3294
|
+
</label>
|
|
3295
|
+
)}
|
|
3296
|
+
{config.general.type === 'bubble' && (
|
|
3297
|
+
<label className='checkbox'>
|
|
3298
|
+
<input
|
|
3299
|
+
type='checkbox'
|
|
3300
|
+
checked={config.visual.extraBubbleBorder}
|
|
3301
|
+
onChange={event => {
|
|
3302
|
+
const _newConfig = cloneConfig(config)
|
|
3303
|
+
_newConfig.visual.extraBubbleBorder = event.target.checked
|
|
3304
|
+
setConfig(_newConfig)
|
|
3305
|
+
}}
|
|
3306
|
+
/>
|
|
3307
|
+
<span className='edit-label'>Bubble Map has extra border</span>
|
|
3308
|
+
</label>
|
|
3309
|
+
)}
|
|
3310
|
+
{(config.general.geoType === 'us' ||
|
|
3311
|
+
config.general.geoType === 'us-county' ||
|
|
3312
|
+
config.general.geoType === 'world') && (
|
|
3313
|
+
<>
|
|
3314
|
+
<Select
|
|
3315
|
+
label='Default City Style'
|
|
3316
|
+
value={config.visual.cityStyle || 'circle'}
|
|
3317
|
+
options={[
|
|
3318
|
+
{ value: 'circle', label: 'Circle' },
|
|
3319
|
+
{ value: 'pin', label: 'Pin' },
|
|
3320
|
+
{ value: 'square', label: 'Square' },
|
|
3321
|
+
{ value: 'triangle', label: 'Triangle' },
|
|
3322
|
+
{ value: 'diamond', label: 'Diamond' },
|
|
3323
|
+
{ value: 'star', label: 'Star' }
|
|
3324
|
+
]}
|
|
3325
|
+
onChange={event => {
|
|
3326
|
+
handleEditorChanges('handleCityStyle', event.target.value)
|
|
3327
|
+
}}
|
|
3328
|
+
/>
|
|
3329
|
+
<TextField
|
|
3330
|
+
value={config.visual.cityStyleLabel}
|
|
3331
|
+
section='visual'
|
|
3332
|
+
fieldName='cityStyleLabel'
|
|
3333
|
+
label='Label (Optional) '
|
|
3334
|
+
updateField={updateField}
|
|
3335
|
+
tooltip={
|
|
3336
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
3337
|
+
<Tooltip.Target>
|
|
3338
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
3339
|
+
</Tooltip.Target>
|
|
3340
|
+
<Tooltip.Content>
|
|
3341
|
+
<p>When a label is provided, the default city style will appear in the legend.</p>
|
|
3342
|
+
</Tooltip.Content>
|
|
3343
|
+
</Tooltip>
|
|
3344
|
+
}
|
|
3345
|
+
/>
|
|
3346
|
+
</>
|
|
3347
|
+
)}
|
|
3348
|
+
{/* <AdditionalCityStyles /> */}
|
|
3349
|
+
<>
|
|
3350
|
+
{config.visual.additionalCityStyles.length > 0 &&
|
|
3351
|
+
config.visual.additionalCityStyles.map(({ label, column, value, shape }, i) => {
|
|
3352
|
+
return (
|
|
3353
|
+
<div className='edit-block' key={`additional-city-style-${i}`}>
|
|
3354
|
+
<button
|
|
3355
|
+
className='remove-column'
|
|
3356
|
+
onClick={e => {
|
|
3357
|
+
e.preventDefault()
|
|
3358
|
+
editCityStyles('remove', i, '', '')
|
|
3359
|
+
}}
|
|
3360
|
+
>
|
|
3361
|
+
Remove
|
|
3362
|
+
</button>
|
|
3363
|
+
<p>City Style {i + 1}</p>
|
|
3364
|
+
<Select
|
|
3365
|
+
label='Column with configuration value'
|
|
3366
|
+
value={column}
|
|
3367
|
+
options={columnsOptions.map(c => c.key)}
|
|
3368
|
+
onChange={e => {
|
|
3369
|
+
editCityStyles('update', i, 'column', e.target.value)
|
|
3370
|
+
}}
|
|
3371
|
+
/>
|
|
3372
|
+
<label>
|
|
3373
|
+
<span className='edit-label column-heading'>Value to Trigger</span>
|
|
3374
|
+
<input
|
|
3375
|
+
type='text'
|
|
3376
|
+
value={value}
|
|
3377
|
+
onChange={e => {
|
|
3378
|
+
editCityStyles('update', i, 'value', e.target.value)
|
|
3379
|
+
}}
|
|
3380
|
+
></input>
|
|
3381
|
+
</label>
|
|
3382
|
+
<Select
|
|
3383
|
+
label='Shape'
|
|
3384
|
+
value={shape}
|
|
3385
|
+
options={[
|
|
3386
|
+
{ value: '', label: '- Select Option -' },
|
|
3387
|
+
...['Circle', 'Square', 'Triangle', 'Diamond', 'Star', 'Pin']
|
|
3388
|
+
.filter(val => String(config.visual.cityStyle).toLowerCase() !== val.toLowerCase())
|
|
3389
|
+
.map(val => ({ value: val, label: val }))
|
|
3390
|
+
]}
|
|
3391
|
+
onChange={e => {
|
|
3392
|
+
editCityStyles('update', i, 'shape', e.target.value)
|
|
3393
|
+
}}
|
|
3394
|
+
/>
|
|
3395
|
+
<label>
|
|
3396
|
+
<span className='edit-label column-heading'>Label</span>
|
|
3397
|
+
<input
|
|
3398
|
+
key={i}
|
|
3399
|
+
type='text'
|
|
3400
|
+
value={label}
|
|
3401
|
+
onChange={e => {
|
|
3402
|
+
editCityStyles('update', i, 'label', e.target.value)
|
|
3403
|
+
}}
|
|
3404
|
+
/>
|
|
3405
|
+
</label>
|
|
3406
|
+
</div>
|
|
3407
|
+
)
|
|
3408
|
+
})}
|
|
3409
|
+
|
|
3410
|
+
<button
|
|
3411
|
+
type='button'
|
|
3412
|
+
onClick={() => editCityStyles('add', 0, '', '')}
|
|
3413
|
+
className='btn btn-primary full-width'
|
|
3414
|
+
>
|
|
3415
|
+
Add city style
|
|
3416
|
+
</button>
|
|
3417
|
+
</>
|
|
3418
|
+
<label htmlFor='opacity'>
|
|
3419
|
+
<TextField
|
|
3420
|
+
type='number'
|
|
3421
|
+
min={0}
|
|
3422
|
+
max={100}
|
|
3423
|
+
value={config.tooltips.opacity ? config.tooltips.opacity : 100}
|
|
3424
|
+
section='tooltips'
|
|
3425
|
+
fieldName='opacity'
|
|
3426
|
+
label='Tooltip Opacity (%)'
|
|
3427
|
+
updateField={updateField}
|
|
3428
|
+
/>
|
|
3429
|
+
</label>
|
|
3430
|
+
{/* Leaflet Map Type */}
|
|
3431
|
+
{config.general.geoType === 'leaflet' && (
|
|
3432
|
+
<>
|
|
3433
|
+
<Select
|
|
3434
|
+
label='Leaflet Theme'
|
|
3435
|
+
options={layerOptions}
|
|
3436
|
+
section={'leaflet'}
|
|
3437
|
+
fieldName='theme'
|
|
3438
|
+
updateField={updateField}
|
|
3439
|
+
/>
|
|
3440
|
+
</>
|
|
3441
|
+
)}
|
|
3442
|
+
</AccordionItemPanel>
|
|
3443
|
+
</AccordionItem>
|
|
3444
|
+
<AccordionItem>
|
|
3445
|
+
<AccordionItemHeading>
|
|
3446
|
+
<AccordionItemButton>Custom Map Layers</AccordionItemButton>
|
|
3447
|
+
</AccordionItemHeading>
|
|
3448
|
+
<AccordionItemPanel>
|
|
3449
|
+
{config.map.layers.length === 0 && <p>There are currently no layers.</p>}
|
|
3450
|
+
|
|
3451
|
+
{config.map.layers.map((layer, index) => {
|
|
3452
|
+
return (
|
|
3453
|
+
<>
|
|
3454
|
+
<Accordion allowZeroExpanded>
|
|
3455
|
+
<AccordionItem className='series-item map-layers-list'>
|
|
3456
|
+
<AccordionItemHeading className='series-item__title map-layers-list--title'>
|
|
3457
|
+
<AccordionItemButton>{`Layer ${index + 1}: ${layer.name}`}</AccordionItemButton>
|
|
3458
|
+
</AccordionItemHeading>
|
|
3459
|
+
<AccordionItemPanel>
|
|
3460
|
+
<div className='map-layers-panel'>
|
|
3461
|
+
<label htmlFor='layerName'>Layer Name:</label>
|
|
3462
|
+
<input
|
|
3463
|
+
type='text'
|
|
3464
|
+
name='layerName'
|
|
3465
|
+
value={layer.name}
|
|
3466
|
+
onChange={e => handleMapLayer(e, index, 'name')}
|
|
3467
|
+
/>
|
|
3468
|
+
<label htmlFor='layerFilename'>File:</label>
|
|
3469
|
+
<input
|
|
3470
|
+
type='text'
|
|
3471
|
+
name='layerFilename'
|
|
3472
|
+
value={layer.url}
|
|
3473
|
+
onChange={e => handleMapLayer(e, index, 'url')}
|
|
3474
|
+
/>
|
|
3475
|
+
<label htmlFor='layerNamespace'>TOPOJSON Namespace:</label>
|
|
3476
|
+
<input
|
|
3477
|
+
type='text'
|
|
3478
|
+
name='layerNamespace'
|
|
3479
|
+
value={layer.namespace}
|
|
3480
|
+
onChange={e => handleMapLayer(e, index, 'namespace')}
|
|
3481
|
+
/>
|
|
3482
|
+
<label htmlFor='layerFill'>Fill Color:</label>
|
|
3483
|
+
<input
|
|
3484
|
+
type='text'
|
|
3485
|
+
name='layerFill'
|
|
3486
|
+
value={layer.fill}
|
|
3487
|
+
onChange={e => handleMapLayer(e, index, 'fill')}
|
|
3488
|
+
/>
|
|
3489
|
+
<label htmlFor='layerFill'>Fill Opacity (%):</label>
|
|
3490
|
+
<input
|
|
3491
|
+
type='number'
|
|
3492
|
+
min={0}
|
|
3493
|
+
max={100}
|
|
3494
|
+
name='layerFill'
|
|
3495
|
+
value={layer.fillOpacity ? layer.fillOpacity * 100 : ''}
|
|
3496
|
+
onChange={e => handleMapLayer(e, index, 'fillOpacity')}
|
|
3497
|
+
/>
|
|
3498
|
+
<label htmlFor='layerStroke'>Stroke Color:</label>
|
|
3499
|
+
<input
|
|
3500
|
+
type='text'
|
|
3501
|
+
name='layerStroke'
|
|
3502
|
+
value={layer.stroke}
|
|
3503
|
+
onChange={e => handleMapLayer(e, index, 'stroke')}
|
|
3504
|
+
/>
|
|
3505
|
+
<label htmlFor='layerStroke'>Stroke Width:</label>
|
|
3506
|
+
<input
|
|
3507
|
+
type='number'
|
|
3508
|
+
min={0}
|
|
3509
|
+
max={5}
|
|
3510
|
+
name='layerStrokeWidth'
|
|
3511
|
+
value={layer.strokeWidth}
|
|
3512
|
+
onChange={e => handleMapLayer(e, index, 'strokeWidth')}
|
|
3513
|
+
/>
|
|
3514
|
+
<label htmlFor='layerTooltip'>Tooltip:</label>
|
|
3515
|
+
<textarea
|
|
3516
|
+
name='layerTooltip'
|
|
3517
|
+
value={layer.tooltip}
|
|
3518
|
+
onChange={e => handleMapLayer(e, index, 'tooltip')}
|
|
3519
|
+
></textarea>
|
|
3520
|
+
<button onClick={e => handleRemoveLayer(e, index)}>Remove Layer</button>
|
|
3521
|
+
</div>
|
|
3522
|
+
</AccordionItemPanel>
|
|
3523
|
+
</AccordionItem>
|
|
3524
|
+
</Accordion>
|
|
3525
|
+
</>
|
|
3526
|
+
)
|
|
3527
|
+
})}
|
|
3528
|
+
<button className={'btn btn-primary full-width'} onClick={handleAddLayer}>
|
|
3529
|
+
Add Map Layer
|
|
3530
|
+
</button>
|
|
3531
|
+
<p className='layer-purpose-details'>
|
|
3532
|
+
Context should be added to your visualization or associated page to describe the significance of
|
|
3533
|
+
layers that are added to maps.
|
|
3534
|
+
</p>
|
|
3535
|
+
</AccordionItemPanel>
|
|
3536
|
+
</AccordionItem>
|
|
3537
|
+
{config.general.geoType === 'us' && <Panels.PatternSettings name='Pattern Settings' />}
|
|
3538
|
+
{config.general.geoType !== 'us-county' && <Panels.Annotate name='Text Annotations' />}
|
|
3539
|
+
<PanelMarkup
|
|
3540
|
+
name='Markup Variables'
|
|
3541
|
+
markupVariables={config.markupVariables || []}
|
|
3542
|
+
data={config.data || []}
|
|
3543
|
+
enableMarkupVariables={config.enableMarkupVariables || false}
|
|
3544
|
+
onMarkupVariablesChange={variables => setConfig({ ...config, markupVariables: variables })}
|
|
3545
|
+
onToggleEnable={enabled => setConfig({ ...config, enableMarkupVariables: enabled })}
|
|
3546
|
+
/>
|
|
3547
|
+
<Panels.SmallMultiples name='Small Multiples' />
|
|
3548
|
+
</Accordion>
|
|
3549
|
+
<AdvancedEditor loadConfig={setConfig} config={config} convertStateToConfig={mapConvertStateToConfig} />
|
|
3550
|
+
</>
|
|
3551
|
+
)
|
|
3552
|
+
}}
|
|
3553
|
+
</BaseEditorPanel>
|
|
3380
3554
|
|
|
3381
3555
|
{showConversionModal && (
|
|
3382
3556
|
<PaletteConversionModal
|
|
@@ -3386,7 +3560,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3386
3560
|
paletteName={pendingPaletteSelection?.palette}
|
|
3387
3561
|
/>
|
|
3388
3562
|
)}
|
|
3389
|
-
</
|
|
3563
|
+
</React.Fragment>
|
|
3390
3564
|
)
|
|
3391
3565
|
}
|
|
3392
3566
|
|