@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,678 @@
1
+ import * as _ from "lodash-es"
2
+ import * as React from "react"
3
+ import * as R from "remeda"
4
+ import {
5
+ getRelativeMouse,
6
+ excludeUndefined,
7
+ isMobile,
8
+ Bounds,
9
+ guid,
10
+ exposeInstanceOnWindow,
11
+ } from "../../utils/index.js"
12
+ import { computed, action, observable, makeObservable } from "mobx"
13
+ import { SeriesName, SeriesStrategy } from "../../types/index.js"
14
+ import {
15
+ BASE_FONT_SIZE,
16
+ DEFAULT_GRAPHER_BOUNDS,
17
+ } from "../core/GrapherConstants"
18
+ import { observer } from "mobx-react"
19
+ import { DualAxisComponent } from "../axis/AxisViews"
20
+ import { DualAxis, HorizontalAxis, VerticalAxis } from "../axis/Axis"
21
+ import { LineLegend } from "../lineLegend/LineLegend"
22
+ import { NoDataModal } from "../noDataModal/NoDataModal"
23
+ import { TooltipFooterIcon } from "../tooltip/TooltipProps.js"
24
+ import {
25
+ Tooltip,
26
+ TooltipState,
27
+ TooltipTable,
28
+ makeTooltipRoundingNotice,
29
+ toTooltipTableColumns,
30
+ } from "../tooltip/Tooltip"
31
+ import { StackedAreaChartState } from "./StackedAreaChartState.js"
32
+ import { AREA_OPACITY, StackedSeries } from "./StackedConstants"
33
+ import {
34
+ makeClipPath,
35
+ isTargetOutsideElement,
36
+ getHoverStateForSeries,
37
+ } from "../chart/ChartUtils"
38
+ import { AxisConfig, AxisManager } from "../axis/AxisConfig.js"
39
+ import { LineLabelSeries } from "../lineLegend/LineLegendTypes"
40
+ import { easeLinear } from "d3-ease"
41
+ import { select, type BaseType, type Selection } from "d3-selection"
42
+ import { ChartInterface } from "../chart/ChartInterface"
43
+ import { ChartManager } from "../chart/ChartManager"
44
+ import { StackedAreas } from "./StackedAreas"
45
+ import { HorizontalColorLegendManager } from "../legend/HorizontalColorLegends"
46
+ import { CategoricalBin } from "../color/ColorScaleBin"
47
+ import { ChartComponentProps } from "../chart/ChartTypeMap.js"
48
+ import { InteractionState } from "../interaction/InteractionState"
49
+ import { resolveCollision } from "./StackedUtils"
50
+
51
+ const STACKED_AREA_CHART_CLASS_NAME = "StackedArea"
52
+
53
+ export type StackedAreaChartProps = ChartComponentProps<StackedAreaChartState>
54
+
55
+ @observer
56
+ export class StackedAreaChart
57
+ extends React.Component<StackedAreaChartProps>
58
+ implements ChartInterface, AxisManager
59
+ {
60
+ constructor(props: StackedAreaChartProps) {
61
+ super(props)
62
+
63
+ makeObservable<StackedAreaChart, "hoverTimer">(this, {
64
+ tooltipState: observable,
65
+ lineLegendHoveredSeriesName: observable,
66
+ hoverTimer: observable,
67
+ })
68
+ }
69
+
70
+ @computed get chartState(): StackedAreaChartState {
71
+ return this.props.chartState
72
+ }
73
+
74
+ @computed private get manager(): ChartManager {
75
+ return this.chartState.manager
76
+ }
77
+
78
+ @computed private get bounds(): Bounds {
79
+ return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
80
+ }
81
+
82
+ @computed private get isStatic(): boolean {
83
+ return this.manager.isStatic ?? false
84
+ }
85
+
86
+ @computed private get renderUid(): number {
87
+ return guid()
88
+ }
89
+
90
+ @computed get fontSize(): number {
91
+ return this.manager.fontSize ?? BASE_FONT_SIZE
92
+ }
93
+
94
+ @computed get detailsOrderedByReference(): string[] {
95
+ return this.manager.detailsOrderedByReference ?? []
96
+ }
97
+
98
+ @computed private get innerBounds(): Bounds {
99
+ return (
100
+ this.bounds
101
+ .padRight(this.paddingForLegendRight)
102
+ // top padding leaves room for tick labels
103
+ .padTop(6)
104
+ // bottom padding avoids axis labels to be cut off at some resolutions
105
+ .padBottom(2)
106
+ )
107
+ }
108
+
109
+ @computed private get dualAxis(): DualAxis {
110
+ const { horizontalAxisPart, verticalAxisPart } = this
111
+ return new DualAxis({
112
+ bounds: this.innerBounds,
113
+ horizontalAxis: horizontalAxisPart,
114
+ verticalAxis: verticalAxisPart,
115
+ comparisonLines: this.manager.comparisonLines,
116
+ })
117
+ }
118
+
119
+ @computed get yAxis(): VerticalAxis {
120
+ return this.dualAxis.verticalAxis
121
+ }
122
+
123
+ @computed get xAxis(): HorizontalAxis {
124
+ return this.dualAxis.horizontalAxis
125
+ }
126
+
127
+ @computed private get horizontalAxisPart(): HorizontalAxis {
128
+ return this.chartState.toHorizontalAxis(this.xAxisConfig)
129
+ }
130
+
131
+ @computed private get yAxisConfig(): AxisConfig {
132
+ const { yAxisConfig } = this.manager
133
+ const custom = { nice: true }
134
+ return new AxisConfig({ ...custom, ...yAxisConfig }, this)
135
+ }
136
+
137
+ @computed private get verticalAxisPart(): VerticalAxis {
138
+ return this.chartState.toVerticalAxis(this.yAxisConfig)
139
+ }
140
+
141
+ @computed private get xAxisConfig(): AxisConfig {
142
+ const { xAxisConfig } = this.manager
143
+ const custom = { hideGridlines: true }
144
+ return new AxisConfig({ ...custom, ...xAxisConfig }, this)
145
+ }
146
+
147
+ private hoverStateForSeries(
148
+ series: StackedSeries<number>
149
+ ): InteractionState {
150
+ return getHoverStateForSeries(series, {
151
+ isHoverModeActive: this.isHoverModeActive,
152
+ hoveredSeriesNames: this.hoveredSeriesNames,
153
+ })
154
+ }
155
+
156
+ @computed private get lineLegendSeries(): LineLabelSeries[] {
157
+ const isEntityStrategy =
158
+ this.chartState.seriesStrategy === SeriesStrategy.entity
159
+
160
+ return this.stackedSeries
161
+ .map((series, index) => ({
162
+ color: series.color,
163
+ seriesName: series.seriesName,
164
+ label:
165
+ isEntityStrategy && series.shortEntityName
166
+ ? series.shortEntityName
167
+ : series.seriesName,
168
+ yValue: this.chartState.midpoints[index],
169
+ isAllZeros: series.isAllZeros,
170
+ hover: this.hoverStateForSeries(series),
171
+ }))
172
+ .filter((series) => !series.isAllZeros)
173
+ .toReversed()
174
+ }
175
+
176
+ @computed private get maxLineLegendWidth(): number {
177
+ return Math.min(150, this.bounds.width / 3)
178
+ }
179
+
180
+ @computed private get showLegend(): boolean {
181
+ return (
182
+ !!this.manager.showLegend &&
183
+ !this.manager.isDisplayedAlongsideComplementaryTable
184
+ )
185
+ }
186
+
187
+ @computed private get lineLegendWidth(): number {
188
+ if (!this.showLegend) return 0
189
+
190
+ // only pass props that are required to calculate
191
+ // the width to avoid circular dependencies
192
+ return LineLegend.stableWidth({
193
+ series: this.lineLegendSeries,
194
+ maxWidth: this.maxLineLegendWidth,
195
+ fontSize: this.fontSize,
196
+ })
197
+ }
198
+
199
+ tooltipState = new TooltipState<{
200
+ index: number // time-index into points array
201
+ series?: SeriesName
202
+ }>({ fade: "immediate" })
203
+
204
+ @action.bound private onAreaMouseEnter(seriesName: SeriesName): void {
205
+ if (this.tooltipState.target) {
206
+ _.extend(this.tooltipState.target, { series: seriesName })
207
+ } else {
208
+ this.tooltipState.target = {
209
+ index: 0, // might be incorrect but will be updated immediately by the move event handler
210
+ series: seriesName,
211
+ }
212
+ }
213
+ }
214
+
215
+ @action.bound private onAreaMouseLeave(): void {
216
+ _.extend(this.tooltipState.target, { series: undefined })
217
+ }
218
+
219
+ lineLegendHoveredSeriesName: SeriesName | undefined = undefined
220
+ private hoverTimer: number | undefined = undefined
221
+
222
+ @computed private get paddingForLegendRight(): number {
223
+ return this.lineLegendWidth
224
+ }
225
+
226
+ @computed get externalLegend(): HorizontalColorLegendManager | undefined {
227
+ if (!this.showLegend) {
228
+ const categoricalLegendData = this.chartState.unstackedSeries
229
+ .map(
230
+ (series, index) =>
231
+ new CategoricalBin({
232
+ index,
233
+ value: series.seriesName,
234
+ label: series.seriesName,
235
+ color: series.color,
236
+ })
237
+ )
238
+ .toReversed()
239
+
240
+ return {
241
+ categoricalLegendData,
242
+ legendStyleConfig: {
243
+ marker: {
244
+ default: { opacity: AREA_OPACITY.DEFAULT },
245
+ focused: { opacity: AREA_OPACITY.FOCUS },
246
+ muted: { opacity: AREA_OPACITY.MUTE },
247
+ },
248
+ text: { muted: { opacity: AREA_OPACITY.MUTE } },
249
+ },
250
+ }
251
+ }
252
+ return undefined
253
+ }
254
+
255
+ @computed private get seriesSortedByImportance(): string[] {
256
+ return this.stackedSeries
257
+ .toSorted(
258
+ (
259
+ s1: StackedSeries<number>,
260
+ s2: StackedSeries<number>
261
+ ): number => {
262
+ const PREFER_S1 = -1
263
+ const PREFER_S2 = 1
264
+
265
+ if (!s1) return PREFER_S2
266
+ if (!s2) return PREFER_S1
267
+
268
+ const picked = resolveCollision(s1, s2)
269
+ if (picked === s1) return PREFER_S1
270
+ if (picked === s2) return PREFER_S2
271
+
272
+ return 0
273
+ }
274
+ )
275
+ .map((s) => s.seriesName)
276
+ }
277
+
278
+ @action.bound onLineLegendMouseOver(seriesName: SeriesName): void {
279
+ clearTimeout(this.hoverTimer)
280
+ this.lineLegendHoveredSeriesName = seriesName
281
+ }
282
+
283
+ @action.bound private clearLineLegendHover(): void {
284
+ this.lineLegendHoveredSeriesName = undefined
285
+ }
286
+
287
+ @action.bound onLineLegendMouseLeave(): void {
288
+ clearTimeout(this.hoverTimer)
289
+
290
+ // Wait before clearing selection in case the mouse is moving
291
+ // quickly over neighboring labels
292
+ this.hoverTimer = window.setTimeout(() => {
293
+ this.clearLineLegendHover()
294
+ }, 200)
295
+ }
296
+
297
+ @computed private get facetLegendHoveredSeriesName():
298
+ | SeriesName
299
+ | undefined {
300
+ const { externalLegendHoverBin } = this.manager
301
+ if (!externalLegendHoverBin) return undefined
302
+ // stacked area charts can't plot the same entity or column multiple times,
303
+ // so we just find the first series that matches the hovered legend item
304
+ const hoveredSeries = this.chartState.rawSeries.find((series) =>
305
+ externalLegendHoverBin.contains(series.seriesName)
306
+ )
307
+ return hoveredSeries?.seriesName
308
+ }
309
+
310
+ @computed private get hoveredSeriesName(): SeriesName | undefined {
311
+ return (
312
+ // if the chart area is hovered
313
+ this.tooltipState.target?.series ??
314
+ // if the line legend is hovered
315
+ this.lineLegendHoveredSeriesName ??
316
+ // if the facet legend is hovered
317
+ this.facetLegendHoveredSeriesName
318
+ )
319
+ }
320
+
321
+ @computed private get isHoverModeActive(): boolean {
322
+ return (
323
+ !!this.hoveredSeriesName ||
324
+ // if the external legend is hovered, we want to mute
325
+ // all non-hovered series even if the chart doesn't plot
326
+ // the currently hovered series
327
+ !!this.manager.externalLegendHoverBin
328
+ )
329
+ }
330
+
331
+ @computed private get hoveredSeriesNames(): string[] {
332
+ return this.hoveredSeriesName ? [this.hoveredSeriesName] : []
333
+ }
334
+
335
+ @action.bound private onCursorMove(
336
+ ev: React.MouseEvent<SVGGElement> | React.TouchEvent<SVGElement>
337
+ ): void {
338
+ const ref = this.base.current,
339
+ parentRef = this.manager.base?.current
340
+
341
+ // the tooltip's origin needs to be in the parent's coordinates
342
+ if (parentRef) {
343
+ this.tooltipState.position = getRelativeMouse(parentRef, ev)
344
+ }
345
+
346
+ if (!ref) return undefined
347
+
348
+ const { stackedSeries: series } = this
349
+ const mouse = getRelativeMouse(ref, ev.nativeEvent)
350
+ const boxPadding = isMobile() ? 44 : 25
351
+
352
+ // expand the box width, so it's easier to see the tooltip for the first & last timepoints
353
+ const boundedBox = this.dualAxis.innerBounds.expand({
354
+ left: boxPadding,
355
+ right: boxPadding,
356
+ })
357
+
358
+ let hoveredIndex
359
+ if (boundedBox.contains(mouse)) {
360
+ const invertedX = this.dualAxis.horizontalAxis.invert(mouse.x)
361
+ const closestPoint = _.minBy(series[0].points, (d) =>
362
+ Math.abs(d.position - invertedX)
363
+ )
364
+ if (closestPoint) {
365
+ const index = series[0].points.indexOf(closestPoint)
366
+ hoveredIndex = index
367
+ }
368
+ }
369
+ this.tooltipState.target =
370
+ hoveredIndex === undefined
371
+ ? null
372
+ : {
373
+ index: hoveredIndex,
374
+ series: this.tooltipState.target?.series,
375
+ }
376
+ }
377
+
378
+ @action.bound private dismissTooltip(): void {
379
+ this.tooltipState.target = null
380
+ }
381
+
382
+ @action.bound private onCursorLeave(): void {
383
+ if (!this.manager.shouldPinTooltipToBottom) {
384
+ this.dismissTooltip()
385
+ }
386
+ this.lineLegendHoveredSeriesName = undefined
387
+ }
388
+
389
+ @computed private get activeXVerticalLine():
390
+ | React.ReactElement
391
+ | undefined {
392
+ const { dualAxis, stackedSeries: series } = this
393
+ const { horizontalAxis, verticalAxis } = dualAxis
394
+ const hoveredPointIndex = this.tooltipState.target?.index
395
+ if (hoveredPointIndex === undefined) return undefined
396
+
397
+ const xPoint = series[0].points[hoveredPointIndex]
398
+ if (xPoint === undefined) return undefined
399
+
400
+ return (
401
+ // disable pointer events to avoid interfering with enter/leave tracking of areas
402
+ <g className="hoverIndicator" style={{ pointerEvents: "none" }}>
403
+ {series.map((series) => {
404
+ const point = series.points[hoveredPointIndex]
405
+ if (!point || point.fake || point.value === 0) return null
406
+ return (
407
+ <circle
408
+ key={series.seriesName}
409
+ cx={horizontalAxis.place(point.position)}
410
+ cy={verticalAxis.place(
411
+ point.value + point.valueOffset
412
+ )}
413
+ r={2}
414
+ fill={series.color}
415
+ />
416
+ )
417
+ })}
418
+ <line
419
+ x1={horizontalAxis.place(xPoint.position)}
420
+ y1={verticalAxis.range[0]}
421
+ x2={horizontalAxis.place(xPoint.position)}
422
+ y2={verticalAxis.range[1]}
423
+ stroke="rgba(180,180,180,.4)"
424
+ />
425
+ </g>
426
+ )
427
+ }
428
+
429
+ @computed private get tooltipId(): number {
430
+ return this.renderUid
431
+ }
432
+
433
+ @computed private get isTooltipActive(): boolean {
434
+ return this.manager.tooltip?.get()?.id === this.tooltipId
435
+ }
436
+
437
+ @computed private get tooltip(): React.ReactElement | undefined {
438
+ const { target, position, fading } = this.tooltipState
439
+ if (!target) return undefined
440
+
441
+ // Grab the first value to get the year from
442
+ const { stackedSeries: series } = this
443
+ const hoveredPointIndex = target.index
444
+ const bottomSeriesPoint = series[0].points[hoveredPointIndex]
445
+ if (!bottomSeriesPoint) return undefined
446
+
447
+ const formatColumn = this.chartState.formatColumn,
448
+ formattedTime = formatColumn.formatTime(bottomSeriesPoint.position),
449
+ { displayUnit } = formatColumn
450
+
451
+ const title = formattedTime
452
+ const titleAnnotation = this.xAxis.label ? `(${this.xAxis.label})` : ""
453
+
454
+ const lastStackedPoint = R.last(series)!.points[hoveredPointIndex]
455
+ if (!lastStackedPoint) return undefined
456
+ const totalValue = lastStackedPoint.value + lastStackedPoint.valueOffset
457
+
458
+ const roundingNotice = formatColumn.roundsToSignificantFigures
459
+ ? {
460
+ icon: TooltipFooterIcon.None,
461
+ text: makeTooltipRoundingNotice([
462
+ formatColumn.numSignificantFigures,
463
+ ]),
464
+ }
465
+ : undefined
466
+ const footer = excludeUndefined([roundingNotice])
467
+
468
+ return (
469
+ <Tooltip
470
+ id={this.tooltipId}
471
+ tooltipManager={this.manager}
472
+ x={position.x}
473
+ y={position.y}
474
+ offsetY={-16}
475
+ offsetX={20}
476
+ offsetXDirection="left"
477
+ style={{ maxWidth: "50%" }}
478
+ title={title}
479
+ titleAnnotation={titleAnnotation}
480
+ subtitle={displayUnit}
481
+ subtitleFormat="unit"
482
+ footer={footer}
483
+ dissolve={fading}
484
+ dismiss={this.dismissTooltip}
485
+ >
486
+ <TooltipTable
487
+ columns={toTooltipTableColumns(formatColumn)}
488
+ totals={[totalValue]}
489
+ rows={series.toReversed().map((series) => {
490
+ const { seriesName: name, color, points } = series
491
+ const point = points[hoveredPointIndex]
492
+ const focused = name === target.series
493
+ const values = [point?.fake ? undefined : point?.value]
494
+ const opacity = focused
495
+ ? AREA_OPACITY.FOCUS
496
+ : AREA_OPACITY.DEFAULT
497
+ const swatch = { color, opacity }
498
+
499
+ return {
500
+ name,
501
+ swatch,
502
+ focused,
503
+ values,
504
+ }
505
+ })}
506
+ />
507
+ </Tooltip>
508
+ )
509
+ }
510
+
511
+ @action.bound onDocumentClick(e: MouseEvent): void {
512
+ // only dismiss the tooltip if the click is outside of the chart area
513
+ // and outside of the chart areas of neighbouring facets
514
+ const chartContainer = this.manager.base?.current
515
+ if (!chartContainer) return
516
+ const chartAreas: Element[] = Array.from(
517
+ chartContainer.getElementsByClassName(STACKED_AREA_CHART_CLASS_NAME)
518
+ )
519
+ const isTargetOutsideChartAreas = chartAreas.every((chartArea) =>
520
+ isTargetOutsideElement(e.target!, chartArea)
521
+ )
522
+ if (isTargetOutsideChartAreas) {
523
+ this.dismissTooltip()
524
+ }
525
+ }
526
+
527
+ animSelection?: Selection<BaseType, unknown, SVGGElement | null, unknown>
528
+
529
+ base = React.createRef<SVGGElement>()
530
+ override componentDidMount(): void {
531
+ document.addEventListener("click", this.onDocumentClick, {
532
+ capture: true,
533
+ })
534
+
535
+ if (!this.manager.disableIntroAnimation) {
536
+ // Fancy intro animation
537
+ this.animSelection = select(this.base.current)
538
+ .selectAll("clipPath > rect")
539
+ .attr("width", 0)
540
+
541
+ this.animSelection
542
+ .transition()
543
+ .duration(800)
544
+ .ease(easeLinear)
545
+ .attr("width", this.bounds.width)
546
+ .on("end", () => this.forceUpdate()) // Important in case bounds changes during transition
547
+ }
548
+ exposeInstanceOnWindow(this)
549
+ }
550
+
551
+ override componentWillUnmount(): void {
552
+ document.removeEventListener("click", this.onDocumentClick, {
553
+ capture: true,
554
+ })
555
+
556
+ if (this.animSelection) this.animSelection.interrupt()
557
+ }
558
+
559
+ renderAxis(): React.ReactElement {
560
+ const { manager } = this
561
+ return (
562
+ <DualAxisComponent
563
+ dualAxis={this.dualAxis}
564
+ showTickMarks={true}
565
+ detailsMarker={manager.detailsMarkerInSvg}
566
+ backgroundColor={this.manager.backgroundColor}
567
+ />
568
+ )
569
+ }
570
+
571
+ renderLegend(): React.ReactElement | undefined {
572
+ if (!this.showLegend) return
573
+ return (
574
+ <LineLegend
575
+ series={this.lineLegendSeries}
576
+ yAxis={this.yAxis}
577
+ x={this.lineLegendX}
578
+ yRange={this.lineLegendY}
579
+ maxWidth={this.maxLineLegendWidth}
580
+ fontSize={this.fontSize}
581
+ seriesNamesSortedByImportance={this.seriesSortedByImportance}
582
+ isStatic={this.isStatic}
583
+ onMouseOver={this.onLineLegendMouseOver}
584
+ onMouseLeave={this.onLineLegendMouseLeave}
585
+ />
586
+ )
587
+ }
588
+
589
+ renderStatic(): React.ReactElement {
590
+ return (
591
+ <>
592
+ {this.renderAxis()}
593
+ {this.renderLegend()}
594
+ <StackedAreas
595
+ dualAxis={this.dualAxis}
596
+ seriesArr={this.stackedSeries}
597
+ hoveredSeriesName={this.hoveredSeriesName}
598
+ />
599
+ </>
600
+ )
601
+ }
602
+
603
+ renderInteractive(): React.ReactElement {
604
+ const { bounds, dualAxis, renderUid, stackedSeries: series } = this
605
+
606
+ const clipPath = makeClipPath({
607
+ renderUid,
608
+ box: {
609
+ ...bounds,
610
+ height: bounds.height * 2,
611
+ x: dualAxis.innerBounds.x,
612
+ },
613
+ })
614
+
615
+ return (
616
+ <g
617
+ ref={this.base}
618
+ className={STACKED_AREA_CHART_CLASS_NAME}
619
+ onMouseLeave={this.onCursorLeave}
620
+ onTouchEnd={this.onCursorLeave}
621
+ onTouchCancel={this.onCursorLeave}
622
+ onMouseMove={this.onCursorMove}
623
+ onTouchStart={this.onCursorMove}
624
+ onTouchMove={this.onCursorMove}
625
+ >
626
+ {clipPath.element}
627
+ <rect {...this.bounds.toProps()} fillOpacity="0">
628
+ {/* This <rect> ensures that the parent <g> is big enough such that we get mouse hover events for the
629
+ whole charting area, including the axis, the entity labels, and the whitespace next to them.
630
+ We need these to be able to show the tooltip for the first/last year even if the mouse is outside the charting area. */}
631
+ </rect>
632
+ {this.renderAxis()}
633
+ <g clipPath={clipPath.id}>
634
+ {this.renderLegend()}
635
+ <StackedAreas
636
+ dualAxis={dualAxis}
637
+ seriesArr={series}
638
+ hoveredSeriesName={this.hoveredSeriesName}
639
+ onAreaMouseEnter={this.onAreaMouseEnter}
640
+ onAreaMouseLeave={this.onAreaMouseLeave}
641
+ />
642
+ </g>
643
+ {this.isTooltipActive && this.activeXVerticalLine}
644
+ {this.tooltip}
645
+ </g>
646
+ )
647
+ }
648
+
649
+ override render(): React.ReactElement {
650
+ if (this.chartState.errorInfo.reason)
651
+ return (
652
+ <g>
653
+ {this.renderAxis()}
654
+ <NoDataModal
655
+ manager={this.manager}
656
+ bounds={this.dualAxis.bounds}
657
+ message={this.chartState.errorInfo.reason}
658
+ />
659
+ </g>
660
+ )
661
+
662
+ return this.manager.isStatic
663
+ ? this.renderStatic()
664
+ : this.renderInteractive()
665
+ }
666
+
667
+ @computed private get lineLegendX(): number {
668
+ return this.showLegend ? this.bounds.right - this.lineLegendWidth : 0
669
+ }
670
+
671
+ @computed private get lineLegendY(): [number, number] {
672
+ return [this.bounds.top, this.bounds.bottom]
673
+ }
674
+
675
+ @computed private get stackedSeries(): readonly StackedSeries<number>[] {
676
+ return this.chartState.series
677
+ }
678
+ }
@@ -0,0 +1,34 @@
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 { stackSeries, withMissingValuesAsZeroes } from "./StackedUtils.js"
7
+ import { ChartManager } from "../chart/ChartManager.js"
8
+
9
+ export class StackedAreaChartState
10
+ extends AbstractStackedChartState
11
+ implements ChartState
12
+ {
13
+ constructor(props: { manager: ChartManager }) {
14
+ super(props)
15
+ makeObservable(this)
16
+ }
17
+
18
+ shouldRunLinearInterpolation = true
19
+
20
+ @computed get useValueBasedColorScheme(): boolean {
21
+ return false
22
+ }
23
+
24
+ @computed get series(): readonly StackedSeries<number>[] {
25
+ return stackSeries(withMissingValuesAsZeroes(this.unstackedSeries))
26
+ }
27
+
28
+ @computed get yDomain(): [number, number] {
29
+ const yValues = this.allStackedPoints.map(
30
+ (point) => point.value + point.valueOffset
31
+ )
32
+ return [0, _.max(yValues) ?? 0]
33
+ }
34
+ }