@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,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect,
|
|
1
|
+
import React, { useState, useEffect, useContext, useRef } from 'react'
|
|
2
2
|
|
|
3
3
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
4
4
|
|
|
@@ -19,27 +19,40 @@ import { patternSizes } from '../helpers/patternSizes'
|
|
|
19
19
|
import Annotation from '../../Annotation'
|
|
20
20
|
import Territory from './Territory'
|
|
21
21
|
|
|
22
|
-
import
|
|
23
|
-
import ConfigContext from '../../../context'
|
|
22
|
+
import ConfigContext, { MapDispatchContext } from '../../../context'
|
|
24
23
|
import { MapContext } from '../../../types/MapContext'
|
|
25
24
|
import { checkColorContrast, getContrastColor, outlinedTextColor } from '@cdc/core/helpers/cove/accessibility'
|
|
26
|
-
import { getGeoFillColor, getGeoStrokeColor } from '../../../helpers/colors'
|
|
27
|
-
import { handleMapAriaLabels } from '../../../helpers/handleMapAriaLabels'
|
|
28
|
-
import { titleCase } from '../../../helpers/titleCase'
|
|
29
25
|
import TerritoriesSection from './TerritoriesSection'
|
|
30
|
-
import { displayGeoName } from '../../../helpers/displayGeoName'
|
|
31
26
|
|
|
27
|
+
import { isMobileStateLabelViewport } from '@cdc/core/helpers/viewports'
|
|
28
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
29
|
+
|
|
30
|
+
import useMapLayers from '../../../hooks/useMapLayers'
|
|
31
|
+
import useGeoClickHandler from '../../../hooks/useGeoClickHandler'
|
|
32
|
+
import { applyLegendToRow } from '../../../helpers/applyLegendToRow'
|
|
33
|
+
import useApplyTooltipsToGeo from '../../../hooks/useApplyTooltipsToGeo'
|
|
34
|
+
import {
|
|
35
|
+
getGeoFillColor,
|
|
36
|
+
getGeoStrokeColor,
|
|
37
|
+
handleMapAriaLabels,
|
|
38
|
+
titleCase,
|
|
39
|
+
displayGeoName,
|
|
40
|
+
SVG_HEIGHT,
|
|
41
|
+
SVG_VIEWBOX,
|
|
42
|
+
SVG_WIDTH,
|
|
43
|
+
hashObj
|
|
44
|
+
} from '../../../helpers'
|
|
32
45
|
const { features: unitedStatesHex } = topoFeature(hexTopoJSON, hexTopoJSON.objects.states)
|
|
33
46
|
|
|
34
47
|
const offsets = {
|
|
35
|
-
'US-VT': [
|
|
36
|
-
'US-NH': [
|
|
37
|
-
'US-MA': [
|
|
38
|
-
'US-RI': [
|
|
39
|
-
'US-CT': [
|
|
40
|
-
'US-NJ': [
|
|
48
|
+
'US-VT': [53, -7],
|
|
49
|
+
'US-NH': [38, 7],
|
|
50
|
+
'US-MA': [34, -1],
|
|
51
|
+
'US-RI': [29, 7],
|
|
52
|
+
'US-CT': [43, 20],
|
|
53
|
+
'US-NJ': [26, 7],
|
|
41
54
|
'US-DE': [33, 0],
|
|
42
|
-
'US-MD': [
|
|
55
|
+
'US-MD': [51, 16]
|
|
43
56
|
}
|
|
44
57
|
|
|
45
58
|
const nudges = {
|
|
@@ -55,22 +68,31 @@ const nudges = {
|
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
const UsaMap = () => {
|
|
58
|
-
// prettier-ignore
|
|
59
71
|
const {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
data,
|
|
73
|
+
setSharedFilterValue,
|
|
74
|
+
config,
|
|
75
|
+
setConfig,
|
|
76
|
+
tooltipId,
|
|
77
|
+
mapId,
|
|
78
|
+
logo,
|
|
79
|
+
legendMemo,
|
|
80
|
+
legendSpecialClassLastMemo,
|
|
81
|
+
currentViewport,
|
|
82
|
+
translate,
|
|
83
|
+
runtimeLegend
|
|
84
|
+
} = useContext<MapContext>(ConfigContext)
|
|
71
85
|
|
|
72
86
|
let isFilterValueSupported = false
|
|
73
|
-
const { general, columns,
|
|
87
|
+
const { general, columns, tooltips, hexMap, map, annotations } = config
|
|
88
|
+
const { displayAsHex } = general
|
|
89
|
+
const { geoClickHandler } = useGeoClickHandler()
|
|
90
|
+
const { applyTooltipsToGeo } = useApplyTooltipsToGeo()
|
|
91
|
+
const dispatch = useContext(MapDispatchContext)
|
|
92
|
+
|
|
93
|
+
const handleDragStateChange = (dragState: any) => {
|
|
94
|
+
dispatch({ type: 'SET_IS_DRAGGING_ANNOTATION', payload: dragState })
|
|
95
|
+
}
|
|
74
96
|
|
|
75
97
|
if (setSharedFilterValue) {
|
|
76
98
|
Object.keys(supportedStates).forEach(supportedState => {
|
|
@@ -92,9 +114,20 @@ const UsaMap = () => {
|
|
|
92
114
|
}
|
|
93
115
|
|
|
94
116
|
// "Choose State" options
|
|
95
|
-
const [extent, setExtent] = useState(null)
|
|
96
117
|
const [focusedStates, setFocusedStates] = useState(null)
|
|
97
|
-
|
|
118
|
+
|
|
119
|
+
const dataRef = useRef(null)
|
|
120
|
+
|
|
121
|
+
const legendMemoUpdated = focusedStates?.every(geo => {
|
|
122
|
+
const geoKey = geo.properties.iso
|
|
123
|
+
const geoData = data[geoKey]
|
|
124
|
+
const hash = hashObj(geoData)
|
|
125
|
+
return legendMemo.current.has(hash)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// we use dataRef so that we can use the old data when legendMemo has not been updated yet
|
|
129
|
+
// prevents flickering of the map when filter is changed
|
|
130
|
+
if (legendMemoUpdated) dataRef.current = data
|
|
98
131
|
|
|
99
132
|
useEffect(() => {
|
|
100
133
|
const fetchData = async () => {
|
|
@@ -107,12 +140,9 @@ const UsaMap = () => {
|
|
|
107
140
|
|
|
108
141
|
// When returning from another map we want to reset the state
|
|
109
142
|
useEffect(() => {
|
|
110
|
-
|
|
111
|
-
setExtent(null)
|
|
143
|
+
dispatch({ type: 'SET_TRANSLATE', payload: [SVG_WIDTH / 2, SVG_HEIGHT / 2] })
|
|
112
144
|
}, [general.geoType])
|
|
113
145
|
|
|
114
|
-
const isHex = general.displayAsHex
|
|
115
|
-
|
|
116
146
|
const [territoriesData, setTerritoriesData] = useState([])
|
|
117
147
|
|
|
118
148
|
const territoriesKeys = Object.keys(supportedTerritories) // data will have already mapped abbreviated territories to their full names
|
|
@@ -123,25 +153,25 @@ const UsaMap = () => {
|
|
|
123
153
|
setTerritoriesData(territoriesKeys)
|
|
124
154
|
} else {
|
|
125
155
|
// Territories need to show up if they're in the data at all, not just if they're "active". That's why this is different from Cities
|
|
126
|
-
const territoriesList = territoriesKeys.filter(key => data[key])
|
|
156
|
+
const territoriesList = territoriesKeys.filter(key => data?.[key])
|
|
127
157
|
setTerritoriesData(territoriesList)
|
|
128
158
|
}
|
|
129
|
-
}, [data, general.territoriesAlwaysShow])
|
|
159
|
+
}, [data, dataRef.current, general.territoriesAlwaysShow])
|
|
130
160
|
|
|
131
|
-
const geoStrokeColor = getGeoStrokeColor(
|
|
132
|
-
const geoFillColor = getGeoFillColor(
|
|
161
|
+
const geoStrokeColor = getGeoStrokeColor(config)
|
|
162
|
+
const geoFillColor = getGeoFillColor(config)
|
|
133
163
|
|
|
134
164
|
const territories = territoriesData.map((territory, territoryIndex) => {
|
|
135
|
-
const Shape =
|
|
165
|
+
const Shape = displayAsHex ? Territory.Hexagon : Territory.Rectangle
|
|
136
166
|
|
|
137
|
-
const territoryData = data[territory]
|
|
167
|
+
const territoryData = data?.[territory]
|
|
138
168
|
|
|
139
169
|
let toolTip
|
|
140
170
|
|
|
141
171
|
let styles = {
|
|
142
172
|
fill: geoFillColor,
|
|
143
173
|
stroke: geoStrokeColor,
|
|
144
|
-
color:
|
|
174
|
+
color: APP_FONT_COLOR
|
|
145
175
|
}
|
|
146
176
|
|
|
147
177
|
const label = supportedTerritories[territory][1]
|
|
@@ -152,7 +182,8 @@ const UsaMap = () => {
|
|
|
152
182
|
key={label}
|
|
153
183
|
label={label}
|
|
154
184
|
style={styles}
|
|
155
|
-
|
|
185
|
+
textColor={styles.color}
|
|
186
|
+
strokeColor='#fff'
|
|
156
187
|
territoryData={territoryData}
|
|
157
188
|
backgroundColor={styles.fill}
|
|
158
189
|
/>
|
|
@@ -160,11 +191,9 @@ const UsaMap = () => {
|
|
|
160
191
|
|
|
161
192
|
toolTip = applyTooltipsToGeo(displayGeoName(territory), territoryData)
|
|
162
193
|
|
|
163
|
-
const legendColors = applyLegendToRow(territoryData)
|
|
194
|
+
const legendColors = applyLegendToRow(territoryData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
|
|
164
195
|
|
|
165
196
|
if (legendColors) {
|
|
166
|
-
const textColor = getContrastColor('#FFF', legendColors[0])
|
|
167
|
-
|
|
168
197
|
let needsPointer = false
|
|
169
198
|
|
|
170
199
|
// If we need to add a pointer cursor
|
|
@@ -172,6 +201,8 @@ const UsaMap = () => {
|
|
|
172
201
|
needsPointer = true
|
|
173
202
|
}
|
|
174
203
|
|
|
204
|
+
const { textColor, strokeColor } = outlinedTextColor(legendColors[0])
|
|
205
|
+
|
|
175
206
|
styles = {
|
|
176
207
|
color: textColor,
|
|
177
208
|
fill: legendColors[0],
|
|
@@ -197,9 +228,9 @@ const UsaMap = () => {
|
|
|
197
228
|
key={`label__${territoryIndex}`}
|
|
198
229
|
label={label}
|
|
199
230
|
style={styles}
|
|
200
|
-
text={styles.color}
|
|
201
231
|
strokeWidth={1}
|
|
202
232
|
textColor={textColor}
|
|
233
|
+
strokeColor={strokeColor}
|
|
203
234
|
handleShapeClick={() => geoClickHandler(territory, territoryData)}
|
|
204
235
|
dataTooltipId={`tooltip__${tooltipId}`}
|
|
205
236
|
dataTooltipHtml={toolTip}
|
|
@@ -214,8 +245,8 @@ const UsaMap = () => {
|
|
|
214
245
|
|
|
215
246
|
let pathGenerator = geoPath().projection(geoAlbersUsa().translate(translate))
|
|
216
247
|
|
|
217
|
-
// Note: Layers are different
|
|
218
|
-
const { pathArray } = useMapLayers(
|
|
248
|
+
// Note: Layers are different from patterns
|
|
249
|
+
const { pathArray } = useMapLayers(config, setConfig, pathGenerator, tooltipId)
|
|
219
250
|
|
|
220
251
|
if (!focusedStates) {
|
|
221
252
|
return <></>
|
|
@@ -246,7 +277,7 @@ const UsaMap = () => {
|
|
|
246
277
|
})
|
|
247
278
|
|
|
248
279
|
const geosJsx = geographies.map(({ feature: geo, path = '' }, geoIndex) => {
|
|
249
|
-
const key =
|
|
280
|
+
const key = displayAsHex ? geo.properties.iso + '-hex-group' : geo.properties.iso + '-group'
|
|
250
281
|
|
|
251
282
|
let styles = {
|
|
252
283
|
fill: geoFillColor,
|
|
@@ -259,13 +290,13 @@ const UsaMap = () => {
|
|
|
259
290
|
|
|
260
291
|
if (!geoKey) return
|
|
261
292
|
|
|
262
|
-
const geoData = data[geoKey]
|
|
293
|
+
const geoData = data?.[geoKey]
|
|
263
294
|
|
|
264
295
|
let legendColors
|
|
265
296
|
|
|
266
297
|
// Once we receive data for this geographic item, setup variables.
|
|
267
298
|
if (geoData !== undefined) {
|
|
268
|
-
legendColors = applyLegendToRow(geoData)
|
|
299
|
+
legendColors = applyLegendToRow(geoData, config, runtimeLegend, legendMemo, legendSpecialClassLastMemo)
|
|
269
300
|
}
|
|
270
301
|
|
|
271
302
|
const geoDisplayName = displayGeoName(geoKey)
|
|
@@ -275,7 +306,7 @@ const UsaMap = () => {
|
|
|
275
306
|
const tooltip = applyTooltipsToGeo(geoDisplayName, geoData)
|
|
276
307
|
|
|
277
308
|
styles = {
|
|
278
|
-
fill:
|
|
309
|
+
fill: config.general.type !== 'bubble' ? legendColors[0] : geoFillColor,
|
|
279
310
|
opacity:
|
|
280
311
|
setSharedFilterValue && isFilterValueSupported && setSharedFilterValue !== geoData[columns.geo.name]
|
|
281
312
|
? 0.5
|
|
@@ -286,10 +317,10 @@ const UsaMap = () => {
|
|
|
286
317
|
: geoStrokeColor,
|
|
287
318
|
cursor: 'default',
|
|
288
319
|
'&:hover': {
|
|
289
|
-
fill:
|
|
320
|
+
fill: config.general.type !== 'bubble' ? legendColors[1] : geoFillColor
|
|
290
321
|
},
|
|
291
322
|
'&:active': {
|
|
292
|
-
fill:
|
|
323
|
+
fill: config.general.type !== 'bubble' ? legendColors[2] : geoFillColor
|
|
293
324
|
}
|
|
294
325
|
}
|
|
295
326
|
|
|
@@ -307,7 +338,7 @@ const UsaMap = () => {
|
|
|
307
338
|
|
|
308
339
|
return (
|
|
309
340
|
<>
|
|
310
|
-
{hexMap.shapeGroups.map((group,
|
|
341
|
+
{hexMap.shapeGroups.map((group, _groupIndex) => {
|
|
311
342
|
return group.items.map((item, itemIndex) => {
|
|
312
343
|
switch (item.operator) {
|
|
313
344
|
case '=':
|
|
@@ -414,7 +445,7 @@ const UsaMap = () => {
|
|
|
414
445
|
<path tabIndex={-1} className='single-geo' strokeWidth={1} d={path} />
|
|
415
446
|
|
|
416
447
|
{/* apply patterns on top of state path*/}
|
|
417
|
-
{map
|
|
448
|
+
{map?.patterns?.map((patternData, _patternIndex) => {
|
|
418
449
|
const { pattern, dataKey, size } = patternData
|
|
419
450
|
const currentFill = styles.fill
|
|
420
451
|
const hasMatchingValues = patternData.dataValue === geoData?.[patternData.dataKey]
|
|
@@ -431,6 +462,7 @@ const UsaMap = () => {
|
|
|
431
462
|
height={patternSizes[size] ?? 10}
|
|
432
463
|
width={patternSizes[size] ?? 10}
|
|
433
464
|
fill={patternColor}
|
|
465
|
+
strokeWidth={0.25}
|
|
434
466
|
/>
|
|
435
467
|
)}
|
|
436
468
|
{pattern === 'circles' && (
|
|
@@ -439,6 +471,8 @@ const UsaMap = () => {
|
|
|
439
471
|
height={patternSizes[size] ?? 10}
|
|
440
472
|
width={patternSizes[size] ?? 10}
|
|
441
473
|
fill={patternColor}
|
|
474
|
+
stroke={patternColor}
|
|
475
|
+
radius={0.5}
|
|
442
476
|
/>
|
|
443
477
|
)}
|
|
444
478
|
{pattern === 'lines' && (
|
|
@@ -447,7 +481,7 @@ const UsaMap = () => {
|
|
|
447
481
|
height={patternSizes[size] ?? 6}
|
|
448
482
|
width={patternSizes[size] ?? 6}
|
|
449
483
|
stroke={patternColor}
|
|
450
|
-
strokeWidth={
|
|
484
|
+
strokeWidth={0.75}
|
|
451
485
|
orientation={['diagonalRightToLeft']}
|
|
452
486
|
/>
|
|
453
487
|
)}
|
|
@@ -461,8 +495,8 @@ const UsaMap = () => {
|
|
|
461
495
|
</>
|
|
462
496
|
)
|
|
463
497
|
})}
|
|
464
|
-
{(
|
|
465
|
-
{
|
|
498
|
+
{(displayAsHex || showLabel) && geoLabel(geo, legendColors[0], projection)}
|
|
499
|
+
{displayAsHex && hexMap.type === 'shapes' && getArrowDirection(geoData, geo, legendColors[0])}
|
|
466
500
|
</g>
|
|
467
501
|
</g>
|
|
468
502
|
)
|
|
@@ -473,27 +507,24 @@ const UsaMap = () => {
|
|
|
473
507
|
<g data-name={geoName} key={key} tabIndex={-1}>
|
|
474
508
|
<g className='geo-group' style={styles} tabIndex={-1}>
|
|
475
509
|
<path tabIndex={-1} className='single-geo' stroke={geoStrokeColor} strokeWidth={1.3} d={path} />
|
|
476
|
-
{(
|
|
510
|
+
{(displayAsHex || showLabel) && geoLabel(geo, styles.fill, projection)}
|
|
477
511
|
</g>
|
|
478
512
|
</g>
|
|
479
513
|
)
|
|
480
514
|
})
|
|
481
515
|
|
|
482
|
-
if (
|
|
516
|
+
if (displayAsHex) return geosJsx
|
|
483
517
|
|
|
484
518
|
// Cities
|
|
485
519
|
geosJsx.push(
|
|
486
520
|
<CityList
|
|
487
521
|
applyLegendToRow={applyLegendToRow}
|
|
488
522
|
applyTooltipsToGeo={applyTooltipsToGeo}
|
|
489
|
-
data={data}
|
|
490
|
-
displayGeoName={displayGeoName}
|
|
491
523
|
geoClickHandler={geoClickHandler}
|
|
492
524
|
isFilterValueSupported={isFilterValueSupported}
|
|
493
525
|
key='cities'
|
|
494
526
|
projection={projection}
|
|
495
527
|
setSharedFilterValue={setSharedFilterValue}
|
|
496
|
-
state={state}
|
|
497
528
|
titleCase={titleCase}
|
|
498
529
|
tooltipId={tooltipId}
|
|
499
530
|
/>
|
|
@@ -501,18 +532,7 @@ const UsaMap = () => {
|
|
|
501
532
|
|
|
502
533
|
// Bubbles
|
|
503
534
|
if (general.type === 'bubble') {
|
|
504
|
-
geosJsx.push(
|
|
505
|
-
<BubbleList
|
|
506
|
-
key='bubbles'
|
|
507
|
-
data={state.data}
|
|
508
|
-
runtimeData={data}
|
|
509
|
-
state={state}
|
|
510
|
-
projection={projection}
|
|
511
|
-
applyLegendToRow={applyLegendToRow}
|
|
512
|
-
applyTooltipsToGeo={applyTooltipsToGeo}
|
|
513
|
-
displayGeoName={displayGeoName}
|
|
514
|
-
/>
|
|
515
|
-
)
|
|
535
|
+
geosJsx.push(<BubbleList runtimeData={dataRef.current} projection={projection} />)
|
|
516
536
|
}
|
|
517
537
|
|
|
518
538
|
// })
|
|
@@ -526,13 +546,13 @@ const UsaMap = () => {
|
|
|
526
546
|
}
|
|
527
547
|
|
|
528
548
|
const geoLabel = (geo, bgColor = '#FFFFFF', projection) => {
|
|
529
|
-
|
|
530
|
-
|
|
549
|
+
const centroid = projection ? projection(geoCentroid(geo)) : [22, 17.5]
|
|
550
|
+
const abbr = geo.properties.iso
|
|
531
551
|
|
|
532
552
|
if (undefined === abbr) return null
|
|
533
553
|
|
|
534
554
|
// HI background is always white since it is off to the side
|
|
535
|
-
if (abbr === 'US-HI' && !general.displayAsHex) {
|
|
555
|
+
if ((abbr === 'US-HI' && !general.displayAsHex) || (Object.keys(offsets).includes(abbr) && !general.displayAsHex)) {
|
|
536
556
|
bgColor = '#FFF'
|
|
537
557
|
}
|
|
538
558
|
const { textColor, strokeColor } = outlinedTextColor(bgColor)
|
|
@@ -541,21 +561,22 @@ const UsaMap = () => {
|
|
|
541
561
|
y = hexMap.type === 'shapes' && general.displayAsHex ? -10 : 5
|
|
542
562
|
|
|
543
563
|
// used to nudge/move some of the labels for better readability
|
|
544
|
-
if (nudges[abbr] && false ===
|
|
564
|
+
if (nudges[abbr] && false === displayAsHex) {
|
|
545
565
|
x += nudges[abbr][0]
|
|
546
566
|
y += nudges[abbr][1]
|
|
547
567
|
}
|
|
548
568
|
|
|
549
|
-
if (undefined === offsets[abbr] ||
|
|
569
|
+
if (undefined === offsets[abbr] || displayAsHex) {
|
|
550
570
|
return (
|
|
551
571
|
<g transform={`translate(${centroid})`} tabIndex={-1}>
|
|
552
572
|
<text
|
|
553
573
|
x={x}
|
|
554
574
|
y={y}
|
|
555
|
-
fontSize={
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
575
|
+
fontSize={isMobileStateLabelViewport(currentViewport) ? 16 : 13}
|
|
576
|
+
fontWeight={900}
|
|
577
|
+
strokeWidth='1'
|
|
578
|
+
paintOrder='stroke'
|
|
579
|
+
stroke={strokeColor}
|
|
559
580
|
style={{ fill: textColor }}
|
|
560
581
|
textAnchor='middle'
|
|
561
582
|
>
|
|
@@ -580,9 +601,9 @@ const UsaMap = () => {
|
|
|
580
601
|
<text
|
|
581
602
|
x={4}
|
|
582
603
|
strokeWidth='0'
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
604
|
+
stroke={APP_FONT_COLOR}
|
|
605
|
+
fontSize={isMobileStateLabelViewport(currentViewport) ? 16 : 13}
|
|
606
|
+
fontWeight={900}
|
|
586
607
|
style={{ fill: textColor }}
|
|
587
608
|
alignmentBaseline='middle'
|
|
588
609
|
transform={`translate(${centroid[0] + dx}, ${centroid[1] + dy})`}
|
|
@@ -595,20 +616,20 @@ const UsaMap = () => {
|
|
|
595
616
|
|
|
596
617
|
return (
|
|
597
618
|
<ErrorBoundary component='UsaMap'>
|
|
598
|
-
<svg viewBox=
|
|
619
|
+
<svg viewBox={SVG_VIEWBOX} role='img' aria-label={handleMapAriaLabels(config)}>
|
|
599
620
|
{general.displayAsHex ? (
|
|
600
621
|
<Mercator data={unitedStatesHex} scale={650} translate={[1600, 775]}>
|
|
601
622
|
{({ features, projection }) => constructGeoJsx(features, projection)}
|
|
602
623
|
</Mercator>
|
|
603
624
|
) : (
|
|
604
|
-
<AlbersUsa data={focusedStates} translate={translate}
|
|
625
|
+
<AlbersUsa data={focusedStates} translate={translate}>
|
|
605
626
|
{({ features, projection }) => constructGeoJsx(features, projection)}
|
|
606
627
|
</AlbersUsa>
|
|
607
628
|
)}
|
|
608
|
-
{annotations
|
|
629
|
+
{annotations?.length > 0 && <Annotation.Draggable onDragStateChange={handleDragStateChange} />}
|
|
609
630
|
</svg>
|
|
610
631
|
|
|
611
|
-
<TerritoriesSection territories={territories} logo={logo} config={
|
|
632
|
+
<TerritoriesSection territories={territories} logo={logo} config={config} territoriesData={territoriesData} />
|
|
612
633
|
</ErrorBoundary>
|
|
613
634
|
)
|
|
614
635
|
}
|
|
@@ -82,7 +82,7 @@ export const getCurrentTopoYear = (state, runtimeFilters) => {
|
|
|
82
82
|
export const isTopoReady = (topoData, state, runtimeFilters) => {
|
|
83
83
|
let currentYear = getCurrentTopoYear(state, runtimeFilters)
|
|
84
84
|
|
|
85
|
-
return topoData
|
|
85
|
+
return topoData?.year && (!currentYear || currentYear === topoData?.year)
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export const hasMoreThanFromHash = (data: { [key: string]: any }): boolean => {
|
|
@@ -109,34 +109,47 @@ export const drawStar = (star, context, state) => {
|
|
|
109
109
|
const outerRadius = star.outerRadius * scaleVal
|
|
110
110
|
const innerRadius = star.innerRadius * scaleVal
|
|
111
111
|
|
|
112
|
+
// Adjust for zoom (based on your existing logic)
|
|
112
113
|
const adjustedOuterRadius = state.mapPosition.zoom > 1 ? outerRadius * percentOfOriginalSize : outerRadius
|
|
113
114
|
const adjustedInnerRadius = state.mapPosition.zoom > 1 ? innerRadius * percentOfOriginalSize : innerRadius
|
|
114
115
|
|
|
116
|
+
// Set line width and color
|
|
115
117
|
context.lineWidth = star.lineWidth
|
|
116
118
|
context.fillStyle = star.color
|
|
117
119
|
context.beginPath()
|
|
118
120
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
// Start drawing the star from the top (no rotation)
|
|
122
|
+
const startAngle = Math.PI / 2 // 90 degrees (points upwards)
|
|
123
|
+
let rot = startAngle
|
|
124
|
+
const step = Math.PI / spikes // angle between each spike
|
|
121
125
|
|
|
122
|
-
// Starting coordinates for the first point
|
|
123
|
-
let x = star.x
|
|
124
|
-
let y = star.y
|
|
125
|
-
context.moveTo(x, y
|
|
126
|
+
// Starting coordinates for the first point of the star
|
|
127
|
+
let x = star.x + Math.cos(rot) * adjustedOuterRadius
|
|
128
|
+
let y = star.y + Math.sin(rot) * adjustedOuterRadius
|
|
129
|
+
context.moveTo(x, y)
|
|
126
130
|
|
|
131
|
+
// Draw the star
|
|
127
132
|
for (let i = 0; i < spikes; i++) {
|
|
133
|
+
// Outer points of the star
|
|
128
134
|
x = star.x + Math.cos(rot) * adjustedOuterRadius
|
|
129
135
|
y = star.y + Math.sin(rot) * adjustedOuterRadius
|
|
130
136
|
context.lineTo(x, y)
|
|
131
137
|
rot += step
|
|
132
138
|
|
|
139
|
+
// Inner points of the star
|
|
133
140
|
x = star.x + Math.cos(rot) * adjustedInnerRadius
|
|
134
141
|
y = star.y + Math.sin(rot) * adjustedInnerRadius
|
|
135
142
|
context.lineTo(x, y)
|
|
136
143
|
rot += step
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
// Close the path by returning to the starting outer point
|
|
147
|
+
// This fixes the gap issue by making sure the first outer point is exactly the same
|
|
148
|
+
x = star.x + Math.cos(startAngle) * adjustedOuterRadius
|
|
149
|
+
y = star.y + Math.sin(startAngle) * adjustedOuterRadius
|
|
150
|
+
context.lineTo(x, y)
|
|
151
|
+
|
|
152
|
+
// Apply fill and stroke
|
|
140
153
|
context.closePath()
|
|
141
154
|
context.fill()
|
|
142
155
|
context.stroke()
|