@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
@@ -1,19 +1,19 @@
1
- import {useState, useEffect} from 'react'
1
+ import { useState, useEffect } from 'react'
2
2
  // Use for accessibility testing
3
3
  const useActiveElement = () => {
4
- const [active, setActive] = useState(document.activeElement);
4
+ const [active, setActive] = useState(document.activeElement)
5
5
 
6
- const handleFocusIn = (e) => {
7
- setActive(document.activeElement);
8
- }
6
+ const handleFocusIn = e => {
7
+ setActive(document.activeElement)
8
+ }
9
9
 
10
- useEffect(() => {
11
- document.addEventListener('focusin', handleFocusIn)
12
- return () => {
13
- document.removeEventListener('focusin', handleFocusIn)
14
- };
15
- }, [])
10
+ useEffect(() => {
11
+ document.addEventListener('focusin', handleFocusIn)
12
+ return () => {
13
+ document.removeEventListener('focusin', handleFocusIn)
14
+ }
15
+ }, [])
16
16
 
17
- return active;
17
+ return active
18
18
  }
19
- export default useActiveElement;
19
+ export default useActiveElement
@@ -1,96 +1,88 @@
1
- import { useEffect, useReducer } from 'react';
1
+ import { useEffect, useReducer } from 'react'
2
2
 
3
- // constants
4
- const SEQUENTIAL = 'SEQUENTIAL';
5
- const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE';
6
- export const GET_PALETTE = 'GET_PALETTE';
3
+ // constants
4
+ const SEQUENTIAL = 'SEQUENTIAL'
5
+ const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE'
6
+ export const GET_PALETTE = 'GET_PALETTE'
7
7
 
8
-
9
- // types & interfaces
8
+ // types & interfaces
10
9
  interface State {
11
- readonly filteredPallets:string[]
12
- readonly filteredQualitative:string[]
13
- readonly isPaletteReversed:boolean;
14
- paletteName:string|undefined
15
- }
16
- interface Action<Palettes> {
17
- type:
18
- | 'SEQUENTIAL'
19
- | 'SEQUENTIAL_REVERSE'
20
- | 'GET_PALETTE'
21
- payload: Palettes;
22
- paletteName?:string
23
- };
10
+ readonly filteredPallets: string[]
11
+ readonly filteredQualitative: string[]
12
+ readonly isPaletteReversed: boolean
13
+ paletteName: string | undefined
14
+ }
15
+ interface Action<Palettes> {
16
+ type: 'SEQUENTIAL' | 'SEQUENTIAL_REVERSE' | 'GET_PALETTE'
17
+ payload: Palettes
18
+ paletteName?: string
19
+ }
24
20
 
25
21
  // create initial state
26
- const initialState:State = {
27
- filteredPallets: [],
28
- isPaletteReversed:false,
29
- filteredQualitative: [],
30
- paletteName:undefined
31
- };
22
+ const initialState: State = {
23
+ filteredPallets: [],
24
+ isPaletteReversed: false,
25
+ filteredQualitative: [],
26
+ paletteName: undefined
27
+ }
32
28
 
33
29
  // create reducer function to handle multiple states & manupilate with each state
34
- function reducer<T> (state:State,action:Action<T>):State{ // <T> refers to generic type
35
- const palletNamesArr:string[] = Object.keys(action.payload); // action.payload === colorPalettes object
36
- let reverseRegex = new RegExp('reverse$'); // matches a string that ends in with "reverse".
37
- let qualitativeRegex = new RegExp('^qualitative'); //matches any string that starts with "qualitative".
38
- let paletteName:string ='';
39
- switch(action.type){
30
+ function reducer<T>(state: State, action: Action<T>): State {
31
+ // <T> refers to generic type
32
+ const palletNamesArr: string[] = Object.keys(action.payload) // action.payload === colorPalettes object
33
+ let reverseRegex = new RegExp('reverse$') // matches a string that ends in with "reverse".
34
+ let qualitativeRegex = new RegExp('^qualitative') //matches any string that starts with "qualitative".
35
+ let paletteName: string = ''
36
+ switch (action.type) {
40
37
  case GET_PALETTE:
41
38
  // this case runs first time when page loads and then every time when color.state changes.It is mounted insude of useEffect on Editors Panel
42
39
  // action.palletName is a string type and equals to state.color which is inisde Editors Panel.
43
- return {...state,paletteName:action.paletteName}
44
- case SEQUENTIAL:
45
- paletteName = String(state.paletteName).endsWith('reverse') ? String(state.paletteName).substring(0,state.paletteName.length-7):String(state.paletteName)
46
- const qualitative :string[]= palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && (!name.match(reverseRegex) && !name.includes('qualitative9')));
47
- const sequential:string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && !name.match(reverseRegex));
48
-
49
- return { ...state, filteredPallets: sequential,filteredQualitative:qualitative, paletteName:paletteName,isPaletteReversed:false};
50
-
51
- case SEQUENTIAL_REVERSE:
52
- paletteName= state.paletteName && String(state.paletteName).concat('reverse');
53
- const qualitativeReverse:string[] = palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && name.match(reverseRegex));
54
- const sequentialReverse:string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && name.match(reverseRegex));
55
-
56
- return { ...state, filteredQualitative:qualitativeReverse, filteredPallets: sequentialReverse ,paletteName:paletteName,isPaletteReversed:true};
57
- default : return state;
40
+ return { ...state, paletteName: action.paletteName }
41
+ case SEQUENTIAL:
42
+ paletteName = String(state.paletteName).endsWith('reverse') ? String(state.paletteName).substring(0, state.paletteName.length - 7) : String(state.paletteName)
43
+ const qualitative: string[] = palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && !name.match(reverseRegex) && !name.includes('qualitative9'))
44
+ const sequential: string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && !name.match(reverseRegex))
45
+
46
+ return { ...state, filteredPallets: sequential, filteredQualitative: qualitative, paletteName: paletteName, isPaletteReversed: false }
47
+
48
+ case SEQUENTIAL_REVERSE:
49
+ paletteName = state.paletteName && String(state.paletteName).concat('reverse')
50
+ const qualitativeReverse: string[] = palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && name.match(reverseRegex))
51
+ const sequentialReverse: string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && name.match(reverseRegex))
52
+
53
+ return { ...state, filteredQualitative: qualitativeReverse, filteredPallets: sequentialReverse, paletteName: paletteName, isPaletteReversed: true }
54
+ default:
55
+ return state
58
56
  }
59
- };
57
+ }
60
58
 
61
59
  interface Keyable {
62
- color:string
63
- general:{
64
- palette:{
65
- isReversed:boolean
60
+ color: string
61
+ general: {
62
+ palette: {
63
+ isReversed: boolean
66
64
  }
67
65
  }
68
66
  }
69
67
 
70
- export function useColorPalette<T,Y extends Keyable>(colorPalettes:T,configState:Y){
71
- const [state, dispatch] = useReducer(reducer, initialState);
72
- const {paletteName,isPaletteReversed,filteredPallets,filteredQualitative} = state
73
-
74
-
75
-
68
+ export function useColorPalette<T, Y extends Keyable>(colorPalettes: T, configState: Y) {
69
+ const [state, dispatch] = useReducer(reducer, initialState)
70
+ const { paletteName, isPaletteReversed, filteredPallets, filteredQualitative } = state
76
71
 
77
72
  useEffect(() => {
78
- dispatch({ type: SEQUENTIAL, payload: colorPalettes });
79
- }, []);
80
-
81
-
82
- useEffect(()=>{
83
- if(configState.general.palette.isReversed){
84
- dispatch({ type: "SEQUENTIAL_REVERSE", payload: colorPalettes });
85
- }
86
- return ()=> dispatch({ type: "SEQUENTIAL", payload: colorPalettes });
87
-
88
- },[configState.general.palette.isReversed,dispatch,colorPalettes])
73
+ dispatch({ type: SEQUENTIAL, payload: colorPalettes })
74
+ }, [])
89
75
 
90
- useEffect(()=>{
91
- if(configState.color) dispatch({type:GET_PALETTE,payload:colorPalettes,paletteName:configState.color})
92
- },[dispatch,configState.color])
76
+ useEffect(() => {
77
+ if (configState.general.palette.isReversed) {
78
+ dispatch({ type: 'SEQUENTIAL_REVERSE', payload: colorPalettes })
79
+ }
80
+ return () => dispatch({ type: 'SEQUENTIAL', payload: colorPalettes })
81
+ }, [configState.general.palette.isReversed, dispatch, colorPalettes])
93
82
 
83
+ useEffect(() => {
84
+ if (configState.color) dispatch({ type: GET_PALETTE, payload: colorPalettes, paletteName: configState.color })
85
+ }, [dispatch, configState.color])
94
86
 
95
- return {paletteName,isPaletteReversed,filteredPallets,filteredQualitative,dispatch}
96
- }
87
+ return { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch }
88
+ }
@@ -1,17 +1,11 @@
1
-
2
- import { useEffect, useRef, useState } from "react"
3
- import {
4
- zoom as d3Zoom,
5
- zoomIdentity as d3ZoomIdentity,
6
- } from "d3-zoom"
7
- import {
8
- select as d3Select,
9
- } from "d3-selection"
1
+ import { useEffect, useRef, useState } from 'react'
2
+ import { zoom as d3Zoom, zoomIdentity as d3ZoomIdentity } from 'd3-zoom'
3
+ import { select as d3Select } from 'd3-selection'
10
4
 
11
5
  function getCoords(w, h, t) {
12
- const xOffset = (w * t.k - w) / 2
13
- const yOffset = (h * t.k - h) / 2
14
- return [w / 2 - (xOffset + t.x) / t.k, h / 2 - (yOffset + t.y) / t.k]
6
+ const xOffset = (w * t.k - w) / 2
7
+ const yOffset = (h * t.k - h) / 2
8
+ return [w / 2 - (xOffset + t.x) / t.k, h / 2 - (yOffset + t.y) / t.k]
15
9
  }
16
10
 
17
11
  export default function useZoomPan({
@@ -20,14 +14,16 @@ export default function useZoomPan({
20
14
  onMoveStart,
21
15
  onMoveEnd,
22
16
  onMove,
23
- translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
17
+ translateExtent = [
18
+ [-Infinity, -Infinity],
19
+ [Infinity, Infinity]
20
+ ],
24
21
  scaleExtent = [1, 8],
25
22
  zoom = 1,
26
23
  width,
27
24
  height,
28
25
  projection
29
26
  }) {
30
-
31
27
  const [lon, lat] = center
32
28
  const [position, setPosition] = useState({ x: 0, y: 0, k: 1 })
33
29
  const lastPosition = useRef({ x: 0, y: 0, k: 1 })
@@ -47,15 +43,15 @@ export default function useZoomPan({
47
43
  if (!onMoveStart || bypassEvents.current) return
48
44
  onMoveStart({ coordinates: projection.invert(getCoords(width, height, d3Event.transform)), zoom: d3Event.transform.k }, d3Event)
49
45
  }
50
-
46
+
51
47
  function handleZoom(d3Event) {
52
48
  if (bypassEvents.current) return
53
- const {transform, sourceEvent} = d3Event
49
+ const { transform, sourceEvent } = d3Event
54
50
  setPosition({ x: transform.x, y: transform.y, k: transform.k, dragging: sourceEvent })
55
51
  if (!onMove) return
56
52
  onMove({ x: transform.x, y: transform.y, k: transform.k, dragging: sourceEvent }, d3Event)
57
53
  }
58
-
54
+
59
55
  function handleZoomEnd(d3Event) {
60
56
  if (bypassEvents.current) {
61
57
  bypassEvents.current = false
@@ -77,10 +73,13 @@ export default function useZoomPan({
77
73
  const zoom = d3Zoom()
78
74
  .filter(filterFunc)
79
75
  .scaleExtent([minZoom, maxZoom])
80
- .translateExtent([[a1, a2], [b1, b2]])
81
- .on("start", handleZoomStart)
82
- .on("zoom", handleZoom)
83
- .on("end", handleZoomEnd)
76
+ .translateExtent([
77
+ [a1, a2],
78
+ [b1, b2]
79
+ ])
80
+ .on('start', handleZoomStart)
81
+ .on('zoom', handleZoom)
82
+ .on('end', handleZoomEnd)
84
83
 
85
84
  zoomRef.current = zoom
86
85
  svg.call(zoom)
@@ -105,6 +104,6 @@ export default function useZoomPan({
105
104
  return {
106
105
  mapRef,
107
106
  position,
108
- transformString: `translate(${position.x} ${position.y}) scale(${position.k})`,
107
+ transformString: `translate(${position.x} ${position.y}) scale(${position.k})`
109
108
  }
110
- }
109
+ }
package/src/index.html CHANGED
@@ -1,33 +1,36 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
6
- <style type="text/css">
7
- body {
8
- margin: 0;
9
- }
10
- .cdc-map-outer-container {
11
- min-height: 100vh;
12
- }
13
- </style>
14
- </head>
15
- <body>
16
- <!-- DEFAULT EXAMPLES -->
17
- <!-- <div class="react-container react-container--maps" data-config="/examples/default-county.json"></div> -->
18
- <!-- <div class="react-container react-container--maps" data-config="/examples/default-geocode.json"></div> -->
19
- <!-- <div class="react-container react-container--maps" data-config="/examples/default-usa-regions.json"></div> -->
20
- <!-- <div class="react-container react-container--maps" data-config="/examples/default-world.json"></div> -->
21
- <!-- <div class="react-container react-container--maps" data-config="/examples/bubble-us.json"></div/> -->
22
- <!-- <div class="react-container react-container&#45;&#45;maps" data-config="/examples/bubble-world.json"></div>-->
23
- <div class="react-container react-container--maps" data-config="/examples/default-single-state.json"></div>
24
-
25
- <!-- TP4 EXAMPLES -->
26
- <!-- <div class="react-container react-container--maps" data-config="/examples/example-city-state.json"></div> -->
27
- <!-- <div class="react-container react-container--maps" data-config="/examples/example-world-map.json"></div> -->
28
- <!-- <div class="react-container react-container--maps" data-config="/examples/default-hex.json"></div> -->
29
-
30
3
 
31
- <noscript>You need to enable JavaScript to run this app.</noscript>
32
- </body>
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
7
+ <style type="text/css">
8
+ body {
9
+ margin: 0;
10
+ }
11
+
12
+ .cdc-map-outer-container {
13
+ min-height: 100vh;
14
+ }
15
+ </style>
16
+ </head>
17
+
18
+ <body>
19
+ <!-- DEFAULT EXAMPLES -->
20
+ <!-- <div class="react-container react-container--maps" data-config="/examples/default-county.json"></div> -->
21
+ <!-- <div class="react-container react-container--maps" data-config="/examples/default-geocode.json"></div> -->
22
+ <!-- <div class="react-container react-container--maps" data-config="/examples/default-usa-regions.json"></div> -->
23
+ <!-- <div class="react-container react-container--maps" data-config="/examples/default-world.json"></div> -->
24
+ <!-- <div class="react-container react-container--maps" data-config="/examples/bubble-us.json"></div /> -->
25
+ <!-- <div class="react-container react-container&#45;&#45;maps" data-config="/examples/bubble-world.json"></div> -->
26
+
27
+ <!-- TP4 EXAMPLES -->
28
+ <div class="react-container react-container--maps" data-config="/examples/example-city-state.json"></div>
29
+ <!-- <div class="react-container react-container--maps" data-config="/examples/example-world-map.json"></div> -->
30
+ <!-- <div class="react-container react-container--maps" data-config="/examples/default-hex.json"></div> -->
31
+
32
+
33
+ <noscript>You need to enable JavaScript to run this app.</noscript>
34
+ </body>
35
+
33
36
  </html>
@@ -1,7 +1,6 @@
1
1
  .data-table-container {
2
2
  margin: 0;
3
3
  @include breakpointClass(md) {
4
- margin: 1em;
4
+ margin: 5px 1em;
5
5
  }
6
-
7
6
  }
@@ -0,0 +1,42 @@
1
+ .cdc-open-viz-module .cdc-map-inner-container .filters-section,
2
+ .cove .cdc-map-inner-container .filters-section {
3
+ margin-left: 1rem;
4
+ margin-right: 1rem;
5
+
6
+ &__title {
7
+ margin: 15px 0;
8
+ }
9
+
10
+ &__wrapper {
11
+ margin-bottom: 40px;
12
+
13
+ hr {
14
+ margin-bottom: 20px;
15
+ }
16
+
17
+ label {
18
+ display: inherit;
19
+ margin-bottom: 5px;
20
+ font-weight: 600;
21
+ font-size: 16px;
22
+ }
23
+ }
24
+
25
+ @include breakpoint(md) {
26
+ display: flex;
27
+ gap: 30px;
28
+ }
29
+
30
+ label:not(:empty) {
31
+ margin-right: 0.4em;
32
+ }
33
+
34
+ select {
35
+ font-size: 1em;
36
+ padding-right: 5px;
37
+ }
38
+
39
+ .single-filter {
40
+ margin-bottom: 0.5em;
41
+ }
42
+ }
@@ -2,6 +2,7 @@
2
2
  @import "~@cdc/core/styles/heading-colors";
3
3
  @import "variables";
4
4
  @import "editor-panel";
5
+ @import "filters";
5
6
 
6
7
  .cdc-map-outer-container {
7
8
  position: relative;
@@ -185,7 +186,7 @@
185
186
  > div.select-heading {
186
187
  font-size: 1.1em;
187
188
  font-weight: 600;
188
- margin-bottom: .75em;
189
+ margin-bottom: .75em;
189
190
  }
190
191
  }
191
192
  form {
@@ -215,5 +216,5 @@
215
216
  [tabIndex]:focus {
216
217
  outline-color: rgb(0, 95, 204)
217
218
  }
218
-
219
- }
219
+
220
+ }
@@ -109,6 +109,28 @@ aside {
109
109
  }
110
110
  }
111
111
  }
112
+
113
+ &.bottom.single-row {
114
+ width: 100%;
115
+ .legend-section ul {
116
+ flex-direction: row;
117
+ align-items: baseline;
118
+ justify-content:flex-start;
119
+ flex-wrap: wrap;
120
+ li {
121
+ justify-items: center;
122
+ line-break:loose;
123
+ align-items: center;
124
+ width: auto;
125
+ padding-right: 1em;
126
+ padding-bottom: 1em;
127
+ display: inline-block;
128
+ & > span {
129
+ margin: 0 !important;
130
+ }
131
+ }
132
+ }
133
+ };
112
134
 
113
135
  @include breakpointClass(sm) {
114
136
  .legend-section ul {