@cdc/map 4.22.10 → 4.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/495.js +3 -0
- package/dist/703.js +1 -0
- package/dist/856.js +3 -0
- package/dist/cdcmap.js +724 -120
- package/examples/bubble-us.json +362 -362
- package/examples/bubble-world.json +426 -426
- package/examples/city-state.json +434 -0
- package/examples/example-city-state.json +202 -25
- package/package.json +3 -4
- package/src/CdcMap.js +249 -423
- package/src/components/BubbleList.js +198 -240
- package/src/components/CityList.js +50 -97
- package/src/components/CountyMap.js +511 -600
- package/src/components/DataTable.js +223 -230
- package/src/components/EditorPanel.js +2395 -2551
- package/src/components/Filters.js +114 -0
- package/src/components/Geo.js +4 -14
- package/src/components/Modal.js +13 -23
- package/src/components/NavigationMenu.js +43 -39
- package/src/components/Sidebar.js +77 -93
- package/src/components/SingleStateMap.js +95 -151
- package/src/components/UsaMap.js +165 -214
- package/src/components/UsaRegionMap.js +122 -160
- package/src/components/WorldMap.js +96 -179
- package/src/components/ZoomableGroup.js +6 -26
- package/src/context.js +5 -0
- package/src/data/initial-state.js +20 -15
- package/src/data/supported-geos.js +3201 -3175
- package/src/hooks/useActiveElement.js +13 -13
- package/src/hooks/useColorPalette.ts +66 -74
- package/src/hooks/useZoomPan.js +22 -23
- package/src/index.html +32 -29
- package/src/scss/datatable.scss +1 -2
- package/src/scss/filters.scss +42 -0
- package/src/scss/main.scss +4 -3
- package/src/scss/sidebar.scss +22 -0
- package/examples/private/atsdr.json +0 -439
- package/examples/private/atsdr_new.json +0 -436
- package/examples/private/bubble.json +0 -285
- package/examples/private/city-state.json +0 -428
- package/examples/private/cty-issue.json +0 -42768
- package/examples/private/default-usa.json +0 -460
- package/examples/private/default-world-data.json +0 -1444
- package/examples/private/default.json +0 -968
- package/examples/private/legend-issue.json +0 -1
- package/examples/private/map-rounding-error.json +0 -42759
- package/examples/private/map.csv +0 -60
- package/examples/private/mdx.json +0 -210
- package/examples/private/monkeypox.json +0 -376
- package/examples/private/regions.json +0 -52
- package/examples/private/valid-data-map.csv +0 -59
- package/examples/private/wcmsrd-13881-data.json +0 -2858
- package/examples/private/wcmsrd-13881.json +0 -5823
- package/examples/private/wcmsrd-14492-data.json +0 -292
- package/examples/private/wcmsrd-14492.json +0 -114
- package/examples/private/wcmsrd-test.json +0 -268
- package/examples/private/world.json +0 -1580
- package/examples/private/worldmap.json +0 -1490
|
@@ -1,244 +1,202 @@
|
|
|
1
|
-
import React, {memo, useState, useEffect} from 'react'
|
|
2
|
-
import { scaleLinear } from 'd3-scale'
|
|
3
|
-
import { countryCoordinates } from '../data/country-coordinates'
|
|
4
|
-
import stateCoordinates from '../data/state-coordinates'
|
|
1
|
+
import React, { memo, useState, useEffect } from 'react'
|
|
2
|
+
import { scaleLinear } from 'd3-scale'
|
|
3
|
+
import { countryCoordinates } from '../data/country-coordinates'
|
|
4
|
+
import stateCoordinates from '../data/state-coordinates'
|
|
5
5
|
import ReactTooltip from 'react-tooltip'
|
|
6
6
|
|
|
7
|
-
export const BubbleList = (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
data-tip={toolTip}
|
|
202
|
-
data-for="tooltip"
|
|
203
|
-
className="bubble"
|
|
204
|
-
cx={ projection(coordinates)[0] || 0 } // || 0 handles error on loads where the data isn't ready
|
|
205
|
-
cy={ projection(coordinates)[1] || 0 }
|
|
206
|
-
r={ Number(size(item[primaryKey])) + 1 }
|
|
207
|
-
fill={"transparent"}
|
|
208
|
-
stroke={"white"}
|
|
209
|
-
strokeWidth={.5}
|
|
210
|
-
fillOpacity={.4}
|
|
211
|
-
onPointerDown={(e) => {
|
|
212
|
-
pointerX = e.clientX;
|
|
213
|
-
pointerY = e.clientY;
|
|
214
|
-
}}
|
|
215
|
-
onPointerUp={(e) => {
|
|
216
|
-
if (pointerX && pointerY &&
|
|
217
|
-
e.clientX > (pointerX - clickTolerance) &&
|
|
218
|
-
e.clientX < (pointerX + clickTolerance) &&
|
|
219
|
-
e.clientY > (pointerY - clickTolerance) &&
|
|
220
|
-
e.clientY < (pointerY + clickTolerance)
|
|
221
|
-
) {
|
|
222
|
-
handleCircleClick(state)
|
|
223
|
-
pointerX = undefined;
|
|
224
|
-
pointerY = undefined;
|
|
225
|
-
}
|
|
226
|
-
}}
|
|
227
|
-
transform={transform}
|
|
228
|
-
style={{ transition: 'all .25s ease-in-out', cursor: "pointer" }}
|
|
229
|
-
/>
|
|
230
|
-
}
|
|
231
|
-
</>
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return (
|
|
236
|
-
<g key={`group-${stateName.replace(' ', '')}`}>
|
|
237
|
-
{circle}
|
|
238
|
-
</g>
|
|
239
|
-
)
|
|
240
|
-
})
|
|
241
|
-
return bubbles;
|
|
242
|
-
}
|
|
7
|
+
export const BubbleList = ({ data: dataImport, state, projection, applyLegendToRow, applyTooltipsToGeo, handleCircleClick, runtimeData, displayGeoName }) => {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
ReactTooltip.hide()
|
|
10
|
+
}, [runtimeData])
|
|
11
|
+
|
|
12
|
+
const maxDataValue = Math.max(...dataImport.map(d => d[state.columns.primary.name]))
|
|
13
|
+
const hasBubblesWithZeroOnMap = state.visual.showBubbleZeros ? 0 : 1
|
|
14
|
+
// sort runtime data. Smaller bubbles should appear on top.
|
|
15
|
+
const sortedRuntimeData = Object.values(runtimeData).sort((a, b) => (a[state.columns.primary.name] < b[state.columns.primary.name] ? 1 : -1))
|
|
16
|
+
if (!sortedRuntimeData) return
|
|
17
|
+
|
|
18
|
+
const clickTolerance = 10
|
|
19
|
+
// Set bubble sizes
|
|
20
|
+
var size = scaleLinear().domain([hasBubblesWithZeroOnMap, maxDataValue]).range([state.visual.minBubbleSize, state.visual.maxBubbleSize])
|
|
21
|
+
|
|
22
|
+
// Start looping through the countries to create the bubbles.
|
|
23
|
+
if (state.general.geoType === 'world') {
|
|
24
|
+
const countries =
|
|
25
|
+
sortedRuntimeData &&
|
|
26
|
+
sortedRuntimeData.map((country, index) => {
|
|
27
|
+
let coordinates = countryCoordinates[country.uid]
|
|
28
|
+
|
|
29
|
+
if (!coordinates) return true
|
|
30
|
+
|
|
31
|
+
const countryName = displayGeoName(country[state.columns.geo.name])
|
|
32
|
+
const toolTip = applyTooltipsToGeo(countryName, country)
|
|
33
|
+
const legendColors = applyLegendToRow(country)
|
|
34
|
+
|
|
35
|
+
let primaryKey = state.columns.primary.name
|
|
36
|
+
if ((Math.floor(Number(country[primaryKey])) === 0 || country[primaryKey] === '') && !state.visual.showBubbleZeros) return
|
|
37
|
+
|
|
38
|
+
let transform = `translate(${projection([coordinates[1], coordinates[0]])})`
|
|
39
|
+
|
|
40
|
+
let pointerX, pointerY
|
|
41
|
+
|
|
42
|
+
if (!projection(coordinates)) return true
|
|
43
|
+
|
|
44
|
+
const circle = (
|
|
45
|
+
<>
|
|
46
|
+
<circle
|
|
47
|
+
key={`circle-${countryName.replace(' ', '')}`}
|
|
48
|
+
data-tip={toolTip}
|
|
49
|
+
data-for='tooltip'
|
|
50
|
+
className={`bubble country--${countryName}`}
|
|
51
|
+
cx={Number(projection(coordinates[1], coordinates[0])[0]) || 0} // || 0 handles error on loads where the data isn't ready
|
|
52
|
+
cy={Number(projection(coordinates[1], coordinates[0])[1]) || 0}
|
|
53
|
+
r={Number(size(country[primaryKey]))}
|
|
54
|
+
fill={legendColors[0]}
|
|
55
|
+
stroke={legendColors[0]}
|
|
56
|
+
strokeWidth={1.25}
|
|
57
|
+
fillOpacity={0.4}
|
|
58
|
+
onPointerDown={e => {
|
|
59
|
+
pointerX = e.clientX
|
|
60
|
+
pointerY = e.clientY
|
|
61
|
+
}}
|
|
62
|
+
onPointerUp={e => {
|
|
63
|
+
if (pointerX && pointerY && e.clientX > pointerX - clickTolerance && e.clientX < pointerX + clickTolerance && e.clientY > pointerY - clickTolerance && e.clientY < pointerY + clickTolerance) {
|
|
64
|
+
handleCircleClick(country)
|
|
65
|
+
pointerX = undefined
|
|
66
|
+
pointerY = undefined
|
|
67
|
+
}
|
|
68
|
+
}}
|
|
69
|
+
transform={transform}
|
|
70
|
+
style={{ transition: 'all .25s ease-in-out', cursor: 'pointer' }}
|
|
71
|
+
/>
|
|
72
|
+
|
|
73
|
+
{state.visual.extraBubbleBorder && (
|
|
74
|
+
<circle
|
|
75
|
+
key={`circle-${countryName.replace(' ', '')}`}
|
|
76
|
+
data-tip={toolTip}
|
|
77
|
+
data-for='tooltip'
|
|
78
|
+
className='bubble'
|
|
79
|
+
cx={Number(projection(coordinates[1], coordinates[0])[0]) || 0} // || 0 handles error on loads where the data isn't ready
|
|
80
|
+
cy={Number(projection(coordinates[1], coordinates[0])[1]) || 0}
|
|
81
|
+
r={Number(size(country[primaryKey])) + 1}
|
|
82
|
+
fill={'transparent'}
|
|
83
|
+
stroke={'white'}
|
|
84
|
+
strokeWidth={0.5}
|
|
85
|
+
onPointerDown={e => {
|
|
86
|
+
pointerX = e.clientX
|
|
87
|
+
pointerY = e.clientY
|
|
88
|
+
}}
|
|
89
|
+
onPointerUp={e => {
|
|
90
|
+
if (pointerX && pointerY && e.clientX > pointerX - clickTolerance && e.clientX < pointerX + clickTolerance && e.clientY > pointerY - clickTolerance && e.clientY < pointerY + clickTolerance) {
|
|
91
|
+
handleCircleClick(country)
|
|
92
|
+
pointerX = undefined
|
|
93
|
+
pointerY = undefined
|
|
94
|
+
}
|
|
95
|
+
}}
|
|
96
|
+
transform={transform}
|
|
97
|
+
style={{ transition: 'all .25s ease-in-out', cursor: 'pointer' }}
|
|
98
|
+
/>
|
|
99
|
+
)}
|
|
100
|
+
</>
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return <g key={`group-${countryName.replace(' ', '')}`}>{circle}</g>
|
|
104
|
+
})
|
|
105
|
+
return countries
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (state.general.geoType === 'us') {
|
|
109
|
+
const bubbles =
|
|
110
|
+
sortedRuntimeData &&
|
|
111
|
+
sortedRuntimeData.map((item, index) => {
|
|
112
|
+
let stateData = stateCoordinates[item.uid]
|
|
113
|
+
let primaryKey = state?.columns?.primary?.name
|
|
114
|
+
if (Number(size(item[primaryKey])) === 0) return
|
|
115
|
+
|
|
116
|
+
if (item[primaryKey] === null) item[primaryKey] = ''
|
|
117
|
+
|
|
118
|
+
// Return if hiding zeros on the map
|
|
119
|
+
if ((Math.floor(Number(item[primaryKey])) === 0 || item[primaryKey] === '') && !state.visual.showBubbleZeros) return
|
|
120
|
+
|
|
121
|
+
if (!stateData) return true
|
|
122
|
+
let longitude = Number(stateData.Longitude)
|
|
123
|
+
let latitude = Number(stateData.Latitude)
|
|
124
|
+
let coordinates = [longitude, latitude]
|
|
125
|
+
//console.log('projection', projection([longitude, latitude]))
|
|
126
|
+
let stateName = stateData.Name
|
|
127
|
+
if (!coordinates) return true
|
|
128
|
+
|
|
129
|
+
stateName = displayGeoName(stateName)
|
|
130
|
+
const toolTip = applyTooltipsToGeo(stateName, item)
|
|
131
|
+
const legendColors = applyLegendToRow(item)
|
|
132
|
+
|
|
133
|
+
let transform = `translate(${projection([coordinates[1], coordinates[0]])})`
|
|
134
|
+
|
|
135
|
+
if (!projection(coordinates)) return true
|
|
136
|
+
|
|
137
|
+
let pointerX, pointerY
|
|
138
|
+
const circle = (
|
|
139
|
+
<>
|
|
140
|
+
<circle
|
|
141
|
+
key={`circle-${stateName.replace(' ', '')}`}
|
|
142
|
+
data-tip={toolTip}
|
|
143
|
+
data-for='tooltip'
|
|
144
|
+
className='bubble'
|
|
145
|
+
cx={projection(coordinates)[0] || 0} // || 0 handles error on loads where the data isn't ready
|
|
146
|
+
cy={projection(coordinates)[1] || 0}
|
|
147
|
+
r={Number(size(item[primaryKey]))}
|
|
148
|
+
fill={legendColors[0]}
|
|
149
|
+
stroke={legendColors[0]}
|
|
150
|
+
strokeWidth={1.25}
|
|
151
|
+
fillOpacity={0.4}
|
|
152
|
+
onPointerDown={e => {
|
|
153
|
+
pointerX = e.clientX
|
|
154
|
+
pointerY = e.clientY
|
|
155
|
+
}}
|
|
156
|
+
onPointerUp={e => {
|
|
157
|
+
if (pointerX && pointerY && e.clientX > pointerX - clickTolerance && e.clientX < pointerX + clickTolerance && e.clientY > pointerY - clickTolerance && e.clientY < pointerY + clickTolerance) {
|
|
158
|
+
handleCircleClick(state)
|
|
159
|
+
pointerX = undefined
|
|
160
|
+
pointerY = undefined
|
|
161
|
+
}
|
|
162
|
+
}}
|
|
163
|
+
transform={transform}
|
|
164
|
+
style={{ transition: 'all .25s ease-in-out', cursor: 'pointer' }}
|
|
165
|
+
/>
|
|
166
|
+
{state.visual.extraBubbleBorder && (
|
|
167
|
+
<circle
|
|
168
|
+
key={`circle-${stateName.replace(' ', '')}`}
|
|
169
|
+
data-tip={toolTip}
|
|
170
|
+
data-for='tooltip'
|
|
171
|
+
className='bubble'
|
|
172
|
+
cx={projection(coordinates)[0] || 0} // || 0 handles error on loads where the data isn't ready
|
|
173
|
+
cy={projection(coordinates)[1] || 0}
|
|
174
|
+
r={Number(size(item[primaryKey])) + 1}
|
|
175
|
+
fill={'transparent'}
|
|
176
|
+
stroke={'white'}
|
|
177
|
+
strokeWidth={0.5}
|
|
178
|
+
fillOpacity={0.4}
|
|
179
|
+
onPointerDown={e => {
|
|
180
|
+
pointerX = e.clientX
|
|
181
|
+
pointerY = e.clientY
|
|
182
|
+
}}
|
|
183
|
+
onPointerUp={e => {
|
|
184
|
+
if (pointerX && pointerY && e.clientX > pointerX - clickTolerance && e.clientX < pointerX + clickTolerance && e.clientY > pointerY - clickTolerance && e.clientY < pointerY + clickTolerance) {
|
|
185
|
+
handleCircleClick(state)
|
|
186
|
+
pointerX = undefined
|
|
187
|
+
pointerY = undefined
|
|
188
|
+
}
|
|
189
|
+
}}
|
|
190
|
+
transform={transform}
|
|
191
|
+
style={{ transition: 'all .25s ease-in-out', cursor: 'pointer' }}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
</>
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
return <g key={`group-${stateName.replace(' ', '')}`}>{circle}</g>
|
|
198
|
+
})
|
|
199
|
+
return bubbles
|
|
200
|
+
}
|
|
243
201
|
}
|
|
244
202
|
export default BubbleList
|
|
@@ -1,76 +1,58 @@
|
|
|
1
|
-
import React, { useState, useEffect, useContext } from 'react'
|
|
1
|
+
import React, { useState, useEffect, useContext } from 'react'
|
|
2
2
|
/** @jsx jsx */
|
|
3
3
|
import { jsx } from '@emotion/react'
|
|
4
|
-
import { supportedCities } from '../data/supported-geos'
|
|
5
|
-
import { scaleLinear } from 'd3-scale'
|
|
6
|
-
import ReactTooltip from 'react-tooltip'
|
|
7
|
-
|
|
8
|
-
const CityList = (
|
|
9
|
-
|
|
10
|
-
state,
|
|
11
|
-
geoClickHandler,
|
|
12
|
-
applyTooltipsToGeo,
|
|
13
|
-
displayGeoName,
|
|
14
|
-
applyLegendToRow,
|
|
15
|
-
projection,
|
|
16
|
-
titleCase,
|
|
17
|
-
setSharedFilterValue,
|
|
18
|
-
isFilterValueSupported,
|
|
19
|
-
isGeoCodeMap
|
|
20
|
-
}) => {
|
|
21
|
-
|
|
22
|
-
const [citiesData, setCitiesData] = useState({});
|
|
4
|
+
import { supportedCities } from '../data/supported-geos'
|
|
5
|
+
import { scaleLinear } from 'd3-scale'
|
|
6
|
+
import ReactTooltip from 'react-tooltip'
|
|
7
|
+
|
|
8
|
+
const CityList = ({ data, state, geoClickHandler, applyTooltipsToGeo, displayGeoName, applyLegendToRow, projection, titleCase, setSharedFilterValue, isFilterValueSupported, isGeoCodeMap }) => {
|
|
9
|
+
const [citiesData, setCitiesData] = useState({})
|
|
23
10
|
|
|
24
11
|
useEffect(() => {
|
|
25
12
|
ReactTooltip.rebuild()
|
|
26
|
-
})
|
|
13
|
+
})
|
|
27
14
|
|
|
28
15
|
useEffect(() => {
|
|
29
|
-
if(!isGeoCodeMap) {
|
|
30
|
-
const citiesList = Object.keys(data).filter(
|
|
31
|
-
|
|
32
|
-
const citiesDictionary = {}
|
|
33
|
-
|
|
34
|
-
citiesList.map(
|
|
35
|
-
|
|
36
|
-
setCitiesData(citiesDictionary)
|
|
16
|
+
if (!isGeoCodeMap) {
|
|
17
|
+
const citiesList = Object.keys(data).filter(item => Object.keys(supportedCities).includes(item))
|
|
18
|
+
|
|
19
|
+
const citiesDictionary = {}
|
|
20
|
+
|
|
21
|
+
citiesList.map(city => (citiesDictionary[city] = data[city]))
|
|
22
|
+
|
|
23
|
+
setCitiesData(citiesDictionary)
|
|
37
24
|
} else {
|
|
38
|
-
const citiesDictionary = {}
|
|
39
|
-
state.data.map(city => citiesDictionary[city[state.columns.geo.name]] = city)
|
|
40
|
-
setCitiesData(citiesDictionary)
|
|
25
|
+
const citiesDictionary = {}
|
|
26
|
+
state.data.map(city => (citiesDictionary[city[state.columns.geo.name]] = city))
|
|
27
|
+
setCitiesData(citiesDictionary)
|
|
41
28
|
}
|
|
42
|
-
}, [data, state.data])
|
|
29
|
+
}, [data, state.data])
|
|
43
30
|
|
|
44
31
|
if (state.general.type === 'bubble') {
|
|
45
32
|
const maxDataValue = Math.max(...state.data.map(d => d[state.columns.primary.name]))
|
|
46
|
-
const sortedRuntimeData = Object.values(data).sort((a, b) => a[state.columns.primary.name] < b[state.columns.primary.name] ? 1 : -1)
|
|
47
|
-
if (!sortedRuntimeData) return
|
|
33
|
+
const sortedRuntimeData = Object.values(data).sort((a, b) => (a[state.columns.primary.name] < b[state.columns.primary.name] ? 1 : -1))
|
|
34
|
+
if (!sortedRuntimeData) return
|
|
48
35
|
|
|
49
36
|
// Set bubble sizes
|
|
50
|
-
var size = scaleLinear()
|
|
51
|
-
.domain([1, maxDataValue])
|
|
52
|
-
.range([state.visual.minBubbleSize, state.visual.maxBubbleSize])
|
|
53
|
-
|
|
37
|
+
var size = scaleLinear().domain([1, maxDataValue]).range([state.visual.minBubbleSize, state.visual.maxBubbleSize])
|
|
54
38
|
}
|
|
55
|
-
let cityList = isGeoCodeMap ? Object.keys(citiesData).filter(
|
|
56
|
-
if(!cityList) return true
|
|
39
|
+
let cityList = isGeoCodeMap ? Object.keys(citiesData).filter(c => undefined !== c) : Object.keys(citiesData).filter(c => undefined !== data[c])
|
|
40
|
+
if (!cityList) return true
|
|
57
41
|
|
|
58
42
|
// Cities output
|
|
59
43
|
const cities = cityList.map((city, i) => {
|
|
44
|
+
const geoData = isGeoCodeMap ? state.data.filter(item => city === item[state.columns.geo.name])[0] : data[city]
|
|
45
|
+
const cityDisplayName = isGeoCodeMap ? city : titleCase(displayGeoName(city))
|
|
60
46
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const cityDisplayName = isGeoCodeMap ? city : titleCase( displayGeoName(city) );
|
|
64
|
-
|
|
65
|
-
const legendColors = (isGeoCodeMap && geoData) ? applyLegendToRow(geoData) : data[city] ? applyLegendToRow(data[city]) : false;
|
|
47
|
+
const legendColors = isGeoCodeMap && geoData ? applyLegendToRow(geoData) : data[city] ? applyLegendToRow(data[city]) : false
|
|
66
48
|
|
|
67
49
|
if (legendColors === false) {
|
|
68
|
-
return true
|
|
50
|
+
return true
|
|
69
51
|
}
|
|
70
52
|
|
|
71
53
|
const styles = {
|
|
72
54
|
fill: legendColors[0],
|
|
73
|
-
opacity: setSharedFilterValue && isFilterValueSupported && data[city][state.columns.geo.name] !== setSharedFilterValue ? .5 : 1,
|
|
55
|
+
opacity: setSharedFilterValue && isFilterValueSupported && data[city][state.columns.geo.name] !== setSharedFilterValue ? 0.5 : 1,
|
|
74
56
|
stroke: setSharedFilterValue && isFilterValueSupported && data[city][state.columns.geo.name] === setSharedFilterValue ? 'rgba(0, 0, 0, 1)' : 'rgba(0, 0, 0, 0.4)',
|
|
75
57
|
'&:hover': {
|
|
76
58
|
fill: legendColors[1],
|
|
@@ -80,54 +62,30 @@ const CityList = (({
|
|
|
80
62
|
fill: legendColors[2],
|
|
81
63
|
outline: 0
|
|
82
64
|
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
65
|
+
}
|
|
86
66
|
|
|
87
|
-
const toolTip = applyTooltipsToGeo(cityDisplayName, data[city])
|
|
67
|
+
const toolTip = applyTooltipsToGeo(cityDisplayName, data[city])
|
|
88
68
|
|
|
89
69
|
// If we need to add a cursor pointer
|
|
90
|
-
if ((state.columns.navigate &&
|
|
70
|
+
if ((state.columns.navigate && geoData?.[state.columns.navigate.name] && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
|
|
91
71
|
styles.cursor = 'pointer'
|
|
92
72
|
}
|
|
93
73
|
|
|
94
|
-
const radius = state.general.geoType === 'us' && !isGeoCodeMap ? 8 : isGeoCodeMap ?
|
|
74
|
+
const radius = state.general.geoType === 'us' && !isGeoCodeMap ? 8 : isGeoCodeMap ? state.visual.geoCodeCircleSize : 4
|
|
95
75
|
|
|
96
76
|
const additionalProps = {
|
|
97
|
-
fillOpacity: state.general.type === 'bubble' ? .4 : 1
|
|
77
|
+
fillOpacity: state.general.type === 'bubble' ? 0.4 : 1
|
|
98
78
|
}
|
|
99
79
|
|
|
100
|
-
const circle = (
|
|
101
|
-
<circle
|
|
102
|
-
data-tip={toolTip}
|
|
103
|
-
data-for="tooltip"
|
|
104
|
-
cx={0}
|
|
105
|
-
cy={0}
|
|
106
|
-
r={ state.general.type === 'bubble' ? size(geoData[state.columns.primary.name]) : radius}
|
|
107
|
-
title="Click for more information"
|
|
108
|
-
onClick={() => geoClickHandler(cityDisplayName, geoData)}
|
|
109
|
-
{...additionalProps}
|
|
110
|
-
/>
|
|
111
|
-
);
|
|
80
|
+
const circle = <circle data-tip={toolTip} data-for='tooltip' cx={0} cy={0} r={state.general.type === 'bubble' ? size(geoData[state.columns.primary.name]) : radius} title='Click for more information' onClick={() => geoClickHandler(cityDisplayName, geoData)} {...additionalProps} />
|
|
112
81
|
|
|
113
82
|
const pin = (
|
|
114
|
-
<path
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
data-for="tooltip"
|
|
121
|
-
strokeWidth={2}
|
|
122
|
-
stroke={'black'}
|
|
123
|
-
{...additionalProps}
|
|
124
|
-
>
|
|
125
|
-
</path>
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
let transform = '';
|
|
129
|
-
|
|
130
|
-
if (!isGeoCodeMap) {
|
|
83
|
+
<path className='marker' d='M0,0l-8.8-17.7C-12.1-24.3-7.4-32,0-32h0c7.4,0,12.1,7.7,8.8,14.3L0,0z' title='Click for more information' onClick={() => geoClickHandler(cityDisplayName, geoData)} data-tip={toolTip} data-for='tooltip' strokeWidth={2} stroke={'black'} {...additionalProps}></path>
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
let transform = ''
|
|
87
|
+
|
|
88
|
+
if (!isGeoCodeMap) {
|
|
131
89
|
transform = `translate(${projection(supportedCities[city])})`
|
|
132
90
|
}
|
|
133
91
|
|
|
@@ -137,19 +95,14 @@ const CityList = (({
|
|
|
137
95
|
}
|
|
138
96
|
|
|
139
97
|
return (
|
|
140
|
-
<g
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
css={styles}
|
|
144
|
-
className="geo-point"
|
|
145
|
-
>
|
|
146
|
-
{state.visual.cityStyle === 'circle' && circle }
|
|
147
|
-
{state.visual.cityStyle === 'pin' && pin }
|
|
98
|
+
<g key={i} transform={transform} css={styles} className='geo-point'>
|
|
99
|
+
{state.visual.cityStyle === 'circle' && circle}
|
|
100
|
+
{state.visual.cityStyle === 'pin' && pin}
|
|
148
101
|
</g>
|
|
149
|
-
)
|
|
150
|
-
})
|
|
102
|
+
)
|
|
103
|
+
})
|
|
151
104
|
|
|
152
|
-
return cities
|
|
153
|
-
}
|
|
105
|
+
return cities
|
|
106
|
+
}
|
|
154
107
|
|
|
155
|
-
export default CityList
|
|
108
|
+
export default CityList
|