@cdc/map 4.25.3 → 4.25.6
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/.idea/map.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/dist/cdcmap.js +31254 -32242
- package/examples/hex-colors.json +3 -3
- package/examples/m2.json +32904 -0
- package/examples/private/test.json +470 -1457
- package/examples/private/{mmr.json → wastewatermap.json} +86 -115
- package/index.html +36 -63
- package/package.json +7 -19
- package/src/CdcMap.tsx +56 -1552
- package/src/CdcMapComponent.tsx +608 -0
- package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +10 -0
- package/src/_stories/CdcMap.Legend.stories.tsx +67 -0
- package/src/_stories/CdcMap.Table.stories.tsx +19 -0
- package/src/_stories/CdcMap.stories.tsx +12 -1
- package/src/_stories/UsaMap.NoData.stories.tsx +4 -4
- package/src/_stories/_mock/default-patterns.json +8 -5
- package/src/_stories/_mock/legend-bins.json +428 -0
- package/{examples/private/default-patterns.json → src/_stories/_mock/legends/legend-tests.json} +36 -131
- package/src/cdcMapComponent.styles.css +9 -0
- package/src/components/Annotation/Annotation.Draggable.tsx +27 -26
- package/src/components/Annotation/AnnotationDropdown.tsx +5 -6
- package/src/components/BubbleList.tsx +135 -49
- package/src/components/CityList.tsx +89 -87
- package/src/components/DataTable.tsx +8 -8
- package/src/components/EditorPanel/components/EditorPanel.tsx +823 -885
- package/src/components/EditorPanel/components/Error.tsx +9 -2
- package/src/components/EditorPanel/components/HexShapeSettings.tsx +127 -141
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +55 -86
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +89 -75
- package/src/components/EditorPanel/components/editorPanel.styles.css +95 -0
- package/src/components/Geo.tsx +9 -1
- package/src/components/GoogleMap/components/GoogleMap.tsx +1 -1
- package/src/components/Legend/components/Legend.tsx +92 -87
- package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +128 -0
- package/src/components/Legend/components/LegendGroup/legend.group.css +27 -0
- package/src/components/Legend/components/LegendItem.Hex.tsx +4 -1
- package/src/components/Legend/components/index.scss +74 -17
- package/src/components/Modal.tsx +17 -7
- package/src/components/NavigationMenu.tsx +11 -9
- package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +12 -8
- package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +4 -4
- package/src/components/UsaMap/components/TerritoriesSection.tsx +33 -10
- package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +12 -10
- package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -14
- package/src/components/UsaMap/components/Territory/TerritoryShape.ts +2 -1
- package/src/components/UsaMap/components/UsaMap.County.tsx +138 -96
- package/src/components/UsaMap/components/UsaMap.Region.styles.css +72 -0
- package/src/components/UsaMap/components/UsaMap.Region.tsx +56 -103
- package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +10 -0
- package/src/components/UsaMap/components/UsaMap.SingleState.tsx +65 -74
- package/src/components/UsaMap/components/UsaMap.State.tsx +112 -91
- package/src/components/UsaMap/helpers/map.ts +1 -1
- package/src/components/UsaMap/helpers/shapes.ts +20 -7
- package/src/components/WorldMap/WorldMap.tsx +64 -118
- package/src/components/WorldMap/worldMap.styles.css +28 -0
- package/src/components/ZoomControls.tsx +15 -13
- package/src/components/zoomControls.styles.css +53 -0
- package/src/context.ts +17 -9
- package/src/data/initial-state.js +5 -2
- package/src/helpers/addUIDs.ts +150 -0
- package/src/helpers/applyColorToLegend.ts +39 -64
- package/src/helpers/applyLegendToRow.ts +51 -0
- package/src/helpers/colorDistributions.ts +12 -0
- package/src/helpers/constants.ts +44 -0
- package/src/helpers/displayGeoName.ts +9 -2
- package/src/helpers/formatLegendLocation.ts +3 -2
- package/src/helpers/generateColorsArray.ts +2 -1
- package/src/helpers/generateRuntimeData.ts +78 -0
- package/src/helpers/generateRuntimeFilters.ts +63 -0
- package/src/helpers/generateRuntimeLegend.ts +566 -0
- package/src/helpers/generateRuntimeLegendHash.ts +16 -15
- package/src/helpers/getColumnNames.ts +19 -0
- package/src/helpers/getMapContainerClasses.ts +23 -0
- package/src/helpers/getStatePicked.ts +8 -0
- package/src/helpers/handleMapTabbing.ts +31 -0
- package/src/helpers/hashObj.ts +1 -1
- package/src/helpers/index.ts +22 -0
- package/src/helpers/navigationHandler.ts +3 -3
- package/src/helpers/resetLegendToggles.ts +13 -0
- package/src/helpers/setBinNumbers.ts +5 -0
- package/src/helpers/sortSpecialClassesLast.ts +7 -0
- package/src/helpers/tests/getColumnNames.test.ts +52 -0
- package/src/helpers/titleCase.ts +1 -1
- package/src/helpers/toggleLegendActive.ts +25 -0
- package/src/hooks/useApplyTooltipsToGeo.tsx +51 -0
- package/src/hooks/useColumnsRequiredChecker.ts +51 -0
- package/src/hooks/useGeoClickHandler.ts +45 -0
- package/src/hooks/useLegendSeparators.ts +26 -0
- package/src/hooks/useMapLayers.tsx +34 -60
- package/src/hooks/useModal.ts +22 -0
- package/src/hooks/useResizeObserver.ts +4 -5
- package/src/hooks/useStateZoom.tsx +52 -75
- package/src/hooks/useTooltip.ts +2 -3
- package/src/index.jsx +3 -9
- package/src/scss/editor-panel.scss +3 -99
- package/src/scss/main.scss +1 -19
- package/src/scss/map.scss +15 -220
- package/src/store/map.actions.ts +46 -0
- package/src/store/map.reducer.ts +96 -0
- package/src/types/Annotations.ts +24 -0
- package/src/types/MapConfig.ts +23 -3
- package/src/types/MapContext.ts +36 -35
- package/src/types/Modal.ts +1 -0
- package/src/types/RuntimeData.ts +3 -0
- package/examples/private/DEV-9644.json +0 -184
- package/examples/private/DEV-9989.json +0 -229
- package/examples/private/ardi.json +0 -180
- package/examples/private/colors 2.json +0 -416
- package/examples/private/colors.json +0 -416
- package/examples/private/colors.json.zip +0 -0
- package/examples/private/customColors.json +0 -45348
- package/examples/test.json +0 -183
- package/src/helpers/closeModal.ts +0 -9
- package/src/scss/btn.scss +0 -69
- package/src/scss/filters.scss +0 -27
- package/src/scss/variables.scss +0 -1
- /package/src/hooks/{useActiveElement.js → useActiveElement.ts} +0 -0
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
import { useEffect, useState, useRef, useContext } from 'react'
|
|
2
|
-
import * as d3 from 'd3-geo'
|
|
3
|
-
|
|
4
2
|
import { geoCentroid, geoPath, geoContains } from 'd3-geo'
|
|
5
3
|
import { feature } from 'topojson-client'
|
|
6
4
|
import { geoAlbersUsaTerritories } from 'd3-composite-projections'
|
|
7
5
|
import debounce from 'lodash.debounce'
|
|
8
|
-
|
|
9
6
|
import Loading from '@cdc/core/components/Loading'
|
|
10
7
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
11
|
-
|
|
12
8
|
import useMapLayers from '../../../hooks/useMapLayers'
|
|
13
9
|
import ConfigContext from '../../../context'
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
drawShape,
|
|
22
|
-
createShapeProperties
|
|
23
|
-
} from '../helpers/shapes'
|
|
24
|
-
import { getGeoStrokeColor } from '../../../helpers/colors'
|
|
25
|
-
import { handleMapAriaLabels } from '../../../helpers/handleMapAriaLabels'
|
|
10
|
+
import { drawShape, createShapeProperties } from '../helpers/shapes'
|
|
11
|
+
import { getGeoStrokeColor, handleMapAriaLabels, displayGeoName } from '../../../helpers'
|
|
12
|
+
import useGeoClickHandler from '../../../hooks/useGeoClickHandler'
|
|
13
|
+
import { applyLegendToRow } from '../../../helpers/applyLegendToRow'
|
|
14
|
+
import useApplyTooltipsToGeo from '../../../hooks/useApplyTooltipsToGeo'
|
|
15
|
+
import { MapConfig } from '../../../types/MapConfig'
|
|
16
|
+
import { DEFAULT_MAP_BACKGROUND } from '../../../helpers/constants'
|
|
26
17
|
|
|
27
18
|
const getCountyTopoURL = year => {
|
|
28
19
|
return `https://www.cdc.gov/TemplatePackage/contrib/data/county-topography/cb_${year}_us_county_20m.json`
|
|
@@ -35,7 +26,7 @@ const sortById = (a, b) => {
|
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
const getTopoData = year => {
|
|
38
|
-
return new Promise(
|
|
29
|
+
return new Promise(resolve => {
|
|
39
30
|
const resolveWithTopo = async response => {
|
|
40
31
|
if (response.status !== 200) {
|
|
41
32
|
response = await import(/* webpackChunkName: "cb_2019_us_county_20m" */ './../data/cb_2019_us_county_20m.json')
|
|
@@ -43,7 +34,14 @@ const getTopoData = year => {
|
|
|
43
34
|
response = await response.json()
|
|
44
35
|
}
|
|
45
36
|
|
|
46
|
-
let topoData = {
|
|
37
|
+
let topoData = {
|
|
38
|
+
year: undefined,
|
|
39
|
+
counties: undefined,
|
|
40
|
+
states: undefined,
|
|
41
|
+
mapData: undefined,
|
|
42
|
+
countyIndecies: undefined,
|
|
43
|
+
projection: undefined
|
|
44
|
+
}
|
|
47
45
|
|
|
48
46
|
topoData.year = year || 'default'
|
|
49
47
|
topoData.counties = feature(response, response.objects.counties).features
|
|
@@ -109,11 +107,11 @@ const getTopoData = year => {
|
|
|
109
107
|
})
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
const getCurrentTopoYear = (
|
|
113
|
-
let currentYear =
|
|
110
|
+
const getCurrentTopoYear = (config: MapConfig, runtimeFilters) => {
|
|
111
|
+
let currentYear = config.general.countyCensusYear
|
|
114
112
|
|
|
115
|
-
if (
|
|
116
|
-
let yearFilter = runtimeFilters.filter(filter => filter.columnName ===
|
|
113
|
+
if (config.general.filterControlsCountyYear && runtimeFilters && runtimeFilters.length > 0) {
|
|
114
|
+
let yearFilter = runtimeFilters.filter(filter => filter.columnName === config.general.filterControlsCountyYear)
|
|
117
115
|
if (yearFilter.length > 0 && yearFilter[0].active) {
|
|
118
116
|
currentYear = yearFilter[0].active
|
|
119
117
|
}
|
|
@@ -122,40 +120,37 @@ const getCurrentTopoYear = (state, runtimeFilters) => {
|
|
|
122
120
|
return currentYear || 'default'
|
|
123
121
|
}
|
|
124
122
|
|
|
125
|
-
const isTopoReady = (topoData,
|
|
126
|
-
let currentYear = getCurrentTopoYear(
|
|
123
|
+
const isTopoReady = (topoData, config: MapConfig, runtimeFilters) => {
|
|
124
|
+
let currentYear = getCurrentTopoYear(config, runtimeFilters)
|
|
127
125
|
|
|
128
126
|
return topoData.year && (!currentYear || currentYear === topoData.year)
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
const CountyMap =
|
|
132
|
-
// prettier-ignore
|
|
129
|
+
const CountyMap = () => {
|
|
133
130
|
const {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
tooltipId,
|
|
146
|
-
tooltipRef,
|
|
131
|
+
container,
|
|
132
|
+
containerEl,
|
|
133
|
+
data,
|
|
134
|
+
runtimeFilters,
|
|
135
|
+
runtimeLegend,
|
|
136
|
+
setConfig,
|
|
137
|
+
config,
|
|
138
|
+
tooltipId,
|
|
139
|
+
tooltipRef,
|
|
140
|
+
legendMemo,
|
|
141
|
+
legendSpecialClassLastMemo
|
|
147
142
|
} = useContext(ConfigContext)
|
|
148
143
|
|
|
149
144
|
// CREATE STATE LINES
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
|
|
145
|
+
const geoStrokeColor = getGeoStrokeColor(config)
|
|
146
|
+
const { geoClickHandler } = useGeoClickHandler()
|
|
147
|
+
const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
|
|
153
148
|
const [focus, setFocus] = useState({})
|
|
154
149
|
const [topoData, setTopoData] = useState({})
|
|
155
150
|
|
|
156
151
|
const pathGenerator = geoPath().projection(geoAlbersUsaTerritories())
|
|
157
152
|
|
|
158
|
-
const { featureArray } = useMapLayers(
|
|
153
|
+
const { featureArray } = useMapLayers(config, setConfig, pathGenerator, tooltipId)
|
|
159
154
|
|
|
160
155
|
useEffect(() => {
|
|
161
156
|
if (containerEl) {
|
|
@@ -166,7 +161,7 @@ const CountyMap = props => {
|
|
|
166
161
|
})
|
|
167
162
|
|
|
168
163
|
useEffect(() => {
|
|
169
|
-
let currentYear = getCurrentTopoYear(
|
|
164
|
+
let currentYear = getCurrentTopoYear(config, runtimeFilters)
|
|
170
165
|
|
|
171
166
|
if (currentYear !== topoData.year) {
|
|
172
167
|
getTopoData(currentYear).then(response => {
|
|
@@ -177,17 +172,17 @@ const CountyMap = props => {
|
|
|
177
172
|
setTopoData(response)
|
|
178
173
|
})
|
|
179
174
|
}
|
|
180
|
-
}, [
|
|
175
|
+
}, [config.general.countyCensusYear, config.general.filterControlsCountyYear, JSON.stringify(runtimeFilters)])
|
|
181
176
|
|
|
182
177
|
// Whenever the memo at the top is triggered and the map is called to re-render, call drawCanvas and update
|
|
183
178
|
// The resize function so it includes the latest state variables
|
|
184
179
|
useEffect(() => {
|
|
185
|
-
if (isTopoReady(topoData,
|
|
180
|
+
if (isTopoReady(topoData, config, runtimeFilters)) {
|
|
186
181
|
drawCanvas()
|
|
187
182
|
}
|
|
188
183
|
|
|
189
184
|
const onResize = () => {
|
|
190
|
-
if (canvasRef.current && isTopoReady(topoData,
|
|
185
|
+
if (canvasRef.current && isTopoReady(topoData, config, runtimeFilters)) {
|
|
191
186
|
drawCanvas()
|
|
192
187
|
}
|
|
193
188
|
}
|
|
@@ -203,7 +198,7 @@ const CountyMap = props => {
|
|
|
203
198
|
const canvasRef = useRef()
|
|
204
199
|
|
|
205
200
|
// If runtimeData is not defined, show loader
|
|
206
|
-
if (!data || !isTopoReady(topoData,
|
|
201
|
+
if (!data || !isTopoReady(topoData, config, runtimeFilters)) {
|
|
207
202
|
return (
|
|
208
203
|
<div style={{ height: 300 }}>
|
|
209
204
|
<Loading />
|
|
@@ -215,8 +210,8 @@ const CountyMap = props => {
|
|
|
215
210
|
const lineWidth = 1
|
|
216
211
|
|
|
217
212
|
const onReset = () => {
|
|
218
|
-
|
|
219
|
-
...
|
|
213
|
+
setConfig({
|
|
214
|
+
...config,
|
|
220
215
|
mapPosition: { coordinates: [0, 30], zoom: 1 }
|
|
221
216
|
})
|
|
222
217
|
setFocus({})
|
|
@@ -240,8 +235,8 @@ const CountyMap = props => {
|
|
|
240
235
|
|
|
241
236
|
// If the user clicked outside of all states, no behavior
|
|
242
237
|
if (clickedState) {
|
|
243
|
-
|
|
244
|
-
...
|
|
238
|
+
setConfig({
|
|
239
|
+
...config,
|
|
245
240
|
mapPosition: { coordinates: [0, 30], zoom: 3 }
|
|
246
241
|
})
|
|
247
242
|
|
|
@@ -274,13 +269,13 @@ const CountyMap = props => {
|
|
|
274
269
|
// Redraw with focus on state
|
|
275
270
|
setFocus({ id: clickedState.id, index: focusIndex, center: geoCentroid(clickedState), feature: clickedState })
|
|
276
271
|
}
|
|
277
|
-
if (
|
|
278
|
-
const geoRadius = (
|
|
272
|
+
if (config.general.type === 'us-geocode') {
|
|
273
|
+
const geoRadius = (config.visual.geoCodeCircleSize || 5) * (focus.id ? 2 : 1)
|
|
279
274
|
let clickedGeo
|
|
280
275
|
for (let i = 0; i < runtimeKeys.length; i++) {
|
|
281
276
|
const pixelCoords = topoData.projection([
|
|
282
|
-
data[runtimeKeys[i]][
|
|
283
|
-
data[runtimeKeys[i]][
|
|
277
|
+
data[runtimeKeys[i]][config.columns.longitude.name],
|
|
278
|
+
data[runtimeKeys[i]][config.columns.latitude.name]
|
|
284
279
|
])
|
|
285
280
|
if (pixelCoords && Math.sqrt(Math.pow(pixelCoords[0] - x, 2) + Math.pow(pixelCoords[1] - y, 2)) < geoRadius) {
|
|
286
281
|
clickedGeo = data[runtimeKeys[i]]
|
|
@@ -289,7 +284,7 @@ const CountyMap = props => {
|
|
|
289
284
|
}
|
|
290
285
|
|
|
291
286
|
if (clickedGeo) {
|
|
292
|
-
geoClickHandler(displayGeoName(clickedGeo[
|
|
287
|
+
geoClickHandler(displayGeoName(clickedGeo[config.columns.geo.name]), clickedGeo)
|
|
293
288
|
}
|
|
294
289
|
}
|
|
295
290
|
}
|
|
@@ -297,7 +292,7 @@ const CountyMap = props => {
|
|
|
297
292
|
const canvasHover = e => {
|
|
298
293
|
if (
|
|
299
294
|
!tooltipRef.current ||
|
|
300
|
-
|
|
295
|
+
config.tooltips.appearanceType !== 'hover' ||
|
|
301
296
|
window.matchMedia('(any-hover: none)').matches
|
|
302
297
|
)
|
|
303
298
|
return
|
|
@@ -312,17 +307,32 @@ const CountyMap = props => {
|
|
|
312
307
|
let pointCoordinates = topoData.projection.invert([x, y])
|
|
313
308
|
|
|
314
309
|
const currentTooltipIndex = parseInt(tooltipRef.current.getAttribute('data-index'))
|
|
315
|
-
const geoRadius = (
|
|
310
|
+
const geoRadius = (config.visual.geoCodeCircleSize || 5) * (focus.id ? 2 : 1)
|
|
316
311
|
|
|
317
312
|
const context = canvas.getContext('2d')
|
|
318
313
|
const path = geoPath(topoData.projection, context)
|
|
319
314
|
|
|
320
315
|
// Handle standard county map hover
|
|
321
|
-
if (
|
|
316
|
+
if (config.general.type !== 'us-geocode') {
|
|
322
317
|
//If no tooltip is shown, or if the current geo associated with the tooltip shown is no longer containing the mouse, then rerender the tooltip
|
|
323
318
|
if (isNaN(currentTooltipIndex) || !geoContains(topoData.mapData[currentTooltipIndex], pointCoordinates)) {
|
|
324
|
-
if (
|
|
325
|
-
|
|
319
|
+
if (
|
|
320
|
+
!isNaN(currentTooltipIndex) &&
|
|
321
|
+
applyLegendToRow(
|
|
322
|
+
data[topoData.mapData[currentTooltipIndex].id],
|
|
323
|
+
config,
|
|
324
|
+
runtimeLegend,
|
|
325
|
+
legendMemo,
|
|
326
|
+
legendSpecialClassLastMemo
|
|
327
|
+
)
|
|
328
|
+
) {
|
|
329
|
+
context.fillStyle = applyLegendToRow(
|
|
330
|
+
data[topoData.mapData[currentTooltipIndex].id],
|
|
331
|
+
config,
|
|
332
|
+
runtimeLegend,
|
|
333
|
+
legendMemo,
|
|
334
|
+
legendSpecialClassLastMemo
|
|
335
|
+
)[0]
|
|
326
336
|
context.strokeStyle = geoStrokeColor
|
|
327
337
|
context.lineWidth = lineWidth
|
|
328
338
|
context.beginPath()
|
|
@@ -342,7 +352,7 @@ const CountyMap = props => {
|
|
|
342
352
|
}
|
|
343
353
|
}
|
|
344
354
|
|
|
345
|
-
// If a state is hovered and it is not an unfocused state, search only the counties within that state for the county hovered
|
|
355
|
+
// If a state is hovered, and it is not an unfocused state, search only the counties within that state for the county hovered
|
|
346
356
|
if (hoveredState && (!focus.id || focus.id === hoveredState) && topoData.countyIndecies[hoveredState]) {
|
|
347
357
|
for (let i = topoData.countyIndecies[hoveredState][0]; i <= topoData.countyIndecies[hoveredState][1]; i++) {
|
|
348
358
|
if (geoContains(topoData.mapData[i], pointCoordinates)) {
|
|
@@ -355,9 +365,17 @@ const CountyMap = props => {
|
|
|
355
365
|
|
|
356
366
|
// If the hovered county is found, show the tooltip for that county, otherwise hide the tooltip
|
|
357
367
|
if (county && data[county.id]) {
|
|
358
|
-
if (applyLegendToRow(data[county.id])) {
|
|
368
|
+
if (applyLegendToRow(data[county.id], config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)) {
|
|
369
|
+
let fillColor = applyLegendToRow(
|
|
370
|
+
data[county.id],
|
|
371
|
+
config,
|
|
372
|
+
runtimeLegend,
|
|
373
|
+
legendMemo,
|
|
374
|
+
legendSpecialClassLastMemo
|
|
375
|
+
)[0]
|
|
376
|
+
if (fillColor === '#000000') return
|
|
359
377
|
context.globalAlpha = 1
|
|
360
|
-
context.fillStyle =
|
|
378
|
+
context.fillStyle = fillColor
|
|
361
379
|
context.strokeStyle = geoStrokeColor
|
|
362
380
|
context.lineWidth = lineWidth
|
|
363
381
|
context.beginPath()
|
|
@@ -386,11 +404,10 @@ const CountyMap = props => {
|
|
|
386
404
|
// Handle geo map hover
|
|
387
405
|
if (!isNaN(currentTooltipIndex)) {
|
|
388
406
|
const pixelCoords = topoData.projection([
|
|
389
|
-
data[runtimeKeys[currentTooltipIndex]][
|
|
390
|
-
data[runtimeKeys[currentTooltipIndex]][
|
|
407
|
+
data[runtimeKeys[currentTooltipIndex]][config.columns.longitude.name],
|
|
408
|
+
data[runtimeKeys[currentTooltipIndex]][config.columns.latitude.name]
|
|
391
409
|
])
|
|
392
410
|
if (pixelCoords && Math.sqrt(Math.pow(pixelCoords[0] - x, 2) + Math.pow(pixelCoords[1] - y, 2)) < geoRadius) {
|
|
393
|
-
// Who knew pythagorean theorum was useful
|
|
394
411
|
return // The user is still hovering over the previous geo point, don't redraw tooltip
|
|
395
412
|
}
|
|
396
413
|
}
|
|
@@ -402,24 +419,27 @@ const CountyMap = props => {
|
|
|
402
419
|
let hoveredGeoIndex
|
|
403
420
|
for (let i = 0; i < runtimeKeys.length; i++) {
|
|
404
421
|
const pixelCoords = topoData.projection([
|
|
405
|
-
data[runtimeKeys[i]][
|
|
406
|
-
data[runtimeKeys[i]][
|
|
422
|
+
data[runtimeKeys[i]][config.columns.longitude.name],
|
|
423
|
+
data[runtimeKeys[i]][config.columns.latitude.name]
|
|
407
424
|
])
|
|
408
|
-
let includedShapes = ['circle', 'diamond', 'star', 'triangle', 'square'].includes(
|
|
425
|
+
let includedShapes = ['circle', 'diamond', 'star', 'triangle', 'square'].includes(config.visual.cityStyle)
|
|
409
426
|
if (
|
|
410
427
|
includedShapes &&
|
|
411
428
|
pixelCoords &&
|
|
412
429
|
Math.sqrt(Math.pow(pixelCoords[0] - x, 2) + Math.pow(pixelCoords[1] - y, 2)) < geoRadius &&
|
|
413
|
-
applyLegendToRow(data[runtimeKeys[i]])
|
|
430
|
+
applyLegendToRow(data[runtimeKeys[i]], config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
|
|
414
431
|
) {
|
|
415
432
|
hoveredGeo = data[runtimeKeys[i]]
|
|
416
433
|
hoveredGeoIndex = i
|
|
417
434
|
break
|
|
418
435
|
}
|
|
419
436
|
|
|
420
|
-
if (
|
|
437
|
+
if (config.visual.cityStyle === 'pin' && pixelCoords) {
|
|
421
438
|
const distance = Math.hypot(pixelCoords[0] - x, pixelCoords[1] - y)
|
|
422
|
-
if (
|
|
439
|
+
if (
|
|
440
|
+
distance < 15 &&
|
|
441
|
+
applyLegendToRow(data[runtimeKeys[i]], config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
|
|
442
|
+
) {
|
|
423
443
|
hoveredGeo = data[runtimeKeys[i]]
|
|
424
444
|
hoveredGeoIndex = i
|
|
425
445
|
break
|
|
@@ -438,7 +458,7 @@ const CountyMap = props => {
|
|
|
438
458
|
tooltipRef.current.style.left = tooltipX + 5 + 'px'
|
|
439
459
|
}
|
|
440
460
|
tooltipRef.current.innerHTML = applyTooltipsToGeo(
|
|
441
|
-
displayGeoName(hoveredGeo[
|
|
461
|
+
displayGeoName(hoveredGeo[config.columns.geo.name]),
|
|
442
462
|
hoveredGeo
|
|
443
463
|
)
|
|
444
464
|
tooltipRef.current.setAttribute('data-index', hoveredGeoIndex)
|
|
@@ -459,7 +479,7 @@ const CountyMap = props => {
|
|
|
459
479
|
|
|
460
480
|
// Redraws canvas. Takes as parameters the fips id of a state to center on and the [lat,long] center of that state
|
|
461
481
|
const drawCanvas = () => {
|
|
462
|
-
if (canvasRef.current && runtimeLegend.length > 0) {
|
|
482
|
+
if (canvasRef.current && runtimeLegend.items.length > 0) {
|
|
463
483
|
const canvas = canvasRef.current
|
|
464
484
|
const context = canvas.getContext('2d')
|
|
465
485
|
const path = geoPath(topoData.projection, context)
|
|
@@ -476,7 +496,7 @@ const CountyMap = props => {
|
|
|
476
496
|
if (resetButton.current) resetButton.current.style.display = 'block'
|
|
477
497
|
}
|
|
478
498
|
|
|
479
|
-
// Centers the projection on the
|
|
499
|
+
// Centers the projection on the parameter passed
|
|
480
500
|
// Centers the projection on the parameter passed
|
|
481
501
|
if (focus.feature) {
|
|
482
502
|
const PADDING = 10
|
|
@@ -495,20 +515,28 @@ const CountyMap = props => {
|
|
|
495
515
|
context.strokeStyle = geoStrokeColor
|
|
496
516
|
|
|
497
517
|
// Iterates through each state/county topo and renders it
|
|
498
|
-
topoData.mapData.forEach(
|
|
518
|
+
topoData.mapData.forEach(geo => {
|
|
499
519
|
// If invalid geo item, don't render
|
|
500
520
|
if (!geo.id) return
|
|
501
521
|
// If the map is focused on one state, don't render counties that are not in that state
|
|
502
522
|
if (focus.id && geo.id.length > 2 && geo.id.indexOf(focus.id) !== 0) return
|
|
503
523
|
// If rendering a geocode map without a focus, don't render counties
|
|
504
|
-
if (!focus.id &&
|
|
524
|
+
if (!focus.id && config.general.type === 'us-geocode' && geo.id.length > 2) return
|
|
505
525
|
|
|
506
526
|
// Gets numeric data associated with the topo data for this state/county
|
|
507
527
|
const geoData = data[geo.id]
|
|
508
528
|
|
|
509
529
|
// Renders state/county
|
|
510
|
-
const legendValues =
|
|
511
|
-
|
|
530
|
+
const legendValues =
|
|
531
|
+
geoData !== undefined
|
|
532
|
+
? applyLegendToRow(geoData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
|
|
533
|
+
: false
|
|
534
|
+
context.fillStyle =
|
|
535
|
+
legendValues && config.general.type !== 'us-geocode'
|
|
536
|
+
? legendValues[0] === '#000000'
|
|
537
|
+
? DEFAULT_MAP_BACKGROUND
|
|
538
|
+
: legendValues[0]
|
|
539
|
+
: DEFAULT_MAP_BACKGROUND
|
|
512
540
|
context.beginPath()
|
|
513
541
|
path(geo)
|
|
514
542
|
context.fill()
|
|
@@ -537,10 +565,10 @@ const CountyMap = props => {
|
|
|
537
565
|
})
|
|
538
566
|
}
|
|
539
567
|
|
|
540
|
-
if (
|
|
568
|
+
if (config.general.type === 'us-geocode') {
|
|
541
569
|
context.strokeStyle = geoStrokeColor
|
|
542
|
-
const geoRadius = (
|
|
543
|
-
const { additionalCityStyles } =
|
|
570
|
+
const geoRadius = (config.visual.geoCodeCircleSize || 5) * (focus.id ? 2 : 1)
|
|
571
|
+
const { additionalCityStyles } = config.visual || []
|
|
544
572
|
const cityStyles = Object.values(data)
|
|
545
573
|
.filter(d => additionalCityStyles.some(style => String(d[style.column]) === String(style.value)))
|
|
546
574
|
.map(d => {
|
|
@@ -552,15 +580,25 @@ const CountyMap = props => {
|
|
|
552
580
|
|
|
553
581
|
let cityPixelCoords = []
|
|
554
582
|
cityStyles.forEach(city => {
|
|
555
|
-
cityPixelCoords = topoData.projection([
|
|
583
|
+
cityPixelCoords = topoData.projection([
|
|
584
|
+
city[config.columns.longitude.name],
|
|
585
|
+
city[config.columns.latitude.name]
|
|
586
|
+
])
|
|
556
587
|
|
|
557
588
|
if (cityPixelCoords) {
|
|
558
|
-
const legendValues = applyLegendToRow(
|
|
589
|
+
const legendValues = applyLegendToRow(
|
|
590
|
+
data[city?.value],
|
|
591
|
+
config,
|
|
592
|
+
runtimeLegend,
|
|
593
|
+
legendMemo,
|
|
594
|
+
legendSpecialClassLastMemo
|
|
595
|
+
)
|
|
559
596
|
if (legendValues) {
|
|
597
|
+
if (legendValues?.[0] === '#000000') return
|
|
560
598
|
const shapeType = city?.shape?.toLowerCase()
|
|
561
|
-
const shapeProperties = createShapeProperties(shapeType, cityPixelCoords, legendValues,
|
|
599
|
+
const shapeProperties = createShapeProperties(shapeType, cityPixelCoords, legendValues, config, geoRadius)
|
|
562
600
|
if (shapeProperties) {
|
|
563
|
-
drawShape(shapeProperties, context,
|
|
601
|
+
drawShape(shapeProperties, context, config, lineWidth)
|
|
564
602
|
}
|
|
565
603
|
}
|
|
566
604
|
}
|
|
@@ -570,16 +608,20 @@ const CountyMap = props => {
|
|
|
570
608
|
const citiesList = new Set(cityStyles.map(item => item.value))
|
|
571
609
|
|
|
572
610
|
const pixelCoords = topoData.projection([
|
|
573
|
-
data[key][
|
|
574
|
-
data[key][
|
|
611
|
+
data[key][config.columns.longitude.name],
|
|
612
|
+
data[key][config.columns.latitude.name]
|
|
575
613
|
])
|
|
576
614
|
if (pixelCoords && !citiesList.has(key)) {
|
|
577
|
-
const legendValues =
|
|
615
|
+
const legendValues =
|
|
616
|
+
data[key] !== undefined
|
|
617
|
+
? applyLegendToRow(data[key], config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
|
|
618
|
+
: false
|
|
578
619
|
if (legendValues) {
|
|
579
|
-
|
|
580
|
-
const
|
|
620
|
+
if (legendValues?.[0] === '#000000' || legendValues?.[0] === DEFAULT_MAP_BACKGROUND) return
|
|
621
|
+
const shapeType = config.visual.cityStyle.toLowerCase()
|
|
622
|
+
const shapeProperties = createShapeProperties(shapeType, pixelCoords, legendValues, config, geoRadius)
|
|
581
623
|
if (shapeProperties) {
|
|
582
|
-
drawShape(shapeProperties, context,
|
|
624
|
+
drawShape(shapeProperties, context, config, lineWidth)
|
|
583
625
|
}
|
|
584
626
|
}
|
|
585
627
|
}
|
|
@@ -592,7 +634,7 @@ const CountyMap = props => {
|
|
|
592
634
|
<ErrorBoundary component='CountyMap'>
|
|
593
635
|
<canvas
|
|
594
636
|
ref={canvasRef}
|
|
595
|
-
aria-label={handleMapAriaLabels(
|
|
637
|
+
aria-label={handleMapAriaLabels(config)}
|
|
596
638
|
onMouseMove={canvasHover}
|
|
597
639
|
onMouseOut={() => {
|
|
598
640
|
tooltipRef.current.style.display = 'none'
|
|
@@ -602,7 +644,7 @@ const CountyMap = props => {
|
|
|
602
644
|
className='county-map-canvas'
|
|
603
645
|
></canvas>
|
|
604
646
|
|
|
605
|
-
<button className={`btn btn--reset btn-primary`} onClick={onReset} ref={resetButton} tabIndex=
|
|
647
|
+
<button className={`btn btn--reset btn-primary p-absolute`} onClick={onReset} ref={resetButton} tabIndex={0}>
|
|
606
648
|
Reset Zoom
|
|
607
649
|
</button>
|
|
608
650
|
</ErrorBoundary>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#region-1-label,
|
|
2
|
+
#region-2-label,
|
|
3
|
+
#region-3-label,
|
|
4
|
+
#region-4-label,
|
|
5
|
+
#region-5-label,
|
|
6
|
+
#region-6-label,
|
|
7
|
+
#region-7-label,
|
|
8
|
+
#region-8-label,
|
|
9
|
+
#region-9-label,
|
|
10
|
+
#region-10-label {
|
|
11
|
+
background: #fff;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#region-1-label {
|
|
15
|
+
transform: translate(90%, 22%);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#region-2-label {
|
|
19
|
+
transform: translate(83%, 33%);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#region-3-label {
|
|
23
|
+
transform: translate(75%, 45%);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#region-4-label {
|
|
27
|
+
transform: translate(68%, 70%);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#region-5-label {
|
|
31
|
+
transform: translate(65%, 44%);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#region-6-label {
|
|
35
|
+
transform: translate(45%, 75%);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#region-7-label {
|
|
39
|
+
transform: translate(53%, 47%);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#region-8-label {
|
|
43
|
+
transform: translate(35%, 30%);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#region-9-label {
|
|
47
|
+
transform: translate(18%, 58%);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#region-10-label {
|
|
51
|
+
transform: translate(15%, 28%);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#region-2-territories,
|
|
55
|
+
#region-9-territories {
|
|
56
|
+
text {
|
|
57
|
+
font-weight: bold;
|
|
58
|
+
font-size: 14px;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#region-2-territories {
|
|
63
|
+
transform: translate(86%, 40%);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#region-9-territories {
|
|
67
|
+
transform: translate(4%, 72%);
|
|
68
|
+
|
|
69
|
+
.region-9-row2 {
|
|
70
|
+
transform: translateY(34px);
|
|
71
|
+
}
|
|
72
|
+
}
|