@cdc/map 4.26.3 → 4.26.5

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.
Files changed (105) hide show
  1. package/CONFIG.md +268 -0
  2. package/README.md +74 -24
  3. package/dist/cdcmap-CY9IcPSi.es.js +6 -0
  4. package/dist/cdcmap-DlpiY3fQ.es.js +4 -0
  5. package/dist/cdcmap.js +29168 -27482
  6. package/examples/{testing-layer-2.json → __data__/testing-layer-2.json} +1 -1
  7. package/examples/{testing-layer.json → __data__/testing-layer.json} +1 -1
  8. package/examples/county-hsa-toggle.json +51993 -0
  9. package/examples/custom-map-layers.json +2 -2
  10. package/examples/default-county.json +6 -3
  11. package/examples/minimal-example.json +73 -0
  12. package/examples/private/annotation-bug.json +2 -2
  13. package/examples/private/css-issue.json +314 -0
  14. package/examples/private/region-breaking.json +1639 -0
  15. package/examples/private/test1.json +27247 -0
  16. package/package.json +4 -4
  17. package/src/CdcMapComponent.tsx +107 -14
  18. package/src/_stories/CdcMap.AltText.stories.tsx +122 -0
  19. package/src/_stories/CdcMap.Editor.ColumnsSectionTests.stories.tsx +600 -0
  20. package/src/_stories/CdcMap.Editor.DataTableSectionTests.stories.tsx +404 -0
  21. package/src/_stories/CdcMap.Editor.FiltersSectionTests.stories.tsx +229 -0
  22. package/src/_stories/CdcMap.Editor.GeneralSectionTests.stories.tsx +262 -0
  23. package/src/_stories/CdcMap.Editor.LegendSectionTests.stories.tsx +541 -0
  24. package/src/_stories/CdcMap.Editor.MultiCountryWorldMapTests.stories.tsx +359 -0
  25. package/src/_stories/CdcMap.Editor.PatternSettingsSectionTests.stories.tsx +516 -0
  26. package/src/_stories/CdcMap.Editor.SmallMultiplesSectionTests.stories.tsx +165 -0
  27. package/src/_stories/CdcMap.Editor.TextAnnotationsSectionTests.stories.tsx +145 -0
  28. package/src/_stories/CdcMap.Editor.TypeSectionTests.stories.tsx +312 -0
  29. package/src/_stories/CdcMap.Editor.VisualSectionTests.stories.tsx +359 -0
  30. package/src/_stories/CdcMap.Editor.ZoomControlsTests.stories.tsx +88 -0
  31. package/src/_stories/CdcMap.FocusVisibility.stories.tsx +87 -0
  32. package/src/_stories/CdcMap.HiddenMount.stories.tsx +69 -0
  33. package/src/_stories/CdcMap.ResetBehavior.stories.tsx +32 -0
  34. package/src/_stories/CdcMap.Zoom.stories.tsx +111 -0
  35. package/src/_stories/{CdcMap.stories.tsx → CdcMap.smoke.stories.tsx} +60 -0
  36. package/src/_stories/_mock/alt_text_metadata.json +65 -0
  37. package/src/_stories/_mock/legends/legend-tests.json +3 -3
  38. package/src/_stories/_mock/world-bubble-reset.json +138 -0
  39. package/src/_stories/_mock/world-data-zoom-filters.json +166 -0
  40. package/src/components/Annotation/AnnotationList.tsx +1 -1
  41. package/src/components/BubbleList.tsx +13 -0
  42. package/src/components/EditorPanel/components/EditorPanel.tsx +637 -382
  43. package/src/components/EditorPanel/components/HexShapeSettings.tsx +1 -1
  44. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +112 -117
  45. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +26 -13
  46. package/src/components/EditorPanel/components/editorPanel.styles.css +22 -2
  47. package/src/components/FilterControls.tsx +21 -0
  48. package/src/components/Legend/components/Legend.tsx +3 -3
  49. package/src/components/Legend/components/LegendItem.Hex.tsx +4 -2
  50. package/src/components/SmallMultiples/SmallMultiples.tsx +2 -2
  51. package/src/components/SmallMultiples/SynchronizedTooltip.tsx +1 -1
  52. package/src/components/UsaMap/components/UsaMap.County.tsx +309 -108
  53. package/src/components/UsaMap/components/UsaMap.Region.tsx +5 -2
  54. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +33 -10
  55. package/src/components/UsaMap/components/UsaMap.State.tsx +10 -3
  56. package/src/components/UsaMap/data/cb_2019_us_county_20m.json +75817 -1
  57. package/src/components/UsaMap/data/hsa_fips_mapping.json +3144 -0
  58. package/src/components/WorldMap/WorldMap.tsx +37 -4
  59. package/src/components/WorldMap/data/world-topo.json +1 -1
  60. package/src/components/ZoomableGroup.tsx +23 -3
  61. package/src/components/filterControls.styles.css +6 -0
  62. package/src/data/initial-state.js +3 -0
  63. package/src/data/supported-counties.json +1 -1
  64. package/src/helpers/countyTerritories.ts +38 -0
  65. package/src/helpers/dataTableHelpers.ts +35 -6
  66. package/src/helpers/generateRuntimeFilters.ts +2 -1
  67. package/src/helpers/handleMapAriaLabels.ts +45 -30
  68. package/src/helpers/shouldAutoResetSingleStateZoom.ts +22 -0
  69. package/src/helpers/tests/countyTerritories.test.ts +87 -0
  70. package/src/helpers/tests/handleMapAriaLabels.test.ts +71 -0
  71. package/src/helpers/tests/shouldAutoResetSingleStateZoom.test.ts +71 -0
  72. package/src/hooks/useApplyTooltipsToGeo.tsx +7 -4
  73. package/src/hooks/useGeoClickHandler.ts +13 -1
  74. package/src/hooks/useMapLayers.tsx +1 -1
  75. package/src/hooks/useStateZoom.tsx +39 -20
  76. package/src/hooks/useTooltip.test.tsx +2 -16
  77. package/src/hooks/useTooltip.ts +18 -7
  78. package/src/index.jsx +5 -2
  79. package/src/scss/main.scss +6 -21
  80. package/src/scss/map.scss +20 -0
  81. package/src/store/map.actions.ts +5 -2
  82. package/src/store/map.reducer.ts +12 -3
  83. package/src/test/CdcMap.test.jsx +24 -0
  84. package/src/types/MapConfig.ts +11 -0
  85. package/src/types/MapContext.ts +6 -1
  86. package/topojson-updater/README.txt +1 -1
  87. package/dist/cdcmap-vr9HZwRt.es.js +0 -6
  88. package/examples/__data__/city-state-data.json +0 -668
  89. package/examples/city-state.json +0 -434
  90. package/examples/default-world-data.json +0 -1450
  91. package/examples/new-cities.json +0 -656
  92. package/src/_stories/CdcMap.Editor.stories.tsx +0 -3648
  93. package/topojson-updater/package-lock.json +0 -223
  94. /package/src/_stories/{CdcMap.ColumnWrap.stories.tsx → CdcMap.ColumnWrap.smoke.stories.tsx} +0 -0
  95. /package/src/_stories/{CdcMap.Defaults.stories.tsx → CdcMap.Defaults.smoke.stories.tsx} +0 -0
  96. /package/src/_stories/{CdcMap.DistrictOfColumbia.stories.tsx → CdcMap.DistrictOfColumbia.smoke.stories.tsx} +0 -0
  97. /package/src/_stories/{CdcMap.Filters.stories.tsx → CdcMap.Filters.smoke.stories.tsx} +0 -0
  98. /package/src/_stories/{CdcMap.Legend.Gradient.stories.tsx → CdcMap.Legend.Gradient.smoke.stories.tsx} +0 -0
  99. /package/src/_stories/{CdcMap.Legend.stories.tsx → CdcMap.Legend.smoke.stories.tsx} +0 -0
  100. /package/src/_stories/{CdcMap.Patterns.stories.tsx → CdcMap.Patterns.smoke.stories.tsx} +0 -0
  101. /package/src/_stories/{CdcMap.SmallMultiples.stories.tsx → CdcMap.SmallMultiples.smoke.stories.tsx} +0 -0
  102. /package/src/_stories/{CdcMap.Table.stories.tsx → CdcMap.Table.smoke.stories.tsx} +0 -0
  103. /package/src/_stories/{CdcMap.ZeroColor.stories.tsx → CdcMap.ZeroColor.smoke.stories.tsx} +0 -0
  104. /package/src/_stories/{GoogleMap.stories.tsx → GoogleMap.smoke.stories.tsx} +0 -0
  105. /package/src/_stories/{UsaMap.NoData.stories.tsx → UsaMap.NoData.smoke.stories.tsx} +0 -0
@@ -0,0 +1,111 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { within, userEvent, expect } from 'storybook/test'
3
+ import CdcMap from '../CdcMap'
4
+ import SingleStateWithFilters from './_mock/DEV-8942.json'
5
+ import MultiCountry from './_mock/multi-country.json'
6
+ import CountyPatterns from './_mock/county-patterns.json'
7
+ import { assertVisualizationRendered, performAndAssert, waitForPresence } from '@cdc/core/helpers/testing'
8
+
9
+ type Story = StoryObj<typeof CdcMap>
10
+
11
+ const meta: Meta<typeof CdcMap> = {
12
+ title: 'Components/Templates/Map/Zoom',
13
+ component: CdcMap,
14
+ parameters: {
15
+ layout: 'fullscreen'
16
+ }
17
+ }
18
+
19
+ export default meta
20
+
21
+ const readZoomState = (canvasElement: HTMLElement) => {
22
+ const zoomTarget = canvasElement.querySelector('[data-zoom-transform]') as HTMLElement | null
23
+
24
+ return {
25
+ transform: zoomTarget?.getAttribute('data-zoom-transform') || '',
26
+ scale: Number(zoomTarget?.getAttribute('data-zoom-scale') || '0')
27
+ }
28
+ }
29
+
30
+ const verifyBasicZoomCycle = async (canvasElement: HTMLElement) => {
31
+ const canvas = within(canvasElement)
32
+
33
+ await assertVisualizationRendered(canvasElement)
34
+ await waitForPresence('button[aria-label="Zoom In"]', canvasElement)
35
+
36
+ const zoomInButton = canvas.getByLabelText('Zoom In')
37
+
38
+ await performAndAssert(
39
+ 'Map zooms in',
40
+ () => readZoomState(canvasElement),
41
+ async () => {
42
+ await userEvent.click(zoomInButton)
43
+ },
44
+ (before, after) => before.transform !== after.transform && after.scale > before.scale
45
+ )
46
+
47
+ const resetButton = canvas.queryByRole('button', { name: 'Reset Zoom' })
48
+
49
+ if (resetButton) {
50
+ await performAndAssert(
51
+ 'Map reset returns zoom to default',
52
+ () => readZoomState(canvasElement),
53
+ async () => {
54
+ await userEvent.click(resetButton)
55
+ },
56
+ (before, after) => before.transform !== after.transform && after.scale === 1
57
+ )
58
+ } else {
59
+ expect(readZoomState(canvasElement).scale).toBeGreaterThan(1)
60
+ }
61
+ }
62
+
63
+ export const SingleState: Story = {
64
+ args: {
65
+ config: SingleStateWithFilters
66
+ },
67
+ parameters: {
68
+ docs: {
69
+ description: {
70
+ story: 'Single-state zoom baseline. Use this to confirm local zoom and reset behavior outside dashboards.'
71
+ }
72
+ }
73
+ },
74
+ play: async ({ canvasElement }) => {
75
+ await verifyBasicZoomCycle(canvasElement)
76
+ }
77
+ }
78
+
79
+ export const County: Story = {
80
+ args: {
81
+ config: CountyPatterns
82
+ },
83
+ parameters: {
84
+ docs: {
85
+ description: {
86
+ story:
87
+ 'County-map zoom baseline. Useful for checking that pan/zoom controls still behave correctly on county geographies.'
88
+ }
89
+ }
90
+ },
91
+ play: async ({ canvasElement }) => {
92
+ await verifyBasicZoomCycle(canvasElement)
93
+ }
94
+ }
95
+
96
+ export const World: Story = {
97
+ args: {
98
+ config: MultiCountry
99
+ },
100
+ parameters: {
101
+ docs: {
102
+ description: {
103
+ story:
104
+ 'World-map zoom baseline. Useful for checking that world-map zoom and reset controls still behave after single-state zoom changes.'
105
+ }
106
+ }
107
+ },
108
+ play: async ({ canvasElement }) => {
109
+ await verifyBasicZoomCycle(canvasElement)
110
+ }
111
+ }
@@ -1,6 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite'
2
2
  import { within, expect } from 'storybook/test'
3
3
  import CdcMap from '../CdcMap'
4
+ import MinimalExampleConfig from '../../examples/minimal-example.json'
4
5
  import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
5
6
  import EqualNumberOptInExample from './_mock/DEV-7286.json'
6
7
  import EqualNumberMap from './_mock/equal-number.json'
@@ -11,8 +12,10 @@ import MultiCountryHide from './_mock/multi-country-hide.json'
11
12
  import SingleStateWithFilters from './_mock/DEV-8942.json'
12
13
  import exampleCityState from './_mock/example-city-state.json'
13
14
  import USBubbleCities from './_mock/us-bubble-cities.json'
15
+ import worldBubbleReset from './_mock/world-bubble-reset.json'
14
16
  import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
15
17
  import exampleLegendBins from './_mock/legend-bins.json'
18
+ import { performAndAssert, waitForPresence } from '@cdc/core/helpers/testing'
16
19
 
17
20
  // Fallback step function for test descriptions
18
21
  const step = async (description: string, fn: () => Promise<void> | void) => {
@@ -67,6 +70,17 @@ export const Equal_Number_Opt_In: Story = {
67
70
  }
68
71
  }
69
72
 
73
+ export const Minimal_Config: Story = {
74
+ args: {
75
+ config: MinimalExampleConfig
76
+ },
77
+ play: async ({ canvasElement }) => {
78
+ await assertVisualizationRendered(canvasElement)
79
+ expect(canvasElement.querySelector('.map-container')).toBeInTheDocument()
80
+ expect(canvasElement.textContent).toContain('Minimal US Map')
81
+ }
82
+ }
83
+
70
84
  export const Equal_Number_Map: Story = {
71
85
  args: {
72
86
  isEditor: true,
@@ -186,6 +200,52 @@ export const Bubble_Map: Story = {
186
200
  }
187
201
  }
188
202
 
203
+ export const World_Bubble_Reset_Restores_All_Bubbles: Story = {
204
+ args: {
205
+ config: worldBubbleReset,
206
+ isEditor: true
207
+ },
208
+ play: async ({ canvasElement }) => {
209
+ await assertVisualizationRendered(canvasElement)
210
+ await waitForPresence('circle.bubble.country--France', canvasElement)
211
+
212
+ const getBubbleState = () => ({
213
+ bubbleCount: canvasElement.querySelectorAll('circle.bubble[data-tooltip-id]').length
214
+ })
215
+
216
+ const dispatchBubblePointerClick = (bubble: Element) => {
217
+ const rect = bubble.getBoundingClientRect()
218
+ const clientX = rect.left + rect.width / 2
219
+ const clientY = rect.top + rect.height / 2
220
+
221
+ bubble.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, clientX, clientY }))
222
+ bubble.dispatchEvent(new PointerEvent('pointerup', { bubbles: true, clientX, clientY }))
223
+ }
224
+
225
+ await performAndAssert(
226
+ 'World bubble click narrows the rendered bubble set',
227
+ getBubbleState,
228
+ async () => {
229
+ const franceBubble = canvasElement.querySelector('circle.bubble.country--France')
230
+ expect(franceBubble).toBeTruthy()
231
+ dispatchBubblePointerClick(franceBubble as Element)
232
+ },
233
+ (before, after) => after.bubbleCount > 0 && after.bubbleCount < before.bubbleCount
234
+ )
235
+
236
+ await performAndAssert(
237
+ 'Reset Zoom restores all world bubbles',
238
+ getBubbleState,
239
+ async () => {
240
+ const resetButton = canvasElement.querySelector('button[aria-label="Reset Zoom"]') as HTMLButtonElement | null
241
+ expect(resetButton).toBeTruthy()
242
+ resetButton?.click()
243
+ },
244
+ (_before, after) => after.bubbleCount === worldBubbleReset.data.length
245
+ )
246
+ }
247
+ }
248
+
189
249
  export const HHS_Region_Map: Story = {
190
250
  args: {
191
251
  configUrl: 'https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/examples/example-hhs-regions-data.json'
@@ -0,0 +1,65 @@
1
+ {
2
+ "version": "4.26.4",
3
+ "color": "pinkpurple",
4
+ "general": {
5
+ "title": "COVID-19 Case Rates by State",
6
+ "geoType": "us",
7
+ "type": "data",
8
+ "showTitle": true
9
+ },
10
+ "type": "map",
11
+ "dataMetadata": {
12
+ "altDescription": "Choropleth map of the United States showing COVID-19 case rates per 100,000 population. Rates are highest in the Southeast, with Alabama, Mississippi, and Louisiana exceeding 50 per 100,000.",
13
+ "lastUpdated": "2024-09-21",
14
+ "source": "CDC COVID Data Tracker"
15
+ },
16
+ "columns": {
17
+ "geo": {
18
+ "name": "FIPS Codes",
19
+ "label": "Location",
20
+ "tooltip": false,
21
+ "dataTable": true
22
+ },
23
+ "primary": {
24
+ "name": "Rate",
25
+ "label": "Rate per 100k",
26
+ "prefix": "",
27
+ "suffix": "",
28
+ "tooltip": true,
29
+ "dataTable": true
30
+ },
31
+ "navigate": { "name": "" },
32
+ "latitude": { "name": "" },
33
+ "longitude": { "name": "" }
34
+ },
35
+ "legend": {
36
+ "type": "equalnumber",
37
+ "numberOfItems": 3,
38
+ "position": "side",
39
+ "style": "circles",
40
+ "title": "Rate per 100k",
41
+ "description": "",
42
+ "descriptions": {},
43
+ "specialClasses": [],
44
+ "unified": false,
45
+ "singleColumn": false,
46
+ "singleRow": false,
47
+ "verticalSorted": false,
48
+ "showSpecialClassesLast": false,
49
+ "dynamicDescription": false,
50
+ "hideBorder": false
51
+ },
52
+ "filters": [],
53
+ "filterBehavior": "Filter Change",
54
+ "data": [
55
+ { "FIPS Codes": "01", "Rate": 55 },
56
+ { "FIPS Codes": "04", "Rate": 22 },
57
+ { "FIPS Codes": "06", "Rate": 31 },
58
+ { "FIPS Codes": "12", "Rate": 44 },
59
+ { "FIPS Codes": "13", "Rate": 48 },
60
+ { "FIPS Codes": "22", "Rate": 52 },
61
+ { "FIPS Codes": "28", "Rate": 58 },
62
+ { "FIPS Codes": "36", "Rate": 27 },
63
+ { "FIPS Codes": "48", "Rate": 38 }
64
+ ]
65
+ }
@@ -100,7 +100,7 @@
100
100
  "layers": [
101
101
  {
102
102
  "name": "Layer One",
103
- "url": "./examples/testing-layer.json",
103
+ "url": "./examples/__data__/testing-layer.json",
104
104
  "namespace": "cove",
105
105
  "fill": "blue",
106
106
  "stroke": "orange",
@@ -108,7 +108,7 @@
108
108
  },
109
109
  {
110
110
  "name": "Layer Two",
111
- "url": "./examples/testing-layer-2.json",
111
+ "url": "./examples/__data__/testing-layer-2.json",
112
112
  "namespace": "cove",
113
113
  "fill": "blue",
114
114
  "stroke": "orange",
@@ -769,4 +769,4 @@
769
769
  "URL": "https://www.cdc.gov/"
770
770
  }
771
771
  ]
772
- }
772
+ }
@@ -0,0 +1,138 @@
1
+ {
2
+ "annotations": [],
3
+ "general": {
4
+ "title": "World Bubble Reset Demo",
5
+ "subtext": "Click a bubble to zoom, then use Reset Zoom to restore all bubbles.",
6
+ "type": "bubble",
7
+ "geoType": "world",
8
+ "headerColor": "theme-blue",
9
+ "showSidebar": true,
10
+ "showTitle": true,
11
+ "showDownloadButton": true,
12
+ "expandDataTable": false,
13
+ "backgroundColor": "#ffffff",
14
+ "geoBorderColor": "darkGray",
15
+ "territoriesLabel": "Territories",
16
+ "language": "en",
17
+ "hasRegions": false,
18
+ "showDownloadMediaButton": false,
19
+ "fullBorder": false,
20
+ "palette": {
21
+ "isReversed": false
22
+ },
23
+ "allowMapZoom": true,
24
+ "hideGeoColumnInTooltip": false,
25
+ "hidePrimaryColumnInTooltip": false,
26
+ "geoLabelOverride": "",
27
+ "noDataFoundMessage": "No data found"
28
+ },
29
+ "type": "map",
30
+ "color": "bluegreen",
31
+ "columns": {
32
+ "geo": {
33
+ "name": "country",
34
+ "label": "Country",
35
+ "tooltip": true,
36
+ "dataTable": true
37
+ },
38
+ "primary": {
39
+ "dataTable": true,
40
+ "tooltip": true,
41
+ "prefix": "",
42
+ "suffix": "",
43
+ "name": "cases",
44
+ "label": "Cases"
45
+ },
46
+ "navigate": {
47
+ "name": ""
48
+ }
49
+ },
50
+ "legend": {
51
+ "descriptions": {},
52
+ "specialClasses": [],
53
+ "unified": false,
54
+ "singleColumn": true,
55
+ "dynamicDescription": false,
56
+ "type": "equalinterval",
57
+ "numberOfItems": 5,
58
+ "position": "side",
59
+ "title": "Cases",
60
+ "showTitle": true,
61
+ "reversedOrder": false,
62
+ "singleColumnLegend": false,
63
+ "hideBorder": false
64
+ },
65
+ "filters": [],
66
+ "table": {
67
+ "label": "Data Table",
68
+ "expanded": false,
69
+ "limitHeight": false,
70
+ "height": "",
71
+ "caption": "",
72
+ "showDownloadUrl": false,
73
+ "showDataTableLink": true,
74
+ "showFullGeoNameInCSV": false,
75
+ "forceDisplay": true,
76
+ "download": true,
77
+ "indexLabel": "",
78
+ "wrapColumns": false,
79
+ "showDownloadLinkBelow": true
80
+ },
81
+ "tooltips": {
82
+ "appearanceType": "hover",
83
+ "linkLabel": "Learn More",
84
+ "capitalizeLabels": true,
85
+ "opacity": 90
86
+ },
87
+ "runtime": {
88
+ "editorErrorMessage": []
89
+ },
90
+ "visual": {
91
+ "minBubbleSize": 10,
92
+ "maxBubbleSize": 28,
93
+ "extraBubbleBorder": false,
94
+ "cityStyle": "circle",
95
+ "geoCodeCircleSize": 12,
96
+ "showBubbleZeros": true,
97
+ "cityStyleLabel": "Bubble",
98
+ "additionalCityStyles": []
99
+ },
100
+ "mapPosition": {
101
+ "coordinates": [0, 30],
102
+ "zoom": 1
103
+ },
104
+ "map": {
105
+ "layers": [],
106
+ "patterns": []
107
+ },
108
+ "hexMap": {
109
+ "type": "",
110
+ "shapeGroups": []
111
+ },
112
+ "data": [
113
+ {
114
+ "country": "France",
115
+ "cases": 120
116
+ },
117
+ {
118
+ "country": "Brazil",
119
+ "cases": 340
120
+ },
121
+ {
122
+ "country": "Japan",
123
+ "cases": 280
124
+ },
125
+ {
126
+ "country": "Australia",
127
+ "cases": 200
128
+ },
129
+ {
130
+ "country": "South Africa",
131
+ "cases": 160
132
+ },
133
+ {
134
+ "country": "Canada",
135
+ "cases": 240
136
+ }
137
+ ]
138
+ }
@@ -0,0 +1,166 @@
1
+ {
2
+ "annotations": [],
3
+ "general": {
4
+ "title": "World Data Map Zoom With Filters",
5
+ "subtext": "Use the region filter, zoom into countries, and test reset behavior on a world data map.",
6
+ "type": "data",
7
+ "geoType": "world",
8
+ "headerColor": "theme-blue",
9
+ "showSidebar": true,
10
+ "showTitle": true,
11
+ "showDownloadButton": true,
12
+ "expandDataTable": false,
13
+ "backgroundColor": "#ffffff",
14
+ "geoBorderColor": "darkGray",
15
+ "territoriesLabel": "Territories",
16
+ "language": "en",
17
+ "hasRegions": false,
18
+ "showDownloadMediaButton": false,
19
+ "fullBorder": false,
20
+ "palette": {
21
+ "isReversed": false
22
+ },
23
+ "allowMapZoom": true,
24
+ "hideGeoColumnInTooltip": false,
25
+ "hidePrimaryColumnInTooltip": false,
26
+ "geoLabelOverride": "",
27
+ "noDataFoundMessage": "No data found"
28
+ },
29
+ "type": "map",
30
+ "color": "bluegreen",
31
+ "columns": {
32
+ "geo": {
33
+ "name": "Country",
34
+ "label": "Country",
35
+ "tooltip": true,
36
+ "dataTable": true
37
+ },
38
+ "primary": {
39
+ "name": "Value",
40
+ "label": "Value",
41
+ "prefix": "",
42
+ "suffix": "",
43
+ "tooltip": true,
44
+ "dataTable": true
45
+ },
46
+ "navigate": {
47
+ "name": ""
48
+ },
49
+ "additionalColumn1": {
50
+ "name": "Region",
51
+ "label": "Region",
52
+ "tooltip": true,
53
+ "dataTable": true,
54
+ "prefix": "",
55
+ "suffix": ""
56
+ }
57
+ },
58
+ "legend": {
59
+ "descriptions": {},
60
+ "specialClasses": [],
61
+ "unified": false,
62
+ "singleColumn": true,
63
+ "dynamicDescription": false,
64
+ "type": "equalinterval",
65
+ "numberOfItems": 5,
66
+ "position": "side",
67
+ "title": "Value",
68
+ "showTitle": true,
69
+ "reversedOrder": false,
70
+ "singleColumnLegend": false,
71
+ "hideBorder": false
72
+ },
73
+ "filters": [
74
+ {
75
+ "order": "asc",
76
+ "label": "Region",
77
+ "columnName": "Region",
78
+ "values": ["Europe", "Americas", "Asia-Pacific"],
79
+ "active": "Europe",
80
+ "filterStyle": "dropdown"
81
+ }
82
+ ],
83
+ "table": {
84
+ "label": "Data Table",
85
+ "expanded": false,
86
+ "limitHeight": false,
87
+ "height": "",
88
+ "caption": "",
89
+ "showDownloadUrl": false,
90
+ "showDataTableLink": true,
91
+ "showFullGeoNameInCSV": false,
92
+ "forceDisplay": true,
93
+ "download": true,
94
+ "indexLabel": "",
95
+ "wrapColumns": false,
96
+ "showDownloadLinkBelow": true
97
+ },
98
+ "tooltips": {
99
+ "appearanceType": "hover",
100
+ "linkLabel": "Learn More",
101
+ "capitalizeLabels": true,
102
+ "opacity": 90
103
+ },
104
+ "runtime": {
105
+ "editorErrorMessage": []
106
+ },
107
+ "visual": {
108
+ "minBubbleSize": 10,
109
+ "maxBubbleSize": 28,
110
+ "extraBubbleBorder": false,
111
+ "cityStyle": "circle",
112
+ "geoCodeCircleSize": 12,
113
+ "showBubbleZeros": true,
114
+ "cityStyleLabel": "Bubble",
115
+ "additionalCityStyles": []
116
+ },
117
+ "mapPosition": {
118
+ "coordinates": [0, 30],
119
+ "zoom": 1
120
+ },
121
+ "map": {
122
+ "layers": [],
123
+ "patterns": []
124
+ },
125
+ "hexMap": {
126
+ "type": "",
127
+ "shapeGroups": []
128
+ },
129
+ "data": [
130
+ {
131
+ "Country": "France",
132
+ "Value": 120,
133
+ "Region": "Europe"
134
+ },
135
+ {
136
+ "Country": "Germany",
137
+ "Value": 150,
138
+ "Region": "Europe"
139
+ },
140
+ {
141
+ "Country": "Italy",
142
+ "Value": 105,
143
+ "Region": "Europe"
144
+ },
145
+ {
146
+ "Country": "Brazil",
147
+ "Value": 210,
148
+ "Region": "Americas"
149
+ },
150
+ {
151
+ "Country": "Canada",
152
+ "Value": 175,
153
+ "Region": "Americas"
154
+ },
155
+ {
156
+ "Country": "Japan",
157
+ "Value": 190,
158
+ "Region": "Asia-Pacific"
159
+ },
160
+ {
161
+ "Country": "Australia",
162
+ "Value": 165,
163
+ "Region": "Asia-Pacific"
164
+ }
165
+ ]
166
+ }
@@ -8,7 +8,7 @@ type AnnotationListProps = {
8
8
  }
9
9
 
10
10
  const AnnotationList: React.FC<AnnotationListProps> = ({ useBootstrapVisibilityClasses = true }) => {
11
- const { state: config } = useContext(ConfigContext)
11
+ const { config } = useContext(ConfigContext)
12
12
  const annotations = config.annotations || []
13
13
 
14
14
  const ulClasses = () => {
@@ -64,11 +64,16 @@ const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
64
64
 
65
65
  // Zoom the map in...
66
66
  dispatch({ type: 'SET_POSITION', payload: { coordinates: reversedCoordinates, zoom: 3 } })
67
+ dispatch({ type: 'SET_FILTERED_COUNTRY_CODE', payload: _filteredCountryCode })
67
68
 
68
69
  // ...and show the data for the clicked country
69
70
  dispatch({ type: 'SET_RUNTIME_DATA', payload: _tempRuntimeData })
70
71
  }
71
72
 
73
+ const handleBubblePointerDown = (e: React.PointerEvent<SVGCircleElement> | React.MouseEvent<SVGCircleElement>) => {
74
+ e.preventDefault()
75
+ }
76
+
72
77
  const sortedRuntimeData: DataRow = Object.values(runtimeData).sort((a, b) =>
73
78
  a[primaryColumnName] < b[primaryColumnName] ? 1 : -1
74
79
  )
@@ -112,7 +117,9 @@ const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
112
117
  strokeWidth={1.25}
113
118
  fillOpacity={0.4}
114
119
  onMouseEnter={() => {}}
120
+ onMouseDown={handleBubblePointerDown}
115
121
  onPointerDown={e => {
122
+ handleBubblePointerDown(e)
116
123
  pointerX = e.clientX
117
124
  pointerY = e.clientY
118
125
  }}
@@ -148,7 +155,9 @@ const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
148
155
  stroke={'white'}
149
156
  strokeWidth={0.5}
150
157
  onMouseEnter={() => {}}
158
+ onMouseDown={handleBubblePointerDown}
151
159
  onPointerDown={e => {
160
+ handleBubblePointerDown(e)
152
161
  pointerX = e.clientX
153
162
  pointerY = e.clientY
154
163
  }}
@@ -226,7 +235,9 @@ const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
226
235
  strokeWidth={1.25}
227
236
  fillOpacity={0.4}
228
237
  onMouseEnter={() => {}}
238
+ onMouseDown={handleBubblePointerDown}
229
239
  onPointerDown={e => {
240
+ handleBubblePointerDown(e)
230
241
  pointerX = e.clientX
231
242
  pointerY = e.clientY
232
243
  }}
@@ -262,7 +273,9 @@ const BubbleList: React.FC<BubbleListProps> = ({ customProjection }) => {
262
273
  strokeWidth={0.5}
263
274
  fillOpacity={0.4}
264
275
  onMouseEnter={() => {}}
276
+ onMouseDown={handleBubblePointerDown}
265
277
  onPointerDown={e => {
278
+ handleBubblePointerDown(e)
266
279
  pointerX = e.clientX
267
280
  pointerY = e.clientY
268
281
  }}