@cdc/map 4.24.5 → 4.24.9
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 +71853 -64936
- package/examples/annotation/index.json +552 -0
- package/examples/annotation/usa-map.json +900 -0
- package/examples/county-year.csv +10 -0
- package/examples/default-geocode.json +44 -10
- package/examples/default-patterns.json +0 -2
- package/examples/default-single-state.json +279 -108
- package/examples/map-issue-3.json +646 -0
- package/examples/single-state-filter.json +153 -0
- package/index.html +10 -6
- package/package.json +6 -5
- package/src/CdcMap.tsx +367 -199
- package/src/_stories/CdcMap.stories.tsx +14 -0
- package/src/_stories/_mock/DEV-7286.json +165 -0
- package/src/_stories/_mock/DEV-8942.json +270 -0
- package/src/components/Annotation/Annotation.Draggable.styles.css +18 -0
- package/src/components/Annotation/Annotation.Draggable.tsx +152 -0
- package/src/components/Annotation/AnnotationDropdown.styles.css +14 -0
- package/src/components/Annotation/AnnotationDropdown.tsx +70 -0
- package/src/components/Annotation/AnnotationList.styles.css +45 -0
- package/src/components/Annotation/AnnotationList.tsx +42 -0
- package/src/components/Annotation/index.tsx +11 -0
- package/src/components/{BubbleList.jsx → BubbleList.tsx} +1 -1
- package/src/components/{CityList.jsx → CityList.tsx} +28 -2
- package/src/components/{DataTable.jsx → DataTable.tsx} +2 -2
- package/src/components/EditorPanel/components/EditorPanel.tsx +650 -129
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +336 -0
- package/src/components/EditorPanel/components/{Panel.PatternSettings.tsx → Panels/Panel.PatternSettings.tsx} +63 -13
- package/src/components/EditorPanel/components/{Panels.tsx → Panels/index.tsx} +3 -0
- package/src/components/Legend/components/Legend.tsx +125 -42
- package/src/components/Legend/components/index.scss +42 -42
- package/src/components/Modal.tsx +25 -0
- package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +74 -0
- package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +29 -0
- package/src/components/UsaMap/components/SingleState/index.tsx +9 -0
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +4 -3
- package/src/components/UsaMap/components/UsaMap.County.tsx +114 -36
- package/src/components/UsaMap/components/UsaMap.Region.tsx +2 -0
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +175 -206
- package/src/components/UsaMap/components/UsaMap.State.tsx +188 -44
- package/src/components/UsaMap/data/us-extended-geography.json +1 -0
- package/src/components/UsaMap/helpers/map.ts +111 -0
- package/src/components/WorldMap/WorldMap.tsx +17 -32
- package/src/components/ZoomControls.tsx +41 -0
- package/src/data/initial-state.js +11 -2
- package/src/data/supported-geos.js +15 -4
- package/src/helpers/generateColorsArray.ts +13 -0
- package/src/helpers/generateRuntimeLegendHash.ts +23 -0
- package/src/helpers/getUniqueValues.ts +19 -0
- package/src/helpers/hashObj.ts +25 -0
- package/src/helpers/tests/generateColorsArray.test.ts +18 -0
- package/src/helpers/tests/generateRuntimeLegendHash.test.ts +11 -0
- package/src/helpers/tests/hashObj.test.ts +10 -0
- package/src/hooks/useStateZoom.tsx +157 -0
- package/src/hooks/{useZoomPan.js → useZoomPan.ts} +6 -5
- package/src/scss/editor-panel.scss +0 -4
- package/src/scss/main.scss +23 -1
- package/src/scss/map.scss +14 -3
- package/src/types/MapConfig.ts +9 -1
- package/src/types/MapContext.ts +16 -2
- package/LICENSE +0 -201
- package/src/components/Modal.jsx +0 -22
- package/src/test/CdcMap.test.jsx +0 -19
- /package/src/components/EditorPanel/components/{Panel.PatternSettings-style.css → Panels/Panel.PatternSettings-style.css} +0 -0
- /package/src/components/{Geo.jsx → Geo.tsx} +0 -0
- /package/src/components/{NavigationMenu.jsx → NavigationMenu.tsx} +0 -0
- /package/src/components/{ZoomableGroup.jsx → ZoomableGroup.tsx} +0 -0
|
@@ -190,6 +190,7 @@ export const supportedStatesFipsCodes = {
|
|
|
190
190
|
'08': 'Colorado',
|
|
191
191
|
'09': 'Connecticut',
|
|
192
192
|
10: 'Delaware',
|
|
193
|
+
11: 'District of Columbia',
|
|
193
194
|
12: 'Florida',
|
|
194
195
|
13: 'Georgia',
|
|
195
196
|
15: 'Hawaii',
|
|
@@ -234,9 +235,9 @@ export const supportedStatesFipsCodes = {
|
|
|
234
235
|
56: 'Wyoming',
|
|
235
236
|
60: 'American Samoa',
|
|
236
237
|
66: 'Guam',
|
|
237
|
-
69: 'Northern Mariana Islands',
|
|
238
|
+
69: 'Commonwealth of the Northern Mariana Islands',
|
|
238
239
|
72: 'Puerto Rico',
|
|
239
|
-
78: 'Virgin Islands'
|
|
240
|
+
78: 'United States Virgin Islands'
|
|
240
241
|
}
|
|
241
242
|
|
|
242
243
|
export const supportedCountries = {
|
|
@@ -289,7 +290,12 @@ export const supportedCountries = {
|
|
|
289
290
|
COL: ['Colombia'],
|
|
290
291
|
COM: ['Comoros'],
|
|
291
292
|
COG: ['Congo', 'Congo, Republic of the', 'Republic of the Congo'],
|
|
292
|
-
COD: [
|
|
293
|
+
COD: [
|
|
294
|
+
'Democratic Republic of the Congo',
|
|
295
|
+
'Congo, Democratic Republic of the',
|
|
296
|
+
'Congo, the Democratic Republic of the',
|
|
297
|
+
'Dem. Rep. Congo'
|
|
298
|
+
],
|
|
293
299
|
COK: ['Cook Islands', 'Cook Is.', 'Cook Islands (New Zealand)'],
|
|
294
300
|
CRI: ['Costa Rica'],
|
|
295
301
|
CIV: ["Côte d'Ivoire"],
|
|
@@ -382,7 +388,12 @@ export const supportedCountries = {
|
|
|
382
388
|
MUS: ['Mauritius'],
|
|
383
389
|
MYT: ['Mayotte', 'Mayotte (France)'],
|
|
384
390
|
MEX: ['Mexico'],
|
|
385
|
-
FSM: [
|
|
391
|
+
FSM: [
|
|
392
|
+
'Micronesia',
|
|
393
|
+
'Federated States of Micronesia',
|
|
394
|
+
'Micronesia (Federated States of)',
|
|
395
|
+
'Micronesia, Federated States of'
|
|
396
|
+
],
|
|
386
397
|
MDA: ['Moldova', 'Moldova, Republic of'],
|
|
387
398
|
MCO: ['Monaco'],
|
|
388
399
|
MNG: ['Mongolia'],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import chroma from 'chroma-js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate an array of colors based on a given color [color, hoverColor, darkColor]
|
|
5
|
+
* @param {string} color - The base color to generate the array from
|
|
6
|
+
* @param {boolean} special - A flag to determine if the hover color should be brighter or saturated
|
|
7
|
+
* @returns {string[]} - An array of colors
|
|
8
|
+
*/
|
|
9
|
+
export const generateColorsArray = (color: string = '#000000', special: boolean = false) => {
|
|
10
|
+
let colorObj = chroma(color)
|
|
11
|
+
let hoverColor = special ? colorObj.brighten(0.5).hex() : colorObj.saturate(1.3).hex()
|
|
12
|
+
return [color, hoverColor, colorObj.darken(0.3).hex()]
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { hashObj } from './hashObj'
|
|
2
|
+
|
|
3
|
+
export const generateRuntimeLegendHash = (state, runtimeFilters) => {
|
|
4
|
+
return hashObj({
|
|
5
|
+
unified: state.legend.unified ?? false,
|
|
6
|
+
equalNumberOptIn: state.general.equalNumberOptIn ?? false,
|
|
7
|
+
specialClassesLast: state.legend.showSpecialClassesLast ?? false,
|
|
8
|
+
color: state.color,
|
|
9
|
+
customColors: state.customColors,
|
|
10
|
+
numberOfItems: state.legend.numberOfItems,
|
|
11
|
+
type: state.legend.type,
|
|
12
|
+
separateZero: state.legend.separateZero ?? false,
|
|
13
|
+
primary: state.columns.primary.name,
|
|
14
|
+
categoryValuesOrder: state.legend.categoryValuesOrder,
|
|
15
|
+
specialClasses: state.legend.specialClasses,
|
|
16
|
+
geoType: state.general.geoType,
|
|
17
|
+
data: state.data,
|
|
18
|
+
filters: {
|
|
19
|
+
...state.filters
|
|
20
|
+
},
|
|
21
|
+
...runtimeFilters
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get unique values from a column in a dataset
|
|
3
|
+
* @returns {Array} - The unique values
|
|
4
|
+
*/
|
|
5
|
+
export const getUniqueValues = (data: Array<Record<string, any>>, columnName: string) => {
|
|
6
|
+
let result = {}
|
|
7
|
+
|
|
8
|
+
for (let i = 0; i < data.length; i++) {
|
|
9
|
+
let val = data[i][columnName]
|
|
10
|
+
|
|
11
|
+
if (undefined === val) continue
|
|
12
|
+
|
|
13
|
+
if (undefined === result[val]) {
|
|
14
|
+
result[val] = true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return Object.keys(result)
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashes an object
|
|
3
|
+
* @param {Object} row - The object to hash
|
|
4
|
+
* @returns {number} - The hash of the object
|
|
5
|
+
*/
|
|
6
|
+
export const hashObj = row => {
|
|
7
|
+
try {
|
|
8
|
+
if (!row || row === undefined) throw new Error('No row supplied to hashObj')
|
|
9
|
+
|
|
10
|
+
let str = JSON.stringify(row)
|
|
11
|
+
let hash = 0
|
|
12
|
+
|
|
13
|
+
if (str.length === 0) return hash
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < str.length; i++) {
|
|
16
|
+
let char = str.charCodeAt(i)
|
|
17
|
+
hash = (hash << 5) - hash + char
|
|
18
|
+
hash = hash & hash
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return hash
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.error({ state: 'COVE: ' + e.message }) // eslint-disable-line
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { generateColorsArray } from '../generateColorsArray'
|
|
2
|
+
|
|
3
|
+
describe('generateColorsArray', () => {
|
|
4
|
+
it('should return an array of colors', () => {
|
|
5
|
+
const colors = generateColorsArray('#fde0dd', false)
|
|
6
|
+
expect(colors).toEqual(expect.arrayContaining(['#fde0dd', '#ffd0c9', '#edd1ce']))
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it('should return a brighter hover color when special flag is true', () => {
|
|
10
|
+
const colors = generateColorsArray('#fde0dd', true)
|
|
11
|
+
expect(colors[1]).toEqual('#fffaf7')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should return a darker color for the third element in the array', () => {
|
|
15
|
+
const colors = generateColorsArray('#fde0dd', false)
|
|
16
|
+
expect(colors[2]).toBe('#edd1ce')
|
|
17
|
+
})
|
|
18
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { generateRuntimeLegendHash } from '../generateRuntimeLegendHash'
|
|
2
|
+
import usaExample from './../../../examples/default-usa.json'
|
|
3
|
+
|
|
4
|
+
describe('generateRuntimeLegendHash', () => {
|
|
5
|
+
it('should return a hash value for a given state and runtime filters', () => {
|
|
6
|
+
const runtimeFilters = []
|
|
7
|
+
const expectedHash = 1253406922
|
|
8
|
+
const result = generateRuntimeLegendHash(usaExample, runtimeFilters)
|
|
9
|
+
expect(result).toBe(expectedHash)
|
|
10
|
+
})
|
|
11
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { hashObj } from '../hashObj'
|
|
2
|
+
|
|
3
|
+
describe('hashObj', () => {
|
|
4
|
+
it('should return a hash value for a given object', () => {
|
|
5
|
+
const obj = { state: 'Georgia', city: 'Atlanta' }
|
|
6
|
+
const expectedHash = -380051767
|
|
7
|
+
const result = hashObj(obj)
|
|
8
|
+
expect(result).toBe(expectedHash)
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { useContext, useEffect, useState } from 'react'
|
|
2
|
+
import ConfigContext from '../context'
|
|
3
|
+
import { geoAlbersUsaTerritories, GeoProjection } from 'd3-composite-projections'
|
|
4
|
+
import { MapContext } from '../types/MapContext'
|
|
5
|
+
import { geoPath, GeoPath } from 'd3-geo'
|
|
6
|
+
import _ from 'lodash'
|
|
7
|
+
import { getFilterControllingStatePicked } from '../components/UsaMap/helpers/map'
|
|
8
|
+
import { supportedStatesFipsCodes } from '../data/supported-geos'
|
|
9
|
+
|
|
10
|
+
interface StateData {
|
|
11
|
+
geometry: { type: 'MultiPolygon'; coordinates: number[][][][] }
|
|
12
|
+
// FIPS ID of US state
|
|
13
|
+
id: string
|
|
14
|
+
// name of US state
|
|
15
|
+
properties: { name: string }
|
|
16
|
+
type: 'Feature'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Position {
|
|
20
|
+
zoom: number
|
|
21
|
+
coordinates: [number, number]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const useSetScaleAndTranslate = (topoData: { states: StateData[] }) => {
|
|
25
|
+
const { setTranslate, setScale, setStateToShow, setPosition, state, setState, runtimeData } = useContext<MapContext>(ConfigContext)
|
|
26
|
+
const statePicked = getFilterControllingStatePicked(state, runtimeData)
|
|
27
|
+
const defaultStateToShow = 'Alabama'
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const fipsCode = Object.keys(supportedStatesFipsCodes).find(key => supportedStatesFipsCodes[key] === statePicked)
|
|
30
|
+
const stateName = statePicked
|
|
31
|
+
const stateData = { fipsCode, stateName }
|
|
32
|
+
setScale(1)
|
|
33
|
+
setTranslate([0, 0])
|
|
34
|
+
setState({
|
|
35
|
+
...state,
|
|
36
|
+
general: {
|
|
37
|
+
...state.general,
|
|
38
|
+
statePicked: stateData
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
setStateToShow(topoData?.states?.find(s => s.properties.name === statePicked))
|
|
42
|
+
}, [topoData])
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const fipsCode = Object.keys(supportedStatesFipsCodes).find(key => supportedStatesFipsCodes[key] === statePicked)
|
|
46
|
+
const stateName = statePicked
|
|
47
|
+
const stateData = { fipsCode, stateName }
|
|
48
|
+
|
|
49
|
+
setState({
|
|
50
|
+
...state,
|
|
51
|
+
general: {
|
|
52
|
+
...state.general,
|
|
53
|
+
statePicked: stateData
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
setScaleAndTranslate('reset')
|
|
57
|
+
}, [statePicked])
|
|
58
|
+
|
|
59
|
+
// SVG ITEMS
|
|
60
|
+
const WIDTH = 880
|
|
61
|
+
const HEIGHT = 500
|
|
62
|
+
const PADDING = 50
|
|
63
|
+
|
|
64
|
+
// TODO: same as city list projection?
|
|
65
|
+
const [projection, setProjection] = useState(() =>
|
|
66
|
+
geoAlbersUsaTerritories()
|
|
67
|
+
.translate([WIDTH / 2, HEIGHT / 2])
|
|
68
|
+
.scale(1)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
/*
|
|
72
|
+
NORMALIZATION_FACTOR NOTES:
|
|
73
|
+
This is used during state switching,
|
|
74
|
+
I'm not sure why the value is 1070 but it does appear to work during the switching.
|
|
75
|
+
During zoom it does not work.
|
|
76
|
+
*/
|
|
77
|
+
const NORMALIZATION_FACTOR = 1070
|
|
78
|
+
const _statePickedData = topoData?.states?.find(s => s.properties.name === statePicked)
|
|
79
|
+
const newProjection = projection.fitExtent(
|
|
80
|
+
[
|
|
81
|
+
[PADDING, PADDING],
|
|
82
|
+
[WIDTH - PADDING, HEIGHT - PADDING]
|
|
83
|
+
],
|
|
84
|
+
_statePickedData
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
// Work for centering the state.
|
|
88
|
+
const newScale = newProjection.scale()
|
|
89
|
+
const normalizedScale = newScale / NORMALIZATION_FACTOR
|
|
90
|
+
let [x, y] = newProjection.translate()
|
|
91
|
+
x = x - WIDTH / 2
|
|
92
|
+
y = y - HEIGHT / 2
|
|
93
|
+
|
|
94
|
+
const path: GeoPath = geoPath().projection(projection)
|
|
95
|
+
const featureCenter = path.centroid(_statePickedData)
|
|
96
|
+
const stateCenter = newProjection.invert(featureCenter)
|
|
97
|
+
|
|
98
|
+
const switchState = () => {
|
|
99
|
+
setStateToShow(_statePickedData)
|
|
100
|
+
setScaleAndTranslate('reset')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const setScaleAndTranslate = (zoomFunction: string = '') => {
|
|
104
|
+
setPosition((pos: Position) => {
|
|
105
|
+
let newZoom = pos.zoom
|
|
106
|
+
let newCoordinates = pos.coordinates
|
|
107
|
+
if (zoomFunction === 'zoomIn' && pos.zoom < 4) {
|
|
108
|
+
newZoom = pos.zoom * 1.5
|
|
109
|
+
newCoordinates = pos.coordinates[0] !== 0 && pos.coordinates[1] !== 0 ? pos.coordinates : stateCenter
|
|
110
|
+
} else if (zoomFunction === 'zoomOut' && pos.zoom > 1) {
|
|
111
|
+
newZoom = pos.zoom / 1.5
|
|
112
|
+
newCoordinates = pos.coordinates[0] !== 0 && pos.coordinates[1] !== 0 ? pos.coordinates : stateCenter
|
|
113
|
+
} else if (zoomFunction === 'reset') {
|
|
114
|
+
newZoom = 1
|
|
115
|
+
newCoordinates = stateCenter
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
zoom: newZoom,
|
|
119
|
+
coordinates: newCoordinates
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
if (zoomFunction === 'reset') {
|
|
124
|
+
setTranslate([0, 0]) // needed for state switcher
|
|
125
|
+
setScale(1) // needed for state switcher
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const handleZoomIn = () => {
|
|
130
|
+
setScaleAndTranslate('zoomIn')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const handleZoomOut = () => {
|
|
134
|
+
setScaleAndTranslate('zoomOut')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const handleMoveEnd = position => {
|
|
138
|
+
setPosition(position)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const handleReset = () => {
|
|
142
|
+
setScaleAndTranslate('reset')
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
statePicked,
|
|
147
|
+
setScaleAndTranslate,
|
|
148
|
+
switchState,
|
|
149
|
+
handleZoomIn,
|
|
150
|
+
handleZoomOut,
|
|
151
|
+
handleMoveEnd,
|
|
152
|
+
handleReset,
|
|
153
|
+
projection
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export default useSetScaleAndTranslate
|
|
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
|
|
|
2
2
|
import { zoom as d3Zoom, zoomIdentity as d3ZoomIdentity } from 'd3-zoom'
|
|
3
3
|
import { select as d3Select } from 'd3-selection'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const getCoords = (w, h, t) => {
|
|
6
6
|
const xOffset = (w * t.k - w) / 2
|
|
7
7
|
const yOffset = (h * t.k - h) / 2
|
|
8
8
|
return [w / 2 - (xOffset + t.x) / t.k, h / 2 - (yOffset + t.y) / t.k]
|
|
@@ -39,12 +39,12 @@ export default function useZoomPan({
|
|
|
39
39
|
useEffect(() => {
|
|
40
40
|
const svg = d3Select(mapRef.current)
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
const handleZoomStart = d3Event => {
|
|
43
43
|
if (!onMoveStart || bypassEvents.current) return
|
|
44
44
|
onMoveStart({ coordinates: projection.invert(getCoords(width, height, d3Event.transform)), zoom: d3Event.transform.k }, d3Event)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
const handleZoom = d3Event => {
|
|
48
48
|
if (bypassEvents.current) return
|
|
49
49
|
const { transform, sourceEvent } = d3Event
|
|
50
50
|
setPosition({ x: transform.x, y: transform.y, k: transform.k, dragging: sourceEvent })
|
|
@@ -52,7 +52,7 @@ export default function useZoomPan({
|
|
|
52
52
|
onMove({ x: transform.x, y: transform.y, k: transform.k, dragging: sourceEvent }, d3Event)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
const handleZoomEnd = d3Event => {
|
|
56
56
|
if (bypassEvents.current) {
|
|
57
57
|
bypassEvents.current = false
|
|
58
58
|
return
|
|
@@ -63,7 +63,7 @@ export default function useZoomPan({
|
|
|
63
63
|
onMoveEnd({ coordinates: [x, y], zoom: d3Event.transform.k }, d3Event)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
const filterFunc = d3Event => {
|
|
67
67
|
if (filterZoomEvent) {
|
|
68
68
|
return filterZoomEvent(d3Event)
|
|
69
69
|
}
|
|
@@ -89,6 +89,7 @@ export default function useZoomPan({
|
|
|
89
89
|
if (lon === lastPosition.current.x && lat === lastPosition.current.y && zoom === lastPosition.current.k) return
|
|
90
90
|
|
|
91
91
|
const coords = projection([lon, lat])
|
|
92
|
+
if (!coords) return
|
|
92
93
|
const x = coords[0] * zoom
|
|
93
94
|
const y = coords[1] * zoom
|
|
94
95
|
const svg = d3Select(mapRef.current)
|
package/src/scss/main.scss
CHANGED
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
@import 'filters';
|
|
6
6
|
@import '@cdc/core/styles/v2/components/ui/tooltip';
|
|
7
7
|
|
|
8
|
+
.type-map--has-error {
|
|
9
|
+
overflow: hidden !important;
|
|
10
|
+
height: 100vh;
|
|
11
|
+
|
|
12
|
+
.waiting {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-content: center;
|
|
15
|
+
flex-wrap: wrap;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-content: center;
|
|
18
|
+
flex-wrap: wrap;
|
|
19
|
+
height: 100vh;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
8
23
|
.cdc-map-outer-container {
|
|
9
24
|
position: relative;
|
|
10
25
|
display: flex; // Needed for the main content
|
|
@@ -58,6 +73,14 @@
|
|
|
58
73
|
display: flex;
|
|
59
74
|
position: relative;
|
|
60
75
|
flex-direction: column;
|
|
76
|
+
|
|
77
|
+
&.bottom {
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
}
|
|
80
|
+
&.top {
|
|
81
|
+
flex-direction: column-reverse;
|
|
82
|
+
}
|
|
83
|
+
|
|
61
84
|
&.modal-background {
|
|
62
85
|
position: relative;
|
|
63
86
|
&::before {
|
|
@@ -142,7 +165,6 @@
|
|
|
142
165
|
|
|
143
166
|
p.subtext {
|
|
144
167
|
font-size: 0.9em;
|
|
145
|
-
padding: 0 0.8em 0.8em;
|
|
146
168
|
em {
|
|
147
169
|
font-style: italic;
|
|
148
170
|
}
|
package/src/scss/map.scss
CHANGED
|
@@ -159,10 +159,13 @@ $medium: 768px;
|
|
|
159
159
|
@extend .territories;
|
|
160
160
|
width: 60%;
|
|
161
161
|
}
|
|
162
|
-
}
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
&--tablet {
|
|
164
|
+
@extend .territories;
|
|
165
|
+
width: 70%;
|
|
166
|
+
svg {
|
|
167
|
+
margin-bottom: 0.2em;
|
|
168
|
+
}
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
|
|
@@ -255,6 +258,10 @@ $medium: 768px;
|
|
|
255
258
|
stroke: none !important;
|
|
256
259
|
}
|
|
257
260
|
|
|
261
|
+
.countyMapGroup--no-transition {
|
|
262
|
+
transition: none !important;
|
|
263
|
+
}
|
|
264
|
+
|
|
258
265
|
// .state {
|
|
259
266
|
// display: none;
|
|
260
267
|
// }
|
|
@@ -371,3 +378,7 @@ canvas {
|
|
|
371
378
|
pointer-events: none;
|
|
372
379
|
display: none;
|
|
373
380
|
}
|
|
381
|
+
|
|
382
|
+
.data-table-container {
|
|
383
|
+
margin: 5px 0px !important;
|
|
384
|
+
}
|
package/src/types/MapConfig.ts
CHANGED
|
@@ -33,6 +33,7 @@ type PatternSelection = {
|
|
|
33
33
|
label: string
|
|
34
34
|
// size of pattern
|
|
35
35
|
size: 'small' | 'medium' | 'large'
|
|
36
|
+
contrastCheck: boolean
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export type GeoColumnProperties = Pick<EditorColumnProperties, 'name' | 'label' | 'tooltip' | 'dataTable'>
|
|
@@ -40,7 +41,7 @@ export type LatitudeColumnProperties = Pick<EditorColumnProperties, 'name'>
|
|
|
40
41
|
export type LongitudeColumnProperties = Pick<EditorColumnProperties, 'name'>
|
|
41
42
|
export type NavigateColumnProperties = Pick<EditorColumnProperties, 'name'>
|
|
42
43
|
export type PrimaryColumnProperties = Pick<EditorColumnProperties, 'dataTable' | 'label' | 'name' | 'prefix' | 'suffix' | 'tooltip'>
|
|
43
|
-
|
|
44
|
+
export type ViewportSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg'
|
|
44
45
|
export type LegendShapeItem = {
|
|
45
46
|
column: string
|
|
46
47
|
key: string
|
|
@@ -123,6 +124,11 @@ export type MapConfig = Visualization & {
|
|
|
123
124
|
numberOfItems: number
|
|
124
125
|
position: string
|
|
125
126
|
title: string
|
|
127
|
+
style: 'circles' | 'boxes' | 'gradient'
|
|
128
|
+
subStyle: 'linear blocks' | 'smooth'
|
|
129
|
+
tickRotation: string
|
|
130
|
+
hideBorder: false
|
|
131
|
+
singleColumnLegend: false
|
|
126
132
|
}
|
|
127
133
|
table: {
|
|
128
134
|
label: string
|
|
@@ -144,6 +150,8 @@ export type MapConfig = Visualization & {
|
|
|
144
150
|
}
|
|
145
151
|
runtime: {
|
|
146
152
|
editorErrorMessage: string[]
|
|
153
|
+
// when a single state map doesn't include a fips code show a message...
|
|
154
|
+
noStateFoundMessage: string
|
|
147
155
|
}
|
|
148
156
|
mapPosition: { coordinates: Coordinate; zoom: number }
|
|
149
157
|
map: {
|
package/src/types/MapContext.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type MapConfig } from './MapConfig'
|
|
1
|
+
import { type MapConfig, type ViewportSize } from './MapConfig'
|
|
2
2
|
|
|
3
3
|
export type MapContext = {
|
|
4
4
|
applyLegendToRow
|
|
5
5
|
applyTooltipsToGeo
|
|
6
6
|
closeModal
|
|
7
7
|
columnsInData
|
|
8
|
-
currentViewport
|
|
8
|
+
currentViewport: ViewportSize
|
|
9
9
|
data
|
|
10
10
|
displayDataAsText
|
|
11
11
|
displayGeoName
|
|
@@ -14,12 +14,15 @@ export type MapContext = {
|
|
|
14
14
|
generateRuntimeData
|
|
15
15
|
geoClickHandler
|
|
16
16
|
handleCircleClick: Function
|
|
17
|
+
handleDragStateChange: Function
|
|
18
|
+
isDraggingAnnotation: boolean
|
|
17
19
|
handleMapAriaLabels
|
|
18
20
|
hasZoom
|
|
19
21
|
innerContainerRef
|
|
20
22
|
isDashboard
|
|
21
23
|
isDebug
|
|
22
24
|
isEditor
|
|
25
|
+
isFilterValueSupported: boolean
|
|
23
26
|
loadConfig
|
|
24
27
|
navigationHandler
|
|
25
28
|
position
|
|
@@ -42,4 +45,15 @@ export type MapContext = {
|
|
|
42
45
|
supportedTerritories
|
|
43
46
|
titleCase
|
|
44
47
|
viewport
|
|
48
|
+
setStateToShow: (string) => void
|
|
49
|
+
stateToShow: string
|
|
50
|
+
scale: number
|
|
51
|
+
translate: [number, number]
|
|
52
|
+
topoData
|
|
53
|
+
setScale: (number) => void
|
|
54
|
+
setTranslate: ([x, y]: [number, number]) => void
|
|
55
|
+
runtimeData: Object[]
|
|
56
|
+
tooltipId: string
|
|
57
|
+
setTopoData: Function
|
|
58
|
+
getTextWidth: (text: string, font: string) => string | undefined
|
|
45
59
|
}
|