@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,728 @@
|
|
|
1
|
+
import * as _ from "lodash-es"
|
|
2
|
+
import React from "react"
|
|
3
|
+
import { select } from "d3-selection"
|
|
4
|
+
import {
|
|
5
|
+
exposeInstanceOnWindow,
|
|
6
|
+
Bounds,
|
|
7
|
+
Time,
|
|
8
|
+
HorizontalAlign,
|
|
9
|
+
AxisAlign,
|
|
10
|
+
makeIdForHumanConsumption,
|
|
11
|
+
dyFromAlign,
|
|
12
|
+
} from "../../utils/index.js"
|
|
13
|
+
import { computed, makeObservable } from "mobx"
|
|
14
|
+
import { observer } from "mobx-react"
|
|
15
|
+
import { ScaleType, VerticalAlign } from "../../types/index.js"
|
|
16
|
+
import {
|
|
17
|
+
BASE_FONT_SIZE,
|
|
18
|
+
DEFAULT_GRAPHER_BOUNDS,
|
|
19
|
+
GRAPHER_FONT_SCALE_12,
|
|
20
|
+
GRAPHER_AREA_OPACITY_DEFAULT,
|
|
21
|
+
GRAPHER_OPACITY_MUTE,
|
|
22
|
+
GRAPHER_AREA_OPACITY_MUTE,
|
|
23
|
+
} from "../core/GrapherConstants"
|
|
24
|
+
import { NoDataModal } from "../noDataModal/NoDataModal"
|
|
25
|
+
import { HorizontalAxisZeroLine } from "../axis/AxisViews"
|
|
26
|
+
import { AxisConfig, AxisManager } from "../axis/AxisConfig"
|
|
27
|
+
import { ChartInterface } from "../chart/ChartInterface"
|
|
28
|
+
import {
|
|
29
|
+
BAR_SPACING_FACTOR,
|
|
30
|
+
DiscreteBarChartManager,
|
|
31
|
+
DiscreteBarSeries,
|
|
32
|
+
FontSettings,
|
|
33
|
+
PlacedDiscreteBarSeries,
|
|
34
|
+
SizedDiscreteBarSeries,
|
|
35
|
+
} from "./DiscreteBarChartConstants"
|
|
36
|
+
import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"
|
|
37
|
+
import {
|
|
38
|
+
HorizontalColorLegendManager,
|
|
39
|
+
HorizontalNumericColorLegend,
|
|
40
|
+
} from "../legend/HorizontalColorLegends"
|
|
41
|
+
import { DiscreteBarChartState } from "./DiscreteBarChartState"
|
|
42
|
+
import { ChartComponentProps } from "../chart/ChartTypeMap.js"
|
|
43
|
+
import {
|
|
44
|
+
makeProjectedDataPatternId,
|
|
45
|
+
enrichSeriesWithLabels,
|
|
46
|
+
} from "./DiscreteBarChartHelpers"
|
|
47
|
+
import { OwidTable } from "../../core-table/index.js"
|
|
48
|
+
import { HorizontalAxis } from "../axis/Axis"
|
|
49
|
+
import { GRAPHER_DARK_TEXT } from "../color/ColorConstants"
|
|
50
|
+
import type { BaseType, Selection } from "d3-selection"
|
|
51
|
+
import { NUMERIC_LEGEND_STYLE } from "../lineCharts/LineChartConstants"
|
|
52
|
+
|
|
53
|
+
const DEFAULT_PROJECTED_DATA_COLOR_IN_LEGEND = "#787878"
|
|
54
|
+
|
|
55
|
+
/** The gap between the entity label and the bar */
|
|
56
|
+
const GAP__ENTITY_LABEL__BAR = 5
|
|
57
|
+
|
|
58
|
+
/** The gap between the the entity label and negative value label */
|
|
59
|
+
const GAP__ENTITY_LABEL__VALUE_LABEL = 10
|
|
60
|
+
|
|
61
|
+
/** The vertical padding between the entity label and the annotation */
|
|
62
|
+
const ANNOTATION_PADDING = 2
|
|
63
|
+
|
|
64
|
+
export interface Label {
|
|
65
|
+
valueString: string
|
|
66
|
+
timeString: string
|
|
67
|
+
width: number
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type DiscreteBarChartProps = ChartComponentProps<DiscreteBarChartState>
|
|
71
|
+
|
|
72
|
+
@observer
|
|
73
|
+
export class DiscreteBarChart
|
|
74
|
+
extends React.Component<DiscreteBarChartProps>
|
|
75
|
+
implements ChartInterface, AxisManager, HorizontalColorLegendManager
|
|
76
|
+
{
|
|
77
|
+
base = React.createRef<SVGGElement>()
|
|
78
|
+
|
|
79
|
+
constructor(props: DiscreteBarChartProps) {
|
|
80
|
+
super(props)
|
|
81
|
+
makeObservable(this)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@computed get chartState(): DiscreteBarChartState {
|
|
85
|
+
return this.props.chartState
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@computed private get manager(): DiscreteBarChartManager {
|
|
89
|
+
return this.chartState.manager
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@computed private get bounds(): Bounds {
|
|
93
|
+
return (this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS).padRight(10)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@computed private get targetTime(): Time | undefined {
|
|
97
|
+
return this.manager.endTime
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@computed private get legendPadding(): number {
|
|
101
|
+
return 0.5 * this.legendHeight
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@computed get fontSize(): number {
|
|
105
|
+
return this.manager.fontSize ?? BASE_FONT_SIZE
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@computed private get barCount(): number {
|
|
109
|
+
return this.series.length
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@computed private get labelFontSize(): number {
|
|
113
|
+
const availableHeight = this.bounds.height / this.barCount
|
|
114
|
+
return Math.min(
|
|
115
|
+
GRAPHER_FONT_SCALE_12 * this.fontSize,
|
|
116
|
+
1.1 * availableHeight
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@computed private get entityLabelStyle(): FontSettings {
|
|
121
|
+
return {
|
|
122
|
+
fontSize: this.labelFontSize,
|
|
123
|
+
fontWeight: 700,
|
|
124
|
+
lineHeight: 1,
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@computed private get entityAnnotationStyle(): FontSettings {
|
|
129
|
+
return {
|
|
130
|
+
fontSize: this.labelFontSize * 0.9,
|
|
131
|
+
fontWeight: 300,
|
|
132
|
+
lineHeight: 1,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@computed get sizedSeries(): SizedDiscreteBarSeries[] {
|
|
137
|
+
return enrichSeriesWithLabels({
|
|
138
|
+
series: this.series,
|
|
139
|
+
availableHeightPerSeries: this.bounds.height / this.barCount,
|
|
140
|
+
minLabelWidth: 0.3 * this.bounds.width,
|
|
141
|
+
maxLabelWidth: 0.66 * this.bounds.width,
|
|
142
|
+
fontSettings: this.entityLabelStyle,
|
|
143
|
+
annotationFontSettings: this.entityAnnotationStyle,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@computed private get valueLabelStyle(): FontSettings {
|
|
148
|
+
return { fontSize: this.labelFontSize, fontWeight: 400, lineHeight: 1 }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@computed private get hasPositive(): boolean {
|
|
152
|
+
return this.series.some((d) => d.value >= 0)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@computed private get hasNegative(): boolean {
|
|
156
|
+
return this.series.some((d) => d.value < 0)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// The amount of space we need to allocate for bar end labels on the right
|
|
160
|
+
@computed private get rightValueLabelsWidth(): number {
|
|
161
|
+
if (!this.hasPositive) return 0
|
|
162
|
+
|
|
163
|
+
const labelsWidths = this.series
|
|
164
|
+
.filter((series) => series.value >= 0)
|
|
165
|
+
.map((series) => this.formatValue(series).width)
|
|
166
|
+
|
|
167
|
+
return _.max(labelsWidths) ?? 0
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@computed private get x0(): number {
|
|
171
|
+
return 0
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Now we can work out the main x axis scale
|
|
175
|
+
@computed private get xDomainDefault(): [number, number] {
|
|
176
|
+
const allValues = this.series.map((d) => d.value)
|
|
177
|
+
return [
|
|
178
|
+
Math.min(this.x0, _.min(allValues) as number),
|
|
179
|
+
Math.max(this.x0, _.max(allValues) as number),
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@computed private get xRange(): [number, number] {
|
|
184
|
+
return this.innerBounds.xRange()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// NB: y-axis settings are used for the horizontal axis in DiscreteBarChart
|
|
188
|
+
@computed private get yAxisConfig(): AxisConfig {
|
|
189
|
+
return new AxisConfig(
|
|
190
|
+
{
|
|
191
|
+
// if we have a single-value x axis, we want to have the vertical axis
|
|
192
|
+
// on the left of the chart
|
|
193
|
+
singleValueAxisPointAlign: AxisAlign.start,
|
|
194
|
+
...this.manager.yAxisConfig,
|
|
195
|
+
},
|
|
196
|
+
this
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@computed get yAxis(): HorizontalAxis {
|
|
201
|
+
// NB: We use the user's YAxis options here to make the XAxis
|
|
202
|
+
const axis = this.yAxisConfig.toHorizontalAxis()
|
|
203
|
+
axis.updateDomainPreservingUserSettings(this.xDomainDefault)
|
|
204
|
+
|
|
205
|
+
axis.scaleType = ScaleType.linear
|
|
206
|
+
axis.formatColumn = this.chartState.formatColumn
|
|
207
|
+
axis.range = this.xRange
|
|
208
|
+
axis.label = ""
|
|
209
|
+
return axis
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The maximum width needed for labels positioned on the left side of the chart.
|
|
214
|
+
*
|
|
215
|
+
* For positive values, returns the width of entity labels and annotations.
|
|
216
|
+
* For negative values, returns the entity label width, annotation width, value label width
|
|
217
|
+
* and the padding between them.
|
|
218
|
+
*/
|
|
219
|
+
@computed private get leftLabelsWidth(): number {
|
|
220
|
+
const labelWidths = this.sizedSeries.map((series) => {
|
|
221
|
+
const labelWidth = series.label?.width ?? 0
|
|
222
|
+
const annotationWidth = series.annotationTextWrap?.width ?? 0
|
|
223
|
+
|
|
224
|
+
// Use the maximum width between label and annotation
|
|
225
|
+
const textWidth = Math.max(labelWidth, annotationWidth)
|
|
226
|
+
|
|
227
|
+
if (series.value < 0) {
|
|
228
|
+
const valueWidth = this.formatValue(series).width
|
|
229
|
+
return textWidth + valueWidth + GAP__ENTITY_LABEL__VALUE_LABEL
|
|
230
|
+
} else {
|
|
231
|
+
return textWidth
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
return _.max(labelWidths) ?? 0
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@computed private get innerBounds(): Bounds {
|
|
239
|
+
return this.bounds
|
|
240
|
+
.padTop(
|
|
241
|
+
this.showColorLegend
|
|
242
|
+
? this.legendHeight + this.legendPadding
|
|
243
|
+
: 0
|
|
244
|
+
)
|
|
245
|
+
.padLeft(this.leftLabelsWidth)
|
|
246
|
+
.padRight(this.rightValueLabelsWidth)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** The total height of the series, i.e. the height of the bar + the white space around it */
|
|
250
|
+
@computed private get seriesHeight(): number {
|
|
251
|
+
return this.innerBounds.height / this.barCount
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@computed private get barSpacing(): number {
|
|
255
|
+
return this.seriesHeight * BAR_SPACING_FACTOR
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@computed private get barHeight(): number {
|
|
259
|
+
const totalWhiteSpace = this.barCount * this.barSpacing
|
|
260
|
+
return (this.innerBounds.height - totalWhiteSpace) / this.barCount
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
@computed private get barPlacements(): { x: number; width: number }[] {
|
|
264
|
+
const { series, yAxis } = this
|
|
265
|
+
return series.map((d) => {
|
|
266
|
+
const isNegative = d.value < 0
|
|
267
|
+
const barX = isNegative
|
|
268
|
+
? yAxis.place(d.value)
|
|
269
|
+
: yAxis.place(this.x0)
|
|
270
|
+
const barWidth = isNegative
|
|
271
|
+
? yAxis.place(this.x0) - barX
|
|
272
|
+
: yAxis.place(d.value) - barX
|
|
273
|
+
|
|
274
|
+
return { x: barX, width: barWidth }
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
@computed private get barWidths(): number[] {
|
|
279
|
+
return this.barPlacements.map((b) => b.width)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
@computed private get placedSeries(): PlacedDiscreteBarSeries[] {
|
|
283
|
+
const yOffset =
|
|
284
|
+
this.innerBounds.top + this.barHeight / 2 + this.barSpacing / 2
|
|
285
|
+
return this.sizedSeries.map((series, index) => {
|
|
286
|
+
const barY = yOffset + index * (this.barHeight + this.barSpacing)
|
|
287
|
+
const isNegative = series.value < 0
|
|
288
|
+
const barX = isNegative
|
|
289
|
+
? this.yAxis.place(series.value)
|
|
290
|
+
: this.yAxis.place(this.x0)
|
|
291
|
+
const barWidth = isNegative
|
|
292
|
+
? this.yAxis.place(this.x0) - barX
|
|
293
|
+
: this.yAxis.place(series.value) - barX
|
|
294
|
+
const label = this.formatValue(series)
|
|
295
|
+
|
|
296
|
+
const entityLabelX = isNegative
|
|
297
|
+
? barX - label.width - GAP__ENTITY_LABEL__VALUE_LABEL
|
|
298
|
+
: barX - GAP__ENTITY_LABEL__BAR
|
|
299
|
+
const valueLabelX =
|
|
300
|
+
this.yAxis.place(series.value) +
|
|
301
|
+
(isNegative ? -GAP__ENTITY_LABEL__BAR : GAP__ENTITY_LABEL__BAR)
|
|
302
|
+
|
|
303
|
+
const annotationHeight = series.annotationTextWrap
|
|
304
|
+
? ANNOTATION_PADDING + series.annotationTextWrap.height
|
|
305
|
+
: 0
|
|
306
|
+
const totalLabelHeight = series.label.height + annotationHeight
|
|
307
|
+
|
|
308
|
+
const entityLabelY = barY - totalLabelHeight / 2
|
|
309
|
+
const annotationY = series.annotationTextWrap
|
|
310
|
+
? entityLabelY + series.label.height + ANNOTATION_PADDING
|
|
311
|
+
: undefined
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
...series,
|
|
315
|
+
barX,
|
|
316
|
+
barY,
|
|
317
|
+
barWidth,
|
|
318
|
+
entityLabelX,
|
|
319
|
+
entityLabelY,
|
|
320
|
+
annotationY,
|
|
321
|
+
valueLabelX,
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
override componentDidMount(): void {
|
|
327
|
+
exposeInstanceOnWindow(this)
|
|
328
|
+
if (!this.manager.disableIntroAnimation) {
|
|
329
|
+
this.d3Bars().attr("width", 0)
|
|
330
|
+
this.animateBarWidth()
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
override componentDidUpdate(): void {
|
|
335
|
+
// Animating the bar width after a render ensures there's no race condition, where the
|
|
336
|
+
// initial animation (in override componentDidMount) did override the now-changed bar width in
|
|
337
|
+
// some cases. Updating the animation with the updated bar widths fixes that.
|
|
338
|
+
if (!this.manager.disableIntroAnimation) this.animateBarWidth()
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private d3Bars(): Selection<
|
|
342
|
+
BaseType,
|
|
343
|
+
unknown,
|
|
344
|
+
SVGGElement | null,
|
|
345
|
+
unknown
|
|
346
|
+
> {
|
|
347
|
+
return select(this.base.current).selectAll("g.bar > rect")
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private animateBarWidth(): void {
|
|
351
|
+
this.d3Bars()
|
|
352
|
+
.transition()
|
|
353
|
+
.attr("width", (_, i) => this.barWidths[i])
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
formatValue(series: DiscreteBarSeries): Label {
|
|
357
|
+
const { yColumn } = series
|
|
358
|
+
|
|
359
|
+
const showYearLabels =
|
|
360
|
+
this.manager.showYearLabels || series.time !== this.targetTime
|
|
361
|
+
const valueString = yColumn.formatValueShort(series.value)
|
|
362
|
+
let timeString = ""
|
|
363
|
+
if (showYearLabels) {
|
|
364
|
+
const { timeColumn } = this.chartState.transformedTable
|
|
365
|
+
const preposition = OwidTable.getPreposition(timeColumn)
|
|
366
|
+
timeString = ` ${preposition} ${timeColumn.formatTime(series.time)}`
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const labelBounds = Bounds.forText(
|
|
370
|
+
valueString + timeString,
|
|
371
|
+
this.valueLabelStyle
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
valueString,
|
|
376
|
+
timeString,
|
|
377
|
+
width: labelBounds.width,
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private renderDefs(): React.ReactElement | void {
|
|
382
|
+
const projections = this.series.filter(
|
|
383
|
+
(series) => series.yColumn.isProjection
|
|
384
|
+
)
|
|
385
|
+
const uniqProjections = _.uniqBy(projections, (series) => series.color)
|
|
386
|
+
if (projections.length === 0) return
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
<defs>
|
|
390
|
+
{/* passed to the legend as pattern for the projected data legend item */}
|
|
391
|
+
<StripedProjectedDataPattern
|
|
392
|
+
patternId={makeProjectedDataPatternId(
|
|
393
|
+
this.projectedDataColorInLegend
|
|
394
|
+
)}
|
|
395
|
+
color={this.projectedDataColorInLegend}
|
|
396
|
+
/>
|
|
397
|
+
{/* make a pattern for every series with a unique color */}
|
|
398
|
+
{uniqProjections.map((series) => (
|
|
399
|
+
<StripedProjectedDataPattern
|
|
400
|
+
key={series.color}
|
|
401
|
+
patternId={makeProjectedDataPatternId(series.color)}
|
|
402
|
+
color={series.color}
|
|
403
|
+
/>
|
|
404
|
+
))}
|
|
405
|
+
</defs>
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private renderEntityLabels(): React.ReactElement {
|
|
410
|
+
return (
|
|
411
|
+
<g id={makeIdForHumanConsumption("entity-labels")}>
|
|
412
|
+
{this.placedSeries.map((series) => {
|
|
413
|
+
return (
|
|
414
|
+
series.label && (
|
|
415
|
+
<React.Fragment key={series.seriesName}>
|
|
416
|
+
{series.label.renderSVG(
|
|
417
|
+
series.entityLabelX,
|
|
418
|
+
series.entityLabelY,
|
|
419
|
+
{
|
|
420
|
+
textProps: {
|
|
421
|
+
fill: "#555",
|
|
422
|
+
textAnchor: "end",
|
|
423
|
+
opacity: series.focus.background
|
|
424
|
+
? GRAPHER_OPACITY_MUTE
|
|
425
|
+
: 1,
|
|
426
|
+
},
|
|
427
|
+
}
|
|
428
|
+
)}
|
|
429
|
+
</React.Fragment>
|
|
430
|
+
)
|
|
431
|
+
)
|
|
432
|
+
})}
|
|
433
|
+
</g>
|
|
434
|
+
)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
private renderEntityAnnotations(): React.ReactElement | null {
|
|
438
|
+
const hasAnnotations = this.placedSeries.some(
|
|
439
|
+
(series) =>
|
|
440
|
+
series.annotationTextWrap && series.annotationY !== undefined
|
|
441
|
+
)
|
|
442
|
+
if (!hasAnnotations) return null
|
|
443
|
+
|
|
444
|
+
return (
|
|
445
|
+
<g id={makeIdForHumanConsumption("entity-annotations")}>
|
|
446
|
+
{this.placedSeries.map((series) => {
|
|
447
|
+
if (!series.annotationTextWrap || !series.annotationY)
|
|
448
|
+
return null
|
|
449
|
+
|
|
450
|
+
return (
|
|
451
|
+
<React.Fragment key={`${series.seriesName}-annotation`}>
|
|
452
|
+
{series.annotationTextWrap.renderSVG(
|
|
453
|
+
series.entityLabelX,
|
|
454
|
+
series.annotationY,
|
|
455
|
+
{
|
|
456
|
+
textProps: {
|
|
457
|
+
fill: "#333",
|
|
458
|
+
textAnchor: "end",
|
|
459
|
+
opacity: series.focus.background
|
|
460
|
+
? GRAPHER_OPACITY_MUTE
|
|
461
|
+
: 1,
|
|
462
|
+
},
|
|
463
|
+
}
|
|
464
|
+
)}
|
|
465
|
+
</React.Fragment>
|
|
466
|
+
)
|
|
467
|
+
})}
|
|
468
|
+
</g>
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
private renderValueLabels(): React.ReactElement {
|
|
473
|
+
return (
|
|
474
|
+
<g id={makeIdForHumanConsumption("value-labels")}>
|
|
475
|
+
{this.placedSeries.map((series) => {
|
|
476
|
+
const formattedLabel = this.formatValue(series)
|
|
477
|
+
return (
|
|
478
|
+
<text
|
|
479
|
+
key={series.seriesName}
|
|
480
|
+
x={0}
|
|
481
|
+
y={0}
|
|
482
|
+
transform={`translate(${series.valueLabelX}, ${series.barY})`}
|
|
483
|
+
fill={GRAPHER_DARK_TEXT}
|
|
484
|
+
dy={dyFromAlign(VerticalAlign.middle)}
|
|
485
|
+
textAnchor={series.value < 0 ? "end" : "start"}
|
|
486
|
+
opacity={
|
|
487
|
+
series.focus.background
|
|
488
|
+
? GRAPHER_OPACITY_MUTE
|
|
489
|
+
: 1
|
|
490
|
+
}
|
|
491
|
+
{...this.valueLabelStyle}
|
|
492
|
+
>
|
|
493
|
+
{formattedLabel.valueString}
|
|
494
|
+
<tspan fill="#999">
|
|
495
|
+
{formattedLabel.timeString}
|
|
496
|
+
</tspan>
|
|
497
|
+
</text>
|
|
498
|
+
)
|
|
499
|
+
})}
|
|
500
|
+
</g>
|
|
501
|
+
)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private renderBars(): React.ReactElement {
|
|
505
|
+
return (
|
|
506
|
+
<g id={makeIdForHumanConsumption("bars")}>
|
|
507
|
+
{this.placedSeries.map((series) => {
|
|
508
|
+
const barColor = series.yColumn.isProjection
|
|
509
|
+
? `url(#${makeProjectedDataPatternId(series.color)})`
|
|
510
|
+
: series.color
|
|
511
|
+
|
|
512
|
+
// Using transforms for positioning to enable better (subpixel) transitions
|
|
513
|
+
// Width transitions don't work well on iOS Safari – they get interrupted and
|
|
514
|
+
// it appears very slow. Also be careful with negative bar charts.
|
|
515
|
+
return (
|
|
516
|
+
<rect
|
|
517
|
+
id={makeIdForHumanConsumption(series.seriesName)}
|
|
518
|
+
key={series.seriesName}
|
|
519
|
+
x={0}
|
|
520
|
+
y={0}
|
|
521
|
+
transform={`translate(${series.barX}, ${series.barY - this.barHeight / 2})`}
|
|
522
|
+
width={series.barWidth}
|
|
523
|
+
height={this.barHeight}
|
|
524
|
+
fill={barColor}
|
|
525
|
+
opacity={
|
|
526
|
+
series.focus.background
|
|
527
|
+
? GRAPHER_AREA_OPACITY_MUTE
|
|
528
|
+
: GRAPHER_AREA_OPACITY_DEFAULT
|
|
529
|
+
}
|
|
530
|
+
style={{ transition: "height 200ms ease" }}
|
|
531
|
+
/>
|
|
532
|
+
)
|
|
533
|
+
})}
|
|
534
|
+
</g>
|
|
535
|
+
)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private renderChartArea(): React.ReactElement {
|
|
539
|
+
return (
|
|
540
|
+
<>
|
|
541
|
+
{this.renderDefs()}
|
|
542
|
+
{this.showColorLegend && (
|
|
543
|
+
<HorizontalNumericColorLegend manager={this} />
|
|
544
|
+
)}
|
|
545
|
+
<HorizontalAxisZeroLine
|
|
546
|
+
horizontalAxis={this.yAxis}
|
|
547
|
+
bounds={this.innerBounds}
|
|
548
|
+
strokeWidth={0.5}
|
|
549
|
+
// if the chart doesn't have negative values, then we
|
|
550
|
+
// move the zero line a little to the left to avoid
|
|
551
|
+
// overlap with the bars
|
|
552
|
+
align={
|
|
553
|
+
this.hasNegative
|
|
554
|
+
? HorizontalAlign.center
|
|
555
|
+
: HorizontalAlign.right
|
|
556
|
+
}
|
|
557
|
+
/>
|
|
558
|
+
{this.renderBars()}
|
|
559
|
+
{this.renderValueLabels()}
|
|
560
|
+
{this.renderEntityLabels()}
|
|
561
|
+
{this.renderEntityAnnotations()}
|
|
562
|
+
</>
|
|
563
|
+
)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
override render(): React.ReactElement {
|
|
567
|
+
if (this.chartState.errorInfo.reason)
|
|
568
|
+
return (
|
|
569
|
+
<NoDataModal
|
|
570
|
+
manager={this.manager}
|
|
571
|
+
bounds={this.bounds}
|
|
572
|
+
message={this.chartState.errorInfo.reason}
|
|
573
|
+
/>
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
return this.manager.isStatic ? (
|
|
577
|
+
this.renderChartArea()
|
|
578
|
+
) : (
|
|
579
|
+
<g
|
|
580
|
+
ref={this.base}
|
|
581
|
+
id={makeIdForHumanConsumption("discrete-bar-chart")}
|
|
582
|
+
className="DiscreteBarChart"
|
|
583
|
+
>
|
|
584
|
+
{this.renderChartArea()}
|
|
585
|
+
</g>
|
|
586
|
+
)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Color legend props
|
|
590
|
+
|
|
591
|
+
@computed private get hasColorLegend(): boolean {
|
|
592
|
+
return this.chartState.hasColorScale || this.chartState.hasProjectedData
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
@computed private get showColorLegend(): boolean {
|
|
596
|
+
return (
|
|
597
|
+
this.hasColorLegend &&
|
|
598
|
+
!!this.manager.showLegend &&
|
|
599
|
+
!this.manager.isDisplayedAlongsideComplementaryTable
|
|
600
|
+
)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
@computed get legendX(): number {
|
|
604
|
+
return this.bounds.x
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
@computed get legendMaxWidth(): number {
|
|
608
|
+
return this.bounds.width
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
@computed get legendAlign(): HorizontalAlign {
|
|
612
|
+
return HorizontalAlign.center
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// TODO just pass colorScale to legend and let it figure it out?
|
|
616
|
+
@computed get numericLegendData(): ColorScaleBin[] {
|
|
617
|
+
const legendBins = this.chartState.colorScale.legendBins.slice()
|
|
618
|
+
|
|
619
|
+
// Show a "Projected data" legend item with a striped pattern if appropriate
|
|
620
|
+
if (this.chartState.hasProjectedData) {
|
|
621
|
+
legendBins.push(
|
|
622
|
+
new CategoricalBin({
|
|
623
|
+
color: this.projectedDataColorInLegend,
|
|
624
|
+
label: "Projected data",
|
|
625
|
+
index: 0,
|
|
626
|
+
value: "projected",
|
|
627
|
+
patternRef: makeProjectedDataPatternId(
|
|
628
|
+
this.projectedDataColorInLegend
|
|
629
|
+
),
|
|
630
|
+
})
|
|
631
|
+
)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Move CategoricalBins to end
|
|
635
|
+
return _.sortBy(legendBins, (bin) => bin instanceof CategoricalBin)
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
@computed private get projectedDataColorInLegend(): string {
|
|
639
|
+
// if a single color is in use, use that color in the legend
|
|
640
|
+
if (_.uniqBy(this.series, "color").length === 1)
|
|
641
|
+
return this.series[0].color
|
|
642
|
+
return DEFAULT_PROJECTED_DATA_COLOR_IN_LEGEND
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Used when the bars are colored by a numeric scale
|
|
646
|
+
numericLegendStyleConfig = NUMERIC_LEGEND_STYLE
|
|
647
|
+
|
|
648
|
+
@computed get externalLegend(): HorizontalColorLegendManager | undefined {
|
|
649
|
+
if (this.hasColorLegend) {
|
|
650
|
+
return {
|
|
651
|
+
numericLegendData: this.numericLegendData,
|
|
652
|
+
numericLegendStyleConfig: this.numericLegendStyleConfig,
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return undefined
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
@computed get numericBinSize(): number {
|
|
659
|
+
return 0.625 * this.fontSize
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
legendTickSize = 1
|
|
663
|
+
|
|
664
|
+
@computed private get numericLegend():
|
|
665
|
+
| HorizontalNumericColorLegend
|
|
666
|
+
| undefined {
|
|
667
|
+
return this.manager.showLegend
|
|
668
|
+
? new HorizontalNumericColorLegend({ manager: this })
|
|
669
|
+
: undefined
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
@computed get numericLegendY(): number {
|
|
673
|
+
return this.bounds.top
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
@computed get legendTitle(): string | undefined {
|
|
677
|
+
return this.chartState.hasColorScale
|
|
678
|
+
? this.chartState.colorScale.legendDescription
|
|
679
|
+
: undefined
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
@computed get legendHeight(): number {
|
|
683
|
+
return this.numericLegend?.height ?? 0
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// End of color legend props
|
|
687
|
+
|
|
688
|
+
@computed private get series(): DiscreteBarSeries[] {
|
|
689
|
+
return this.chartState.series
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function StripedProjectedDataPattern({
|
|
694
|
+
patternId,
|
|
695
|
+
color,
|
|
696
|
+
opacity = 0.5,
|
|
697
|
+
size = 7,
|
|
698
|
+
strokeWidth = 10,
|
|
699
|
+
}: {
|
|
700
|
+
patternId: string
|
|
701
|
+
color: string
|
|
702
|
+
opacity?: number
|
|
703
|
+
size?: number
|
|
704
|
+
strokeWidth?: number
|
|
705
|
+
}): React.ReactElement {
|
|
706
|
+
return (
|
|
707
|
+
<pattern
|
|
708
|
+
id={patternId}
|
|
709
|
+
patternUnits="userSpaceOnUse"
|
|
710
|
+
width={size}
|
|
711
|
+
height={size}
|
|
712
|
+
patternTransform="rotate(45)"
|
|
713
|
+
>
|
|
714
|
+
{/* semi-transparent background */}
|
|
715
|
+
<rect width={size} height={size} fill={color} opacity={opacity} />
|
|
716
|
+
|
|
717
|
+
{/* stripes */}
|
|
718
|
+
<line
|
|
719
|
+
x1="0"
|
|
720
|
+
y1="0"
|
|
721
|
+
x2="0"
|
|
722
|
+
y2={size}
|
|
723
|
+
stroke={color}
|
|
724
|
+
strokeWidth={strokeWidth}
|
|
725
|
+
/>
|
|
726
|
+
</pattern>
|
|
727
|
+
)
|
|
728
|
+
}
|