@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,619 @@
1
+ import * as _ from "lodash-es"
2
+ import * as React from "react"
3
+ import { computed, action, observable, makeObservable } from "mobx"
4
+ import { observer } from "mobx-react"
5
+ import {
6
+ Bounds,
7
+ Time,
8
+ getRelativeMouse,
9
+ excludeUndefined,
10
+ makeIdForHumanConsumption,
11
+ guid,
12
+ exposeInstanceOnWindow,
13
+ } from "../../utils/index.js"
14
+ import { DualAxisComponent } from "../axis/AxisViews"
15
+ import { NoDataModal } from "../noDataModal/NoDataModal"
16
+ import {
17
+ VerticalColorLegend,
18
+ VerticalColorLegendManager,
19
+ } from "../legend/VerticalColorLegend"
20
+ import { TooltipFooterIcon } from "../tooltip/TooltipProps.js"
21
+ import {
22
+ Tooltip,
23
+ TooltipState,
24
+ TooltipTable,
25
+ makeTooltipRoundingNotice,
26
+ toTooltipTableColumns,
27
+ } from "../tooltip/Tooltip"
28
+ import {
29
+ BASE_FONT_SIZE,
30
+ DEFAULT_GRAPHER_BOUNDS,
31
+ } from "../core/GrapherConstants"
32
+ import { StackedBarChartState } from "./StackedBarChartState.js"
33
+ import {
34
+ BAR_OPACITY,
35
+ LEGEND_STYLE_FOR_STACKED_CHARTS,
36
+ StackedPoint,
37
+ StackedSeries,
38
+ } from "./StackedConstants"
39
+ import { LegendInteractionState } from "../legend/LegendInteractionState"
40
+ import { DualAxis, HorizontalAxis, VerticalAxis } from "../axis/Axis"
41
+ import { HorizontalAlign, SeriesName } from "../../types/index.js"
42
+ import { makeClipPath } from "../chart/ChartUtils"
43
+ import {
44
+ HorizontalCategoricalColorLegend,
45
+ HorizontalColorLegendManager,
46
+ } from "../legend/HorizontalColorLegends"
47
+ import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"
48
+ import { AxisConfig, AxisManager } from "../axis/AxisConfig.js"
49
+ import { easeLinear } from "d3-ease"
50
+ import { select, type BaseType, type Selection } from "d3-selection"
51
+ import { ChartInterface } from "../chart/ChartInterface"
52
+ import { ChartManager } from "../chart/ChartManager"
53
+ import { ChartComponentProps } from "../chart/ChartTypeMap.js"
54
+ import { StackedBars } from "./StackedBars"
55
+ import { getXAxisConfigDefaultsForStackedBar } from "./StackedUtils"
56
+
57
+ interface TickmarkPlacement {
58
+ time: number
59
+ text: string
60
+ bounds: Bounds
61
+ isHidden: boolean
62
+ }
63
+
64
+ export type StackedBarChartProps = ChartComponentProps<StackedBarChartState>
65
+
66
+ @observer
67
+ export class StackedBarChart
68
+ extends React.Component<StackedBarChartProps>
69
+ implements
70
+ ChartInterface,
71
+ AxisManager,
72
+ VerticalColorLegendManager,
73
+ HorizontalColorLegendManager
74
+ {
75
+ readonly minBarSpacing = 4
76
+
77
+ constructor(props: StackedBarChartProps) {
78
+ super(props)
79
+
80
+ makeObservable(this, {
81
+ hoverColor: observable,
82
+ hoveredTick: observable,
83
+ tooltipState: observable,
84
+ })
85
+ }
86
+
87
+ // currently hovered legend color
88
+ hoverColor: string | undefined = undefined
89
+ // currently hovered axis label
90
+ hoveredTick: TickmarkPlacement | undefined = undefined
91
+ // current hovered individual bar
92
+ tooltipState = new TooltipState<{
93
+ bar: StackedPoint<number>
94
+ series: StackedSeries<number>
95
+ }>()
96
+
97
+ legendStyleConfig = LEGEND_STYLE_FOR_STACKED_CHARTS
98
+
99
+ @computed get chartState(): StackedBarChartState {
100
+ return this.props.chartState
101
+ }
102
+
103
+ @computed private get manager(): ChartManager {
104
+ return this.chartState.manager
105
+ }
106
+
107
+ @computed private get bounds(): Bounds {
108
+ return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
109
+ }
110
+
111
+ @computed get isStatic(): boolean {
112
+ return this.manager.isStatic ?? false
113
+ }
114
+
115
+ @computed private get renderUid(): number {
116
+ return guid()
117
+ }
118
+
119
+ @computed get fontSize(): number {
120
+ return this.manager.fontSize ?? BASE_FONT_SIZE
121
+ }
122
+
123
+ @computed get detailsOrderedByReference(): string[] {
124
+ return this.manager.detailsOrderedByReference ?? []
125
+ }
126
+
127
+ @computed private get innerBounds(): Bounds {
128
+ return (
129
+ this.bounds
130
+ .padTop(this.paddingForLegendTop)
131
+ .padRight(this.paddingForLegendRight)
132
+ // top padding leaves room for tick labels
133
+ .padTop(6)
134
+ // bottom padding avoids axis labels to be cut off at some resolutions
135
+ .padBottom(2)
136
+ )
137
+ }
138
+
139
+ @computed private get dualAxis(): DualAxis {
140
+ const { horizontalAxisPart, verticalAxisPart } = this
141
+ return new DualAxis({
142
+ bounds: this.innerBounds,
143
+ horizontalAxis: horizontalAxisPart,
144
+ verticalAxis: verticalAxisPart,
145
+ comparisonLines: this.manager.comparisonLines,
146
+ })
147
+ }
148
+
149
+ @computed get yAxis(): VerticalAxis {
150
+ return this.dualAxis.verticalAxis
151
+ }
152
+
153
+ @computed get xAxis(): HorizontalAxis {
154
+ return this.dualAxis.horizontalAxis
155
+ }
156
+
157
+ @computed private get horizontalAxisPart(): HorizontalAxis {
158
+ return this.chartState.toHorizontalAxis(this.xAxisConfig)
159
+ }
160
+
161
+ @computed private get yAxisConfig(): AxisConfig {
162
+ const { yAxisConfig } = this.manager
163
+ const custom = { nice: true }
164
+ return new AxisConfig({ ...custom, ...yAxisConfig }, this)
165
+ }
166
+
167
+ @computed private get verticalAxisPart(): VerticalAxis {
168
+ return this.chartState.toVerticalAxis(this.yAxisConfig)
169
+ }
170
+
171
+ @computed private get xAxisConfig(): AxisConfig {
172
+ const { xAxisConfig } = this.manager
173
+ const defaults = getXAxisConfigDefaultsForStackedBar(this.chartState)
174
+ return new AxisConfig({ ...defaults, ...xAxisConfig }, this)
175
+ }
176
+
177
+ @computed
178
+ get allStackedPoints(): readonly StackedPoint<number>[] {
179
+ return this.stackedSeries.flatMap((series) => series.points)
180
+ }
181
+
182
+ @computed private get showHorizontalLegend(): boolean {
183
+ return !!(this.manager.isSemiNarrow || this.manager.isStaticAndSmall)
184
+ }
185
+
186
+ @computed get legendAlign(): HorizontalAlign {
187
+ return HorizontalAlign.left
188
+ }
189
+
190
+ @computed private get paddingForLegendRight(): number {
191
+ return this.showHorizontalLegend
192
+ ? 0
193
+ : this.sidebarWidth > 0
194
+ ? this.sidebarWidth + 20
195
+ : 0
196
+ }
197
+
198
+ @computed private get paddingForLegendTop(): number {
199
+ return this.showHorizontalLegend
200
+ ? this.horizontalColorLegend.height + 8
201
+ : 0
202
+ }
203
+
204
+ @computed private get hoveredSeriesNames(): SeriesName[] {
205
+ const { hoverColor, manager } = this
206
+ const { externalLegendHoverBin } = manager
207
+
208
+ const hoveredSeriesNames =
209
+ hoverColor === undefined
210
+ ? []
211
+ : _.uniq(
212
+ this.stackedSeries
213
+ .filter((g) => g.color === hoverColor)
214
+ .map((g) => g.seriesName)
215
+ )
216
+ if (externalLegendHoverBin) {
217
+ hoveredSeriesNames.push(
218
+ ...this.chartState.rawSeries
219
+ .map((g) => g.seriesName)
220
+ .filter((name) => externalLegendHoverBin.contains(name))
221
+ )
222
+ }
223
+
224
+ return hoveredSeriesNames
225
+ }
226
+
227
+ @computed get activeColors(): string[] {
228
+ const { hoveredSeriesNames = [], hoverColor } = this
229
+
230
+ const hoveredColors = this.stackedSeries
231
+ .filter((g) => hoveredSeriesNames.indexOf(g.seriesName) !== -1)
232
+ .map((g) => g.color)
233
+ const activeColors = _.uniq(
234
+ excludeUndefined([...hoveredColors, hoverColor])
235
+ )
236
+
237
+ return activeColors
238
+ }
239
+
240
+ getLegendBinState(bin: ColorScaleBin): LegendInteractionState {
241
+ const isActive = this.activeColors?.includes(bin.color)
242
+
243
+ if (this.activeColors.length === 0)
244
+ return LegendInteractionState.Default
245
+
246
+ return isActive
247
+ ? LegendInteractionState.Focused
248
+ : LegendInteractionState.Muted
249
+ }
250
+
251
+ @computed get categoricalLegendData(): CategoricalBin[] {
252
+ return this.stackedSeries
253
+ .map(
254
+ (series, index) =>
255
+ new CategoricalBin({
256
+ index,
257
+ value: series.seriesName,
258
+ label: series.seriesName,
259
+ color: series.color,
260
+ })
261
+ )
262
+ .toReversed() // Vertical legend orders things in the opposite direction we want
263
+ }
264
+
265
+ @computed get legendWidth(): number {
266
+ return this.showHorizontalLegend
267
+ ? this.bounds.width
268
+ : this.verticalColorLegend.width
269
+ }
270
+
271
+ @computed get maxLegendWidth(): number {
272
+ return this.showHorizontalLegend
273
+ ? this.bounds.width
274
+ : this.sidebarMaxWidth
275
+ }
276
+
277
+ @computed private get sidebarMaxWidth(): number {
278
+ return this.bounds.width / 5
279
+ }
280
+
281
+ @computed private get sidebarMinWidth(): number {
282
+ return 100
283
+ }
284
+
285
+ @computed private get showLegend(): boolean {
286
+ return (
287
+ !!this.manager.showLegend &&
288
+ !this.manager.isDisplayedAlongsideComplementaryTable
289
+ )
290
+ }
291
+
292
+ @computed private get sidebarWidth(): number {
293
+ if (!this.showLegend) return 0
294
+ const {
295
+ sidebarMinWidth,
296
+ sidebarMaxWidth,
297
+ verticalColorLegend: legendDimensions,
298
+ } = this
299
+ return Math.max(
300
+ Math.min(legendDimensions.width, sidebarMaxWidth),
301
+ sidebarMinWidth
302
+ )
303
+ }
304
+
305
+ @computed private get verticalColorLegend(): VerticalColorLegend {
306
+ return new VerticalColorLegend({ manager: this })
307
+ }
308
+
309
+ @computed
310
+ private get horizontalColorLegend(): HorizontalCategoricalColorLegend {
311
+ return new HorizontalCategoricalColorLegend({ manager: this })
312
+ }
313
+
314
+ @computed get externalLegend(): HorizontalColorLegendManager | undefined {
315
+ if (!this.showLegend) {
316
+ const categoricalLegendData = this.chartState.unstackedSeries
317
+ .map(
318
+ (series, index) =>
319
+ new CategoricalBin({
320
+ index,
321
+ value: series.seriesName,
322
+ label: series.seriesName,
323
+ color: series.color,
324
+ })
325
+ )
326
+ .toReversed()
327
+
328
+ return {
329
+ categoricalLegendData,
330
+ legendStyleConfig: this.legendStyleConfig,
331
+ }
332
+ }
333
+ return undefined
334
+ }
335
+
336
+ @computed private get tooltip(): React.ReactElement | undefined {
337
+ const {
338
+ tooltipState: { target, position, fading },
339
+ stackedSeries: series,
340
+ hoveredTick,
341
+ } = this
342
+ const { formatColumn } = this.chartState
343
+
344
+ const { bar: hoverBar, series: hoverSeries } = target ?? {}
345
+ let hoverTime: number
346
+ if (hoverBar !== undefined) {
347
+ hoverTime = hoverBar.position
348
+ } else if (hoveredTick !== undefined) {
349
+ hoverTime = hoveredTick.time
350
+ } else return
351
+
352
+ const title = formatColumn.formatTime(hoverTime)
353
+ const titleAnnotation = this.xAxis.label ? `(${this.xAxis.label})` : ""
354
+
355
+ const { displayUnit } = formatColumn
356
+
357
+ const totalValue = _.sum(
358
+ series.map(
359
+ ({ points }) =>
360
+ points.find((bar) => bar.position === hoverTime)?.value ?? 0
361
+ )
362
+ )
363
+
364
+ const roundingNotice = formatColumn.roundsToSignificantFigures
365
+ ? {
366
+ icon: TooltipFooterIcon.None,
367
+ text: makeTooltipRoundingNotice([
368
+ formatColumn.numSignificantFigures,
369
+ ]),
370
+ }
371
+ : undefined
372
+ const footer = excludeUndefined([roundingNotice])
373
+
374
+ const hoverPoints = series.map((series) => {
375
+ const point = series.points.find(
376
+ (bar) => bar.position === hoverTime
377
+ )
378
+ return {
379
+ seriesName: series.seriesName,
380
+ seriesColor: series.color,
381
+ point,
382
+ }
383
+ })
384
+ const [positivePoints, negativePoints] = _.partition(
385
+ hoverPoints,
386
+ ({ point }) => (point?.value ?? 0) >= 0
387
+ )
388
+ const sortedHoverPoints = [
389
+ ...positivePoints.toReversed(),
390
+ ...negativePoints,
391
+ ]
392
+
393
+ return (
394
+ <Tooltip
395
+ id={this.renderUid}
396
+ tooltipManager={this.manager}
397
+ x={position.x}
398
+ y={position.y}
399
+ style={{ maxWidth: "500px" }}
400
+ offsetX={20}
401
+ offsetY={-16}
402
+ title={title}
403
+ titleAnnotation={titleAnnotation}
404
+ subtitle={displayUnit}
405
+ subtitleFormat="unit"
406
+ footer={footer}
407
+ dissolve={fading}
408
+ dismiss={() => (this.tooltipState.target = null)}
409
+ >
410
+ <TooltipTable
411
+ columns={toTooltipTableColumns(formatColumn)}
412
+ totals={[totalValue]}
413
+ rows={sortedHoverPoints.map(
414
+ ({ point, seriesName: name, seriesColor }) => {
415
+ const focused = hoverSeries?.seriesName === name
416
+ const blurred = point?.fake ?? true
417
+ const values = [
418
+ point?.fake ? undefined : point?.value,
419
+ ]
420
+
421
+ const color = point?.color ?? seriesColor
422
+ const opacity = focused
423
+ ? BAR_OPACITY.FOCUS
424
+ : BAR_OPACITY.DEFAULT
425
+ const swatch = { color, opacity }
426
+
427
+ return { name, swatch, blurred, focused, values }
428
+ }
429
+ )}
430
+ />
431
+ </Tooltip>
432
+ )
433
+ }
434
+
435
+ @action.bound onLegendMouseOver(bin: ColorScaleBin): void {
436
+ this.hoverColor = bin.color
437
+ }
438
+
439
+ @action.bound onLegendMouseLeave(): void {
440
+ this.hoverColor = undefined
441
+ }
442
+
443
+ @action.bound onLabelMouseOver(tick: TickmarkPlacement): void {
444
+ this.hoveredTick = tick
445
+ }
446
+
447
+ @action.bound onLabelMouseLeave(): void {
448
+ this.hoveredTick = undefined
449
+ }
450
+
451
+ @action.bound onBarMouseOver(
452
+ bar: StackedPoint<Time>,
453
+ series: StackedSeries<Time>
454
+ ): void {
455
+ this.tooltipState.target = { bar, series }
456
+ }
457
+
458
+ @action.bound private onMouseMove(ev: React.MouseEvent): void {
459
+ const ref = this.manager.base?.current
460
+ if (ref) {
461
+ this.tooltipState.position = getRelativeMouse(ref, ev)
462
+ }
463
+ }
464
+
465
+ @action.bound onBarMouseLeave(): void {
466
+ this.tooltipState.target = null
467
+ }
468
+
469
+ renderLegend(): React.ReactElement | undefined {
470
+ const { showLegend, showHorizontalLegend } = this
471
+
472
+ if (!showLegend) return
473
+
474
+ return showHorizontalLegend ? (
475
+ <HorizontalCategoricalColorLegend manager={this} />
476
+ ) : (
477
+ <VerticalColorLegend manager={this} />
478
+ )
479
+ }
480
+
481
+ renderAxis(): React.ReactElement {
482
+ const { manager } = this
483
+
484
+ return (
485
+ <DualAxisComponent
486
+ dualAxis={this.dualAxis}
487
+ showTickMarks={true}
488
+ detailsMarker={manager.detailsMarkerInSvg}
489
+ backgroundColor={this.manager.backgroundColor}
490
+ />
491
+ )
492
+ }
493
+
494
+ renderBars(): React.ReactElement {
495
+ return (
496
+ <StackedBars
497
+ dualAxis={this.dualAxis}
498
+ series={this.stackedSeries}
499
+ formatColumn={this.chartState.formatColumn}
500
+ hoveredSeriesNames={this.hoveredSeriesNames}
501
+ hoveredBar={this.tooltipState.target?.bar}
502
+ onBarMouseOver={this.onBarMouseOver}
503
+ onBarMouseLeave={this.onBarMouseLeave}
504
+ />
505
+ )
506
+ }
507
+
508
+ renderStatic(): React.ReactElement {
509
+ return (
510
+ <>
511
+ {this.renderAxis()}
512
+ <g id={makeIdForHumanConsumption("bars")}>
513
+ {this.renderBars()}
514
+ </g>
515
+ {this.renderLegend()}
516
+ </>
517
+ )
518
+ }
519
+
520
+ renderInteractive(): React.ReactElement {
521
+ const { dualAxis, renderUid, bounds } = this
522
+ const { innerBounds } = dualAxis
523
+
524
+ const clipPath = makeClipPath({
525
+ renderUid: renderUid,
526
+ box: innerBounds,
527
+ })
528
+
529
+ return (
530
+ <g
531
+ className="StackedBarChart"
532
+ width={bounds.width}
533
+ height={bounds.height}
534
+ onMouseMove={this.onMouseMove}
535
+ >
536
+ {clipPath.element}
537
+ <rect
538
+ x={bounds.left}
539
+ y={bounds.top}
540
+ width={bounds.width}
541
+ height={bounds.height}
542
+ opacity={0}
543
+ fill="rgba(255,255,255,0)"
544
+ />
545
+ {this.renderAxis()}
546
+ <g clipPath={clipPath.id}>{this.renderBars()}</g>
547
+ {this.renderLegend()}
548
+ {this.tooltip}
549
+ </g>
550
+ )
551
+ }
552
+
553
+ override render(): React.ReactElement {
554
+ const { dualAxis, bounds } = this
555
+
556
+ if (this.chartState.errorInfo.reason)
557
+ return (
558
+ <g
559
+ className="StackedBarChart"
560
+ width={bounds.width}
561
+ height={bounds.height}
562
+ >
563
+ {this.renderAxis()}
564
+ <NoDataModal
565
+ manager={this.manager}
566
+ bounds={dualAxis.innerBounds}
567
+ message={this.chartState.errorInfo.reason}
568
+ />
569
+ </g>
570
+ )
571
+
572
+ return this.manager.isStatic
573
+ ? this.renderStatic()
574
+ : this.renderInteractive()
575
+ }
576
+
577
+ @computed get categoryLegendY(): number {
578
+ return this.bounds.top
579
+ }
580
+
581
+ @computed get legendY(): number {
582
+ return this.bounds.top
583
+ }
584
+
585
+ @computed get legendX(): number {
586
+ return this.showHorizontalLegend
587
+ ? this.bounds.left
588
+ : this.bounds.right - this.sidebarWidth
589
+ }
590
+
591
+ @computed
592
+ get stackedSeries(): readonly StackedSeries<number>[] {
593
+ return this.chartState.series
594
+ }
595
+
596
+ animSelection?: Selection<BaseType, unknown, SVGGElement | null, unknown>
597
+
598
+ base = React.createRef<SVGGElement>()
599
+ override componentDidMount(): void {
600
+ if (!this.manager.disableIntroAnimation) {
601
+ // Fancy intro animation
602
+ this.animSelection = select(this.base.current)
603
+ .selectAll("clipPath > rect")
604
+ .attr("width", 0)
605
+
606
+ this.animSelection
607
+ .transition()
608
+ .duration(800)
609
+ .ease(easeLinear)
610
+ .attr("width", this.bounds.width)
611
+ .on("end", () => this.forceUpdate()) // Important in case bounds changes during transition
612
+ }
613
+ exposeInstanceOnWindow(this)
614
+ }
615
+
616
+ override componentWillUnmount(): void {
617
+ if (this.animSelection) this.animSelection.interrupt()
618
+ }
619
+ }
@@ -0,0 +1,80 @@
1
+ import * as _ from "lodash-es"
2
+ import { computed, makeObservable } from "mobx"
3
+ import { AbstractStackedChartState } from "./AbstractStackedChartState.js"
4
+ import { ChartState } from "../chart/ChartInterface.js"
5
+ import { StackedSeries } from "./StackedConstants.js"
6
+ import { ColumnTypeMap } from "../../core-table/index.js"
7
+ import {
8
+ stackSeriesInBothDirections,
9
+ withMissingValuesAsZeroes,
10
+ } from "./StackedUtils.js"
11
+ import { ColorScaleManager } from "../color/ColorScale.js"
12
+ import {
13
+ ColorScaleConfigInterface,
14
+ ColorSchemeName,
15
+ } from "../../types/index.js"
16
+ import { ChartManager } from "../chart/ChartManager.js"
17
+
18
+ export class StackedBarChartState
19
+ extends AbstractStackedChartState
20
+ implements ChartState, ColorScaleManager
21
+ {
22
+ constructor(props: { manager: ChartManager }) {
23
+ super(props)
24
+ makeObservable(this)
25
+ }
26
+
27
+ shouldRunLinearInterpolation = false
28
+
29
+ defaultBaseColorScheme = ColorSchemeName.stackedAreaDefault
30
+
31
+ @computed
32
+ get unstackedSeriesWithMissingValuesAsZeroes(): StackedSeries<number>[] {
33
+ // TODO: remove once monthly data is supported (https://github.com/owid/owid-grapher/issues/2007)
34
+ const enforceUniformSpacing = !(
35
+ this.transformedTable.timeColumn instanceof ColumnTypeMap.Day
36
+ )
37
+
38
+ return withMissingValuesAsZeroes(this.unstackedSeries, {
39
+ enforceUniformSpacing,
40
+ })
41
+ }
42
+
43
+ @computed get series(): readonly StackedSeries<number>[] {
44
+ return stackSeriesInBothDirections(
45
+ this.unstackedSeriesWithMissingValuesAsZeroes
46
+ )
47
+ }
48
+
49
+ @computed get xValues(): number[] {
50
+ return _.uniq(
51
+ this.unstackedSeriesWithMissingValuesAsZeroes.flatMap((s) =>
52
+ s.points.map((p) => p.position)
53
+ )
54
+ )
55
+ }
56
+
57
+ /** Colour positive and negative values differently in stacked bar charts */
58
+ @computed get useValueBasedColorScheme(): boolean {
59
+ // Switched on externally, e.g. in a faceted chart
60
+ if (this.manager.useValueBasedColorScheme) return true
61
+
62
+ // Check if there is only one series and that series has both positive and negative values
63
+ return (
64
+ this.rawSeries.length === 1 &&
65
+ this.rawSeries[0].rows.some((row) => row.value < 0) &&
66
+ this.rawSeries[0].rows.some((row) => row.value > 0)
67
+ )
68
+ }
69
+
70
+ @computed get colorScaleConfig(): ColorScaleConfigInterface | undefined {
71
+ return this.manager.colorScale
72
+ }
73
+
74
+ @computed get yDomain(): [number, number] {
75
+ const yValues = this.allStackedPoints.map(
76
+ (point) => point.value + point.valueOffset
77
+ )
78
+ return [_.min([0, ...yValues]) ?? 0, _.max([0, ...yValues]) ?? 0]
79
+ }
80
+ }