@cdc/map 4.24.12 → 4.25.2-25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdcmap.js +50119 -48822
- package/examples/annotation/index.json +1 -1
- package/examples/custom-map-layers.json +1 -1
- package/examples/default-geocode.json +2 -2
- package/examples/example-city-state.json +1 -1
- package/examples/private/DEV-9989.json +229 -0
- package/examples/private/ardi.json +180 -0
- package/examples/private/colors 2.json +416 -0
- package/examples/private/colors.json +416 -0
- package/examples/private/colors.json.zip +0 -0
- package/examples/private/customColors.json +45348 -0
- package/examples/private/mmr.json +246 -0
- package/examples/private/test.json +1632 -0
- package/index.html +12 -14
- package/package.json +8 -3
- package/src/CdcMap.tsx +126 -396
- package/src/_stories/CdcMap.Filters.stories.tsx +19 -0
- package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +9 -0
- package/src/_stories/CdcMap.stories.tsx +1 -1
- package/src/_stories/GoogleMap.stories.tsx +19 -0
- package/src/_stories/_mock/DEV-10148.json +859 -0
- package/src/_stories/_mock/DEV-9989.json +229 -0
- package/src/_stories/_mock/example-city-state.json +1 -1
- package/src/_stories/_mock/google-map.json +819 -0
- package/src/_stories/_mock/wastewater-map.json +210 -206
- package/src/components/Annotation/Annotation.Draggable.tsx +34 -43
- package/src/components/Annotation/AnnotationDropdown.tsx +4 -4
- package/src/components/CityList.tsx +3 -9
- package/src/components/DataTable.tsx +8 -9
- package/src/components/EditorPanel/components/EditorPanel.tsx +255 -490
- package/src/components/GoogleMap/components/GoogleMap.tsx +67 -0
- package/src/components/GoogleMap/index.tsx +3 -0
- package/src/components/Legend/components/Legend.tsx +40 -30
- package/src/components/Legend/components/LegendItem.Hex.tsx +7 -3
- package/src/components/Legend/components/index.scss +22 -16
- package/src/components/Modal.tsx +6 -5
- package/src/components/NavigationMenu.tsx +4 -3
- package/src/components/UsaMap/components/TerritoriesSection.tsx +66 -0
- package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +15 -16
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +3 -3
- package/src/components/UsaMap/components/UsaMap.County.tsx +1 -1
- package/src/components/UsaMap/components/UsaMap.Region.tsx +12 -8
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +2 -2
- package/src/components/UsaMap/components/UsaMap.State.tsx +23 -29
- package/src/components/WorldMap/WorldMap.tsx +3 -5
- package/src/context.ts +0 -12
- package/src/data/initial-state.js +2 -2
- package/src/data/supported-geos.js +23 -3
- package/src/helpers/applyColorToLegend.ts +3 -3
- package/src/helpers/closeModal.ts +9 -0
- package/src/helpers/handleMapAriaLabels.ts +38 -0
- package/src/helpers/indexOfIgnoreType.ts +8 -0
- package/src/helpers/navigationHandler.ts +21 -0
- package/src/helpers/toTitleCase.ts +44 -0
- package/src/helpers/validateFipsCodeLength.ts +30 -0
- package/src/hooks/useResizeObserver.ts +42 -0
- package/src/hooks/useTooltip.ts +4 -2
- package/src/index.jsx +1 -0
- package/src/scss/editor-panel.scss +2 -1
- package/src/scss/filters.scss +0 -5
- package/src/scss/main.scss +57 -61
- package/src/scss/map.scss +1 -13
- package/src/types/MapConfig.ts +20 -11
- package/src/types/MapContext.ts +4 -12
package/src/CdcMap.tsx
CHANGED
|
@@ -1,47 +1,36 @@
|
|
|
1
|
+
// Vendor
|
|
1
2
|
import React, { useState, useEffect, useRef, useCallback, useId } from 'react'
|
|
2
3
|
import * as d3 from 'd3'
|
|
3
|
-
import Layout from '@cdc/core/components/Layout'
|
|
4
|
-
import Waiting from '@cdc/core/components/Waiting'
|
|
5
|
-
import Annotation from './components/Annotation'
|
|
6
|
-
import Error from './components/EditorPanel/components/Error'
|
|
7
4
|
import _ from 'lodash'
|
|
8
|
-
import { applyColorToLegend } from './helpers/applyColorToLegend'
|
|
9
|
-
|
|
10
|
-
// types
|
|
11
|
-
import { type ViewportSize } from './types/MapConfig'
|
|
12
|
-
import { type DimensionsType } from '@cdc/core/types/Dimensions'
|
|
13
|
-
|
|
14
|
-
// IE11
|
|
15
5
|
import 'whatwg-fetch'
|
|
16
|
-
import ResizeObserver from 'resize-observer-polyfill'
|
|
17
|
-
|
|
18
|
-
// Third party
|
|
19
6
|
import { Tooltip as ReactTooltip } from 'react-tooltip'
|
|
20
7
|
import Papa from 'papaparse'
|
|
21
8
|
import parse from 'html-react-parser'
|
|
22
9
|
import 'react-tooltip/dist/react-tooltip.css'
|
|
23
10
|
|
|
24
|
-
//
|
|
25
|
-
import
|
|
26
|
-
import {
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
31
|
-
import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
|
|
11
|
+
// Core Components
|
|
12
|
+
import DataTable from '@cdc/core/components/DataTable'
|
|
13
|
+
import Filters, { useFilters } from '@cdc/core/components/Filters'
|
|
14
|
+
import Layout from '@cdc/core/components/Layout'
|
|
15
|
+
import MediaControls from '@cdc/core/components/MediaControls'
|
|
16
|
+
import SkipTo from '@cdc/core/components/elements/SkipTo'
|
|
32
17
|
import Title from '@cdc/core/components/ui/Title'
|
|
18
|
+
import Waiting from '@cdc/core/components/Waiting'
|
|
19
|
+
|
|
20
|
+
// types
|
|
21
|
+
import { type Coordinate, type MapConfig } from './types/MapConfig'
|
|
33
22
|
|
|
34
23
|
// Data
|
|
35
24
|
import { countryCoordinates } from './data/country-coordinates'
|
|
36
25
|
import {
|
|
37
|
-
|
|
38
|
-
supportedTerritories,
|
|
39
|
-
supportedCountries,
|
|
40
|
-
supportedCounties,
|
|
26
|
+
stateFipsToTwoDigit,
|
|
41
27
|
supportedCities,
|
|
28
|
+
supportedCounties,
|
|
29
|
+
supportedCountries,
|
|
30
|
+
supportedRegions,
|
|
31
|
+
supportedStates,
|
|
42
32
|
supportedStatesFipsCodes,
|
|
43
|
-
|
|
44
|
-
supportedRegions
|
|
33
|
+
supportedTerritories
|
|
45
34
|
} from './data/supported-geos'
|
|
46
35
|
import colorPalettes from '@cdc/core/data/colorPalettes'
|
|
47
36
|
import initialState from './data/initial-state'
|
|
@@ -51,33 +40,48 @@ import ExternalIcon from './images/external-link.svg'
|
|
|
51
40
|
|
|
52
41
|
// Sass
|
|
53
42
|
import './scss/main.scss'
|
|
54
|
-
|
|
55
|
-
// TODO: combine in scss.
|
|
56
43
|
import './scss/btn.scss'
|
|
57
44
|
|
|
58
|
-
// Core
|
|
59
|
-
import
|
|
60
|
-
import MediaControls from '@cdc/core/components/MediaControls'
|
|
45
|
+
// Core Helpers
|
|
46
|
+
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
61
47
|
import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
|
|
62
|
-
import getViewport from '@cdc/core/helpers/getViewport'
|
|
63
48
|
import isDomainExternal from '@cdc/core/helpers/isDomainExternal'
|
|
64
49
|
import numberFromString from '@cdc/core/helpers/numberFromString'
|
|
65
|
-
import
|
|
50
|
+
import { DataTransform } from '@cdc/core/helpers/DataTransform'
|
|
51
|
+
import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
|
|
52
|
+
import { isSolrCsv, isSolrJson } from '@cdc/core/helpers/isSolr'
|
|
53
|
+
import { publish } from '@cdc/core/helpers/events'
|
|
54
|
+
|
|
55
|
+
// Map Helpers
|
|
56
|
+
import { applyColorToLegend } from './helpers/applyColorToLegend'
|
|
57
|
+
import { closeModal } from './helpers/closeModal'
|
|
58
|
+
import { generateColorsArray } from './helpers/generateColorsArray'
|
|
59
|
+
import { generateRuntimeLegendHash } from './helpers/generateRuntimeLegendHash'
|
|
60
|
+
import { getGeoFillColor } from './helpers/colors'
|
|
61
|
+
import { getUniqueValues } from './helpers/getUniqueValues'
|
|
62
|
+
import { hashObj } from './helpers/hashObj'
|
|
63
|
+
import { navigationHandler } from './helpers/navigationHandler'
|
|
64
|
+
import { validateFipsCodeLength } from './helpers/validateFipsCodeLength'
|
|
65
|
+
import { titleCase } from './helpers/titleCase'
|
|
66
|
+
import { indexOfIgnoreType } from './helpers/indexOfIgnoreType'
|
|
66
67
|
|
|
67
68
|
// Child Components
|
|
69
|
+
import Annotation from './components/Annotation'
|
|
68
70
|
import ConfigContext from './context'
|
|
69
|
-
import
|
|
70
|
-
import
|
|
71
|
+
import EditorPanel from './components/EditorPanel'
|
|
72
|
+
import Error from './components/EditorPanel/components/Error'
|
|
71
73
|
import Legend from './components/Legend'
|
|
74
|
+
import Modal from './components/Modal'
|
|
75
|
+
import NavigationMenu from './components/NavigationMenu'
|
|
76
|
+
import UsaMap from './components/UsaMap'
|
|
77
|
+
import WorldMap from './components/WorldMap'
|
|
78
|
+
import GoogleMap from './components/GoogleMap'
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
import NavigationMenu from './components/NavigationMenu' // Future: Lazy
|
|
75
|
-
import UsaMap from './components/UsaMap' // Future: Lazy
|
|
76
|
-
import WorldMap from './components/WorldMap' // Future: Lazy
|
|
80
|
+
// hooks
|
|
77
81
|
import useTooltip from './hooks/useTooltip'
|
|
78
|
-
import
|
|
79
|
-
import
|
|
80
|
-
import {
|
|
82
|
+
import useResizeObserver from './hooks/useResizeObserver'
|
|
83
|
+
import { SubGrouping } from '@cdc/core/types/VizFilter'
|
|
84
|
+
import { ViewPort } from '@cdc/core/types/ViewPort'
|
|
81
85
|
|
|
82
86
|
// Data props
|
|
83
87
|
const stateKeys = Object.keys(supportedStates)
|
|
@@ -87,17 +91,7 @@ const countryKeys = Object.keys(supportedCountries)
|
|
|
87
91
|
const countyKeys = Object.keys(supportedCounties)
|
|
88
92
|
const cityKeys = Object.keys(supportedCities)
|
|
89
93
|
|
|
90
|
-
const indexOfIgnoreType = (arr, item) => {
|
|
91
|
-
for (let i = 0; i < arr.length; i++) {
|
|
92
|
-
if (item === arr[i]) {
|
|
93
|
-
return i
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return -1
|
|
97
|
-
}
|
|
98
|
-
|
|
99
94
|
const CdcMap = ({
|
|
100
|
-
className,
|
|
101
95
|
config,
|
|
102
96
|
navigationHandler: customNavigationHandler,
|
|
103
97
|
isDashboard = false,
|
|
@@ -113,26 +107,31 @@ const CdcMap = ({
|
|
|
113
107
|
const transform = new DataTransform()
|
|
114
108
|
const [translate, setTranslate] = useState([0, 0])
|
|
115
109
|
const [scale, setScale] = useState(1)
|
|
116
|
-
const [state, setState] = useState({ ...initialState })
|
|
110
|
+
const [state, setState] = useState<MapConfig>({ ...initialState })
|
|
117
111
|
const [isDraggingAnnotation, setIsDraggingAnnotation] = useState(false)
|
|
118
112
|
const [loading, setLoading] = useState(true)
|
|
119
113
|
const [displayPanel, setDisplayPanel] = useState(true)
|
|
120
|
-
const [
|
|
121
|
-
const [topoData, setTopoData] = useState<Topology | {}>({})
|
|
114
|
+
const [topoData, setTopoData] = useState<{}>({})
|
|
122
115
|
const [runtimeFilters, setRuntimeFilters] = useState([])
|
|
123
|
-
const [runtimeLegend, setRuntimeLegend] = useState([])
|
|
124
116
|
const [runtimeData, setRuntimeData] = useState({ init: true })
|
|
117
|
+
const _setRuntimeData = (data: any) => {
|
|
118
|
+
if (config) {
|
|
119
|
+
setRuntimeData(data)
|
|
120
|
+
} else {
|
|
121
|
+
setRuntimeFilters(data)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const [runtimeLegend, setRuntimeLegend] = useState([])
|
|
125
125
|
const [stateToShow, setStateToShow] = useState(null)
|
|
126
126
|
const [modal, setModal] = useState(null)
|
|
127
127
|
const [accessibleStatus, setAccessibleStatus] = useState('')
|
|
128
128
|
const [filteredCountryCode, setFilteredCountryCode] = useState()
|
|
129
129
|
const [position, setPosition] = useState(state.mapPosition)
|
|
130
130
|
const [coveLoadedHasRan, setCoveLoadedHasRan] = useState(false)
|
|
131
|
-
const [container, setContainer] = useState()
|
|
132
131
|
const [imageId, setImageId] = useState(`cove-${Math.random().toString(16).slice(-4)}`) // eslint-disable-line
|
|
133
|
-
const [dimensions, setDimensions] = useState<DimensionsType>([0, 0])
|
|
134
132
|
const [requiredColumns, setRequiredColumns] = useState(null) // Simple state so we know if we need more information before parsing the map
|
|
135
133
|
const [projection, setProjection] = useState(null)
|
|
134
|
+
const { currentViewport, dimensions, container, outerContainerRef } = useResizeObserver(isEditor)
|
|
136
135
|
|
|
137
136
|
const legendRef = useRef(null)
|
|
138
137
|
const tooltipRef = useRef(null)
|
|
@@ -141,7 +140,7 @@ const CdcMap = ({
|
|
|
141
140
|
const tooltipId = `${Math.random().toString(16).slice(-4)}`
|
|
142
141
|
const mapId = useId()
|
|
143
142
|
|
|
144
|
-
const {
|
|
143
|
+
const { handleSorting } = useFilters({ config: state, setConfig: setState })
|
|
145
144
|
let legendMemo = useRef(new Map())
|
|
146
145
|
let legendSpecialClassLastMemo = useRef(new Map())
|
|
147
146
|
let innerContainerRef = useRef()
|
|
@@ -166,10 +165,7 @@ const CdcMap = ({
|
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
// Navigate is required for navigation maps
|
|
169
|
-
if (
|
|
170
|
-
'navigation' === state.general.type &&
|
|
171
|
-
('' === state.columns.navigate.name || undefined === state.columns.navigate)
|
|
172
|
-
) {
|
|
168
|
+
if ('navigation' === state.general.type && '' === state.columns.navigate.name) {
|
|
173
169
|
columnList.push('Navigation')
|
|
174
170
|
}
|
|
175
171
|
|
|
@@ -198,7 +194,7 @@ const CdcMap = ({
|
|
|
198
194
|
const coordinates = countryCoordinates[filteredCountryCode]
|
|
199
195
|
const long = coordinates[1]
|
|
200
196
|
const lat = coordinates[0]
|
|
201
|
-
const reversedCoordinates = [long, lat]
|
|
197
|
+
const reversedCoordinates: Coordinate = [long, lat]
|
|
202
198
|
|
|
203
199
|
setState({
|
|
204
200
|
...state,
|
|
@@ -228,27 +224,11 @@ const CdcMap = ({
|
|
|
228
224
|
}
|
|
229
225
|
}, [state.mapPosition, setPosition])
|
|
230
226
|
|
|
231
|
-
const resizeObserver = new ResizeObserver(entries => {
|
|
232
|
-
for (let entry of entries) {
|
|
233
|
-
let { width, height } = entry.contentRect
|
|
234
|
-
let newViewport = getViewport(entry.contentRect.width)
|
|
235
|
-
|
|
236
|
-
let editorWidth = 350
|
|
237
|
-
|
|
238
|
-
setCurrentViewport(newViewport)
|
|
239
|
-
|
|
240
|
-
if (isEditor) {
|
|
241
|
-
width = width - editorWidth
|
|
242
|
-
}
|
|
243
|
-
setDimensions([width, height])
|
|
244
|
-
}
|
|
245
|
-
})
|
|
246
|
-
|
|
247
227
|
// Tag each row with a UID. Helps with filtering/placing geos. Not enumerable so doesn't show up in loops/console logs except when directly addressed ex row.uid
|
|
248
228
|
// We are mutating state in place here (depending on where called) - but it's okay, this isn't used for rerender
|
|
249
229
|
// eslint-disable-next-line
|
|
250
230
|
const addUIDs = useCallback((obj, fromColumn) => {
|
|
251
|
-
obj.data.forEach(
|
|
231
|
+
obj.data.forEach(row => {
|
|
252
232
|
let uid = null
|
|
253
233
|
|
|
254
234
|
if (row.uid) row.uid = null // Wipe existing UIDs
|
|
@@ -358,7 +338,7 @@ const CdcMap = ({
|
|
|
358
338
|
})
|
|
359
339
|
|
|
360
340
|
// eslint-disable-next-line
|
|
361
|
-
const generateRuntimeLegend = useCallback((obj,
|
|
341
|
+
const generateRuntimeLegend = useCallback((obj, runtimeFilters, hash) => {
|
|
362
342
|
const newLegendMemo = new Map() // Reset memoization
|
|
363
343
|
const newLegendSpecialClassLastMemo = new Map() // Reset bin memoization
|
|
364
344
|
let primaryCol = obj.columns.primary.name,
|
|
@@ -373,24 +353,10 @@ const CdcMap = ({
|
|
|
373
353
|
result.fromHash = hash
|
|
374
354
|
}
|
|
375
355
|
|
|
376
|
-
result.runtimeDataHash =
|
|
356
|
+
result.runtimeDataHash = runtimeFilters?.fromHash
|
|
377
357
|
|
|
378
|
-
// Unified will
|
|
358
|
+
// Unified will base the legend off ALL of the data maps received. Otherwise, it will use
|
|
379
359
|
let dataSet = obj.legend.unified ? obj.data : Object.values(runtimeData)
|
|
380
|
-
|
|
381
|
-
const colorDistributions = {
|
|
382
|
-
1: [1],
|
|
383
|
-
2: [1, 3],
|
|
384
|
-
3: [1, 3, 5],
|
|
385
|
-
4: [0, 2, 4, 6],
|
|
386
|
-
5: [0, 2, 4, 6, 7],
|
|
387
|
-
6: [0, 2, 3, 4, 5, 7],
|
|
388
|
-
7: [0, 2, 3, 4, 5, 6, 7],
|
|
389
|
-
8: [0, 2, 3, 4, 5, 6, 7, 8],
|
|
390
|
-
9: [0, 1, 2, 3, 4, 5, 6, 7, 8],
|
|
391
|
-
10: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
392
|
-
}
|
|
393
|
-
|
|
394
360
|
let specialClasses = 0
|
|
395
361
|
let specialClassesHash = {}
|
|
396
362
|
|
|
@@ -416,7 +382,7 @@ const CdcMap = ({
|
|
|
416
382
|
specialClasses += 1
|
|
417
383
|
}
|
|
418
384
|
|
|
419
|
-
let specialColor
|
|
385
|
+
let specialColor: number
|
|
420
386
|
|
|
421
387
|
// color the state if val is in row
|
|
422
388
|
specialColor = result.findIndex(p => p.value === val)
|
|
@@ -648,7 +614,6 @@ const CdcMap = ({
|
|
|
648
614
|
}
|
|
649
615
|
} else {
|
|
650
616
|
// get nums
|
|
651
|
-
let hasZeroInData = dataSet.filter(obj => obj[state.columns.primary.name] === 0).length > 0
|
|
652
617
|
let domainNums = new Set(dataSet.map(item => item[state.columns.primary.name]))
|
|
653
618
|
|
|
654
619
|
domainNums = d3.extent(domainNums)
|
|
@@ -683,7 +648,7 @@ const CdcMap = ({
|
|
|
683
648
|
|
|
684
649
|
const breaks = getBreaks(scale)
|
|
685
650
|
|
|
686
|
-
// if
|
|
651
|
+
// if separating zero force it into breaks
|
|
687
652
|
if (breaks[0] !== 0) {
|
|
688
653
|
breaks.unshift(0)
|
|
689
654
|
}
|
|
@@ -698,7 +663,7 @@ const CdcMap = ({
|
|
|
698
663
|
min = 0
|
|
699
664
|
}
|
|
700
665
|
|
|
701
|
-
// if we're on the second break, and
|
|
666
|
+
// if we're on the second break, and separating out zero, increment min to 1.
|
|
702
667
|
if (index === 1 && state.legend.separateZero) {
|
|
703
668
|
min = 1
|
|
704
669
|
}
|
|
@@ -714,20 +679,12 @@ const CdcMap = ({
|
|
|
714
679
|
return Math.pow(10, -n)
|
|
715
680
|
}
|
|
716
681
|
|
|
717
|
-
const setMax =
|
|
682
|
+
const setMax = index => {
|
|
718
683
|
let max = Number(breaks[index + 1]) - getDecimalPlace(Number(state?.columns?.primary?.roundToPlace))
|
|
719
684
|
|
|
720
|
-
// check if min and max range are the same
|
|
721
|
-
// if (min === max + 1) {
|
|
722
|
-
// max = breaks[index + 1]
|
|
723
|
-
// }
|
|
724
|
-
|
|
725
685
|
if (index === 0 && state.legend.separateZero) {
|
|
726
686
|
max = 0
|
|
727
687
|
}
|
|
728
|
-
// if ((index === state.legend.specialClasses.length && state.legend.specialClasses.length !== 0) && !state.legend.separateZero && hasZeroInData) {
|
|
729
|
-
// max = 0;
|
|
730
|
-
// }
|
|
731
688
|
|
|
732
689
|
if (index + 1 === breaks.length) {
|
|
733
690
|
max = domainNums[1]
|
|
@@ -745,7 +702,7 @@ const CdcMap = ({
|
|
|
745
702
|
color: scale(item)
|
|
746
703
|
})
|
|
747
704
|
|
|
748
|
-
dataSet.forEach(
|
|
705
|
+
dataSet.forEach(row => {
|
|
749
706
|
let number = row[state.columns.primary.name]
|
|
750
707
|
let updated = result.length - 1
|
|
751
708
|
|
|
@@ -810,7 +767,7 @@ const CdcMap = ({
|
|
|
810
767
|
legendMemo.current = newLegendMemo
|
|
811
768
|
|
|
812
769
|
if (state.general.geoType === 'world') {
|
|
813
|
-
const runtimeDataKeys = Object.keys(
|
|
770
|
+
const runtimeDataKeys = Object.keys(runtimeFilters)
|
|
814
771
|
const isCountriesWithNoDataState =
|
|
815
772
|
obj.data === undefined ? false : !countryKeys.every(countryKey => runtimeDataKeys.includes(countryKey))
|
|
816
773
|
|
|
@@ -875,32 +832,21 @@ const CdcMap = ({
|
|
|
875
832
|
) => {
|
|
876
833
|
let newFilter = runtimeFilters[idx]
|
|
877
834
|
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
const sortDesc = (a, b) => {
|
|
883
|
-
return b.toString().localeCompare(a.toString(), 'en', { numeric: true })
|
|
835
|
+
const sort = (a, b) => {
|
|
836
|
+
const asc = obj.filters[idx].order !== 'desc'
|
|
837
|
+
return String(asc ? a : b).localeCompare(String(asc ? b : a), 'en', { numeric: true })
|
|
884
838
|
}
|
|
885
839
|
|
|
886
840
|
if (type !== 'url') {
|
|
887
841
|
values = getUniqueValues(state.data, columnName)
|
|
888
842
|
|
|
889
|
-
if (obj.filters[idx].order === 'asc') {
|
|
890
|
-
values = values.sort(sortAsc)
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
if (obj.filters[idx].order === 'desc') {
|
|
894
|
-
values = values.sort(sortDesc)
|
|
895
|
-
}
|
|
896
|
-
|
|
897
843
|
if (obj.filters[idx].order === 'cust') {
|
|
898
844
|
if (obj.filters[idx]?.values.length > 0) {
|
|
899
845
|
values = obj.filters[idx].values
|
|
900
846
|
}
|
|
847
|
+
} else {
|
|
848
|
+
values = values.sort(sort)
|
|
901
849
|
}
|
|
902
|
-
} else {
|
|
903
|
-
values = values
|
|
904
850
|
}
|
|
905
851
|
|
|
906
852
|
if (undefined === newFilter) {
|
|
@@ -920,6 +866,7 @@ const CdcMap = ({
|
|
|
920
866
|
newFilter.active = active ?? values[0] // Default to first found value
|
|
921
867
|
newFilter.filterStyle = obj.filters[idx].filterStyle ? obj.filters[idx].filterStyle : 'dropdown'
|
|
922
868
|
newFilter.showDropdown = showDropdown
|
|
869
|
+
newFilter.subGrouping = obj.filters[idx].subGrouping
|
|
923
870
|
|
|
924
871
|
filters.push(newFilter)
|
|
925
872
|
}
|
|
@@ -960,7 +907,7 @@ const CdcMap = ({
|
|
|
960
907
|
// Strip hidden characters before we check length
|
|
961
908
|
navigateUrl = navigateUrl.replace(/(\r\n|\n|\r)/gm, '')
|
|
962
909
|
}
|
|
963
|
-
if (0 === navigateUrl
|
|
910
|
+
if (0 === navigateUrl?.length) {
|
|
964
911
|
return false
|
|
965
912
|
}
|
|
966
913
|
}
|
|
@@ -968,103 +915,31 @@ const CdcMap = ({
|
|
|
968
915
|
// Filters
|
|
969
916
|
if (filters?.length) {
|
|
970
917
|
for (let i = 0; i < filters.length; i++) {
|
|
971
|
-
const { columnName, active, type } = filters[i]
|
|
972
|
-
|
|
918
|
+
const { columnName, active, type, filterStyle, subGrouping } = filters[i]
|
|
919
|
+
const isDataFilter = type !== 'url'
|
|
920
|
+
const matchingValue = String(active) === String(row[columnName]) // Group
|
|
921
|
+
if (isDataFilter && !matchingValue) return false // Bail out, data doesn't match the filter selection
|
|
922
|
+
if (filterStyle == 'nested-dropdown') {
|
|
923
|
+
const matchingSubValue = String(row[subGrouping?.columnName]) === String(subGrouping?.active)
|
|
924
|
+
if (subGrouping?.active && !matchingSubValue) {
|
|
925
|
+
return false // Bail out, data doesn't match the subgroup selection
|
|
926
|
+
}
|
|
927
|
+
}
|
|
973
928
|
}
|
|
974
929
|
}
|
|
975
|
-
|
|
976
930
|
// Don't add additional rows with same UID
|
|
977
|
-
if (
|
|
931
|
+
if (result[row.uid] === undefined) {
|
|
978
932
|
result[row.uid] = row
|
|
979
933
|
}
|
|
980
934
|
})
|
|
981
|
-
|
|
982
935
|
return result
|
|
983
936
|
} catch (e) {
|
|
984
937
|
console.error('COVE: ', e) // eslint-disable-line
|
|
985
938
|
}
|
|
986
939
|
})
|
|
987
940
|
|
|
988
|
-
const outerContainerRef = useCallback(node => {
|
|
989
|
-
if (node !== null) {
|
|
990
|
-
resizeObserver.observe(node)
|
|
991
|
-
}
|
|
992
|
-
setContainer(node)
|
|
993
|
-
}, []) // eslint-disable-line
|
|
994
|
-
|
|
995
941
|
const mapSvg = useRef(null)
|
|
996
942
|
|
|
997
|
-
const closeModal = ({ target }) => {
|
|
998
|
-
if (
|
|
999
|
-
'string' === typeof target.className &&
|
|
1000
|
-
(target.className.includes('modal-close') || target.className.includes('modal-background')) &&
|
|
1001
|
-
null !== modal
|
|
1002
|
-
) {
|
|
1003
|
-
setModal(null)
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
const displayDataAsText = (value, columnName) => {
|
|
1008
|
-
if (value === null || value === '' || value === undefined) {
|
|
1009
|
-
return ''
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
// if string of letters like 'Home' then dont need to format as a number
|
|
1013
|
-
if (
|
|
1014
|
-
typeof value === 'string' &&
|
|
1015
|
-
value.length > 0 &&
|
|
1016
|
-
/[a-zA-Z]/.test(value) &&
|
|
1017
|
-
state.legend.type === 'equalnumber'
|
|
1018
|
-
) {
|
|
1019
|
-
return value
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
let formattedValue = value
|
|
1023
|
-
|
|
1024
|
-
let columnObj = state.columns[columnName]
|
|
1025
|
-
|
|
1026
|
-
if (columnObj === undefined) {
|
|
1027
|
-
// then use left axis config
|
|
1028
|
-
columnObj = state.columns.primary
|
|
1029
|
-
// NOTE: Left Value Axis uses different names
|
|
1030
|
-
// so map them below so the code below works
|
|
1031
|
-
// - copy commas to useCommas to work below
|
|
1032
|
-
columnObj['useCommas'] = columnObj.commas
|
|
1033
|
-
// - copy roundTo to roundToPlace to work below
|
|
1034
|
-
columnObj['roundToPlace'] = columnObj.roundTo ? columnObj.roundTo : ''
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
if (columnObj) {
|
|
1038
|
-
// If value is a number, apply specific formattings
|
|
1039
|
-
if (Number(value)) {
|
|
1040
|
-
const hasDecimal = columnObj.roundToPlace && (columnObj.roundToPlace !== '' || columnObj.roundToPlace !== null)
|
|
1041
|
-
const decimalPoint = columnObj.roundToPlace ? Number(columnObj.roundToPlace) : 0
|
|
1042
|
-
|
|
1043
|
-
// Rounding
|
|
1044
|
-
if (columnObj.hasOwnProperty('roundToPlace') && hasDecimal) {
|
|
1045
|
-
formattedValue = Number(value).toFixed(decimalPoint)
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
if (columnObj.hasOwnProperty('useCommas') && columnObj.useCommas === true) {
|
|
1049
|
-
// Formats number to string with commas - allows up to 5 decimal places, if rounding is not defined.
|
|
1050
|
-
// Otherwise, uses the rounding value set at 'columnObj.roundToPlace'.
|
|
1051
|
-
formattedValue = Number(value).toLocaleString('en-US', {
|
|
1052
|
-
style: 'decimal',
|
|
1053
|
-
minimumFractionDigits: hasDecimal ? decimalPoint : 0,
|
|
1054
|
-
maximumFractionDigits: hasDecimal ? decimalPoint : 5
|
|
1055
|
-
})
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// Check if it's a special value. If it is not, apply the designated prefix and suffix
|
|
1060
|
-
if (false === state.legend.specialClasses.includes(String(value))) {
|
|
1061
|
-
formattedValue = (columnObj.prefix || '') + formattedValue + (columnObj.suffix || '')
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
return formattedValue
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
943
|
// this is passed DOWN into the various components
|
|
1069
944
|
// then they do a lookup based on the bin number as index into here
|
|
1070
945
|
const applyLegendToRow = rowObj => {
|
|
@@ -1101,50 +976,6 @@ const CdcMap = ({
|
|
|
1101
976
|
}
|
|
1102
977
|
}
|
|
1103
978
|
|
|
1104
|
-
// if city has a hyphen then in tooltip it ends up UPPER CASE instead of just regular Upper Case
|
|
1105
|
-
// - this function is used to prevent that and instead give the formatting that is wanted
|
|
1106
|
-
// Example: Desired city display in tooltip on map: "Inter-Tribal Indian Reservation"
|
|
1107
|
-
const titleCase = string => {
|
|
1108
|
-
// guard clause else error in editor
|
|
1109
|
-
if (!string) return
|
|
1110
|
-
if (string !== undefined) {
|
|
1111
|
-
const toTitleCase = word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase()
|
|
1112
|
-
|
|
1113
|
-
if (string.toUpperCase().includes('U.S.') || string.toUpperCase().includes('US')) {
|
|
1114
|
-
return string
|
|
1115
|
-
.split(' ')
|
|
1116
|
-
.map(word => {
|
|
1117
|
-
if (word.toUpperCase() === 'U.S.' || word.toUpperCase() === 'US') {
|
|
1118
|
-
return word.toUpperCase()
|
|
1119
|
-
} else {
|
|
1120
|
-
return toTitleCase(word)
|
|
1121
|
-
}
|
|
1122
|
-
})
|
|
1123
|
-
.join(' ')
|
|
1124
|
-
}
|
|
1125
|
-
// if hyphen found, then split, uppercase each word, and put back together
|
|
1126
|
-
if (string.includes('–') || string.includes('-')) {
|
|
1127
|
-
let dashSplit = string.includes('–') ? string.split('–') : string.split('-') // determine hyphen or en dash to split on
|
|
1128
|
-
let splitCharacter = string.includes('–') ? '–' : '-' // print hyphen or en dash later on.
|
|
1129
|
-
let frontSplit = dashSplit[0]
|
|
1130
|
-
.split(' ')
|
|
1131
|
-
.map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase())
|
|
1132
|
-
.join(' ')
|
|
1133
|
-
let backSplit = dashSplit[1]
|
|
1134
|
-
.split(' ')
|
|
1135
|
-
.map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase())
|
|
1136
|
-
.join(' ')
|
|
1137
|
-
return frontSplit + splitCharacter + backSplit
|
|
1138
|
-
} else {
|
|
1139
|
-
// just return with each word uppercase
|
|
1140
|
-
return string
|
|
1141
|
-
.split(' ')
|
|
1142
|
-
.map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase())
|
|
1143
|
-
.join(' ')
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
979
|
// This resets all active legend toggles.
|
|
1149
980
|
const resetLegendToggles = async () => {
|
|
1150
981
|
let newLegend = [...runtimeLegend]
|
|
@@ -1217,7 +1048,7 @@ const CdcMap = ({
|
|
|
1217
1048
|
value = dict[value]
|
|
1218
1049
|
}
|
|
1219
1050
|
|
|
1220
|
-
// if you get here and it's 2 letters then
|
|
1051
|
+
// if you get here and it's 2 letters then dont titleCase state abbreviations like "AL"
|
|
1221
1052
|
if (value.length === 2) {
|
|
1222
1053
|
return value
|
|
1223
1054
|
} else {
|
|
@@ -1226,7 +1057,7 @@ const CdcMap = ({
|
|
|
1226
1057
|
}
|
|
1227
1058
|
|
|
1228
1059
|
// todo: convert to store or context eventually.
|
|
1229
|
-
const { buildTooltip } = useTooltip({ state, displayGeoName,
|
|
1060
|
+
const { buildTooltip } = useTooltip({ state, displayGeoName, supportedStatesFipsCodes })
|
|
1230
1061
|
|
|
1231
1062
|
const applyTooltipsToGeo = (geoName, row, returnType = 'string') => {
|
|
1232
1063
|
let toolTipText = buildTooltip(row, geoName, '')
|
|
@@ -1244,11 +1075,15 @@ const CdcMap = ({
|
|
|
1244
1075
|
key='modal-navigation-link'
|
|
1245
1076
|
onClick={e => {
|
|
1246
1077
|
e.preventDefault()
|
|
1247
|
-
navigationHandler(
|
|
1078
|
+
navigationHandler(
|
|
1079
|
+
state.general.navigationTarget,
|
|
1080
|
+
row[state.columns.navigate.name],
|
|
1081
|
+
customNavigationHandler
|
|
1082
|
+
)
|
|
1248
1083
|
}}
|
|
1249
1084
|
>
|
|
1250
1085
|
{state.tooltips.linkLabel}
|
|
1251
|
-
{isDomainExternal(row[state.columns.navigate.name]) && <ExternalIcon className='inline-icon
|
|
1086
|
+
{isDomainExternal(row[state.columns.navigate.name]) && <ExternalIcon className='inline-icon ms-1' />}
|
|
1252
1087
|
</a>
|
|
1253
1088
|
)
|
|
1254
1089
|
}
|
|
@@ -1257,24 +1092,6 @@ const CdcMap = ({
|
|
|
1257
1092
|
return toolTipText
|
|
1258
1093
|
}
|
|
1259
1094
|
|
|
1260
|
-
const navigationHandler = urlString => {
|
|
1261
|
-
// Call custom navigation method if passed
|
|
1262
|
-
if (customNavigationHandler) {
|
|
1263
|
-
customNavigationHandler(urlString)
|
|
1264
|
-
return
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
// Abort if value is blank
|
|
1268
|
-
if (0 === urlString.length) {
|
|
1269
|
-
throw Error('Blank string passed as URL. Navigation aborted.')
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
const urlObj = new URL(urlString, window.location.origin)
|
|
1273
|
-
|
|
1274
|
-
// Open constructed link in new tab/window
|
|
1275
|
-
window.open(urlObj.toString(), '_blank')
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
1095
|
const geoClickHandler = (key, value) => {
|
|
1279
1096
|
if (setSharedFilter) {
|
|
1280
1097
|
setSharedFilter(state.uid, value)
|
|
@@ -1291,7 +1108,7 @@ const CdcMap = ({
|
|
|
1291
1108
|
})
|
|
1292
1109
|
}
|
|
1293
1110
|
|
|
1294
|
-
// If modals are set or we are on a mobile viewport, display modal
|
|
1111
|
+
// If modals are set, or we are on a mobile viewport, display modal
|
|
1295
1112
|
if (window.matchMedia('(any-hover: none)').matches || 'click' === state.tooltips.appearanceType) {
|
|
1296
1113
|
setModal({
|
|
1297
1114
|
geoName: key,
|
|
@@ -1303,64 +1120,7 @@ const CdcMap = ({
|
|
|
1303
1120
|
|
|
1304
1121
|
// Otherwise if this item has a link specified for it, do regular navigation.
|
|
1305
1122
|
if (state.columns.navigate && value[state.columns.navigate.name]) {
|
|
1306
|
-
navigationHandler(value[state.columns.navigate.name])
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
const validateFipsCodeLength = newState => {
|
|
1311
|
-
if (
|
|
1312
|
-
newState.general.geoType === 'us-county' ||
|
|
1313
|
-
newState.general.geoType === 'single-state' ||
|
|
1314
|
-
(newState.general.geoType === 'us' && newState?.data)
|
|
1315
|
-
) {
|
|
1316
|
-
newState?.data.forEach(dataPiece => {
|
|
1317
|
-
if (dataPiece[newState.columns.geo.name]) {
|
|
1318
|
-
if (
|
|
1319
|
-
!isNaN(parseInt(dataPiece[newState.columns.geo.name])) &&
|
|
1320
|
-
dataPiece[newState.columns.geo.name].length === 4
|
|
1321
|
-
) {
|
|
1322
|
-
dataPiece[newState.columns.geo.name] = 0 + dataPiece[newState.columns.geo.name]
|
|
1323
|
-
}
|
|
1324
|
-
dataPiece[newState.columns.geo.name] = dataPiece[newState.columns.geo.name].toString()
|
|
1325
|
-
}
|
|
1326
|
-
})
|
|
1327
|
-
}
|
|
1328
|
-
return newState
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
const handleMapAriaLabels = (state = '', testing = false) => {
|
|
1332
|
-
if (testing) console.log(`handleMapAriaLabels Testing On: ${state}`) // eslint-disable-line
|
|
1333
|
-
try {
|
|
1334
|
-
if (!state.general.geoType) throw Error('handleMapAriaLabels: no geoType found in state')
|
|
1335
|
-
let ariaLabel = ''
|
|
1336
|
-
switch (state.general.geoType) {
|
|
1337
|
-
case 'world':
|
|
1338
|
-
ariaLabel += 'World map'
|
|
1339
|
-
break
|
|
1340
|
-
case 'us':
|
|
1341
|
-
ariaLabel += 'United States map'
|
|
1342
|
-
break
|
|
1343
|
-
case 'us-county':
|
|
1344
|
-
ariaLabel += `United States county map`
|
|
1345
|
-
break
|
|
1346
|
-
case 'single-state':
|
|
1347
|
-
ariaLabel += `${state.general.statePicked.stateName} county map`
|
|
1348
|
-
break
|
|
1349
|
-
case 'us-region':
|
|
1350
|
-
ariaLabel += `United States HHS Region map`
|
|
1351
|
-
break
|
|
1352
|
-
default:
|
|
1353
|
-
ariaLabel = 'Data visualization container'
|
|
1354
|
-
break
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
if (state.general.title) {
|
|
1358
|
-
ariaLabel += ` with the title: ${state.general.title}`
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
return ariaLabel
|
|
1362
|
-
} catch (e) {
|
|
1363
|
-
console.error('COVE: ', e.message) // eslint-disable-line
|
|
1123
|
+
navigationHandler(state.general.navigationTarget, value[state.columns.navigate.name], customNavigationHandler)
|
|
1364
1124
|
}
|
|
1365
1125
|
}
|
|
1366
1126
|
|
|
@@ -1464,7 +1224,7 @@ const CdcMap = ({
|
|
|
1464
1224
|
|
|
1465
1225
|
// This code goes through and adds the defaults for every property declaring in the initial state at the top.
|
|
1466
1226
|
// This allows you to easily add new properties to the config without having to worry about accounting for backwards compatibility.
|
|
1467
|
-
// Right now this does not work recursively -- only on first and second level properties. So state -> prop1 ->
|
|
1227
|
+
// Right now this does not work recursively -- only on first and second level properties. So state -> prop1 -> childPropOne
|
|
1468
1228
|
Object.keys(newState).forEach(key => {
|
|
1469
1229
|
if ('object' === typeof newState[key] && false === Array.isArray(newState[key])) {
|
|
1470
1230
|
if (initialState[key]) {
|
|
@@ -1522,11 +1282,11 @@ const CdcMap = ({
|
|
|
1522
1282
|
}, []) // eslint-disable-line
|
|
1523
1283
|
|
|
1524
1284
|
useEffect(() => {
|
|
1525
|
-
if (state && !coveLoadedHasRan && container) {
|
|
1285
|
+
if (state && !runtimeData.init && !coveLoadedHasRan && container) {
|
|
1526
1286
|
publish('cove_loaded', { config: state })
|
|
1527
1287
|
setCoveLoadedHasRan(true)
|
|
1528
1288
|
}
|
|
1529
|
-
}, [state, container]) // eslint-disable-line
|
|
1289
|
+
}, [state, container, runtimeData.init]) // eslint-disable-line
|
|
1530
1290
|
|
|
1531
1291
|
useEffect(() => {
|
|
1532
1292
|
// When geotype changes - add UID
|
|
@@ -1535,25 +1295,6 @@ const CdcMap = ({
|
|
|
1535
1295
|
}
|
|
1536
1296
|
}, [state]) // eslint-disable-line
|
|
1537
1297
|
|
|
1538
|
-
// DEV-769 make "Data Table" both a required field and default value
|
|
1539
|
-
useEffect(() => {
|
|
1540
|
-
if (state.table?.label === '' || state.table?.label === undefined) {
|
|
1541
|
-
setState({
|
|
1542
|
-
...state,
|
|
1543
|
-
table: {
|
|
1544
|
-
...state.table,
|
|
1545
|
-
title: 'Data Table'
|
|
1546
|
-
}
|
|
1547
|
-
})
|
|
1548
|
-
}
|
|
1549
|
-
}, [state.table]) // eslint-disable-line
|
|
1550
|
-
|
|
1551
|
-
// When geo label override changes
|
|
1552
|
-
// - redo the tooltips
|
|
1553
|
-
useEffect(() => {
|
|
1554
|
-
applyTooltipsToGeo()
|
|
1555
|
-
}, [state.general.geoLabelOverride]) // eslint-disable-line
|
|
1556
|
-
|
|
1557
1298
|
useEffect(() => {
|
|
1558
1299
|
// UID
|
|
1559
1300
|
if (state.data && state.columns.geo.name && state.columns.geo.name !== state.data.fromColumn) {
|
|
@@ -1564,7 +1305,7 @@ const CdcMap = ({
|
|
|
1564
1305
|
const hashFilters = hashObj(state.filters)
|
|
1565
1306
|
let filters
|
|
1566
1307
|
|
|
1567
|
-
if (state.filters && hashFilters !== runtimeFilters.fromHash) {
|
|
1308
|
+
if (state.filters && (config || hashFilters !== runtimeFilters.fromHash)) {
|
|
1568
1309
|
filters = generateRuntimeFilters(state, hashFilters, runtimeFilters)
|
|
1569
1310
|
|
|
1570
1311
|
if (filters) {
|
|
@@ -1593,12 +1334,12 @@ const CdcMap = ({
|
|
|
1593
1334
|
})
|
|
1594
1335
|
|
|
1595
1336
|
// Data
|
|
1596
|
-
if (hashData !== runtimeData
|
|
1337
|
+
if (hashData !== runtimeData?.fromHash && state.data?.fromColumn) {
|
|
1597
1338
|
const newRuntimeData = generateRuntimeData(state, filters || runtimeFilters, hashData)
|
|
1598
1339
|
|
|
1599
1340
|
setRuntimeData(newRuntimeData)
|
|
1600
1341
|
} else {
|
|
1601
|
-
if (hashLegend !== runtimeLegend
|
|
1342
|
+
if (hashLegend !== runtimeLegend?.fromHash && undefined === runtimeData.init) {
|
|
1602
1343
|
const legend = generateRuntimeLegend(state, runtimeData, hashLegend)
|
|
1603
1344
|
setRuntimeLegend(legend)
|
|
1604
1345
|
}
|
|
@@ -1674,21 +1415,14 @@ const CdcMap = ({
|
|
|
1674
1415
|
handleDragStateChange,
|
|
1675
1416
|
applyLegendToRow,
|
|
1676
1417
|
applyTooltipsToGeo,
|
|
1677
|
-
capitalize: state.tooltips?.capitalizeLabels,
|
|
1678
|
-
closeModal,
|
|
1679
|
-
columnsInData: state?.data?.[0] ? Object.keys(state.data[0]) : [],
|
|
1680
1418
|
container,
|
|
1681
1419
|
content: modal,
|
|
1682
|
-
currentViewport,
|
|
1683
1420
|
data: runtimeData,
|
|
1684
|
-
dimensions,
|
|
1685
|
-
displayDataAsText,
|
|
1686
1421
|
displayGeoName,
|
|
1687
1422
|
filteredCountryCode,
|
|
1688
1423
|
generateColorsArray,
|
|
1689
1424
|
generateRuntimeData,
|
|
1690
1425
|
geoClickHandler,
|
|
1691
|
-
handleMapAriaLabels,
|
|
1692
1426
|
hasZoom: state.general.allowMapZoom,
|
|
1693
1427
|
innerContainerRef,
|
|
1694
1428
|
isDashboard,
|
|
@@ -1696,7 +1430,6 @@ const CdcMap = ({
|
|
|
1696
1430
|
isEditor,
|
|
1697
1431
|
loadConfig,
|
|
1698
1432
|
logo,
|
|
1699
|
-
navigationHandler,
|
|
1700
1433
|
position,
|
|
1701
1434
|
resetLegendToggles,
|
|
1702
1435
|
runtimeFilters,
|
|
@@ -1712,18 +1445,14 @@ const CdcMap = ({
|
|
|
1712
1445
|
setSharedFilterValue,
|
|
1713
1446
|
setState,
|
|
1714
1447
|
state,
|
|
1715
|
-
supportedCities,
|
|
1716
|
-
supportedCounties,
|
|
1717
|
-
supportedCountries,
|
|
1718
|
-
supportedTerritories,
|
|
1719
|
-
titleCase,
|
|
1720
|
-
type: general.type,
|
|
1721
|
-
viewport: currentViewport,
|
|
1722
1448
|
tooltipId,
|
|
1723
1449
|
tooltipRef,
|
|
1724
1450
|
topoData,
|
|
1725
1451
|
setTopoData,
|
|
1726
|
-
mapId
|
|
1452
|
+
mapId,
|
|
1453
|
+
outerContainerRef,
|
|
1454
|
+
dimensions,
|
|
1455
|
+
currentViewport
|
|
1727
1456
|
}
|
|
1728
1457
|
|
|
1729
1458
|
if (!mapProps.data || !state.data) return <></>
|
|
@@ -1766,7 +1495,12 @@ const CdcMap = ({
|
|
|
1766
1495
|
)
|
|
1767
1496
|
|
|
1768
1497
|
const sectionClassNames = () => {
|
|
1769
|
-
const classes = [
|
|
1498
|
+
const classes = [
|
|
1499
|
+
'cove-component__content',
|
|
1500
|
+
'cdc-map-inner-container',
|
|
1501
|
+
`${currentViewport}`,
|
|
1502
|
+
`${state?.general?.headerColor}`
|
|
1503
|
+
]
|
|
1770
1504
|
if (config?.runtime?.editorErrorMessage.length > 0) classes.push('type-map--has-error')
|
|
1771
1505
|
return classes.join(' ')
|
|
1772
1506
|
}
|
|
@@ -1800,20 +1534,16 @@ const CdcMap = ({
|
|
|
1800
1534
|
<SkipTo skipId={tabId} skipMessage={`Skip over annotations`} key={`skip-annotations`} />
|
|
1801
1535
|
)}
|
|
1802
1536
|
|
|
1803
|
-
{general.introText && (
|
|
1804
|
-
<section className='introText' style={{ padding: '15px', margin: '0px' }}>
|
|
1805
|
-
{parse(general.introText)}
|
|
1806
|
-
</section>
|
|
1807
|
-
)}
|
|
1537
|
+
{general.introText && <section className='introText mb-4'>{parse(general.introText)}</section>}
|
|
1808
1538
|
|
|
1809
1539
|
{state?.filters?.length > 0 && (
|
|
1810
1540
|
<Filters
|
|
1811
1541
|
config={state}
|
|
1812
1542
|
setConfig={setState}
|
|
1813
|
-
getUniqueValues={getUniqueValues}
|
|
1814
1543
|
filteredData={runtimeFilters}
|
|
1815
|
-
setFilteredData={
|
|
1544
|
+
setFilteredData={_setRuntimeData}
|
|
1816
1545
|
dimensions={dimensions}
|
|
1546
|
+
standaloneMap={!config}
|
|
1817
1547
|
/>
|
|
1818
1548
|
)}
|
|
1819
1549
|
|
|
@@ -1821,10 +1551,10 @@ const CdcMap = ({
|
|
|
1821
1551
|
role='region'
|
|
1822
1552
|
tabIndex='0'
|
|
1823
1553
|
className={mapContainerClasses.join(' ')}
|
|
1824
|
-
onClick={e => closeModal(e)}
|
|
1554
|
+
onClick={e => closeModal(e, modal, setModal)}
|
|
1825
1555
|
onKeyDown={e => {
|
|
1826
|
-
if (e.
|
|
1827
|
-
closeModal(e)
|
|
1556
|
+
if (e.key === 'Enter') {
|
|
1557
|
+
closeModal(e, modal, setModal)
|
|
1828
1558
|
}
|
|
1829
1559
|
}}
|
|
1830
1560
|
style={{ padding: '15px 0px', margin: '0px' }}
|
|
@@ -1840,6 +1570,7 @@ const CdcMap = ({
|
|
|
1840
1570
|
{'us-county' === geoType && <UsaMap.County />}
|
|
1841
1571
|
{'world' === geoType && <WorldMap />}
|
|
1842
1572
|
{/* logo is handled in UsaMap.State when applicable */}
|
|
1573
|
+
{'google-map' === geoType && <GoogleMap />}
|
|
1843
1574
|
{'data' === general.type && logo && ('us' !== geoType || 'us-geocode' === state.general.type) && (
|
|
1844
1575
|
<img src={logo} alt='' className='map-logo' style={{ maxWidth: '50px' }} />
|
|
1845
1576
|
)}
|
|
@@ -1865,14 +1596,14 @@ const CdcMap = ({
|
|
|
1865
1596
|
data={runtimeData}
|
|
1866
1597
|
options={general}
|
|
1867
1598
|
columns={state.columns}
|
|
1868
|
-
navigationHandler={val => navigationHandler(val)}
|
|
1599
|
+
navigationHandler={val => navigationHandler('_blank', val, customNavigationHandler)}
|
|
1869
1600
|
/>
|
|
1870
1601
|
)}
|
|
1871
1602
|
|
|
1872
1603
|
{/* Link */}
|
|
1873
1604
|
{isDashboard && config.table?.forceDisplay && config.table.showDataTableLink ? tableLink : link && link}
|
|
1874
1605
|
|
|
1875
|
-
{subtext.length > 0 && <p className='subtext'>{parse(subtext)}</p>}
|
|
1606
|
+
{subtext.length > 0 && <p className='subtext mt-4'>{parse(subtext)}</p>}
|
|
1876
1607
|
|
|
1877
1608
|
<MediaControls.Section classes={['download-buttons']}>
|
|
1878
1609
|
{state.general.showDownloadImgButton && (
|
|
@@ -1910,7 +1641,6 @@ const CdcMap = ({
|
|
|
1910
1641
|
showFullGeoNameInCSV={table.showFullGeoNameInCSV}
|
|
1911
1642
|
runtimeLegend={runtimeLegend}
|
|
1912
1643
|
runtimeData={runtimeData}
|
|
1913
|
-
displayDataAsText={displayDataAsText}
|
|
1914
1644
|
displayGeoName={displayGeoName}
|
|
1915
1645
|
applyLegendToRow={applyLegendToRow}
|
|
1916
1646
|
tableTitle={table.label}
|
|
@@ -1932,7 +1662,7 @@ const CdcMap = ({
|
|
|
1932
1662
|
|
|
1933
1663
|
{state.annotations.length > 0 && <Annotation.Dropdown />}
|
|
1934
1664
|
|
|
1935
|
-
{general.footnotes && <section className='footnotes'>{parse(general.footnotes)}</section>}
|
|
1665
|
+
{general.footnotes && <section className='footnotes pt-2 mt-4'>{parse(general.footnotes)}</section>}
|
|
1936
1666
|
</section>
|
|
1937
1667
|
)}
|
|
1938
1668
|
|