@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,24 @@
|
|
|
1
|
+
import { ChartSeries } from "../chart/ChartInterface"
|
|
2
|
+
import { ChartManager } from "../chart/ChartManager"
|
|
3
|
+
import { GrapherChartType } from "../../types/index.js"
|
|
4
|
+
import { Bounds } from "../../utils/index.js"
|
|
5
|
+
|
|
6
|
+
export interface FacetChartManager extends ChartManager {
|
|
7
|
+
canSelectMultipleEntities?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FacetChartProps {
|
|
11
|
+
bounds?: Bounds
|
|
12
|
+
chartTypeName?: GrapherChartType
|
|
13
|
+
manager: FacetChartManager
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FacetSeries extends ChartSeries {
|
|
17
|
+
manager: Partial<ChartManager>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PlacedFacetSeries extends FacetSeries {
|
|
21
|
+
manager: ChartManager
|
|
22
|
+
bounds: Bounds
|
|
23
|
+
contentBounds: Bounds
|
|
24
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { BASE_FONT_SIZE, GRAPHER_FONT_SCALE_10 } from "../core/GrapherConstants"
|
|
2
|
+
|
|
3
|
+
// not sure if we want to do something more sophisticated
|
|
4
|
+
export const getFontSize = (
|
|
5
|
+
containerWidth: number,
|
|
6
|
+
count: number,
|
|
7
|
+
baseFontSize = BASE_FONT_SIZE,
|
|
8
|
+
minSize = 8
|
|
9
|
+
): number => {
|
|
10
|
+
// Pick a fixed font size for very small charts
|
|
11
|
+
if (containerWidth < 300) return GRAPHER_FONT_SCALE_10 * baseFontSize
|
|
12
|
+
|
|
13
|
+
// Scale the font size based on the number of series otherwise
|
|
14
|
+
if (count <= 2) return Math.max(minSize, baseFontSize * (15 / 16))
|
|
15
|
+
if (count <= 4) return Math.max(minSize, baseFontSize * (14 / 16))
|
|
16
|
+
if (count <= 9) return Math.max(minSize, baseFontSize * (13 / 16))
|
|
17
|
+
if (count <= 16) return Math.max(minSize, baseFontSize * (12 / 16))
|
|
18
|
+
if (count <= 25) return Math.max(minSize, baseFontSize * (11 / 16))
|
|
19
|
+
return minSize
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getLabelPadding = (baseFontSize: number): number =>
|
|
23
|
+
0.5 * baseFontSize
|
|
24
|
+
|
|
25
|
+
export const getFacetGridPadding = ({
|
|
26
|
+
baseFontSize,
|
|
27
|
+
shouldAddRowPadding = true,
|
|
28
|
+
shouldAddColumnPadding = true,
|
|
29
|
+
}: {
|
|
30
|
+
baseFontSize: number
|
|
31
|
+
shouldAddRowPadding?: boolean
|
|
32
|
+
shouldAddColumnPadding?: boolean
|
|
33
|
+
}): { rowPadding: number; columnPadding: number; outerPadding: number } => {
|
|
34
|
+
const labelHeight = baseFontSize
|
|
35
|
+
const labelPadding = getLabelPadding(baseFontSize)
|
|
36
|
+
|
|
37
|
+
const rowPadding = shouldAddRowPadding ? baseFontSize : 0
|
|
38
|
+
const columnPadding = shouldAddColumnPadding ? baseFontSize : 0
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
rowPadding: Math.round(labelHeight + labelPadding + rowPadding),
|
|
42
|
+
columnPadding: Math.round(columnPadding),
|
|
43
|
+
outerPadding: 0,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const calculateAspectRatio = (width: number, height: number): number => {
|
|
48
|
+
const aspectRatio = width / height // can be NaN if height is 0, which can happen when the chart is temporarily hidden
|
|
49
|
+
if (isNaN(aspectRatio)) return 1
|
|
50
|
+
return aspectRatio
|
|
51
|
+
}
|
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { observer } from "mobx-react"
|
|
3
|
+
import {
|
|
4
|
+
Bounds,
|
|
5
|
+
GridParameters,
|
|
6
|
+
HorizontalAlign,
|
|
7
|
+
Color,
|
|
8
|
+
makeIdForHumanConsumption,
|
|
9
|
+
exposeInstanceOnWindow,
|
|
10
|
+
SplitBoundsPadding,
|
|
11
|
+
} from "../../utils/index.js"
|
|
12
|
+
import { action, computed, makeObservable, observable } from "mobx"
|
|
13
|
+
import {
|
|
14
|
+
BASE_FONT_SIZE,
|
|
15
|
+
DEFAULT_GRAPHER_BOUNDS,
|
|
16
|
+
GRAPHER_FONT_SCALE_18,
|
|
17
|
+
} from "../core/GrapherConstants"
|
|
18
|
+
import {
|
|
19
|
+
ChartErrorInfo,
|
|
20
|
+
GRAPHER_MAP_TYPE,
|
|
21
|
+
GrapherInteractionEvent,
|
|
22
|
+
MapRegionName,
|
|
23
|
+
Time,
|
|
24
|
+
} from "../../types/index.js"
|
|
25
|
+
import {
|
|
26
|
+
calculateAspectRatio,
|
|
27
|
+
getFacetGridPadding,
|
|
28
|
+
getLabelPadding as getFacetLabelPadding,
|
|
29
|
+
} from "./FacetChartUtils"
|
|
30
|
+
import {
|
|
31
|
+
FacetMapManager,
|
|
32
|
+
MapFacetSeries,
|
|
33
|
+
FacetMapProps,
|
|
34
|
+
PlacedMapFacetSeries,
|
|
35
|
+
} from "./FacetMapConstants"
|
|
36
|
+
import { OwidTable } from "../../core-table/index.js"
|
|
37
|
+
import {
|
|
38
|
+
HorizontalCategoricalColorLegend,
|
|
39
|
+
HorizontalColorLegendManager,
|
|
40
|
+
HorizontalNumericColorLegend,
|
|
41
|
+
} from "../legend/HorizontalColorLegends"
|
|
42
|
+
import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"
|
|
43
|
+
import { GRAPHER_DARK_TEXT, GRAY_30 } from "../color/ColorConstants"
|
|
44
|
+
import {
|
|
45
|
+
LegendInteractionState,
|
|
46
|
+
LegendStyleConfig,
|
|
47
|
+
} from "../legend/LegendInteractionState"
|
|
48
|
+
import {
|
|
49
|
+
MAP_LEGEND_MAX_WIDTH_RATIO,
|
|
50
|
+
MapChart,
|
|
51
|
+
PADDING_BELOW_MAP_LEGEND,
|
|
52
|
+
PADDING_BETWEEN_MAP_AND_LEGEND,
|
|
53
|
+
PADDING_BETWEEN_MAP_LEGENDS,
|
|
54
|
+
} from "../mapCharts/MapChart"
|
|
55
|
+
import { ChartComponent, makeChartInstance } from "../chart/ChartTypeMap"
|
|
56
|
+
import {
|
|
57
|
+
MAP_VIEWPORT_FACETED_WORLD,
|
|
58
|
+
MAP_VIEWPORTS,
|
|
59
|
+
MapChartManager,
|
|
60
|
+
MapViewport,
|
|
61
|
+
} from "../mapCharts/MapChartConstants"
|
|
62
|
+
import { ChartState } from "../chart/ChartInterface.js"
|
|
63
|
+
import { MapConfig } from "../mapCharts/MapConfig"
|
|
64
|
+
|
|
65
|
+
@observer
|
|
66
|
+
export class FacetMap
|
|
67
|
+
extends React.Component<FacetMapProps>
|
|
68
|
+
implements ChartState, HorizontalColorLegendManager
|
|
69
|
+
{
|
|
70
|
+
private legendHoverBin: ColorScaleBin | undefined = undefined
|
|
71
|
+
|
|
72
|
+
constructor(props: FacetMapProps) {
|
|
73
|
+
super(props)
|
|
74
|
+
makeObservable<FacetMap, "legendHoverBin">(this, {
|
|
75
|
+
legendHoverBin: observable.ref,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
transformTable(table: OwidTable): OwidTable {
|
|
80
|
+
return table
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@computed get inputTable(): OwidTable {
|
|
84
|
+
return this.manager.table
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@computed get transformedTable(): OwidTable {
|
|
88
|
+
return (
|
|
89
|
+
this.manager.transformedTable ??
|
|
90
|
+
this.transformTable(this.inputTable)
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@computed private get manager(): FacetMapManager {
|
|
95
|
+
return this.props.manager
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@computed private get table(): OwidTable {
|
|
99
|
+
return this.manager.table
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@computed private get transformedTableFromGrapher(): OwidTable | undefined {
|
|
103
|
+
return this.manager.transformedTable
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@computed get isStatic(): boolean {
|
|
107
|
+
return !!this.manager.isStatic
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@computed get errorInfo(): ChartErrorInfo {
|
|
111
|
+
if (this.manager.startTime === undefined)
|
|
112
|
+
return { reason: "No start time selected" }
|
|
113
|
+
|
|
114
|
+
if (this.manager.endTime === undefined)
|
|
115
|
+
return { reason: "No end time selected" }
|
|
116
|
+
|
|
117
|
+
return { reason: "" }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@computed private get startTime(): Time {
|
|
121
|
+
return this.manager.startTime!
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@computed private get endTime(): Time {
|
|
125
|
+
return this.manager.endTime!
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@computed private get bounds(): Bounds {
|
|
129
|
+
const bounds = this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
|
|
130
|
+
return bounds.padTop(6)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@computed private get facetsContainerBounds(): Bounds {
|
|
134
|
+
return (
|
|
135
|
+
this.bounds
|
|
136
|
+
// Make space for facet labels
|
|
137
|
+
.padTop(this.labelHeight + this.labelPadding)
|
|
138
|
+
// Make space for the legend
|
|
139
|
+
.padBottom(
|
|
140
|
+
this.legendHeight +
|
|
141
|
+
PADDING_BETWEEN_MAP_AND_LEGEND +
|
|
142
|
+
PADDING_BELOW_MAP_LEGEND
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@computed private get targetTimes(): [Time, Time] {
|
|
148
|
+
return [this.startTime, this.endTime]
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@computed get fontSize(): number {
|
|
152
|
+
return this.manager.fontSize ?? BASE_FONT_SIZE
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@computed private get facetFontSize(): number {
|
|
156
|
+
return Math.floor(this.fontSize * GRAPHER_FONT_SCALE_18)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@computed private get mapConfig(): MapConfig {
|
|
160
|
+
return this.manager.mapConfig ?? new MapConfig()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@computed private get mapViewport(): MapViewport {
|
|
164
|
+
const { region } = this.mapConfig
|
|
165
|
+
|
|
166
|
+
// Use a custom viewport for the World map that zooms in a little bit to make best use of the space
|
|
167
|
+
if (region === MapRegionName.World) return MAP_VIEWPORT_FACETED_WORLD
|
|
168
|
+
|
|
169
|
+
return MAP_VIEWPORTS[region]
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private getGridParams(bounds: Bounds): GridParameters {
|
|
173
|
+
// We determine the preferred layout (horizontal vs vertical)
|
|
174
|
+
// by comparing which orientation produces an aspect ratio closest to
|
|
175
|
+
// the map's natural aspect ratio. The globe uses the horizontal layout.
|
|
176
|
+
|
|
177
|
+
const horizontalLayout = { rows: 1, columns: 2, count: 2 }
|
|
178
|
+
const verticalLayout = { rows: 2, columns: 1, count: 2 }
|
|
179
|
+
|
|
180
|
+
if (this.mapConfig.globe.isActive)
|
|
181
|
+
return bounds.width > bounds.height
|
|
182
|
+
? horizontalLayout
|
|
183
|
+
: verticalLayout
|
|
184
|
+
|
|
185
|
+
const mapAspectRatio = this.mapViewport.ratio
|
|
186
|
+
|
|
187
|
+
// If the faceted maps are side-by-side
|
|
188
|
+
const horizontalLayoutAspectRatio = calculateAspectRatio(
|
|
189
|
+
bounds.width / 2,
|
|
190
|
+
bounds.height
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// If the faceted maps are stacked vertically
|
|
194
|
+
const verticalLayoutAspectRatio = calculateAspectRatio(
|
|
195
|
+
bounds.width,
|
|
196
|
+
bounds.height / 2
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
const horizontalDiff = Math.abs(
|
|
200
|
+
Math.log2(mapAspectRatio / horizontalLayoutAspectRatio)
|
|
201
|
+
)
|
|
202
|
+
const verticalDiff = Math.abs(
|
|
203
|
+
Math.log2(mapAspectRatio / verticalLayoutAspectRatio)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
// World maps tend to look better side-by-side, so we give the
|
|
207
|
+
// horizontal layout an advantage when the region is World
|
|
208
|
+
const bias = this.mapConfig.region === MapRegionName.World ? 0.5 : 0
|
|
209
|
+
|
|
210
|
+
return horizontalDiff - bias <= verticalDiff
|
|
211
|
+
? horizontalLayout
|
|
212
|
+
: verticalLayout
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@computed private get facetGridPadding(): SplitBoundsPadding {
|
|
216
|
+
return getFacetGridPadding({
|
|
217
|
+
baseFontSize: this.facetFontSize,
|
|
218
|
+
shouldAddRowPadding: false,
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@computed private get labelHeight(): number {
|
|
223
|
+
return this.facetFontSize
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@computed private get labelPadding(): number {
|
|
227
|
+
return getFacetLabelPadding(this.facetFontSize)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@computed get series(): MapFacetSeries[] {
|
|
231
|
+
return this.targetTimes.map((time) => ({
|
|
232
|
+
seriesName: this.table.timeColumn.formatTime(time),
|
|
233
|
+
// Required for a ChartSeries, but isn't meaningful for facets
|
|
234
|
+
color: "none",
|
|
235
|
+
// Only set overrides for this facet. Default properties are set elsewhere.
|
|
236
|
+
manager: { targetTime: time },
|
|
237
|
+
}))
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@action.bound logGrapherInteractionEvent(
|
|
241
|
+
action: GrapherInteractionEvent,
|
|
242
|
+
target?: string
|
|
243
|
+
): void {
|
|
244
|
+
this.manager.analytics?.logGrapherInteractionEvent(action, {
|
|
245
|
+
...this.manager.analyticsContext,
|
|
246
|
+
target,
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@computed private get intermediatePlacedSeries(): PlacedMapFacetSeries[] {
|
|
251
|
+
const {
|
|
252
|
+
manager,
|
|
253
|
+
series,
|
|
254
|
+
table,
|
|
255
|
+
transformedTableFromGrapher,
|
|
256
|
+
targetTimes,
|
|
257
|
+
mapViewport,
|
|
258
|
+
facetFontSize,
|
|
259
|
+
legendHoverBin,
|
|
260
|
+
logGrapherInteractionEvent,
|
|
261
|
+
} = this
|
|
262
|
+
|
|
263
|
+
// We are using `bounds` instead of `facetsContainerBounds` because the legend
|
|
264
|
+
// is not yet created, and it is derived from the intermediate chart series.
|
|
265
|
+
const bounds = this.bounds
|
|
266
|
+
const gridBoundsArr = bounds.grid(
|
|
267
|
+
this.getGridParams(bounds),
|
|
268
|
+
this.facetGridPadding
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
const {
|
|
272
|
+
backgroundColor,
|
|
273
|
+
isStatic,
|
|
274
|
+
mapColumnSlug = "",
|
|
275
|
+
mapConfig,
|
|
276
|
+
isMapSelectionEnabled,
|
|
277
|
+
colorScale,
|
|
278
|
+
globeController,
|
|
279
|
+
base,
|
|
280
|
+
tooltip,
|
|
281
|
+
shouldPinTooltipToBottom,
|
|
282
|
+
projectionColumnInfoBySlug,
|
|
283
|
+
isFaceted,
|
|
284
|
+
yColumnSlug,
|
|
285
|
+
} = manager
|
|
286
|
+
|
|
287
|
+
return series.map((series, index) => {
|
|
288
|
+
const { bounds } = gridBoundsArr[index]
|
|
289
|
+
|
|
290
|
+
const manager: MapChartManager = {
|
|
291
|
+
table,
|
|
292
|
+
transformedTable: transformedTableFromGrapher,
|
|
293
|
+
fontSize: facetFontSize,
|
|
294
|
+
showLegend: false,
|
|
295
|
+
backgroundColor,
|
|
296
|
+
isStatic,
|
|
297
|
+
mapColumnSlug,
|
|
298
|
+
mapConfig,
|
|
299
|
+
isMapSelectionEnabled,
|
|
300
|
+
colorScale,
|
|
301
|
+
globeController,
|
|
302
|
+
base,
|
|
303
|
+
tooltip,
|
|
304
|
+
shouldPinTooltipToBottom,
|
|
305
|
+
externalLegendHoverBin: legendHoverBin,
|
|
306
|
+
logGrapherInteractionEvent,
|
|
307
|
+
disableIntroAnimation: true,
|
|
308
|
+
projectionColumnInfoBySlug,
|
|
309
|
+
highlightedTimesInTooltip: targetTimes,
|
|
310
|
+
mapViewport,
|
|
311
|
+
isFaceted,
|
|
312
|
+
yColumnSlug,
|
|
313
|
+
...series.manager,
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
bounds,
|
|
318
|
+
manager,
|
|
319
|
+
seriesName: series.seriesName,
|
|
320
|
+
color: series.color,
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@computed private get intermediateMapInstances(): MapChart[] {
|
|
326
|
+
return this.intermediatePlacedSeries.map(
|
|
327
|
+
({ bounds, manager }) =>
|
|
328
|
+
makeChartInstance({
|
|
329
|
+
manager,
|
|
330
|
+
bounds,
|
|
331
|
+
chartType: GRAPHER_MAP_TYPE,
|
|
332
|
+
variant: this.manager.variant,
|
|
333
|
+
}) as MapChart
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Used to construct the shared legend for all map facets.
|
|
339
|
+
*
|
|
340
|
+
* Unlike in FacetChart, we only need a single MapChart instance to construct
|
|
341
|
+
* the legend since all facets share the same legend.
|
|
342
|
+
*/
|
|
343
|
+
@computed get intermediateMapInstance(): MapChart {
|
|
344
|
+
return this.intermediateMapInstances[0]
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
@computed private get gridParams(): GridParameters {
|
|
348
|
+
return this.getGridParams(this.facetsContainerBounds)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
@computed private get facetArrangement(): "side-by-side" | "stacked" {
|
|
352
|
+
return this.gridParams.rows > this.gridParams.columns
|
|
353
|
+
? "stacked"
|
|
354
|
+
: "side-by-side"
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@computed get placedSeries(): PlacedMapFacetSeries[] {
|
|
358
|
+
const bounds = this.facetsContainerBounds
|
|
359
|
+
const gridBoundsArr = bounds.grid(
|
|
360
|
+
this.gridParams,
|
|
361
|
+
this.facetGridPadding
|
|
362
|
+
)
|
|
363
|
+
return this.intermediatePlacedSeries.map((series, i) => {
|
|
364
|
+
const { bounds } = gridBoundsArr[i]
|
|
365
|
+
return { ...series, bounds }
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
@computed private get externalLegend():
|
|
370
|
+
| HorizontalColorLegendManager
|
|
371
|
+
| undefined {
|
|
372
|
+
return this.intermediateMapInstance.externalLegend
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@computed get legendX(): number {
|
|
376
|
+
return this.bounds.x
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
@computed get numericLegendY(): number {
|
|
380
|
+
if (!this.numericLegend) return 0
|
|
381
|
+
return (
|
|
382
|
+
this.bounds.bottom -
|
|
383
|
+
this.numericLegendHeight -
|
|
384
|
+
PADDING_BELOW_MAP_LEGEND -
|
|
385
|
+
// If present, the category legend is placed below the numeric legend
|
|
386
|
+
(this.categoryLegend
|
|
387
|
+
? this.categoryLegendHeight + PADDING_BETWEEN_MAP_LEGENDS
|
|
388
|
+
: 0)
|
|
389
|
+
)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
@computed get categoryLegendY(): number {
|
|
393
|
+
if (!this.categoryLegend) return 0
|
|
394
|
+
return (
|
|
395
|
+
this.bounds.bottom -
|
|
396
|
+
this.categoryLegend.height -
|
|
397
|
+
PADDING_BELOW_MAP_LEGEND
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@computed get legendMaxWidth(): number {
|
|
402
|
+
return this.bounds.width * MAP_LEGEND_MAX_WIDTH_RATIO
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
@computed get legendAlign(): HorizontalAlign {
|
|
406
|
+
return HorizontalAlign.center
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
@computed get hoverColors(): Color[] | undefined {
|
|
410
|
+
if (!this.legendHoverBin) return undefined
|
|
411
|
+
return [this.legendHoverBin.color]
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
@computed get numericLegendData(): ColorScaleBin[] {
|
|
415
|
+
return this.externalLegend?.numericLegendData ?? []
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
@computed get categoricalLegendData(): CategoricalBin[] {
|
|
419
|
+
return this.externalLegend?.categoricalLegendData ?? []
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
@computed private get numericLegendHeight(): number {
|
|
423
|
+
return this.numericLegend ? this.numericLegend.height : 0
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
@computed private get categoryLegendHeight(): number {
|
|
427
|
+
return this.categoryLegend ? this.categoryLegend.height : 0
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
@computed get legendHeight(): number {
|
|
431
|
+
return this.categoryLegendHeight + this.numericLegendHeight
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
@action.bound onLegendMouseOver(bin: ColorScaleBin): void {
|
|
435
|
+
this.legendHoverBin = bin
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
@action.bound onLegendMouseLeave(): void {
|
|
439
|
+
this.legendHoverBin = undefined
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
@computed private get categoryLegend():
|
|
443
|
+
| HorizontalCategoricalColorLegend
|
|
444
|
+
| undefined {
|
|
445
|
+
return this.categoricalLegendData.length > 1
|
|
446
|
+
? new HorizontalCategoricalColorLegend({ manager: this })
|
|
447
|
+
: undefined
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
@computed private get numericLegend():
|
|
451
|
+
| HorizontalNumericColorLegend
|
|
452
|
+
| undefined {
|
|
453
|
+
return this.numericLegendData.length > 1
|
|
454
|
+
? new HorizontalNumericColorLegend({ manager: this })
|
|
455
|
+
: undefined
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
getLegendBinState(bin: ColorScaleBin): LegendInteractionState {
|
|
459
|
+
if (!this.legendHoverBin && !this.mapConfig.hoverCountry) {
|
|
460
|
+
return LegendInteractionState.Default
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Check if this bin is being hovered
|
|
464
|
+
if (this.legendHoverBin && bin.equals(this.legendHoverBin)) {
|
|
465
|
+
return LegendInteractionState.Focused
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Check if a country is being hovered and matches this bin
|
|
469
|
+
if (this.mapConfig.hoverCountry) {
|
|
470
|
+
const series = this.intermediateMapInstances.map((mapChart) =>
|
|
471
|
+
mapChart.chartState.series.find(
|
|
472
|
+
(s) => s.seriesName === this.mapConfig.hoverCountry
|
|
473
|
+
)
|
|
474
|
+
)
|
|
475
|
+
if (series.some((s) => s?.color === bin.color))
|
|
476
|
+
return LegendInteractionState.Focused
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return LegendInteractionState.Muted
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
@computed get legendStyleConfig(): LegendStyleConfig | undefined {
|
|
483
|
+
return this.externalLegend?.legendStyleConfig
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
override componentDidMount(): void {
|
|
487
|
+
exposeInstanceOnWindow(this, "facetMap")
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private getLabelPosition(facet: PlacedMapFacetSeries): {
|
|
491
|
+
x: number
|
|
492
|
+
y: number
|
|
493
|
+
} {
|
|
494
|
+
const { mapConfig, labelPadding } = this
|
|
495
|
+
const { bounds } = facet
|
|
496
|
+
|
|
497
|
+
const labelX = bounds.centerX
|
|
498
|
+
let labelY = bounds.top - labelPadding
|
|
499
|
+
|
|
500
|
+
// For the globe and 2D continent views, simply render the label at the top
|
|
501
|
+
if (
|
|
502
|
+
mapConfig.globe.isActive ||
|
|
503
|
+
mapConfig.region !== MapRegionName.World
|
|
504
|
+
)
|
|
505
|
+
return { x: labelX, y: labelY }
|
|
506
|
+
|
|
507
|
+
// There is often quite a bit of vertical padding around the 2D World map.
|
|
508
|
+
// It looks nicer to position the facet label closer to the actual map content
|
|
509
|
+
// rather than at the very top
|
|
510
|
+
|
|
511
|
+
const mapAspectRatio = MAP_VIEWPORT_FACETED_WORLD.ratio
|
|
512
|
+
|
|
513
|
+
// Find the map's width and height
|
|
514
|
+
let mapWidth = bounds.width
|
|
515
|
+
let mapHeight = mapWidth / mapAspectRatio
|
|
516
|
+
if (mapHeight > bounds.height) {
|
|
517
|
+
mapHeight = bounds.height
|
|
518
|
+
mapWidth = mapHeight * mapAspectRatio
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Move the label closer to the map if there is vertical padding
|
|
522
|
+
if (mapHeight < bounds.height) {
|
|
523
|
+
const shiftY = (bounds.height - mapHeight) / 2
|
|
524
|
+
labelY = Math.max(labelY, labelY + shiftY - 3 * labelPadding)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return { x: labelX, y: labelY }
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
private renderMapLegend(): React.ReactElement {
|
|
531
|
+
return (
|
|
532
|
+
<>
|
|
533
|
+
{this.numericLegend && (
|
|
534
|
+
<HorizontalNumericColorLegend manager={this} />
|
|
535
|
+
)}
|
|
536
|
+
{this.categoryLegend && (
|
|
537
|
+
<HorizontalCategoricalColorLegend manager={this} />
|
|
538
|
+
)}
|
|
539
|
+
</>
|
|
540
|
+
)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
private renderSeparatorLine(): React.ReactElement | null {
|
|
544
|
+
const {
|
|
545
|
+
mapConfig,
|
|
546
|
+
facetArrangement,
|
|
547
|
+
facetsContainerBounds: bounds,
|
|
548
|
+
} = this
|
|
549
|
+
|
|
550
|
+
// It can be difficult to visually distinguish two continent maps
|
|
551
|
+
// when plotted side by side, so we draw a gray line between them
|
|
552
|
+
if (
|
|
553
|
+
mapConfig.region !== MapRegionName.World &&
|
|
554
|
+
facetArrangement === "side-by-side"
|
|
555
|
+
) {
|
|
556
|
+
return (
|
|
557
|
+
<line
|
|
558
|
+
x1={bounds.centerX}
|
|
559
|
+
y1={bounds.top}
|
|
560
|
+
x2={bounds.centerX}
|
|
561
|
+
y2={bounds.bottom}
|
|
562
|
+
stroke={GRAY_30}
|
|
563
|
+
/>
|
|
564
|
+
)
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return null
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
override render(): React.ReactElement {
|
|
571
|
+
const { facetFontSize } = this
|
|
572
|
+
return (
|
|
573
|
+
<>
|
|
574
|
+
{this.renderMapLegend()}
|
|
575
|
+
{this.renderSeparatorLine()}
|
|
576
|
+
{this.placedSeries.map((series) => {
|
|
577
|
+
const { bounds, seriesName } = series
|
|
578
|
+
|
|
579
|
+
return (
|
|
580
|
+
<React.Fragment key={seriesName}>
|
|
581
|
+
<text
|
|
582
|
+
{...this.getLabelPosition(series)}
|
|
583
|
+
fill={GRAPHER_DARK_TEXT}
|
|
584
|
+
fontSize={facetFontSize}
|
|
585
|
+
textAnchor="middle"
|
|
586
|
+
style={{ fontWeight: 700 }}
|
|
587
|
+
>
|
|
588
|
+
{seriesName}
|
|
589
|
+
</text>
|
|
590
|
+
<g id={makeIdForHumanConsumption(seriesName)}>
|
|
591
|
+
<ChartComponent
|
|
592
|
+
manager={series.manager}
|
|
593
|
+
chartType={GRAPHER_MAP_TYPE}
|
|
594
|
+
variant={this.manager.variant}
|
|
595
|
+
bounds={bounds}
|
|
596
|
+
/>
|
|
597
|
+
</g>
|
|
598
|
+
</React.Fragment>
|
|
599
|
+
)
|
|
600
|
+
})}
|
|
601
|
+
</>
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ChartSeries } from "../chart/ChartInterface"
|
|
2
|
+
import { Bounds, GrapherAnalyticsContext } from "../../utils/index.js"
|
|
3
|
+
import { MapChartManager } from "../mapCharts/MapChartConstants"
|
|
4
|
+
import { GrapherAnalytics } from "../core/GrapherAnalytics"
|
|
5
|
+
|
|
6
|
+
export interface FacetMapManager extends MapChartManager {
|
|
7
|
+
analytics?: GrapherAnalytics
|
|
8
|
+
analyticsContext?: GrapherAnalyticsContext
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FacetMapProps {
|
|
12
|
+
bounds?: Bounds
|
|
13
|
+
manager: FacetMapManager
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface MapFacetSeries extends ChartSeries {
|
|
17
|
+
manager: Partial<MapChartManager>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PlacedMapFacetSeries extends MapFacetSeries {
|
|
21
|
+
manager: MapChartManager
|
|
22
|
+
bounds: Bounds
|
|
23
|
+
}
|