@buildcanada/charts 0.1.0

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 (404) hide show
  1. package/LICENSE.md +8 -0
  2. package/README.md +113 -0
  3. package/package.json +137 -0
  4. package/src/components/BodyPortal/BodyPortal.tsx +40 -0
  5. package/src/components/Button/Button.scss +110 -0
  6. package/src/components/Button/Button.tsx +101 -0
  7. package/src/components/Checkbox.scss +93 -0
  8. package/src/components/Checkbox.tsx +47 -0
  9. package/src/components/ExpandableToggle/ExpandableToggle.scss +123 -0
  10. package/src/components/ExpandableToggle/ExpandableToggle.tsx +60 -0
  11. package/src/components/GrapherTabIcon.tsx +156 -0
  12. package/src/components/GrapherTrendArrow.scss +16 -0
  13. package/src/components/GrapherTrendArrow.tsx +30 -0
  14. package/src/components/Halo/Halo.tsx +44 -0
  15. package/src/components/LabeledSwitch/LabeledSwitch.scss +109 -0
  16. package/src/components/LabeledSwitch/LabeledSwitch.tsx +62 -0
  17. package/src/components/MarkdownTextWrap/MarkdownTextWrap.tsx +1173 -0
  18. package/src/components/OverlayHeader.scss +18 -0
  19. package/src/components/OverlayHeader.tsx +29 -0
  20. package/src/components/RadioButton.scss +69 -0
  21. package/src/components/RadioButton.tsx +42 -0
  22. package/src/components/SimpleMarkdownText.tsx +89 -0
  23. package/src/components/TextInput.scss +17 -0
  24. package/src/components/TextInput.tsx +19 -0
  25. package/src/components/TextWrap/TextWrap.tsx +361 -0
  26. package/src/components/TextWrap/TextWrapUtils.ts +32 -0
  27. package/src/components/closeButton/CloseButton.scss +40 -0
  28. package/src/components/closeButton/CloseButton.tsx +27 -0
  29. package/src/components/index.ts +70 -0
  30. package/src/components/loadingIndicator/LoadingIndicator.scss +40 -0
  31. package/src/components/loadingIndicator/LoadingIndicator.tsx +28 -0
  32. package/src/components/markdown/remarkPlainLinks.ts +36 -0
  33. package/src/components/reactUtil.ts +20 -0
  34. package/src/components/stubs/CodeSnippet.tsx +19 -0
  35. package/src/components/stubs/DataCitation.tsx +16 -0
  36. package/src/components/stubs/IndicatorKeyData.tsx +45 -0
  37. package/src/components/stubs/IndicatorProcessing.tsx +15 -0
  38. package/src/components/stubs/IndicatorSources.tsx +15 -0
  39. package/src/components/styles/colors.scss +113 -0
  40. package/src/components/styles/mixins.scss +630 -0
  41. package/src/components/styles/typography.scss +579 -0
  42. package/src/components/styles/util.scss +89 -0
  43. package/src/components/styles/variables.scss +208 -0
  44. package/src/config/ChartsConfig.ts +163 -0
  45. package/src/config/ChartsProvider.tsx +157 -0
  46. package/src/config/index.ts +20 -0
  47. package/src/core-table/CoreTable.ts +1355 -0
  48. package/src/core-table/CoreTableColumns.ts +973 -0
  49. package/src/core-table/CoreTableUtils.ts +793 -0
  50. package/src/core-table/ErrorValues.ts +73 -0
  51. package/src/core-table/OwidTable.ts +1175 -0
  52. package/src/core-table/OwidTableSynthesizers.ts +272 -0
  53. package/src/core-table/OwidTableUtil.ts +76 -0
  54. package/src/core-table/Transforms.ts +484 -0
  55. package/src/core-table/index.ts +82 -0
  56. package/src/explorer/ColumnGrammar.ts +217 -0
  57. package/src/explorer/Explorer.sample.ts +212 -0
  58. package/src/explorer/Explorer.scss +148 -0
  59. package/src/explorer/Explorer.tsx +1283 -0
  60. package/src/explorer/ExplorerConstants.ts +85 -0
  61. package/src/explorer/ExplorerControls.scss +156 -0
  62. package/src/explorer/ExplorerControls.tsx +210 -0
  63. package/src/explorer/ExplorerDecisionMatrix.ts +471 -0
  64. package/src/explorer/ExplorerGrammar.ts +161 -0
  65. package/src/explorer/ExplorerProgram.ts +568 -0
  66. package/src/explorer/ExplorerUtils.ts +59 -0
  67. package/src/explorer/GrapherGrammar.ts +387 -0
  68. package/src/explorer/gridLang/GrammarUtils.ts +121 -0
  69. package/src/explorer/gridLang/GridCell.ts +298 -0
  70. package/src/explorer/gridLang/GridLangConstants.ts +255 -0
  71. package/src/explorer/gridLang/GridProgram.ts +311 -0
  72. package/src/explorer/gridLang/readme.md +17 -0
  73. package/src/explorer/index.ts +69 -0
  74. package/src/explorer/readme.md +19 -0
  75. package/src/explorer/urlMigrations/CO2UrlMigration.ts +46 -0
  76. package/src/explorer/urlMigrations/CovidUrlMigration.ts +37 -0
  77. package/src/explorer/urlMigrations/EnergyUrlMigration.ts +41 -0
  78. package/src/explorer/urlMigrations/ExplorerPageUrlMigrationSpec.ts +12 -0
  79. package/src/explorer/urlMigrations/ExplorerUrlMigrationUtils.ts +45 -0
  80. package/src/explorer/urlMigrations/ExplorerUrlMigrations.ts +33 -0
  81. package/src/explorer/urlMigrations/LegacyCovidUrlMigration.ts +144 -0
  82. package/src/explorer/urlMigrations/readme.md +39 -0
  83. package/src/grapher/axis/Axis.ts +973 -0
  84. package/src/grapher/axis/AxisConfig.ts +179 -0
  85. package/src/grapher/axis/AxisViews.tsx +597 -0
  86. package/src/grapher/barCharts/DiscreteBarChart.tsx +728 -0
  87. package/src/grapher/barCharts/DiscreteBarChartConstants.ts +60 -0
  88. package/src/grapher/barCharts/DiscreteBarChartHelpers.ts +338 -0
  89. package/src/grapher/barCharts/DiscreteBarChartState.ts +354 -0
  90. package/src/grapher/barCharts/DiscreteBarChartThumbnail.tsx +34 -0
  91. package/src/grapher/captionedChart/CaptionedChart.scss +61 -0
  92. package/src/grapher/captionedChart/CaptionedChart.tsx +523 -0
  93. package/src/grapher/captionedChart/Logos.tsx +141 -0
  94. package/src/grapher/captionedChart/LogosSVG.tsx +16 -0
  95. package/src/grapher/captionedChart/StaticChartRasterizer.tsx +178 -0
  96. package/src/grapher/captionedChart/assets/buildcanada-logo-square.svg +15 -0
  97. package/src/grapher/captionedChart/assets/buildcanada-logo.svg +15 -0
  98. package/src/grapher/captionedChart/assets/canadaspends.svg +7 -0
  99. package/src/grapher/captionedChart/readme.md +14 -0
  100. package/src/grapher/chart/Chart.tsx +62 -0
  101. package/src/grapher/chart/ChartAreaContent.tsx +172 -0
  102. package/src/grapher/chart/ChartDimension.ts +121 -0
  103. package/src/grapher/chart/ChartInterface.ts +83 -0
  104. package/src/grapher/chart/ChartManager.ts +113 -0
  105. package/src/grapher/chart/ChartTabs.ts +178 -0
  106. package/src/grapher/chart/ChartTypeMap.tsx +158 -0
  107. package/src/grapher/chart/ChartTypeSwitcher.tsx +26 -0
  108. package/src/grapher/chart/ChartUtils.tsx +364 -0
  109. package/src/grapher/chart/DimensionSlot.ts +45 -0
  110. package/src/grapher/chart/StaticChartWrapper.tsx +94 -0
  111. package/src/grapher/chart/guidedChartUtils.ts +82 -0
  112. package/src/grapher/color/BinningStrategies.ts +484 -0
  113. package/src/grapher/color/BinningStrategyEqualSizeBins.ts +132 -0
  114. package/src/grapher/color/BinningStrategyLogarithmic.ts +121 -0
  115. package/src/grapher/color/CategoricalColorAssigner.ts +97 -0
  116. package/src/grapher/color/ColorBrewerSchemes.ts +80 -0
  117. package/src/grapher/color/ColorConstants.ts +20 -0
  118. package/src/grapher/color/ColorScale.ts +339 -0
  119. package/src/grapher/color/ColorScaleBin.ts +147 -0
  120. package/src/grapher/color/ColorScaleConfig.ts +204 -0
  121. package/src/grapher/color/ColorScheme.ts +137 -0
  122. package/src/grapher/color/ColorSchemes.ts +149 -0
  123. package/src/grapher/color/ColorUtils.ts +86 -0
  124. package/src/grapher/color/CustomSchemes.ts +1772 -0
  125. package/src/grapher/color/readme.md +84 -0
  126. package/src/grapher/comparisonLine/ComparisonLine.tsx +31 -0
  127. package/src/grapher/comparisonLine/ComparisonLineConstants.ts +11 -0
  128. package/src/grapher/comparisonLine/ComparisonLineGenerator.ts +60 -0
  129. package/src/grapher/comparisonLine/ComparisonLineHelpers.ts +10 -0
  130. package/src/grapher/comparisonLine/CustomComparisonLine.tsx +159 -0
  131. package/src/grapher/comparisonLine/VerticalComparisonLine.tsx +208 -0
  132. package/src/grapher/controls/ActionButtons.scss +97 -0
  133. package/src/grapher/controls/ActionButtons.tsx +453 -0
  134. package/src/grapher/controls/CommandPalette.scss +50 -0
  135. package/src/grapher/controls/CommandPalette.tsx +74 -0
  136. package/src/grapher/controls/ContentSwitchers.scss +93 -0
  137. package/src/grapher/controls/ContentSwitchers.tsx +238 -0
  138. package/src/grapher/controls/Controls.scss +158 -0
  139. package/src/grapher/controls/DataTableFilterDropdown.scss +7 -0
  140. package/src/grapher/controls/DataTableFilterDropdown.tsx +168 -0
  141. package/src/grapher/controls/DataTableSearchField.scss +3 -0
  142. package/src/grapher/controls/DataTableSearchField.tsx +76 -0
  143. package/src/grapher/controls/Dropdown.scss +252 -0
  144. package/src/grapher/controls/Dropdown.tsx +235 -0
  145. package/src/grapher/controls/EntitySelectionToggle.tsx +135 -0
  146. package/src/grapher/controls/MapRegionDropdown.scss +3 -0
  147. package/src/grapher/controls/MapRegionDropdown.tsx +104 -0
  148. package/src/grapher/controls/MapResetButton.tsx +115 -0
  149. package/src/grapher/controls/MapZoomDropdown.scss +9 -0
  150. package/src/grapher/controls/MapZoomDropdown.tsx +270 -0
  151. package/src/grapher/controls/MapZoomToSelectionButton.tsx +87 -0
  152. package/src/grapher/controls/SearchField.scss +78 -0
  153. package/src/grapher/controls/SearchField.tsx +63 -0
  154. package/src/grapher/controls/SettingsMenu.scss +191 -0
  155. package/src/grapher/controls/SettingsMenu.tsx +399 -0
  156. package/src/grapher/controls/ShareMenu.scss +58 -0
  157. package/src/grapher/controls/ShareMenu.tsx +304 -0
  158. package/src/grapher/controls/SortIcon.tsx +39 -0
  159. package/src/grapher/controls/VerticalScrollContainer.tsx +263 -0
  160. package/src/grapher/controls/controlsRow/ControlsRow.tsx +168 -0
  161. package/src/grapher/controls/dropdown-icons.scss +4 -0
  162. package/src/grapher/controls/entityPicker/EntityPicker.scss +255 -0
  163. package/src/grapher/controls/entityPicker/EntityPicker.tsx +816 -0
  164. package/src/grapher/controls/entityPicker/EntityPickerConstants.ts +23 -0
  165. package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.scss +129 -0
  166. package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.tsx +463 -0
  167. package/src/grapher/controls/globalEntitySelector/GlobalEntitySelectorConstants.ts +3 -0
  168. package/src/grapher/controls/globalEntitySelector/readme.md +17 -0
  169. package/src/grapher/controls/settings/AbsRelToggle.tsx +64 -0
  170. package/src/grapher/controls/settings/AxisScaleToggle.tsx +53 -0
  171. package/src/grapher/controls/settings/FacetStrategySelector.tsx +110 -0
  172. package/src/grapher/controls/settings/FacetYDomainToggle.tsx +51 -0
  173. package/src/grapher/controls/settings/NoDataAreaToggle.tsx +38 -0
  174. package/src/grapher/controls/settings/ZoomToggle.tsx +36 -0
  175. package/src/grapher/core/EntitiesByRegionType.ts +174 -0
  176. package/src/grapher/core/EntityCodes.ts +19 -0
  177. package/src/grapher/core/EntityUrlBuilder.ts +200 -0
  178. package/src/grapher/core/FetchingGrapher.tsx +156 -0
  179. package/src/grapher/core/Grapher.tsx +760 -0
  180. package/src/grapher/core/GrapherAnalytics.ts +229 -0
  181. package/src/grapher/core/GrapherConstants.ts +173 -0
  182. package/src/grapher/core/GrapherState.tsx +3659 -0
  183. package/src/grapher/core/GrapherUrl.ts +184 -0
  184. package/src/grapher/core/GrapherUrlMigrations.ts +29 -0
  185. package/src/grapher/core/GrapherUseHelpers.tsx +147 -0
  186. package/src/grapher/core/LegacyToOwidTable.ts +841 -0
  187. package/src/grapher/core/grapher.entry.ts +5 -0
  188. package/src/grapher/core/grapher.scss +257 -0
  189. package/src/grapher/core/loadGrapherTableHelpers.ts +116 -0
  190. package/src/grapher/core/loadVariable.ts +104 -0
  191. package/src/grapher/core/relatedQuestion.ts +12 -0
  192. package/src/grapher/core/typography.scss +206 -0
  193. package/src/grapher/dataTable/DataTable.sample.ts +206 -0
  194. package/src/grapher/dataTable/DataTable.scss +249 -0
  195. package/src/grapher/dataTable/DataTable.tsx +1332 -0
  196. package/src/grapher/dataTable/DataTableConstants.ts +186 -0
  197. package/src/grapher/entitySelector/EntitySelector.scss +255 -0
  198. package/src/grapher/entitySelector/EntitySelector.tsx +1838 -0
  199. package/src/grapher/facet/FacetChart.tsx +943 -0
  200. package/src/grapher/facet/FacetChartConstants.ts +24 -0
  201. package/src/grapher/facet/FacetChartUtils.ts +51 -0
  202. package/src/grapher/facet/FacetMap.tsx +604 -0
  203. package/src/grapher/facet/FacetMapConstants.ts +23 -0
  204. package/src/grapher/facet/readme.md +13 -0
  205. package/src/grapher/focus/FocusArray.ts +79 -0
  206. package/src/grapher/footer/Footer.scss +63 -0
  207. package/src/grapher/footer/Footer.tsx +809 -0
  208. package/src/grapher/footer/FooterManager.ts +44 -0
  209. package/src/grapher/fullScreen/FullScreen.scss +11 -0
  210. package/src/grapher/fullScreen/FullScreen.tsx +61 -0
  211. package/src/grapher/header/Header.scss +35 -0
  212. package/src/grapher/header/Header.tsx +372 -0
  213. package/src/grapher/header/HeaderManager.ts +28 -0
  214. package/src/grapher/index.ts +157 -0
  215. package/src/grapher/interaction/InteractionState.ts +60 -0
  216. package/src/grapher/legend/HorizontalColorLegends.tsx +923 -0
  217. package/src/grapher/legend/LegendInteractionState.ts +40 -0
  218. package/src/grapher/legend/VerticalColorLegend.tsx +295 -0
  219. package/src/grapher/lineCharts/LineChart.tsx +968 -0
  220. package/src/grapher/lineCharts/LineChartConstants.ts +89 -0
  221. package/src/grapher/lineCharts/LineChartHelpers.ts +184 -0
  222. package/src/grapher/lineCharts/LineChartState.ts +394 -0
  223. package/src/grapher/lineCharts/LineChartThumbnail.tsx +437 -0
  224. package/src/grapher/lineCharts/Lines.tsx +258 -0
  225. package/src/grapher/lineLegend/LineLegend.tsx +723 -0
  226. package/src/grapher/lineLegend/LineLegendConstants.ts +9 -0
  227. package/src/grapher/lineLegend/LineLegendFilterAlgorithms.ts +143 -0
  228. package/src/grapher/lineLegend/LineLegendHelpers.ts +253 -0
  229. package/src/grapher/lineLegend/LineLegendTypes.ts +32 -0
  230. package/src/grapher/mapCharts/CanadaTopology.ts +17922 -0
  231. package/src/grapher/mapCharts/ChoroplethGlobe.tsx +949 -0
  232. package/src/grapher/mapCharts/ChoroplethMap.tsx +662 -0
  233. package/src/grapher/mapCharts/GeoFeatures.ts +184 -0
  234. package/src/grapher/mapCharts/GlobeController.ts +496 -0
  235. package/src/grapher/mapCharts/MapAnnotationPlacements.json +1040 -0
  236. package/src/grapher/mapCharts/MapAnnotationPlacements.ts +31 -0
  237. package/src/grapher/mapCharts/MapAnnotations.ts +723 -0
  238. package/src/grapher/mapCharts/MapChart.sample.ts +59 -0
  239. package/src/grapher/mapCharts/MapChart.scss +5 -0
  240. package/src/grapher/mapCharts/MapChart.tsx +720 -0
  241. package/src/grapher/mapCharts/MapChartConstants.ts +260 -0
  242. package/src/grapher/mapCharts/MapChartState.ts +416 -0
  243. package/src/grapher/mapCharts/MapChartThumbnail.tsx +25 -0
  244. package/src/grapher/mapCharts/MapComponents.tsx +338 -0
  245. package/src/grapher/mapCharts/MapConfig.ts +156 -0
  246. package/src/grapher/mapCharts/MapHelpers.ts +181 -0
  247. package/src/grapher/mapCharts/MapProjections.ts +49 -0
  248. package/src/grapher/mapCharts/MapSparkline.tsx +257 -0
  249. package/src/grapher/mapCharts/MapTooltip.scss +49 -0
  250. package/src/grapher/mapCharts/MapTooltip.tsx +409 -0
  251. package/src/grapher/mapCharts/MapTopology.ts +1766 -0
  252. package/src/grapher/mapCharts/d3-bboxCollide.js +204 -0
  253. package/src/grapher/mapCharts/d3-geo-projection.ts +198 -0
  254. package/src/grapher/modal/DownloadIcons.tsx +39 -0
  255. package/src/grapher/modal/DownloadModal.scss +300 -0
  256. package/src/grapher/modal/DownloadModal.tsx +1226 -0
  257. package/src/grapher/modal/EmbedModal.scss +40 -0
  258. package/src/grapher/modal/EmbedModal.tsx +160 -0
  259. package/src/grapher/modal/EntitySelectorModal.tsx +59 -0
  260. package/src/grapher/modal/Modal.scss +31 -0
  261. package/src/grapher/modal/Modal.tsx +90 -0
  262. package/src/grapher/modal/ModalHeader.scss +12 -0
  263. package/src/grapher/modal/ModalHeader.tsx +16 -0
  264. package/src/grapher/modal/SourcesDescriptions.scss +87 -0
  265. package/src/grapher/modal/SourcesDescriptions.tsx +89 -0
  266. package/src/grapher/modal/SourcesKeyDataTable.scss +49 -0
  267. package/src/grapher/modal/SourcesKeyDataTable.tsx +87 -0
  268. package/src/grapher/modal/SourcesModal.scss +301 -0
  269. package/src/grapher/modal/SourcesModal.tsx +568 -0
  270. package/src/grapher/noDataModal/NoDataModal.tsx +125 -0
  271. package/src/grapher/scatterCharts/ConnectedScatterLegend.tsx +143 -0
  272. package/src/grapher/scatterCharts/MultiColorPolyline.tsx +129 -0
  273. package/src/grapher/scatterCharts/NoDataSection.scss +14 -0
  274. package/src/grapher/scatterCharts/NoDataSection.tsx +56 -0
  275. package/src/grapher/scatterCharts/ScatterPlotChart.tsx +792 -0
  276. package/src/grapher/scatterCharts/ScatterPlotChartConstants.ts +157 -0
  277. package/src/grapher/scatterCharts/ScatterPlotChartState.ts +678 -0
  278. package/src/grapher/scatterCharts/ScatterPlotChartThumbnail.tsx +155 -0
  279. package/src/grapher/scatterCharts/ScatterPlotTooltip.tsx +560 -0
  280. package/src/grapher/scatterCharts/ScatterPoints.tsx +153 -0
  281. package/src/grapher/scatterCharts/ScatterPointsWithLabels.tsx +708 -0
  282. package/src/grapher/scatterCharts/ScatterSizeLegend.tsx +327 -0
  283. package/src/grapher/scatterCharts/ScatterUtils.ts +265 -0
  284. package/src/grapher/scatterCharts/Triangle.tsx +41 -0
  285. package/src/grapher/schema/README.md +33 -0
  286. package/src/grapher/schema/defaultGrapherConfig.ts +100 -0
  287. package/src/grapher/schema/grapher-schema.009.yaml +781 -0
  288. package/src/grapher/schema/migrations/helpers.ts +58 -0
  289. package/src/grapher/schema/migrations/migrate.ts +75 -0
  290. package/src/grapher/schema/migrations/migrations.ts +158 -0
  291. package/src/grapher/selection/MapSelectionArray.ts +99 -0
  292. package/src/grapher/selection/SelectionArray.ts +71 -0
  293. package/src/grapher/selection/readme.md +16 -0
  294. package/src/grapher/sidePanel/SidePanel.scss +10 -0
  295. package/src/grapher/sidePanel/SidePanel.tsx +23 -0
  296. package/src/grapher/slideInDrawer/SlideInDrawer.scss +57 -0
  297. package/src/grapher/slideInDrawer/SlideInDrawer.tsx +125 -0
  298. package/src/grapher/slideshowController/SlideShowController.tsx +43 -0
  299. package/src/grapher/slideshowController/readme.md +7 -0
  300. package/src/grapher/slopeCharts/MarkX.tsx +45 -0
  301. package/src/grapher/slopeCharts/Slope.tsx +102 -0
  302. package/src/grapher/slopeCharts/SlopeChart.tsx +1152 -0
  303. package/src/grapher/slopeCharts/SlopeChartConstants.ts +33 -0
  304. package/src/grapher/slopeCharts/SlopeChartHelpers.ts +73 -0
  305. package/src/grapher/slopeCharts/SlopeChartState.ts +392 -0
  306. package/src/grapher/slopeCharts/SlopeChartThumbnail.tsx +368 -0
  307. package/src/grapher/stackedCharts/AbstractStackedChartState.ts +370 -0
  308. package/src/grapher/stackedCharts/MarimekkoBars.tsx +190 -0
  309. package/src/grapher/stackedCharts/MarimekkoBarsForOneEntity.tsx +168 -0
  310. package/src/grapher/stackedCharts/MarimekkoChart.tsx +1144 -0
  311. package/src/grapher/stackedCharts/MarimekkoChartConstants.ts +112 -0
  312. package/src/grapher/stackedCharts/MarimekkoChartHelpers.ts +21 -0
  313. package/src/grapher/stackedCharts/MarimekkoChartState.ts +465 -0
  314. package/src/grapher/stackedCharts/MarimekkoChartThumbnail.tsx +168 -0
  315. package/src/grapher/stackedCharts/MarimekkoInternalLabels.tsx +124 -0
  316. package/src/grapher/stackedCharts/StackedAreaChart.tsx +678 -0
  317. package/src/grapher/stackedCharts/StackedAreaChartState.ts +34 -0
  318. package/src/grapher/stackedCharts/StackedAreaChartThumbnail.tsx +215 -0
  319. package/src/grapher/stackedCharts/StackedAreas.tsx +223 -0
  320. package/src/grapher/stackedCharts/StackedBarChart.tsx +619 -0
  321. package/src/grapher/stackedCharts/StackedBarChartState.ts +80 -0
  322. package/src/grapher/stackedCharts/StackedBarChartThumbnail.tsx +220 -0
  323. package/src/grapher/stackedCharts/StackedBarSegment.tsx +87 -0
  324. package/src/grapher/stackedCharts/StackedBars.tsx +102 -0
  325. package/src/grapher/stackedCharts/StackedConstants.ts +109 -0
  326. package/src/grapher/stackedCharts/StackedDiscreteBarChart.tsx +270 -0
  327. package/src/grapher/stackedCharts/StackedDiscreteBarChartState.ts +296 -0
  328. package/src/grapher/stackedCharts/StackedDiscreteBarChartThumbnail.tsx +27 -0
  329. package/src/grapher/stackedCharts/StackedDiscreteBars.tsx +648 -0
  330. package/src/grapher/stackedCharts/StackedUtils.ts +142 -0
  331. package/src/grapher/tabs/Tabs.scss +169 -0
  332. package/src/grapher/tabs/Tabs.tsx +54 -0
  333. package/src/grapher/tabs/TabsWithDropdown.scss +62 -0
  334. package/src/grapher/tabs/TabsWithDropdown.tsx +114 -0
  335. package/src/grapher/testData/OwidTestData.sample.ts +273 -0
  336. package/src/grapher/testData/OwidTestData.ts +64 -0
  337. package/src/grapher/timeline/TimelineComponent.scss +139 -0
  338. package/src/grapher/timeline/TimelineComponent.tsx +658 -0
  339. package/src/grapher/timeline/TimelineController.ts +368 -0
  340. package/src/grapher/timeline/readme.md +7 -0
  341. package/src/grapher/tooltip/Tooltip.scss +510 -0
  342. package/src/grapher/tooltip/Tooltip.tsx +294 -0
  343. package/src/grapher/tooltip/TooltipContents.tsx +383 -0
  344. package/src/grapher/tooltip/TooltipProps.ts +123 -0
  345. package/src/grapher/tooltip/TooltipState.ts +81 -0
  346. package/src/grapher/verticalLabels/VerticalLabels.tsx +31 -0
  347. package/src/grapher/verticalLabels/VerticalLabelsState.ts +154 -0
  348. package/src/index.ts +226 -0
  349. package/src/styles/charts.scss +15 -0
  350. package/src/types/NominalType.ts +30 -0
  351. package/src/types/OwidOrigin.ts +18 -0
  352. package/src/types/OwidSource.ts +9 -0
  353. package/src/types/OwidVariable.ts +133 -0
  354. package/src/types/OwidVariableDisplayConfigInterface.ts +49 -0
  355. package/src/types/analyticsTypes.ts +54 -0
  356. package/src/types/dbTypes/Tags.ts +11 -0
  357. package/src/types/domainTypes/Archive.ts +139 -0
  358. package/src/types/domainTypes/Author.ts +28 -0
  359. package/src/types/domainTypes/ContentGraph.ts +76 -0
  360. package/src/types/domainTypes/CoreTableTypes.ts +305 -0
  361. package/src/types/domainTypes/DeployStatus.ts +23 -0
  362. package/src/types/domainTypes/Layout.ts +34 -0
  363. package/src/types/domainTypes/Posts.ts +34 -0
  364. package/src/types/domainTypes/Search.ts +299 -0
  365. package/src/types/domainTypes/Site.ts +8 -0
  366. package/src/types/domainTypes/StaticViz.ts +64 -0
  367. package/src/types/domainTypes/Toc.ts +11 -0
  368. package/src/types/domainTypes/Tombstone.ts +19 -0
  369. package/src/types/domainTypes/Various.ts +79 -0
  370. package/src/types/gdocTypes/Gdoc.ts +280 -0
  371. package/src/types/grapherTypes/BinningStrategyTypes.ts +46 -0
  372. package/src/types/grapherTypes/GrapherConstants.ts +53 -0
  373. package/src/types/grapherTypes/GrapherTypes.ts +743 -0
  374. package/src/types/index.ts +316 -0
  375. package/src/types/wordpressTypes/WordpressTypes.ts +9 -0
  376. package/src/utils/Bounds.ts +439 -0
  377. package/src/utils/BrowserUtils.ts +12 -0
  378. package/src/utils/FuzzySearch.ts +74 -0
  379. package/src/utils/MultiDimDataPageConfig.ts +31 -0
  380. package/src/utils/OwidVariable.ts +82 -0
  381. package/src/utils/PointVector.ts +97 -0
  382. package/src/utils/PromiseCache.ts +36 -0
  383. package/src/utils/PromiseSwitcher.ts +52 -0
  384. package/src/utils/TimeBounds.ts +130 -0
  385. package/src/utils/Tippy.tsx +57 -0
  386. package/src/utils/Util.ts +2369 -0
  387. package/src/utils/archival/archivalDate.ts +48 -0
  388. package/src/utils/dayjs.ts +32 -0
  389. package/src/utils/formatValue.ts +242 -0
  390. package/src/utils/grapherConfigUtils.ts +81 -0
  391. package/src/utils/image.ts +225 -0
  392. package/src/utils/index.ts +318 -0
  393. package/src/utils/isPresent.ts +5 -0
  394. package/src/utils/metadataHelpers.ts +329 -0
  395. package/src/utils/persistable/Persistable.ts +82 -0
  396. package/src/utils/persistable/readme.md +50 -0
  397. package/src/utils/regions.json +5635 -0
  398. package/src/utils/regions.ts +463 -0
  399. package/src/utils/serializers.ts +16 -0
  400. package/src/utils/string.ts +42 -0
  401. package/src/utils/urls/Url.ts +195 -0
  402. package/src/utils/urls/UrlMigration.ts +10 -0
  403. package/src/utils/urls/UrlUtils.ts +54 -0
  404. package/src/utils/urls/readme.md +90 -0
@@ -0,0 +1,338 @@
1
+ import React from "react"
2
+ import { makeIdForHumanConsumption } from "../../utils/index.js"
3
+ import {
4
+ BLUR_FILL_OPACITY,
5
+ BLUR_STROKE_OPACITY,
6
+ ChoroplethSeries,
7
+ DEFAULT_STROKE_COLOR,
8
+ DEFAULT_STROKE_WIDTH,
9
+ HOVER_STROKE_COLOR,
10
+ HOVER_STROKE_WIDTH,
11
+ PATTERN_STROKE_WIDTH,
12
+ SELECTED_STROKE_WIDTH,
13
+ SVGMouseEvent,
14
+ RenderFeature,
15
+ InternalAnnotation,
16
+ ExternalAnnotation,
17
+ } from "./MapChartConstants"
18
+ import { isMapRenderFeature } from "./MapHelpers"
19
+ import { getExternalMarkerEndPosition } from "./MapAnnotations"
20
+ import { Patterns } from "../core/GrapherConstants"
21
+ import { calculateLightnessScore, isDarkColor } from "../color/ColorUtils"
22
+ import { Halo } from "../../components/index.js"
23
+ import { InteractionState } from "../interaction/InteractionState"
24
+
25
+ export function BackgroundCountry<Feature extends RenderFeature>({
26
+ feature,
27
+ path,
28
+ strokeWidth = DEFAULT_STROKE_WIDTH,
29
+ }: {
30
+ feature: Feature
31
+ path?: string
32
+ strokeWidth?: number
33
+ }): React.ReactElement {
34
+ return (
35
+ <path
36
+ id={makeIdForHumanConsumption(feature.id)}
37
+ d={isMapRenderFeature(feature) ? feature.path : path}
38
+ strokeWidth={strokeWidth}
39
+ stroke="#aaa"
40
+ fill="#fff"
41
+ />
42
+ )
43
+ }
44
+
45
+ export function CountryWithData<Feature extends RenderFeature>({
46
+ feature,
47
+ series,
48
+ path,
49
+ isSelected = false,
50
+ hover,
51
+ strokeScale = 1,
52
+ onClick,
53
+ onTouchStart,
54
+ onMouseEnter,
55
+ onMouseLeave,
56
+ }: {
57
+ feature: Feature
58
+ series: ChoroplethSeries
59
+ path?: string
60
+ isSelected?: boolean
61
+ hover?: InteractionState
62
+ strokeScale?: number
63
+ onClick?: (event: SVGMouseEvent) => void
64
+ onTouchStart?: (event: React.TouchEvent<SVGElement>) => void
65
+ onMouseEnter?: (feature: Feature, event: MouseEvent) => void
66
+ onMouseLeave?: () => void
67
+ }): React.ReactElement {
68
+ const isProjection = series.isProjection
69
+ const isHovered = hover?.active ?? false
70
+
71
+ const stroke =
72
+ isHovered || isSelected ? HOVER_STROKE_COLOR : DEFAULT_STROKE_COLOR
73
+ const strokeWidth = getStrokeWidth({ isHovered, isSelected }) / strokeScale
74
+ const strokeOpacity = hover?.background ? BLUR_STROKE_OPACITY : 1
75
+
76
+ const fill = isProjection
77
+ ? `url(#${makeProjectedDataPatternId(series.color)})`
78
+ : series.color
79
+ const fillOpacity = hover?.background ? BLUR_FILL_OPACITY : 1
80
+
81
+ return (
82
+ <path
83
+ id={makeIdForHumanConsumption(feature.id)}
84
+ data-feature-id={feature.id}
85
+ d={isMapRenderFeature(feature) ? feature.path : path}
86
+ strokeWidth={strokeWidth}
87
+ stroke={stroke}
88
+ strokeOpacity={strokeOpacity}
89
+ cursor="pointer"
90
+ fill={fill}
91
+ fillOpacity={fillOpacity}
92
+ onClick={onClick}
93
+ onTouchStart={onTouchStart}
94
+ onMouseEnter={(event): void =>
95
+ onMouseEnter?.(feature, event.nativeEvent)
96
+ }
97
+ onMouseLeave={onMouseLeave}
98
+ />
99
+ )
100
+ }
101
+
102
+ export function CountryWithNoData<Feature extends RenderFeature>({
103
+ feature,
104
+ path,
105
+ patternId,
106
+ isSelected = false,
107
+ hover,
108
+ strokeScale = 1,
109
+ onClick,
110
+ onTouchStart,
111
+ onMouseEnter,
112
+ onMouseLeave,
113
+ }: {
114
+ feature: Feature
115
+ path?: string
116
+ patternId: string
117
+ isSelected?: boolean
118
+ hover?: InteractionState
119
+ strokeScale?: number
120
+ onClick?: (event: SVGMouseEvent) => void
121
+ onTouchStart?: (event: React.TouchEvent<SVGElement>) => void
122
+ onMouseEnter?: (feature: Feature, event: MouseEvent) => void
123
+ onMouseLeave?: () => void
124
+ }): React.ReactElement {
125
+ const isHovered = hover?.active ?? false
126
+
127
+ const stroke = isHovered || isSelected ? HOVER_STROKE_COLOR : "#aaa"
128
+ const strokeWidth = getStrokeWidth({ isHovered, isSelected }) / strokeScale
129
+ const strokeOpacity = hover?.background ? BLUR_STROKE_OPACITY : 1
130
+
131
+ const fillOpacity = hover?.background ? BLUR_FILL_OPACITY : 1
132
+
133
+ return (
134
+ <path
135
+ id={makeIdForHumanConsumption(feature.id)}
136
+ data-feature-id={feature.id}
137
+ d={isMapRenderFeature(feature) ? feature.path : path}
138
+ strokeWidth={strokeWidth}
139
+ stroke={stroke}
140
+ strokeOpacity={strokeOpacity}
141
+ cursor="pointer"
142
+ fill={`url(#${patternId})`}
143
+ fillOpacity={fillOpacity}
144
+ onClick={onClick}
145
+ onTouchStart={onTouchStart}
146
+ onMouseEnter={(event): void =>
147
+ onMouseEnter?.(feature, event.nativeEvent)
148
+ }
149
+ onMouseLeave={onMouseLeave}
150
+ />
151
+ )
152
+ }
153
+
154
+ export function NoDataPattern({
155
+ patternId,
156
+ scale = 1,
157
+ }: {
158
+ patternId: string
159
+ scale?: number
160
+ }): React.ReactElement {
161
+ return (
162
+ <pattern
163
+ id={patternId}
164
+ patternUnits="userSpaceOnUse"
165
+ width="4"
166
+ height="4"
167
+ patternTransform={`rotate(-45 2 2) scale(${scale})`}
168
+ >
169
+ <path
170
+ d="M -1,2 l 6,0"
171
+ stroke="#ccc"
172
+ strokeWidth={PATTERN_STROKE_WIDTH}
173
+ />
174
+ </pattern>
175
+ )
176
+ }
177
+
178
+ export function ProjectedDataPattern({
179
+ color,
180
+ scale = 1,
181
+ forLegend = false,
182
+ }: {
183
+ color: string
184
+ scale?: number
185
+ forLegend?: boolean
186
+ }): React.ReactElement {
187
+ return (
188
+ <DottedProjectedDataPattern
189
+ patternId={makeProjectedDataPatternId(color, { forLegend })}
190
+ color={color}
191
+ scale={scale}
192
+ dotOpacity={forLegend ? 0.2 : undefined}
193
+ />
194
+ )
195
+ }
196
+
197
+ function DottedProjectedDataPattern({
198
+ patternId,
199
+ color,
200
+ scale = 1,
201
+ patternSize = 4,
202
+ dotSize = patternSize / 4,
203
+ dotOpacity,
204
+ }: {
205
+ patternId: string
206
+ color: string
207
+ scale?: number
208
+ patternSize?: number
209
+ dotSize?: number
210
+ dotOpacity?: number // inferred from color lightness if not provided
211
+ }): React.ReactElement {
212
+ // Choose the dot opacity based on the lightness of the color:
213
+ // - If the color is light, make the dots more transparent
214
+ // - If the color is dark, make the dots more opaque
215
+ const lightness = calculateLightnessScore(color) ?? 0
216
+ const opacity = dotOpacity ?? Math.max(1 - lightness, 0.1)
217
+
218
+ return (
219
+ <pattern
220
+ id={patternId}
221
+ patternUnits="userSpaceOnUse"
222
+ width={patternSize}
223
+ height={patternSize}
224
+ patternTransform={`rotate(45) scale(${scale})`}
225
+ >
226
+ {/* colored background */}
227
+ <rect width={patternSize} height={patternSize} fill={color} />
228
+
229
+ {/* dots */}
230
+ <circle
231
+ cx={patternSize / 2}
232
+ cy={patternSize / 2}
233
+ r={dotSize}
234
+ fill="black"
235
+ fillOpacity={opacity}
236
+ />
237
+ </pattern>
238
+ )
239
+ }
240
+
241
+ export function InternalValueAnnotation({
242
+ annotation,
243
+ strokeScale = 1,
244
+ showOutline = false,
245
+ }: {
246
+ annotation: InternalAnnotation
247
+ strokeScale?: number
248
+ showOutline?: boolean
249
+ }): React.ReactElement {
250
+ const { id, text, color, placedBounds, fontSize } = annotation
251
+
252
+ const showHalo = showOutline && isDarkColor(color)
253
+
254
+ return (
255
+ <Halo id={id} outlineWidth={3} show={showHalo}>
256
+ <text
257
+ id={makeIdForHumanConsumption(id)}
258
+ x={placedBounds.topLeft.x}
259
+ y={placedBounds.topLeft.y + placedBounds.height - 1}
260
+ fontSize={fontSize}
261
+ fontWeight={700}
262
+ fill={color}
263
+ strokeWidth={DEFAULT_STROKE_WIDTH / strokeScale}
264
+ style={{ pointerEvents: "none" }}
265
+ >
266
+ {text}
267
+ </text>
268
+ </Halo>
269
+ )
270
+ }
271
+
272
+ export function ExternalValueAnnotation({
273
+ annotation,
274
+ strokeScale = 1,
275
+ onMouseEnter,
276
+ onMouseLeave,
277
+ }: {
278
+ annotation: ExternalAnnotation
279
+ strokeScale?: number
280
+ onMouseEnter?: (feature: RenderFeature) => void
281
+ onMouseLeave?: () => void
282
+ }): React.ReactElement {
283
+ const { id, text, direction, anchor, placedBounds, fontSize } = annotation
284
+
285
+ const markerStart = anchor
286
+ const markerEnd = getExternalMarkerEndPosition({
287
+ textBounds: placedBounds,
288
+ direction,
289
+ })
290
+
291
+ return (
292
+ <g id={makeIdForHumanConsumption(id)}>
293
+ <line
294
+ x1={markerStart[0]}
295
+ y1={markerStart[1]}
296
+ x2={markerEnd[0]}
297
+ y2={markerEnd[1]}
298
+ stroke={annotation.color}
299
+ strokeWidth={(0.5 * HOVER_STROKE_WIDTH) / strokeScale}
300
+ style={{ pointerEvents: "none" }}
301
+ />
302
+ <text
303
+ x={placedBounds.x}
304
+ y={placedBounds.y + placedBounds.height - 1}
305
+ fontSize={fontSize}
306
+ strokeWidth={DEFAULT_STROKE_WIDTH / strokeScale}
307
+ fill={annotation.color}
308
+ fontWeight={700}
309
+ onMouseEnter={() => onMouseEnter?.(annotation.feature)}
310
+ onMouseLeave={onMouseLeave}
311
+ >
312
+ {text}
313
+ </text>
314
+ </g>
315
+ )
316
+ }
317
+
318
+ function getStrokeWidth({
319
+ isSelected,
320
+ isHovered,
321
+ }: {
322
+ isSelected: boolean
323
+ isHovered: boolean
324
+ }): number {
325
+ if (isHovered) return HOVER_STROKE_WIDTH
326
+ if (isSelected) return SELECTED_STROKE_WIDTH
327
+ return DEFAULT_STROKE_WIDTH
328
+ }
329
+
330
+ export function makeProjectedDataPatternId(
331
+ color: string,
332
+ options?: { forLegend: boolean }
333
+ ): string {
334
+ const prefix = options?.forLegend
335
+ ? Patterns.projectedDataPatternForLegend
336
+ : Patterns.projectedDataPattern
337
+ return `${prefix}_${color}`
338
+ }
@@ -0,0 +1,156 @@
1
+ import { observable, makeObservable } from "mobx"
2
+ import {
3
+ GlobeConfig,
4
+ MapRegionName,
5
+ MapConfigInterface,
6
+ TimeBound,
7
+ EntityName,
8
+ } from "../../types/index.js"
9
+ import { ColorScaleConfig } from "../color/ColorScaleConfig"
10
+ import {
11
+ ColumnSlug,
12
+ Persistable,
13
+ updatePersistables,
14
+ objectWithPersistablesToObject,
15
+ deleteRuntimeAndUnchangedProps,
16
+ maxTimeBoundFromJSONOrPositiveInfinity,
17
+ maxTimeToJSON,
18
+ minTimeToJSON,
19
+ trimObject,
20
+ NoUndefinedValues,
21
+ ToleranceStrategy,
22
+ minTimeBoundFromJSONOrNegativeInfinity,
23
+ } from "../../utils/index.js"
24
+ import { MapSelectionArray } from "../selection/MapSelectionArray"
25
+ import { DEFAULT_GLOBE_ROTATION, DEFAULT_GLOBE_ZOOM } from "./MapChartConstants"
26
+ import * as R from "remeda"
27
+
28
+ // MapConfig holds the data and underlying logic needed by MapTab.
29
+ // It wraps the map property on ChartConfig.
30
+ // TODO: migrate database config & only pass legend props
31
+ class MapConfigDefaults {
32
+ columnSlug: ColumnSlug | undefined = undefined
33
+ time: TimeBound | undefined = undefined
34
+ startTime: TimeBound | undefined = undefined
35
+ timeTolerance: number | undefined = undefined
36
+ toleranceStrategy: ToleranceStrategy | undefined = undefined
37
+ hideTimeline: boolean | undefined = undefined
38
+
39
+ region = MapRegionName.World
40
+ selection = new MapSelectionArray()
41
+ hoverCountry?: EntityName // shared across facets
42
+
43
+ globe: GlobeConfig = {
44
+ isActive: false,
45
+ rotation: DEFAULT_GLOBE_ROTATION, // specified as [lot, lan]
46
+ zoom: DEFAULT_GLOBE_ZOOM,
47
+ }
48
+
49
+ colorScale = new ColorScaleConfig()
50
+ // Show the label from colorSchemeLabels in the tooltip instead of the numeric value
51
+ tooltipUseCustomLabels: boolean | undefined = undefined
52
+
53
+ constructor() {
54
+ makeObservable(this, {
55
+ columnSlug: observable,
56
+ time: observable,
57
+ startTime: observable,
58
+ timeTolerance: observable,
59
+ toleranceStrategy: observable,
60
+ hideTimeline: observable,
61
+ region: observable,
62
+ selection: observable,
63
+ globe: observable,
64
+ colorScale: observable,
65
+ tooltipUseCustomLabels: observable,
66
+ hoverCountry: observable,
67
+ })
68
+ }
69
+ }
70
+
71
+ export class MapConfig extends MapConfigDefaults implements Persistable {
72
+ updateFromObject(obj: Partial<MapConfigInterface>): void {
73
+ updatePersistables(this, obj)
74
+
75
+ this.time = maxTimeBoundFromJSONOrPositiveInfinity(obj.time)
76
+
77
+ // If a start time is provided, use it; otherwise, set it to the end time
78
+ // so that a single map (not a facetted one) is shown by default
79
+ if (obj.startTime) {
80
+ this.startTime = minTimeBoundFromJSONOrNegativeInfinity(
81
+ obj.startTime
82
+ )
83
+ } else {
84
+ this.startTime = this.time
85
+ }
86
+
87
+ // Map [lat, lon] to the internally used [lon, lat]
88
+ if (obj.globe?.rotation) {
89
+ this.globe = {
90
+ ...this.globe,
91
+ rotation: R.reverse(obj.globe.rotation),
92
+ }
93
+ }
94
+
95
+ // Update selection
96
+ if (obj.selectedEntityNames)
97
+ this.selection.setSelectedEntities(obj.selectedEntityNames)
98
+ }
99
+
100
+ toObject(): NoUndefinedValues<MapConfigInterface> {
101
+ const obj = objectWithPersistablesToObject(this) as MapConfigInterface
102
+ deleteRuntimeAndUnchangedProps(obj, new MapConfigDefaults())
103
+
104
+ if (obj.time) obj.time = maxTimeToJSON(this.time) as any
105
+ if (obj.startTime) obj.startTime = minTimeToJSON(this.startTime) as any
106
+
107
+ // No need to store the startTime if it's the same as the end time
108
+ if (obj.startTime === obj.time) delete obj.startTime
109
+
110
+ // persist selection
111
+ obj.selectedEntityNames = this.selection.selectedEntityNames
112
+ // @ts-expect-error hack to prevent selection from being persisted
113
+ delete obj.selection
114
+
115
+ // don't persist globe settings if the globe isn't active
116
+ if (!obj.globe?.isActive) delete obj.globe
117
+
118
+ // round rotation coordinates before persisting
119
+ if (obj.globe?.rotation)
120
+ obj.globe = {
121
+ ...obj.globe,
122
+ rotation: [
123
+ // we use [lon, lat] internally, but persist [lat, lon]
124
+ R.round(obj.globe.rotation[1], 2),
125
+ R.round(obj.globe.rotation[0], 2),
126
+ ],
127
+ }
128
+
129
+ // round zoom level before persisting
130
+ if (obj.globe?.zoom) {
131
+ obj.globe = {
132
+ ...obj.globe,
133
+ zoom: R.round(obj.globe.zoom, 2),
134
+ }
135
+ }
136
+
137
+ return trimObject(obj)
138
+ }
139
+
140
+ constructor(obj?: Partial<MapConfigInterface>) {
141
+ super()
142
+ if (obj) this.updateFromObject(obj)
143
+ }
144
+
145
+ isContinentActive(): this is MapConfigWithActiveContinent {
146
+ return this.region !== MapRegionName.World
147
+ }
148
+
149
+ is2dContinentActive(): this is MapConfigWithActiveContinent {
150
+ return this.isContinentActive() && !this.globe.isActive
151
+ }
152
+ }
153
+
154
+ type MapConfigWithActiveContinent = MapConfig & {
155
+ region: Exclude<MapRegionName, "World">
156
+ }
@@ -0,0 +1,181 @@
1
+ import { Quadtree } from "d3-quadtree"
2
+ import {
3
+ EntityName,
4
+ getAggregates,
5
+ getContinents,
6
+ getIncomeGroups,
7
+ getCountryNamesForRegion,
8
+ getRelativeMouse,
9
+ lazy,
10
+ } from "../../utils/index.js"
11
+ import { GlobeRegionName, MapRegionName } from "../../types/index.js"
12
+ import {
13
+ GEO_FEATURES_CLASSNAME,
14
+ MAP_HOVER_TARGET_RANGE,
15
+ RenderFeature,
16
+ MapRenderFeature,
17
+ RenderFeatureType,
18
+ } from "./MapChartConstants"
19
+ import { CanadaTopology } from "./CanadaTopology.js"
20
+ import { MapTopology } from "./MapTopology.js"
21
+ import { MapSelectionArray } from "../selection/MapSelectionArray.js"
22
+ import * as R from "remeda"
23
+
24
+ export function detectNearbyFeature<Feature extends RenderFeature>({
25
+ quadtree,
26
+ element,
27
+ event,
28
+ distance = MAP_HOVER_TARGET_RANGE,
29
+ }: {
30
+ quadtree: Quadtree<Feature>
31
+ element: SVGGElement
32
+ event: MouseEvent | TouchEvent
33
+ distance?: number
34
+ }): Feature | undefined {
35
+ const groupElement = element.querySelector(`.${GEO_FEATURES_CLASSNAME}`)
36
+ if (!groupElement) {
37
+ console.error(`.${GEO_FEATURES_CLASSNAME} doesn't exist`)
38
+ return
39
+ }
40
+
41
+ const { x, y } = getRelativeMouse(groupElement, event)
42
+ return quadtree.find(x, y, distance)
43
+ }
44
+
45
+ export const sortFeaturesByInteractionStateAndSize = <
46
+ Feature extends RenderFeature,
47
+ >(
48
+ features: Feature[],
49
+ {
50
+ isHovered,
51
+ isSelected,
52
+ }: {
53
+ isHovered: (featureId: string) => boolean
54
+ isSelected: (featureId: string) => boolean
55
+ }
56
+ ): Feature[] => {
57
+ const preferA = 1 as const
58
+ const preferB = -1 as const
59
+
60
+ return R.sort(features, (a, b) => {
61
+ if (isHovered(a.id) && !isHovered(b.id)) return preferA
62
+ if (!isHovered(a.id) && isHovered(b.id)) return preferB
63
+
64
+ if (isSelected(a.id) && !isSelected(b.id)) return preferA
65
+ if (!isSelected(a.id) && isSelected(b.id)) return preferB
66
+
67
+ return a.geoBounds.area < b.geoBounds.area ? preferA : preferB
68
+ })
69
+ }
70
+
71
+ export const calculateDistance = (
72
+ p1: [number, number],
73
+ p2: [number, number]
74
+ ): number => {
75
+ return Math.hypot(p2[0] - p1[0], p2[1] - p1[1])
76
+ }
77
+
78
+ /**
79
+ * Check if a country is visible on the rendered 3d globe from the current
80
+ * viewing angle, without taking into account the zoom level.
81
+ *
82
+ * More specifically, this function checks if the feature's _centroid_ is
83
+ * visible on the globe, i.e. parts of a country could still be visible
84
+ * even if the centroid is not.
85
+ */
86
+ export function isPointPlacedOnVisibleHemisphere(
87
+ point: [number, number],
88
+ rotation: [number, number],
89
+ threshold = 0 // 1 = at the exact center, 0 = anywhere on the visible hemisphere
90
+ ): boolean {
91
+ const toRadians = (degree: number): number => (degree * Math.PI) / 180
92
+
93
+ // convert centroid degrees to radians
94
+ const lambda = toRadians(point[0])
95
+ const phi = toRadians(point[1])
96
+
97
+ // get current rotation in radians
98
+ const rotationLambda = toRadians(rotation[0])
99
+ const rotationPhi = toRadians(rotation[1])
100
+
101
+ // calculate the cosine of the angular distance between the feature's
102
+ // center point and the center points of the current view
103
+ const cosDelta =
104
+ Math.sin(phi) * Math.sin(rotationPhi) +
105
+ Math.cos(phi) *
106
+ Math.cos(rotationPhi) *
107
+ Math.cos(lambda - rotationLambda)
108
+
109
+ return cosDelta > threshold
110
+ }
111
+
112
+ export function getForegroundFeatures<Feature extends RenderFeature>(
113
+ features: Feature[],
114
+ selectionArray: MapSelectionArray
115
+ ): Feature[] {
116
+ // if no regions are selected, then all countries are in the foreground
117
+ if (!selectionArray.hasRegions) return features
118
+
119
+ // all countries within the selected regions are in the foreground
120
+ const countrySet = selectionArray.countryNamesForSelectedRegionsSet
121
+ return features.filter((feature) => countrySet.has(feature.id))
122
+ }
123
+
124
+ // A map of the form:
125
+ // - Africa: [Algeria, Angola, ...]
126
+ // - North America: [Canada, United States, ...]
127
+ const countriesByRegionMap = lazy(
128
+ () =>
129
+ new Map(
130
+ [...getContinents(), ...getAggregates(), ...getIncomeGroups()].map(
131
+ (region) => [
132
+ region.name,
133
+ new Set(getCountryNamesForRegion(region)),
134
+ ]
135
+ )
136
+ )
137
+ )
138
+
139
+ export const getCountriesByRegion = (
140
+ regionName: string
141
+ ): Set<string> | undefined => countriesByRegionMap().get(regionName)
142
+
143
+ let _isOnTheMapCache: Set<string>
144
+ export const isOnTheMap = (entityName: EntityName): boolean => {
145
+ // Cache the result
146
+ if (!_isOnTheMapCache)
147
+ _isOnTheMapCache = new Set(
148
+ MapTopology.objects.world.geometries.map((region: any) => region.id)
149
+ )
150
+ return _isOnTheMapCache.has(entityName)
151
+ }
152
+
153
+ let _isOnTheCanadaMapCache: Set<string>
154
+ export const isOnTheCanadaMap = (entityName: EntityName): boolean => {
155
+ // Cache the result
156
+ if (!_isOnTheCanadaMapCache)
157
+ _isOnTheCanadaMapCache = new Set(
158
+ CanadaTopology.objects.canada.geometries.map(
159
+ (region: any) => region.id
160
+ )
161
+ )
162
+ return _isOnTheCanadaMapCache.has(entityName)
163
+ }
164
+
165
+ export function isMapRenderFeature(
166
+ feature: RenderFeature
167
+ ): feature is MapRenderFeature {
168
+ return feature.type === RenderFeatureType.Map
169
+ }
170
+
171
+ export function isValidMapRegionName(
172
+ candidate: string
173
+ ): candidate is MapRegionName {
174
+ return Object.values(MapRegionName).includes(candidate as any)
175
+ }
176
+
177
+ export function isValidGlobeRegionName(
178
+ candidate: string
179
+ ): candidate is GlobeRegionName {
180
+ return isValidMapRegionName(candidate) && candidate !== MapRegionName.World
181
+ }