@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,720 @@
1
+ import {
2
+ Bounds,
3
+ getRelativeMouse,
4
+ guid,
5
+ exposeInstanceOnWindow,
6
+ Color,
7
+ HorizontalAlign,
8
+ } from "../../utils/index.js"
9
+ import { observable, computed, action, makeObservable } from "mobx"
10
+ import { observer } from "mobx-react"
11
+ import {
12
+ HorizontalCategoricalColorLegend,
13
+ HorizontalColorLegendManager,
14
+ HorizontalNumericColorLegend,
15
+ } from "../legend/HorizontalColorLegends"
16
+ import { select } from "d3-selection"
17
+ import { easeCubic } from "d3-ease"
18
+ import { MapTooltip } from "./MapTooltip"
19
+ import { TooltipState } from "../tooltip/Tooltip.js"
20
+ import { CoreColumn } from "../../core-table/index.js"
21
+ import {
22
+ GeoFeature,
23
+ MapBracket,
24
+ MapChartManager,
25
+ ChoroplethSeriesByName,
26
+ ChoroplethMapManager,
27
+ DEFAULT_STROKE_COLOR,
28
+ HOVER_STROKE_COLOR,
29
+ HOVER_STROKE_WIDTH,
30
+ MAP_CHART_CLASSNAME,
31
+ MapColumnInfo,
32
+ PROJECTED_DATA_LEGEND_COLOR,
33
+ MapViewport,
34
+ } from "./MapChartConstants"
35
+ import { MapConfig } from "./MapConfig"
36
+ import { ColorScale } from "../color/ColorScale"
37
+ import {
38
+ BASE_FONT_SIZE,
39
+ DEFAULT_GRAPHER_BOUNDS,
40
+ GRAPHER_MAX_TOOLTIP_WIDTH,
41
+ Patterns,
42
+ } from "../core/GrapherConstants"
43
+ import { ChartInterface } from "../chart/ChartInterface"
44
+ import {
45
+ CategoricalBin,
46
+ ColorScaleBin,
47
+ isCategoricalBin,
48
+ isNoDataBin,
49
+ isNumericBin,
50
+ isProjectedDataBin,
51
+ NumericBin,
52
+ } from "../color/ColorScaleBin"
53
+ import {
54
+ LegendInteractionState,
55
+ LegendStyleConfig,
56
+ } from "../legend/LegendInteractionState"
57
+ import {
58
+ ColumnSlug,
59
+ GrapherVariant,
60
+ MapRegionName,
61
+ } from "../../types/index.js"
62
+ import { ClipPath, makeClipPath } from "../chart/ChartUtils"
63
+ import { NoDataModal } from "../noDataModal/NoDataModal"
64
+ import { Component, createRef } from "react"
65
+ import { ChoroplethMap } from "./ChoroplethMap"
66
+ import { ChoroplethGlobe } from "./ChoroplethGlobe"
67
+ import { GlobeController } from "./GlobeController"
68
+ import { MapSelectionArray } from "../selection/MapSelectionArray.js"
69
+ import { match } from "ts-pattern"
70
+ import { makeProjectedDataPatternId } from "./MapComponents"
71
+ import { MapChartState } from "./MapChartState"
72
+ import { ChartComponentProps } from "../chart/ChartTypeMap.js"
73
+ import { InteractionState } from "../interaction/InteractionState"
74
+
75
+ export type MapChartProps = ChartComponentProps<MapChartState>
76
+
77
+ export const PADDING_BETWEEN_MAP_AND_LEGEND = 8
78
+ export const PADDING_BELOW_MAP_LEGEND = 4
79
+ export const PADDING_BETWEEN_MAP_LEGENDS = 4
80
+ export const MAP_LEGEND_MAX_WIDTH_RATIO = 0.95
81
+
82
+ @observer
83
+ export class MapChart
84
+ extends Component<MapChartProps>
85
+ implements
86
+ ChartInterface,
87
+ HorizontalColorLegendManager,
88
+ ChoroplethMapManager
89
+ {
90
+ constructor(props: MapChartProps) {
91
+ super(props)
92
+
93
+ makeObservable(this, {
94
+ hoverBracket: observable,
95
+ tooltipState: observable,
96
+ })
97
+ }
98
+
99
+ /**
100
+ * The currently hovered map bracket.
101
+ *
102
+ * Hovering a map bracket highlights all countries within that bracket on the map.
103
+ */
104
+ hoverBracket: MapBracket | undefined = undefined
105
+
106
+ tooltipState = new TooltipState<{
107
+ featureId: string
108
+ }>()
109
+
110
+ @computed get chartState(): MapChartState {
111
+ return this.props.chartState
112
+ }
113
+
114
+ @computed get selectionArray(): MapSelectionArray {
115
+ return this.chartState.selectionArray
116
+ }
117
+
118
+ @computed get mapColumn(): CoreColumn {
119
+ return this.chartState.mapColumn
120
+ }
121
+
122
+ @computed private get mapColumnSlug(): ColumnSlug {
123
+ return this.chartState.mapColumnSlug
124
+ }
125
+
126
+ @computed private get mapColumnInfo(): MapColumnInfo {
127
+ return this.chartState.mapColumnInfo
128
+ }
129
+
130
+ @computed get hasProjectedData(): boolean {
131
+ return this.mapColumnInfo.type !== "historical"
132
+ }
133
+
134
+ @computed private get targetTime(): number | undefined {
135
+ return this.chartState.targetTime
136
+ }
137
+
138
+ @computed private get bounds(): Bounds {
139
+ return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
140
+ }
141
+
142
+ @computed get choroplethData(): ChoroplethSeriesByName {
143
+ return this.chartState.seriesMap
144
+ }
145
+
146
+ base = createRef<SVGGElement>()
147
+ @action.bound onMapMouseOver(feature: GeoFeature): void {
148
+ if (feature.id !== undefined) {
149
+ const featureId = feature.id as string
150
+ this.mapConfig.hoverCountry = featureId
151
+ this.tooltipState.target = { featureId }
152
+ this.manager.logGrapherInteractionEvent?.(
153
+ "map_country_hover",
154
+ featureId
155
+ )
156
+ }
157
+ }
158
+
159
+ @action.bound onMapMouseMove(ev: React.MouseEvent): void {
160
+ const ref = this.manager?.base?.current
161
+ if (ref) {
162
+ this.tooltipState.position = getRelativeMouse(ref, ev)
163
+ }
164
+ }
165
+
166
+ @action.bound onMapMouseLeave(): void {
167
+ this.mapConfig.hoverCountry = undefined
168
+ this.tooltipState.target = null
169
+ }
170
+
171
+ @computed private get manager(): MapChartManager {
172
+ return this.chartState.manager
173
+ }
174
+
175
+ @computed get globeController(): GlobeController {
176
+ return this.manager.globeController ?? new GlobeController(this)
177
+ }
178
+
179
+ @computed get mapViewport(): MapViewport | undefined {
180
+ return this.manager.mapViewport
181
+ }
182
+
183
+ @computed get isFaceted(): boolean | undefined {
184
+ return this.manager.isFaceted
185
+ }
186
+
187
+ @computed get isMapSelectionEnabled(): boolean {
188
+ return !!this.manager.isMapSelectionEnabled
189
+ }
190
+
191
+ override componentWillUnmount(): void {
192
+ this.onMapMouseLeave()
193
+ this.onLegendMouseLeave()
194
+ document.removeEventListener("keydown", this.onDocumentKeyDown)
195
+ }
196
+
197
+ @action.bound onLegendMouseEnter(bracket: MapBracket): void {
198
+ this.manager.logGrapherInteractionEvent?.(
199
+ "map_legend_hover",
200
+ bracket.label
201
+ )
202
+ }
203
+
204
+ @action.bound onLegendMouseOver(bracket: MapBracket): void {
205
+ this.hoverBracket = bracket
206
+ }
207
+
208
+ @action.bound onLegendMouseLeave(): void {
209
+ this.hoverBracket = undefined
210
+ }
211
+
212
+ @computed get mapConfig(): MapConfig {
213
+ return this.chartState.mapConfig
214
+ }
215
+
216
+ @action.bound onRegionChange(value: MapRegionName): void {
217
+ this.mapConfig.region = value
218
+ }
219
+
220
+ @computed private get colorScale(): ColorScale {
221
+ return this.chartState.colorScale
222
+ }
223
+
224
+ @action.bound onDocumentKeyDown(e: KeyboardEvent): void {
225
+ // Hide the globe on hitting the Escape key
226
+ if (e.key === "Escape" && this.mapConfig.globe.isActive) {
227
+ this.globeController.hideGlobe()
228
+ this.globeController.resetGlobe()
229
+ this.mapConfig.region = MapRegionName.World
230
+ }
231
+ }
232
+
233
+ @computed get externalLegend(): HorizontalColorLegendManager | undefined {
234
+ const {
235
+ numericLegendData,
236
+ categoricalLegendData,
237
+ legendMaxWidth,
238
+ legendStyleConfig,
239
+ } = this
240
+
241
+ if (this.manager.showLegend) return undefined
242
+
243
+ return {
244
+ numericLegendData,
245
+ categoricalLegendData,
246
+ legendMaxWidth,
247
+ legendStyleConfig,
248
+ }
249
+ }
250
+
251
+ @computed private get disableIntroAnimation(): boolean {
252
+ // The intro animation transitions from a neutral color to the actual color.
253
+ // That doesn't work if a pattern is used to fill the country outlines,
254
+ // which is the case for projected data.
255
+ if (this.mapColumnInfo.type !== "historical") return true
256
+
257
+ return !!this.manager.disableIntroAnimation
258
+ }
259
+
260
+ override componentDidMount(): void {
261
+ if (!this.disableIntroAnimation) {
262
+ select(this.base.current)
263
+ .selectAll(`.${MAP_CHART_CLASSNAME} path`)
264
+ .attr("data-fill", function () {
265
+ return (this as SVGPathElement).getAttribute("fill")
266
+ })
267
+ .attr("fill", this.colorScale.noDataColor)
268
+ .transition()
269
+ .duration(500)
270
+ .ease(easeCubic)
271
+ .attr("fill", function () {
272
+ return (this as SVGPathElement).getAttribute("data-fill")
273
+ })
274
+ .attr("data-fill", function () {
275
+ return (this as SVGPathElement).getAttribute("fill")
276
+ })
277
+ }
278
+ exposeInstanceOnWindow(this)
279
+
280
+ document.addEventListener("keydown", this.onDocumentKeyDown)
281
+ }
282
+
283
+ @computed private get legendData(): ColorScaleBin[] {
284
+ return this.colorScale.legendBins.filter((bin) => !bin.isHidden)
285
+ }
286
+
287
+ /** The value of the currently hovered feature/country */
288
+ @computed private get hoverValue(): string | number | undefined {
289
+ if (!this.mapConfig.hoverCountry) return undefined
290
+
291
+ const series = this.choroplethData.get(this.mapConfig.hoverCountry)
292
+ if (!series) return "No data"
293
+
294
+ return series.value
295
+ }
296
+
297
+ private isHovered(featureId: string): boolean {
298
+ const { mapConfig, hoverBracket } = this
299
+ const { externalLegendHoverBin } = this.manager
300
+
301
+ // Check if a country is focused on the globe
302
+ if (mapConfig.globe.focusCountry === featureId) return true
303
+
304
+ // Check if a country is hovered
305
+ if (mapConfig.hoverCountry === featureId) return true
306
+
307
+ // Check if the legend bracket of a country is hovered
308
+ const series = this.choroplethData.get(featureId)
309
+ if (
310
+ hoverBracket?.contains(series?.value, {
311
+ isProjection: series?.isProjection,
312
+ })
313
+ )
314
+ return true
315
+
316
+ // Check if the external legend bracket of a country is hovered (used in faceted maps)
317
+ if (externalLegendHoverBin?.contains(series?.value)) return true
318
+
319
+ return false
320
+ }
321
+
322
+ isSelected(featureId: string): boolean {
323
+ return this.selectionArray.selectedSet.has(featureId)
324
+ }
325
+
326
+ getHoverState(featureId: string): InteractionState {
327
+ const isHovered = this.isHovered(featureId)
328
+ const isHoverModeActive = !!(
329
+ this.hoverBracket || this.manager.externalLegendHoverBin
330
+ )
331
+ return new InteractionState(isHovered, isHoverModeActive)
332
+ }
333
+
334
+ @computed get fontSize(): number {
335
+ return this.manager.fontSize ?? BASE_FONT_SIZE
336
+ }
337
+
338
+ @computed get choroplethMapBounds(): Bounds {
339
+ return this.bounds.padBottom(
340
+ this.legendHeight
341
+ ? this.legendHeight +
342
+ PADDING_BETWEEN_MAP_AND_LEGEND +
343
+ PADDING_BELOW_MAP_LEGEND
344
+ : 0
345
+ )
346
+ }
347
+
348
+ @computed private get region(): MapRegionName {
349
+ return this.mapConfig.region
350
+ }
351
+
352
+ @computed private get shouldAddProjectionPatternToLegendBins(): boolean {
353
+ return match(this.mapColumnInfo)
354
+ .with({ type: "historical" }, () => false)
355
+ .with({ type: "projected" }, () => true)
356
+ .with({ type: "historical+projected" }, (info) =>
357
+ // Only add a pattern to the legend bins if _all_ values are projections.
358
+ // If there is even a single non-projected (historical) value, the legend
359
+ // should use solid colors.
360
+ this.chartState.transformedTable
361
+ .get(info.slugForIsProjectionColumn)
362
+ .values.every((value) => value === true)
363
+ )
364
+ .exhaustive()
365
+ }
366
+
367
+ private maybeAddPatternRefToBin<Bin extends ColorScaleBin>(bin: Bin): Bin {
368
+ if (isNoDataBin(bin))
369
+ return new CategoricalBin({
370
+ ...bin.props,
371
+ patternRef: Patterns.noDataPattern,
372
+ }) as Bin
373
+
374
+ if (isProjectedDataBin(bin)) {
375
+ const patternRef = makeProjectedDataPatternId(
376
+ PROJECTED_DATA_LEGEND_COLOR,
377
+ { forLegend: true }
378
+ )
379
+ return new CategoricalBin({ ...bin.props, patternRef }) as Bin
380
+ }
381
+
382
+ if (this.shouldAddProjectionPatternToLegendBins) {
383
+ const patternRef = makeProjectedDataPatternId(bin.color, {
384
+ forLegend: true,
385
+ })
386
+ return (
387
+ bin instanceof CategoricalBin
388
+ ? new CategoricalBin({ ...bin.props, patternRef })
389
+ : new NumericBin({ ...bin.props, patternRef })
390
+ ) as Bin
391
+ }
392
+
393
+ return bin
394
+ }
395
+
396
+ @computed get numericLegendData(): ColorScaleBin[] {
397
+ const hasNoDataBin = this.legendData.some((bin) => isNoDataBin(bin))
398
+ if (this.hasCategoricalLegendData || !hasNoDataBin)
399
+ return this.legendData
400
+ .filter((bin) => isNumericBin(bin))
401
+ .map((bin) => this.maybeAddPatternRefToBin(bin))
402
+
403
+ const bins: ColorScaleBin[] = this.legendData
404
+ .filter((bin) => isNumericBin(bin) || isNoDataBin(bin))
405
+ .map((bin) => this.maybeAddPatternRefToBin(bin))
406
+
407
+ // Move the no-data bin from the end to the start
408
+ return [bins[bins.length - 1], ...bins.slice(0, -1)]
409
+ }
410
+
411
+ @computed private get numMembersPerCategoricalBinByIndex(): Map<
412
+ number,
413
+ number
414
+ > {
415
+ const { chartState, legendData } = this
416
+ return new Map(
417
+ legendData
418
+ .filter((bin) => isCategoricalBin(bin))
419
+ .map((bin) => {
420
+ const memberCount = chartState.series.filter((series) =>
421
+ bin.contains(series.value)
422
+ ).length
423
+ return [bin.index, memberCount]
424
+ })
425
+ )
426
+ }
427
+
428
+ @computed get categoricalLegendData(): CategoricalBin[] {
429
+ let categoricalLegendData = this.legendData
430
+ .filter((bin) => isCategoricalBin(bin))
431
+ .map((bin) => this.maybeAddPatternRefToBin(bin))
432
+
433
+ // Hide empty bins in thumbnails
434
+ if (
435
+ this.isStatic &&
436
+ this.manager.variant === GrapherVariant.Thumbnail
437
+ ) {
438
+ categoricalLegendData = categoricalLegendData.filter((bin) => {
439
+ const memberCount =
440
+ this.numMembersPerCategoricalBinByIndex.get(bin.index) ?? 0
441
+ return (
442
+ isNoDataBin(bin) ||
443
+ isProjectedDataBin(bin) ||
444
+ memberCount > 0
445
+ )
446
+ })
447
+ }
448
+
449
+ return categoricalLegendData
450
+ }
451
+
452
+ @computed private get hasCategoricalLegendData(): boolean {
453
+ return this.categoricalLegendData.length > 1
454
+ }
455
+
456
+ @computed get binColors(): string[] {
457
+ return this.legendData.map((bin) => bin.color)
458
+ }
459
+
460
+ @computed private get numericHoverBracket(): ColorScaleBin | undefined {
461
+ const { hoverBracket, hoverValue, numericLegendData } = this
462
+ const { externalLegendHoverBin } = this.manager
463
+
464
+ if (hoverBracket) return hoverBracket
465
+
466
+ if (hoverValue !== undefined)
467
+ return numericLegendData.find((bin) => bin.contains(hoverValue))
468
+
469
+ return externalLegendHoverBin
470
+ }
471
+
472
+ @computed private get categoricalHoverBracket():
473
+ | CategoricalBin
474
+ | undefined {
475
+ const { hoverBracket, hoverValue, categoricalLegendData } = this
476
+
477
+ if (hoverBracket && hoverBracket instanceof CategoricalBin)
478
+ return hoverBracket
479
+
480
+ if (hoverValue !== undefined)
481
+ return categoricalLegendData.find((bin) => bin.contains(hoverValue))
482
+
483
+ return undefined
484
+ }
485
+
486
+ getLegendBinState(bin: ColorScaleBin): LegendInteractionState {
487
+ if (!this.categoricalHoverBracket && !this.numericHoverBracket)
488
+ return LegendInteractionState.Default
489
+
490
+ // Check if this bin is being hovered
491
+ if (
492
+ this.categoricalHoverBracket &&
493
+ bin.equals(this.categoricalHoverBracket)
494
+ ) {
495
+ return LegendInteractionState.Focused
496
+ }
497
+ if (this.numericHoverBracket && bin.equals(this.numericHoverBracket)) {
498
+ return LegendInteractionState.Focused
499
+ }
500
+
501
+ return LegendInteractionState.Muted
502
+ }
503
+
504
+ legendStyleConfig: LegendStyleConfig = {
505
+ marker: {
506
+ default: { stroke: DEFAULT_STROKE_COLOR },
507
+ focused: {
508
+ stroke: HOVER_STROKE_COLOR,
509
+ strokeWidth: HOVER_STROKE_WIDTH,
510
+ },
511
+ },
512
+ }
513
+
514
+ @computed get legendMaxWidth(): number {
515
+ // it seems nice to have just a little bit of extra padding left and right
516
+ return this.bounds.width * MAP_LEGEND_MAX_WIDTH_RATIO
517
+ }
518
+
519
+ @computed get legendX(): number {
520
+ return this.bounds.x + (this.bounds.width - this.legendMaxWidth) / 2
521
+ }
522
+
523
+ @computed get legendHeight(): number {
524
+ return this.categoryLegendHeight + this.numericLegendHeight
525
+ }
526
+
527
+ @computed private get numericLegendHeight(): number {
528
+ return this.numericLegend ? this.numericLegend.height : 0
529
+ }
530
+
531
+ @computed private get categoryLegendHeight(): number {
532
+ return this.categoryLegend ? this.categoryLegend.height : 0
533
+ }
534
+
535
+ @computed private get categoryLegend():
536
+ | HorizontalCategoricalColorLegend
537
+ | undefined {
538
+ if (this.manager.isDisplayedAlongsideComplementaryTable)
539
+ return undefined
540
+ return this.manager.showLegend && this.categoricalLegendData.length > 1
541
+ ? new HorizontalCategoricalColorLegend({ manager: this })
542
+ : undefined
543
+ }
544
+
545
+ @computed private get numericLegend():
546
+ | HorizontalNumericColorLegend
547
+ | undefined {
548
+ if (this.manager.isDisplayedAlongsideComplementaryTable)
549
+ return undefined
550
+ return this.manager.showLegend && this.numericLegendData.length > 1
551
+ ? new HorizontalNumericColorLegend({ manager: this })
552
+ : undefined
553
+ }
554
+
555
+ @computed get categoryLegendY(): number {
556
+ if (!this.categoryLegend) return 0
557
+
558
+ return (
559
+ this.bounds.bottom -
560
+ this.categoryLegend.height -
561
+ PADDING_BELOW_MAP_LEGEND
562
+ )
563
+ }
564
+
565
+ @computed get legendAlign(): HorizontalAlign {
566
+ return HorizontalAlign.center
567
+ }
568
+
569
+ @computed get numericLegendY(): number {
570
+ if (!this.numericLegend) return 0
571
+ return (
572
+ this.bounds.bottom -
573
+ this.numericLegendHeight -
574
+ PADDING_BELOW_MAP_LEGEND -
575
+ // If present, the category legend is placed below the numeric legend
576
+ (this.categoryLegend
577
+ ? this.categoryLegendHeight + PADDING_BETWEEN_MAP_LEGENDS
578
+ : 0)
579
+ )
580
+ }
581
+
582
+ @computed get hoverColors(): Color[] | undefined {
583
+ if (!this.hoverBracket) return undefined
584
+ return [this.hoverBracket.color]
585
+ }
586
+
587
+ @computed get isStatic(): boolean {
588
+ return this.manager.isStatic ?? false
589
+ }
590
+
591
+ @computed private get renderUid(): number {
592
+ return guid()
593
+ }
594
+
595
+ @computed private get clipPath(): ClipPath {
596
+ return makeClipPath({
597
+ renderUid: this.renderUid,
598
+ box: this.choroplethMapBounds,
599
+ })
600
+ }
601
+
602
+ @computed get numericBinSize(): number {
603
+ return 0.625 * this.fontSize
604
+ }
605
+
606
+ renderMapLegend(): React.ReactElement {
607
+ const { numericLegend, categoryLegend } = this
608
+
609
+ return (
610
+ <>
611
+ {numericLegend && (
612
+ <HorizontalNumericColorLegend manager={this} />
613
+ )}
614
+ {categoryLegend && (
615
+ <HorizontalCategoricalColorLegend manager={this} />
616
+ )}
617
+ </>
618
+ )
619
+ }
620
+
621
+ renderMapOrGlobe({ clipping = true } = {}): React.ReactElement {
622
+ const mapOrGlobe = this.mapConfig.globe.isActive ? (
623
+ <ChoroplethGlobe manager={this} />
624
+ ) : (
625
+ <ChoroplethMap manager={this} />
626
+ )
627
+
628
+ if (!clipping) return mapOrGlobe
629
+
630
+ return (
631
+ <>
632
+ {this.clipPath.element}
633
+ <g clipPath={this.clipPath.id}>{mapOrGlobe}</g>
634
+ </>
635
+ )
636
+ }
637
+
638
+ renderStatic(): React.ReactElement {
639
+ // Clipping the chart area is only necessary when the map is
640
+ // zoomed in or we're showing the globe. If that isn't the case,
641
+ // then we don't add a clipping element since it introduces noise
642
+ // in SVG editing programs like Figma.
643
+ const clipping =
644
+ this.mapConfig.globe.isActive || this.region !== MapRegionName.World
645
+
646
+ return (
647
+ <>
648
+ {this.renderMapOrGlobe({ clipping })}
649
+ {this.renderMapLegend()}
650
+ </>
651
+ )
652
+ }
653
+
654
+ renderInteractive(): React.ReactElement {
655
+ const { tooltipState } = this
656
+
657
+ let sparklineWidth: number | undefined
658
+ if (this.manager.shouldPinTooltipToBottom) {
659
+ const windowWidth = window?.innerWidth ?? 240
660
+ sparklineWidth = Math.min(
661
+ GRAPHER_MAX_TOOLTIP_WIDTH,
662
+ windowWidth - 8
663
+ )
664
+ }
665
+
666
+ const tooltipCountry =
667
+ tooltipState.target?.featureId ??
668
+ // show a pinned-to-the-bottom tooltip when focused on a country
669
+ (this.manager.shouldPinTooltipToBottom
670
+ ? this.mapConfig.globe.focusCountry
671
+ : undefined)
672
+
673
+ return (
674
+ <g
675
+ ref={this.base}
676
+ className={MAP_CHART_CLASSNAME}
677
+ onMouseMove={this.onMapMouseMove}
678
+ >
679
+ {this.renderMapOrGlobe()}
680
+ {this.renderMapLegend()}
681
+ {tooltipCountry && (
682
+ <MapTooltip
683
+ mapColumnSlug={this.mapColumnSlug}
684
+ mapColumnInfo={this.mapColumnInfo}
685
+ entityName={tooltipCountry}
686
+ position={tooltipState.position}
687
+ fading={tooltipState.fading}
688
+ timeSeriesTable={this.chartState.inputTable}
689
+ formatValueForTooltip={
690
+ this.chartState.formatValueForTooltip
691
+ }
692
+ manager={this.manager}
693
+ lineColorScale={this.colorScale}
694
+ targetTime={this.targetTime}
695
+ targetTimes={this.manager.highlightedTimesInTooltip}
696
+ sparklineWidth={sparklineWidth}
697
+ dismissTooltip={action(() => {
698
+ this.mapConfig.hoverCountry = undefined
699
+ this.tooltipState.target = null
700
+ this.globeController.dismissCountryFocus()
701
+ })}
702
+ />
703
+ )}
704
+ </g>
705
+ )
706
+ }
707
+
708
+ override render(): React.ReactElement {
709
+ if (this.chartState.errorInfo.reason)
710
+ return (
711
+ <NoDataModal
712
+ manager={this.manager}
713
+ bounds={this.props.bounds}
714
+ message={this.chartState.errorInfo.reason}
715
+ />
716
+ )
717
+
718
+ return this.isStatic ? this.renderStatic() : this.renderInteractive()
719
+ }
720
+ }