@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,84 @@
1
+ # Binning Strategies
2
+
3
+ Grapher supports several automatic binning strategies, and can also automatically choose the best strategy to use based on data.
4
+ One key input into choosing a suiting strategy is the (log10) magnitude difference, i.e. $\log_{10}(maxValue) - \log_{10}(minValue)$.
5
+ For example, the magnitude difference between 4 and 400 is 2, because $4 \cdot 10^{\mathbf 2} = 400$.
6
+
7
+ In general, if we have a high magnitude difference, we want to use a logarithmic binning strategy, and if we have a low one we want to use an equal-sized binning strategy.
8
+ We only compute the magnitude difference based on positive values, and don't take the lowest and highest values directly, but rather some low and high quantiles.
9
+
10
+ ```mermaid
11
+ flowchart TD
12
+ A -->|small magnitude diff| E
13
+ S --> E[equalSizeBins]
14
+ S(Binning Strategy) --> A[auto]
15
+ S --> L[logarithmic]
16
+ A -->|large magnitude diff| L
17
+
18
+ E --> E1(Compute min, max value based on quantiles)
19
+ E1 --> E2(Find fitting, nice step size that produces a decent number of bins)
20
+ E2 -->|e.g. 10| E3(Compute bins; e.g. 0, 10, 20, 30, 40)
21
+
22
+ L --> L1(Compute min, max value based on quantiles)
23
+ L1 --> L2(Decide specific strategy based on magnitude difference)
24
+ L2 -->|log-1-2-5| L3(Compute bins; e.g. 0, 10, 20, 50, 100)
25
+ L2 -->|log-1-3| L3
26
+ L2 -->|log-1-10| L3
27
+ ```
28
+
29
+ ## Finding min & max values
30
+
31
+ To find the min and max values for binning, we use low and high quantiles instead of the raw min and max values.
32
+ This naturally removes outliers and will produce open-ended bins more often.
33
+
34
+ Min & max values can also be overridden manually in the admin.
35
+
36
+ Note that min & max values need to be non-zero positive numbers for log strategies, but can be any number for equal-size strategies.
37
+
38
+ ## Equal-size strategy
39
+
40
+ For the equal-size strategy, we are differentiating between four different strategies:
41
+
42
+ - `equalSizeBins-normal` (default): creates 5-9 bins
43
+ - `equalSizeBins-few-bins`: creates fewer bins than that
44
+ - `equalSizeBins-many-bins`: creates more bins than that
45
+ - `equalSizeBins-percent`: creates bins of size 10% (0-10%, 10-20%, ...)
46
+
47
+ Note that `equalSizeBins-percent` is chosen automatically when we detect that the data is a percentage that's roughly in the 0-100% range.
48
+
49
+ Once we have resolved the strategy to use, we can then proceed to pick the step size to use. This process is based on a list of "known good" step sizes, which we choose in such a way that we arrive at a reasonable number of bins that is within the target range of bins.
50
+
51
+ ## Logarithmic strategy
52
+
53
+ For logarithmic binning, we also differentiate between several strategies:
54
+
55
+ - `log-auto`: automatically chooses the best log binning strategy based on data, useful for when you want to force using a log strategy
56
+ - `log-1-2-5`: follows the 1, 2, 5, 10, 20, ... pattern
57
+ - `log-1-3`: follows the 1, 3, 10, 30, 100, ... pattern
58
+ - `log-1-10`: follows the 1, 10, 100, ... pattern
59
+
60
+ After picking out one of these strategies (either manually or automatically), the log strategy then produces bins such that they fill the range between `minValue` and `maxValue`.
61
+
62
+ ## Midpoints & midpoint modes
63
+
64
+ Some of our charts also have natural midpoints, where we want to create a diverging color scale around the midpoint.
65
+ The most common natural midpoint is 0.
66
+
67
+ We have a bunch of different midpoint modes:
68
+
69
+ - `undefined` (automatic): chooses `symmetric` if there are values on both sides of the midpoint, otherwise chooses `none`
70
+ - `none`: disregards the midpoint
71
+ - `symmetric`: creates bins around the midpoint that are fully symmetric, i.e. there's the same number of bins on both sides, and they have the same distance from the midpoint
72
+ - example: `-20, -10, -5, 0, 5, 10, 20`
73
+ - `same-num-bins`: creates (roughly) the same number of bins on both sides, but creates them independently, without regard to the distance from the midpoint
74
+ - example: `-10, -5, -2, 0, 10, 20, 50`
75
+ - `asymmetric`: like `symmetric`, but then prunes any bins that are not below `minValue` or above `maxValue`
76
+ - example: `-10, -5, 0, 5, 10, 20`
77
+
78
+ ### NO integration with diverging color schemes
79
+
80
+ Note that currently, midpoints are not integrated with color scales.
81
+ This means that modes other than `symmetric` will not pick "good/bad" colors from a _diverging color scheme_ for the bins on both sides of the midpoint.
82
+ `symmetric` mode supports this, by virtue of it picking the same number of bins on both sides of the midpoint.
83
+
84
+ This is a feature that's clearly relevant, and it shouldn't be too hard to implement this in the future.
@@ -0,0 +1,31 @@
1
+ import { DualAxis } from "../axis/Axis"
2
+ import {
3
+ Color,
4
+ ComparisonLineConfig,
5
+ VerticalComparisonLineConfig,
6
+ } from "../../types/index.js"
7
+ import { VerticalComparisonLine } from "./VerticalComparisonLine"
8
+ import { CustomComparisonLine } from "./CustomComparisonLine"
9
+ import { isValidVerticalComparisonLineConfig } from "./ComparisonLineHelpers"
10
+
11
+ export interface ComparisonLineProps<LineConfig extends ComparisonLineConfig> {
12
+ dualAxis: DualAxis
13
+ comparisonLine: LineConfig
14
+ backgroundColor?: Color
15
+ }
16
+
17
+ export const ComparisonLine = <LineConfig extends ComparisonLineConfig>(
18
+ props: ComparisonLineProps<LineConfig>
19
+ ) => {
20
+ if (isVerticalComparisonLineProps(props)) {
21
+ return <VerticalComparisonLine {...props} />
22
+ } else {
23
+ return <CustomComparisonLine {...props} />
24
+ }
25
+ }
26
+
27
+ function isVerticalComparisonLineProps(
28
+ props: ComparisonLineProps<ComparisonLineConfig>
29
+ ): props is ComparisonLineProps<VerticalComparisonLineConfig> {
30
+ return isValidVerticalComparisonLineConfig(props.comparisonLine)
31
+ }
@@ -0,0 +1,11 @@
1
+ export const COMPARISON_LINE_STYLE = {
2
+ opacity: 0.9,
3
+ fill: "none",
4
+ stroke: "#ccc",
5
+ strokeDasharray: "2 2",
6
+ }
7
+
8
+ export const COMPARISON_LINE_LABEL_STYLE = {
9
+ fill: "#999",
10
+ opacity: 0.9,
11
+ }
@@ -0,0 +1,60 @@
1
+ import Formula from "fparser"
2
+ import { scaleLinear, scaleLog } from "d3-scale"
3
+ import { ScaleType } from "../../types/index.js"
4
+
5
+ export function generateComparisonLinePoints(
6
+ lineFunction: string = "x",
7
+ xScaleDomain: [number, number],
8
+ yScaleDomain: [number, number],
9
+ xScaleType: ScaleType,
10
+ yScaleType: ScaleType
11
+ ): [number, number][] {
12
+ const formula = parseEquation(lineFunction)
13
+ const yFunc = (x: number): number | undefined =>
14
+ evalFormula(formula, { x }, undefined)
15
+
16
+ // Construct control data by running the equation across sample points
17
+ const numPoints = 500
18
+
19
+ const scaleFunction = xScaleType === ScaleType.log ? scaleLog : scaleLinear
20
+ const scale = scaleFunction().domain(xScaleDomain).range([0, numPoints])
21
+
22
+ const controlData: Array<[number, number]> = []
23
+ for (let i = 0; i < numPoints; i++) {
24
+ const x = scale.invert(i)
25
+ const y = yFunc(x)
26
+
27
+ if (y === undefined || Number.isNaN(x) || Number.isNaN(y)) continue
28
+ if (xScaleType === ScaleType.log && x <= 0) continue
29
+ if (yScaleType === ScaleType.log && y <= 0) continue
30
+ if (y > yScaleDomain[1]) continue
31
+ controlData.push([x, y])
32
+ }
33
+
34
+ return controlData
35
+ }
36
+
37
+ export function evalFormula<D>(
38
+ expr: Formula | undefined,
39
+ context: Record<string, number>,
40
+ defaultOnError: D
41
+ ): number | D {
42
+ if (expr === undefined) return defaultOnError
43
+ try {
44
+ return expr.evaluate(context) as number
45
+ } catch {
46
+ return defaultOnError
47
+ }
48
+ }
49
+
50
+ export function parseEquation(equation: string): Formula | undefined {
51
+ try {
52
+ const formula = new Formula(equation)
53
+ formula.ln = Math.log
54
+ formula.e = Math.E
55
+ return formula
56
+ } catch (e) {
57
+ console.error(e)
58
+ return undefined
59
+ }
60
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ ComparisonLineConfig,
3
+ VerticalComparisonLineConfig,
4
+ } from "../../types/index.js"
5
+
6
+ export function isValidVerticalComparisonLineConfig(
7
+ lineConfig: ComparisonLineConfig
8
+ ): lineConfig is VerticalComparisonLineConfig {
9
+ return "xEquals" in lineConfig && lineConfig.xEquals !== undefined
10
+ }
@@ -0,0 +1,159 @@
1
+ import * as React from "react"
2
+ import { computed, makeObservable } from "mobx"
3
+ import { observer } from "mobx-react"
4
+ import { line as d3_line, curveLinear } from "d3-shape"
5
+ import {
6
+ guid,
7
+ PointVector,
8
+ makeIdForHumanConsumption,
9
+ } from "../../utils/index.js"
10
+ import { CustomComparisonLineConfig } from "../../types/index.js"
11
+ import { generateComparisonLinePoints } from "./ComparisonLineGenerator"
12
+ import { Halo } from "../../components/index.js"
13
+ import { GRAPHER_TEXT_OUTLINE_FACTOR } from "../core/GrapherConstants"
14
+ import { ClipPath, makeClipPath } from "../chart/ChartUtils"
15
+ import {
16
+ COMPARISON_LINE_STYLE,
17
+ COMPARISON_LINE_LABEL_STYLE,
18
+ } from "./ComparisonLineConstants"
19
+ import { ComparisonLineProps } from "./ComparisonLine"
20
+
21
+ @observer
22
+ export class CustomComparisonLine extends React.Component<
23
+ ComparisonLineProps<CustomComparisonLineConfig>
24
+ > {
25
+ private renderUid = guid()
26
+ private pathId = `path-${this.renderUid}`
27
+
28
+ constructor(props: ComparisonLineProps<CustomComparisonLineConfig>) {
29
+ super(props)
30
+ makeObservable(this)
31
+ }
32
+
33
+ @computed private get fontSize(): number {
34
+ return this.props.dualAxis.comparisonLineLabelFontSize
35
+ }
36
+
37
+ @computed private get haloOutlineWidth(): number {
38
+ return GRAPHER_TEXT_OUTLINE_FACTOR * this.fontSize
39
+ }
40
+
41
+ @computed get clipPath(): ClipPath {
42
+ return makeClipPath({
43
+ name: "axisBounds",
44
+ renderUid: this.renderUid,
45
+ box: this.props.dualAxis.innerBounds,
46
+ })
47
+ }
48
+
49
+ @computed private get controlData(): [number, number][] {
50
+ const { comparisonLine, dualAxis } = this.props
51
+ const { horizontalAxis, verticalAxis } = dualAxis
52
+
53
+ return generateComparisonLinePoints(
54
+ comparisonLine.yEquals,
55
+ horizontalAxis.domain,
56
+ verticalAxis.domain,
57
+ horizontalAxis.scaleType,
58
+ verticalAxis.scaleType
59
+ )
60
+ }
61
+
62
+ @computed private get linePath(): string | null {
63
+ const { controlData } = this
64
+ const { horizontalAxis, verticalAxis } = this.props.dualAxis
65
+ const line = d3_line()
66
+ .curve(curveLinear)
67
+ .x((d) => horizontalAxis.place(d[0]))
68
+ .y((d) => verticalAxis.place(d[1]))
69
+ return line(controlData)
70
+ }
71
+
72
+ @computed private get placedLabel():
73
+ | { x: number; y: number; angle: number; text: string }
74
+ | undefined {
75
+ const { label } = this.props.comparisonLine
76
+ if (!label) return
77
+
78
+ const { controlData } = this
79
+ const { horizontalAxis, verticalAxis, innerBounds } =
80
+ this.props.dualAxis
81
+
82
+ // Find the points of the line that are actually placeable on the chart
83
+ const linePoints = controlData
84
+ .map(
85
+ (d) =>
86
+ new PointVector(
87
+ horizontalAxis.place(d[0]),
88
+ verticalAxis.place(d[1])
89
+ )
90
+ )
91
+ .filter((p) => innerBounds.contains(p))
92
+ if (!linePoints.length) return
93
+
94
+ const labelPosition = linePoints[Math.floor(linePoints.length / 2)]
95
+ const p1 = linePoints[0]
96
+ const p2 = linePoints[linePoints.length - 1]
97
+ const angle = (Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180) / Math.PI
98
+
99
+ return {
100
+ x: labelPosition.x,
101
+ y: labelPosition.y,
102
+ angle: angle,
103
+ text: label,
104
+ }
105
+ }
106
+
107
+ private renderLabel(): React.ReactElement | null {
108
+ const { pathId, renderUid, placedLabel } = this
109
+
110
+ if (!placedLabel) return null
111
+
112
+ return (
113
+ <text
114
+ style={{
115
+ ...COMPARISON_LINE_LABEL_STYLE,
116
+ textAnchor: "end",
117
+ fontSize: this.fontSize,
118
+ }}
119
+ clipPath={this.clipPath.id}
120
+ >
121
+ <Halo
122
+ id={`halo-${renderUid}`}
123
+ outlineWidth={this.haloOutlineWidth}
124
+ outlineColor={this.props.backgroundColor}
125
+ >
126
+ <textPath
127
+ baselineShift="-0.2rem"
128
+ href={`#${pathId}`}
129
+ startOffset="90%"
130
+ >
131
+ {placedLabel.text}
132
+ </textPath>
133
+ </Halo>
134
+ </text>
135
+ )
136
+ }
137
+
138
+ override render(): React.ReactElement | null {
139
+ if (!this.linePath) return null
140
+
141
+ return (
142
+ <g
143
+ id={makeIdForHumanConsumption(
144
+ "comparison-line",
145
+ this.props.comparisonLine.label
146
+ )}
147
+ >
148
+ {this.clipPath.element}
149
+ <path
150
+ style={COMPARISON_LINE_STYLE}
151
+ id={this.pathId}
152
+ d={this.linePath}
153
+ clipPath={this.clipPath.id}
154
+ />
155
+ {this.renderLabel()}
156
+ </g>
157
+ )
158
+ }
159
+ }
@@ -0,0 +1,208 @@
1
+ import * as React from "react"
2
+ import { computed, makeObservable } from "mobx"
3
+ import { observer } from "mobx-react"
4
+ import * as _ from "lodash-es"
5
+ import {
6
+ Bounds,
7
+ dyFromAlign,
8
+ makeIdForHumanConsumption,
9
+ VerticalAlign,
10
+ } from "../../utils/index.js"
11
+ import {
12
+ COMPARISON_LINE_STYLE,
13
+ COMPARISON_LINE_LABEL_STYLE,
14
+ } from "./ComparisonLineConstants"
15
+ import { ComparisonLineProps } from "./ComparisonLine"
16
+ import { VerticalComparisonLineConfig } from "../../types/index.js"
17
+ import { isValidVerticalComparisonLineConfig } from "./ComparisonLineHelpers"
18
+
19
+ @observer
20
+ export class VerticalComparisonLine extends React.Component<
21
+ ComparisonLineProps<VerticalComparisonLineConfig>
22
+ > {
23
+ constructor(props: ComparisonLineProps<VerticalComparisonLineConfig>) {
24
+ super(props)
25
+ makeObservable(this)
26
+ }
27
+
28
+ @computed private get fontSize(): number {
29
+ return this.props.dualAxis.comparisonLineLabelFontSize
30
+ }
31
+
32
+ @computed private get labelHeight(): number {
33
+ // Since the label isn't wrapped, its height equals the font size
34
+ return this.fontSize
35
+ }
36
+
37
+ @computed private get lineConfig(): VerticalComparisonLineConfig {
38
+ return this.props.comparisonLine
39
+ }
40
+
41
+ @computed
42
+ private get otherVerticalComparisonLines(): VerticalComparisonLineConfig[] {
43
+ return this.props.dualAxis.comparisonLines.filter(
44
+ (lineConfig): lineConfig is VerticalComparisonLineConfig =>
45
+ isValidVerticalComparisonLineConfig(lineConfig) &&
46
+ lineConfig.xEquals !== this.props.comparisonLine.xEquals
47
+ )
48
+ }
49
+
50
+ /** Nearest comparison line to the left of this line */
51
+ @computed private get closestLeftLine():
52
+ | VerticalComparisonLineConfig
53
+ | undefined {
54
+ const linesOnTheLeft = this.otherVerticalComparisonLines.filter(
55
+ (otherLine) => otherLine.xEquals < this.lineConfig.xEquals
56
+ )
57
+ return _.maxBy(linesOnTheLeft, (line) => line.xEquals)
58
+ }
59
+
60
+ /** Nearest comparison line to the right of this line */
61
+ @computed private get closestRightLine():
62
+ | VerticalComparisonLineConfig
63
+ | undefined {
64
+ const linesOnTheRight = this.otherVerticalComparisonLines.filter(
65
+ (otherLine) => otherLine.xEquals > this.lineConfig.xEquals
66
+ )
67
+ return _.minBy(linesOnTheRight, (line) => line.xEquals)
68
+ }
69
+
70
+ /**
71
+ * X-coordinate of the leftmost boundary for label placement.
72
+ *
73
+ * Either the position of the nearest comparison line on the left
74
+ * or the chart's bound.
75
+ */
76
+ @computed private get leftBoundX(): number {
77
+ const { closestLeftLine } = this
78
+ const { innerBounds, horizontalAxis } = this.props.dualAxis
79
+
80
+ if (!closestLeftLine) return innerBounds.left
81
+
82
+ return Math.max(
83
+ horizontalAxis.place(closestLeftLine.xEquals),
84
+ innerBounds.left
85
+ )
86
+ }
87
+
88
+ /**
89
+ * X-coordinate of the rightmost boundary for label placement.
90
+ *
91
+ * Either the position of the nearest comparison line on the right
92
+ * or the chart's bound.
93
+ */
94
+ @computed private get rightBoundX(): number {
95
+ const { closestRightLine } = this
96
+ const { innerBounds, horizontalAxis } = this.props.dualAxis
97
+
98
+ if (!closestRightLine) return innerBounds.right
99
+
100
+ return Math.min(
101
+ horizontalAxis.place(closestRightLine.xEquals),
102
+ innerBounds.right
103
+ )
104
+ }
105
+
106
+ /** Screen coordinates for rendering the vertical line */
107
+ @computed private get lineCoordinates():
108
+ | { x: number; y1: number; y2: number }
109
+ | undefined {
110
+ const { dualAxis } = this.props
111
+ const { horizontalAxis, innerBounds } = dualAxis
112
+ const xValue = this.lineConfig.xEquals
113
+ const [minX, maxX] = horizontalAxis.domain
114
+
115
+ // Only render if the line is within the chart bounds
116
+ const isWithinBounds = xValue >= minX && xValue <= maxX
117
+ if (!isWithinBounds) return undefined
118
+
119
+ return {
120
+ x: horizontalAxis.place(xValue),
121
+ // The line extends outside of the chart area, so that the label
122
+ // isn't covered by any chart elements
123
+ y1: innerBounds.top - this.labelHeight,
124
+ y2: innerBounds.bottom,
125
+ }
126
+ }
127
+
128
+ /** Calculated position and alignment for the label text */
129
+ @computed private get labelPosition():
130
+ | { x: number; y: number; anchor: "start" | "end" }
131
+ | undefined {
132
+ const { fontSize, lineCoordinates, rightBoundX, leftBoundX } = this
133
+ const { label } = this.lineConfig
134
+
135
+ if (!label || !lineCoordinates) return undefined
136
+
137
+ const { x, y1: y } = lineCoordinates
138
+
139
+ // Calculate available space on both sides
140
+ const padding = 4 // padding between label and line
141
+ const availableSpaceRight = rightBoundX - x - 2 * padding
142
+ const availableSpaceLeft = x - leftBoundX - 2 * padding
143
+
144
+ // Determine label placement:
145
+ // - Prefer the right side if there's enough space
146
+ // - Otherwise, try placing the label on the left side
147
+ // - If neither side has enough space, hide the label
148
+ const labelWidth = Bounds.forText(label, { fontSize }).width
149
+ const side =
150
+ labelWidth <= availableSpaceRight
151
+ ? "right"
152
+ : labelWidth <= availableSpaceLeft
153
+ ? "left"
154
+ : null
155
+
156
+ // Can't fit the label
157
+ if (side === null) return undefined
158
+
159
+ // Add a bit of padding between label and line and determine text anchor
160
+ const labelX = side === "right" ? x + padding : x - padding
161
+ const anchor = side === "right" ? "start" : "end"
162
+
163
+ return { x: labelX, y, anchor }
164
+ }
165
+
166
+ private renderLabel(): React.ReactElement | null {
167
+ if (!this.labelPosition) return null
168
+
169
+ const { x, y, anchor } = this.labelPosition
170
+
171
+ return (
172
+ <text
173
+ {...COMPARISON_LINE_LABEL_STYLE}
174
+ x={x}
175
+ y={y}
176
+ fontSize={this.fontSize}
177
+ dy={dyFromAlign(VerticalAlign.bottom)}
178
+ textAnchor={anchor}
179
+ >
180
+ {this.lineConfig.label}
181
+ </text>
182
+ )
183
+ }
184
+
185
+ override render(): React.ReactElement | null {
186
+ if (!this.lineCoordinates || !this.labelPosition) return null
187
+
188
+ const { x, y1, y2 } = this.lineCoordinates
189
+
190
+ return (
191
+ <g
192
+ id={makeIdForHumanConsumption(
193
+ "comparison-line",
194
+ this.lineConfig.label
195
+ )}
196
+ >
197
+ <line
198
+ x1={x}
199
+ y1={y1}
200
+ x2={x}
201
+ y2={y2}
202
+ style={COMPARISON_LINE_STYLE}
203
+ />
204
+ {this.renderLabel()}
205
+ </g>
206
+ )
207
+ }
208
+ }
@@ -0,0 +1,97 @@
1
+ // keep in sync with constant values in ActionButtons.tsx
2
+ $actionButtonHeight: 32px; // keep in sync with BUTTON_HEIGHT
3
+ $paddingBetweenActionButtons: 8px; // keep in sync with PADDING_BETWEEN_BUTTONS
4
+ $paddingBetweenIconAndLabel: 8px; // keep in sync with PADDING_BETWEEN_ICON_AND_LABEL
5
+ $paddingX: 12px; // keep in sync with PADDING_X
6
+
7
+ .ActionButtons {
8
+ margin: 0;
9
+ padding: 0;
10
+ white-space: nowrap;
11
+
12
+ ul {
13
+ display: flex;
14
+ list-style: none;
15
+ height: $actionButtonHeight;
16
+ padding: 0;
17
+ }
18
+
19
+ li {
20
+ height: 100%;
21
+ display: inline-block;
22
+ position: relative;
23
+ }
24
+
25
+ li + li {
26
+ margin-left: $paddingBetweenActionButtons;
27
+ }
28
+ }
29
+
30
+ div.ActionButton {
31
+ --light-fill: #{$gray-10};
32
+ --hover-fill: #{$gray-20};
33
+ --active-fill: #{$blue-20};
34
+ --text-color: #{$dark-text};
35
+
36
+ &.ActionButton--exploreData {
37
+ --light-fill: #{$blue-20};
38
+ --hover-fill: #{$blue-20};
39
+ --active-fill: #{$blue-10};
40
+ --text-color: #{$blue-90};
41
+
42
+ --hover-decoration: underline;
43
+ }
44
+
45
+ &.ActionButton--donate {
46
+ --light-fill: #{rgba($vermillion, 0.15)};
47
+ --hover-fill: #{rgba(#f4a39f, 0.15)};
48
+ --active-fill: var(--hover-fill);
49
+ --text-color: #{$vermillion};
50
+ }
51
+
52
+ height: 100%;
53
+ border-radius: 4px;
54
+ position: relative;
55
+
56
+ button,
57
+ a {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: $paddingBetweenIconAndLabel;
61
+ height: 100%;
62
+ width: 100%;
63
+ cursor: pointer;
64
+ color: var(--text-color);
65
+ font-size: 13px;
66
+ font-weight: 500;
67
+ padding: 0 $paddingX;
68
+ border-radius: inherit;
69
+ background-color: var(--light-fill);
70
+ position: relative;
71
+ letter-spacing: 0.01em;
72
+
73
+ svg {
74
+ font-size: 12px;
75
+ }
76
+
77
+ &.icon-only {
78
+ justify-content: center;
79
+ padding: 0;
80
+ }
81
+
82
+ &:visited {
83
+ color: var(--text-color);
84
+ }
85
+
86
+ &:hover {
87
+ background-color: var(--hover-fill);
88
+ text-decoration: var(--hover-decoration);
89
+ }
90
+
91
+ &:active,
92
+ &.active {
93
+ color: $active-text;
94
+ background-color: var(--active-fill);
95
+ }
96
+ }
97
+ }