@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,968 @@
|
|
|
1
|
+
import * as _ from "lodash-es"
|
|
2
|
+
import React from "react"
|
|
3
|
+
import * as R from "remeda"
|
|
4
|
+
import {
|
|
5
|
+
guid,
|
|
6
|
+
excludeNullish,
|
|
7
|
+
getRelativeMouse,
|
|
8
|
+
exposeInstanceOnWindow,
|
|
9
|
+
excludeUndefined,
|
|
10
|
+
isMobile,
|
|
11
|
+
Bounds,
|
|
12
|
+
HorizontalAlign,
|
|
13
|
+
isTouchDevice,
|
|
14
|
+
} from "../../utils/index.js"
|
|
15
|
+
import { computed, action, observable, makeObservable } from "mobx"
|
|
16
|
+
import { observer } from "mobx-react"
|
|
17
|
+
import { select, type Selection, type BaseType } from "d3-selection"
|
|
18
|
+
import { easeLinear } from "d3-ease"
|
|
19
|
+
import { DualAxisComponent } from "../axis/AxisViews"
|
|
20
|
+
import { DualAxis, HorizontalAxis, VerticalAxis } from "../axis/Axis"
|
|
21
|
+
import { LineLegend } from "../lineLegend/LineLegend"
|
|
22
|
+
import { TooltipFooterIcon } from "../tooltip/TooltipProps.js"
|
|
23
|
+
import {
|
|
24
|
+
Tooltip,
|
|
25
|
+
TooltipState,
|
|
26
|
+
TooltipTable,
|
|
27
|
+
makeTooltipRoundingNotice,
|
|
28
|
+
toTooltipTableColumns,
|
|
29
|
+
} from "../tooltip/Tooltip"
|
|
30
|
+
import { NoDataModal } from "../noDataModal/NoDataModal"
|
|
31
|
+
import { extent } from "d3-array"
|
|
32
|
+
import { SeriesName, VerticalAlign, Time } from "../../types/index.js"
|
|
33
|
+
import {
|
|
34
|
+
BASE_FONT_SIZE,
|
|
35
|
+
DEFAULT_GRAPHER_BOUNDS,
|
|
36
|
+
GRAPHER_OPACITY_MUTE,
|
|
37
|
+
} from "../core/GrapherConstants"
|
|
38
|
+
import { ChartInterface } from "../chart/ChartInterface"
|
|
39
|
+
import {
|
|
40
|
+
LineChartSeries,
|
|
41
|
+
LineChartManager,
|
|
42
|
+
LinePoint,
|
|
43
|
+
PlacedLineChartSeries,
|
|
44
|
+
RenderLineChartSeries,
|
|
45
|
+
CATEGORICAL_LEGEND_STYLE,
|
|
46
|
+
NUMERIC_LEGEND_STYLE,
|
|
47
|
+
LEGEND_PADDING,
|
|
48
|
+
VARIABLE_COLOR_STROKE_WIDTH,
|
|
49
|
+
DEFAULT_STROKE_WIDTH,
|
|
50
|
+
VARIABLE_COLOR_LINE_OUTLINE_WIDTH,
|
|
51
|
+
DEFAULT_LINE_OUTLINE_WIDTH,
|
|
52
|
+
DISCONNECTED_DOTS_MARKER_RADIUS,
|
|
53
|
+
VARIABLE_COLOR_MARKER_RADIUS,
|
|
54
|
+
STATIC_SMALL_MARKER_RADIUS,
|
|
55
|
+
DEFAULT_MARKER_RADIUS,
|
|
56
|
+
LINE_CHART_CLASS_NAME,
|
|
57
|
+
} from "./LineChartConstants"
|
|
58
|
+
import { CoreColumn } from "../../core-table/index.js"
|
|
59
|
+
import {
|
|
60
|
+
ClipPath,
|
|
61
|
+
getHoverStateForSeries,
|
|
62
|
+
getSeriesKey,
|
|
63
|
+
isTargetOutsideElement,
|
|
64
|
+
makeClipPath,
|
|
65
|
+
} from "../chart/ChartUtils"
|
|
66
|
+
import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"
|
|
67
|
+
import { ColorScale } from "../color/ColorScale"
|
|
68
|
+
import { GRAPHER_BACKGROUND_DEFAULT, GRAY_50 } from "../color/ColorConstants"
|
|
69
|
+
import { darkenColorForLine } from "../color/ColorUtils"
|
|
70
|
+
import {
|
|
71
|
+
HorizontalColorLegendManager,
|
|
72
|
+
HorizontalNumericColorLegend,
|
|
73
|
+
} from "../legend/HorizontalColorLegends"
|
|
74
|
+
import {
|
|
75
|
+
AnnotationsMap,
|
|
76
|
+
getAnnotationsForSeries,
|
|
77
|
+
getAnnotationsMap,
|
|
78
|
+
getYAxisConfigDefaults,
|
|
79
|
+
toPlacedLineChartSeries,
|
|
80
|
+
toRenderLineChartSeries,
|
|
81
|
+
} from "./LineChartHelpers"
|
|
82
|
+
import { LineLabelSeries } from "../lineLegend/LineLegendTypes"
|
|
83
|
+
import { Lines } from "./Lines"
|
|
84
|
+
import { LineChartState } from "./LineChartState.js"
|
|
85
|
+
import { AxisConfig, AxisManager } from "../axis/AxisConfig"
|
|
86
|
+
import { ChartComponentProps } from "../chart/ChartTypeMap.js"
|
|
87
|
+
import { InteractionState } from "../interaction/InteractionState"
|
|
88
|
+
import { LegendStyleConfig } from "../legend/LegendInteractionState"
|
|
89
|
+
|
|
90
|
+
export type LineChartProps = ChartComponentProps<LineChartState>
|
|
91
|
+
|
|
92
|
+
@observer
|
|
93
|
+
export class LineChart
|
|
94
|
+
extends React.Component<LineChartProps>
|
|
95
|
+
implements ChartInterface, HorizontalColorLegendManager, AxisManager
|
|
96
|
+
{
|
|
97
|
+
private base = React.createRef<SVGGElement>()
|
|
98
|
+
|
|
99
|
+
constructor(props: LineChartProps) {
|
|
100
|
+
super(props)
|
|
101
|
+
|
|
102
|
+
makeObservable<
|
|
103
|
+
LineChart,
|
|
104
|
+
"tooltipState" | "lineLegendHoveredSeriesName" | "hoverTimer"
|
|
105
|
+
>(this, {
|
|
106
|
+
tooltipState: observable,
|
|
107
|
+
lineLegendHoveredSeriesName: observable,
|
|
108
|
+
hoverTimer: observable,
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@computed get chartState(): LineChartState {
|
|
113
|
+
return this.props.chartState
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@computed get isStatic(): boolean {
|
|
117
|
+
return this.manager.isStatic ?? false
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@computed get detailsOrderedByReference(): string[] {
|
|
121
|
+
return this.manager.detailsOrderedByReference ?? []
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@computed get annotationsMap(): AnnotationsMap | undefined {
|
|
125
|
+
return getAnnotationsMap(
|
|
126
|
+
this.chartState.inputTable,
|
|
127
|
+
this.yColumnSlugs[0]
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@action.bound private dismissTooltip(): void {
|
|
132
|
+
this.tooltipState.target = null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@action.bound private onCursorLeave(): void {
|
|
136
|
+
if (!this.manager.shouldPinTooltipToBottom) {
|
|
137
|
+
this.dismissTooltip()
|
|
138
|
+
}
|
|
139
|
+
this.clearHighlightedSeries()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@computed private get allValues(): LinePoint[] {
|
|
143
|
+
return this.placedSeries.flatMap((series) => series.points)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private tooltipState = new TooltipState<{ time: Time }>({
|
|
147
|
+
fade: "immediate",
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
@action.bound private onCursorMove(
|
|
151
|
+
ev: React.MouseEvent | React.TouchEvent
|
|
152
|
+
): void {
|
|
153
|
+
const ref = this.base.current,
|
|
154
|
+
parentRef = this.manager.base?.current
|
|
155
|
+
|
|
156
|
+
// the tooltip's origin needs to be in the parent's coordinates
|
|
157
|
+
if (parentRef) {
|
|
158
|
+
this.tooltipState.position = getRelativeMouse(parentRef, ev)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!ref) return
|
|
162
|
+
|
|
163
|
+
const mouse = getRelativeMouse(ref, ev)
|
|
164
|
+
const boxPadding = isMobile() ? 44 : 25
|
|
165
|
+
|
|
166
|
+
// expand the box width, so it's easier to see the tooltip for the first & last timepoints
|
|
167
|
+
const boundedBox = this.dualAxis.innerBounds.expand({
|
|
168
|
+
left: boxPadding,
|
|
169
|
+
right: boxPadding,
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
let hoverTime
|
|
173
|
+
if (boundedBox.contains(mouse)) {
|
|
174
|
+
const invertedX = this.dualAxis.horizontalAxis.invert(mouse.x)
|
|
175
|
+
|
|
176
|
+
const closestValue = _.minBy(this.allValues, (point) =>
|
|
177
|
+
Math.abs(invertedX - point.x)
|
|
178
|
+
)
|
|
179
|
+
hoverTime = closestValue?.x
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// be sure all lines are un-dimmed if the cursor is above the graph itself
|
|
183
|
+
if (this.dualAxis.innerBounds.contains(mouse)) {
|
|
184
|
+
this.clearLineLegendHover()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.tooltipState.target =
|
|
188
|
+
hoverTime === undefined ? null : { time: hoverTime }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@computed private get manager(): LineChartManager {
|
|
192
|
+
return this.chartState.manager
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@computed private get bounds(): Bounds {
|
|
196
|
+
return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@computed private get boundsWithoutColorLegend(): Bounds {
|
|
200
|
+
return this.bounds.padTop(
|
|
201
|
+
this.hasColorLegend ? this.legendHeight + LEGEND_PADDING : 0
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@computed private get maxLineLegendWidth(): number {
|
|
206
|
+
return this.bounds.width / 3
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@computed private get lineStrokeWidth(): number {
|
|
210
|
+
if (this.manager.lineStrokeWidth) return this.manager.lineStrokeWidth
|
|
211
|
+
const factor = this.manager.isStaticAndSmall ? 2 : 1
|
|
212
|
+
return this.hasColorScale
|
|
213
|
+
? factor * VARIABLE_COLOR_STROKE_WIDTH
|
|
214
|
+
: factor * DEFAULT_STROKE_WIDTH
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@computed private get lineOutlineWidth(): number {
|
|
218
|
+
return this.hasColorScale
|
|
219
|
+
? VARIABLE_COLOR_LINE_OUTLINE_WIDTH
|
|
220
|
+
: DEFAULT_LINE_OUTLINE_WIDTH
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@computed private get markerRadius(): number {
|
|
224
|
+
if (this.hasMarkersOnlySeries) return DISCONNECTED_DOTS_MARKER_RADIUS
|
|
225
|
+
if (this.hasColorScale) return VARIABLE_COLOR_MARKER_RADIUS
|
|
226
|
+
if (this.manager.isStaticAndSmall) return STATIC_SMALL_MARKER_RADIUS
|
|
227
|
+
return DEFAULT_MARKER_RADIUS
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@computed get activeTimes(): Time[] {
|
|
231
|
+
const { highlightedTimesInLineChart = [] } = this.manager
|
|
232
|
+
return _.uniq(
|
|
233
|
+
this.tooltipState.target?.time
|
|
234
|
+
? [
|
|
235
|
+
this.tooltipState.target.time,
|
|
236
|
+
...highlightedTimesInLineChart,
|
|
237
|
+
]
|
|
238
|
+
: highlightedTimesInLineChart
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@computed private get activeXVerticalLines(): React.ReactElement | null {
|
|
243
|
+
const { activeTimes, dualAxis } = this
|
|
244
|
+
const { horizontalAxis, verticalAxis } = dualAxis
|
|
245
|
+
|
|
246
|
+
if (!activeTimes) return null
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<>
|
|
250
|
+
{activeTimes.map((time) => (
|
|
251
|
+
<g className="hoverIndicator" key={time}>
|
|
252
|
+
<line
|
|
253
|
+
x1={horizontalAxis.place(time)}
|
|
254
|
+
y1={verticalAxis.range[0]}
|
|
255
|
+
x2={horizontalAxis.place(time)}
|
|
256
|
+
y2={verticalAxis.range[1]}
|
|
257
|
+
stroke="rgba(180,180,180,.4)"
|
|
258
|
+
/>
|
|
259
|
+
{this.renderSeries.map((series, index) => {
|
|
260
|
+
const point = series.points.find(
|
|
261
|
+
(point) => point.x === time
|
|
262
|
+
)
|
|
263
|
+
if (!point || series.hover.background) return null
|
|
264
|
+
|
|
265
|
+
const valueColor = this.hasColorScale
|
|
266
|
+
? darkenColorForLine(
|
|
267
|
+
this.chartState.getColorScaleColor(
|
|
268
|
+
point.colorValue
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
: series.color
|
|
272
|
+
const color =
|
|
273
|
+
!series.focus.background || series.hover.active
|
|
274
|
+
? valueColor
|
|
275
|
+
: GRAY_50
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<circle
|
|
279
|
+
key={getSeriesKey(series, index)}
|
|
280
|
+
cx={horizontalAxis.place(point.x)}
|
|
281
|
+
cy={verticalAxis.place(point.y)}
|
|
282
|
+
r={this.lineStrokeWidth / 2 + 3.5}
|
|
283
|
+
fill={color}
|
|
284
|
+
stroke={
|
|
285
|
+
this.manager.backgroundColor ??
|
|
286
|
+
GRAPHER_BACKGROUND_DEFAULT
|
|
287
|
+
}
|
|
288
|
+
strokeWidth={0.5}
|
|
289
|
+
/>
|
|
290
|
+
)
|
|
291
|
+
})}
|
|
292
|
+
</g>
|
|
293
|
+
))}
|
|
294
|
+
</>
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@computed private get tooltipId(): number {
|
|
299
|
+
return this.renderUid
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
@computed private get isTooltipActive(): boolean {
|
|
303
|
+
return this.manager.tooltip?.get()?.id === this.tooltipId
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@computed private get tooltip(): React.ReactElement | undefined {
|
|
307
|
+
const { formatColumn, colorColumn, hasColorScale } = this
|
|
308
|
+
const { target, position, fading } = this.tooltipState
|
|
309
|
+
|
|
310
|
+
if (!target) return undefined
|
|
311
|
+
|
|
312
|
+
// Duplicate seriesNames will be present if there is a projected-values line
|
|
313
|
+
const seriesSegments = _.mapValues(
|
|
314
|
+
_.groupBy(this.series, "seriesName"),
|
|
315
|
+
(segments) =>
|
|
316
|
+
segments.find((series) =>
|
|
317
|
+
// Ideally pick series with a defined value at the target time
|
|
318
|
+
series.points.find((point) => point.x === target.time)
|
|
319
|
+
) ??
|
|
320
|
+
segments.find((series): boolean | void => {
|
|
321
|
+
// Otherwise pick the series whose start & end contains the target time
|
|
322
|
+
// and display a "No data" notice.
|
|
323
|
+
const [startX, endX] = extent(series.points, ({ x }) => x)
|
|
324
|
+
return (
|
|
325
|
+
_.isNumber(startX) &&
|
|
326
|
+
_.isNumber(endX) &&
|
|
327
|
+
startX < target.time &&
|
|
328
|
+
target.time < endX
|
|
329
|
+
)
|
|
330
|
+
}) ??
|
|
331
|
+
null // If neither series matches, exclude the entity from the tooltip altogether
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
const sortedData = _.sortBy(
|
|
335
|
+
excludeNullish(R.values(seriesSegments)),
|
|
336
|
+
(series) => {
|
|
337
|
+
const value = series.points.find(
|
|
338
|
+
(point) => point.x === target.time
|
|
339
|
+
)
|
|
340
|
+
return value !== undefined ? -value.y : Infinity
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
const formattedTime = formatColumn.formatTime(target.time),
|
|
345
|
+
{ displayUnit: unitLabel } = formatColumn,
|
|
346
|
+
{ isRelativeMode, startTime } = this.manager
|
|
347
|
+
|
|
348
|
+
const title = formattedTime
|
|
349
|
+
const titleAnnotation = this.xAxis.label ? `(${this.xAxis.label})` : ""
|
|
350
|
+
|
|
351
|
+
const columns = [formatColumn]
|
|
352
|
+
if (hasColorScale && colorColumn.slug !== formatColumn.slug)
|
|
353
|
+
columns.push(colorColumn)
|
|
354
|
+
|
|
355
|
+
const subtitle =
|
|
356
|
+
isRelativeMode && startTime
|
|
357
|
+
? `% change since ${formatColumn.formatTime(startTime)}`
|
|
358
|
+
: unitLabel
|
|
359
|
+
const subtitleFormat = subtitle === unitLabel ? "unit" : undefined
|
|
360
|
+
|
|
361
|
+
const projectionNotice = sortedData.some(
|
|
362
|
+
(series) => series.isProjection
|
|
363
|
+
)
|
|
364
|
+
? { icon: TooltipFooterIcon.Stripes, text: "Projected data" }
|
|
365
|
+
: undefined
|
|
366
|
+
const roundingNotice = formatColumn.roundsToSignificantFigures
|
|
367
|
+
? {
|
|
368
|
+
icon: TooltipFooterIcon.None,
|
|
369
|
+
text: makeTooltipRoundingNotice([
|
|
370
|
+
formatColumn.numSignificantFigures,
|
|
371
|
+
]),
|
|
372
|
+
}
|
|
373
|
+
: undefined
|
|
374
|
+
const footer = excludeUndefined([projectionNotice, roundingNotice])
|
|
375
|
+
|
|
376
|
+
return (
|
|
377
|
+
<Tooltip
|
|
378
|
+
id={this.tooltipId}
|
|
379
|
+
tooltipManager={this.manager}
|
|
380
|
+
x={position.x}
|
|
381
|
+
y={position.y}
|
|
382
|
+
style={{ maxWidth: "400px" }}
|
|
383
|
+
offsetXDirection="left"
|
|
384
|
+
offsetX={20}
|
|
385
|
+
offsetY={-16}
|
|
386
|
+
title={title}
|
|
387
|
+
titleAnnotation={titleAnnotation}
|
|
388
|
+
subtitle={subtitle}
|
|
389
|
+
subtitleFormat={subtitleFormat}
|
|
390
|
+
footer={footer}
|
|
391
|
+
dissolve={fading}
|
|
392
|
+
dismiss={this.dismissTooltip}
|
|
393
|
+
>
|
|
394
|
+
<TooltipTable
|
|
395
|
+
columns={toTooltipTableColumns(columns)}
|
|
396
|
+
rows={sortedData.map((series) => {
|
|
397
|
+
const {
|
|
398
|
+
seriesName,
|
|
399
|
+
displayName,
|
|
400
|
+
isProjection: striped,
|
|
401
|
+
} = series
|
|
402
|
+
const annotation = getAnnotationsForSeries(
|
|
403
|
+
this.annotationsMap,
|
|
404
|
+
seriesName
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
const point = series.points.find(
|
|
408
|
+
(point) => point.x === target.time
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
const blurred =
|
|
412
|
+
this.hoverStateForSeries(series).background ||
|
|
413
|
+
series.focus.background ||
|
|
414
|
+
point === undefined
|
|
415
|
+
|
|
416
|
+
const color = this.hasColorScale
|
|
417
|
+
? darkenColorForLine(
|
|
418
|
+
this.chartState.getColorScaleColor(
|
|
419
|
+
point?.colorValue
|
|
420
|
+
)
|
|
421
|
+
)
|
|
422
|
+
: series.color
|
|
423
|
+
const opacity = blurred ? GRAPHER_OPACITY_MUTE : 1
|
|
424
|
+
const swatch = { color, opacity }
|
|
425
|
+
|
|
426
|
+
const values = excludeUndefined([
|
|
427
|
+
point?.y,
|
|
428
|
+
point?.colorValue as undefined | number,
|
|
429
|
+
])
|
|
430
|
+
|
|
431
|
+
return {
|
|
432
|
+
name: displayName,
|
|
433
|
+
annotation,
|
|
434
|
+
swatch,
|
|
435
|
+
blurred,
|
|
436
|
+
striped,
|
|
437
|
+
values,
|
|
438
|
+
}
|
|
439
|
+
})}
|
|
440
|
+
/>
|
|
441
|
+
</Tooltip>
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private defaultRightPadding = 1
|
|
446
|
+
|
|
447
|
+
private lineLegendHoveredSeriesName: SeriesName | undefined = undefined
|
|
448
|
+
private hoverTimer: number | undefined = undefined
|
|
449
|
+
|
|
450
|
+
@action.bound private onLineLegendMouseOver(seriesName: SeriesName): void {
|
|
451
|
+
clearTimeout(this.hoverTimer)
|
|
452
|
+
this.lineLegendHoveredSeriesName = seriesName
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
@action.bound private clearLineLegendHover(): void {
|
|
456
|
+
this.lineLegendHoveredSeriesName = undefined
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
@action.bound private clearHighlightedSeries(): void {
|
|
460
|
+
clearTimeout(this.hoverTimer)
|
|
461
|
+
|
|
462
|
+
// Wait before clearing selection in case the mouse is moving
|
|
463
|
+
// quickly over neighboring labels
|
|
464
|
+
this.hoverTimer = window.setTimeout(() => {
|
|
465
|
+
this.clearLineLegendHover()
|
|
466
|
+
}, 200)
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@action.bound private onLineLegendMouseLeave(): void {
|
|
470
|
+
this.clearHighlightedSeries()
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
@action.bound private onLineLegendClick(seriesName: SeriesName): void {
|
|
474
|
+
this.chartState.focusArray.toggle(seriesName)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
@computed private get hoveredSeriesNames(): string[] {
|
|
478
|
+
const { externalLegendHoverBin } = this.manager
|
|
479
|
+
const hoveredSeriesNames = excludeUndefined([
|
|
480
|
+
this.lineLegendHoveredSeriesName,
|
|
481
|
+
])
|
|
482
|
+
if (externalLegendHoverBin) {
|
|
483
|
+
hoveredSeriesNames.push(
|
|
484
|
+
...this.series
|
|
485
|
+
.map((s) => s.seriesName)
|
|
486
|
+
.filter((name) => externalLegendHoverBin.contains(name))
|
|
487
|
+
)
|
|
488
|
+
}
|
|
489
|
+
return hoveredSeriesNames
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
@computed private get isHoverModeActive(): boolean {
|
|
493
|
+
return (
|
|
494
|
+
this.hoveredSeriesNames.length > 0 ||
|
|
495
|
+
// if the external legend is hovered, we want to mute
|
|
496
|
+
// all non-hovered series even if the chart doesn't plot
|
|
497
|
+
// the currently hovered series
|
|
498
|
+
(!!this.manager.externalLegendHoverBin && !this.hasColorScale)
|
|
499
|
+
)
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
@computed private get canToggleFocusMode(): boolean {
|
|
503
|
+
return !isTouchDevice() && this.series.length > 1
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
@computed private get hasTimeHighlights(): boolean {
|
|
507
|
+
const { highlightedTimesInLineChart = [] } = this.manager
|
|
508
|
+
return highlightedTimesInLineChart.length > 0
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
@action.bound private onDocumentClick(e: MouseEvent): void {
|
|
512
|
+
// only dismiss the tooltip if the click is outside of the chart area
|
|
513
|
+
// and outside of the chart areas of neighbouring facets
|
|
514
|
+
const chartContainer = this.manager.base?.current
|
|
515
|
+
if (!chartContainer) return
|
|
516
|
+
const chartAreas = chartContainer.getElementsByClassName(
|
|
517
|
+
LINE_CHART_CLASS_NAME
|
|
518
|
+
)
|
|
519
|
+
const isTargetOutsideChartAreas = Array.from(chartAreas).every(
|
|
520
|
+
(chartArea) => isTargetOutsideElement(e.target!, chartArea)
|
|
521
|
+
)
|
|
522
|
+
if (isTargetOutsideChartAreas) {
|
|
523
|
+
this.dismissTooltip()
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
private animSelection?: Selection<
|
|
528
|
+
BaseType,
|
|
529
|
+
unknown,
|
|
530
|
+
SVGGElement | null,
|
|
531
|
+
unknown
|
|
532
|
+
>
|
|
533
|
+
override componentDidMount(): void {
|
|
534
|
+
if (!this.manager.disableIntroAnimation) {
|
|
535
|
+
this.runFancyIntroAnimation()
|
|
536
|
+
}
|
|
537
|
+
exposeInstanceOnWindow(this)
|
|
538
|
+
document.addEventListener("click", this.onDocumentClick, {
|
|
539
|
+
capture: true,
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
override componentWillUnmount(): void {
|
|
544
|
+
if (this.animSelection) this.animSelection.interrupt()
|
|
545
|
+
document.removeEventListener("click", this.onDocumentClick, {
|
|
546
|
+
capture: true,
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
@computed private get renderUid(): number {
|
|
551
|
+
return guid()
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
@computed get fontSize(): number {
|
|
555
|
+
return this.manager.fontSize ?? BASE_FONT_SIZE
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
@computed private get fontWeight(): number {
|
|
559
|
+
return this.hasColorScale ? 700 : 400
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
@computed private get hidePoints(): boolean {
|
|
563
|
+
return !!this.manager.hidePoints
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
@computed private get lineLegendX(): number {
|
|
567
|
+
return this.bounds.right - this.lineLegendWidth
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
@computed private get lineLegendY(): [number, number] {
|
|
571
|
+
return [
|
|
572
|
+
this.boundsWithoutColorLegend.top,
|
|
573
|
+
this.boundsWithoutColorLegend.bottom,
|
|
574
|
+
]
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
@computed private get clipPathBounds(): Bounds {
|
|
578
|
+
const { dualAxis, boundsWithoutColorLegend } = this
|
|
579
|
+
return boundsWithoutColorLegend
|
|
580
|
+
.set({ x: dualAxis.innerBounds.x })
|
|
581
|
+
.expand(10)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
@computed private get clipPath(): ClipPath {
|
|
585
|
+
return makeClipPath({
|
|
586
|
+
renderUid: this.renderUid,
|
|
587
|
+
box: this.clipPathBounds,
|
|
588
|
+
})
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
private runFancyIntroAnimation(): void {
|
|
592
|
+
this.animSelection = select(this.base.current)
|
|
593
|
+
.selectAll("clipPath > rect")
|
|
594
|
+
.attr("width", 0)
|
|
595
|
+
this.animSelection
|
|
596
|
+
.transition()
|
|
597
|
+
.duration(800)
|
|
598
|
+
.ease(easeLinear)
|
|
599
|
+
.attr("width", this.clipPathBounds.width)
|
|
600
|
+
.on("end", () => this.forceUpdate()) // Important in case bounds changes during transition
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
@computed private get lineLegendWidth(): number {
|
|
604
|
+
if (!this.manager.showLegend) return 0
|
|
605
|
+
|
|
606
|
+
// only pass props that are required to calculate
|
|
607
|
+
// the width to avoid circular dependencies
|
|
608
|
+
return LineLegend.stableWidth({
|
|
609
|
+
series: this.lineLegendSeries,
|
|
610
|
+
maxWidth: this.maxLineLegendWidth,
|
|
611
|
+
fontSize: this.fontSize,
|
|
612
|
+
fontWeight: this.fontWeight,
|
|
613
|
+
verticalAlign: VerticalAlign.top,
|
|
614
|
+
})
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
private renderDualAxis(): React.ReactElement {
|
|
618
|
+
const { manager, dualAxis } = this
|
|
619
|
+
|
|
620
|
+
return (
|
|
621
|
+
<DualAxisComponent
|
|
622
|
+
dualAxis={dualAxis}
|
|
623
|
+
showTickMarks={true}
|
|
624
|
+
detailsMarker={manager.detailsMarkerInSvg}
|
|
625
|
+
backgroundColor={manager.backgroundColor}
|
|
626
|
+
/>
|
|
627
|
+
)
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
private renderColorLegend(): React.ReactElement | null {
|
|
631
|
+
if (!this.hasColorLegend) return null
|
|
632
|
+
return <HorizontalNumericColorLegend manager={this} />
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Render the lines themselves and their labels
|
|
637
|
+
*/
|
|
638
|
+
private renderChartElements(): React.ReactElement {
|
|
639
|
+
const { manager } = this
|
|
640
|
+
return (
|
|
641
|
+
<>
|
|
642
|
+
{manager.showLegend && (
|
|
643
|
+
<LineLegend
|
|
644
|
+
series={this.lineLegendSeries}
|
|
645
|
+
yAxis={this.yAxis}
|
|
646
|
+
x={this.lineLegendX}
|
|
647
|
+
yRange={this.lineLegendY}
|
|
648
|
+
maxWidth={this.maxLineLegendWidth}
|
|
649
|
+
verticalAlign={VerticalAlign.top}
|
|
650
|
+
fontSize={this.fontSize}
|
|
651
|
+
fontWeight={this.fontWeight}
|
|
652
|
+
isStatic={this.isStatic}
|
|
653
|
+
onMouseOver={this.onLineLegendMouseOver}
|
|
654
|
+
onMouseLeave={this.onLineLegendMouseLeave}
|
|
655
|
+
onClick={
|
|
656
|
+
this.canToggleFocusMode
|
|
657
|
+
? this.onLineLegendClick
|
|
658
|
+
: undefined
|
|
659
|
+
}
|
|
660
|
+
/>
|
|
661
|
+
)}
|
|
662
|
+
<Lines
|
|
663
|
+
dualAxis={this.dualAxis}
|
|
664
|
+
series={this.renderSeries}
|
|
665
|
+
multiColor={this.hasColorScale}
|
|
666
|
+
hidePoints={this.hidePoints}
|
|
667
|
+
lineStrokeWidth={this.lineStrokeWidth}
|
|
668
|
+
lineOutlineWidth={this.lineOutlineWidth}
|
|
669
|
+
backgroundColor={this.manager.backgroundColor}
|
|
670
|
+
markerRadius={this.markerRadius}
|
|
671
|
+
isStatic={manager.isStatic}
|
|
672
|
+
/>
|
|
673
|
+
</>
|
|
674
|
+
)
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
private renderStatic(): React.ReactElement {
|
|
678
|
+
return (
|
|
679
|
+
<>
|
|
680
|
+
{this.renderColorLegend()}
|
|
681
|
+
{this.renderDualAxis()}
|
|
682
|
+
{this.renderChartElements()}
|
|
683
|
+
</>
|
|
684
|
+
)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
private renderInteractive(): React.ReactElement {
|
|
688
|
+
return (
|
|
689
|
+
<g
|
|
690
|
+
ref={this.base}
|
|
691
|
+
className={LINE_CHART_CLASS_NAME}
|
|
692
|
+
onMouseLeave={this.onCursorLeave}
|
|
693
|
+
onTouchEnd={this.onCursorLeave}
|
|
694
|
+
onTouchCancel={this.onCursorLeave}
|
|
695
|
+
onMouseMove={this.onCursorMove}
|
|
696
|
+
onTouchStart={this.onCursorMove}
|
|
697
|
+
onTouchMove={this.onCursorMove}
|
|
698
|
+
>
|
|
699
|
+
{/* The tiny bit of extra space in the clippath is to ensure circles
|
|
700
|
+
centered on the very edge are still fully visible */}
|
|
701
|
+
{this.clipPath.element}
|
|
702
|
+
<rect {...this.bounds.toProps()} fillOpacity="0">
|
|
703
|
+
{/* This <rect> ensures that the parent <g> is big enough such that
|
|
704
|
+
we get mouse hover events for the whole charting area, including
|
|
705
|
+
the axis, the entity labels, and the whitespace next to them.
|
|
706
|
+
We need these to be able to show the tooltip for the first/last
|
|
707
|
+
year even if the mouse is outside the charting area. */}
|
|
708
|
+
</rect>
|
|
709
|
+
{this.renderColorLegend()}
|
|
710
|
+
{this.renderDualAxis()}
|
|
711
|
+
<g clipPath={this.clipPath.id}>{this.renderChartElements()}</g>
|
|
712
|
+
|
|
713
|
+
{(this.isTooltipActive || this.hasTimeHighlights) &&
|
|
714
|
+
this.activeXVerticalLines}
|
|
715
|
+
{this.tooltip}
|
|
716
|
+
</g>
|
|
717
|
+
)
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
override render(): React.ReactElement {
|
|
721
|
+
const { manager, dualAxis } = this
|
|
722
|
+
|
|
723
|
+
if (this.chartState.errorInfo.reason)
|
|
724
|
+
return (
|
|
725
|
+
<g>
|
|
726
|
+
{this.renderDualAxis()}
|
|
727
|
+
<NoDataModal
|
|
728
|
+
manager={manager}
|
|
729
|
+
bounds={dualAxis.innerBounds}
|
|
730
|
+
message={this.chartState.errorInfo.reason}
|
|
731
|
+
/>
|
|
732
|
+
</g>
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
return manager.isStatic ? this.renderStatic() : this.renderInteractive()
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
@computed protected get yColumnSlugs(): string[] {
|
|
739
|
+
return this.chartState.yColumnSlugs
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
@computed private get colorColumn(): CoreColumn {
|
|
743
|
+
return this.chartState.colorColumn
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
@computed private get formatColumn(): CoreColumn {
|
|
747
|
+
return this.chartState.formatColumn
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
@computed private get hasColorScale(): boolean {
|
|
751
|
+
return this.chartState.hasColorScale
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
@computed private get hasColorLegend(): boolean {
|
|
755
|
+
return (
|
|
756
|
+
this.hasColorScale &&
|
|
757
|
+
!!this.manager.showLegend &&
|
|
758
|
+
!this.manager.isDisplayedAlongsideComplementaryTable
|
|
759
|
+
)
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
@computed get legendX(): number {
|
|
763
|
+
return this.bounds.x
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
@computed get legendMaxWidth(): number {
|
|
767
|
+
return this.bounds.width
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
@computed get legendAlign(): HorizontalAlign {
|
|
771
|
+
return HorizontalAlign.center
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
@computed private get colorScale(): ColorScale {
|
|
775
|
+
return this.chartState.colorScale
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// TODO just pass colorScale to legend and let it figure it out?
|
|
779
|
+
@computed get numericLegendData(): ColorScaleBin[] {
|
|
780
|
+
// Move CategoricalBins to end
|
|
781
|
+
return _.sortBy(
|
|
782
|
+
this.colorScale.legendBins,
|
|
783
|
+
(bin) => bin instanceof CategoricalBin
|
|
784
|
+
)
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
numericBinSize = 6
|
|
788
|
+
legendTickSize = 1
|
|
789
|
+
|
|
790
|
+
// Used when faceted
|
|
791
|
+
categoricalLegendStyleConfig: LegendStyleConfig = CATEGORICAL_LEGEND_STYLE
|
|
792
|
+
|
|
793
|
+
// Used when the lines are colored by a numeric scale
|
|
794
|
+
numericLegendStyleConfig = NUMERIC_LEGEND_STYLE
|
|
795
|
+
|
|
796
|
+
@computed private get numericLegend():
|
|
797
|
+
| HorizontalNumericColorLegend
|
|
798
|
+
| undefined {
|
|
799
|
+
return this.hasColorScale && this.manager.showLegend
|
|
800
|
+
? new HorizontalNumericColorLegend({ manager: this })
|
|
801
|
+
: undefined
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
@computed get numericLegendY(): number {
|
|
805
|
+
return this.bounds.top
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
@computed get legendTitle(): string | undefined {
|
|
809
|
+
return this.hasColorScale
|
|
810
|
+
? this.colorScale.legendDescription
|
|
811
|
+
: undefined
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
@computed get legendHeight(): number {
|
|
815
|
+
return this.numericLegend?.height ?? 0
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// End of color legend props
|
|
819
|
+
|
|
820
|
+
@computed get series(): readonly LineChartSeries[] {
|
|
821
|
+
return this.chartState.series
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
@computed private get hasMarkersOnlySeries(): boolean {
|
|
825
|
+
return this.series.some((series) => series.plotMarkersOnly)
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
@computed get placedSeries(): PlacedLineChartSeries[] {
|
|
829
|
+
return toPlacedLineChartSeries(this.series, {
|
|
830
|
+
chartState: this.chartState,
|
|
831
|
+
dualAxis: this.dualAxis,
|
|
832
|
+
})
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
private hoverStateForSeries(series: LineChartSeries): InteractionState {
|
|
836
|
+
return getHoverStateForSeries(series, {
|
|
837
|
+
isHoverModeActive: this.isHoverModeActive,
|
|
838
|
+
hoveredSeriesNames: this.hoveredSeriesNames,
|
|
839
|
+
})
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
@computed private get renderSeries(): RenderLineChartSeries[] {
|
|
843
|
+
return toRenderLineChartSeries(this.placedSeries, {
|
|
844
|
+
isFocusModeActive: this.chartState.isFocusModeActive,
|
|
845
|
+
isHoverModeActive: this.isHoverModeActive,
|
|
846
|
+
hoveredSeriesNames: this.hoveredSeriesNames,
|
|
847
|
+
})
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// Order of the legend items on a line chart should visually correspond
|
|
851
|
+
// to the order of the lines as the approach the legend
|
|
852
|
+
@computed private get lineLegendSeries(): LineLabelSeries[] {
|
|
853
|
+
// If there are any projections, ignore non-projection legends (bit of a hack)
|
|
854
|
+
let series = this.series
|
|
855
|
+
if (series.some((series) => !!series.isProjection))
|
|
856
|
+
series = series.filter((series) => series.isProjection)
|
|
857
|
+
|
|
858
|
+
// Deduplicate series by seriesName to avoid showing the same label multiple times
|
|
859
|
+
const deduplicatedSeries: LineChartSeries[] = []
|
|
860
|
+
const seriesGroupedByName = _.groupBy(series, "seriesName")
|
|
861
|
+
for (const duplicates of Object.values(seriesGroupedByName)) {
|
|
862
|
+
// keep only the label for the series with the most recent data
|
|
863
|
+
// (series are sorted by time, so we can just take the last one)
|
|
864
|
+
deduplicatedSeries.push(R.last(duplicates)!)
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return deduplicatedSeries.map((series) => {
|
|
868
|
+
const { seriesName, displayName, color } = series
|
|
869
|
+
const lastValue = R.last(series.points)!.y
|
|
870
|
+
return {
|
|
871
|
+
color,
|
|
872
|
+
seriesName,
|
|
873
|
+
// E.g. https://ourworldindata.org/grapher/size-poverty-gap-world
|
|
874
|
+
label: !this.manager.showLegend ? "" : displayName,
|
|
875
|
+
annotation: getAnnotationsForSeries(
|
|
876
|
+
this.annotationsMap,
|
|
877
|
+
seriesName
|
|
878
|
+
),
|
|
879
|
+
yValue: lastValue,
|
|
880
|
+
focus: series.focus,
|
|
881
|
+
hover: this.hoverStateForSeries(series),
|
|
882
|
+
} satisfies LineLabelSeries
|
|
883
|
+
})
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
@computed private get yAxisConfig(): AxisConfig {
|
|
887
|
+
const { yAxisConfig } = this.manager
|
|
888
|
+
const defaults = getYAxisConfigDefaults(yAxisConfig)
|
|
889
|
+
return new AxisConfig({ ...defaults, ...yAxisConfig }, this)
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
@computed private get xAxisConfig(): AxisConfig {
|
|
893
|
+
const { xAxisConfig } = this.manager
|
|
894
|
+
const custom = { hideGridlines: true }
|
|
895
|
+
return new AxisConfig({ ...custom, ...xAxisConfig }, this)
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
@computed private get horizontalAxisPart(): HorizontalAxis {
|
|
899
|
+
return this.chartState.toHorizontalAxis(this.xAxisConfig)
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
@computed private get verticalAxisPart(): VerticalAxis {
|
|
903
|
+
return this.chartState.toVerticalAxis(this.yAxisConfig)
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
@computed private get innerBounds(): Bounds {
|
|
907
|
+
return (
|
|
908
|
+
this.boundsWithoutColorLegend
|
|
909
|
+
.padRight(
|
|
910
|
+
this.manager.showLegend
|
|
911
|
+
? this.lineLegendWidth
|
|
912
|
+
: this.defaultRightPadding
|
|
913
|
+
)
|
|
914
|
+
// The top padding leaves room for tick labels.
|
|
915
|
+
// No padding is needed when plotted on a log axis because the
|
|
916
|
+
// log scale notice leaves enough space for tick labels.
|
|
917
|
+
.padTop(this.chartState.isLogScale ? 0 : 6)
|
|
918
|
+
// The bottom padding avoids axis labels to be cut off at some resolutions
|
|
919
|
+
.padBottom(2)
|
|
920
|
+
)
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
@computed get dualAxis(): DualAxis {
|
|
924
|
+
return new DualAxis({
|
|
925
|
+
bounds: this.innerBounds,
|
|
926
|
+
verticalAxis: this.verticalAxisPart,
|
|
927
|
+
horizontalAxis: this.horizontalAxisPart,
|
|
928
|
+
comparisonLines: this.manager.comparisonLines,
|
|
929
|
+
})
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
@computed get yAxis(): VerticalAxis {
|
|
933
|
+
return this.dualAxis.verticalAxis
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
@computed get xAxis(): HorizontalAxis {
|
|
937
|
+
return this.dualAxis.horizontalAxis
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
@computed get externalLegend(): HorizontalColorLegendManager | undefined {
|
|
941
|
+
if (!this.manager.showLegend) {
|
|
942
|
+
const numericLegendData = this.hasColorScale
|
|
943
|
+
? this.numericLegendData
|
|
944
|
+
: []
|
|
945
|
+
const categoricalLegendData = this.hasColorScale
|
|
946
|
+
? []
|
|
947
|
+
: this.series.map(
|
|
948
|
+
(series, index) =>
|
|
949
|
+
new CategoricalBin({
|
|
950
|
+
index,
|
|
951
|
+
value: series.seriesName,
|
|
952
|
+
label: series.displayName,
|
|
953
|
+
color: series.color,
|
|
954
|
+
})
|
|
955
|
+
)
|
|
956
|
+
return {
|
|
957
|
+
legendTitle: this.legendTitle,
|
|
958
|
+
legendTickSize: this.legendTickSize,
|
|
959
|
+
numericBinSize: this.numericBinSize,
|
|
960
|
+
numericLegendData,
|
|
961
|
+
categoricalLegendData,
|
|
962
|
+
categoricalLegendStyleConfig: this.categoricalLegendStyleConfig,
|
|
963
|
+
numericLegendStyleConfig: this.numericLegendStyleConfig,
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return undefined
|
|
967
|
+
}
|
|
968
|
+
}
|