@cdc/map 4.23.2 → 4.23.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdcmap.js +24661 -24191
- package/examples/custom-map-layers.json +764 -0
- package/examples/default-county.json +169 -155
- package/examples/default-geocode.json +744 -744
- package/examples/default-hex.json +3 -5
- package/examples/example-city-state-no-territories.json +703 -0
- package/examples/example-city-state.json +26 -7
- package/examples/example-city-stateBAD.json +744 -0
- package/examples/gallery/city-state.json +478 -478
- package/examples/testing-layer-2.json +1 -0
- package/examples/testing-layer.json +96 -0
- package/examples/world-geocode-data.json +18 -0
- package/examples/world-geocode.json +108 -0
- package/index.html +35 -29
- package/package.json +6 -3
- package/src/CdcMap.jsx +179 -111
- package/src/components/CityList.jsx +35 -35
- package/src/components/CountyMap.jsx +309 -446
- package/src/components/DataTable.jsx +7 -31
- package/src/components/EditorPanel.jsx +468 -217
- package/src/components/Sidebar.jsx +2 -0
- package/src/components/UsaMap.jsx +34 -23
- package/src/components/WorldMap.jsx +40 -8
- package/src/data/feature-test.json +73 -0
- package/src/data/initial-state.js +10 -3
- package/src/data/supported-geos.js +7 -7
- package/src/hooks/useMapLayers.jsx +243 -0
- package/src/index.jsx +4 -8
- package/src/scss/editor-panel.scss +97 -97
- package/src/scss/filters.scss +0 -2
- package/src/scss/main.scss +25 -26
- package/src/scss/map.scss +12 -0
- package/src/test/CdcMap.test.jsx +19 -0
- package/vite.config.js +3 -3
- package/src/components/Filters.jsx +0 -113
- package/src/hooks/useColorPalette.ts +0 -88
package/src/scss/map.scss
CHANGED
|
@@ -225,6 +225,7 @@ header + .map-container.full-border {
|
|
|
225
225
|
position: absolute;
|
|
226
226
|
top: 10px;
|
|
227
227
|
right: 10px;
|
|
228
|
+
display: none;
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
//Region Maps
|
|
@@ -310,3 +311,14 @@ header + .map-container.full-border {
|
|
|
310
311
|
stroke-linecap: round;
|
|
311
312
|
pointer-events: none;
|
|
312
313
|
}
|
|
314
|
+
|
|
315
|
+
canvas {
|
|
316
|
+
width: 100%;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#canvas-tooltip {
|
|
320
|
+
position: fixed;
|
|
321
|
+
background-color: white;
|
|
322
|
+
pointer-events: none;
|
|
323
|
+
display: none;
|
|
324
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
2
|
+
import CdcMap from './../CdcMap'
|
|
3
|
+
import usaConfig from './../../examples/example-city-state.json'
|
|
4
|
+
|
|
5
|
+
// Example: City State Map
|
|
6
|
+
describe('United States Map', () => {
|
|
7
|
+
it('loads', async () => {
|
|
8
|
+
render(<CdcMap config={usaConfig} />)
|
|
9
|
+
// screen.debug()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('accepts title changes', async () => {
|
|
13
|
+
render(<CdcMap config={usaConfig} isEditor />)
|
|
14
|
+
const titleInput = screen.getByTestId('title-input')
|
|
15
|
+
expect(titleInput.value).toBe('Example Data Map with Cities')
|
|
16
|
+
fireEvent.change(titleInput, { target: { value: 'My New Title' } })
|
|
17
|
+
expect(titleInput.value).toBe('My New Title')
|
|
18
|
+
})
|
|
19
|
+
})
|
package/vite.config.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import GenerateViteConfig from '../../generateViteConfig.js'
|
|
2
2
|
import { moduleName } from './package.json'
|
|
3
3
|
|
|
4
|
-
export default GenerateViteConfig(moduleName,null,{
|
|
4
|
+
export default GenerateViteConfig(moduleName, null, {
|
|
5
5
|
jsxImportSource: '@emotion/react',
|
|
6
6
|
babel: {
|
|
7
|
-
plugins: [
|
|
8
|
-
}
|
|
7
|
+
plugins: ['@emotion/babel-plugin']
|
|
8
|
+
}
|
|
9
9
|
})
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import React, { useState, useContext } from 'react'
|
|
2
|
-
import Context from './../context'
|
|
3
|
-
import Button from '@cdc/core/components/elements/Button'
|
|
4
|
-
|
|
5
|
-
// TODO: Combine Charts/Maps Filters.js files
|
|
6
|
-
const useFilters = () => {
|
|
7
|
-
const { state: config, setState: setConfig, runtimeFilters, setRuntimeFilters } = useContext(Context)
|
|
8
|
-
const [showApplyButton, setShowApplyButton] = useState(false)
|
|
9
|
-
|
|
10
|
-
const sortAsc = (a, b) => {
|
|
11
|
-
return a.toString().localeCompare(b.toString(), 'en', { numeric: true })
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const sortDesc = (a, b) => {
|
|
15
|
-
return b.toString().localeCompare(a.toString(), 'en', { numeric: true })
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const announceChange = text => { }
|
|
19
|
-
|
|
20
|
-
const changeFilterActive = (index, value) => {
|
|
21
|
-
let newFilters = config.filters
|
|
22
|
-
newFilters[index].active = value
|
|
23
|
-
setRuntimeFilters(newFilters)
|
|
24
|
-
setShowApplyButton(true)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const handleApplyButton = () => {
|
|
28
|
-
setConfig({ ...config, filters: runtimeFilters })
|
|
29
|
-
setShowApplyButton(false)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const handleReset = (e) => {
|
|
33
|
-
e.preventDefault()
|
|
34
|
-
let newFilters = runtimeFilters
|
|
35
|
-
|
|
36
|
-
// reset to first item in values array.
|
|
37
|
-
newFilters.map(filter => {
|
|
38
|
-
filter.active = filter.values[0]
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
setConfig({ ...config, filters: newFilters })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return { announceChange, sortAsc, sortDesc, changeFilterActive, showApplyButton, handleReset, handleApplyButton }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const Filters = () => {
|
|
48
|
-
const { runtimeFilters, state: config } = useContext(Context)
|
|
49
|
-
const { handleApplyButton, changeFilterActive, announceChange, sortAsc, sortDesc, showApplyButton, handleReset } = useFilters()
|
|
50
|
-
|
|
51
|
-
const buttonText = 'Apply Filters'
|
|
52
|
-
const resetText = 'Reset All'
|
|
53
|
-
|
|
54
|
-
const { filters } = config
|
|
55
|
-
|
|
56
|
-
if (filters.length === 0) return false
|
|
57
|
-
|
|
58
|
-
const FilterList = ({ filters: runtimeFilters }) => {
|
|
59
|
-
if (runtimeFilters) {
|
|
60
|
-
return runtimeFilters.map((singleFilter, idx) => {
|
|
61
|
-
const values = []
|
|
62
|
-
|
|
63
|
-
if (undefined === singleFilter.active) return null
|
|
64
|
-
|
|
65
|
-
singleFilter.values.forEach((filterOption, idx) => {
|
|
66
|
-
values.push(
|
|
67
|
-
<option key={idx} value={filterOption}>
|
|
68
|
-
{filterOption}
|
|
69
|
-
</option>
|
|
70
|
-
)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<section className='filter-col single-filter' key={idx}>
|
|
75
|
-
{singleFilter.label?.length > 0 && <label htmlFor={`filter-${idx}`}>{singleFilter.label}</label>}
|
|
76
|
-
<select
|
|
77
|
-
id={`filter-${idx}`}
|
|
78
|
-
className='filter-select'
|
|
79
|
-
aria-label='select filter'
|
|
80
|
-
value={singleFilter.active}
|
|
81
|
-
onChange={e => {
|
|
82
|
-
changeFilterActive(idx, e.target.value)
|
|
83
|
-
announceChange(`Filter ${singleFilter.label} value has been changed to ${e.target.value}, please reference the data table to see updated values.`)
|
|
84
|
-
}}
|
|
85
|
-
>
|
|
86
|
-
{values}
|
|
87
|
-
</select>
|
|
88
|
-
</section>
|
|
89
|
-
)
|
|
90
|
-
})
|
|
91
|
-
} else {
|
|
92
|
-
return null
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<section className={`filters-section`} style={{ display: 'block', width: '100%' }}>
|
|
98
|
-
<div className='filters-section__wrapper' style={{ flexWrap: 'wrap', display: 'flex', gap: '7px 15px', marginTop: '15px' }}>
|
|
99
|
-
<FilterList filters={runtimeFilters} />
|
|
100
|
-
<div className='filter-section__buttons' style={{ width: '100%' }}>
|
|
101
|
-
<Button onClick={handleApplyButton} disabled={!showApplyButton} style={{ marginRight: '10px' }}>
|
|
102
|
-
{buttonText}
|
|
103
|
-
</Button>
|
|
104
|
-
<a href='#!' role='button' onClick={handleReset}>
|
|
105
|
-
{resetText}
|
|
106
|
-
</a>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
</section>
|
|
110
|
-
)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export default Filters
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { useEffect, useReducer } from 'react'
|
|
2
|
-
|
|
3
|
-
// constants
|
|
4
|
-
const SEQUENTIAL = 'SEQUENTIAL'
|
|
5
|
-
const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE'
|
|
6
|
-
export const GET_PALETTE = 'GET_PALETTE'
|
|
7
|
-
|
|
8
|
-
// types & interfaces
|
|
9
|
-
interface State {
|
|
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
|
-
}
|
|
20
|
-
|
|
21
|
-
// create initial state
|
|
22
|
-
const initialState: State = {
|
|
23
|
-
filteredPallets: [],
|
|
24
|
-
isPaletteReversed: false,
|
|
25
|
-
filteredQualitative: [],
|
|
26
|
-
paletteName: undefined
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// create reducer function to handle multiple states & manupilate with each state
|
|
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) {
|
|
37
|
-
case GET_PALETTE:
|
|
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
|
|
39
|
-
// action.palletName is a string type and equals to state.color which is inisde Editors Panel.
|
|
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
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
interface Keyable {
|
|
60
|
-
color: string
|
|
61
|
-
general: {
|
|
62
|
-
palette: {
|
|
63
|
-
isReversed: boolean
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
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
|
|
71
|
-
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
dispatch({ type: SEQUENTIAL, payload: colorPalettes })
|
|
74
|
-
}, [])
|
|
75
|
-
|
|
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])
|
|
82
|
-
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
if (configState.color) dispatch({ type: GET_PALETTE, payload: colorPalettes, paletteName: configState.color })
|
|
85
|
-
}, [dispatch, configState.color])
|
|
86
|
-
|
|
87
|
-
return { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch }
|
|
88
|
-
}
|