@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,728 @@
1
+ import * as _ from "lodash-es"
2
+ import React from "react"
3
+ import { select } from "d3-selection"
4
+ import {
5
+ exposeInstanceOnWindow,
6
+ Bounds,
7
+ Time,
8
+ HorizontalAlign,
9
+ AxisAlign,
10
+ makeIdForHumanConsumption,
11
+ dyFromAlign,
12
+ } from "../../utils/index.js"
13
+ import { computed, makeObservable } from "mobx"
14
+ import { observer } from "mobx-react"
15
+ import { ScaleType, VerticalAlign } from "../../types/index.js"
16
+ import {
17
+ BASE_FONT_SIZE,
18
+ DEFAULT_GRAPHER_BOUNDS,
19
+ GRAPHER_FONT_SCALE_12,
20
+ GRAPHER_AREA_OPACITY_DEFAULT,
21
+ GRAPHER_OPACITY_MUTE,
22
+ GRAPHER_AREA_OPACITY_MUTE,
23
+ } from "../core/GrapherConstants"
24
+ import { NoDataModal } from "../noDataModal/NoDataModal"
25
+ import { HorizontalAxisZeroLine } from "../axis/AxisViews"
26
+ import { AxisConfig, AxisManager } from "../axis/AxisConfig"
27
+ import { ChartInterface } from "../chart/ChartInterface"
28
+ import {
29
+ BAR_SPACING_FACTOR,
30
+ DiscreteBarChartManager,
31
+ DiscreteBarSeries,
32
+ FontSettings,
33
+ PlacedDiscreteBarSeries,
34
+ SizedDiscreteBarSeries,
35
+ } from "./DiscreteBarChartConstants"
36
+ import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"
37
+ import {
38
+ HorizontalColorLegendManager,
39
+ HorizontalNumericColorLegend,
40
+ } from "../legend/HorizontalColorLegends"
41
+ import { DiscreteBarChartState } from "./DiscreteBarChartState"
42
+ import { ChartComponentProps } from "../chart/ChartTypeMap.js"
43
+ import {
44
+ makeProjectedDataPatternId,
45
+ enrichSeriesWithLabels,
46
+ } from "./DiscreteBarChartHelpers"
47
+ import { OwidTable } from "../../core-table/index.js"
48
+ import { HorizontalAxis } from "../axis/Axis"
49
+ import { GRAPHER_DARK_TEXT } from "../color/ColorConstants"
50
+ import type { BaseType, Selection } from "d3-selection"
51
+ import { NUMERIC_LEGEND_STYLE } from "../lineCharts/LineChartConstants"
52
+
53
+ const DEFAULT_PROJECTED_DATA_COLOR_IN_LEGEND = "#787878"
54
+
55
+ /** The gap between the entity label and the bar */
56
+ const GAP__ENTITY_LABEL__BAR = 5
57
+
58
+ /** The gap between the the entity label and negative value label */
59
+ const GAP__ENTITY_LABEL__VALUE_LABEL = 10
60
+
61
+ /** The vertical padding between the entity label and the annotation */
62
+ const ANNOTATION_PADDING = 2
63
+
64
+ export interface Label {
65
+ valueString: string
66
+ timeString: string
67
+ width: number
68
+ }
69
+
70
+ export type DiscreteBarChartProps = ChartComponentProps<DiscreteBarChartState>
71
+
72
+ @observer
73
+ export class DiscreteBarChart
74
+ extends React.Component<DiscreteBarChartProps>
75
+ implements ChartInterface, AxisManager, HorizontalColorLegendManager
76
+ {
77
+ base = React.createRef<SVGGElement>()
78
+
79
+ constructor(props: DiscreteBarChartProps) {
80
+ super(props)
81
+ makeObservable(this)
82
+ }
83
+
84
+ @computed get chartState(): DiscreteBarChartState {
85
+ return this.props.chartState
86
+ }
87
+
88
+ @computed private get manager(): DiscreteBarChartManager {
89
+ return this.chartState.manager
90
+ }
91
+
92
+ @computed private get bounds(): Bounds {
93
+ return (this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS).padRight(10)
94
+ }
95
+
96
+ @computed private get targetTime(): Time | undefined {
97
+ return this.manager.endTime
98
+ }
99
+
100
+ @computed private get legendPadding(): number {
101
+ return 0.5 * this.legendHeight
102
+ }
103
+
104
+ @computed get fontSize(): number {
105
+ return this.manager.fontSize ?? BASE_FONT_SIZE
106
+ }
107
+
108
+ @computed private get barCount(): number {
109
+ return this.series.length
110
+ }
111
+
112
+ @computed private get labelFontSize(): number {
113
+ const availableHeight = this.bounds.height / this.barCount
114
+ return Math.min(
115
+ GRAPHER_FONT_SCALE_12 * this.fontSize,
116
+ 1.1 * availableHeight
117
+ )
118
+ }
119
+
120
+ @computed private get entityLabelStyle(): FontSettings {
121
+ return {
122
+ fontSize: this.labelFontSize,
123
+ fontWeight: 700,
124
+ lineHeight: 1,
125
+ }
126
+ }
127
+
128
+ @computed private get entityAnnotationStyle(): FontSettings {
129
+ return {
130
+ fontSize: this.labelFontSize * 0.9,
131
+ fontWeight: 300,
132
+ lineHeight: 1,
133
+ }
134
+ }
135
+
136
+ @computed get sizedSeries(): SizedDiscreteBarSeries[] {
137
+ return enrichSeriesWithLabels({
138
+ series: this.series,
139
+ availableHeightPerSeries: this.bounds.height / this.barCount,
140
+ minLabelWidth: 0.3 * this.bounds.width,
141
+ maxLabelWidth: 0.66 * this.bounds.width,
142
+ fontSettings: this.entityLabelStyle,
143
+ annotationFontSettings: this.entityAnnotationStyle,
144
+ })
145
+ }
146
+
147
+ @computed private get valueLabelStyle(): FontSettings {
148
+ return { fontSize: this.labelFontSize, fontWeight: 400, lineHeight: 1 }
149
+ }
150
+
151
+ @computed private get hasPositive(): boolean {
152
+ return this.series.some((d) => d.value >= 0)
153
+ }
154
+
155
+ @computed private get hasNegative(): boolean {
156
+ return this.series.some((d) => d.value < 0)
157
+ }
158
+
159
+ // The amount of space we need to allocate for bar end labels on the right
160
+ @computed private get rightValueLabelsWidth(): number {
161
+ if (!this.hasPositive) return 0
162
+
163
+ const labelsWidths = this.series
164
+ .filter((series) => series.value >= 0)
165
+ .map((series) => this.formatValue(series).width)
166
+
167
+ return _.max(labelsWidths) ?? 0
168
+ }
169
+
170
+ @computed private get x0(): number {
171
+ return 0
172
+ }
173
+
174
+ // Now we can work out the main x axis scale
175
+ @computed private get xDomainDefault(): [number, number] {
176
+ const allValues = this.series.map((d) => d.value)
177
+ return [
178
+ Math.min(this.x0, _.min(allValues) as number),
179
+ Math.max(this.x0, _.max(allValues) as number),
180
+ ]
181
+ }
182
+
183
+ @computed private get xRange(): [number, number] {
184
+ return this.innerBounds.xRange()
185
+ }
186
+
187
+ // NB: y-axis settings are used for the horizontal axis in DiscreteBarChart
188
+ @computed private get yAxisConfig(): AxisConfig {
189
+ return new AxisConfig(
190
+ {
191
+ // if we have a single-value x axis, we want to have the vertical axis
192
+ // on the left of the chart
193
+ singleValueAxisPointAlign: AxisAlign.start,
194
+ ...this.manager.yAxisConfig,
195
+ },
196
+ this
197
+ )
198
+ }
199
+
200
+ @computed get yAxis(): HorizontalAxis {
201
+ // NB: We use the user's YAxis options here to make the XAxis
202
+ const axis = this.yAxisConfig.toHorizontalAxis()
203
+ axis.updateDomainPreservingUserSettings(this.xDomainDefault)
204
+
205
+ axis.scaleType = ScaleType.linear
206
+ axis.formatColumn = this.chartState.formatColumn
207
+ axis.range = this.xRange
208
+ axis.label = ""
209
+ return axis
210
+ }
211
+
212
+ /**
213
+ * The maximum width needed for labels positioned on the left side of the chart.
214
+ *
215
+ * For positive values, returns the width of entity labels and annotations.
216
+ * For negative values, returns the entity label width, annotation width, value label width
217
+ * and the padding between them.
218
+ */
219
+ @computed private get leftLabelsWidth(): number {
220
+ const labelWidths = this.sizedSeries.map((series) => {
221
+ const labelWidth = series.label?.width ?? 0
222
+ const annotationWidth = series.annotationTextWrap?.width ?? 0
223
+
224
+ // Use the maximum width between label and annotation
225
+ const textWidth = Math.max(labelWidth, annotationWidth)
226
+
227
+ if (series.value < 0) {
228
+ const valueWidth = this.formatValue(series).width
229
+ return textWidth + valueWidth + GAP__ENTITY_LABEL__VALUE_LABEL
230
+ } else {
231
+ return textWidth
232
+ }
233
+ })
234
+
235
+ return _.max(labelWidths) ?? 0
236
+ }
237
+
238
+ @computed private get innerBounds(): Bounds {
239
+ return this.bounds
240
+ .padTop(
241
+ this.showColorLegend
242
+ ? this.legendHeight + this.legendPadding
243
+ : 0
244
+ )
245
+ .padLeft(this.leftLabelsWidth)
246
+ .padRight(this.rightValueLabelsWidth)
247
+ }
248
+
249
+ /** The total height of the series, i.e. the height of the bar + the white space around it */
250
+ @computed private get seriesHeight(): number {
251
+ return this.innerBounds.height / this.barCount
252
+ }
253
+
254
+ @computed private get barSpacing(): number {
255
+ return this.seriesHeight * BAR_SPACING_FACTOR
256
+ }
257
+
258
+ @computed private get barHeight(): number {
259
+ const totalWhiteSpace = this.barCount * this.barSpacing
260
+ return (this.innerBounds.height - totalWhiteSpace) / this.barCount
261
+ }
262
+
263
+ @computed private get barPlacements(): { x: number; width: number }[] {
264
+ const { series, yAxis } = this
265
+ return series.map((d) => {
266
+ const isNegative = d.value < 0
267
+ const barX = isNegative
268
+ ? yAxis.place(d.value)
269
+ : yAxis.place(this.x0)
270
+ const barWidth = isNegative
271
+ ? yAxis.place(this.x0) - barX
272
+ : yAxis.place(d.value) - barX
273
+
274
+ return { x: barX, width: barWidth }
275
+ })
276
+ }
277
+
278
+ @computed private get barWidths(): number[] {
279
+ return this.barPlacements.map((b) => b.width)
280
+ }
281
+
282
+ @computed private get placedSeries(): PlacedDiscreteBarSeries[] {
283
+ const yOffset =
284
+ this.innerBounds.top + this.barHeight / 2 + this.barSpacing / 2
285
+ return this.sizedSeries.map((series, index) => {
286
+ const barY = yOffset + index * (this.barHeight + this.barSpacing)
287
+ const isNegative = series.value < 0
288
+ const barX = isNegative
289
+ ? this.yAxis.place(series.value)
290
+ : this.yAxis.place(this.x0)
291
+ const barWidth = isNegative
292
+ ? this.yAxis.place(this.x0) - barX
293
+ : this.yAxis.place(series.value) - barX
294
+ const label = this.formatValue(series)
295
+
296
+ const entityLabelX = isNegative
297
+ ? barX - label.width - GAP__ENTITY_LABEL__VALUE_LABEL
298
+ : barX - GAP__ENTITY_LABEL__BAR
299
+ const valueLabelX =
300
+ this.yAxis.place(series.value) +
301
+ (isNegative ? -GAP__ENTITY_LABEL__BAR : GAP__ENTITY_LABEL__BAR)
302
+
303
+ const annotationHeight = series.annotationTextWrap
304
+ ? ANNOTATION_PADDING + series.annotationTextWrap.height
305
+ : 0
306
+ const totalLabelHeight = series.label.height + annotationHeight
307
+
308
+ const entityLabelY = barY - totalLabelHeight / 2
309
+ const annotationY = series.annotationTextWrap
310
+ ? entityLabelY + series.label.height + ANNOTATION_PADDING
311
+ : undefined
312
+
313
+ return {
314
+ ...series,
315
+ barX,
316
+ barY,
317
+ barWidth,
318
+ entityLabelX,
319
+ entityLabelY,
320
+ annotationY,
321
+ valueLabelX,
322
+ }
323
+ })
324
+ }
325
+
326
+ override componentDidMount(): void {
327
+ exposeInstanceOnWindow(this)
328
+ if (!this.manager.disableIntroAnimation) {
329
+ this.d3Bars().attr("width", 0)
330
+ this.animateBarWidth()
331
+ }
332
+ }
333
+
334
+ override componentDidUpdate(): void {
335
+ // Animating the bar width after a render ensures there's no race condition, where the
336
+ // initial animation (in override componentDidMount) did override the now-changed bar width in
337
+ // some cases. Updating the animation with the updated bar widths fixes that.
338
+ if (!this.manager.disableIntroAnimation) this.animateBarWidth()
339
+ }
340
+
341
+ private d3Bars(): Selection<
342
+ BaseType,
343
+ unknown,
344
+ SVGGElement | null,
345
+ unknown
346
+ > {
347
+ return select(this.base.current).selectAll("g.bar > rect")
348
+ }
349
+
350
+ private animateBarWidth(): void {
351
+ this.d3Bars()
352
+ .transition()
353
+ .attr("width", (_, i) => this.barWidths[i])
354
+ }
355
+
356
+ formatValue(series: DiscreteBarSeries): Label {
357
+ const { yColumn } = series
358
+
359
+ const showYearLabels =
360
+ this.manager.showYearLabels || series.time !== this.targetTime
361
+ const valueString = yColumn.formatValueShort(series.value)
362
+ let timeString = ""
363
+ if (showYearLabels) {
364
+ const { timeColumn } = this.chartState.transformedTable
365
+ const preposition = OwidTable.getPreposition(timeColumn)
366
+ timeString = ` ${preposition} ${timeColumn.formatTime(series.time)}`
367
+ }
368
+
369
+ const labelBounds = Bounds.forText(
370
+ valueString + timeString,
371
+ this.valueLabelStyle
372
+ )
373
+
374
+ return {
375
+ valueString,
376
+ timeString,
377
+ width: labelBounds.width,
378
+ }
379
+ }
380
+
381
+ private renderDefs(): React.ReactElement | void {
382
+ const projections = this.series.filter(
383
+ (series) => series.yColumn.isProjection
384
+ )
385
+ const uniqProjections = _.uniqBy(projections, (series) => series.color)
386
+ if (projections.length === 0) return
387
+
388
+ return (
389
+ <defs>
390
+ {/* passed to the legend as pattern for the projected data legend item */}
391
+ <StripedProjectedDataPattern
392
+ patternId={makeProjectedDataPatternId(
393
+ this.projectedDataColorInLegend
394
+ )}
395
+ color={this.projectedDataColorInLegend}
396
+ />
397
+ {/* make a pattern for every series with a unique color */}
398
+ {uniqProjections.map((series) => (
399
+ <StripedProjectedDataPattern
400
+ key={series.color}
401
+ patternId={makeProjectedDataPatternId(series.color)}
402
+ color={series.color}
403
+ />
404
+ ))}
405
+ </defs>
406
+ )
407
+ }
408
+
409
+ private renderEntityLabels(): React.ReactElement {
410
+ return (
411
+ <g id={makeIdForHumanConsumption("entity-labels")}>
412
+ {this.placedSeries.map((series) => {
413
+ return (
414
+ series.label && (
415
+ <React.Fragment key={series.seriesName}>
416
+ {series.label.renderSVG(
417
+ series.entityLabelX,
418
+ series.entityLabelY,
419
+ {
420
+ textProps: {
421
+ fill: "#555",
422
+ textAnchor: "end",
423
+ opacity: series.focus.background
424
+ ? GRAPHER_OPACITY_MUTE
425
+ : 1,
426
+ },
427
+ }
428
+ )}
429
+ </React.Fragment>
430
+ )
431
+ )
432
+ })}
433
+ </g>
434
+ )
435
+ }
436
+
437
+ private renderEntityAnnotations(): React.ReactElement | null {
438
+ const hasAnnotations = this.placedSeries.some(
439
+ (series) =>
440
+ series.annotationTextWrap && series.annotationY !== undefined
441
+ )
442
+ if (!hasAnnotations) return null
443
+
444
+ return (
445
+ <g id={makeIdForHumanConsumption("entity-annotations")}>
446
+ {this.placedSeries.map((series) => {
447
+ if (!series.annotationTextWrap || !series.annotationY)
448
+ return null
449
+
450
+ return (
451
+ <React.Fragment key={`${series.seriesName}-annotation`}>
452
+ {series.annotationTextWrap.renderSVG(
453
+ series.entityLabelX,
454
+ series.annotationY,
455
+ {
456
+ textProps: {
457
+ fill: "#333",
458
+ textAnchor: "end",
459
+ opacity: series.focus.background
460
+ ? GRAPHER_OPACITY_MUTE
461
+ : 1,
462
+ },
463
+ }
464
+ )}
465
+ </React.Fragment>
466
+ )
467
+ })}
468
+ </g>
469
+ )
470
+ }
471
+
472
+ private renderValueLabels(): React.ReactElement {
473
+ return (
474
+ <g id={makeIdForHumanConsumption("value-labels")}>
475
+ {this.placedSeries.map((series) => {
476
+ const formattedLabel = this.formatValue(series)
477
+ return (
478
+ <text
479
+ key={series.seriesName}
480
+ x={0}
481
+ y={0}
482
+ transform={`translate(${series.valueLabelX}, ${series.barY})`}
483
+ fill={GRAPHER_DARK_TEXT}
484
+ dy={dyFromAlign(VerticalAlign.middle)}
485
+ textAnchor={series.value < 0 ? "end" : "start"}
486
+ opacity={
487
+ series.focus.background
488
+ ? GRAPHER_OPACITY_MUTE
489
+ : 1
490
+ }
491
+ {...this.valueLabelStyle}
492
+ >
493
+ {formattedLabel.valueString}
494
+ <tspan fill="#999">
495
+ {formattedLabel.timeString}
496
+ </tspan>
497
+ </text>
498
+ )
499
+ })}
500
+ </g>
501
+ )
502
+ }
503
+
504
+ private renderBars(): React.ReactElement {
505
+ return (
506
+ <g id={makeIdForHumanConsumption("bars")}>
507
+ {this.placedSeries.map((series) => {
508
+ const barColor = series.yColumn.isProjection
509
+ ? `url(#${makeProjectedDataPatternId(series.color)})`
510
+ : series.color
511
+
512
+ // Using transforms for positioning to enable better (subpixel) transitions
513
+ // Width transitions don't work well on iOS Safari – they get interrupted and
514
+ // it appears very slow. Also be careful with negative bar charts.
515
+ return (
516
+ <rect
517
+ id={makeIdForHumanConsumption(series.seriesName)}
518
+ key={series.seriesName}
519
+ x={0}
520
+ y={0}
521
+ transform={`translate(${series.barX}, ${series.barY - this.barHeight / 2})`}
522
+ width={series.barWidth}
523
+ height={this.barHeight}
524
+ fill={barColor}
525
+ opacity={
526
+ series.focus.background
527
+ ? GRAPHER_AREA_OPACITY_MUTE
528
+ : GRAPHER_AREA_OPACITY_DEFAULT
529
+ }
530
+ style={{ transition: "height 200ms ease" }}
531
+ />
532
+ )
533
+ })}
534
+ </g>
535
+ )
536
+ }
537
+
538
+ private renderChartArea(): React.ReactElement {
539
+ return (
540
+ <>
541
+ {this.renderDefs()}
542
+ {this.showColorLegend && (
543
+ <HorizontalNumericColorLegend manager={this} />
544
+ )}
545
+ <HorizontalAxisZeroLine
546
+ horizontalAxis={this.yAxis}
547
+ bounds={this.innerBounds}
548
+ strokeWidth={0.5}
549
+ // if the chart doesn't have negative values, then we
550
+ // move the zero line a little to the left to avoid
551
+ // overlap with the bars
552
+ align={
553
+ this.hasNegative
554
+ ? HorizontalAlign.center
555
+ : HorizontalAlign.right
556
+ }
557
+ />
558
+ {this.renderBars()}
559
+ {this.renderValueLabels()}
560
+ {this.renderEntityLabels()}
561
+ {this.renderEntityAnnotations()}
562
+ </>
563
+ )
564
+ }
565
+
566
+ override render(): React.ReactElement {
567
+ if (this.chartState.errorInfo.reason)
568
+ return (
569
+ <NoDataModal
570
+ manager={this.manager}
571
+ bounds={this.bounds}
572
+ message={this.chartState.errorInfo.reason}
573
+ />
574
+ )
575
+
576
+ return this.manager.isStatic ? (
577
+ this.renderChartArea()
578
+ ) : (
579
+ <g
580
+ ref={this.base}
581
+ id={makeIdForHumanConsumption("discrete-bar-chart")}
582
+ className="DiscreteBarChart"
583
+ >
584
+ {this.renderChartArea()}
585
+ </g>
586
+ )
587
+ }
588
+
589
+ // Color legend props
590
+
591
+ @computed private get hasColorLegend(): boolean {
592
+ return this.chartState.hasColorScale || this.chartState.hasProjectedData
593
+ }
594
+
595
+ @computed private get showColorLegend(): boolean {
596
+ return (
597
+ this.hasColorLegend &&
598
+ !!this.manager.showLegend &&
599
+ !this.manager.isDisplayedAlongsideComplementaryTable
600
+ )
601
+ }
602
+
603
+ @computed get legendX(): number {
604
+ return this.bounds.x
605
+ }
606
+
607
+ @computed get legendMaxWidth(): number {
608
+ return this.bounds.width
609
+ }
610
+
611
+ @computed get legendAlign(): HorizontalAlign {
612
+ return HorizontalAlign.center
613
+ }
614
+
615
+ // TODO just pass colorScale to legend and let it figure it out?
616
+ @computed get numericLegendData(): ColorScaleBin[] {
617
+ const legendBins = this.chartState.colorScale.legendBins.slice()
618
+
619
+ // Show a "Projected data" legend item with a striped pattern if appropriate
620
+ if (this.chartState.hasProjectedData) {
621
+ legendBins.push(
622
+ new CategoricalBin({
623
+ color: this.projectedDataColorInLegend,
624
+ label: "Projected data",
625
+ index: 0,
626
+ value: "projected",
627
+ patternRef: makeProjectedDataPatternId(
628
+ this.projectedDataColorInLegend
629
+ ),
630
+ })
631
+ )
632
+ }
633
+
634
+ // Move CategoricalBins to end
635
+ return _.sortBy(legendBins, (bin) => bin instanceof CategoricalBin)
636
+ }
637
+
638
+ @computed private get projectedDataColorInLegend(): string {
639
+ // if a single color is in use, use that color in the legend
640
+ if (_.uniqBy(this.series, "color").length === 1)
641
+ return this.series[0].color
642
+ return DEFAULT_PROJECTED_DATA_COLOR_IN_LEGEND
643
+ }
644
+
645
+ // Used when the bars are colored by a numeric scale
646
+ numericLegendStyleConfig = NUMERIC_LEGEND_STYLE
647
+
648
+ @computed get externalLegend(): HorizontalColorLegendManager | undefined {
649
+ if (this.hasColorLegend) {
650
+ return {
651
+ numericLegendData: this.numericLegendData,
652
+ numericLegendStyleConfig: this.numericLegendStyleConfig,
653
+ }
654
+ }
655
+ return undefined
656
+ }
657
+
658
+ @computed get numericBinSize(): number {
659
+ return 0.625 * this.fontSize
660
+ }
661
+
662
+ legendTickSize = 1
663
+
664
+ @computed private get numericLegend():
665
+ | HorizontalNumericColorLegend
666
+ | undefined {
667
+ return this.manager.showLegend
668
+ ? new HorizontalNumericColorLegend({ manager: this })
669
+ : undefined
670
+ }
671
+
672
+ @computed get numericLegendY(): number {
673
+ return this.bounds.top
674
+ }
675
+
676
+ @computed get legendTitle(): string | undefined {
677
+ return this.chartState.hasColorScale
678
+ ? this.chartState.colorScale.legendDescription
679
+ : undefined
680
+ }
681
+
682
+ @computed get legendHeight(): number {
683
+ return this.numericLegend?.height ?? 0
684
+ }
685
+
686
+ // End of color legend props
687
+
688
+ @computed private get series(): DiscreteBarSeries[] {
689
+ return this.chartState.series
690
+ }
691
+ }
692
+
693
+ function StripedProjectedDataPattern({
694
+ patternId,
695
+ color,
696
+ opacity = 0.5,
697
+ size = 7,
698
+ strokeWidth = 10,
699
+ }: {
700
+ patternId: string
701
+ color: string
702
+ opacity?: number
703
+ size?: number
704
+ strokeWidth?: number
705
+ }): React.ReactElement {
706
+ return (
707
+ <pattern
708
+ id={patternId}
709
+ patternUnits="userSpaceOnUse"
710
+ width={size}
711
+ height={size}
712
+ patternTransform="rotate(45)"
713
+ >
714
+ {/* semi-transparent background */}
715
+ <rect width={size} height={size} fill={color} opacity={opacity} />
716
+
717
+ {/* stripes */}
718
+ <line
719
+ x1="0"
720
+ y1="0"
721
+ x2="0"
722
+ y2={size}
723
+ stroke={color}
724
+ strokeWidth={strokeWidth}
725
+ />
726
+ </pattern>
727
+ )
728
+ }