@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.
- package/LICENSE.md +8 -0
- package/README.md +113 -0
- package/package.json +137 -0
- package/src/components/BodyPortal/BodyPortal.tsx +40 -0
- package/src/components/Button/Button.scss +110 -0
- package/src/components/Button/Button.tsx +101 -0
- package/src/components/Checkbox.scss +93 -0
- package/src/components/Checkbox.tsx +47 -0
- package/src/components/ExpandableToggle/ExpandableToggle.scss +123 -0
- package/src/components/ExpandableToggle/ExpandableToggle.tsx +60 -0
- package/src/components/GrapherTabIcon.tsx +156 -0
- package/src/components/GrapherTrendArrow.scss +16 -0
- package/src/components/GrapherTrendArrow.tsx +30 -0
- package/src/components/Halo/Halo.tsx +44 -0
- package/src/components/LabeledSwitch/LabeledSwitch.scss +109 -0
- package/src/components/LabeledSwitch/LabeledSwitch.tsx +62 -0
- package/src/components/MarkdownTextWrap/MarkdownTextWrap.tsx +1173 -0
- package/src/components/OverlayHeader.scss +18 -0
- package/src/components/OverlayHeader.tsx +29 -0
- package/src/components/RadioButton.scss +69 -0
- package/src/components/RadioButton.tsx +42 -0
- package/src/components/SimpleMarkdownText.tsx +89 -0
- package/src/components/TextInput.scss +17 -0
- package/src/components/TextInput.tsx +19 -0
- package/src/components/TextWrap/TextWrap.tsx +361 -0
- package/src/components/TextWrap/TextWrapUtils.ts +32 -0
- package/src/components/closeButton/CloseButton.scss +40 -0
- package/src/components/closeButton/CloseButton.tsx +27 -0
- package/src/components/index.ts +70 -0
- package/src/components/loadingIndicator/LoadingIndicator.scss +40 -0
- package/src/components/loadingIndicator/LoadingIndicator.tsx +28 -0
- package/src/components/markdown/remarkPlainLinks.ts +36 -0
- package/src/components/reactUtil.ts +20 -0
- package/src/components/stubs/CodeSnippet.tsx +19 -0
- package/src/components/stubs/DataCitation.tsx +16 -0
- package/src/components/stubs/IndicatorKeyData.tsx +45 -0
- package/src/components/stubs/IndicatorProcessing.tsx +15 -0
- package/src/components/stubs/IndicatorSources.tsx +15 -0
- package/src/components/styles/colors.scss +113 -0
- package/src/components/styles/mixins.scss +630 -0
- package/src/components/styles/typography.scss +579 -0
- package/src/components/styles/util.scss +89 -0
- package/src/components/styles/variables.scss +208 -0
- package/src/config/ChartsConfig.ts +163 -0
- package/src/config/ChartsProvider.tsx +157 -0
- package/src/config/index.ts +20 -0
- package/src/core-table/CoreTable.ts +1355 -0
- package/src/core-table/CoreTableColumns.ts +973 -0
- package/src/core-table/CoreTableUtils.ts +793 -0
- package/src/core-table/ErrorValues.ts +73 -0
- package/src/core-table/OwidTable.ts +1175 -0
- package/src/core-table/OwidTableSynthesizers.ts +272 -0
- package/src/core-table/OwidTableUtil.ts +76 -0
- package/src/core-table/Transforms.ts +484 -0
- package/src/core-table/index.ts +82 -0
- package/src/explorer/ColumnGrammar.ts +217 -0
- package/src/explorer/Explorer.sample.ts +212 -0
- package/src/explorer/Explorer.scss +148 -0
- package/src/explorer/Explorer.tsx +1283 -0
- package/src/explorer/ExplorerConstants.ts +85 -0
- package/src/explorer/ExplorerControls.scss +156 -0
- package/src/explorer/ExplorerControls.tsx +210 -0
- package/src/explorer/ExplorerDecisionMatrix.ts +471 -0
- package/src/explorer/ExplorerGrammar.ts +161 -0
- package/src/explorer/ExplorerProgram.ts +568 -0
- package/src/explorer/ExplorerUtils.ts +59 -0
- package/src/explorer/GrapherGrammar.ts +387 -0
- package/src/explorer/gridLang/GrammarUtils.ts +121 -0
- package/src/explorer/gridLang/GridCell.ts +298 -0
- package/src/explorer/gridLang/GridLangConstants.ts +255 -0
- package/src/explorer/gridLang/GridProgram.ts +311 -0
- package/src/explorer/gridLang/readme.md +17 -0
- package/src/explorer/index.ts +69 -0
- package/src/explorer/readme.md +19 -0
- package/src/explorer/urlMigrations/CO2UrlMigration.ts +46 -0
- package/src/explorer/urlMigrations/CovidUrlMigration.ts +37 -0
- package/src/explorer/urlMigrations/EnergyUrlMigration.ts +41 -0
- package/src/explorer/urlMigrations/ExplorerPageUrlMigrationSpec.ts +12 -0
- package/src/explorer/urlMigrations/ExplorerUrlMigrationUtils.ts +45 -0
- package/src/explorer/urlMigrations/ExplorerUrlMigrations.ts +33 -0
- package/src/explorer/urlMigrations/LegacyCovidUrlMigration.ts +144 -0
- package/src/explorer/urlMigrations/readme.md +39 -0
- package/src/grapher/axis/Axis.ts +973 -0
- package/src/grapher/axis/AxisConfig.ts +179 -0
- package/src/grapher/axis/AxisViews.tsx +597 -0
- package/src/grapher/barCharts/DiscreteBarChart.tsx +728 -0
- package/src/grapher/barCharts/DiscreteBarChartConstants.ts +60 -0
- package/src/grapher/barCharts/DiscreteBarChartHelpers.ts +338 -0
- package/src/grapher/barCharts/DiscreteBarChartState.ts +354 -0
- package/src/grapher/barCharts/DiscreteBarChartThumbnail.tsx +34 -0
- package/src/grapher/captionedChart/CaptionedChart.scss +61 -0
- package/src/grapher/captionedChart/CaptionedChart.tsx +523 -0
- package/src/grapher/captionedChart/Logos.tsx +141 -0
- package/src/grapher/captionedChart/LogosSVG.tsx +16 -0
- package/src/grapher/captionedChart/StaticChartRasterizer.tsx +178 -0
- package/src/grapher/captionedChart/assets/buildcanada-logo-square.svg +15 -0
- package/src/grapher/captionedChart/assets/buildcanada-logo.svg +15 -0
- package/src/grapher/captionedChart/assets/canadaspends.svg +7 -0
- package/src/grapher/captionedChart/readme.md +14 -0
- package/src/grapher/chart/Chart.tsx +62 -0
- package/src/grapher/chart/ChartAreaContent.tsx +172 -0
- package/src/grapher/chart/ChartDimension.ts +121 -0
- package/src/grapher/chart/ChartInterface.ts +83 -0
- package/src/grapher/chart/ChartManager.ts +113 -0
- package/src/grapher/chart/ChartTabs.ts +178 -0
- package/src/grapher/chart/ChartTypeMap.tsx +158 -0
- package/src/grapher/chart/ChartTypeSwitcher.tsx +26 -0
- package/src/grapher/chart/ChartUtils.tsx +364 -0
- package/src/grapher/chart/DimensionSlot.ts +45 -0
- package/src/grapher/chart/StaticChartWrapper.tsx +94 -0
- package/src/grapher/chart/guidedChartUtils.ts +82 -0
- package/src/grapher/color/BinningStrategies.ts +484 -0
- package/src/grapher/color/BinningStrategyEqualSizeBins.ts +132 -0
- package/src/grapher/color/BinningStrategyLogarithmic.ts +121 -0
- package/src/grapher/color/CategoricalColorAssigner.ts +97 -0
- package/src/grapher/color/ColorBrewerSchemes.ts +80 -0
- package/src/grapher/color/ColorConstants.ts +20 -0
- package/src/grapher/color/ColorScale.ts +339 -0
- package/src/grapher/color/ColorScaleBin.ts +147 -0
- package/src/grapher/color/ColorScaleConfig.ts +204 -0
- package/src/grapher/color/ColorScheme.ts +137 -0
- package/src/grapher/color/ColorSchemes.ts +149 -0
- package/src/grapher/color/ColorUtils.ts +86 -0
- package/src/grapher/color/CustomSchemes.ts +1772 -0
- package/src/grapher/color/readme.md +84 -0
- package/src/grapher/comparisonLine/ComparisonLine.tsx +31 -0
- package/src/grapher/comparisonLine/ComparisonLineConstants.ts +11 -0
- package/src/grapher/comparisonLine/ComparisonLineGenerator.ts +60 -0
- package/src/grapher/comparisonLine/ComparisonLineHelpers.ts +10 -0
- package/src/grapher/comparisonLine/CustomComparisonLine.tsx +159 -0
- package/src/grapher/comparisonLine/VerticalComparisonLine.tsx +208 -0
- package/src/grapher/controls/ActionButtons.scss +97 -0
- package/src/grapher/controls/ActionButtons.tsx +453 -0
- package/src/grapher/controls/CommandPalette.scss +50 -0
- package/src/grapher/controls/CommandPalette.tsx +74 -0
- package/src/grapher/controls/ContentSwitchers.scss +93 -0
- package/src/grapher/controls/ContentSwitchers.tsx +238 -0
- package/src/grapher/controls/Controls.scss +158 -0
- package/src/grapher/controls/DataTableFilterDropdown.scss +7 -0
- package/src/grapher/controls/DataTableFilterDropdown.tsx +168 -0
- package/src/grapher/controls/DataTableSearchField.scss +3 -0
- package/src/grapher/controls/DataTableSearchField.tsx +76 -0
- package/src/grapher/controls/Dropdown.scss +252 -0
- package/src/grapher/controls/Dropdown.tsx +235 -0
- package/src/grapher/controls/EntitySelectionToggle.tsx +135 -0
- package/src/grapher/controls/MapRegionDropdown.scss +3 -0
- package/src/grapher/controls/MapRegionDropdown.tsx +104 -0
- package/src/grapher/controls/MapResetButton.tsx +115 -0
- package/src/grapher/controls/MapZoomDropdown.scss +9 -0
- package/src/grapher/controls/MapZoomDropdown.tsx +270 -0
- package/src/grapher/controls/MapZoomToSelectionButton.tsx +87 -0
- package/src/grapher/controls/SearchField.scss +78 -0
- package/src/grapher/controls/SearchField.tsx +63 -0
- package/src/grapher/controls/SettingsMenu.scss +191 -0
- package/src/grapher/controls/SettingsMenu.tsx +399 -0
- package/src/grapher/controls/ShareMenu.scss +58 -0
- package/src/grapher/controls/ShareMenu.tsx +304 -0
- package/src/grapher/controls/SortIcon.tsx +39 -0
- package/src/grapher/controls/VerticalScrollContainer.tsx +263 -0
- package/src/grapher/controls/controlsRow/ControlsRow.tsx +168 -0
- package/src/grapher/controls/dropdown-icons.scss +4 -0
- package/src/grapher/controls/entityPicker/EntityPicker.scss +255 -0
- package/src/grapher/controls/entityPicker/EntityPicker.tsx +816 -0
- package/src/grapher/controls/entityPicker/EntityPickerConstants.ts +23 -0
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.scss +129 -0
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.tsx +463 -0
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelectorConstants.ts +3 -0
- package/src/grapher/controls/globalEntitySelector/readme.md +17 -0
- package/src/grapher/controls/settings/AbsRelToggle.tsx +64 -0
- package/src/grapher/controls/settings/AxisScaleToggle.tsx +53 -0
- package/src/grapher/controls/settings/FacetStrategySelector.tsx +110 -0
- package/src/grapher/controls/settings/FacetYDomainToggle.tsx +51 -0
- package/src/grapher/controls/settings/NoDataAreaToggle.tsx +38 -0
- package/src/grapher/controls/settings/ZoomToggle.tsx +36 -0
- package/src/grapher/core/EntitiesByRegionType.ts +174 -0
- package/src/grapher/core/EntityCodes.ts +19 -0
- package/src/grapher/core/EntityUrlBuilder.ts +200 -0
- package/src/grapher/core/FetchingGrapher.tsx +156 -0
- package/src/grapher/core/Grapher.tsx +760 -0
- package/src/grapher/core/GrapherAnalytics.ts +229 -0
- package/src/grapher/core/GrapherConstants.ts +173 -0
- package/src/grapher/core/GrapherState.tsx +3659 -0
- package/src/grapher/core/GrapherUrl.ts +184 -0
- package/src/grapher/core/GrapherUrlMigrations.ts +29 -0
- package/src/grapher/core/GrapherUseHelpers.tsx +147 -0
- package/src/grapher/core/LegacyToOwidTable.ts +841 -0
- package/src/grapher/core/grapher.entry.ts +5 -0
- package/src/grapher/core/grapher.scss +257 -0
- package/src/grapher/core/loadGrapherTableHelpers.ts +116 -0
- package/src/grapher/core/loadVariable.ts +104 -0
- package/src/grapher/core/relatedQuestion.ts +12 -0
- package/src/grapher/core/typography.scss +206 -0
- package/src/grapher/dataTable/DataTable.sample.ts +206 -0
- package/src/grapher/dataTable/DataTable.scss +249 -0
- package/src/grapher/dataTable/DataTable.tsx +1332 -0
- package/src/grapher/dataTable/DataTableConstants.ts +186 -0
- package/src/grapher/entitySelector/EntitySelector.scss +255 -0
- package/src/grapher/entitySelector/EntitySelector.tsx +1838 -0
- package/src/grapher/facet/FacetChart.tsx +943 -0
- package/src/grapher/facet/FacetChartConstants.ts +24 -0
- package/src/grapher/facet/FacetChartUtils.ts +51 -0
- package/src/grapher/facet/FacetMap.tsx +604 -0
- package/src/grapher/facet/FacetMapConstants.ts +23 -0
- package/src/grapher/facet/readme.md +13 -0
- package/src/grapher/focus/FocusArray.ts +79 -0
- package/src/grapher/footer/Footer.scss +63 -0
- package/src/grapher/footer/Footer.tsx +809 -0
- package/src/grapher/footer/FooterManager.ts +44 -0
- package/src/grapher/fullScreen/FullScreen.scss +11 -0
- package/src/grapher/fullScreen/FullScreen.tsx +61 -0
- package/src/grapher/header/Header.scss +35 -0
- package/src/grapher/header/Header.tsx +372 -0
- package/src/grapher/header/HeaderManager.ts +28 -0
- package/src/grapher/index.ts +157 -0
- package/src/grapher/interaction/InteractionState.ts +60 -0
- package/src/grapher/legend/HorizontalColorLegends.tsx +923 -0
- package/src/grapher/legend/LegendInteractionState.ts +40 -0
- package/src/grapher/legend/VerticalColorLegend.tsx +295 -0
- package/src/grapher/lineCharts/LineChart.tsx +968 -0
- package/src/grapher/lineCharts/LineChartConstants.ts +89 -0
- package/src/grapher/lineCharts/LineChartHelpers.ts +184 -0
- package/src/grapher/lineCharts/LineChartState.ts +394 -0
- package/src/grapher/lineCharts/LineChartThumbnail.tsx +437 -0
- package/src/grapher/lineCharts/Lines.tsx +258 -0
- package/src/grapher/lineLegend/LineLegend.tsx +723 -0
- package/src/grapher/lineLegend/LineLegendConstants.ts +9 -0
- package/src/grapher/lineLegend/LineLegendFilterAlgorithms.ts +143 -0
- package/src/grapher/lineLegend/LineLegendHelpers.ts +253 -0
- package/src/grapher/lineLegend/LineLegendTypes.ts +32 -0
- package/src/grapher/mapCharts/CanadaTopology.ts +17922 -0
- package/src/grapher/mapCharts/ChoroplethGlobe.tsx +949 -0
- package/src/grapher/mapCharts/ChoroplethMap.tsx +662 -0
- package/src/grapher/mapCharts/GeoFeatures.ts +184 -0
- package/src/grapher/mapCharts/GlobeController.ts +496 -0
- package/src/grapher/mapCharts/MapAnnotationPlacements.json +1040 -0
- package/src/grapher/mapCharts/MapAnnotationPlacements.ts +31 -0
- package/src/grapher/mapCharts/MapAnnotations.ts +723 -0
- package/src/grapher/mapCharts/MapChart.sample.ts +59 -0
- package/src/grapher/mapCharts/MapChart.scss +5 -0
- package/src/grapher/mapCharts/MapChart.tsx +720 -0
- package/src/grapher/mapCharts/MapChartConstants.ts +260 -0
- package/src/grapher/mapCharts/MapChartState.ts +416 -0
- package/src/grapher/mapCharts/MapChartThumbnail.tsx +25 -0
- package/src/grapher/mapCharts/MapComponents.tsx +338 -0
- package/src/grapher/mapCharts/MapConfig.ts +156 -0
- package/src/grapher/mapCharts/MapHelpers.ts +181 -0
- package/src/grapher/mapCharts/MapProjections.ts +49 -0
- package/src/grapher/mapCharts/MapSparkline.tsx +257 -0
- package/src/grapher/mapCharts/MapTooltip.scss +49 -0
- package/src/grapher/mapCharts/MapTooltip.tsx +409 -0
- package/src/grapher/mapCharts/MapTopology.ts +1766 -0
- package/src/grapher/mapCharts/d3-bboxCollide.js +204 -0
- package/src/grapher/mapCharts/d3-geo-projection.ts +198 -0
- package/src/grapher/modal/DownloadIcons.tsx +39 -0
- package/src/grapher/modal/DownloadModal.scss +300 -0
- package/src/grapher/modal/DownloadModal.tsx +1226 -0
- package/src/grapher/modal/EmbedModal.scss +40 -0
- package/src/grapher/modal/EmbedModal.tsx +160 -0
- package/src/grapher/modal/EntitySelectorModal.tsx +59 -0
- package/src/grapher/modal/Modal.scss +31 -0
- package/src/grapher/modal/Modal.tsx +90 -0
- package/src/grapher/modal/ModalHeader.scss +12 -0
- package/src/grapher/modal/ModalHeader.tsx +16 -0
- package/src/grapher/modal/SourcesDescriptions.scss +87 -0
- package/src/grapher/modal/SourcesDescriptions.tsx +89 -0
- package/src/grapher/modal/SourcesKeyDataTable.scss +49 -0
- package/src/grapher/modal/SourcesKeyDataTable.tsx +87 -0
- package/src/grapher/modal/SourcesModal.scss +301 -0
- package/src/grapher/modal/SourcesModal.tsx +568 -0
- package/src/grapher/noDataModal/NoDataModal.tsx +125 -0
- package/src/grapher/scatterCharts/ConnectedScatterLegend.tsx +143 -0
- package/src/grapher/scatterCharts/MultiColorPolyline.tsx +129 -0
- package/src/grapher/scatterCharts/NoDataSection.scss +14 -0
- package/src/grapher/scatterCharts/NoDataSection.tsx +56 -0
- package/src/grapher/scatterCharts/ScatterPlotChart.tsx +792 -0
- package/src/grapher/scatterCharts/ScatterPlotChartConstants.ts +157 -0
- package/src/grapher/scatterCharts/ScatterPlotChartState.ts +678 -0
- package/src/grapher/scatterCharts/ScatterPlotChartThumbnail.tsx +155 -0
- package/src/grapher/scatterCharts/ScatterPlotTooltip.tsx +560 -0
- package/src/grapher/scatterCharts/ScatterPoints.tsx +153 -0
- package/src/grapher/scatterCharts/ScatterPointsWithLabels.tsx +708 -0
- package/src/grapher/scatterCharts/ScatterSizeLegend.tsx +327 -0
- package/src/grapher/scatterCharts/ScatterUtils.ts +265 -0
- package/src/grapher/scatterCharts/Triangle.tsx +41 -0
- package/src/grapher/schema/README.md +33 -0
- package/src/grapher/schema/defaultGrapherConfig.ts +100 -0
- package/src/grapher/schema/grapher-schema.009.yaml +781 -0
- package/src/grapher/schema/migrations/helpers.ts +58 -0
- package/src/grapher/schema/migrations/migrate.ts +75 -0
- package/src/grapher/schema/migrations/migrations.ts +158 -0
- package/src/grapher/selection/MapSelectionArray.ts +99 -0
- package/src/grapher/selection/SelectionArray.ts +71 -0
- package/src/grapher/selection/readme.md +16 -0
- package/src/grapher/sidePanel/SidePanel.scss +10 -0
- package/src/grapher/sidePanel/SidePanel.tsx +23 -0
- package/src/grapher/slideInDrawer/SlideInDrawer.scss +57 -0
- package/src/grapher/slideInDrawer/SlideInDrawer.tsx +125 -0
- package/src/grapher/slideshowController/SlideShowController.tsx +43 -0
- package/src/grapher/slideshowController/readme.md +7 -0
- package/src/grapher/slopeCharts/MarkX.tsx +45 -0
- package/src/grapher/slopeCharts/Slope.tsx +102 -0
- package/src/grapher/slopeCharts/SlopeChart.tsx +1152 -0
- package/src/grapher/slopeCharts/SlopeChartConstants.ts +33 -0
- package/src/grapher/slopeCharts/SlopeChartHelpers.ts +73 -0
- package/src/grapher/slopeCharts/SlopeChartState.ts +392 -0
- package/src/grapher/slopeCharts/SlopeChartThumbnail.tsx +368 -0
- package/src/grapher/stackedCharts/AbstractStackedChartState.ts +370 -0
- package/src/grapher/stackedCharts/MarimekkoBars.tsx +190 -0
- package/src/grapher/stackedCharts/MarimekkoBarsForOneEntity.tsx +168 -0
- package/src/grapher/stackedCharts/MarimekkoChart.tsx +1144 -0
- package/src/grapher/stackedCharts/MarimekkoChartConstants.ts +112 -0
- package/src/grapher/stackedCharts/MarimekkoChartHelpers.ts +21 -0
- package/src/grapher/stackedCharts/MarimekkoChartState.ts +465 -0
- package/src/grapher/stackedCharts/MarimekkoChartThumbnail.tsx +168 -0
- package/src/grapher/stackedCharts/MarimekkoInternalLabels.tsx +124 -0
- package/src/grapher/stackedCharts/StackedAreaChart.tsx +678 -0
- package/src/grapher/stackedCharts/StackedAreaChartState.ts +34 -0
- package/src/grapher/stackedCharts/StackedAreaChartThumbnail.tsx +215 -0
- package/src/grapher/stackedCharts/StackedAreas.tsx +223 -0
- package/src/grapher/stackedCharts/StackedBarChart.tsx +619 -0
- package/src/grapher/stackedCharts/StackedBarChartState.ts +80 -0
- package/src/grapher/stackedCharts/StackedBarChartThumbnail.tsx +220 -0
- package/src/grapher/stackedCharts/StackedBarSegment.tsx +87 -0
- package/src/grapher/stackedCharts/StackedBars.tsx +102 -0
- package/src/grapher/stackedCharts/StackedConstants.ts +109 -0
- package/src/grapher/stackedCharts/StackedDiscreteBarChart.tsx +270 -0
- package/src/grapher/stackedCharts/StackedDiscreteBarChartState.ts +296 -0
- package/src/grapher/stackedCharts/StackedDiscreteBarChartThumbnail.tsx +27 -0
- package/src/grapher/stackedCharts/StackedDiscreteBars.tsx +648 -0
- package/src/grapher/stackedCharts/StackedUtils.ts +142 -0
- package/src/grapher/tabs/Tabs.scss +169 -0
- package/src/grapher/tabs/Tabs.tsx +54 -0
- package/src/grapher/tabs/TabsWithDropdown.scss +62 -0
- package/src/grapher/tabs/TabsWithDropdown.tsx +114 -0
- package/src/grapher/testData/OwidTestData.sample.ts +273 -0
- package/src/grapher/testData/OwidTestData.ts +64 -0
- package/src/grapher/timeline/TimelineComponent.scss +139 -0
- package/src/grapher/timeline/TimelineComponent.tsx +658 -0
- package/src/grapher/timeline/TimelineController.ts +368 -0
- package/src/grapher/timeline/readme.md +7 -0
- package/src/grapher/tooltip/Tooltip.scss +510 -0
- package/src/grapher/tooltip/Tooltip.tsx +294 -0
- package/src/grapher/tooltip/TooltipContents.tsx +383 -0
- package/src/grapher/tooltip/TooltipProps.ts +123 -0
- package/src/grapher/tooltip/TooltipState.ts +81 -0
- package/src/grapher/verticalLabels/VerticalLabels.tsx +31 -0
- package/src/grapher/verticalLabels/VerticalLabelsState.ts +154 -0
- package/src/index.ts +226 -0
- package/src/styles/charts.scss +15 -0
- package/src/types/NominalType.ts +30 -0
- package/src/types/OwidOrigin.ts +18 -0
- package/src/types/OwidSource.ts +9 -0
- package/src/types/OwidVariable.ts +133 -0
- package/src/types/OwidVariableDisplayConfigInterface.ts +49 -0
- package/src/types/analyticsTypes.ts +54 -0
- package/src/types/dbTypes/Tags.ts +11 -0
- package/src/types/domainTypes/Archive.ts +139 -0
- package/src/types/domainTypes/Author.ts +28 -0
- package/src/types/domainTypes/ContentGraph.ts +76 -0
- package/src/types/domainTypes/CoreTableTypes.ts +305 -0
- package/src/types/domainTypes/DeployStatus.ts +23 -0
- package/src/types/domainTypes/Layout.ts +34 -0
- package/src/types/domainTypes/Posts.ts +34 -0
- package/src/types/domainTypes/Search.ts +299 -0
- package/src/types/domainTypes/Site.ts +8 -0
- package/src/types/domainTypes/StaticViz.ts +64 -0
- package/src/types/domainTypes/Toc.ts +11 -0
- package/src/types/domainTypes/Tombstone.ts +19 -0
- package/src/types/domainTypes/Various.ts +79 -0
- package/src/types/gdocTypes/Gdoc.ts +280 -0
- package/src/types/grapherTypes/BinningStrategyTypes.ts +46 -0
- package/src/types/grapherTypes/GrapherConstants.ts +53 -0
- package/src/types/grapherTypes/GrapherTypes.ts +743 -0
- package/src/types/index.ts +316 -0
- package/src/types/wordpressTypes/WordpressTypes.ts +9 -0
- package/src/utils/Bounds.ts +439 -0
- package/src/utils/BrowserUtils.ts +12 -0
- package/src/utils/FuzzySearch.ts +74 -0
- package/src/utils/MultiDimDataPageConfig.ts +31 -0
- package/src/utils/OwidVariable.ts +82 -0
- package/src/utils/PointVector.ts +97 -0
- package/src/utils/PromiseCache.ts +36 -0
- package/src/utils/PromiseSwitcher.ts +52 -0
- package/src/utils/TimeBounds.ts +130 -0
- package/src/utils/Tippy.tsx +57 -0
- package/src/utils/Util.ts +2369 -0
- package/src/utils/archival/archivalDate.ts +48 -0
- package/src/utils/dayjs.ts +32 -0
- package/src/utils/formatValue.ts +242 -0
- package/src/utils/grapherConfigUtils.ts +81 -0
- package/src/utils/image.ts +225 -0
- package/src/utils/index.ts +318 -0
- package/src/utils/isPresent.ts +5 -0
- package/src/utils/metadataHelpers.ts +329 -0
- package/src/utils/persistable/Persistable.ts +82 -0
- package/src/utils/persistable/readme.md +50 -0
- package/src/utils/regions.json +5635 -0
- package/src/utils/regions.ts +463 -0
- package/src/utils/serializers.ts +16 -0
- package/src/utils/string.ts +42 -0
- package/src/utils/urls/Url.ts +195 -0
- package/src/utils/urls/UrlMigration.ts +10 -0
- package/src/utils/urls/UrlUtils.ts +54 -0
- package/src/utils/urls/readme.md +90 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as R from "remeda"
|
|
3
|
+
import { computed, makeObservable } from "mobx"
|
|
4
|
+
import { scaleLinear, ScaleLinear } from "d3-scale"
|
|
5
|
+
import { TextWrap, Halo } from "../../components/index.js"
|
|
6
|
+
import {
|
|
7
|
+
Color,
|
|
8
|
+
makeIdForHumanConsumption,
|
|
9
|
+
OwidVariableRoundingMode,
|
|
10
|
+
} from "../../utils/index.js"
|
|
11
|
+
import {
|
|
12
|
+
BASE_FONT_SIZE,
|
|
13
|
+
GRAPHER_FONT_SCALE_10,
|
|
14
|
+
GRAPHER_FONT_SCALE_11,
|
|
15
|
+
GRAPHER_TEXT_OUTLINE_FACTOR,
|
|
16
|
+
} from "../core/GrapherConstants"
|
|
17
|
+
import { CoreColumn } from "../../core-table/index.js"
|
|
18
|
+
import {
|
|
19
|
+
ScatterSeries,
|
|
20
|
+
SCATTER_POINT_MAX_RADIUS,
|
|
21
|
+
SCATTER_POINT_OPACITY,
|
|
22
|
+
SCATTER_POINT_STROKE_WIDTH,
|
|
23
|
+
SCATTER_POINT_DEFAULT_RADIUS,
|
|
24
|
+
} from "./ScatterPlotChartConstants"
|
|
25
|
+
import { darkenColorForText } from "../color/ColorUtils"
|
|
26
|
+
import {
|
|
27
|
+
GRAPHER_BACKGROUND_DEFAULT,
|
|
28
|
+
GRAPHER_DARK_TEXT,
|
|
29
|
+
GRAPHER_LIGHT_TEXT,
|
|
30
|
+
} from "../color/ColorConstants"
|
|
31
|
+
|
|
32
|
+
export interface ScatterSizeLegendManager {
|
|
33
|
+
sidebarWidth: number
|
|
34
|
+
sizeColumn: CoreColumn
|
|
35
|
+
sizeScale: ScaleLinear<number, number>
|
|
36
|
+
fontSize?: number
|
|
37
|
+
tooltipSeries?: ScatterSeries
|
|
38
|
+
backgroundColor?: Color
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const LEGEND_PADDING = 3
|
|
42
|
+
const LEGEND_CIRCLE_COLOR = "#bbb"
|
|
43
|
+
const LEGEND_VALUE_COLOR = "#444"
|
|
44
|
+
const LABEL_PADDING = 2
|
|
45
|
+
const LABEL_COLOR = GRAPHER_LIGHT_TEXT
|
|
46
|
+
const TITLE_COLOR = GRAPHER_DARK_TEXT
|
|
47
|
+
|
|
48
|
+
const MIN_FONT_SIZE = 9
|
|
49
|
+
|
|
50
|
+
export class ScatterSizeLegend {
|
|
51
|
+
manager: ScatterSizeLegendManager
|
|
52
|
+
constructor(manager: ScatterSizeLegendManager) {
|
|
53
|
+
makeObservable(this)
|
|
54
|
+
this.manager = manager
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@computed private get baseFontSize(): number {
|
|
58
|
+
return this.manager.fontSize ?? BASE_FONT_SIZE
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@computed private get maxWidth(): number {
|
|
62
|
+
return this.manager.sidebarWidth
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@computed private get ticks(): number[] {
|
|
66
|
+
const { sizeScale } = this.manager
|
|
67
|
+
const [domainStart, domainEnd] = sizeScale.domain()
|
|
68
|
+
if (domainStart === domainEnd) return [domainStart]
|
|
69
|
+
const [largestTick, ...restTicks] = sizeScale.ticks(6).toReversed()
|
|
70
|
+
if (largestTick === undefined) return []
|
|
71
|
+
const ticks = [largestTick]
|
|
72
|
+
restTicks.forEach((value) => {
|
|
73
|
+
if (
|
|
74
|
+
// make sure there is enough distance to prevent overlap with previous tick
|
|
75
|
+
sizeScale(value) <= sizeScale(R.last(ticks)!) - 6 &&
|
|
76
|
+
// don't go below the minimum tick radius
|
|
77
|
+
sizeScale(value) >= 6
|
|
78
|
+
) {
|
|
79
|
+
ticks.push(value)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
return ticks
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private getPointRadius(value: number | undefined): number {
|
|
86
|
+
if (value === undefined) return SCATTER_POINT_DEFAULT_RADIUS
|
|
87
|
+
return this.manager.sizeScale(value)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// input radius, output font size
|
|
91
|
+
@computed private get fontSizeFromRadius(): ScaleLinear<number, number> {
|
|
92
|
+
return (
|
|
93
|
+
scaleLinear()
|
|
94
|
+
// choosing the domain & range somewhat arbitrarily here,
|
|
95
|
+
// by experimenting visually with font sizes
|
|
96
|
+
.domain([6, SCATTER_POINT_MAX_RADIUS])
|
|
97
|
+
.range([8, 11])
|
|
98
|
+
.clamp(true)
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Since it's circular, this is both the width and the height of the legend.
|
|
103
|
+
@computed private get legendSize(): number {
|
|
104
|
+
if (this.ticks.length === 0) return 0
|
|
105
|
+
const maxRadius = R.last(this.manager.sizeScale.range()) ?? 0
|
|
106
|
+
// adding some padding to account for label sticking out at the top
|
|
107
|
+
return 2 * maxRadius + 2
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@computed private get label(): TextWrap {
|
|
111
|
+
const fontSize = Math.max(
|
|
112
|
+
MIN_FONT_SIZE,
|
|
113
|
+
GRAPHER_FONT_SCALE_10 * this.baseFontSize
|
|
114
|
+
)
|
|
115
|
+
return new TextWrap({
|
|
116
|
+
text: "Circles sized by",
|
|
117
|
+
// Allow text to _slightly_ go outside boundaries.
|
|
118
|
+
// Since we have padding left and right, this doesn't
|
|
119
|
+
// actually visibly overflow.
|
|
120
|
+
maxWidth: this.maxWidth + 12,
|
|
121
|
+
fontSize,
|
|
122
|
+
lineHeight: 1,
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@computed private get title(): TextWrap {
|
|
127
|
+
const fontSize = Math.max(
|
|
128
|
+
MIN_FONT_SIZE,
|
|
129
|
+
GRAPHER_FONT_SCALE_11 * this.baseFontSize
|
|
130
|
+
)
|
|
131
|
+
return new TextWrap({
|
|
132
|
+
text: this.manager.sizeColumn.displayName,
|
|
133
|
+
// Allow text to _slightly_ go outside boundaries.
|
|
134
|
+
// Since we have padding left and right, this doesn't
|
|
135
|
+
// actually visibly overflow.
|
|
136
|
+
maxWidth: this.maxWidth + 10,
|
|
137
|
+
fontSize,
|
|
138
|
+
fontWeight: 700,
|
|
139
|
+
lineHeight: 1,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@computed get width(): number {
|
|
144
|
+
return this.manager.sidebarWidth
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@computed get height(): number {
|
|
148
|
+
return (
|
|
149
|
+
this.legendSize +
|
|
150
|
+
LEGEND_PADDING +
|
|
151
|
+
this.label.height +
|
|
152
|
+
LABEL_PADDING +
|
|
153
|
+
this.title.height
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@computed private get highlight():
|
|
158
|
+
| { value: number | undefined; color: string }
|
|
159
|
+
| undefined {
|
|
160
|
+
const { tooltipSeries } = this.manager
|
|
161
|
+
if (
|
|
162
|
+
tooltipSeries?.points.length === 1 &&
|
|
163
|
+
R.first(tooltipSeries.points)?.size !== undefined
|
|
164
|
+
) {
|
|
165
|
+
return {
|
|
166
|
+
value: R.first(tooltipSeries.points)!.size,
|
|
167
|
+
color: tooltipSeries.color,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return undefined
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private renderLegend(targetX: number, targetY: number): React.ReactElement {
|
|
174
|
+
const { highlight } = this
|
|
175
|
+
const cx = targetX + this.maxWidth / 2
|
|
176
|
+
return (
|
|
177
|
+
<React.Fragment>
|
|
178
|
+
{this.ticks.map((value) => {
|
|
179
|
+
const radius = this.getPointRadius(value)
|
|
180
|
+
return (
|
|
181
|
+
<LegendItem
|
|
182
|
+
key={value}
|
|
183
|
+
label={this.manager.sizeColumn.formatValueShortWithAbbreviations(
|
|
184
|
+
value,
|
|
185
|
+
{
|
|
186
|
+
roundingMode:
|
|
187
|
+
OwidVariableRoundingMode.decimalPlaces,
|
|
188
|
+
}
|
|
189
|
+
)}
|
|
190
|
+
cx={cx}
|
|
191
|
+
cy={targetY + this.legendSize - radius}
|
|
192
|
+
circleRadius={radius}
|
|
193
|
+
circleStroke={
|
|
194
|
+
highlight ? "#ddd" : LEGEND_CIRCLE_COLOR
|
|
195
|
+
}
|
|
196
|
+
labelFontSize={this.fontSizeFromRadius(radius)}
|
|
197
|
+
labelFill={highlight ? "#bbb" : LEGEND_VALUE_COLOR}
|
|
198
|
+
backgroundColor={this.manager.backgroundColor}
|
|
199
|
+
/>
|
|
200
|
+
)
|
|
201
|
+
})}
|
|
202
|
+
{highlight && (
|
|
203
|
+
<LegendItem
|
|
204
|
+
key={highlight.value}
|
|
205
|
+
label={this.manager.sizeColumn.formatValueShort(
|
|
206
|
+
highlight.value
|
|
207
|
+
)}
|
|
208
|
+
cx={cx}
|
|
209
|
+
cy={
|
|
210
|
+
targetY +
|
|
211
|
+
this.legendSize -
|
|
212
|
+
this.getPointRadius(highlight.value)
|
|
213
|
+
}
|
|
214
|
+
circleFill={highlight.color}
|
|
215
|
+
circleStroke={"#333"}
|
|
216
|
+
circleStrokeWidth={SCATTER_POINT_STROKE_WIDTH}
|
|
217
|
+
circleRadius={this.getPointRadius(highlight.value)}
|
|
218
|
+
circleOpacity={SCATTER_POINT_OPACITY}
|
|
219
|
+
labelFontSize={12}
|
|
220
|
+
labelFill={darkenColorForText(highlight.color)}
|
|
221
|
+
labelFontWeight={700}
|
|
222
|
+
outsideLabel={true}
|
|
223
|
+
backgroundColor={this.manager.backgroundColor}
|
|
224
|
+
/>
|
|
225
|
+
)}
|
|
226
|
+
</React.Fragment>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
render(
|
|
231
|
+
targetX: number,
|
|
232
|
+
targetY: number,
|
|
233
|
+
renderOptions: React.SVGAttributes<SVGGElement> = {}
|
|
234
|
+
): React.ReactElement {
|
|
235
|
+
const centerX = targetX + this.maxWidth / 2
|
|
236
|
+
return (
|
|
237
|
+
<g id={makeIdForHumanConsumption("size-legend")} {...renderOptions}>
|
|
238
|
+
{this.renderLegend(targetX, targetY)}
|
|
239
|
+
{this.label.renderSVG(
|
|
240
|
+
centerX,
|
|
241
|
+
targetY + this.legendSize + LEGEND_PADDING,
|
|
242
|
+
{
|
|
243
|
+
textProps: {
|
|
244
|
+
fill: LABEL_COLOR,
|
|
245
|
+
textAnchor: "middle",
|
|
246
|
+
},
|
|
247
|
+
}
|
|
248
|
+
)}
|
|
249
|
+
{this.title.renderSVG(
|
|
250
|
+
centerX,
|
|
251
|
+
targetY +
|
|
252
|
+
this.legendSize +
|
|
253
|
+
LEGEND_PADDING +
|
|
254
|
+
this.label.height +
|
|
255
|
+
LABEL_PADDING,
|
|
256
|
+
{
|
|
257
|
+
textProps: {
|
|
258
|
+
fill: TITLE_COLOR,
|
|
259
|
+
textAnchor: "middle",
|
|
260
|
+
},
|
|
261
|
+
}
|
|
262
|
+
)}
|
|
263
|
+
</g>
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const LegendItem = ({
|
|
269
|
+
label,
|
|
270
|
+
cx,
|
|
271
|
+
cy,
|
|
272
|
+
circleRadius,
|
|
273
|
+
circleFill = "none",
|
|
274
|
+
circleStroke = LEGEND_CIRCLE_COLOR,
|
|
275
|
+
circleStrokeWidth = 1.25,
|
|
276
|
+
circleOpacity = 1,
|
|
277
|
+
labelFill = LEGEND_VALUE_COLOR,
|
|
278
|
+
labelFontSize,
|
|
279
|
+
labelFontWeight = 400,
|
|
280
|
+
outsideLabel = false,
|
|
281
|
+
backgroundColor = GRAPHER_BACKGROUND_DEFAULT,
|
|
282
|
+
}: {
|
|
283
|
+
label: string
|
|
284
|
+
cx: number
|
|
285
|
+
cy: number
|
|
286
|
+
circleRadius: number
|
|
287
|
+
circleFill?: string
|
|
288
|
+
circleStroke?: string
|
|
289
|
+
circleStrokeWidth?: number
|
|
290
|
+
circleOpacity?: number
|
|
291
|
+
labelFill?: string
|
|
292
|
+
labelFontSize: number
|
|
293
|
+
labelFontWeight?: number
|
|
294
|
+
outsideLabel?: boolean
|
|
295
|
+
backgroundColor?: Color
|
|
296
|
+
}): React.ReactElement => {
|
|
297
|
+
return (
|
|
298
|
+
<g>
|
|
299
|
+
<circle
|
|
300
|
+
cx={cx}
|
|
301
|
+
cy={cy}
|
|
302
|
+
r={circleRadius}
|
|
303
|
+
fill={circleFill}
|
|
304
|
+
stroke={circleStroke}
|
|
305
|
+
strokeWidth={circleStrokeWidth}
|
|
306
|
+
opacity={circleOpacity}
|
|
307
|
+
/>
|
|
308
|
+
<Halo
|
|
309
|
+
id={label}
|
|
310
|
+
outlineWidth={GRAPHER_TEXT_OUTLINE_FACTOR * labelFontSize}
|
|
311
|
+
outlineColor={backgroundColor}
|
|
312
|
+
>
|
|
313
|
+
<text
|
|
314
|
+
x={cx}
|
|
315
|
+
y={cy - circleRadius}
|
|
316
|
+
dy={outsideLabel ? "-.32em" : ".47em"}
|
|
317
|
+
fill={labelFill}
|
|
318
|
+
fontSize={labelFontSize}
|
|
319
|
+
fontWeight={labelFontWeight}
|
|
320
|
+
textAnchor="middle"
|
|
321
|
+
>
|
|
322
|
+
{label}
|
|
323
|
+
</text>
|
|
324
|
+
</Halo>
|
|
325
|
+
</g>
|
|
326
|
+
)
|
|
327
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import * as _ from "lodash-es"
|
|
2
|
+
import * as R from "remeda"
|
|
3
|
+
import {
|
|
4
|
+
Bounds,
|
|
5
|
+
ColumnSlug,
|
|
6
|
+
PointVector,
|
|
7
|
+
ValueRange,
|
|
8
|
+
} from "../../utils/index.js"
|
|
9
|
+
import {
|
|
10
|
+
SCATTER_LABEL_FONT_SIZE_FACTOR_WHEN_HIDDEN_LINES,
|
|
11
|
+
SCATTER_LINE_DEFAULT_WIDTH,
|
|
12
|
+
SCATTER_LINE_MAX_WIDTH,
|
|
13
|
+
SCATTER_POINT_DEFAULT_RADIUS,
|
|
14
|
+
SCATTER_POINT_MAX_RADIUS,
|
|
15
|
+
ScatterLabel,
|
|
16
|
+
ScatterRenderPoint,
|
|
17
|
+
ScatterRenderSeries,
|
|
18
|
+
} from "./ScatterPlotChartConstants"
|
|
19
|
+
import { BASE_FONT_SIZE } from "../core/GrapherConstants.js"
|
|
20
|
+
import { ScatterPlotChartState } from "./ScatterPlotChartState"
|
|
21
|
+
import { OwidTable } from "../../core-table/index.js"
|
|
22
|
+
|
|
23
|
+
export const labelPriority = (label: ScatterLabel): number => {
|
|
24
|
+
let priority = label.fontSize
|
|
25
|
+
|
|
26
|
+
if (label.series.isHover) priority += 10000
|
|
27
|
+
if (label.series.isFocus) priority += 1000
|
|
28
|
+
if (label.isEnd) priority += 100
|
|
29
|
+
|
|
30
|
+
return priority
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create the start year label for a series
|
|
34
|
+
export const makeStartLabel = (
|
|
35
|
+
series: ScatterRenderSeries,
|
|
36
|
+
isSubtleForeground: boolean,
|
|
37
|
+
hideConnectedScatterLines: boolean,
|
|
38
|
+
baseFontSize: number
|
|
39
|
+
): ScatterLabel | undefined => {
|
|
40
|
+
// No room to label the year if it's a single point
|
|
41
|
+
if (!series.isForeground || series.points.length <= 1) return undefined
|
|
42
|
+
|
|
43
|
+
const fontSize = hideConnectedScatterLines
|
|
44
|
+
? SCATTER_LABEL_FONT_SIZE_FACTOR_WHEN_HIDDEN_LINES * baseFontSize
|
|
45
|
+
: series.isForeground
|
|
46
|
+
? isSubtleForeground
|
|
47
|
+
? (8 / BASE_FONT_SIZE) * baseFontSize
|
|
48
|
+
: (9 / BASE_FONT_SIZE) * baseFontSize
|
|
49
|
+
: (7 / BASE_FONT_SIZE) * baseFontSize
|
|
50
|
+
const firstValue = series.points[0]
|
|
51
|
+
const nextValue = series.points[1]
|
|
52
|
+
const nextSegment = nextValue.position.subtract(firstValue.position)
|
|
53
|
+
|
|
54
|
+
const pos = firstValue.position.subtract(nextSegment.normalize().times(5))
|
|
55
|
+
let bounds = Bounds.forText(firstValue.label, {
|
|
56
|
+
x: pos.x,
|
|
57
|
+
y: pos.y,
|
|
58
|
+
fontSize: fontSize,
|
|
59
|
+
})
|
|
60
|
+
if (pos.x < firstValue.position.x)
|
|
61
|
+
bounds = new Bounds(
|
|
62
|
+
bounds.x - bounds.width + 2,
|
|
63
|
+
bounds.y,
|
|
64
|
+
bounds.width,
|
|
65
|
+
bounds.height
|
|
66
|
+
)
|
|
67
|
+
if (pos.y > firstValue.position.y)
|
|
68
|
+
bounds = new Bounds(
|
|
69
|
+
bounds.x,
|
|
70
|
+
bounds.y + bounds.height / 2,
|
|
71
|
+
bounds.width,
|
|
72
|
+
bounds.height
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
text: firstValue.label,
|
|
77
|
+
fontSize,
|
|
78
|
+
fontWeight: 400,
|
|
79
|
+
color: firstValue.color,
|
|
80
|
+
bounds,
|
|
81
|
+
series,
|
|
82
|
+
isStart: true,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Make labels for the points between start and end on a series
|
|
87
|
+
// Positioned using normals of the line segments
|
|
88
|
+
export const makeMidLabels = (
|
|
89
|
+
series: ScatterRenderSeries,
|
|
90
|
+
isSubtleForeground: boolean,
|
|
91
|
+
hideConnectedScatterLines: boolean,
|
|
92
|
+
baseFontSize: number
|
|
93
|
+
): ScatterLabel[] => {
|
|
94
|
+
if (
|
|
95
|
+
!series.isForeground ||
|
|
96
|
+
series.points.length <= 1 ||
|
|
97
|
+
(!series.isHover && isSubtleForeground)
|
|
98
|
+
)
|
|
99
|
+
return []
|
|
100
|
+
|
|
101
|
+
const fontSize = hideConnectedScatterLines
|
|
102
|
+
? SCATTER_LABEL_FONT_SIZE_FACTOR_WHEN_HIDDEN_LINES * baseFontSize
|
|
103
|
+
: series.isForeground
|
|
104
|
+
? isSubtleForeground
|
|
105
|
+
? (8 / BASE_FONT_SIZE) * baseFontSize
|
|
106
|
+
: (9 / BASE_FONT_SIZE) * baseFontSize
|
|
107
|
+
: (7 / BASE_FONT_SIZE) * baseFontSize
|
|
108
|
+
const fontWeight = 400
|
|
109
|
+
|
|
110
|
+
// label all the way to the end for the tooltip series, otherwise to n-1
|
|
111
|
+
const lastIndex = series.isTooltip && !series.isFocus ? Infinity : -1
|
|
112
|
+
|
|
113
|
+
return series.points.slice(1, lastIndex).map((v, i) => {
|
|
114
|
+
const prevPos = i > 0 && series.points[i - 1].position
|
|
115
|
+
const prevSegment = prevPos && v.position.subtract(prevPos)
|
|
116
|
+
const nextPos = series.points[i + 1].position
|
|
117
|
+
const nextSegment = nextPos.subtract(v.position)
|
|
118
|
+
|
|
119
|
+
let pos = v.position
|
|
120
|
+
if (prevPos && prevSegment) {
|
|
121
|
+
const normals = prevSegment
|
|
122
|
+
.add(nextSegment)
|
|
123
|
+
.normalize()
|
|
124
|
+
.normals()
|
|
125
|
+
.map((x) => x.times(5))
|
|
126
|
+
const potentialSpots = normals.map((n) => v.position.add(n))
|
|
127
|
+
pos = _.maxBy(potentialSpots, (p) => {
|
|
128
|
+
return (
|
|
129
|
+
PointVector.distance(p, prevPos) +
|
|
130
|
+
PointVector.distance(p, nextPos)
|
|
131
|
+
)
|
|
132
|
+
}) as PointVector
|
|
133
|
+
} else {
|
|
134
|
+
pos = v.position.subtract(nextSegment.normalize().times(5))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let bounds = Bounds.forText(v.label, {
|
|
138
|
+
x: pos.x,
|
|
139
|
+
y: pos.y,
|
|
140
|
+
fontSize: fontSize,
|
|
141
|
+
fontWeight: fontWeight,
|
|
142
|
+
})
|
|
143
|
+
if (pos.x < v.position.x)
|
|
144
|
+
bounds = new Bounds(
|
|
145
|
+
bounds.x - bounds.width + 2,
|
|
146
|
+
bounds.y,
|
|
147
|
+
bounds.width,
|
|
148
|
+
bounds.height
|
|
149
|
+
)
|
|
150
|
+
if (pos.y > v.position.y)
|
|
151
|
+
bounds = new Bounds(
|
|
152
|
+
bounds.x,
|
|
153
|
+
bounds.y + bounds.height / 2,
|
|
154
|
+
bounds.width,
|
|
155
|
+
bounds.height
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
text: v.label,
|
|
160
|
+
fontSize,
|
|
161
|
+
fontWeight,
|
|
162
|
+
color: v.color,
|
|
163
|
+
bounds,
|
|
164
|
+
series,
|
|
165
|
+
isMid: true,
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Make the end label (entity label) for a series. Will be pushed
|
|
171
|
+
// slightly out based on the direction of the series if multiple values
|
|
172
|
+
// are present
|
|
173
|
+
// This is also the one label in the case of a single point
|
|
174
|
+
export const makeEndLabel = (
|
|
175
|
+
series: ScatterRenderSeries,
|
|
176
|
+
isSubtleForeground: boolean,
|
|
177
|
+
hideConnectedScatterLines: boolean,
|
|
178
|
+
baseFontSize: number
|
|
179
|
+
): ScatterLabel => {
|
|
180
|
+
const lastValue = R.last(series.points) as ScatterRenderPoint
|
|
181
|
+
const lastPos = lastValue.position
|
|
182
|
+
const fontSize = hideConnectedScatterLines
|
|
183
|
+
? SCATTER_LABEL_FONT_SIZE_FACTOR_WHEN_HIDDEN_LINES * baseFontSize
|
|
184
|
+
: series.fontSize *
|
|
185
|
+
(series.isForeground ? (isSubtleForeground ? 1.2 : 1.3) : 1.1)
|
|
186
|
+
const fontWeight =
|
|
187
|
+
series.isForeground && !hideConnectedScatterLines ? 700 : 400
|
|
188
|
+
|
|
189
|
+
let offsetVector = PointVector.up
|
|
190
|
+
if (series.points.length > 1) {
|
|
191
|
+
const prevValue = series.points[series.points.length - 2]
|
|
192
|
+
const prevPos = prevValue.position
|
|
193
|
+
offsetVector = lastPos.subtract(prevPos)
|
|
194
|
+
}
|
|
195
|
+
series.offsetVector = offsetVector
|
|
196
|
+
|
|
197
|
+
const labelPos = lastPos.add(
|
|
198
|
+
offsetVector
|
|
199
|
+
.normalize()
|
|
200
|
+
.times(series.points.length === 1 ? lastValue.size + 1 : 5)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
let labelBounds = Bounds.forText(series.text, {
|
|
204
|
+
x: labelPos.x,
|
|
205
|
+
y: labelPos.y,
|
|
206
|
+
fontSize: fontSize,
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
if (labelPos.x < lastPos.x)
|
|
210
|
+
labelBounds = labelBounds.set({
|
|
211
|
+
x: labelBounds.x - labelBounds.width,
|
|
212
|
+
})
|
|
213
|
+
if (labelPos.y > lastPos.y)
|
|
214
|
+
labelBounds = labelBounds.set({
|
|
215
|
+
y: labelBounds.y + labelBounds.height / 2,
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
text:
|
|
220
|
+
hideConnectedScatterLines && series.isForeground
|
|
221
|
+
? lastValue.label
|
|
222
|
+
: series.isTooltip && !series.isFocus
|
|
223
|
+
? "" // don't doubly label the series name when the tooltip is visible
|
|
224
|
+
: series.text,
|
|
225
|
+
fontSize,
|
|
226
|
+
fontWeight,
|
|
227
|
+
color: lastValue.color,
|
|
228
|
+
bounds: labelBounds,
|
|
229
|
+
series,
|
|
230
|
+
isEnd: true,
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function toSizeRange(
|
|
235
|
+
chartState: ScatterPlotChartState,
|
|
236
|
+
bounds: Bounds
|
|
237
|
+
): [number, number] {
|
|
238
|
+
if (chartState.sizeColumn.isMissing) {
|
|
239
|
+
// if the size column is missing, we want all points/lines to have the same width
|
|
240
|
+
return chartState.isConnected
|
|
241
|
+
? [SCATTER_LINE_DEFAULT_WIDTH, SCATTER_LINE_DEFAULT_WIDTH]
|
|
242
|
+
: [SCATTER_POINT_DEFAULT_RADIUS, SCATTER_POINT_DEFAULT_RADIUS]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const maxLineWidth = SCATTER_LINE_MAX_WIDTH
|
|
246
|
+
const maxPointRadius = Math.min(
|
|
247
|
+
SCATTER_POINT_MAX_RADIUS,
|
|
248
|
+
_.round(Math.min(bounds.width, bounds.height) * 0.06, 1)
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
return chartState.isConnected
|
|
252
|
+
? // Note that the scale starts at 0.
|
|
253
|
+
// When using the scale to plot marks, we need to make sure the minimums
|
|
254
|
+
// (e.g. `SCATTER_POINT_MIN_RADIUS`) are respected.
|
|
255
|
+
[0, maxLineWidth]
|
|
256
|
+
: [0, maxPointRadius]
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function computeSizeDomain(
|
|
260
|
+
table: OwidTable,
|
|
261
|
+
slug: ColumnSlug
|
|
262
|
+
): ValueRange {
|
|
263
|
+
const sizeValues = table.get(slug).values.filter(_.isNumber)
|
|
264
|
+
return [0, _.max(sizeValues) ?? 1]
|
|
265
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as _ from "lodash-es"
|
|
3
|
+
|
|
4
|
+
type TriangleProps = Readonly<{
|
|
5
|
+
cx: number
|
|
6
|
+
cy: number
|
|
7
|
+
r: number
|
|
8
|
+
fill?: string
|
|
9
|
+
stroke?: string
|
|
10
|
+
strokeWidth?: number
|
|
11
|
+
rotation?: number
|
|
12
|
+
}> &
|
|
13
|
+
React.SVGProps<SVGPolygonElement>
|
|
14
|
+
|
|
15
|
+
export const Triangle = (props: TriangleProps): React.ReactElement => {
|
|
16
|
+
const { cx, cy, r, rotation } = props
|
|
17
|
+
const x = cx - r,
|
|
18
|
+
y = cy - r
|
|
19
|
+
const points = [
|
|
20
|
+
[x, y + r * 2],
|
|
21
|
+
[x + (r * 2) / 2, y],
|
|
22
|
+
[x + r * 2, y + r * 2],
|
|
23
|
+
]
|
|
24
|
+
const rotationRounded = rotation
|
|
25
|
+
? [rotation, cx, cy].map((v) => _.round(v, 2))
|
|
26
|
+
: undefined
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<polygon
|
|
30
|
+
points={points
|
|
31
|
+
.map((p) => `${p[0].toFixed(2)},${p[1].toFixed(2)}`)
|
|
32
|
+
.join(" ")}
|
|
33
|
+
transform={
|
|
34
|
+
rotationRounded
|
|
35
|
+
? `rotate(${rotationRounded.join(", ")})`
|
|
36
|
+
: undefined
|
|
37
|
+
}
|
|
38
|
+
{..._.omit(props, "rotation")}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
This folder contains the JSON schema for the configuration of Grapher.
|
|
2
|
+
|
|
3
|
+
## How to evolve the schema
|
|
4
|
+
|
|
5
|
+
The schema is versioned. There is one yaml file with a version number. For nonbreaking changes (e.g. additions of optional fields) you can just
|
|
6
|
+
edit the yaml file as is. A github action will then generate a .latest.yaml and two json files (one .latest.json and one with the version number.json)
|
|
7
|
+
and upload them to S3 so they can be accessed publicly.
|
|
8
|
+
|
|
9
|
+
If you update the default value of an existing property or you add a new property with a default value, make sure to regenerate the default object from the schema and save it to `defaultGrapherConfig.ts` (see below).
|
|
10
|
+
|
|
11
|
+
Breaking changes should be done by renaming the schema file to an increased version number. Make sure to also rename the authorative url
|
|
12
|
+
inside the schema file (the "$id" field at the top level) to point to the new version number json. Then write the migrations from the last to
|
|
13
|
+
the current version of the schema, including the migration of pointing to the URL of the new schema version.s
|
|
14
|
+
|
|
15
|
+
Checklist for breaking changes:
|
|
16
|
+
|
|
17
|
+
- Rename the schema file to an increased version number
|
|
18
|
+
- Rename the authorative url inside the schema file to point to the new version number json
|
|
19
|
+
- Write the migrations from the last to the current version of the schema, including the migration of pointing to the URL of the new schema version
|
|
20
|
+
- Regenerate the default object from the schema and save it to `defaultGrapherConfig.ts` (see below)
|
|
21
|
+
- Write a migration to update the `chart_configs.full` column in the database for all stand-alone charts
|
|
22
|
+
- Write a migration to update configs in code (see `migrations/migrations.ts`)
|
|
23
|
+
- Update the hardcoded default schema version in ETL
|
|
24
|
+
|
|
25
|
+
To regenerate `defaultGrapherConfig.ts` from the schema, replace `XXX` with the current schema version number and run:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# generate json from the yaml schema
|
|
29
|
+
nu -c 'open packages/@ourworldindata/grapher/src/schema/grapher-schema.XXX.yaml | to json' > packages/@ourworldindata/grapher/src/schema/grapher-schema.XXX.json
|
|
30
|
+
|
|
31
|
+
# generate the default object from the schema
|
|
32
|
+
yarn tsx --tsconfig tsconfig.tsx.json devTools/schema/generate-default-object-from-schema.ts packages/@ourworldindata/grapher/src/schema/grapher-schema.XXX.json --save-ts packages/@ourworldindata/grapher/src/schema/defaultGrapherConfig.ts
|
|
33
|
+
```
|