@cdc/map 4.26.2 → 4.26.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONFIG.md +235 -0
- package/README.md +70 -24
- package/dist/cdcmap-CY9IcPSi.es.js +6 -0
- package/dist/cdcmap-DlpiY3fQ.es.js +4 -0
- package/dist/cdcmap.js +31260 -27946
- package/examples/{testing-layer-2.json → __data__/testing-layer-2.json} +1 -1
- package/examples/{testing-layer.json → __data__/testing-layer.json} +1 -1
- package/examples/county-hsa-toggle.json +51993 -0
- package/examples/custom-map-layers.json +2 -2
- package/examples/default-county.json +3 -3
- package/examples/minimal-example.json +69 -0
- package/examples/private/annotation-bug.json +642 -0
- package/examples/private/css-issue.json +314 -0
- package/examples/private/region-breaking.json +1639 -0
- package/examples/private/test1.json +27247 -0
- package/package.json +4 -4
- package/src/CdcMap.tsx +3 -14
- package/src/CdcMapComponent.tsx +302 -164
- package/src/_stories/CdcMap.Defaults.smoke.stories.tsx +76 -0
- package/src/_stories/CdcMap.Editor.ColumnsSectionTests.stories.tsx +601 -0
- package/src/_stories/CdcMap.Editor.DataTableSectionTests.stories.tsx +404 -0
- package/src/_stories/CdcMap.Editor.FiltersSectionTests.stories.tsx +229 -0
- package/src/_stories/CdcMap.Editor.GeneralSectionTests.stories.tsx +262 -0
- package/src/_stories/CdcMap.Editor.LegendSectionTests.stories.tsx +541 -0
- package/src/_stories/CdcMap.Editor.MultiCountryWorldMapTests.stories.tsx +359 -0
- package/src/_stories/CdcMap.Editor.PatternSettingsSectionTests.stories.tsx +516 -0
- package/src/_stories/CdcMap.Editor.SmallMultiplesSectionTests.stories.tsx +165 -0
- package/src/_stories/CdcMap.Editor.TextAnnotationsSectionTests.stories.tsx +145 -0
- package/src/_stories/CdcMap.Editor.TypeSectionTests.stories.tsx +312 -0
- package/src/_stories/CdcMap.Editor.VisualSectionTests.stories.tsx +359 -0
- package/src/_stories/CdcMap.Editor.ZoomControlsTests.stories.tsx +88 -0
- package/src/_stories/{CdcMap.stories.tsx → CdcMap.smoke.stories.tsx} +23 -1
- package/src/_stories/Map.HTMLInDataTable.stories.tsx +385 -0
- package/src/_stories/_mock/legends/legend-tests.json +3 -3
- package/src/_stories/_mock/multi-state-show-unselected.json +82 -0
- package/src/cdcMapComponent.styles.css +2 -2
- package/src/components/Annotation/Annotation.Draggable.styles.css +4 -4
- package/src/components/Annotation/AnnotationDropdown.styles.css +1 -1
- package/src/components/Annotation/AnnotationList.styles.css +13 -13
- package/src/components/Annotation/AnnotationList.tsx +1 -1
- package/src/components/EditorPanel/components/EditorPanel.tsx +905 -416
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +112 -117
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings-style.css +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +31 -15
- package/src/components/EditorPanel/components/editorPanel.styles.css +55 -25
- package/src/components/Legend/components/Legend.tsx +12 -7
- package/src/components/Legend/components/LegendGroup/legend.group.css +5 -5
- package/src/components/Legend/components/LegendItem.Hex.tsx +4 -2
- package/src/components/Legend/components/index.scss +2 -3
- package/src/components/NavigationMenu.tsx +2 -1
- package/src/components/SmallMultiples/SmallMultiples.css +5 -5
- package/src/components/SmallMultiples/SynchronizedTooltip.tsx +1 -1
- package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +32 -17
- package/src/components/UsaMap/components/TerritoriesSection.tsx +3 -2
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +13 -8
- package/src/components/UsaMap/components/UsaMap.County.tsx +629 -231
- package/src/components/UsaMap/components/UsaMap.Region.styles.css +1 -1
- package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +2 -2
- package/src/components/UsaMap/components/UsaMap.State.tsx +14 -9
- package/src/components/UsaMap/data/cb_2019_us_county_20m.json +75817 -1
- package/src/components/UsaMap/data/hsa_fips_mapping.json +3144 -0
- package/src/components/WorldMap/WorldMap.tsx +10 -13
- package/src/components/WorldMap/data/world-topo-updated.json +1 -0
- package/src/components/WorldMap/data/world-topo.json +1 -1
- package/src/components/WorldMap/worldMap.styles.css +1 -1
- package/src/components/ZoomControls.tsx +49 -18
- package/src/components/zoomControls.styles.css +27 -11
- package/src/data/initial-state.js +15 -5
- package/src/data/legacy-defaults.ts +8 -0
- package/src/data/supported-counties.json +1 -1
- package/src/data/supported-geos.js +19 -0
- package/src/helpers/colors.ts +2 -1
- package/src/helpers/countyTerritories.ts +38 -0
- package/src/helpers/dataTableHelpers.ts +85 -0
- package/src/helpers/displayGeoName.ts +19 -11
- package/src/helpers/getMapContainerClasses.ts +8 -2
- package/src/helpers/getMatchingPatternForRow.ts +67 -0
- package/src/helpers/getPatternForRow.ts +11 -18
- package/src/helpers/tests/countyTerritories.test.ts +87 -0
- package/src/helpers/tests/dataTableHelpers.test.ts +78 -0
- package/src/helpers/tests/displayGeoName.test.ts +17 -0
- package/src/helpers/tests/getMatchingPatternForRow.test.ts +150 -0
- package/src/helpers/tests/getPatternForRow.test.ts +140 -2
- package/src/helpers/urlDataHelpers.ts +7 -1
- package/src/hooks/useApplyTooltipsToGeo.tsx +7 -4
- package/src/hooks/useMapLayers.tsx +1 -1
- package/src/hooks/useResizeObserver.ts +36 -22
- package/src/hooks/useTooltip.test.tsx +64 -0
- package/src/hooks/useTooltip.ts +46 -15
- package/src/scss/editor-panel.scss +1 -1
- package/src/scss/main.scss +140 -6
- package/src/scss/map.scss +9 -4
- package/src/store/map.actions.ts +5 -0
- package/src/store/map.reducer.ts +13 -0
- package/src/test/CdcMap.test.jsx +26 -2
- package/src/types/MapConfig.ts +28 -4
- package/src/types/MapContext.ts +5 -1
- package/topojson-updater/README.txt +1 -1
- package/dist/cdcmap-Cf9_fbQf.es.js +0 -6
- package/examples/__data__/city-state-data.json +0 -668
- package/examples/city-state.json +0 -434
- package/examples/default-world-data.json +0 -1450
- package/examples/new-cities.json +0 -656
- package/src/_stories/CdcMap.Editor.stories.tsx +0 -3475
- package/src/helpers/componentHelpers.ts +0 -8
- package/topojson-updater/package-lock.json +0 -223
- /package/src/_stories/{CdcMap.ColumnWrap.stories.tsx → CdcMap.ColumnWrap.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.DistrictOfColumbia.stories.tsx → CdcMap.DistrictOfColumbia.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Filters.stories.tsx → CdcMap.Filters.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Legend.Gradient.stories.tsx → CdcMap.Legend.Gradient.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Legend.stories.tsx → CdcMap.Legend.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Patterns.stories.tsx → CdcMap.Patterns.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.SmallMultiples.stories.tsx → CdcMap.SmallMultiples.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.Table.stories.tsx → CdcMap.Table.smoke.stories.tsx} +0 -0
- /package/src/_stories/{CdcMap.ZeroColor.stories.tsx → CdcMap.ZeroColor.smoke.stories.tsx} +0 -0
- /package/src/_stories/{GoogleMap.stories.tsx → GoogleMap.smoke.stories.tsx} +0 -0
- /package/src/_stories/{UsaMap.NoData.stories.tsx → UsaMap.NoData.smoke.stories.tsx} +0 -0
|
@@ -12,22 +12,24 @@ import {
|
|
|
12
12
|
} from 'react-accessible-accordion'
|
|
13
13
|
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'
|
|
14
14
|
import { useDebounce } from 'use-debounce'
|
|
15
|
-
import
|
|
15
|
+
import cloneDeep from 'lodash/cloneDeep'
|
|
16
|
+
import includes from 'lodash/includes'
|
|
16
17
|
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
|
17
18
|
import 'react-tooltip/dist/react-tooltip.css'
|
|
18
19
|
import Panels from './Panels'
|
|
19
|
-
import Layout from '@cdc/core/components/Layout'
|
|
20
20
|
|
|
21
21
|
// Data
|
|
22
22
|
import { mapColorPalettes as colorPalettes } from '@cdc/core/data/colorPalettes'
|
|
23
23
|
import { supportedStatesFipsCodes, supportedCountries } from '../../../data/supported-geos.js'
|
|
24
24
|
import { getSupportedCountryOptions } from '../../../helpers/getCountriesPicked'
|
|
25
|
+
import { displayGeoName } from '../../../helpers/displayGeoName'
|
|
25
26
|
|
|
26
27
|
// Components - Core
|
|
27
28
|
import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel/EditorPanel'
|
|
28
29
|
import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
|
|
29
30
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
30
31
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
32
|
+
import GroupedList from '@cdc/core/components/EditorPanel/GroupedList'
|
|
31
33
|
import InputToggle from '@cdc/core/components/inputs/InputToggle'
|
|
32
34
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
33
35
|
import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
|
|
@@ -49,19 +51,27 @@ import { MapContext } from '../../../types/MapContext.js'
|
|
|
49
51
|
import Alert from '@cdc/core/components/Alert'
|
|
50
52
|
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
51
53
|
import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
|
|
54
|
+
import DownloadUrlControls from '@cdc/core/components/EditorPanel/DownloadUrlControls'
|
|
55
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
56
|
+
import StyleTreatmentSection from '@cdc/core/components/EditorPanel/sections/StyleTreatmentSection'
|
|
52
57
|
import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
|
|
53
58
|
import useColumnsRequiredChecker from '../../../hooks/useColumnsRequiredChecker'
|
|
54
59
|
import { addUIDs } from '../../../helpers'
|
|
55
60
|
import generateRuntimeData from '../../../helpers/generateRuntimeData'
|
|
56
61
|
|
|
57
|
-
import '@cdc/core/
|
|
62
|
+
import '@cdc/core/components/EditorPanel/editor.scss'
|
|
58
63
|
import './editorPanel.styles.css'
|
|
59
64
|
import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
|
|
65
|
+
import CustomSortOrder from '@cdc/core/components/EditorPanel/CustomSortOrder'
|
|
60
66
|
import { Datasets } from '@cdc/core/types/DataSet'
|
|
61
67
|
import MultiSelect from '@cdc/core/components/MultiSelect'
|
|
62
68
|
import { paletteMigrationMap } from '@cdc/core/helpers/palettes/migratePaletteName'
|
|
63
69
|
import { isV1Palette, getCurrentPaletteName, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
|
|
64
|
-
import {
|
|
70
|
+
import {
|
|
71
|
+
ENABLE_CHART_MAP_TP5_TREATMENT_SELECTION,
|
|
72
|
+
ENABLE_MAP_DATA_BITE_VISUAL_SETTINGS,
|
|
73
|
+
USE_V2_MIGRATION
|
|
74
|
+
} from '@cdc/core/helpers/constants'
|
|
65
75
|
import { isCoveDeveloperMode } from '@cdc/core/helpers/queryStringUtils'
|
|
66
76
|
import { PaletteSelector, DeveloperPaletteRollback } from '@cdc/core/components/PaletteSelector'
|
|
67
77
|
import PaletteConversionModal from '@cdc/core/components/PaletteConversionModal'
|
|
@@ -71,6 +81,39 @@ type MapEditorPanelProps = {
|
|
|
71
81
|
datasets?: Datasets
|
|
72
82
|
}
|
|
73
83
|
|
|
84
|
+
type ColumnSectionProps = {
|
|
85
|
+
fieldKey: 'geo' | 'primary'
|
|
86
|
+
fieldName: string
|
|
87
|
+
show: boolean
|
|
88
|
+
setShow: (fieldKey: 'geo' | 'primary', value: boolean) => void
|
|
89
|
+
children: React.ReactNode
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const ColumnSection = ({ fieldKey, fieldName, show, setShow, children }: ColumnSectionProps) => {
|
|
93
|
+
if (!show) {
|
|
94
|
+
return (
|
|
95
|
+
<div className='mb-1'>
|
|
96
|
+
<button type='button' className='btn btn-light' onClick={() => setShow(fieldKey, true)}>
|
|
97
|
+
<Icon display='caretDown' />
|
|
98
|
+
</button>
|
|
99
|
+
<span> {fieldName}</span>
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<fieldset className='primary-fieldset edit-block column-section' key={fieldKey}>
|
|
106
|
+
<div className='column-section__header'>
|
|
107
|
+
<button type='button' className='btn btn-light' onClick={() => setShow(fieldKey, false)}>
|
|
108
|
+
<Icon display='caretUp' />
|
|
109
|
+
</button>
|
|
110
|
+
<span className='column-section__title'>{fieldName}</span>
|
|
111
|
+
</div>
|
|
112
|
+
{children}
|
|
113
|
+
</fieldset>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
74
117
|
const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
75
118
|
const {
|
|
76
119
|
setParentConfig,
|
|
@@ -114,11 +157,16 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
114
157
|
const [loadedDefault, setLoadedDefault] = useState(false)
|
|
115
158
|
const [activeFilterValueForDescription, setActiveFilterValueForDescription] = useState([0, 0])
|
|
116
159
|
const [showConversionModal, setShowConversionModal] = useState(false)
|
|
160
|
+
const [columnSectionsOpen, setColumnSectionsOpen] = useState({ geo: true, primary: true })
|
|
117
161
|
const [pendingPaletteSelection, setPendingPaletteSelection] = useState<{
|
|
118
162
|
palette: string
|
|
119
163
|
action: () => void
|
|
120
164
|
} | null>(null)
|
|
121
165
|
|
|
166
|
+
const setColumnSectionOpen = (fieldKey: 'geo' | 'primary', value: boolean) => {
|
|
167
|
+
setColumnSectionsOpen(prev => ({ ...prev, [fieldKey]: value }))
|
|
168
|
+
}
|
|
169
|
+
|
|
122
170
|
const {
|
|
123
171
|
MapLayerHandlers: { handleMapLayer, handleAddLayer, handleRemoveLayer }
|
|
124
172
|
} = useMapLayers(config, setConfig, false, tooltipId)
|
|
@@ -296,7 +344,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
296
344
|
legend: {
|
|
297
345
|
...config.legend,
|
|
298
346
|
position: value,
|
|
299
|
-
hideBorder:
|
|
347
|
+
hideBorder: includes(['top', 'bottom'], value)
|
|
300
348
|
}
|
|
301
349
|
})
|
|
302
350
|
break
|
|
@@ -518,7 +566,13 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
518
566
|
break
|
|
519
567
|
case 'geoType':
|
|
520
568
|
addUIDs(config, config.columns.geo.name)
|
|
521
|
-
dispatch({
|
|
569
|
+
dispatch({
|
|
570
|
+
type: 'SET_POSITION',
|
|
571
|
+
payload: {
|
|
572
|
+
coordinates: value === 'world' ? [0, 30] : [0, 0],
|
|
573
|
+
zoom: 1
|
|
574
|
+
}
|
|
575
|
+
})
|
|
522
576
|
|
|
523
577
|
// If we're still working with default data, switch to the world default to show it as an example
|
|
524
578
|
if (true === loadedDefault && 'world' === value) {
|
|
@@ -866,6 +920,11 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
866
920
|
}
|
|
867
921
|
}
|
|
868
922
|
|
|
923
|
+
const updateColumnOrder = (columnName, value) => {
|
|
924
|
+
const parsedValue = Number.parseInt(value, 10)
|
|
925
|
+
editColumn(columnName, 'order', Number.isNaN(parsedValue) ? undefined : parsedValue)
|
|
926
|
+
}
|
|
927
|
+
|
|
869
928
|
// just adds a new column but not set to any data yet
|
|
870
929
|
const addAdditionalColumn = number => {
|
|
871
930
|
const columnKey = `additionalColumn${number}`
|
|
@@ -931,7 +990,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
931
990
|
}
|
|
932
991
|
|
|
933
992
|
// Remove the legend
|
|
934
|
-
let strippedLegend =
|
|
993
|
+
let strippedLegend = cloneDeep(config.legend)
|
|
935
994
|
|
|
936
995
|
delete strippedLegend.disabledAmt
|
|
937
996
|
|
|
@@ -941,7 +1000,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
941
1000
|
delete strippedState.defaultData
|
|
942
1001
|
|
|
943
1002
|
// Remove tooltips if they're active in the editor
|
|
944
|
-
strippedState.general =
|
|
1003
|
+
strippedState.general = cloneDeep(config.general)
|
|
945
1004
|
|
|
946
1005
|
// Add columns property back to data if it's there
|
|
947
1006
|
if (config.columns) {
|
|
@@ -963,7 +1022,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
963
1022
|
const isV1PaletteConfig = isV1Palette(config)
|
|
964
1023
|
|
|
965
1024
|
const executeSelection = () => {
|
|
966
|
-
const _newConfig =
|
|
1025
|
+
const _newConfig = cloneDeep(config)
|
|
967
1026
|
|
|
968
1027
|
// If v2 migration is disabled, use the original palette name and keep v1 version
|
|
969
1028
|
if (!USE_V2_MIGRATION) {
|
|
@@ -1062,6 +1121,44 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1062
1121
|
|
|
1063
1122
|
const updateField = updateFieldFactory(config, setConfig)
|
|
1064
1123
|
|
|
1124
|
+
const handleStyleTreatmentChange = (value: string) => {
|
|
1125
|
+
const useTp5Treatment = value === 'tp5'
|
|
1126
|
+
|
|
1127
|
+
setConfig({
|
|
1128
|
+
...config,
|
|
1129
|
+
general: {
|
|
1130
|
+
...config.general,
|
|
1131
|
+
titleStyle: useTp5Treatment ? 'small' : 'legacy'
|
|
1132
|
+
},
|
|
1133
|
+
visual: {
|
|
1134
|
+
...config.visual,
|
|
1135
|
+
tp5Treatment: useTp5Treatment,
|
|
1136
|
+
border: useTp5Treatment ? false : config.visual?.border,
|
|
1137
|
+
borderColorTheme: useTp5Treatment ? false : config.visual?.borderColorTheme,
|
|
1138
|
+
accent: useTp5Treatment ? false : config.visual?.accent
|
|
1139
|
+
}
|
|
1140
|
+
})
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
const handleTitleStyleChange = (newTitleStyle: string) => {
|
|
1144
|
+
setConfig({
|
|
1145
|
+
...config,
|
|
1146
|
+
general: {
|
|
1147
|
+
...config.general,
|
|
1148
|
+
titleStyle: newTitleStyle
|
|
1149
|
+
},
|
|
1150
|
+
visual:
|
|
1151
|
+
newTitleStyle === 'legacy'
|
|
1152
|
+
? config.visual
|
|
1153
|
+
: {
|
|
1154
|
+
...config.visual,
|
|
1155
|
+
border: undefined,
|
|
1156
|
+
borderColorTheme: undefined,
|
|
1157
|
+
accent: undefined
|
|
1158
|
+
}
|
|
1159
|
+
})
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1065
1162
|
const StateOptionList = () => {
|
|
1066
1163
|
const arrOfArrays = Object.entries(supportedStatesFipsCodes)
|
|
1067
1164
|
|
|
@@ -1149,7 +1246,11 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1149
1246
|
))
|
|
1150
1247
|
}
|
|
1151
1248
|
|
|
1152
|
-
const isLoadedFromUrl =
|
|
1249
|
+
const isLoadedFromUrl =
|
|
1250
|
+
config?.dataFileSourceType === 'url' ||
|
|
1251
|
+
Boolean(config?.runtimeDataUrl || config?.dataUrl || config?.dataFileName) ||
|
|
1252
|
+
config?.dataKey?.includes('http://') ||
|
|
1253
|
+
config?.dataKey?.includes('https://')
|
|
1153
1254
|
|
|
1154
1255
|
// Custom convertStateToConfig for map with map-specific logic
|
|
1155
1256
|
const customConvertStateToConfig = () => {
|
|
@@ -1163,7 +1264,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1163
1264
|
}
|
|
1164
1265
|
|
|
1165
1266
|
// Remove the legend
|
|
1166
|
-
let strippedLegend =
|
|
1267
|
+
let strippedLegend = cloneDeep(config.legend)
|
|
1167
1268
|
|
|
1168
1269
|
delete strippedLegend.disabledAmt
|
|
1169
1270
|
|
|
@@ -1173,7 +1274,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1173
1274
|
delete strippedState.defaultData
|
|
1174
1275
|
|
|
1175
1276
|
// Remove tooltips if they're active in the editor
|
|
1176
|
-
strippedState.general =
|
|
1277
|
+
strippedState.general = cloneDeep(config.general)
|
|
1177
1278
|
|
|
1178
1279
|
strippedState.general.showSidebar = 'hidden'
|
|
1179
1280
|
|
|
@@ -1268,6 +1369,41 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1268
1369
|
}}
|
|
1269
1370
|
/>
|
|
1270
1371
|
)}
|
|
1372
|
+
{config.general.geoType === 'us-county' && (
|
|
1373
|
+
<>
|
|
1374
|
+
<CheckBox
|
|
1375
|
+
value={config.general.showNeighboringStates || false}
|
|
1376
|
+
fieldName='showNeighboringStates'
|
|
1377
|
+
label="Show Neighboring States' Data"
|
|
1378
|
+
updateField={updateField}
|
|
1379
|
+
section='general'
|
|
1380
|
+
/>
|
|
1381
|
+
<CheckBox
|
|
1382
|
+
value={config.general.showHSABoundaries || false}
|
|
1383
|
+
fieldName='showHSABoundaries'
|
|
1384
|
+
label='Show HSA Boundaries'
|
|
1385
|
+
updateField={updateField}
|
|
1386
|
+
section='general'
|
|
1387
|
+
tooltip={
|
|
1388
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1389
|
+
<Tooltip.Target>
|
|
1390
|
+
<Icon
|
|
1391
|
+
display='question'
|
|
1392
|
+
style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
|
|
1393
|
+
/>
|
|
1394
|
+
</Tooltip.Target>
|
|
1395
|
+
<Tooltip.Content>
|
|
1396
|
+
<p>
|
|
1397
|
+
Health Service Areas (HSAs) are a county or cluster of contiguous counties which are
|
|
1398
|
+
relatively self-contained with respect to hospital care. Set HSA description in
|
|
1399
|
+
tooltip under the Columns accordion.
|
|
1400
|
+
</p>
|
|
1401
|
+
</Tooltip.Content>
|
|
1402
|
+
</Tooltip>
|
|
1403
|
+
}
|
|
1404
|
+
/>
|
|
1405
|
+
</>
|
|
1406
|
+
)}
|
|
1271
1407
|
{(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
|
|
1272
1408
|
<Select
|
|
1273
1409
|
label='County Census Year'
|
|
@@ -1319,20 +1455,31 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1319
1455
|
{/* Type */}
|
|
1320
1456
|
{/* Select > Filter a state */}
|
|
1321
1457
|
{config.general.geoType === 'single-state' && (
|
|
1322
|
-
|
|
1323
|
-
<
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1458
|
+
<>
|
|
1459
|
+
<label>
|
|
1460
|
+
<span>States Selector</span>
|
|
1461
|
+
<MultiSelect
|
|
1462
|
+
selected={config.general.statesPicked.map(state => state.stateName)}
|
|
1463
|
+
options={StateOptionList().map(option => ({
|
|
1464
|
+
value: option.props.value,
|
|
1465
|
+
label: option.props.children
|
|
1466
|
+
}))}
|
|
1467
|
+
fieldName={'statesPicked'}
|
|
1468
|
+
updateField={(_, __, ___, selectedOptions) => {
|
|
1469
|
+
handleEditorChanges('chooseState', selectedOptions)
|
|
1470
|
+
}}
|
|
1471
|
+
/>
|
|
1472
|
+
</label>
|
|
1473
|
+
{config.general.statesPicked && config.general.statesPicked.length > 0 && (
|
|
1474
|
+
<CheckBox
|
|
1475
|
+
value={config.general.hideUnselectedStates !== false}
|
|
1476
|
+
fieldName='hideUnselectedStates'
|
|
1477
|
+
label='Hide Unselected States'
|
|
1478
|
+
updateField={updateField}
|
|
1479
|
+
section='general'
|
|
1480
|
+
/>
|
|
1481
|
+
)}
|
|
1482
|
+
</>
|
|
1336
1483
|
)}
|
|
1337
1484
|
{/* Country Selection for World Maps */}
|
|
1338
1485
|
{config.general.geoType === 'world' && (
|
|
@@ -1494,14 +1641,26 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1494
1641
|
/>
|
|
1495
1642
|
)}
|
|
1496
1643
|
|
|
1497
|
-
{'us'
|
|
1644
|
+
{['us', 'us-county'].includes(config.general.geoType) && (
|
|
1498
1645
|
<CheckBox
|
|
1499
|
-
value={general.territoriesAlwaysShow
|
|
1646
|
+
value={general.territoriesAlwaysShow ?? true}
|
|
1500
1647
|
section='general'
|
|
1501
1648
|
subsection={null}
|
|
1502
1649
|
fieldName='territoriesAlwaysShow'
|
|
1503
|
-
label='Show
|
|
1504
|
-
updateField={
|
|
1650
|
+
label='Show Available Territories'
|
|
1651
|
+
updateField={() => {
|
|
1652
|
+
setConfig({
|
|
1653
|
+
...config,
|
|
1654
|
+
general: {
|
|
1655
|
+
...config.general,
|
|
1656
|
+
territoriesAlwaysShow: !(general.territoriesAlwaysShow ?? true)
|
|
1657
|
+
},
|
|
1658
|
+
migrations: {
|
|
1659
|
+
...config.migrations,
|
|
1660
|
+
showPuertoRico: false
|
|
1661
|
+
}
|
|
1662
|
+
})
|
|
1663
|
+
}}
|
|
1505
1664
|
/>
|
|
1506
1665
|
)}
|
|
1507
1666
|
</AccordionItemPanel>
|
|
@@ -1541,12 +1700,12 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1541
1700
|
section='general'
|
|
1542
1701
|
fieldName='titleStyle'
|
|
1543
1702
|
label='Title Style'
|
|
1544
|
-
updateField={updateField}
|
|
1545
1703
|
options={[
|
|
1546
1704
|
{ value: 'small', label: 'Small (h3)' },
|
|
1547
1705
|
{ value: 'large', label: 'Large (h2)' },
|
|
1548
1706
|
{ value: 'legacy', label: 'Legacy' }
|
|
1549
1707
|
]}
|
|
1708
|
+
onChange={event => handleTitleStyleChange(event.target.value)}
|
|
1550
1709
|
tooltip={
|
|
1551
1710
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
1552
1711
|
<Tooltip.Target>
|
|
@@ -1649,6 +1808,29 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1649
1808
|
<input type="checkbox" checked={ state.general.showDownloadMediaButton } onChange={(event) => { handleEditorChanges("toggleDownloadMediaButton", event.target.checked) }} />
|
|
1650
1809
|
<span className="edit-label">Enable Media Download</span>
|
|
1651
1810
|
</label> */}
|
|
1811
|
+
<Select
|
|
1812
|
+
value={config.locale}
|
|
1813
|
+
fieldName='locale'
|
|
1814
|
+
label='Language for dates and numbers'
|
|
1815
|
+
updateField={updateField}
|
|
1816
|
+
options={[
|
|
1817
|
+
{ value: 'en-US', label: 'English (en-US)' },
|
|
1818
|
+
{ value: 'es-MX', label: 'Spanish (es-MX)' }
|
|
1819
|
+
]}
|
|
1820
|
+
tooltip={
|
|
1821
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1822
|
+
<Tooltip.Target>
|
|
1823
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1824
|
+
</Tooltip.Target>
|
|
1825
|
+
<Tooltip.Content>
|
|
1826
|
+
<p>
|
|
1827
|
+
Change the language (locale) for this visualization to alter the way dates and numbers are
|
|
1828
|
+
formatted.
|
|
1829
|
+
</p>
|
|
1830
|
+
</Tooltip.Content>
|
|
1831
|
+
</Tooltip>
|
|
1832
|
+
}
|
|
1833
|
+
/>
|
|
1652
1834
|
</AccordionItemPanel>
|
|
1653
1835
|
</AccordionItem>
|
|
1654
1836
|
<AccordionItem>
|
|
@@ -1658,7 +1840,12 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1658
1840
|
<AccordionItemButton>Columns</AccordionItemButton>
|
|
1659
1841
|
</AccordionItemHeading>
|
|
1660
1842
|
<AccordionItemPanel>
|
|
1661
|
-
<
|
|
1843
|
+
<ColumnSection
|
|
1844
|
+
fieldKey='geo'
|
|
1845
|
+
fieldName='Geography'
|
|
1846
|
+
show={columnSectionsOpen.geo}
|
|
1847
|
+
setShow={setColumnSectionOpen}
|
|
1848
|
+
>
|
|
1662
1849
|
<label>
|
|
1663
1850
|
<span className='edit-label column-heading'>
|
|
1664
1851
|
Geography
|
|
@@ -1701,6 +1888,24 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1701
1888
|
label='Hide Geography Column Name in Tooltip'
|
|
1702
1889
|
updateField={updateField}
|
|
1703
1890
|
/>
|
|
1891
|
+
<TextField
|
|
1892
|
+
value={columns.geo.label}
|
|
1893
|
+
section='columns'
|
|
1894
|
+
subsection='geo'
|
|
1895
|
+
fieldName='label'
|
|
1896
|
+
label='Geography Column Label'
|
|
1897
|
+
updateField={updateField}
|
|
1898
|
+
tooltip={
|
|
1899
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1900
|
+
<Tooltip.Target>
|
|
1901
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1902
|
+
</Tooltip.Target>
|
|
1903
|
+
<Tooltip.Content>
|
|
1904
|
+
<p>Enter a label for the geography column in tooltips and the data table.</p>
|
|
1905
|
+
</Tooltip.Content>
|
|
1906
|
+
</Tooltip>
|
|
1907
|
+
}
|
|
1908
|
+
/>
|
|
1704
1909
|
<TextField
|
|
1705
1910
|
value={config.general.geoLabelOverride}
|
|
1706
1911
|
section='general'
|
|
@@ -1719,9 +1924,86 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1719
1924
|
</Tooltip>
|
|
1720
1925
|
}
|
|
1721
1926
|
/>
|
|
1722
|
-
|
|
1927
|
+
<label className='mt-2'>
|
|
1928
|
+
<span className='edit-label column-heading'>
|
|
1929
|
+
Geography Display Column
|
|
1930
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1931
|
+
<Tooltip.Target>
|
|
1932
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1933
|
+
</Tooltip.Target>
|
|
1934
|
+
<Tooltip.Content>
|
|
1935
|
+
<p>
|
|
1936
|
+
Optional. Select a column containing alternate display names for geographies (e.g.,
|
|
1937
|
+
translated names). These will be shown in tooltips, the data table, and navigation menus
|
|
1938
|
+
instead of the geography column values.
|
|
1939
|
+
</p>
|
|
1940
|
+
</Tooltip.Content>
|
|
1941
|
+
</Tooltip>
|
|
1942
|
+
</span>
|
|
1943
|
+
<Select
|
|
1944
|
+
value={config.columns.geo?.displayColumn || ''}
|
|
1945
|
+
options={columnsOptions.map(c => c.key)}
|
|
1946
|
+
onChange={event => {
|
|
1947
|
+
editColumn('geo', 'displayColumn', event.target.value)
|
|
1948
|
+
}}
|
|
1949
|
+
/>
|
|
1950
|
+
</label>
|
|
1951
|
+
<CheckBox
|
|
1952
|
+
value={config.columns.geo?.dataTable || false}
|
|
1953
|
+
section='columns'
|
|
1954
|
+
subsection='geo'
|
|
1955
|
+
fieldName='dataTable'
|
|
1956
|
+
label='Show in Data Table'
|
|
1957
|
+
updateField={updateField}
|
|
1958
|
+
/>
|
|
1959
|
+
<CheckBox
|
|
1960
|
+
value={config.columns.geo?.tooltip || false}
|
|
1961
|
+
section='columns'
|
|
1962
|
+
subsection='geo'
|
|
1963
|
+
fieldName='tooltip'
|
|
1964
|
+
label='Show in Tooltips'
|
|
1965
|
+
updateField={updateField}
|
|
1966
|
+
/>
|
|
1967
|
+
<label className='mt-2'>
|
|
1968
|
+
<span className='edit-label column-heading'>Order</span>
|
|
1969
|
+
<input
|
|
1970
|
+
onWheel={e => e.currentTarget.blur()}
|
|
1971
|
+
type='number'
|
|
1972
|
+
min='1'
|
|
1973
|
+
value={config.columns.geo?.order ?? ''}
|
|
1974
|
+
onChange={event => {
|
|
1975
|
+
updateColumnOrder('geo', event.target.value)
|
|
1976
|
+
}}
|
|
1977
|
+
/>
|
|
1978
|
+
</label>
|
|
1979
|
+
</ColumnSection>
|
|
1980
|
+
{config.general.geoType === 'us-county' && config.general.showHSABoundaries && (
|
|
1981
|
+
<Select
|
|
1982
|
+
label='HSA Description Column'
|
|
1983
|
+
value={config.columns.hsa?.name}
|
|
1984
|
+
options={columnsOptions.map(c => c.key)}
|
|
1985
|
+
onChange={e => {
|
|
1986
|
+
editColumn('hsa', 'name', e.target.value)
|
|
1987
|
+
}}
|
|
1988
|
+
tooltip={
|
|
1989
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1990
|
+
<Tooltip.Target>
|
|
1991
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
1992
|
+
</Tooltip.Target>
|
|
1993
|
+
<Tooltip.Content>
|
|
1994
|
+
<p>Select the source column containing the HSA description.</p>
|
|
1995
|
+
</Tooltip.Content>
|
|
1996
|
+
</Tooltip>
|
|
1997
|
+
}
|
|
1998
|
+
/>
|
|
1999
|
+
)}
|
|
1723
2000
|
{'navigation' !== config.general.type && (
|
|
1724
|
-
<
|
|
2001
|
+
<ColumnSection
|
|
2002
|
+
fieldKey='primary'
|
|
2003
|
+
fieldName='Data'
|
|
2004
|
+
show={columnSectionsOpen.primary}
|
|
2005
|
+
setShow={setColumnSectionOpen}
|
|
2006
|
+
>
|
|
1725
2007
|
<Select
|
|
1726
2008
|
label='Data Column'
|
|
1727
2009
|
value={columns.primary.name}
|
|
@@ -1829,8 +2111,20 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1829
2111
|
label='Show in Tooltips'
|
|
1830
2112
|
updateField={updateField}
|
|
1831
2113
|
/>
|
|
2114
|
+
<label>
|
|
2115
|
+
<span className='edit-label column-heading'>Order</span>
|
|
2116
|
+
<input
|
|
2117
|
+
onWheel={e => e.currentTarget.blur()}
|
|
2118
|
+
type='number'
|
|
2119
|
+
min='1'
|
|
2120
|
+
value={config.columns.primary?.order ?? ''}
|
|
2121
|
+
onChange={event => {
|
|
2122
|
+
updateColumnOrder('primary', event.target.value)
|
|
2123
|
+
}}
|
|
2124
|
+
/>
|
|
2125
|
+
</label>
|
|
1832
2126
|
</ul>
|
|
1833
|
-
</
|
|
2127
|
+
</ColumnSection>
|
|
1834
2128
|
)}
|
|
1835
2129
|
|
|
1836
2130
|
{config.general.type === 'bubble' && config.legend.type === 'category' && (
|
|
@@ -1881,105 +2175,6 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
1881
2175
|
</>
|
|
1882
2176
|
}
|
|
1883
2177
|
|
|
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
|
-
}}
|
|
1935
|
-
/>
|
|
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
|
-
}}
|
|
1952
|
-
/>
|
|
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>
|
|
1967
|
-
</div>
|
|
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
2178
|
<label className='edit-block navigate column-heading'>
|
|
1984
2179
|
<span className='edit-label column-heading'>
|
|
1985
2180
|
Navigation
|
|
@@ -2007,123 +2202,261 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2007
2202
|
<fieldset className='primary-fieldset edit-block'>
|
|
2008
2203
|
<label>
|
|
2009
2204
|
<span className='edit-label'>
|
|
2010
|
-
|
|
2205
|
+
Special Classes
|
|
2011
2206
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
2012
2207
|
<Tooltip.Target>
|
|
2013
2208
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2014
2209
|
</Tooltip.Target>
|
|
2015
2210
|
<Tooltip.Content>
|
|
2016
2211
|
<p>
|
|
2017
|
-
|
|
2018
|
-
|
|
2212
|
+
For secondary values such as "NA", the system can automatically color-code them in
|
|
2213
|
+
shades of gray, one shade for each special class.
|
|
2019
2214
|
</p>
|
|
2020
2215
|
</Tooltip.Content>
|
|
2021
2216
|
</Tooltip>
|
|
2022
2217
|
</span>
|
|
2023
2218
|
</label>
|
|
2024
|
-
{
|
|
2025
|
-
<
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2219
|
+
{config.legend.specialClasses.length === 2 && (
|
|
2220
|
+
<Alert
|
|
2221
|
+
type='info'
|
|
2222
|
+
message='If a third special class is needed you can apply a pattern to set it apart.'
|
|
2223
|
+
showCloseButton={false}
|
|
2224
|
+
/>
|
|
2225
|
+
)}
|
|
2226
|
+
<GroupedList
|
|
2227
|
+
items={specialClasses}
|
|
2228
|
+
label='Special Classes'
|
|
2229
|
+
droppableId='map-special-classes'
|
|
2230
|
+
draggable={false}
|
|
2231
|
+
renderItem={(specialClass, i) => (
|
|
2232
|
+
<Accordion allowZeroExpanded key={`special-class-${i}`}>
|
|
2233
|
+
<AccordionItem className='series-item series-item--chart'>
|
|
2234
|
+
<AccordionItemHeading className='series-item__title'>
|
|
2235
|
+
<AccordionItemButton className='accordion__button'>
|
|
2236
|
+
{specialClass.label || specialClass.value || `Special Class ${i + 1}`}
|
|
2237
|
+
</AccordionItemButton>
|
|
2238
|
+
</AccordionItemHeading>
|
|
2239
|
+
<AccordionItemPanel>
|
|
2240
|
+
<div className='series-item__panel-actions'>
|
|
2241
|
+
<Button
|
|
2242
|
+
type='button'
|
|
2243
|
+
variant='danger'
|
|
2244
|
+
size='sm'
|
|
2245
|
+
className='grouped-list__remove'
|
|
2246
|
+
onClick={() => editColumn('primary', 'specialClassDelete', i)}
|
|
2247
|
+
>
|
|
2248
|
+
Remove
|
|
2249
|
+
</Button>
|
|
2250
|
+
</div>
|
|
2251
|
+
<Select
|
|
2252
|
+
label='Data Key'
|
|
2253
|
+
value={specialClass.key}
|
|
2254
|
+
options={columnsOptions.map(option => ({
|
|
2255
|
+
value: option.key,
|
|
2256
|
+
label: option.key
|
|
2257
|
+
}))}
|
|
2258
|
+
onChange={event => {
|
|
2259
|
+
editColumn('primary', 'specialClassEdit', {
|
|
2260
|
+
prop: 'key',
|
|
2261
|
+
index: i,
|
|
2262
|
+
value: event.target.value
|
|
2263
|
+
})
|
|
2264
|
+
}}
|
|
2265
|
+
/>
|
|
2266
|
+
<Select
|
|
2267
|
+
label='Value'
|
|
2268
|
+
value={specialClass.value}
|
|
2269
|
+
options={[
|
|
2270
|
+
{ value: '', label: '- Select Value -' },
|
|
2271
|
+
...(columnsByKey[specialClass.key] || [])
|
|
2272
|
+
.sort()
|
|
2273
|
+
.map(option => ({ value: option, label: option }))
|
|
2274
|
+
]}
|
|
2275
|
+
onChange={event => {
|
|
2276
|
+
editColumn('primary', 'specialClassEdit', {
|
|
2277
|
+
prop: 'value',
|
|
2278
|
+
index: i,
|
|
2279
|
+
value: event.target.value
|
|
2280
|
+
})
|
|
2281
|
+
}}
|
|
2282
|
+
/>
|
|
2283
|
+
<label>
|
|
2284
|
+
<span className='edit-label column-heading'>Label</span>
|
|
2285
|
+
<input
|
|
2286
|
+
type='text'
|
|
2287
|
+
value={specialClass.label}
|
|
2288
|
+
onChange={e => {
|
|
2289
|
+
editColumn('primary', 'specialClassEdit', {
|
|
2290
|
+
prop: 'label',
|
|
2291
|
+
index: i,
|
|
2292
|
+
value: e.target.value
|
|
2293
|
+
})
|
|
2294
|
+
}}
|
|
2295
|
+
/>
|
|
2296
|
+
</label>
|
|
2297
|
+
</AccordionItemPanel>
|
|
2298
|
+
</AccordionItem>
|
|
2299
|
+
</Accordion>
|
|
2300
|
+
)}
|
|
2301
|
+
/>
|
|
2302
|
+
{config.legend.specialClasses.length < 2 && (
|
|
2303
|
+
<Button
|
|
2304
|
+
type='button'
|
|
2305
|
+
variant='editor-primary'
|
|
2306
|
+
onClick={() => editColumn('primary', 'specialClassAdd', {})}
|
|
2307
|
+
>
|
|
2308
|
+
Add Special Class
|
|
2309
|
+
</Button>
|
|
2310
|
+
)}
|
|
2311
|
+
</fieldset>
|
|
2312
|
+
)}
|
|
2313
|
+
{'navigation' !== config.general.type && (
|
|
2314
|
+
<fieldset className='primary-fieldset edit-block'>
|
|
2315
|
+
<GroupedList
|
|
2316
|
+
items={additionalColumns}
|
|
2317
|
+
label={
|
|
2318
|
+
<>
|
|
2319
|
+
Additional Columns
|
|
2320
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2321
|
+
<Tooltip.Target>
|
|
2322
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2323
|
+
</Tooltip.Target>
|
|
2324
|
+
<Tooltip.Content>
|
|
2325
|
+
<p>
|
|
2326
|
+
You can specify additional columns to display in tooltips and / or the supporting
|
|
2327
|
+
data table.
|
|
2328
|
+
</p>
|
|
2329
|
+
</Tooltip.Content>
|
|
2330
|
+
</Tooltip>
|
|
2331
|
+
</>
|
|
2332
|
+
}
|
|
2333
|
+
droppableId='map-additional-columns'
|
|
2334
|
+
draggable={false}
|
|
2335
|
+
renderItem={val => (
|
|
2336
|
+
<Accordion allowZeroExpanded key={val}>
|
|
2337
|
+
<AccordionItem className='series-item series-item--chart'>
|
|
2338
|
+
<AccordionItemHeading className='series-item__title'>
|
|
2339
|
+
<AccordionItemButton className='accordion__button'>
|
|
2340
|
+
{columns[val]?.label || config.columns[val]?.name || 'New Column'}
|
|
2341
|
+
</AccordionItemButton>
|
|
2342
|
+
</AccordionItemHeading>
|
|
2343
|
+
<AccordionItemPanel>
|
|
2344
|
+
<div className='series-item__panel-actions'>
|
|
2345
|
+
<Button
|
|
2346
|
+
type='button'
|
|
2347
|
+
variant='danger'
|
|
2348
|
+
size='sm'
|
|
2349
|
+
className='grouped-list__remove'
|
|
2350
|
+
onClick={() => removeAdditionalColumn(val)}
|
|
2351
|
+
>
|
|
2352
|
+
Remove
|
|
2353
|
+
</Button>
|
|
2354
|
+
</div>
|
|
2355
|
+
<Select
|
|
2356
|
+
label='Column'
|
|
2357
|
+
value={config.columns[val] ? config.columns[val].name : ''}
|
|
2358
|
+
options={columnsOptions.map(option => ({
|
|
2359
|
+
value: option.props.value,
|
|
2360
|
+
label: option.props.children
|
|
2361
|
+
}))}
|
|
2362
|
+
onChange={event => {
|
|
2363
|
+
editColumn(val, 'name', event.target.value)
|
|
2364
|
+
}}
|
|
2365
|
+
/>
|
|
2366
|
+
<TextField
|
|
2367
|
+
value={columns[val].label}
|
|
2368
|
+
section='columns'
|
|
2369
|
+
subsection={val}
|
|
2370
|
+
fieldName='label'
|
|
2371
|
+
label='Label'
|
|
2372
|
+
updateField={updateField}
|
|
2373
|
+
/>
|
|
2374
|
+
<ul className='column-edit'>
|
|
2375
|
+
<li className='three-col'>
|
|
2376
|
+
<TextField
|
|
2377
|
+
value={columns[val].prefix}
|
|
2378
|
+
section='columns'
|
|
2379
|
+
subsection={val}
|
|
2380
|
+
fieldName='prefix'
|
|
2381
|
+
label='Prefix'
|
|
2382
|
+
updateField={updateField}
|
|
2383
|
+
/>
|
|
2384
|
+
<TextField
|
|
2385
|
+
value={columns[val].suffix}
|
|
2386
|
+
section='columns'
|
|
2387
|
+
subsection={val}
|
|
2388
|
+
fieldName='suffix'
|
|
2389
|
+
label='Suffix'
|
|
2390
|
+
updateField={updateField}
|
|
2391
|
+
/>
|
|
2392
|
+
<TextField
|
|
2393
|
+
type='number'
|
|
2394
|
+
value={columns[val].roundToPlace}
|
|
2395
|
+
section='columns'
|
|
2396
|
+
subsection={val}
|
|
2397
|
+
fieldName='roundToPlace'
|
|
2398
|
+
label='Round'
|
|
2399
|
+
updateField={updateField}
|
|
2400
|
+
/>
|
|
2401
|
+
</li>
|
|
2402
|
+
<CheckBox
|
|
2403
|
+
value={config.columns[val].useCommas}
|
|
2404
|
+
section='columns'
|
|
2405
|
+
subsection={val}
|
|
2406
|
+
fieldName='useCommas'
|
|
2407
|
+
label='Add Commas to Numbers'
|
|
2408
|
+
updateField={updateField}
|
|
2409
|
+
onChange={event => {
|
|
2410
|
+
editColumn(val, 'useCommas', event.target.checked)
|
|
2411
|
+
}}
|
|
2412
|
+
/>
|
|
2413
|
+
<CheckBox
|
|
2414
|
+
value={config.columns[val].dataTable}
|
|
2415
|
+
section='columns'
|
|
2416
|
+
subsection={val}
|
|
2417
|
+
fieldName='dataTable'
|
|
2418
|
+
label='Show in Data Table'
|
|
2419
|
+
updateField={updateField}
|
|
2420
|
+
onChange={event => {
|
|
2421
|
+
editColumn(val, 'dataTable', event.target.checked)
|
|
2422
|
+
}}
|
|
2423
|
+
/>
|
|
2424
|
+
<CheckBox
|
|
2425
|
+
value={config.columns[val].tooltip}
|
|
2426
|
+
section='columns'
|
|
2427
|
+
subsection={val}
|
|
2428
|
+
fieldName='tooltip'
|
|
2429
|
+
label='Show in Tooltips'
|
|
2430
|
+
updateField={updateField}
|
|
2431
|
+
onChange={event => {
|
|
2432
|
+
editColumn(val, 'tooltip', event.target.checked)
|
|
2433
|
+
}}
|
|
2434
|
+
/>
|
|
2435
|
+
<label>
|
|
2436
|
+
<span className='edit-label column-heading'>Order</span>
|
|
2437
|
+
<input
|
|
2438
|
+
onWheel={e => e.currentTarget.blur()}
|
|
2439
|
+
type='number'
|
|
2440
|
+
min='1'
|
|
2441
|
+
value={config.columns[val]?.order ?? ''}
|
|
2442
|
+
onChange={event => {
|
|
2443
|
+
updateColumnOrder(val, event.target.value)
|
|
2444
|
+
}}
|
|
2445
|
+
/>
|
|
2446
|
+
</label>
|
|
2447
|
+
</ul>
|
|
2448
|
+
</AccordionItemPanel>
|
|
2449
|
+
</AccordionItem>
|
|
2450
|
+
</Accordion>
|
|
2451
|
+
)}
|
|
2452
|
+
/>
|
|
2453
|
+
<Button
|
|
2454
|
+
type='button'
|
|
2455
|
+
variant='editor-primary'
|
|
2456
|
+
onClick={() => addAdditionalColumn(additionalColumns.length + 1)}
|
|
2124
2457
|
>
|
|
2125
2458
|
Add Column
|
|
2126
|
-
</
|
|
2459
|
+
</Button>
|
|
2127
2460
|
</fieldset>
|
|
2128
2461
|
)}
|
|
2129
2462
|
{'category' === config.legend.type && (
|
|
@@ -2171,8 +2504,8 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2171
2504
|
</label>
|
|
2172
2505
|
</fieldset>
|
|
2173
2506
|
))}
|
|
2174
|
-
<
|
|
2175
|
-
className={'btn btn-primary full-width'}
|
|
2507
|
+
<Button
|
|
2508
|
+
className={'btn btn-primary full-width editor-panel-action-button'}
|
|
2176
2509
|
onClick={event => {
|
|
2177
2510
|
event.preventDefault()
|
|
2178
2511
|
const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
|
|
@@ -2181,7 +2514,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2181
2514
|
}}
|
|
2182
2515
|
>
|
|
2183
2516
|
Add Category
|
|
2184
|
-
</
|
|
2517
|
+
</Button>
|
|
2185
2518
|
</fieldset>
|
|
2186
2519
|
)}
|
|
2187
2520
|
</AccordionItemPanel>
|
|
@@ -2679,6 +3012,15 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2679
3012
|
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2680
3013
|
</AccordionItemHeading>
|
|
2681
3014
|
<AccordionItemPanel>
|
|
3015
|
+
{config.general.geoType === 'us-county' && (
|
|
3016
|
+
<CheckBox
|
|
3017
|
+
value={config.general.showStateDropdown || false}
|
|
3018
|
+
fieldName='showStateDropdown'
|
|
3019
|
+
label='Show State Dropdown'
|
|
3020
|
+
updateField={updateField}
|
|
3021
|
+
section='general'
|
|
3022
|
+
/>
|
|
3023
|
+
)}
|
|
2682
3024
|
<VizFilterEditor
|
|
2683
3025
|
config={config}
|
|
2684
3026
|
updateField={updateField}
|
|
@@ -2878,6 +3220,78 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2878
3220
|
label='Show collapse below table'
|
|
2879
3221
|
updateField={updateField}
|
|
2880
3222
|
/>
|
|
3223
|
+
<Select
|
|
3224
|
+
value={config.table.defaultSort?.column || ''}
|
|
3225
|
+
fieldName='column'
|
|
3226
|
+
section='table'
|
|
3227
|
+
subsection='defaultSort'
|
|
3228
|
+
label='Default Sort Column'
|
|
3229
|
+
initial='-Select-'
|
|
3230
|
+
options={Object.keys(config.columns)
|
|
3231
|
+
.filter(key => config.columns[key].dataTable !== false && config.columns[key].name)
|
|
3232
|
+
.map(key => ({
|
|
3233
|
+
label: config.columns[key].label || config.columns[key].name || key,
|
|
3234
|
+
value: key
|
|
3235
|
+
}))}
|
|
3236
|
+
updateField={(_section, _subSection, _fieldName, value) => {
|
|
3237
|
+
if (value === '' || value === '-Select-') {
|
|
3238
|
+
updateField('table', null, 'defaultSort', {})
|
|
3239
|
+
} else {
|
|
3240
|
+
updateField('table', null, 'defaultSort', { column: value, sortDirection: 'asc' })
|
|
3241
|
+
}
|
|
3242
|
+
}}
|
|
3243
|
+
tooltip={
|
|
3244
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
3245
|
+
<Tooltip.Target>
|
|
3246
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
3247
|
+
</Tooltip.Target>
|
|
3248
|
+
<Tooltip.Content>
|
|
3249
|
+
<p>Choose a column to sort the data table by when it first loads.</p>
|
|
3250
|
+
</Tooltip.Content>
|
|
3251
|
+
</Tooltip>
|
|
3252
|
+
}
|
|
3253
|
+
/>
|
|
3254
|
+
{config.table.defaultSort?.column && (
|
|
3255
|
+
<Select
|
|
3256
|
+
value={config.table.defaultSort?.sortDirection || 'asc'}
|
|
3257
|
+
fieldName='sortDirection'
|
|
3258
|
+
section='table'
|
|
3259
|
+
subsection='defaultSort'
|
|
3260
|
+
label='Sort Direction'
|
|
3261
|
+
options={[
|
|
3262
|
+
{ label: 'Ascending', value: 'asc' },
|
|
3263
|
+
{ label: 'Descending', value: 'desc' },
|
|
3264
|
+
{ label: 'Custom', value: 'custom' }
|
|
3265
|
+
]}
|
|
3266
|
+
updateField={(_section, _subSection, _fieldName, value) => {
|
|
3267
|
+
const newDefaultSort = { ...config.table.defaultSort, sortDirection: value }
|
|
3268
|
+
if (value !== 'custom') {
|
|
3269
|
+
delete newDefaultSort.customOrder
|
|
3270
|
+
} else if (!newDefaultSort.customOrder?.length) {
|
|
3271
|
+
// Auto-populate customOrder with unique values so the table updates immediately
|
|
3272
|
+
const col = newDefaultSort.column
|
|
3273
|
+
const dataCol = config.columns?.[col]?.name || col
|
|
3274
|
+
if (dataCol && config.data?.length) {
|
|
3275
|
+
newDefaultSort.customOrder = Array.from(
|
|
3276
|
+
new Set(config.data.map(row => String(row[dataCol] ?? '')).filter(v => v !== ''))
|
|
3277
|
+
)
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
updateField('table', null, 'defaultSort', newDefaultSort)
|
|
3281
|
+
}}
|
|
3282
|
+
/>
|
|
3283
|
+
)}
|
|
3284
|
+
{config.table.defaultSort?.column && config.table.defaultSort?.sortDirection === 'custom' && (
|
|
3285
|
+
<CustomSortOrder
|
|
3286
|
+
column={
|
|
3287
|
+
config.columns[config.table.defaultSort.column]?.name || config.table.defaultSort.column
|
|
3288
|
+
}
|
|
3289
|
+
data={config.data}
|
|
3290
|
+
customOrder={config.table.defaultSort.customOrder}
|
|
3291
|
+
updateField={updateField}
|
|
3292
|
+
displayTransform={config.table.defaultSort.column === 'geo' ? displayGeoName : undefined}
|
|
3293
|
+
/>
|
|
3294
|
+
)}
|
|
2881
3295
|
<CheckBox
|
|
2882
3296
|
value={config.table.download}
|
|
2883
3297
|
fieldName='download'
|
|
@@ -2907,6 +3321,16 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2907
3321
|
section='table'
|
|
2908
3322
|
updateField={updateField}
|
|
2909
3323
|
/>
|
|
3324
|
+
<div className='ms-4 mt-2' style={{ maxWidth: 'calc(100% - 1.5rem)' }}>
|
|
3325
|
+
<TextField
|
|
3326
|
+
value={config.table.downloadDataLabel}
|
|
3327
|
+
section='table'
|
|
3328
|
+
fieldName='downloadDataLabel'
|
|
3329
|
+
label='Download Data Link Text'
|
|
3330
|
+
placeholder='Download Data (CSV)'
|
|
3331
|
+
updateField={updateField}
|
|
3332
|
+
/>
|
|
3333
|
+
</div>
|
|
2910
3334
|
</>
|
|
2911
3335
|
)}
|
|
2912
3336
|
{isDashboard && (
|
|
@@ -2919,16 +3343,12 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2919
3343
|
updateField={updateField}
|
|
2920
3344
|
/>
|
|
2921
3345
|
)}
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
label='Show URL to Automatically Updated Data'
|
|
2929
|
-
updateField={updateField}
|
|
2930
|
-
/>
|
|
2931
|
-
)}
|
|
3346
|
+
<DownloadUrlControls
|
|
3347
|
+
hasUrlBackedDataSource={Boolean(isLoadedFromUrl)}
|
|
3348
|
+
showDownloadUrl={config.table.showDownloadUrl}
|
|
3349
|
+
downloadUrlLabel={config.table.downloadUrlLabel}
|
|
3350
|
+
updateField={updateField}
|
|
3351
|
+
/>
|
|
2932
3352
|
<CheckBox
|
|
2933
3353
|
value={config.table.showFullGeoNameInCSV}
|
|
2934
3354
|
section='table'
|
|
@@ -2952,28 +3372,40 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
2952
3372
|
}}
|
|
2953
3373
|
/>
|
|
2954
3374
|
{config.general.showDownloadImgButton && (
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
<Tooltip
|
|
2966
|
-
<
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
<
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
3375
|
+
<>
|
|
3376
|
+
<CheckBox
|
|
3377
|
+
value={config.general.includeContextInDownload}
|
|
3378
|
+
section='general'
|
|
3379
|
+
subsection={null}
|
|
3380
|
+
className='ms-4'
|
|
3381
|
+
fieldName='includeContextInDownload'
|
|
3382
|
+
label='Include Heading & Context'
|
|
3383
|
+
updateField={updateField}
|
|
3384
|
+
tooltip={
|
|
3385
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
3386
|
+
<Tooltip.Target>
|
|
3387
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
3388
|
+
</Tooltip.Target>
|
|
3389
|
+
<Tooltip.Content>
|
|
3390
|
+
<p>
|
|
3391
|
+
When enabled, the image download will include the section heading (H2 or H3) and any
|
|
3392
|
+
explanatory paragraphs that appear before the visualization
|
|
3393
|
+
</p>
|
|
3394
|
+
</Tooltip.Content>
|
|
3395
|
+
</Tooltip>
|
|
3396
|
+
}
|
|
3397
|
+
/>
|
|
3398
|
+
<div className='ms-4 mt-2' style={{ maxWidth: 'calc(100% - 1.5rem)' }}>
|
|
3399
|
+
<TextField
|
|
3400
|
+
value={config.table.downloadImageLabel}
|
|
3401
|
+
section='table'
|
|
3402
|
+
fieldName='downloadImageLabel'
|
|
3403
|
+
label='Download Image Link Text'
|
|
3404
|
+
placeholder='Download Map (PNG)'
|
|
3405
|
+
updateField={updateField}
|
|
3406
|
+
/>
|
|
3407
|
+
</div>
|
|
3408
|
+
</>
|
|
2977
3409
|
)}
|
|
2978
3410
|
|
|
2979
3411
|
{/* <label className='checkbox'>
|
|
@@ -3031,6 +3463,14 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3031
3463
|
updateField={updateField}
|
|
3032
3464
|
/>
|
|
3033
3465
|
)}
|
|
3466
|
+
<TextField
|
|
3467
|
+
value={tooltips.noDataLabel}
|
|
3468
|
+
section='tooltips'
|
|
3469
|
+
fieldName='noDataLabel'
|
|
3470
|
+
label='No Data Tooltip Text'
|
|
3471
|
+
placeholder='No Data'
|
|
3472
|
+
updateField={updateField}
|
|
3473
|
+
/>
|
|
3034
3474
|
</AccordionItemPanel>
|
|
3035
3475
|
</AccordionItem>
|
|
3036
3476
|
<AccordionItem>
|
|
@@ -3045,6 +3485,19 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3045
3485
|
onThemeSelect={palette => handleEditorChanges('headerColor', palette)}
|
|
3046
3486
|
label='Header Theme'
|
|
3047
3487
|
/>
|
|
3488
|
+
{ENABLE_MAP_DATA_BITE_VISUAL_SETTINGS && (
|
|
3489
|
+
<StyleTreatmentSection
|
|
3490
|
+
styleTreatment={
|
|
3491
|
+
config.general.titleStyle === 'legacy' && !config.visual?.tp5Treatment ? 'legacy' : 'tp5'
|
|
3492
|
+
}
|
|
3493
|
+
onStyleTreatmentChange={handleStyleTreatmentChange}
|
|
3494
|
+
showStyleTreatment={ENABLE_CHART_MAP_TP5_TREATMENT_SELECTION}
|
|
3495
|
+
border={config.visual?.border}
|
|
3496
|
+
borderColorTheme={config.visual?.borderColorTheme}
|
|
3497
|
+
accent={config.visual?.accent}
|
|
3498
|
+
updateField={updateField}
|
|
3499
|
+
/>
|
|
3500
|
+
)}
|
|
3048
3501
|
<CheckBox
|
|
3049
3502
|
value={config.general.showTitle || false}
|
|
3050
3503
|
section='general'
|
|
@@ -3276,7 +3729,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3276
3729
|
type='checkbox'
|
|
3277
3730
|
checked={config.visual.showBubbleZeros}
|
|
3278
3731
|
onChange={event => {
|
|
3279
|
-
const _newConfig =
|
|
3732
|
+
const _newConfig = cloneDeep(config)
|
|
3280
3733
|
_newConfig.visual.showBubbleZeros = event.target.checked
|
|
3281
3734
|
setConfig(_newConfig)
|
|
3282
3735
|
}}
|
|
@@ -3284,7 +3737,9 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3284
3737
|
<span className='edit-label'>Show Data with Zero's on Bubble Map</span>
|
|
3285
3738
|
</label>
|
|
3286
3739
|
)}
|
|
3287
|
-
{(config.general.geoType === 'world' ||
|
|
3740
|
+
{(config.general.geoType === 'world' ||
|
|
3741
|
+
config.general.geoType === 'single-state' ||
|
|
3742
|
+
config.general.geoType === 'us-county') && (
|
|
3288
3743
|
<label className='checkbox'>
|
|
3289
3744
|
<input
|
|
3290
3745
|
type='checkbox'
|
|
@@ -3354,73 +3809,84 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3354
3809
|
)}
|
|
3355
3810
|
{/* <AdditionalCityStyles /> */}
|
|
3356
3811
|
<>
|
|
3357
|
-
|
|
3358
|
-
config.visual.additionalCityStyles
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
</
|
|
3370
|
-
<
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3812
|
+
<GroupedList
|
|
3813
|
+
items={config.visual.additionalCityStyles}
|
|
3814
|
+
label='Additional City Styles'
|
|
3815
|
+
droppableId='map-city-styles'
|
|
3816
|
+
draggable={false}
|
|
3817
|
+
renderItem={({ label, column, value, shape }, i) => (
|
|
3818
|
+
<Accordion allowZeroExpanded key={`additional-city-style-${i}`}>
|
|
3819
|
+
<AccordionItem className='series-item series-item--chart'>
|
|
3820
|
+
<AccordionItemHeading className='series-item__title'>
|
|
3821
|
+
<AccordionItemButton className='accordion__button'>
|
|
3822
|
+
{label || column || `City Style ${i + 1}`}
|
|
3823
|
+
</AccordionItemButton>
|
|
3824
|
+
</AccordionItemHeading>
|
|
3825
|
+
<AccordionItemPanel>
|
|
3826
|
+
<div className='series-item__panel-actions'>
|
|
3827
|
+
<Button
|
|
3828
|
+
type='button'
|
|
3829
|
+
variant='danger'
|
|
3830
|
+
size='sm'
|
|
3831
|
+
className='grouped-list__remove'
|
|
3832
|
+
onClick={() => editCityStyles('remove', i, '', '')}
|
|
3833
|
+
>
|
|
3834
|
+
Remove
|
|
3835
|
+
</Button>
|
|
3836
|
+
</div>
|
|
3837
|
+
<Select
|
|
3838
|
+
label='Column with configuration value'
|
|
3839
|
+
value={column}
|
|
3840
|
+
options={columnsOptions.map(c => c.key)}
|
|
3384
3841
|
onChange={e => {
|
|
3385
|
-
editCityStyles('update', i, '
|
|
3842
|
+
editCityStyles('update', i, 'column', e.target.value)
|
|
3386
3843
|
}}
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3844
|
+
/>
|
|
3845
|
+
<label>
|
|
3846
|
+
<span className='edit-label column-heading'>Value to Trigger</span>
|
|
3847
|
+
<input
|
|
3848
|
+
type='text'
|
|
3849
|
+
value={value}
|
|
3850
|
+
onChange={e => {
|
|
3851
|
+
editCityStyles('update', i, 'value', e.target.value)
|
|
3852
|
+
}}
|
|
3853
|
+
/>
|
|
3854
|
+
</label>
|
|
3855
|
+
<Select
|
|
3856
|
+
label='Shape'
|
|
3857
|
+
value={shape}
|
|
3858
|
+
options={[
|
|
3859
|
+
{ value: '', label: '- Select Option -' },
|
|
3860
|
+
...['Circle', 'Square', 'Triangle', 'Diamond', 'Star', 'Pin']
|
|
3861
|
+
.filter(
|
|
3862
|
+
val => String(config.visual.cityStyle).toLowerCase() !== val.toLowerCase()
|
|
3863
|
+
)
|
|
3864
|
+
.map(val => ({ value: val, label: val }))
|
|
3865
|
+
]}
|
|
3408
3866
|
onChange={e => {
|
|
3409
|
-
editCityStyles('update', i, '
|
|
3867
|
+
editCityStyles('update', i, 'shape', e.target.value)
|
|
3410
3868
|
}}
|
|
3411
3869
|
/>
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3870
|
+
<label>
|
|
3871
|
+
<span className='edit-label column-heading'>Label</span>
|
|
3872
|
+
<input
|
|
3873
|
+
key={i}
|
|
3874
|
+
type='text'
|
|
3875
|
+
value={label}
|
|
3876
|
+
onChange={e => {
|
|
3877
|
+
editCityStyles('update', i, 'label', e.target.value)
|
|
3878
|
+
}}
|
|
3879
|
+
/>
|
|
3880
|
+
</label>
|
|
3881
|
+
</AccordionItemPanel>
|
|
3882
|
+
</AccordionItem>
|
|
3883
|
+
</Accordion>
|
|
3884
|
+
)}
|
|
3885
|
+
/>
|
|
3886
|
+
|
|
3887
|
+
<Button type='button' variant='editor-primary' onClick={() => editCityStyles('add', 0, '', '')}>
|
|
3422
3888
|
Add city style
|
|
3423
|
-
</
|
|
3889
|
+
</Button>
|
|
3424
3890
|
</>
|
|
3425
3891
|
<label htmlFor='opacity'>
|
|
3426
3892
|
<TextField
|
|
@@ -3446,6 +3912,15 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3446
3912
|
/>
|
|
3447
3913
|
</>
|
|
3448
3914
|
)}
|
|
3915
|
+
{isCoveDeveloperMode() && (
|
|
3916
|
+
<CheckBox
|
|
3917
|
+
value={config.visual?.highlightWrappers}
|
|
3918
|
+
section='visual'
|
|
3919
|
+
fieldName='highlightWrappers'
|
|
3920
|
+
label='Highlight Layout Wrappers'
|
|
3921
|
+
updateField={updateField}
|
|
3922
|
+
/>
|
|
3923
|
+
)}
|
|
3449
3924
|
</AccordionItemPanel>
|
|
3450
3925
|
</AccordionItem>
|
|
3451
3926
|
<AccordionItem>
|
|
@@ -3454,87 +3929,100 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3454
3929
|
</AccordionItemHeading>
|
|
3455
3930
|
<AccordionItemPanel>
|
|
3456
3931
|
{config.map.layers.length === 0 && <p>There are currently no layers.</p>}
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
<
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3932
|
+
<GroupedList
|
|
3933
|
+
items={config.map.layers}
|
|
3934
|
+
label='Custom Map Layers'
|
|
3935
|
+
droppableId='map-custom-layers'
|
|
3936
|
+
draggable={false}
|
|
3937
|
+
renderItem={(layer, index) => (
|
|
3938
|
+
<Accordion allowZeroExpanded key={`map-layer-${index}`}>
|
|
3939
|
+
<AccordionItem className='series-item series-item--chart map-layers-list'>
|
|
3940
|
+
<AccordionItemHeading className='series-item__title map-layers-list--title'>
|
|
3941
|
+
<AccordionItemButton className='accordion__button'>
|
|
3942
|
+
{`Layer ${index + 1}: ${layer.name}`}
|
|
3943
|
+
</AccordionItemButton>
|
|
3944
|
+
</AccordionItemHeading>
|
|
3945
|
+
<AccordionItemPanel>
|
|
3946
|
+
<div className='series-item__panel-actions'>
|
|
3947
|
+
<Button
|
|
3948
|
+
type='button'
|
|
3949
|
+
variant='danger'
|
|
3950
|
+
size='sm'
|
|
3951
|
+
className='grouped-list__remove'
|
|
3952
|
+
onClick={e => handleRemoveLayer(e, index)}
|
|
3953
|
+
>
|
|
3954
|
+
Remove Layer
|
|
3955
|
+
</Button>
|
|
3956
|
+
</div>
|
|
3957
|
+
<div className='map-layers-panel'>
|
|
3958
|
+
<label htmlFor='layerName'>Layer Name:</label>
|
|
3959
|
+
<input
|
|
3960
|
+
type='text'
|
|
3961
|
+
name='layerName'
|
|
3962
|
+
value={layer.name}
|
|
3963
|
+
onChange={e => handleMapLayer(e, index, 'name')}
|
|
3964
|
+
/>
|
|
3965
|
+
<label htmlFor='layerFilename'>File:</label>
|
|
3966
|
+
<input
|
|
3967
|
+
type='text'
|
|
3968
|
+
name='layerFilename'
|
|
3969
|
+
value={layer.url}
|
|
3970
|
+
onChange={e => handleMapLayer(e, index, 'url')}
|
|
3971
|
+
/>
|
|
3972
|
+
<label htmlFor='layerNamespace'>TOPOJSON Namespace:</label>
|
|
3973
|
+
<input
|
|
3974
|
+
type='text'
|
|
3975
|
+
name='layerNamespace'
|
|
3976
|
+
value={layer.namespace}
|
|
3977
|
+
onChange={e => handleMapLayer(e, index, 'namespace')}
|
|
3978
|
+
/>
|
|
3979
|
+
<label htmlFor='layerFill'>Fill Color:</label>
|
|
3980
|
+
<input
|
|
3981
|
+
type='text'
|
|
3982
|
+
name='layerFill'
|
|
3983
|
+
value={layer.fill}
|
|
3984
|
+
onChange={e => handleMapLayer(e, index, 'fill')}
|
|
3985
|
+
/>
|
|
3986
|
+
<label htmlFor='layerFill'>Fill Opacity (%):</label>
|
|
3987
|
+
<input
|
|
3988
|
+
type='number'
|
|
3989
|
+
min={0}
|
|
3990
|
+
max={100}
|
|
3991
|
+
name='layerFill'
|
|
3992
|
+
value={layer.fillOpacity ? layer.fillOpacity * 100 : ''}
|
|
3993
|
+
onChange={e => handleMapLayer(e, index, 'fillOpacity')}
|
|
3994
|
+
/>
|
|
3995
|
+
<label htmlFor='layerStroke'>Stroke Color:</label>
|
|
3996
|
+
<input
|
|
3997
|
+
type='text'
|
|
3998
|
+
name='layerStroke'
|
|
3999
|
+
value={layer.stroke}
|
|
4000
|
+
onChange={e => handleMapLayer(e, index, 'stroke')}
|
|
4001
|
+
/>
|
|
4002
|
+
<label htmlFor='layerStroke'>Stroke Width:</label>
|
|
4003
|
+
<input
|
|
4004
|
+
type='number'
|
|
4005
|
+
min={0}
|
|
4006
|
+
max={5}
|
|
4007
|
+
name='layerStrokeWidth'
|
|
4008
|
+
value={layer.strokeWidth}
|
|
4009
|
+
onChange={e => handleMapLayer(e, index, 'strokeWidth')}
|
|
4010
|
+
/>
|
|
4011
|
+
<label htmlFor='layerTooltip'>Tooltip:</label>
|
|
4012
|
+
<textarea
|
|
4013
|
+
name='layerTooltip'
|
|
4014
|
+
value={layer.tooltip}
|
|
4015
|
+
onChange={e => handleMapLayer(e, index, 'tooltip')}
|
|
4016
|
+
></textarea>
|
|
4017
|
+
</div>
|
|
4018
|
+
</AccordionItemPanel>
|
|
4019
|
+
</AccordionItem>
|
|
4020
|
+
</Accordion>
|
|
4021
|
+
)}
|
|
4022
|
+
/>
|
|
4023
|
+
<Button type='button' variant='editor-primary' onClick={handleAddLayer}>
|
|
3536
4024
|
Add Map Layer
|
|
3537
|
-
</
|
|
4025
|
+
</Button>
|
|
3538
4026
|
<p className='layer-purpose-details'>
|
|
3539
4027
|
Context should be added to your visualization or associated page to describe the significance of
|
|
3540
4028
|
layers that are added to maps.
|
|
@@ -3552,6 +4040,7 @@ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
|
|
|
3552
4040
|
enableMarkupVariables={config.enableMarkupVariables || false}
|
|
3553
4041
|
onMarkupVariablesChange={variables => setConfig({ ...config, markupVariables: variables })}
|
|
3554
4042
|
onToggleEnable={enabled => setConfig({ ...config, enableMarkupVariables: enabled })}
|
|
4043
|
+
dataMetadata={config.dataMetadata}
|
|
3555
4044
|
/>
|
|
3556
4045
|
<Panels.SmallMultiples name='Small Multiples' />
|
|
3557
4046
|
</Accordion>
|