@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,568 @@
1
+ import * as _ from "lodash-es"
2
+ import * as R from "remeda"
3
+ import {
4
+ Bounds,
5
+ getAttributionFragmentsFromVariable,
6
+ getLastUpdatedFromVariable,
7
+ getNextUpdateFromVariable,
8
+ excludeUndefined,
9
+ DisplaySource,
10
+ prepareSourcesForDisplay,
11
+ OwidSource,
12
+ IndicatorTitleWithFragments,
13
+ joinTitleFragments,
14
+ getCitationShort,
15
+ getCitationLong,
16
+ } from "../../utils/index.js"
17
+ import {
18
+ IndicatorSources,
19
+ IndicatorProcessing,
20
+ SimpleMarkdownText,
21
+ DataCitation,
22
+ OverlayHeader,
23
+ CLOSE_BUTTON_WIDTH,
24
+ CloseButton,
25
+ LoadingIndicator,
26
+ } from "../../components/index.js"
27
+ import * as React from "react"
28
+ import cx from "classnames"
29
+ import { action, computed, makeObservable, observable } from "mobx"
30
+ import { observer } from "mobx-react"
31
+ import { faPencilAlt } from "@fortawesome/free-solid-svg-icons"
32
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
33
+ import { OwidColumnDef } from "../../types/index.js"
34
+ import { CoreColumn } from "../../core-table/index.js"
35
+ import { Modal } from "./Modal"
36
+ import { SourcesKeyDataTable } from "./SourcesKeyDataTable"
37
+ import { SourcesDescriptions } from "./SourcesDescriptions"
38
+ import { TabItem, Tabs } from "../tabs/Tabs"
39
+ import { TabsWithDropdown } from "../tabs/TabsWithDropdown"
40
+ import {
41
+ DEFAULT_GRAPHER_BOUNDS,
42
+ GrapherModal,
43
+ isContinentsVariableId,
44
+ } from "../core/GrapherConstants"
45
+
46
+ // keep in sync with variables in SourcesModal.scss
47
+ const MAX_CONTENT_WIDTH = 640
48
+ const TAB_PADDING = 8
49
+ const TAB_FONT_SIZE = 13
50
+ const TAB_GAP = 8
51
+ const TAB_TITLE_SPACING = 6
52
+
53
+ export interface SourcesModalManager {
54
+ isReady?: boolean
55
+ adminBaseUrl?: string
56
+ columnsWithSourcesExtensive: CoreColumn[]
57
+ showAdminControls?: boolean
58
+ activeModal?: GrapherModal
59
+ frameBounds?: Bounds
60
+ isEmbeddedInADataPage?: boolean
61
+ isNarrow?: boolean
62
+ fontSize?: number
63
+ }
64
+
65
+ interface SourcesModalProps {
66
+ manager: SourcesModalManager
67
+ }
68
+
69
+ @observer
70
+ export class SourcesModal extends React.Component<SourcesModalProps> {
71
+ private container = React.createRef<HTMLDivElement>()
72
+
73
+ private activeTabKey = ""
74
+
75
+ constructor(props: SourcesModalProps) {
76
+ super(props)
77
+ makeObservable<SourcesModal, "activeTabKey">(this, {
78
+ activeTabKey: observable,
79
+ })
80
+ }
81
+
82
+ @action override componentDidMount(): void {
83
+ this.activeTabKey = this.tabs[0]?.label.key ?? ""
84
+ }
85
+
86
+ @action.bound private setActiveTabKey(key: string): void {
87
+ this.activeTabKey = key
88
+ }
89
+
90
+ @computed private get manager(): SourcesModalManager {
91
+ return this.props.manager
92
+ }
93
+
94
+ @computed private get frameBounds(): Bounds {
95
+ return this.manager.frameBounds ?? DEFAULT_GRAPHER_BOUNDS
96
+ }
97
+
98
+ @computed private get modalBounds(): Bounds {
99
+ const maxWidth = MAX_CONTENT_WIDTH + 220
100
+ // using 15px instead of 16px to make sure the modal fully covers the OWID logo in the header
101
+ const padWidth = Math.max(15, (this.frameBounds.width - maxWidth) / 2)
102
+ return this.frameBounds.padHeight(15).padWidth(padWidth)
103
+ }
104
+
105
+ @computed private get showStickyHeader(): boolean {
106
+ const modalWidth = this.modalBounds.width - 2 * this.modalPadding
107
+ return (modalWidth - MAX_CONTENT_WIDTH) / 2 < CLOSE_BUTTON_WIDTH + 2
108
+ }
109
+
110
+ @computed private get modalPadding(): number {
111
+ return 1.5 * (this.manager.fontSize ?? 16)
112
+ }
113
+
114
+ @computed private get editBaseUrl(): string | undefined {
115
+ if (!this.manager.showAdminControls) return undefined
116
+ return `${this.props.manager.adminBaseUrl}/admin`
117
+ }
118
+
119
+ @computed private get columns(): CoreColumn[] {
120
+ return this.manager.columnsWithSourcesExtensive
121
+ }
122
+
123
+ private makeTabLabelString(title: string, attribution?: string): string {
124
+ return `${title} ${attribution ?? ""}`.trim()
125
+ }
126
+
127
+ private makeTabLabelElement(
128
+ title: string,
129
+ attribution?: string
130
+ ): React.ReactElement {
131
+ return (
132
+ <>
133
+ {title}
134
+ {attribution && (
135
+ <span className="attribution">{attribution}</span>
136
+ )}
137
+ </>
138
+ )
139
+ }
140
+
141
+ @computed private get tabs(): {
142
+ column: CoreColumn
143
+ label: TabItem
144
+ }[] {
145
+ return _.uniqBy(
146
+ this.columns.map((column) => {
147
+ const title = column.titlePublicOrDisplayName.title
148
+ const attribution = joinTitleFragments(
149
+ column.titlePublicOrDisplayName.attributionShort,
150
+ column.titlePublicOrDisplayName.titleVariant
151
+ )
152
+ return {
153
+ column,
154
+ label: {
155
+ key: this.makeTabLabelString(title, attribution),
156
+ element: this.makeTabLabelElement(title, attribution),
157
+ },
158
+ }
159
+ }),
160
+ // deduplicate tabs by their label
161
+ (tab) => tab.label.key
162
+ )
163
+ }
164
+
165
+ @computed private get tabLabels(): TabItem[] {
166
+ return this.tabs.map(({ label }) => label)
167
+ }
168
+
169
+ @computed private get tabLabelWidths(): number[] {
170
+ return this.tabs.map(({ column }) => {
171
+ const title = `${column.titlePublicOrDisplayName.title}`
172
+ const fragments = joinTitleFragments(
173
+ column.titlePublicOrDisplayName.attributionShort,
174
+ column.titlePublicOrDisplayName.titleVariant
175
+ )
176
+ return measureTabWidth(title, fragments)
177
+ })
178
+ }
179
+
180
+ private renderSource(
181
+ column: CoreColumn | undefined
182
+ ): React.ReactElement | null {
183
+ if (!column) return null
184
+ return (
185
+ <Source
186
+ column={column}
187
+ editBaseUrl={this.editBaseUrl}
188
+ isEmbeddedInADataPage={
189
+ this.manager.isEmbeddedInADataPage ?? false
190
+ }
191
+ />
192
+ )
193
+ }
194
+
195
+ private renderTabs(): React.ReactElement {
196
+ // Display horizontally scrolling tabs on mobile
197
+ if (this.manager.isNarrow) {
198
+ return (
199
+ <Tabs
200
+ className="sources-modal-tabs"
201
+ items={this.tabLabels}
202
+ selectedKey={this.activeTabKey}
203
+ onChange={this.setActiveTabKey}
204
+ variant="scroll"
205
+ />
206
+ )
207
+ }
208
+
209
+ // Show all tabs if there are 4 or fewer
210
+ if (this.tabs.length <= 4) {
211
+ return (
212
+ <Tabs
213
+ className="sources-modal-tabs"
214
+ items={this.tabLabels}
215
+ selectedKey={this.activeTabKey}
216
+ onChange={this.setActiveTabKey}
217
+ variant="scroll"
218
+ />
219
+ )
220
+ }
221
+
222
+ // Find the subset of tabs that fit into a single line
223
+ const getVisibleLabels = (labels: TabItem[]): TabItem[] => {
224
+ // Maximum width available for tabs
225
+ const maxWidth = Math.min(
226
+ MAX_CONTENT_WIDTH,
227
+ this.modalBounds.width - 2 * this.modalPadding
228
+ )
229
+
230
+ // Hardcoded width of the "More" button
231
+ const moreButtonWidth = 74
232
+
233
+ const visibleLabels: TabItem[] = []
234
+ let currentWidth = moreButtonWidth
235
+ for (const [label, labelWidth] of R.zip(
236
+ labels,
237
+ this.tabLabelWidths
238
+ )) {
239
+ currentWidth += labelWidth + TAB_GAP
240
+ if (currentWidth > maxWidth) break
241
+ visibleLabels.push(label)
242
+ }
243
+
244
+ return visibleLabels
245
+ }
246
+
247
+ const visibleLabels = getVisibleLabels(this.tabLabels)
248
+
249
+ // No need for a dropdown if all tabs are visible
250
+ if (visibleLabels.length === this.tabLabels.length) {
251
+ return (
252
+ <Tabs
253
+ className="sources-modal-tabs"
254
+ items={this.tabLabels}
255
+ selectedKey={this.activeTabKey}
256
+ onChange={this.setActiveTabKey}
257
+ variant="scroll"
258
+ />
259
+ )
260
+ }
261
+
262
+ // Ensure at least 3 tabs are visible
263
+ const numVisibleTabs = Math.max(3, visibleLabels.length)
264
+
265
+ return (
266
+ <TabsWithDropdown
267
+ className="sources-modal-tabs"
268
+ items={this.tabLabels}
269
+ selectedKey={this.activeTabKey}
270
+ onChange={this.setActiveTabKey}
271
+ numVisibleTabs={numVisibleTabs}
272
+ portalContainer={this.container.current ?? undefined}
273
+ />
274
+ )
275
+ }
276
+
277
+ private renderMultipleSources(): React.ReactElement {
278
+ const activeColumn = this.tabs.find(
279
+ (tab) => tab.label.key === this.activeTabKey
280
+ )?.column
281
+
282
+ return (
283
+ <>
284
+ <p className="note-multiple-indicators">
285
+ This chart is composed of multiple indicators. Select an
286
+ indicator for more information.
287
+ </p>
288
+ {this.renderTabs()}
289
+ {this.renderSource(activeColumn)}
290
+ </>
291
+ )
292
+ }
293
+
294
+ private renderModalContent(): React.ReactElement | null {
295
+ return this.tabs.length === 1
296
+ ? this.renderSource(this.tabs[0].column)
297
+ : this.renderMultipleSources()
298
+ }
299
+
300
+ @action.bound private onDismiss(): void {
301
+ this.manager.activeModal = undefined
302
+ }
303
+
304
+ override render(): React.ReactElement {
305
+ return (
306
+ <Modal
307
+ bounds={this.modalBounds}
308
+ isHeightFixed={true}
309
+ onDismiss={this.onDismiss}
310
+ >
311
+ <div className="sources-modal-content" ref={this.container}>
312
+ {this.showStickyHeader ? (
313
+ <OverlayHeader title="" onDismiss={this.onDismiss} />
314
+ ) : (
315
+ <CloseButton
316
+ className="close-button--top-right"
317
+ onClick={this.onDismiss}
318
+ />
319
+ )}
320
+ <div
321
+ className={cx("scrollable", {
322
+ "scrollable--pad-top": !this.showStickyHeader,
323
+ })}
324
+ >
325
+ <div className="centered">
326
+ {this.manager.isReady ? (
327
+ this.renderModalContent()
328
+ ) : (
329
+ <LoadingIndicator />
330
+ )}
331
+ </div>
332
+ </div>
333
+ </div>
334
+ </Modal>
335
+ )
336
+ }
337
+ }
338
+
339
+ interface SourceProps {
340
+ column: CoreColumn
341
+ editBaseUrl?: string
342
+ isEmbeddedInADataPage?: boolean
343
+ }
344
+
345
+ @observer
346
+ export class Source extends React.Component<SourceProps> {
347
+ constructor(props: SourceProps) {
348
+ super(props)
349
+ makeObservable(this)
350
+ }
351
+
352
+ @computed get column(): CoreColumn {
353
+ return this.props.column
354
+ }
355
+
356
+ @computed get def(): OwidColumnDef & { source?: OwidSource } {
357
+ return { ...this.column.def, source: this.column.source }
358
+ }
359
+
360
+ @computed get citationShort(): string {
361
+ return getCitationShort(
362
+ this.def.origins ?? [],
363
+ getAttributionFragmentsFromVariable(this.def),
364
+ this.def.owidProcessingLevel
365
+ )
366
+ }
367
+
368
+ @computed get citationLong(): string {
369
+ return getCitationLong(
370
+ this.title,
371
+ this.def.origins ?? [],
372
+ this.source,
373
+ getAttributionFragmentsFromVariable(this.def),
374
+ this.def.presentation?.attributionShort,
375
+ this.def.presentation?.titleVariant,
376
+ this.def.owidProcessingLevel,
377
+ undefined,
378
+ undefined
379
+ )
380
+ }
381
+
382
+ @computed private get source(): OwidSource {
383
+ return this.def.source ?? {}
384
+ }
385
+
386
+ @computed private get title(): IndicatorTitleWithFragments {
387
+ return this.column.titlePublicOrDisplayName
388
+ }
389
+
390
+ @computed private get editUrl(): string | undefined {
391
+ if (!this.props.editBaseUrl) return undefined
392
+
393
+ // point user directly to the variable edit page if possible
394
+ if (this.def.owidVariableId) {
395
+ return `${this.props.editBaseUrl}/variables/${this.def.owidVariableId}`
396
+ }
397
+
398
+ // if that's not possible, point user to the dataset edit page
399
+ if (this.def.datasetId) {
400
+ return `${this.props.editBaseUrl}/datasets/${this.def.datasetId}`
401
+ }
402
+
403
+ // we can't link to an edit page for explorers that define the FASTT in TSV
404
+ return undefined
405
+ }
406
+
407
+ @computed private get producers(): string[] {
408
+ if (!this.def.origins) return []
409
+ return _.uniq(excludeUndefined(this.def.origins.map((o) => o.producer)))
410
+ }
411
+
412
+ @computed get attributions(): string | undefined {
413
+ const attributionFragments =
414
+ getAttributionFragmentsFromVariable(this.def) ?? this.producers
415
+ if (attributionFragments.length === 0) return undefined
416
+ return attributionFragments.join(", ")
417
+ }
418
+
419
+ @computed get lastUpdated(): string | undefined {
420
+ return getLastUpdatedFromVariable(this.def)
421
+ }
422
+
423
+ @computed get nextUpdate(): string | undefined {
424
+ return getNextUpdateFromVariable(this.def)
425
+ }
426
+
427
+ @computed get unit(): string | undefined {
428
+ return this.column.unit
429
+ }
430
+
431
+ @computed private get datapageHasFAQSection(): boolean {
432
+ const faqCount = this.def.presentation?.faqs?.length ?? 0
433
+ return !!this.props.isEmbeddedInADataPage && faqCount > 0
434
+ }
435
+
436
+ @computed private get showDescriptions(): boolean {
437
+ return (
438
+ (this.def.descriptionKey && this.def.descriptionKey.length > 0) ||
439
+ !!this.def.descriptionFromProducer ||
440
+ !!this.source.additionalInfo
441
+ )
442
+ }
443
+
444
+ @computed private get sourcesForDisplay(): DisplaySource[] {
445
+ return prepareSourcesForDisplay(this.def)
446
+ }
447
+
448
+ @computed protected get sourcesSectionHeading(): string {
449
+ return "The data of this indicator is based on the following sources:"
450
+ }
451
+
452
+ @computed private get hideSourcesForDisplay(): boolean {
453
+ // the "Continent" variable curated by OWID is used in many charts but doesn't come with useful source information.
454
+ // that's why we hide the sources section for this indicator for now, but we might decide to show it in the future.
455
+ return (
456
+ !!this.def.owidVariableId &&
457
+ isContinentsVariableId(this.def.owidVariableId)
458
+ )
459
+ }
460
+
461
+ @computed private get descriptionBelowTitle(): string | undefined {
462
+ return this.def.descriptionShort || this.def.description
463
+ }
464
+
465
+ protected renderTitle(): React.ReactElement {
466
+ return (
467
+ <h2>
468
+ <span className="title">{this.title.title}</span>{" "}
469
+ {(this.title.attributionShort || this.title.titleVariant) && (
470
+ <>
471
+ <span className="title-fragments">
472
+ {joinTitleFragments(
473
+ this.title.attributionShort,
474
+ this.title.titleVariant
475
+ )}
476
+ </span>{" "}
477
+ </>
478
+ )}
479
+ {this.editUrl && (
480
+ <a href={this.editUrl}>
481
+ <FontAwesomeIcon icon={faPencilAlt} />
482
+ </a>
483
+ )}
484
+ </h2>
485
+ )
486
+ }
487
+
488
+ override render(): React.ReactElement {
489
+ return (
490
+ <div className="source">
491
+ {this.renderTitle()}
492
+ {this.descriptionBelowTitle && (
493
+ <div className="description-below-title">
494
+ <SimpleMarkdownText text={this.descriptionBelowTitle} />
495
+ </div>
496
+ )}
497
+ <SourcesKeyDataTable
498
+ attribution={this.attributions}
499
+ owidProcessingLevel={this.def.owidProcessingLevel}
500
+ dateRange={this.def.timespan}
501
+ lastUpdated={this.lastUpdated}
502
+ nextUpdate={this.nextUpdate}
503
+ unit={this.unit}
504
+ link={this.source.link}
505
+ unitConversionFactor={this.column.unitConversionFactor}
506
+ isEmbeddedInADataPage={this.props.isEmbeddedInADataPage}
507
+ />
508
+ {this.showDescriptions && (
509
+ <SourcesDescriptions
510
+ descriptionShort={this.def.descriptionShort}
511
+ descriptionKey={this.def.descriptionKey ?? []}
512
+ hasFaqEntries={this.datapageHasFAQSection}
513
+ descriptionFromProducer={
514
+ this.def.descriptionFromProducer
515
+ }
516
+ attributionShort={
517
+ this.def.presentation?.attributionShort
518
+ }
519
+ additionalInfo={this.source.additionalInfo}
520
+ isEmbeddedInADataPage={this.props.isEmbeddedInADataPage}
521
+ />
522
+ )}
523
+ {!this.hideSourcesForDisplay &&
524
+ this.sourcesForDisplay &&
525
+ this.sourcesForDisplay.length > 0 && (
526
+ <>
527
+ <h3 className="heading">
528
+ {this.sourcesSectionHeading}
529
+ </h3>
530
+ <IndicatorSources
531
+ sources={this.sourcesForDisplay}
532
+ isEmbeddedInADataPage={
533
+ this.props.isEmbeddedInADataPage
534
+ }
535
+ />
536
+ </>
537
+ )}
538
+ <h3 className="heading heading--tight">
539
+ How we process data at Our World in Data:
540
+ </h3>
541
+ <IndicatorProcessing
542
+ descriptionProcessing={this.def.descriptionProcessing}
543
+ />
544
+ <h3 className="heading heading--tight">
545
+ How to cite this data:
546
+ </h3>
547
+ <DataCitation
548
+ citationShort={this.citationShort}
549
+ citationLong={this.citationLong}
550
+ />
551
+ </div>
552
+ )
553
+ }
554
+ }
555
+
556
+ const measureTabWidth = (label: string, secondary?: string): number => {
557
+ const getWidth = (text: string) =>
558
+ Bounds.forText(text, { fontSize: TAB_FONT_SIZE }).width
559
+
560
+ const labelWidth = getWidth(label)
561
+ const secondaryTextWidth = secondary
562
+ ? getWidth(secondary) + TAB_TITLE_SPACING
563
+ : 0
564
+ const padding = 2 * TAB_PADDING
565
+ const borderWidth = 2
566
+
567
+ return labelWidth + secondaryTextWidth + padding + borderWidth
568
+ }
@@ -0,0 +1,125 @@
1
+ import * as React from "react"
2
+ import { computed, makeObservable } from "mobx"
3
+ import { observer } from "mobx-react"
4
+ import a from "indefinite"
5
+ import { Bounds, VerticalAlign, dyFromAlign } from "../../utils/index.js"
6
+ import {
7
+ BASE_FONT_SIZE,
8
+ DEFAULT_GRAPHER_BOUNDS,
9
+ DEFAULT_GRAPHER_ENTITY_TYPE,
10
+ DEFAULT_GRAPHER_ENTITY_TYPE_PLURAL,
11
+ GRAPHER_TEXT_OUTLINE_FACTOR,
12
+ } from "../core/GrapherConstants"
13
+ import { Halo } from "../../components/index.js"
14
+ import { GRAPHER_DARK_TEXT, GRAPHER_LIGHT_TEXT } from "../color/ColorConstants"
15
+
16
+ export interface NoDataModalManager {
17
+ canChangeEntity?: boolean
18
+ canAddEntities?: boolean
19
+ entityType?: string
20
+ entityTypePlural?: string
21
+ fontSize?: number
22
+ isStatic?: boolean
23
+ }
24
+
25
+ interface NoDataModalProps {
26
+ bounds?: Bounds
27
+ message?: string
28
+ helpText?: string
29
+ hideTextOutline?: boolean
30
+ manager: NoDataModalManager
31
+ }
32
+
33
+ @observer
34
+ export class NoDataModal extends React.Component<NoDataModalProps> {
35
+ constructor(props: NoDataModalProps) {
36
+ super(props)
37
+ makeObservable(this)
38
+ }
39
+
40
+ @computed private get bounds(): Bounds {
41
+ return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
42
+ }
43
+
44
+ @computed private get manager(): NoDataModalManager {
45
+ return this.props.manager
46
+ }
47
+
48
+ @computed private get fontSize(): number {
49
+ // font sizes bigger than the base font size are too large for the no data text
50
+ return Math.min(this.manager.fontSize ?? BASE_FONT_SIZE, BASE_FONT_SIZE)
51
+ }
52
+
53
+ override render(): React.ReactElement {
54
+ const { bounds } = this
55
+ const { message } = this.props
56
+ const {
57
+ entityType = DEFAULT_GRAPHER_ENTITY_TYPE,
58
+ entityTypePlural = DEFAULT_GRAPHER_ENTITY_TYPE_PLURAL,
59
+ canAddEntities,
60
+ canChangeEntity,
61
+ isStatic,
62
+ } = this.manager
63
+
64
+ const defaultHelpText = canAddEntities
65
+ ? `Try adding ${entityTypePlural} to display data.`
66
+ : canChangeEntity
67
+ ? `Try choosing ${a(entityType)} to display data.`
68
+ : undefined
69
+ const helpText = this.props.helpText ?? defaultHelpText
70
+
71
+ const center = bounds.centerPos
72
+ const padding = 0.75 * this.fontSize
73
+ const showHelpText = !isStatic && !!helpText
74
+ const helpTextFontSize = 0.9 * this.fontSize
75
+
76
+ return (
77
+ <g className="no-data">
78
+ <rect {...bounds.toProps()} fill="#fff" opacity={0.6} />
79
+
80
+ <Halo
81
+ id="no-data-message"
82
+ outlineWidth={GRAPHER_TEXT_OUTLINE_FACTOR * this.fontSize}
83
+ show={!this.props.hideTextOutline}
84
+ >
85
+ <text
86
+ x={center.x}
87
+ y={center.y}
88
+ dy={
89
+ showHelpText
90
+ ? -padding / 2
91
+ : dyFromAlign(VerticalAlign.middle)
92
+ }
93
+ textAnchor="middle"
94
+ fontSize={this.fontSize}
95
+ fontWeight={500}
96
+ fill={GRAPHER_DARK_TEXT}
97
+ >
98
+ {message || "No available data"}
99
+ </text>
100
+ </Halo>
101
+
102
+ {showHelpText && (
103
+ <Halo
104
+ id="no-data-help"
105
+ outlineWidth={
106
+ GRAPHER_TEXT_OUTLINE_FACTOR * helpTextFontSize
107
+ }
108
+ show={!this.props.hideTextOutline}
109
+ >
110
+ <text
111
+ x={center.x}
112
+ y={center.y + padding / 2}
113
+ textAnchor="middle"
114
+ dy={dyFromAlign(VerticalAlign.bottom)}
115
+ fontSize={helpTextFontSize}
116
+ fill={GRAPHER_LIGHT_TEXT}
117
+ >
118
+ {helpText}
119
+ </text>
120
+ </Halo>
121
+ )}
122
+ </g>
123
+ )
124
+ }
125
+ }