@cdc/map 4.22.10 → 4.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/495.js +3 -0
  2. package/dist/703.js +1 -0
  3. package/dist/856.js +3 -0
  4. package/dist/cdcmap.js +724 -120
  5. package/examples/bubble-us.json +362 -362
  6. package/examples/bubble-world.json +426 -426
  7. package/examples/city-state.json +434 -0
  8. package/examples/example-city-state.json +202 -25
  9. package/package.json +3 -4
  10. package/src/CdcMap.js +249 -423
  11. package/src/components/BubbleList.js +198 -240
  12. package/src/components/CityList.js +50 -97
  13. package/src/components/CountyMap.js +511 -600
  14. package/src/components/DataTable.js +223 -230
  15. package/src/components/EditorPanel.js +2395 -2551
  16. package/src/components/Filters.js +114 -0
  17. package/src/components/Geo.js +4 -14
  18. package/src/components/Modal.js +13 -23
  19. package/src/components/NavigationMenu.js +43 -39
  20. package/src/components/Sidebar.js +77 -93
  21. package/src/components/SingleStateMap.js +95 -151
  22. package/src/components/UsaMap.js +165 -214
  23. package/src/components/UsaRegionMap.js +122 -160
  24. package/src/components/WorldMap.js +96 -179
  25. package/src/components/ZoomableGroup.js +6 -26
  26. package/src/context.js +5 -0
  27. package/src/data/initial-state.js +20 -15
  28. package/src/data/supported-geos.js +3201 -3175
  29. package/src/hooks/useActiveElement.js +13 -13
  30. package/src/hooks/useColorPalette.ts +66 -74
  31. package/src/hooks/useZoomPan.js +22 -23
  32. package/src/index.html +32 -29
  33. package/src/scss/datatable.scss +1 -2
  34. package/src/scss/filters.scss +42 -0
  35. package/src/scss/main.scss +4 -3
  36. package/src/scss/sidebar.scss +22 -0
  37. package/examples/private/atsdr.json +0 -439
  38. package/examples/private/atsdr_new.json +0 -436
  39. package/examples/private/bubble.json +0 -285
  40. package/examples/private/city-state.json +0 -428
  41. package/examples/private/cty-issue.json +0 -42768
  42. package/examples/private/default-usa.json +0 -460
  43. package/examples/private/default-world-data.json +0 -1444
  44. package/examples/private/default.json +0 -968
  45. package/examples/private/legend-issue.json +0 -1
  46. package/examples/private/map-rounding-error.json +0 -42759
  47. package/examples/private/map.csv +0 -60
  48. package/examples/private/mdx.json +0 -210
  49. package/examples/private/monkeypox.json +0 -376
  50. package/examples/private/regions.json +0 -52
  51. package/examples/private/valid-data-map.csv +0 -59
  52. package/examples/private/wcmsrd-13881-data.json +0 -2858
  53. package/examples/private/wcmsrd-13881.json +0 -5823
  54. package/examples/private/wcmsrd-14492-data.json +0 -292
  55. package/examples/private/wcmsrd-14492.json +0 -114
  56. package/examples/private/wcmsrd-test.json +0 -268
  57. package/examples/private/world.json +0 -1580
  58. package/examples/private/worldmap.json +0 -1490
package/src/CdcMap.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useRef, memo, useCallback } from 'react'
1
+ import React, { useState, useEffect, useRef, useCallback } from 'react'
2
2
  import * as d3 from 'd3'
3
3
 
4
4
  // IE11
@@ -10,42 +10,25 @@ import ResizeObserver from 'resize-observer-polyfill'
10
10
  import ReactTooltip from 'react-tooltip'
11
11
  import chroma from 'chroma-js'
12
12
  import parse from 'html-react-parser'
13
- import html2pdf from 'html2pdf.js'
14
- import html2canvas from 'html2canvas'
15
- import Canvg from 'canvg'
16
13
 
17
14
  // Data
18
15
  import colorPalettes from '../../core/data/colorPalettes'
19
16
  import ExternalIcon from './images/external-link.svg'
20
- import {
21
- supportedStates,
22
- supportedTerritories,
23
- supportedCountries,
24
- supportedCounties,
25
- supportedCities,
26
- supportedStatesFipsCodes,
27
- stateFipsToTwoDigit,
28
- supportedRegions
29
- } from './data/supported-geos'
17
+ import { supportedStates, supportedTerritories, supportedCountries, supportedCounties, supportedCities, supportedStatesFipsCodes, stateFipsToTwoDigit, supportedRegions } from './data/supported-geos'
30
18
  import initialState from './data/initial-state'
31
19
  import { countryCoordinates } from './data/country-coordinates'
20
+ import CoveMediaControls from '@cdc/core/helpers/CoveMediaControls'
32
21
 
33
22
  // Sass
34
23
  import './scss/main.scss'
35
24
  import './scss/btn.scss'
36
25
 
37
- // Images
38
- // TODO: Move to Icon component
39
- import DownloadImg from './images/icon-download-img.svg'
40
- import DownloadPdf from './images/icon-download-pdf.svg'
41
-
42
26
  // Core
43
- import Loading from '@cdc/core/components/Loading';
44
- import { DataTransform } from '@cdc/core/helpers/DataTransform';
45
- import getViewport from '@cdc/core/helpers/getViewport';
46
- import numberFromString from '@cdc/core/helpers/numberFromString';
47
- import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData';
48
- import cacheBustingString from '@cdc/core/helpers/cacheBustingString';
27
+ import Loading from '@cdc/core/components/Loading'
28
+ import { DataTransform } from '@cdc/core/helpers/DataTransform'
29
+ import getViewport from '@cdc/core/helpers/getViewport'
30
+ import numberFromString from '@cdc/core/helpers/numberFromString'
31
+ import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
49
32
 
50
33
  // Child Components
51
34
  import Sidebar from './components/Sidebar'
@@ -58,6 +41,8 @@ import DataTable from './components/DataTable' // Future: Lazy
58
41
  import NavigationMenu from './components/NavigationMenu' // Future: Lazy
59
42
  import WorldMap from './components/WorldMap' // Future: Lazy
60
43
  import SingleStateMap from './components/SingleStateMap' // Future: Lazy
44
+ import Filters from './components/Filters'
45
+ import Context from './context'
61
46
 
62
47
  import { publish } from '@cdc/core/helpers/events'
63
48
 
@@ -73,14 +58,10 @@ const generateColorsArray = (color = '#000000', special = false) => {
73
58
  let colorObj = chroma(color)
74
59
  let hoverColor = special ? colorObj.brighten(0.5).hex() : colorObj.saturate(1.3).hex()
75
60
 
76
- return [
77
- color,
78
- hoverColor,
79
- colorObj.darken(0.3).hex()
80
- ]
61
+ return [color, hoverColor, colorObj.darken(0.3).hex()]
81
62
  }
82
63
 
83
- const hashObj = (row) => {
64
+ const hashObj = row => {
84
65
  try {
85
66
  if (!row) throw new Error('No row supplied to hashObj')
86
67
 
@@ -91,7 +72,7 @@ const hashObj = (row) => {
91
72
 
92
73
  for (let i = 0; i < str.length; i++) {
93
74
  let char = str.charCodeAt(i)
94
- hash = ((hash << 5) - hash) + char
75
+ hash = (hash << 5) - hash + char
95
76
  hash = hash & hash
96
77
  }
97
78
 
@@ -119,31 +100,31 @@ const getUniqueValues = (data, columnName) => {
119
100
  }
120
101
 
121
102
  const CdcMap = ({ className, config, navigationHandler: customNavigationHandler, isDashboard = false, isEditor = false, configUrl, logo = null, setConfig, setSharedFilter, setSharedFilterValue, hostname = 'localhost:8080', link }) => {
122
- const [ showLoadingMessage, setShowLoadingMessage ] = useState(false)
123
103
  const transform = new DataTransform()
124
- const [ state, setState ] = useState({ ...initialState })
125
- const [ loading, setLoading ] = useState(true)
126
- const [ currentViewport, setCurrentViewport ] = useState()
127
- const [ runtimeFilters, setRuntimeFilters ] = useState([])
128
- const [ runtimeLegend, setRuntimeLegend ] = useState([])
129
- const [ runtimeData, setRuntimeData ] = useState({ init: true })
130
- const [ modal, setModal ] = useState(null)
131
- const [ accessibleStatus, setAccessibleStatus ] = useState('')
132
- const [ filteredCountryCode, setFilteredCountryCode ] = useState()
133
- const [ position, setPosition ] = useState(state.mapPosition)
134
- const [ coveLoadedHasRan, setCoveLoadedHasRan ] = useState(false)
135
- const [ container, setContainer ] = useState()
104
+ const [state, setState] = useState({ ...initialState })
105
+ const [loading, setLoading] = useState(true)
106
+ const [currentViewport, setCurrentViewport] = useState()
107
+ const [runtimeFilters, setRuntimeFilters] = useState([])
108
+ const [runtimeLegend, setRuntimeLegend] = useState([])
109
+ const [runtimeData, setRuntimeData] = useState({ init: true })
110
+ const [modal, setModal] = useState(null)
111
+ const [accessibleStatus, setAccessibleStatus] = useState('')
112
+ const [filteredCountryCode, setFilteredCountryCode] = useState()
113
+ const [position, setPosition] = useState(state.mapPosition)
114
+ const [coveLoadedHasRan, setCoveLoadedHasRan] = useState(false)
115
+ const [container, setContainer] = useState()
116
+ const [imageId, setImageId] = useState(`cove-${Math.random().toString(16).slice(-4)}`) // eslint-disable-line
136
117
 
137
118
  let legendMemo = useRef(new Map())
119
+ let innerContainerRef = useRef()
138
120
 
139
121
  useEffect(() => {
140
122
  try {
141
123
  if (filteredCountryCode) {
142
- const filteredCountryObj = runtimeData[filteredCountryCode]
143
124
  const coordinates = countryCoordinates[filteredCountryCode]
144
125
  const long = coordinates[1]
145
126
  const lat = coordinates[0]
146
- const reversedCoordinates = [ long, lat ]
127
+ const reversedCoordinates = [long, lat]
147
128
 
148
129
  setState({
149
130
  ...state,
@@ -153,7 +134,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
153
134
  } catch (e) {
154
135
  console.error('Failed to set world map zoom.')
155
136
  }
156
- }, [ filteredCountryCode ])
137
+ }, [filteredCountryCode])
157
138
 
158
139
  useEffect(() => {
159
140
  setTimeout(() => {
@@ -165,20 +146,13 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
165
146
  setRuntimeData(tmpData)
166
147
  }
167
148
  }, 100)
168
- }, [ filteredCountryCode ])
149
+ }, [filteredCountryCode])
169
150
 
170
151
  useEffect(() => {
171
152
  if (state.mapPosition) {
172
153
  setPosition(state.mapPosition)
173
154
  }
174
- }, [ state.mapPosition, setPosition ])
175
-
176
- const setZoom = (reversedCoordinates) => {
177
- setState({
178
- ...state,
179
- mapPosition: { coordinates: reversedCoordinates, zoom: 3 }
180
- })
181
- }
155
+ }, [state.mapPosition, setPosition])
182
156
 
183
157
  const resizeObserver = new ResizeObserver(entries => {
184
158
  for (let entry of entries) {
@@ -207,16 +181,16 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
207
181
  }
208
182
 
209
183
  // States
210
- uid = stateKeys.find((key) => supportedStates[key].includes(geoName))
184
+ uid = stateKeys.find(key => supportedStates[key].includes(geoName))
211
185
 
212
186
  // Territories
213
187
  if (!uid) {
214
- uid = territoryKeys.find((key) => supportedTerritories[key].includes(geoName))
188
+ uid = territoryKeys.find(key => supportedTerritories[key].includes(geoName))
215
189
  }
216
190
 
217
191
  // Cities
218
192
  if (!uid) {
219
- uid = cityKeys.find((key) => key === geoName)
193
+ uid = cityKeys.find(key => key === geoName)
220
194
  }
221
195
  }
222
196
 
@@ -230,20 +204,20 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
230
204
  }
231
205
 
232
206
  // Regions
233
- uid = regionKeys.find((key) => supportedRegions[key].includes(geoName))
207
+ uid = regionKeys.find(key => supportedRegions[key].includes(geoName))
234
208
  }
235
209
 
236
210
  // World Check
237
211
  if ('world' === obj.general.geoType) {
238
212
  const geoName = row[obj.columns.geo.name]
239
213
 
240
- uid = countryKeys.find((key) => supportedCountries[key].includes(geoName))
214
+ uid = countryKeys.find(key => supportedCountries[key].includes(geoName))
241
215
  }
242
216
 
243
217
  // County Check
244
218
  if (('us-county' === obj.general.geoType || 'single-state' === obj.general.geoType) && 'us-geocode' !== obj.general.type) {
245
219
  const fips = row[obj.columns.geo.name]
246
- uid = countyKeys.find((key) => key === fips)
220
+ uid = countyKeys.find(key => key === fips)
247
221
  }
248
222
 
249
223
  if ('us-geocode' === state.general.type) {
@@ -263,9 +237,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
263
237
 
264
238
  const generateRuntimeLegend = useCallback((obj, runtimeData, hash) => {
265
239
  const newLegendMemo = new Map() // Reset memoization
266
- const
267
- primaryCol = obj.columns.primary.name,
268
- isData = obj.general.type === 'data',
240
+ const primaryCol = obj.columns.primary.name,
269
241
  isBubble = obj.general.type === 'bubble',
270
242
  categoricalCol = obj.columns.categorical ? obj.columns.categorical.name : undefined,
271
243
  type = obj.legend.type,
@@ -281,19 +253,19 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
281
253
  let dataSet = obj.legend.unified ? obj.data : Object.values(runtimeData)
282
254
 
283
255
  const colorDistributions = {
284
- 1: [ 1 ],
285
- 2: [ 1, 3 ],
286
- 3: [ 1, 3, 5 ],
287
- 4: [ 0, 2, 4, 6 ],
288
- 5: [ 0, 2, 4, 6, 7 ],
289
- 6: [ 0, 2, 3, 4, 5, 7 ],
290
- 7: [ 0, 2, 3, 4, 5, 6, 7 ],
291
- 8: [ 0, 2, 3, 4, 5, 6, 7, 8 ],
292
- 9: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ],
293
- 10: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
256
+ 1: [1],
257
+ 2: [1, 3],
258
+ 3: [1, 3, 5],
259
+ 4: [0, 2, 4, 6],
260
+ 5: [0, 2, 4, 6, 7],
261
+ 6: [0, 2, 3, 4, 5, 7],
262
+ 7: [0, 2, 3, 4, 5, 6, 7],
263
+ 8: [0, 2, 3, 4, 5, 6, 7, 8],
264
+ 9: [0, 1, 2, 3, 4, 5, 6, 7, 8],
265
+ 10: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
294
266
  }
295
267
 
296
- const applyColorToLegend = (legendIdx) => {
268
+ const applyColorToLegend = legendIdx => {
297
269
  // Default to "bluegreen" color scheme if the passed color isn't valid
298
270
  let mapColorPalette = obj.customColors || colorPalettes[obj.color] || colorPalettes['bluegreen']
299
271
 
@@ -310,7 +282,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
310
282
 
311
283
  // Special Classes (No Data)
312
284
  if (result[legendIdx].special) {
313
- const specialClassColors = chroma.scale([ '#D4D4D4', '#939393' ]).colors(specialClasses)
285
+ const specialClassColors = chroma.scale(['#D4D4D4', '#939393']).colors(specialClasses)
314
286
 
315
287
  return specialClassColors[legendIdx]
316
288
  }
@@ -410,7 +382,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
410
382
  if (undefined === value) continue
411
383
 
412
384
  if (false === uniqueValues.has(value)) {
413
- uniqueValues.set(value, [ hashObj(row) ])
385
+ uniqueValues.set(value, [hashObj(row)])
414
386
  count++
415
387
  } else {
416
388
  uniqueValues.get(value).push(hashObj(row))
@@ -419,16 +391,11 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
419
391
  if (count === 10) break // Can only have 10 categorical items for now
420
392
  }
421
393
 
422
- let sorted = [ ...uniqueValues.keys() ]
394
+ let sorted = [...uniqueValues.keys()]
423
395
 
424
396
  // Apply custom sorting or regular sorting
425
397
  let configuredOrder = obj.legend.categoryValuesOrder ?? []
426
398
 
427
- // Coerce strings to numbers inside configuredOrder property
428
- for(let i = 0; i < configuredOrder.length; i++) {
429
- configuredOrder[i] = numberFromString(configuredOrder[i])
430
- }
431
-
432
399
  if (configuredOrder.length) {
433
400
  sorted.sort((a, b) => {
434
401
  return configuredOrder.indexOf(a) - configuredOrder.indexOf(b)
@@ -438,9 +405,9 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
438
405
  }
439
406
 
440
407
  // Add legend item for each
441
- sorted.forEach((val) => {
408
+ sorted.forEach(val => {
442
409
  result.push({
443
- value: val,
410
+ value: val
444
411
  })
445
412
 
446
413
  let lastIdx = result.length - 1
@@ -500,12 +467,14 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
500
467
 
501
468
  // Sort data for use in equalnumber or equalinterval
502
469
  if (state.general.type !== 'us-geocode') {
503
- dataSet = dataSet.filter(row => typeof row[primaryCol] === 'number').sort((a, b) => {
504
- let aNum = a[primaryCol]
505
- let bNum = b[primaryCol]
470
+ dataSet = dataSet
471
+ .filter(row => typeof row[primaryCol] === 'number')
472
+ .sort((a, b) => {
473
+ let aNum = a[primaryCol]
474
+ let bNum = b[primaryCol]
506
475
 
507
- return aNum - bNum
508
- })
476
+ return aNum - bNum
477
+ })
509
478
  }
510
479
 
511
480
  // Equal Number
@@ -558,8 +527,9 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
558
527
  let colors = colorPalettes[state.color]
559
528
  let colorRange = colors.slice(0, state.legend.numberOfItems)
560
529
 
561
- let scale = d3.scaleQuantile()
562
- .domain([ ...new Set(dataSet.map(item => Math.round(item[state.columns.primary.name]))) ]) // min/max values
530
+ let scale = d3
531
+ .scaleQuantile()
532
+ .domain([...new Set(dataSet.map(item => Math.round(item[state.columns.primary.name])))]) // min/max values
563
533
  .range(colorRange) // set range to our colors array
564
534
 
565
535
  let breaks = scale.quantiles()
@@ -572,8 +542,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
572
542
  }
573
543
 
574
544
  breaks.map((item, index) => {
575
- const setMin = (index) => {
576
- //debugger;
545
+ const setMin = index => {
577
546
  let min = breaks[index]
578
547
 
579
548
  // if first break is a seperated zero, min is zero
@@ -665,7 +634,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
665
634
  for (let i = 0; i < legendNumber; i++) {
666
635
  let interval = Math.abs(dataMax - dataMin) / legendNumber
667
636
 
668
- let min = dataMin + (interval * i)
637
+ let min = dataMin + interval * i
669
638
  let max = min + interval
670
639
 
671
640
  // If this is the last loop, assign actual max of data as the end point
@@ -679,7 +648,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
679
648
 
680
649
  let range = {
681
650
  min: Math.round(min * 100) / 100,
682
- max: Math.round(max * 100) / 100,
651
+ max: Math.round(max * 100) / 100
683
652
  }
684
653
 
685
654
  result.push(range)
@@ -768,11 +737,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
768
737
  if (undefined === row.uid) return false // No UID for this row, we can't use for mapping
769
738
 
770
739
  // When on a single state map filter runtime data by state
771
- if (
772
- !(String(row[obj.columns.geo.name]).substring(0, 2) === obj.general?.statePicked?.fipsCode) &&
773
- obj.general.geoType === 'single-state' &&
774
- obj.general.type !== 'us-geocode'
775
- ) {
740
+ if (!(String(row[obj.columns.geo.name]).substring(0, 2) === obj.general?.statePicked?.fipsCode) && obj.general.geoType === 'single-state' && obj.general.type !== 'us-geocode') {
776
741
  return false
777
742
  }
778
743
 
@@ -828,105 +793,16 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
828
793
  }
829
794
  }
830
795
 
831
- const saveImageAs = (uri, filename) => {
832
- const ie = navigator.userAgent.match(/MSIE\s([\d.]+)/)
833
- const ie11 = navigator.userAgent.match(/Trident\/7.0/) && navigator.userAgent.match(/rv:11/)
834
- const ieEdge = navigator.userAgent.match(/Edge/g)
835
- const ieVer = (ie ? ie[1] : (ie11 ? 11 : (ieEdge ? 12 : -1)))
836
-
837
- if (ieVer > -1) {
838
- const fileAsBlob = new Blob([ uri ], {
839
- type: 'image/png'
840
- })
841
- window.navigator.msSaveBlob(fileAsBlob, filename)
842
- } else {
843
- const link = document.createElement('a')
844
- if (typeof link.download === 'string') {
845
- link.href = uri
846
- link.download = filename
847
- link.onclick = (e) => document.body.removeChild(e.target)
848
- document.body.appendChild(link)
849
- link.click()
850
- } else {
851
- window.open(uri)
852
- }
853
- }
854
- }
855
-
856
- const generateMedia = (target, type) => {
857
- // Convert SVG to canvas
858
- const baseSvg = mapSvg.current.querySelector('.rsm-svg')
859
-
860
- const ratio = baseSvg.getBoundingClientRect().height / baseSvg.getBoundingClientRect().width
861
- const calcHeight = ratio * 1440
862
- const xmlSerializer = new XMLSerializer()
863
- const svgStr = xmlSerializer.serializeToString(baseSvg)
864
- const options = { log: false, ignoreMouse: true }
865
- const canvas = document.createElement('canvas')
866
- const ctx = canvas.getContext('2d')
867
- ctx.canvas.width = 1440
868
- ctx.canvas.height = calcHeight
869
- const canvg = Canvg.fromString(ctx, svgStr, options)
870
- canvg.start()
871
-
872
- // Generate DOM <img> from svg data
873
- const generatedImage = document.createElement('img')
874
- generatedImage.src = canvas.toDataURL('image/png')
875
- generatedImage.style.width = '100%'
876
- generatedImage.style.height = 'auto'
877
-
878
- baseSvg.style.display = 'none' // Hide default SVG during media generation
879
- baseSvg.parentNode.insertBefore(generatedImage, baseSvg.nextSibling) // Insert png generated from canvas of svg
880
-
881
- // Construct filename with timestamp
882
- const date = new Date()
883
- const filename = state.general.title.replace(/\s+/g, '-').toLowerCase() + '-' + date.getDate() + date.getMonth() + date.getFullYear()
884
-
885
- switch (type) {
886
- case 'image':
887
- return html2canvas(target, {
888
- allowTaint: true,
889
- backgroundColor: '#ffffff',
890
- width: 1440,
891
- windowWidth: 1440,
892
- scale: 1,
893
- logging: false
894
- }).then(canvas => {
895
- saveImageAs(canvas.toDataURL(), filename + '.png')
896
- }).then(() => {
897
- generatedImage.remove() // Remove generated png
898
- baseSvg.style.display = null // Re-display initial svg map
899
- })
900
- case 'pdf':
901
- let opt = {
902
- margin: 0.2,
903
- filename: filename + '.pdf',
904
- image: { type: 'png' },
905
- html2canvas: { scale: 2, logging: false },
906
- jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
907
- }
908
-
909
- html2pdf().set(opt).from(target).save().then(() => {
910
- generatedImage.remove() // Remove generated png
911
- baseSvg.style.display = null // Re-display initial svg map
912
- })
913
- break
914
- default:
915
- console.warn('generateMedia param 2 type must be \'image\' or \'pdf\'')
916
- break
917
- }
918
- }
919
-
920
796
  const changeFilterActive = async (idx, activeValue) => {
921
797
  // Reset active legend toggles
922
798
  resetLegendToggles()
923
799
 
924
800
  try {
925
- const isEmpty = (obj) => {
801
+ const isEmpty = obj => {
926
802
  return Object.keys(obj).length === 0
927
803
  }
928
804
 
929
- let filters = [ ...runtimeFilters ]
805
+ let filters = [...runtimeFilters]
930
806
 
931
807
  filters[idx] = { ...filters[idx] }
932
808
  filters[idx].active = activeValue
@@ -988,7 +864,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
988
864
  return formattedValue
989
865
  }
990
866
 
991
- const applyLegendToRow = (rowObj) => {
867
+ const applyLegendToRow = rowObj => {
992
868
  try {
993
869
  if (!rowObj) throw new Error('COVE: No rowObj in applyLegendToRow')
994
870
  // Navigation map
@@ -1013,16 +889,11 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1013
889
  }
1014
890
 
1015
891
  const applyTooltipsToGeo = (geoName, row, returnType = 'string') => {
1016
-
1017
- if(!row) return;
892
+ if (!row) return
1018
893
  let toolTipText = ''
1019
894
 
1020
895
  // Adds geo label, ie State: Georgia
1021
- let stateOrCounty = state.general.geoType === 'us'
1022
- ? 'State: '
1023
- : (state.general.geoType === 'us-county' || state.general.geoType === 'single-state')
1024
- ? 'County: '
1025
- : ''
896
+ let stateOrCounty = state.general.geoType === 'us' ? 'State: ' : state.general.geoType === 'us-county' || state.general.geoType === 'single-state' ? 'County: ' : ''
1026
897
 
1027
898
  if (state.general.geoType === 'us-county' && state.general.type !== 'us-geocode') {
1028
899
  let stateFipsCode = row[state.columns.geo.name].substring(0, 2)
@@ -1036,7 +907,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1036
907
  if (('data' === state.general.type || state.general.type === 'bubble' || state.general.type === 'us-geocode') && undefined !== row) {
1037
908
  toolTipText += `<dl>`
1038
909
 
1039
- Object.keys(state.columns).forEach((columnKey) => {
910
+ Object.keys(state.columns).forEach(columnKey => {
1040
911
  const column = state.columns[columnKey]
1041
912
 
1042
913
  if (true === column.tooltip) {
@@ -1057,7 +928,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1057
928
  value = displayDataAsText(row[column.name], columnKey)
1058
929
  }
1059
930
 
1060
- if (0 < value.length) { // Only spit out the tooltip if there's a value there
931
+ if (0 < value.length) {
932
+ // Only spit out the tooltip if there's a value there
1061
933
  toolTipText += state.general.hidePrimaryColumnInTooltip ? `<div><dd>${value}</dd></div>` : `<div><dt>${label}</dt><dd>${value}</dd></div>`
1062
934
  }
1063
935
  }
@@ -1067,23 +939,47 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1067
939
 
1068
940
  // We convert the markup into JSX and add a navigation link if it's going into a modal.
1069
941
  if ('jsx' === returnType) {
1070
- toolTipText = [ (<div key="modal-content">{parse(toolTipText)}</div>) ]
942
+ toolTipText = [<div key='modal-content'>{parse(toolTipText)}</div>]
1071
943
 
1072
944
  if (state.columns.hasOwnProperty('navigate') && row[state.columns.navigate.name]) {
1073
- toolTipText.push((<span className="navigation-link" key="modal-navigation-link" onClick={() => navigationHandler(row[state.columns.navigate.name])}>{state.tooltips.linkLabel}<ExternalIcon className="inline-icon ml-1"/></span>))
945
+ toolTipText.push(
946
+ <span className='navigation-link' key='modal-navigation-link' onClick={() => navigationHandler(row[state.columns.navigate.name])}>
947
+ {state.tooltips.linkLabel}
948
+ <ExternalIcon className='inline-icon ml-1' />
949
+ </span>
950
+ )
1074
951
  }
1075
952
  }
1076
953
 
1077
954
  return toolTipText
1078
955
  }
1079
956
 
1080
- const titleCase = (string) => {
1081
- return string.split(' ').map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase()).join(' ')
957
+ const titleCase = string => {
958
+ // if hyphen found, then split, uppercase each word, and put back together
959
+ if (string.includes('–') || string.includes('-')) {
960
+ let dashSplit = string.includes('–') ? string.split('–') : string.split('-') // determine hyphen or en dash to split on
961
+ let splitCharacter = string.includes('–') ? '–' : '-' // print hyphen or en dash later on.
962
+ let frontSplit = dashSplit[0]
963
+ .split(' ')
964
+ .map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase())
965
+ .join(' ')
966
+ let backSplit = dashSplit[1]
967
+ .split(' ')
968
+ .map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase())
969
+ .join(' ')
970
+ return frontSplit + splitCharacter + backSplit
971
+ } else {
972
+ // just return with each word upper cased
973
+ return string
974
+ .split(' ')
975
+ .map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase())
976
+ .join(' ')
977
+ }
1082
978
  }
1083
979
 
1084
980
  // This resets all active legend toggles.
1085
981
  const resetLegendToggles = async () => {
1086
- let newLegend = [ ...runtimeLegend ]
982
+ let newLegend = [...runtimeLegend]
1087
983
 
1088
984
  newLegend.forEach(legendItem => {
1089
985
  delete legendItem.disabled
@@ -1092,7 +988,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1092
988
  setRuntimeLegend(newLegend)
1093
989
  }
1094
990
 
1095
- const formatLegendLocation = (key) => {
991
+ const formatLegendLocation = key => {
1096
992
  let value = key
1097
993
  let formattedName = ''
1098
994
  let stateName = stateFipsToTwoDigit[key.substring(0, 2)]
@@ -1109,9 +1005,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1109
1005
  }
1110
1006
 
1111
1007
  // Attempts to find the corresponding value
1112
- const displayGeoName = (key) => {
1008
+ const displayGeoName = key => {
1113
1009
  let value = key
1114
-
1115
1010
  // Map to first item in values array which is the preferred label
1116
1011
  if (stateKeys.includes(value)) {
1117
1012
  value = titleCase(supportedStates[key][0])
@@ -1132,9 +1027,9 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1132
1027
  const dict = {
1133
1028
  'Washington D.C.': 'District of Columbia',
1134
1029
  'WASHINGTON DC': 'District of Columbia',
1135
- 'DC': 'District of Columbia',
1030
+ DC: 'District of Columbia',
1136
1031
  'WASHINGTON DC.': 'District of Columbia',
1137
- 'Congo': 'Republic of the Congo'
1032
+ Congo: 'Republic of the Congo'
1138
1033
  }
1139
1034
 
1140
1035
  if (true === Object.keys(dict).includes(value)) {
@@ -1143,7 +1038,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1143
1038
  return titleCase(value)
1144
1039
  }
1145
1040
 
1146
- const navigationHandler = (urlString) => {
1041
+ const navigationHandler = urlString => {
1147
1042
  // Call custom navigation method if passed
1148
1043
  if (customNavigationHandler) {
1149
1044
  customNavigationHandler(urlString)
@@ -1182,12 +1077,10 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1182
1077
  }
1183
1078
  }
1184
1079
 
1185
- const validateFipsCodeLength = (newState) => {
1186
- if (newState.general.geoType === 'us-county' || newState.general.geoType === 'single-state' || newState.general.geoType === 'us' && newState?.data) {
1187
-
1080
+ const validateFipsCodeLength = newState => {
1081
+ if (newState.general.geoType === 'us-county' || newState.general.geoType === 'single-state' || (newState.general.geoType === 'us' && newState?.data)) {
1188
1082
  newState?.data.forEach(dataPiece => {
1189
1083
  if (dataPiece[newState.columns.geo.name]) {
1190
-
1191
1084
  if (!isNaN(parseInt(dataPiece[newState.columns.geo.name])) && dataPiece[newState.columns.geo.name].length === 4) {
1192
1085
  dataPiece[newState.columns.geo.name] = 0 + dataPiece[newState.columns.geo.name]
1193
1086
  }
@@ -1234,7 +1127,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1234
1127
  }
1235
1128
  }
1236
1129
 
1237
- const loadConfig = async (configObj) => {
1130
+ const loadConfig = async configObj => {
1238
1131
  // Set loading flag
1239
1132
  if (!loading) setLoading(true)
1240
1133
 
@@ -1244,16 +1137,15 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1244
1137
  ...configObj
1245
1138
  }
1246
1139
 
1140
+ // If a dataUrl property exists, always pull from that.
1141
+ if (newState.dataUrl) {
1142
+ if (newState.dataUrl[0] === '/') {
1143
+ newState.dataUrl = 'http://' + hostname + newState.dataUrl
1144
+ }
1247
1145
 
1248
- // If a dataUrl property exists, always pull from that.
1249
- if (newState.dataUrl) {
1250
- if(newState.dataUrl[0] === '/') {
1251
- newState.dataUrl = 'http://' + hostname + newState.dataUrl
1252
- }
1253
-
1254
- // handle urls with spaces in the name.
1255
- if (newState.dataUrl) newState.dataUrl = encodeURI(`${newState.dataUrl}?v=${cacheBustingString()}`)
1256
- let newData = await fetchRemoteData(newState.dataUrl )
1146
+ // handle urls with spaces in the name.
1147
+ if (newState.dataUrl) newState.dataUrl = encodeURI(`${newState.dataUrl}`)
1148
+ let newData = await fetchRemoteData(newState.dataUrl, 'map')
1257
1149
 
1258
1150
  if (newData && newState.dataDescription) {
1259
1151
  newData = transform.autoStandardize(newData)
@@ -1268,10 +1160,10 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1268
1160
  // This code goes through and adds the defaults for every property declaring in the initial state at the top.
1269
1161
  // This allows you to easily add new properties to the config without having to worry about accounting for backwards compatibility.
1270
1162
  // Right now this does not work recursively -- only on first and second level properties. So state -> prop1 -> childprop1
1271
- Object.keys(newState).forEach((key) => {
1163
+ Object.keys(newState).forEach(key => {
1272
1164
  if ('object' === typeof newState[key] && false === Array.isArray(newState[key])) {
1273
1165
  if (initialState[key]) {
1274
- Object.keys(initialState[key]).forEach((property) => {
1166
+ Object.keys(initialState[key]).forEach(property => {
1275
1167
  if (undefined === newState[key][property]) {
1276
1168
  newState[key][property] = initialState[key][property]
1277
1169
  }
@@ -1323,14 +1215,14 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1323
1215
  publish('cove_loaded', { config: state })
1324
1216
  setCoveLoadedHasRan(true)
1325
1217
  }
1326
- }, [ state, container ])
1218
+ }, [state, container])
1327
1219
 
1328
1220
  useEffect(() => {
1329
1221
  if (state.data) {
1330
1222
  let newData = generateRuntimeData(state)
1331
1223
  setRuntimeData(newData)
1332
1224
  }
1333
- }, [ state.general.statePicked ])
1225
+ }, [state.general.statePicked])
1334
1226
 
1335
1227
  // When geotype changes
1336
1228
  useEffect(() => {
@@ -1338,7 +1230,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1338
1230
  if (state.data && state.columns.geo.name) {
1339
1231
  addUIDs(state, state.columns.geo.name)
1340
1232
  }
1341
- }, [ state ])
1233
+ }, [state])
1342
1234
 
1343
1235
  useEffect(() => {
1344
1236
  // UID
@@ -1368,7 +1260,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1368
1260
  specialClasses: state.legend.specialClasses,
1369
1261
  geoType: state.general.geoType,
1370
1262
  data: state.data,
1371
- ...runtimeLegend
1263
+ ...runtimeLegend,
1264
+ ...runtimeFilters
1372
1265
  })
1373
1266
 
1374
1267
  const hashData = hashObj({
@@ -1379,7 +1272,8 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1379
1272
  primary: state.columns.primary.name,
1380
1273
  data: state.data,
1381
1274
  ...runtimeFilters,
1382
- mapPosition: state.mapPosition
1275
+ mapPosition: state.mapPosition,
1276
+ ...runtimeFilters
1383
1277
  })
1384
1278
 
1385
1279
  // Data
@@ -1394,8 +1288,7 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1394
1288
  const legend = generateRuntimeLegend(state, newRuntimeData || runtimeData, hashLegend)
1395
1289
  setRuntimeLegend(legend)
1396
1290
  }
1397
-
1398
- }, [ state ])
1291
+ }, [state])
1399
1292
 
1400
1293
  useEffect(() => {
1401
1294
  const hashLegend = hashObj({
@@ -1415,13 +1308,12 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1415
1308
  const legend = generateRuntimeLegend(state, runtimeData)
1416
1309
  setRuntimeLegend(legend)
1417
1310
  }
1418
-
1419
- }, [ runtimeData ])
1311
+ }, [runtimeData])
1420
1312
 
1421
1313
  if (config) {
1422
1314
  useEffect(() => {
1423
1315
  loadConfig(config)
1424
- }, [ config.data ])
1316
+ }, [config.data])
1425
1317
  }
1426
1318
 
1427
1319
  // Destructuring for more readable JSX
@@ -1429,24 +1321,14 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1429
1321
  const { title = '', subtext = '' } = general
1430
1322
 
1431
1323
  // Outer container classes
1432
- let outerContainerClasses = [
1433
- 'cdc-open-viz-module',
1434
- 'cdc-map-outer-container',
1435
- currentViewport
1436
- ]
1324
+ let outerContainerClasses = ['cdc-open-viz-module', 'cdc-map-outer-container', currentViewport]
1437
1325
 
1438
1326
  if (className) {
1439
1327
  outerContainerClasses.push(className)
1440
1328
  }
1441
1329
 
1442
1330
  // Map container classes
1443
- let mapContainerClasses = [
1444
- 'map-container',
1445
- state.legend.position,
1446
- state.general.type,
1447
- state.general.geoType,
1448
- 'outline-none'
1449
- ]
1331
+ let mapContainerClasses = ['map-container', state.legend.position, state.general.type, state.general.geoType, 'outline-none']
1450
1332
 
1451
1333
  if (modal) {
1452
1334
  mapContainerClasses.push('modal-background')
@@ -1479,10 +1361,13 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1479
1361
  setPosition,
1480
1362
  setSharedFilterValue,
1481
1363
  hasZoom: state.general.allowMapZoom,
1482
- handleMapAriaLabels
1364
+ handleMapAriaLabels,
1365
+ runtimeFilters,
1366
+ setRuntimeFilters,
1367
+ innerContainerRef
1483
1368
  }
1484
1369
 
1485
- if (!mapProps.data || !state.data) return <Loading/>
1370
+ if (!mapProps.data || !state.data) return <Loading />
1486
1371
 
1487
1372
  const hasDataTable = state.runtime.editorErrorMessage.length === 0 && true === dataTable.forceDisplay && general.type !== 'navigation' && false === loading
1488
1373
 
@@ -1511,183 +1396,124 @@ const CdcMap = ({ className, config, navigationHandler: customNavigationHandler,
1511
1396
  const tabId = handleMapTabbing()
1512
1397
 
1513
1398
  return (
1514
- <div className={outerContainerClasses.join(' ')} ref={outerContainerRef}>
1515
- {isEditor && (
1516
- <EditorPanel
1517
- isDashboard={isDashboard}
1518
- state={state}
1519
- setState={setState}
1520
- loadConfig={loadConfig}
1521
- setParentConfig={setConfig}
1522
- setRuntimeFilters={setRuntimeFilters}
1523
- runtimeFilters={runtimeFilters}
1524
- runtimeLegend={runtimeLegend}
1525
- columnsInData={Object.keys(state.data[0])}
1526
- />
1527
- )}
1528
- {!runtimeData.init && (general.type === 'navigation' || runtimeLegend) && <section className={`cdc-map-inner-container ${currentViewport}`} aria-label={'Map: ' + title}>
1529
- {!window.matchMedia('(any-hover: none)').matches && 'hover' === tooltips.appearanceType && (
1530
- <ReactTooltip
1531
- id="tooltip"
1532
- place="right"
1533
- type="light"
1534
- html={true}
1535
- className={tooltips.capitalizeLabels ? 'capitalize tooltip' : 'tooltip'}
1536
- />
1537
- )}
1538
- {state.general.title &&
1539
- <header className={general.showTitle === true ? 'visible' : 'hidden'} {...(!general.showTitle || !state.general.title ? { 'aria-hidden': true } : { 'aria-hidden': false })}>
1540
- <div role="heading" className={'map-title ' + general.headerColor} tabIndex="0" aria-level="2">
1541
- <sup>{general.superTitle}</sup>
1542
- <div>{parse(title)}</div>
1543
- </div>
1544
- </header>
1545
- }
1546
-
1547
- <div>
1548
- {general.introText && <section className="introText">{parse(general.introText)}</section>}
1549
- </div>
1399
+ <Context.Provider value={mapProps}>
1400
+ <div className={outerContainerClasses.join(' ')} ref={outerContainerRef} data-download-id={imageId}>
1401
+ {isEditor && <EditorPanel isDashboard={isDashboard} state={state} setState={setState} loadConfig={loadConfig} setParentConfig={setConfig} setRuntimeFilters={setRuntimeFilters} runtimeFilters={runtimeFilters} runtimeLegend={runtimeLegend} columnsInData={Object.keys(state.data[0])} />}
1402
+ {!runtimeData.init && (general.type === 'navigation' || runtimeLegend) && (
1403
+ <section className={`cdc-map-inner-container ${currentViewport}`} aria-label={'Map: ' + title} ref={innerContainerRef}>
1404
+ {!window.matchMedia('(any-hover: none)').matches && 'hover' === tooltips.appearanceType && <ReactTooltip id='tooltip' place='right' type='light' html={true} className={tooltips.capitalizeLabels ? 'capitalize tooltip' : 'tooltip'} />}
1405
+ {state.general.title && (
1406
+ <header className={general.showTitle === true ? 'visible' : 'hidden'} {...(!general.showTitle || !state.general.title ? { 'aria-hidden': true } : { 'aria-hidden': false })}>
1407
+ <div role='heading' className={'map-title ' + general.headerColor} tabIndex='0' aria-level='2'>
1408
+ <sup>{general.superTitle}</sup>
1409
+ <div>{parse(title)}</div>
1410
+ </div>
1411
+ </header>
1412
+ )}
1550
1413
 
1551
- <section
1552
- role="button"
1553
- tabIndex="0"
1554
- className={mapContainerClasses.join(' ')}
1555
- onClick={(e) => closeModal(e)}
1556
- onKeyDown={(e) => {
1557
- if (e.keyCode === 13) {
1558
- closeModal(e)
1559
- }
1560
- }}
1561
- >
1562
- {general.showDownloadMediaButton === true && (
1563
- <div className="map-downloads" data-html2canvas-ignore>
1564
- <div className="map-downloads__ui btn-group">
1565
- <button
1566
- className="btn"
1567
- title="Download Map as Image"
1568
- onClick={() => generateMedia(outerContainerRef.current, 'image')}
1569
- >
1570
- <DownloadImg className="btn__icon" title="Download Map as Image"/>
1571
- </button>
1572
- <button
1573
- className="btn"
1574
- title="Download Map as PDF"
1575
- onClick={() => generateMedia(outerContainerRef.current, 'pdf')}
1576
- >
1577
- <DownloadPdf className="btn__icon" title="Download Map as PDF"/>
1578
- </button>
1579
- </div>
1580
- </div>
1581
- )}
1582
-
1583
- <a id="skip-geo-container" className="cdcdataviz-sr-only-focusable" href={tabId}>
1584
- Skip Over Map Container
1585
- </a>
1586
-
1587
- <section className="geography-container outline-none" ref={mapSvg} tabIndex="0">
1588
- {currentViewport && (
1589
- <section className="geography-container" ref={mapSvg}>
1590
- {modal && (
1591
- <Modal
1592
- type={general.type}
1593
- viewport={currentViewport}
1594
- applyTooltipsToGeo={applyTooltipsToGeo}
1595
- applyLegendToRow={applyLegendToRow}
1596
- capitalize={state.tooltips.capitalizeLabels}
1597
- content={modal}
1598
- />
1599
- )}
1600
- {'single-state' === general.geoType && (
1601
- <SingleStateMap supportedTerritories={supportedTerritories} {...mapProps} />
1602
- )}
1603
- {('us' === general.geoType && 'us-geocode' !== state.general.type) && (
1604
- <UsaMap supportedTerritories={supportedTerritories} {...mapProps} />
1605
- )}
1606
- {'us-region' === general.geoType && (
1607
- <UsaRegionMap supportedTerritories={supportedTerritories} {...mapProps} />
1414
+ <div>{general.introText && <section className='introText'>{parse(general.introText)}</section>}</div>
1415
+
1416
+ <Filters />
1417
+
1418
+ <div
1419
+ role='button'
1420
+ tabIndex='0'
1421
+ className={mapContainerClasses.join(' ')}
1422
+ onClick={e => closeModal(e)}
1423
+ onKeyDown={e => {
1424
+ if (e.keyCode === 13) {
1425
+ closeModal(e)
1426
+ }
1427
+ }}
1428
+ >
1429
+ <a id='skip-geo-container' className='cdcdataviz-sr-only-focusable' href={tabId}>
1430
+ Skip Over Map Container
1431
+ </a>
1432
+
1433
+ <section className='geography-container outline-none' ref={mapSvg} tabIndex='0'>
1434
+ {currentViewport && (
1435
+ <section className='geography-container' ref={mapSvg}>
1436
+ {modal && <Modal type={general.type} viewport={currentViewport} applyTooltipsToGeo={applyTooltipsToGeo} applyLegendToRow={applyLegendToRow} capitalize={state.tooltips.capitalizeLabels} content={modal} />}
1437
+ {'single-state' === general.geoType && <SingleStateMap supportedTerritories={supportedTerritories} {...mapProps} />}
1438
+ {'us' === general.geoType && 'us-geocode' !== state.general.type && <UsaMap supportedTerritories={supportedTerritories} {...mapProps} />}
1439
+ {'us-region' === general.geoType && <UsaRegionMap supportedTerritories={supportedTerritories} {...mapProps} />}
1440
+ {'world' === general.geoType && <WorldMap supportedCountries={supportedCountries} {...mapProps} />}
1441
+ {'us-county' === general.geoType && <CountyMap supportedCountries={supportedCountries} {...mapProps} />}
1442
+ {'data' === general.type && logo && <img src={logo} alt='' className='map-logo' />}
1443
+ </section>
1608
1444
  )}
1609
- {'world' === general.geoType && (
1610
- <WorldMap supportedCountries={supportedCountries} {...mapProps} />
1611
- )}
1612
- {('us-county' === general.geoType) && (
1613
- <CountyMap
1614
- supportedCountries={supportedCountries}
1615
- {...mapProps}
1616
- />
1617
- )}
1618
- {'data' === general.type && logo && <img src={logo} alt="" className="map-logo"/>}
1619
1445
  </section>
1620
1446
 
1621
- )}
1622
- </section>
1447
+ {general.showSidebar && 'navigation' !== general.type && (
1448
+ <Sidebar
1449
+ viewport={currentViewport}
1450
+ legend={state.legend}
1451
+ runtimeLegend={runtimeLegend}
1452
+ setRuntimeLegend={setRuntimeLegend}
1453
+ runtimeFilters={runtimeFilters}
1454
+ columns={state.columns}
1455
+ sharing={state.sharing}
1456
+ prefix={state.columns.primary.prefix}
1457
+ suffix={state.columns.primary.suffix}
1458
+ setState={setState}
1459
+ resetLegendToggles={resetLegendToggles}
1460
+ changeFilterActive={changeFilterActive}
1461
+ setAccessibleStatus={setAccessibleStatus}
1462
+ displayDataAsText={displayDataAsText}
1463
+ />
1464
+ )}
1465
+ </div>
1623
1466
 
1624
- {general.showSidebar && 'navigation' !== general.type && (
1625
- <Sidebar
1626
- viewport={currentViewport}
1627
- legend={state.legend}
1628
- runtimeLegend={runtimeLegend}
1629
- setRuntimeLegend={setRuntimeLegend}
1630
- runtimeFilters={runtimeFilters}
1631
- columns={state.columns}
1632
- sharing={state.sharing}
1633
- prefix={state.columns.primary.prefix}
1634
- suffix={state.columns.primary.suffix}
1635
- setState={setState}
1636
- resetLegendToggles={resetLegendToggles}
1637
- changeFilterActive={changeFilterActive}
1638
- setAccessibleStatus={setAccessibleStatus}
1639
- displayDataAsText={displayDataAsText}
1640
- />
1641
- )}
1642
- </section>
1643
-
1644
- {'navigation' === general.type && (
1645
- <NavigationMenu
1646
- mapTabbingID={tabId}
1647
- displayGeoName={displayGeoName}
1648
- data={runtimeData}
1649
- options={general}
1650
- columns={state.columns}
1651
- navigationHandler={(val) => navigationHandler(val)}
1652
- />
1653
- )}
1467
+ {'navigation' === general.type && <NavigationMenu mapTabbingID={tabId} displayGeoName={displayGeoName} data={runtimeData} options={general} columns={state.columns} navigationHandler={val => navigationHandler(val)} />}
1468
+
1469
+ {link && link}
1470
+
1471
+ {subtext.length > 0 && <p className='subtext'>{parse(subtext)}</p>}
1472
+
1473
+ <CoveMediaControls.Section classes={['download-buttons']}>
1474
+ {state.general.showDownloadImgButton && <CoveMediaControls.Button text='Download Image' title='Download Chart as Image' type='image' state={state} elementToCapture={imageId} />}
1475
+ {state.general.showDownloadPdfButton && <CoveMediaControls.Button text='Download PDF' title='Download Chart as PDF' type='pdf' state={state} elementToCapture={imageId} />}
1476
+ </CoveMediaControls.Section>
1477
+
1478
+ {state.runtime.editorErrorMessage.length === 0 && true === dataTable.forceDisplay && general.type !== 'navigation' && false === loading && (
1479
+ <DataTable
1480
+ state={state}
1481
+ rawData={state.data}
1482
+ navigationHandler={navigationHandler}
1483
+ expandDataTable={general.expandDataTable}
1484
+ headerColor={general.headerColor}
1485
+ columns={state.columns}
1486
+ showDownloadButton={general.showDownloadButton}
1487
+ runtimeLegend={runtimeLegend}
1488
+ runtimeData={runtimeData}
1489
+ displayDataAsText={displayDataAsText}
1490
+ displayGeoName={displayGeoName}
1491
+ applyLegendToRow={applyLegendToRow}
1492
+ tableTitle={dataTable.title}
1493
+ indexTitle={dataTable.indexLabel}
1494
+ mapTitle={general.title}
1495
+ viewport={currentViewport}
1496
+ formatLegendLocation={formatLegendLocation}
1497
+ setFilteredCountryCode={setFilteredCountryCode}
1498
+ tabbingId={tabId}
1499
+ showDownloadImgButton={state.general.showDownloadImgButton}
1500
+ showDownloadPdfButton={state.general.showDownloadPdfButton}
1501
+ innerContainerRef={innerContainerRef}
1502
+ outerContainerRef={outerContainerRef}
1503
+ imageRef={imageId}
1504
+ />
1505
+ )}
1654
1506
 
1655
- {link && link}
1656
-
1657
- {subtext.length > 0 && <p className="subtext">{parse(subtext)}</p>}
1658
-
1659
- {state.runtime.editorErrorMessage.length === 0 && true === dataTable.forceDisplay && general.type !== 'navigation' && false === loading && (
1660
- <DataTable
1661
- state={state}
1662
- rawData={state.data}
1663
- navigationHandler={navigationHandler}
1664
- expandDataTable={general.expandDataTable}
1665
- headerColor={general.headerColor}
1666
- columns={state.columns}
1667
- showDownloadButton={general.showDownloadButton}
1668
- runtimeLegend={runtimeLegend}
1669
- runtimeData={runtimeData}
1670
- displayDataAsText={displayDataAsText}
1671
- displayGeoName={displayGeoName}
1672
- applyLegendToRow={applyLegendToRow}
1673
- tableTitle={dataTable.title}
1674
- indexTitle={dataTable.indexLabel}
1675
- mapTitle={general.title}
1676
- viewport={currentViewport}
1677
- formatLegendLocation={formatLegendLocation}
1678
- setFilteredCountryCode={setFilteredCountryCode}
1679
- tabbingId={tabId}
1680
- />
1507
+ {general.footnotes && <section className='footnotes'>{parse(general.footnotes)}</section>}
1508
+ </section>
1681
1509
  )}
1682
1510
 
1683
- {general.footnotes && <section className="footnotes">{parse(general.footnotes)}</section>}
1684
- </section>}
1685
-
1686
- <div aria-live="assertive" className="cdcdataviz-sr-only">
1687
- {accessibleStatus}
1511
+ <div aria-live='assertive' className='cdcdataviz-sr-only'>
1512
+ {accessibleStatus}
1513
+ </div>
1688
1514
  </div>
1689
- </div>
1515
+ </Context.Provider>
1690
1516
  )
1691
1517
  }
1692
1518
 
1693
- export default memo(CdcMap)
1519
+ export default CdcMap