From c77e1cfab2cb5209c413307c40054ad8afd36b41 Mon Sep 17 00:00:00 2001 From: Sophia Mersmann Date: Tue, 26 Nov 2024 10:56:30 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20(grapher)=20replace=20some=20enu?= =?UTF-8?q?m=20types=20/=20TAS-709=20(#4170)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactors Grapher types by replacing enums with compile-time-only types. I introduced `GrapherTabName` in the previous PR, which is either a `ChartTypeName` or `"WorldMap"` or `"Table"`. But enums currently [can't be extended or merged](https://github.com/microsoft/TypeScript/issues/17592), which means that I had to copy-paste all chart type names into `GrapherTabName`. As a result, TypeScript doesn't do a good job of type narrowing, forcing me to write (unnecessary) type assertions in many places. This PR refactors `ChartTypeName` and other tab-related types so they don't use enums. However, I still wanted the convenience of a single object to access chart types, for example. To get that, the types are inferred from const objects: ```ts const GRAPHER_CHART_TYPES = { LineChart: "LineChart", ScatterPlot: "ScatterPlot" } as const type GrapherChartType = keyof typeof GRAPHER_CHART_TYPES ``` I first did it the other way around (first defining the types, then using them for the objects), but it turns out the way it's done now leads to better type narrowing. **Newly introduced types:** - `GrapherMapType`: only "WorldMap" - `GrapherChartType`: "LineChart", "ScatterPlot", etc. (without "WorldMap") - `GrapherChartOrMapType`: `GrapherChartType` or `GrapherMapType` - `GrapherTabName`: Internal tab names used in Grapher (a chart type name or "WorldMap" or "Table") - `GrapherTabOption`: Grapher tab specified in the config that determines the default tab to show ("chart", "map" or "tab") - `GrapherTabQueryParam`: Valid values for the `tab` query parameter in Grapher ("chart", "map", "line", "slope", etc.) --- adminSiteClient/ChartList.tsx | 13 +- adminSiteClient/ColorSchemeDropdown.tsx | 4 +- adminSiteClient/EditorBasicTab.tsx | 13 +- adminSiteClient/EditorColorScaleSection.tsx | 6 +- adminSiteClient/EditorCustomizeTab.tsx | 8 +- adminSiteClient/EditorMapTab.tsx | 4 +- adminSiteClient/GrapherConfigGridEditor.tsx | 7 +- adminSiteClient/VariableEditPage.tsx | 6 +- adminSiteServer/testPageRouter.tsx | 28 ++-- baker/updateChartEntities.ts | 6 +- .../1661264304751-MigrateSelectedData.ts | 12 +- db/model/Chart.ts | 4 +- db/model/Gdoc/GdocBase.ts | 4 +- db/model/Variable.ts | 4 +- devTools/graphersToGit/tasks.ts | 4 +- devTools/svgTester/chart-configurations.ts | 45 +++-- devTools/svgTester/dump-chart-ids.ts | 4 +- devTools/svgTester/utils.ts | 31 ++-- .../explorer/src/Explorer.jsdom.test.tsx | 8 +- .../explorer/src/Explorer.sample.tsx | 4 +- .../@ourworldindata/explorer/src/Explorer.tsx | 9 +- .../explorer/src/ExplorerProgram.ts | 4 +- .../explorer/src/GrapherGrammar.ts | 8 +- .../captionedChart/CaptionedChart.stories.tsx | 10 +- .../src/captionedChart/CaptionedChart.tsx | 36 ++-- .../grapher/src/chart/ChartTypeMap.tsx | 27 +-- .../grapher/src/chart/ChartTypeSwitcher.tsx | 9 +- .../grapher/src/chart/ChartUtils.tsx | 75 +++++---- .../grapher/src/color/ColorSchemes.ts | 32 ++-- .../grapher/src/controls/ChartIcons.tsx | 26 ++- .../grapher/src/controls/ContentSwitchers.tsx | 34 ++-- .../grapher/src/controls/SettingsMenu.tsx | 22 ++- .../src/controls/settings/AbsRelToggle.tsx | 10 +- .../grapher/src/core/Grapher.jsdom.test.ts | 93 ++++++----- .../grapher/src/core/Grapher.stories.tsx | 24 +-- .../grapher/src/core/Grapher.tsx | 154 +++++++++--------- .../grapher/src/core/GrapherConstants.ts | 4 +- .../core/GrapherWithChartTypes.jsdom.test.tsx | 4 +- .../src/core/LegacyToOwidTable.test.ts | 4 +- .../grapher/src/core/LegacyToOwidTable.ts | 6 +- .../src/dataTable/DataTable.jsdom.test.tsx | 6 +- .../grapher/src/dataTable/DataTable.sample.ts | 10 +- .../src/dataTable/DataTable.stories.tsx | 6 +- .../src/facetChart/FacetChart.stories.tsx | 8 +- .../grapher/src/facetChart/FacetChart.test.ts | 10 +- .../grapher/src/facetChart/FacetChart.tsx | 18 +- .../src/facetChart/FacetChartConstants.ts | 4 +- .../grapher/src/mapCharts/MapChart.sample.ts | 4 +- .../grapher/src/mapCharts/MapChart.tsx | 4 +- .../src/mapCharts/MapChartConstants.ts | 4 +- .../src/schema/migrations/migrations.ts | 6 +- .../MarimekkoChart.jsdom.test.tsx | 10 +- .../types/src/dbTypes/ChartConfigs.ts | 4 +- .../src/grapherTypes/GrapherConstants.ts | 64 ++++++++ .../types/src/grapherTypes/GrapherTypes.ts | 73 ++------- packages/@ourworldindata/types/src/index.ts | 15 +- packages/@ourworldindata/utils/src/Util.ts | 6 +- .../utils/src/grapherConfigUtils.test.ts | 30 ++-- .../components/KeyIndicatorCollection.tsx | 11 +- site/multiembedder/MultiEmbedder.tsx | 8 +- 60 files changed, 593 insertions(+), 514 deletions(-) diff --git a/adminSiteClient/ChartList.tsx b/adminSiteClient/ChartList.tsx index dccdf863c14..c3ed89386cc 100644 --- a/adminSiteClient/ChartList.tsx +++ b/adminSiteClient/ChartList.tsx @@ -4,9 +4,10 @@ import { runInAction, observable } from "mobx" import { bind } from "decko" import { AdminAppContext, AdminAppContextType } from "./AdminAppContext.js" import { - ChartTypeName, + GrapherChartType, GrapherInterface, - GrapherTabOption, + GRAPHER_CHART_TYPES, + GRAPHER_TAB_OPTIONS, } from "@ourworldindata/types" import { startCase, DbChartTagJoin } from "@ourworldindata/utils" import { References, getFullReferencesCount } from "./ChartEditor.js" @@ -24,7 +25,7 @@ export interface ChartListItem { tab: GrapherInterface["tab"] hasMapTab: GrapherInterface["hasMapTab"] - type?: ChartTypeName + type?: GrapherChartType hasChartTab: boolean lastEditedAt: string @@ -152,11 +153,11 @@ export function showChartType(chart: ChartListItem): string { if (!chartType) return "Map" - const displayType = ChartTypeName[chartType] - ? startCase(ChartTypeName[chartType]) + const displayType = GRAPHER_CHART_TYPES[chartType] + ? startCase(GRAPHER_CHART_TYPES[chartType]) : "Unknown" - if (chart.tab === GrapherTabOption.map) { + if (chart.tab === GRAPHER_TAB_OPTIONS.map) { if (chart.hasChartTab) return `Map + ${displayType}` else return "Map" } else { diff --git a/adminSiteClient/ColorSchemeDropdown.tsx b/adminSiteClient/ColorSchemeDropdown.tsx index bb10e8ca5dc..b4f0b0df570 100644 --- a/adminSiteClient/ColorSchemeDropdown.tsx +++ b/adminSiteClient/ColorSchemeDropdown.tsx @@ -1,7 +1,7 @@ import React from "react" import { computed, action } from "mobx" import Select from "react-select" -import { ChartTypeName } from "@ourworldindata/types" +import { GrapherChartOrMapType } from "@ourworldindata/types" import { ColorScheme, getColorSchemeForChartType, @@ -21,7 +21,7 @@ interface ColorSchemeDropdownProps { value?: string gradientColorCount: number invertedColorScheme: boolean - chartType: ChartTypeName + chartType: GrapherChartOrMapType onChange: (selected: ColorSchemeOption) => void onBlur?: () => void } diff --git a/adminSiteClient/EditorBasicTab.tsx b/adminSiteClient/EditorBasicTab.tsx index d484ef7842a..04f05a9cead 100644 --- a/adminSiteClient/EditorBasicTab.tsx +++ b/adminSiteClient/EditorBasicTab.tsx @@ -9,9 +9,10 @@ import { } from "mobx" import { observer } from "mobx-react" import { - ChartTypeName, EntitySelectionMode, StackMode, + ALL_GRAPHER_CHART_TYPES, + GrapherChartType, } from "@ourworldindata/types" import { DimensionSlot, @@ -362,7 +363,9 @@ export class EditorBasicTab< const { grapher } = this.props.editor grapher.chartTypes = - value === this.chartTypeOptionNone ? [] : [value as ChartTypeName] + value === this.chartTypeOptionNone + ? [] + : [value as GrapherChartType] if (grapher.isMarimekko) { grapher.hideRelativeToggle = false @@ -403,11 +406,7 @@ export class EditorBasicTab< value: string label: string }[] { - const allChartTypes = Object.keys(ChartTypeName).filter( - (chartType) => chartType !== ChartTypeName.WorldMap - ) - - const chartTypeOptions = allChartTypes.map((key) => ({ + const chartTypeOptions = ALL_GRAPHER_CHART_TYPES.map((key) => ({ value: key, label: startCase(key), })) diff --git a/adminSiteClient/EditorColorScaleSection.tsx b/adminSiteClient/EditorColorScaleSection.tsx index b04e6ea07b6..fe6753d1276 100644 --- a/adminSiteClient/EditorColorScaleSection.tsx +++ b/adminSiteClient/EditorColorScaleSection.tsx @@ -7,7 +7,7 @@ import { faPlus, faMinus } from "@fortawesome/free-solid-svg-icons" import { ColorSchemeName, BinningStrategy, - ChartTypeName, + GrapherChartOrMapType, Color, } from "@ourworldindata/types" import { @@ -43,7 +43,7 @@ interface EditorColorScaleSectionFeatures { @observer export class EditorColorScaleSection extends React.Component<{ scale: ColorScale - chartType: ChartTypeName + chartType: GrapherChartOrMapType features: EditorColorScaleSectionFeatures showLineChartColors: boolean onChange?: () => void @@ -132,7 +132,7 @@ class ColorLegendSection extends React.Component<{ @observer class ColorsSection extends React.Component<{ scale: ColorScale - chartType: ChartTypeName + chartType: GrapherChartOrMapType showLineChartColors: boolean onChange?: () => void }> { diff --git a/adminSiteClient/EditorCustomizeTab.tsx b/adminSiteClient/EditorCustomizeTab.tsx index 2949b38a5d0..7f92dd1fb09 100644 --- a/adminSiteClient/EditorCustomizeTab.tsx +++ b/adminSiteClient/EditorCustomizeTab.tsx @@ -6,7 +6,7 @@ import { ColorSchemeName, FacetAxisDomain, FacetStrategy, - ChartTypeName, + GRAPHER_CHART_TYPES, } from "@ourworldindata/types" import { Grapher } from "@ourworldindata/grapher" import { @@ -161,7 +161,7 @@ export class ColorSchemeSelector extends React.Component<{ onBlur={this.onBlur} chartType={ this.props.grapher.chartType ?? - ChartTypeName.LineChart + GRAPHER_CHART_TYPES.LineChart } invertedColorScheme={!!grapher.invertColorScheme} additionalOptions={[ @@ -755,7 +755,9 @@ export class EditorCustomizeTab< {grapher.chartInstanceExceptMap.colorScale && ( >"$.hasMapTab" = "true"`) - tab = tab || GrapherTabOption.map + tab = tab || GRAPHER_TAB_OPTIONS.map } else { query = query.andWhereRaw(`cc.chartType = :type`, { type: params.type, }) - tab = tab || GrapherTabOption.chart + tab = tab || GRAPHER_TAB_OPTIONS.chart } } @@ -163,26 +165,26 @@ async function propsFromQueryParams( query = query.andWhereRaw( `cc.full->>'$.yAxis.canChangeScaleType' = "true" OR cc.full->>'$.xAxis.canChangeScaleType' = "true"` ) - tab = GrapherTabOption.chart + tab = GRAPHER_TAB_OPTIONS.chart } if (params.comparisonLines) { query = query.andWhereRaw( `cc.full->'$.comparisonLines[0].yEquals' != ''` ) - tab = GrapherTabOption.chart + tab = GRAPHER_TAB_OPTIONS.chart } if (params.stackMode) { query = query.andWhereRaw(`cc.full->'$.stackMode' = :stackMode`, { stackMode: params.stackMode, }) - tab = GrapherTabOption.chart + tab = GRAPHER_TAB_OPTIONS.chart } if (params.relativeToggle) { query = query.andWhereRaw(`cc.full->>'$.hideRelativeToggle' = "false"`) - tab = GrapherTabOption.chart + tab = GRAPHER_TAB_OPTIONS.chart } if (params.categoricalLegend) { @@ -192,7 +194,7 @@ async function propsFromQueryParams( query = query.andWhereRaw( `json_length(cc.full->'$.map.colorScale.customCategoryColors') > 1` ) - tab = GrapherTabOption.map + tab = GRAPHER_TAB_OPTIONS.map } if (params.mixedTimeTypes) { @@ -232,9 +234,9 @@ async function propsFromQueryParams( query = query.andWhereRaw(`charts.id IN (${params.ids})`) } - if (tab === GrapherTabOption.map) { + if (tab === GRAPHER_TAB_OPTIONS.map) { query = query.andWhereRaw(`cc.full->>"$.hasMapTab" = "true"`) - } else if (tab === GrapherTabOption.chart) { + } else if (tab === GRAPHER_TAB_OPTIONS.chart) { query = query.andWhereRaw(`cc.chartType IS NOT NULL`) } diff --git a/baker/updateChartEntities.ts b/baker/updateChartEntities.ts index 10264e28155..49e582a71d8 100644 --- a/baker/updateChartEntities.ts +++ b/baker/updateChartEntities.ts @@ -9,7 +9,7 @@ import { ChartsXEntitiesTableName, DbPlainChart, GrapherInterface, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, MultipleOwidVariableDataDimensionsMap, OwidVariableDataMetadataDimensions, DbRawChartConfig, @@ -97,7 +97,7 @@ const obtainAvailableEntitiesForGrapherConfig = async ( // If the grapher has a chart tab, then the available entities there are the "most interesting" ones to us if (grapher.hasChartTab) { - grapher.tab = GrapherTabOption.chart + grapher.tab = GRAPHER_TAB_OPTIONS.chart // If the grapher allows for changing or multi-selecting entities, then let's index all entities the // user can choose from. Otherwise, we'll just use the default-selected entities. @@ -112,7 +112,7 @@ const obtainAvailableEntitiesForGrapherConfig = async ( return grapher.tableForSelection.availableEntityNames as string[] else return grapher.selectedEntityNames ?? [] } else if (grapher.hasMapTab) { - grapher.tab = GrapherTabOption.map + grapher.tab = GRAPHER_TAB_OPTIONS.map // On a map tab, tableAfterAuthorTimelineAndActiveChartTransform contains all // mappable entities for which data is available return grapher.tableAfterAuthorTimelineAndActiveChartTransform diff --git a/db/migration/1661264304751-MigrateSelectedData.ts b/db/migration/1661264304751-MigrateSelectedData.ts index 5c8e73382ce..c7ae5880ac4 100644 --- a/db/migration/1661264304751-MigrateSelectedData.ts +++ b/db/migration/1661264304751-MigrateSelectedData.ts @@ -3,7 +3,7 @@ import { MigrationInterface, QueryRunner } from "typeorm" import { entityNameById } from "./data/entityNameById.js" -import { ChartTypeName } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES, GrapherChartType } from "@ourworldindata/types" type GrapherInterface = Record @@ -85,11 +85,11 @@ export class MigrateSelectedData1661264304751 implements MigrationInterface { } }) - const migrateDimensionsTypes: ChartTypeName[] = [ - ChartTypeName.Marimekko, - ChartTypeName.StackedArea, - ChartTypeName.StackedBar, - ChartTypeName.StackedDiscreteBar, + const migrateDimensionsTypes: GrapherChartType[] = [ + GRAPHER_CHART_TYPES.Marimekko, + GRAPHER_CHART_TYPES.StackedArea, + GRAPHER_CHART_TYPES.StackedBar, + GRAPHER_CHART_TYPES.StackedDiscreteBar, ] // Migrate order of dimensions. diff --git a/db/model/Chart.ts b/db/model/Chart.ts index e665f6301c0..7a74b18698d 100644 --- a/db/model/Chart.ts +++ b/db/model/Chart.ts @@ -13,7 +13,6 @@ import { } from "@ourworldindata/utils" import { GrapherInterface, - ChartTypeName, RelatedChart, DbPlainPostLink, DbPlainChart, @@ -22,6 +21,7 @@ import { DbPlainTag, DbRawChartConfig, DbEnrichedChartConfig, + GrapherChartType, } from "@ourworldindata/types" import { OpenAI } from "openai" import { @@ -556,7 +556,7 @@ export async function getChartVariableData( export const getMostViewedGrapherIdsByChartType = async ( knex: db.KnexReadonlyTransaction, - chartType: ChartTypeName, + chartType: GrapherChartType, count = 10 ): Promise => { const ids = await db.knexRaw<{ id: number }>( diff --git a/db/model/Gdoc/GdocBase.ts b/db/model/Gdoc/GdocBase.ts index 4dfacfe69f0..f0c5e036a38 100644 --- a/db/model/Gdoc/GdocBase.ts +++ b/db/model/Gdoc/GdocBase.ts @@ -19,7 +19,7 @@ import { OwidGdocMinimalPostInterface, urlToSlug, grabMetadataForGdocLinkedIndicator, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, DbInsertPostGdocLink, DbPlainTag, formatDate, @@ -934,7 +934,7 @@ export async function makeGrapherLinkedChart( const resolvedSlug = config.slug ?? "" const resolvedTitle = config.title ?? "" const resolvedUrl = `${BAKED_GRAPHER_URL}/${resolvedSlug}` - const tab = config.tab ?? GrapherTabOption.chart + const tab = config.tab ?? GRAPHER_TAB_OPTIONS.chart const datapageIndicator = await getVariableOfDatapageIfApplicable(config) return { configType: ChartConfigType.Grapher, diff --git a/db/model/Variable.ts b/db/model/Variable.ts index dacd7ed1ebd..ddd6665bc5f 100644 --- a/db/model/Variable.ts +++ b/db/model/Variable.ts @@ -22,7 +22,7 @@ import { OwidVariableMixedData, OwidVariableWithSourceAndDimension, OwidVariableId, - ChartTypeName, + GRAPHER_CHART_TYPES, DimensionProperty, GrapherInterface, DbRawVariable, @@ -878,7 +878,7 @@ export async function getVariableOfDatapageIfApplicable( // showing a data page. if ( yVariableIds.length === 1 && - (grapher.chartTypes?.[0] !== ChartTypeName.ScatterPlot || + (grapher.chartTypes?.[0] !== GRAPHER_CHART_TYPES.ScatterPlot || xVariableIds.length === 0) ) { const variableId = yVariableIds[0] diff --git a/devTools/graphersToGit/tasks.ts b/devTools/graphersToGit/tasks.ts index c5a95e87711..cc555c3ad30 100755 --- a/devTools/graphersToGit/tasks.ts +++ b/devTools/graphersToGit/tasks.ts @@ -2,7 +2,7 @@ import { CoreTable } from "@ourworldindata/core-table" import { - ChartTypeName, + GRAPHER_CHART_TYPES, ColorScaleConfig, Grapher, GrapherProgrammaticInterface, @@ -173,7 +173,7 @@ const dumpComplexSelections = async () => { : 0 return { grapherId: config.id, - type: config.type ?? ChartTypeName.LineChart, + type: config.type ?? GRAPHER_CHART_TYPES.LineChart, url: `https://ourworldindata.org/grapher/${config.slug}`, dimensionVariableCount, selectionVariableCount, diff --git a/devTools/svgTester/chart-configurations.ts b/devTools/svgTester/chart-configurations.ts index 03a82a5f1c7..f7de4b99909 100644 --- a/devTools/svgTester/chart-configurations.ts +++ b/devTools/svgTester/chart-configurations.ts @@ -1,10 +1,11 @@ import _ from "lodash" import { - ChartTypeName, + GRAPHER_CHART_TYPES, StackMode, ScaleType, FacetStrategy, GrapherQueryParams, + GrapherChartType, } from "@ourworldindata/types" import { cartesian } from "@ourworldindata/utils" @@ -32,8 +33,8 @@ const scaleTypeOptions = Object.values(ScaleType) const facetOptions = Object.values(FacetStrategy) const booleanOptions = Object.values(Boolean) -const VIEW_MATRIX_BY_CHART_TYPE: Record = { - [ChartTypeName.LineChart]: { +const VIEW_MATRIX_BY_CHART_TYPE: Record = { + [GRAPHER_CHART_TYPES.LineChart]: { tab: ["chart"], time: timeOptionsAll, stackMode: stackModeOptions, @@ -41,7 +42,7 @@ const VIEW_MATRIX_BY_CHART_TYPE: Record = { facet: facetOptions, uniformYAxis: booleanOptions, }, - [ChartTypeName.ScatterPlot]: { + [GRAPHER_CHART_TYPES.ScatterPlot]: { tab: ["chart"], time: timeOptionsAll, stackMode: stackModeOptions, @@ -50,61 +51,60 @@ const VIEW_MATRIX_BY_CHART_TYPE: Record = { endpointsOnly: booleanOptions, // zoomToSelection ignored for now }, - [ChartTypeName.DiscreteBar]: { + [GRAPHER_CHART_TYPES.DiscreteBar]: { tab: ["chart"], time: timePoints, facet: facetOptions, // uniformYAxis doesn't apply }, - [ChartTypeName.StackedDiscreteBar]: { + [GRAPHER_CHART_TYPES.StackedDiscreteBar]: { tab: ["chart"], time: timePoints, stackMode: stackModeOptions, facet: facetOptions, // uniformYAxis doesn't apply }, - [ChartTypeName.Marimekko]: { + [GRAPHER_CHART_TYPES.Marimekko]: { tab: ["chart"], time: timePoints, stackMode: stackModeOptions, showNoDataArea: booleanOptions, }, - [ChartTypeName.SlopeChart]: { + [GRAPHER_CHART_TYPES.SlopeChart]: { tab: ["chart"], time: timeSpan, yScale: scaleTypeOptions, }, - [ChartTypeName.StackedArea]: { + [GRAPHER_CHART_TYPES.StackedArea]: { tab: ["chart"], time: timeSpan, stackMode: stackModeOptions, facet: facetOptions, uniformYAxis: booleanOptions, }, - [ChartTypeName.StackedBar]: { + [GRAPHER_CHART_TYPES.StackedBar]: { tab: ["chart"], time: timeSpan, stackMode: stackModeOptions, facet: facetOptions, uniformYAxis: booleanOptions, }, - [ChartTypeName.WorldMap]: {}, } // the above view matrix is used to generate all possible combinations of query params // but some combinations don't make sense. this matrix is used to exclude those combinations. // for example, if a chart is not faceted, the uniformYAxis param doesn't apply const EXCLUDE_VIEWS_BY_CHART_TYPE: Record< - ChartTypeName, + GrapherChartType, Record[] > = { - [ChartTypeName.LineChart]: [ + [GRAPHER_CHART_TYPES.LineChart]: [ // sharing an axis only makes sense if a chart is faceted { facet: FacetStrategy.none, uniformYAxis: Boolean.true }, // log scale for percentage values doesn't make sense { stackMode: StackMode.relative, yScale: ScaleType.log }, ], - [ChartTypeName.ScatterPlot]: [ + [GRAPHER_CHART_TYPES.ScatterPlot]: [ // relative mode only makes sense if a time span is selected { time: TimePoint.earliest, stackMode: StackMode.relative }, { time: TimePoint.latest, stackMode: StackMode.relative }, @@ -117,19 +117,18 @@ const EXCLUDE_VIEWS_BY_CHART_TYPE: Record< { stackMode: StackMode.relative, yScale: ScaleType.log }, { stackMode: StackMode.relative, xScale: ScaleType.log }, ], - [ChartTypeName.DiscreteBar]: [], - [ChartTypeName.StackedDiscreteBar]: [], - [ChartTypeName.Marimekko]: [], - [ChartTypeName.SlopeChart]: [], - [ChartTypeName.StackedArea]: [ + [GRAPHER_CHART_TYPES.DiscreteBar]: [], + [GRAPHER_CHART_TYPES.StackedDiscreteBar]: [], + [GRAPHER_CHART_TYPES.Marimekko]: [], + [GRAPHER_CHART_TYPES.SlopeChart]: [], + [GRAPHER_CHART_TYPES.StackedArea]: [ // sharing an axis only makes sense if a chart is faceted { facet: FacetStrategy.none, uniformYAxis: Boolean.true }, ], - [ChartTypeName.StackedBar]: [ + [GRAPHER_CHART_TYPES.StackedBar]: [ // sharing an axis only makes sense if a chart is faceted { facet: FacetStrategy.none, uniformYAxis: Boolean.true }, ], - [ChartTypeName.WorldMap]: [], } export const queryStringsByChartType = Object.fromEntries( @@ -137,7 +136,7 @@ export const queryStringsByChartType = Object.fromEntries( const combinations = explode(viewMatrix) const viewsToExclude = - EXCLUDE_VIEWS_BY_CHART_TYPE[chartType as ChartTypeName] + EXCLUDE_VIEWS_BY_CHART_TYPE[chartType as GrapherChartType] const validCombinations = combinations.filter((view) => viewsToExclude.every( (viewToExclude) => !_.isMatch(view, viewToExclude) @@ -147,7 +146,7 @@ export const queryStringsByChartType = Object.fromEntries( const queryStrings = validCombinations.map(toQueryStr) return [chartType, queryStrings] }) -) as Record +) as Record function toQueryStr(params: Record): string { return new URLSearchParams(params).toString() diff --git a/devTools/svgTester/dump-chart-ids.ts b/devTools/svgTester/dump-chart-ids.ts index e824f5898f9..16055805e54 100644 --- a/devTools/svgTester/dump-chart-ids.ts +++ b/devTools/svgTester/dump-chart-ids.ts @@ -5,7 +5,7 @@ import parseArgs from "minimist" import { TransactionCloseMode, knexReadonlyTransaction } from "../../db/db.js" import { getMostViewedGrapherIdsByChartType } from "../../db/model/Chart.js" -import { CHART_TYPES } from "./utils.js" +import { ALL_GRAPHER_CHART_TYPES } from "@ourworldindata/types" const DEFAULT_OUT_FILE = "../owid-grapher-svgs/most-viewed-charts.txt" const CHART_COUNT_PER_TYPE = 25 @@ -15,7 +15,7 @@ async function main(parsedArgs: parseArgs.ParsedArgs) { const outFile = parsedArgs["o"] ?? DEFAULT_OUT_FILE const chartIds = await knexReadonlyTransaction(async (trx) => { - const promises = CHART_TYPES.flatMap((chartType) => + const promises = ALL_GRAPHER_CHART_TYPES.flatMap((chartType) => getMostViewedGrapherIdsByChartType( trx, chartType, diff --git a/devTools/svgTester/utils.ts b/devTools/svgTester/utils.ts index 724a41a0492..746e94a7bb6 100644 --- a/devTools/svgTester/utils.ts +++ b/devTools/svgTester/utils.ts @@ -1,7 +1,8 @@ import { - ChartTypeName, + GRAPHER_CHART_TYPES, + GrapherChartType, GrapherTabName, - GrapherTabOption, + ALL_GRAPHER_CHART_TYPES, } from "@ourworldindata/types" import { MultipleOwidVariableDataDimensionsMap, @@ -26,11 +27,6 @@ import { getHeapStatistics } from "v8" import { queryStringsByChartType } from "./chart-configurations.js" import * as d3 from "d3" -// ignore WorldMaps -export const CHART_TYPES = Object.values(ChartTypeName).filter( - (chartType) => chartType !== ChartTypeName.WorldMap -) - // the owid-grapher-svgs repo is usually cloned as a sibling to the owid-grapher repo export const DEFAULT_CONFIGS_DIR = "../owid-grapher-svgs/configs" export const DEFAULT_REFERENCE_DIR = "../owid-grapher-svgs/svg" @@ -44,7 +40,7 @@ export const finished = util.promisify(stream.finished) // (A) export interface ChartWithQueryStr { id: number slug: string - type: ChartTypeName + type: GrapherChartType queryStr?: string } @@ -182,7 +178,7 @@ export async function selectChartIdsToProcess( options: { chartIdsFile?: string grapherIds?: number[] - chartTypes?: ChartTypeName[] + chartTypes?: GrapherChartType[] randomCount?: number } ): Promise { @@ -210,7 +206,7 @@ export async function findChartViewsToGenerate( const slug = grapherConfig.slug ?? chartId.toString() const chartType = - grapherConfig.chartTypes?.[0] ?? ChartTypeName.LineChart + grapherConfig.chartTypes?.[0] ?? GRAPHER_CHART_TYPES.LineChart const queryStrings = options.shouldTestAllViews ? queryStringsByChartType[chartType] @@ -240,7 +236,7 @@ export async function findValidChartIds( }: { chartIdsFile?: string grapherIds?: number[] - chartTypes?: ChartTypeName[] + chartTypes?: GrapherChartType[] } ): Promise { const validChartIds: number[] = [] @@ -289,7 +285,8 @@ export async function findValidChartIds( inDir, }) const chartType = - grapherConfig.chartTypes?.[0] ?? ChartTypeName.LineChart + grapherConfig.chartTypes?.[0] ?? + GRAPHER_CHART_TYPES.LineChart if (chartTypes.includes(chartType)) { validChartIds.push(grapherId) } @@ -300,17 +297,17 @@ export async function findValidChartIds( return validChartIds } -export function validateChartTypes(chartTypes: string[]): ChartTypeName[] { +export function validateChartTypes(chartTypes: string[]): GrapherChartType[] { const validChartTypes = chartTypes.filter( - (chartType): chartType is ChartTypeName => - CHART_TYPES.includes(chartType as any) + (chartType): chartType is GrapherChartType => + ALL_GRAPHER_CHART_TYPES.includes(chartType as any) ) const invalidChartTypes = chartTypes.filter( - (chartType) => !CHART_TYPES.includes(chartType as any) + (chartType) => !ALL_GRAPHER_CHART_TYPES.includes(chartType as any) ) if (invalidChartTypes.length) { console.warn( - `Invalid chart types given: ${invalidChartTypes}. Valid chart types are: ${CHART_TYPES}` + `Invalid chart types given: ${invalidChartTypes}. Valid chart types are: ${ALL_GRAPHER_CHART_TYPES}` ) } return _.uniq(validChartTypes) diff --git a/packages/@ourworldindata/explorer/src/Explorer.jsdom.test.tsx b/packages/@ourworldindata/explorer/src/Explorer.jsdom.test.tsx index 644852c0684..e35fcf581c0 100755 --- a/packages/@ourworldindata/explorer/src/Explorer.jsdom.test.tsx +++ b/packages/@ourworldindata/explorer/src/Explorer.jsdom.test.tsx @@ -8,7 +8,7 @@ import { import Enzyme from "enzyme" import Adapter from "@wojtekmaj/enzyme-adapter-react-17" -import { GrapherTabOption } from "@ourworldindata/types" +import { GRAPHER_TAB_OPTIONS } from "@ourworldindata/types" Enzyme.configure({ adapter: new Adapter() }) @@ -30,20 +30,20 @@ describe(Explorer, () => { explorer.onChangeChoice("Gas")("All GHGs (CO₂eq)") - if (explorer.grapher) explorer.grapher.tab = GrapherTabOption.table + if (explorer.grapher) explorer.grapher.tab = GRAPHER_TAB_OPTIONS.table else throw Error("where's the grapher?") expect(explorer.queryParams.tab).toEqual("table") explorer.onChangeChoice("Gas")("CO₂") expect(explorer.queryParams.tab).toEqual("table") - explorer.grapher.tab = GrapherTabOption.chart + explorer.grapher.tab = GRAPHER_TAB_OPTIONS.chart }) it("switches to first tab if current tab does not exist in new view", () => { const explorer = element.instance() as Explorer expect(explorer.queryParams.tab).toBeUndefined() - if (explorer.grapher) explorer.grapher.tab = GrapherTabOption.map + if (explorer.grapher) explorer.grapher.tab = GRAPHER_TAB_OPTIONS.map else throw Error("where's the grapher?") expect(explorer.queryParams.tab).toEqual("map") diff --git a/packages/@ourworldindata/explorer/src/Explorer.sample.tsx b/packages/@ourworldindata/explorer/src/Explorer.sample.tsx index a15b805a6f5..53cb8bff93e 100644 --- a/packages/@ourworldindata/explorer/src/Explorer.sample.tsx +++ b/packages/@ourworldindata/explorer/src/Explorer.sample.tsx @@ -1,6 +1,6 @@ import React from "react" import { DimensionProperty } from "@ourworldindata/utils" -import { GrapherTabOption } from "@ourworldindata/types" +import { GRAPHER_TAB_OPTIONS } from "@ourworldindata/types" import { GrapherProgrammaticInterface } from "@ourworldindata/grapher" import { Explorer, ExplorerProps } from "./Explorer.js" @@ -54,7 +54,7 @@ export const SampleExplorerOfGraphers = (props?: Partial) => { property: DimensionProperty.y, }, ], - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, owidDataset: new Map([ [ 142609, diff --git a/packages/@ourworldindata/explorer/src/Explorer.tsx b/packages/@ourworldindata/explorer/src/Explorer.tsx index 7cffdb8c34a..fcc38ed659e 100644 --- a/packages/@ourworldindata/explorer/src/Explorer.tsx +++ b/packages/@ourworldindata/explorer/src/Explorer.tsx @@ -8,8 +8,7 @@ import { TableSlug, GrapherInterface, GrapherQueryParams, - GrapherTabQueryParam, - GrapherTabName, + GRAPHER_TAB_QUERY_PARAMS, } from "@ourworldindata/types" import { OwidTable, @@ -455,14 +454,14 @@ export class Explorer } else if (this.grapher.validChartTypes.length > 0) { // otherwise, switch to the first chart tab newGrapherParams.tab = this.grapher.mapGrapherTabToQueryParam( - this.grapher.validChartTypes[0] as unknown as GrapherTabName + this.grapher.validChartTypes[0] ) } else if (this.grapher.hasMapTab) { // or switch to the map, if there is one - newGrapherParams.tab = GrapherTabQueryParam.WorldMap + newGrapherParams.tab = GRAPHER_TAB_QUERY_PARAMS.map } else { // if everything fails, switch to the table tab that is always available - newGrapherParams.tab = GrapherTabQueryParam.Table + newGrapherParams.tab = GRAPHER_TAB_QUERY_PARAMS.table } this.grapher.populateFromQueryParams(newGrapherParams) diff --git a/packages/@ourworldindata/explorer/src/ExplorerProgram.ts b/packages/@ourworldindata/explorer/src/ExplorerProgram.ts index 748b4e333c0..033dc5746d4 100644 --- a/packages/@ourworldindata/explorer/src/ExplorerProgram.ts +++ b/packages/@ourworldindata/explorer/src/ExplorerProgram.ts @@ -8,7 +8,7 @@ import { FacetAxisDomain, GrapherInterface, AxisMinMaxValueStr, - ChartTypeName, + GrapherChartType, } from "@ourworldindata/types" import { CoreTable, @@ -65,7 +65,7 @@ interface ExplorerGrapherInterface extends GrapherInterface { relatedQuestionText?: string relatedQuestionUrl?: string mapTargetTime?: number - type?: ChartTypeName | "None" + type?: GrapherChartType | "None" } const ExplorerRootDef: CellDef = { diff --git a/packages/@ourworldindata/explorer/src/GrapherGrammar.ts b/packages/@ourworldindata/explorer/src/GrapherGrammar.ts index bbcb295f6a6..78d6a82344a 100644 --- a/packages/@ourworldindata/explorer/src/GrapherGrammar.ts +++ b/packages/@ourworldindata/explorer/src/GrapherGrammar.ts @@ -1,9 +1,9 @@ import { - ChartTypeName, + ALL_GRAPHER_CHART_TYPES, ColorSchemeName, FacetAxisDomain, FacetStrategy, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, MissingDataStrategy, StackMode, } from "@ourworldindata/types" @@ -65,7 +65,7 @@ export const GrapherGrammar: Grammar = { keyword: "type", description: `The type of chart to show such as LineChart or ScatterPlot. If set to None, then the chart tab is hidden.`, terminalOptions: toTerminalOptions([ - ...Object.values(ChartTypeName), + ...ALL_GRAPHER_CHART_TYPES, "None", ]), toGrapherObject: (value) => ({ @@ -95,7 +95,7 @@ export const GrapherGrammar: Grammar = { ...EnumCellDef, keyword: "tab", description: "Which tab to show by default", - terminalOptions: toTerminalOptions(Object.values(GrapherTabOption)), + terminalOptions: toTerminalOptions(Object.values(GRAPHER_TAB_OPTIONS)), toGrapherObject: (value) => ({ tab: value }), }, xSlug: { diff --git a/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.stories.tsx b/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.stories.tsx index 63157d73e38..830ed484691 100644 --- a/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.stories.tsx +++ b/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.stories.tsx @@ -1,8 +1,8 @@ import { SynthesizeGDPTable } from "@ourworldindata/core-table" import { - ChartTypeName, + GRAPHER_CHART_TYPES, FacetStrategy, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, SeriesStrategy, } from "@ourworldindata/types" import { DEFAULT_BOUNDS } from "@ourworldindata/utils" @@ -48,13 +48,13 @@ export const StaticLineChartForExport = (): React.ReactElement => { } export const MapChart = (): React.ReactElement => ( - + ) export const StackedArea = (): React.ReactElement => ( @@ -63,7 +63,7 @@ export const Scatter = (): React.ReactElement => ( diff --git a/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.tsx b/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.tsx index 7e5b8482a13..2238dc78e8f 100644 --- a/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.tsx +++ b/packages/@ourworldindata/grapher/src/captionedChart/CaptionedChart.tsx @@ -34,11 +34,14 @@ import { HeaderManager } from "../header/HeaderManager" import { SelectionArray } from "../selection/SelectionArray" import { EntityName, - ChartTypeName, + GRAPHER_CHART_TYPES, FacetStrategy, RelatedQuestionsConfig, Color, GrapherTabName, + GRAPHER_MAP_TYPE, + GrapherChartOrMapType, + GrapherChartType, } from "@ourworldindata/types" import { DataTable, DataTableManager } from "../dataTable/DataTable" import { @@ -79,7 +82,7 @@ export interface CaptionedChartManager activeTab?: GrapherTabName isOnMapTab?: boolean isOnTableTab?: boolean - activeChartType?: ChartTypeName + activeChartType?: GrapherChartType isLineChartThatTurnedIntoDiscreteBar?: boolean showEntitySelectionToggle?: boolean isExportingForSocialMedia?: boolean @@ -189,29 +192,34 @@ export class CaptionedChart extends React.Component { return !this.manager.isOnMapTab && hasStrategy } - @computed get activeChartType(): ChartTypeName | undefined { + @computed get activeChartOrMapType(): GrapherChartOrMapType | undefined { const { manager } = this if (manager.isOnTableTab) return undefined - if (manager.isOnMapTab) return ChartTypeName.WorldMap + if (manager.isOnMapTab) return GRAPHER_MAP_TYPE if (manager.isOnChartTab) { return manager.isLineChartThatTurnedIntoDiscreteBar - ? ChartTypeName.DiscreteBar + ? GRAPHER_CHART_TYPES.DiscreteBar : manager.activeChartType } return undefined } renderChart(): React.ReactElement | void { - const { manager, activeChartType, containerElement } = this + const { + manager, + boundsForChartArea: bounds, + activeChartOrMapType, + containerElement, + } = this - if (!activeChartType) return - - const bounds = this.boundsForChartArea - const ChartClass = - ChartComponentClassMap.get(activeChartType) ?? DefaultChartClass + if (!activeChartOrMapType) return // Todo: make FacetChart a chart type name? - if (this.isFaceted) + const activeChartType = + activeChartOrMapType !== GRAPHER_MAP_TYPE + ? activeChartOrMapType + : undefined + if (this.isFaceted && activeChartType) return ( { /> ) + const ChartClass = + ChartComponentClassMap.get(activeChartOrMapType) ?? + DefaultChartClass + return ( { } export const ChartComponentClassMap = new Map< - ChartTypeName, + GrapherChartOrMapType, ChartComponentClass >([ - [ChartTypeName.DiscreteBar, DiscreteBarChart], - [ChartTypeName.LineChart, LineChart], - [ChartTypeName.SlopeChart, SlopeChart], - [ChartTypeName.StackedArea, StackedAreaChart], - [ChartTypeName.StackedBar, StackedBarChart], - [ChartTypeName.StackedDiscreteBar, StackedDiscreteBarChart], - [ChartTypeName.ScatterPlot, ScatterPlotChart], - [ChartTypeName.Marimekko, MarimekkoChart], - [ChartTypeName.WorldMap, MapChart], + [GRAPHER_CHART_TYPES.DiscreteBar, DiscreteBarChart], + [GRAPHER_CHART_TYPES.LineChart, LineChart], + [GRAPHER_CHART_TYPES.SlopeChart, SlopeChart], + [GRAPHER_CHART_TYPES.StackedArea, StackedAreaChart], + [GRAPHER_CHART_TYPES.StackedBar, StackedBarChart], + [GRAPHER_CHART_TYPES.StackedDiscreteBar, StackedDiscreteBarChart], + [GRAPHER_CHART_TYPES.ScatterPlot, ScatterPlotChart], + [GRAPHER_CHART_TYPES.Marimekko, MarimekkoChart], + [GRAPHER_MAP_TYPE, MapChart], ]) export const DefaultChartClass = LineChart as ChartComponentClass +export const defaultChartType = GRAPHER_CHART_TYPES.LineChart diff --git a/packages/@ourworldindata/grapher/src/chart/ChartTypeSwitcher.tsx b/packages/@ourworldindata/grapher/src/chart/ChartTypeSwitcher.tsx index 8afc64f6754..0e1886d7a8b 100644 --- a/packages/@ourworldindata/grapher/src/chart/ChartTypeSwitcher.tsx +++ b/packages/@ourworldindata/grapher/src/chart/ChartTypeSwitcher.tsx @@ -1,9 +1,12 @@ import React from "react" -import { ChartTypeName } from "@ourworldindata/types" +import { + ALL_GRAPHER_CHART_TYPES, + GrapherChartType, +} from "@ourworldindata/types" // Just a utility for testing export class ChartTypeSwitcher extends React.Component<{ - onChange: (chartType: ChartTypeName) => void + onChange: (chartType: GrapherChartType) => void }> { render(): React.ReactElement { return ( @@ -12,7 +15,7 @@ export class ChartTypeSwitcher extends React.Component<{ this.props.onChange(event.target.value as any) } > - {Object.values(ChartTypeName).map((value) => ( + {ALL_GRAPHER_CHART_TYPES.map((value) => ( diff --git a/packages/@ourworldindata/grapher/src/chart/ChartUtils.tsx b/packages/@ourworldindata/grapher/src/chart/ChartUtils.tsx index 4ba869a8132..375e9816c7a 100644 --- a/packages/@ourworldindata/grapher/src/chart/ChartUtils.tsx +++ b/packages/@ourworldindata/grapher/src/chart/ChartUtils.tsx @@ -4,7 +4,9 @@ import { SeriesStrategy, EntityName, GrapherTabQueryParam, - ChartTypeName, + GrapherChartType, + GRAPHER_CHART_TYPES, + GRAPHER_TAB_QUERY_PARAMS, } from "@ourworldindata/types" import { LineChartSeries } from "../lineCharts/LineChartConstants" import { SelectionArray } from "../selection/SelectionArray" @@ -128,51 +130,48 @@ export function isTargetOutsideElement( export function mapQueryParamToChartTypeName( chartTab: string -): ChartTypeName | undefined { +): GrapherChartType | undefined { switch (chartTab) { - case GrapherTabQueryParam.LineChart: - return ChartTypeName.LineChart - case GrapherTabQueryParam.SlopeChart: - return ChartTypeName.SlopeChart - case GrapherTabQueryParam.ScatterPlot: - return ChartTypeName.ScatterPlot - case GrapherTabQueryParam.StackedArea: - return ChartTypeName.StackedArea - case GrapherTabQueryParam.StackedBar: - return ChartTypeName.StackedBar - case GrapherTabQueryParam.DiscreteBar: - return ChartTypeName.DiscreteBar - case GrapherTabQueryParam.StackedDiscreteBar: - return ChartTypeName.StackedDiscreteBar - case GrapherTabQueryParam.Marimekko: - return ChartTypeName.Marimekko + case GRAPHER_TAB_QUERY_PARAMS.line: + return GRAPHER_CHART_TYPES.LineChart + case GRAPHER_TAB_QUERY_PARAMS.slope: + return GRAPHER_CHART_TYPES.SlopeChart + case GRAPHER_TAB_QUERY_PARAMS.scatter: + return GRAPHER_CHART_TYPES.ScatterPlot + case GRAPHER_TAB_QUERY_PARAMS["stacked-area"]: + return GRAPHER_CHART_TYPES.StackedArea + case GRAPHER_TAB_QUERY_PARAMS["stacked-bar"]: + return GRAPHER_CHART_TYPES.StackedBar + case GRAPHER_TAB_QUERY_PARAMS["discrete-bar"]: + return GRAPHER_CHART_TYPES.DiscreteBar + case GRAPHER_TAB_QUERY_PARAMS["stacked-discrete-bar"]: + return GRAPHER_CHART_TYPES.StackedDiscreteBar + case GRAPHER_TAB_QUERY_PARAMS.marimekko: + return GRAPHER_CHART_TYPES.Marimekko default: return undefined } } export function mapChartTypeNameToQueryParam( - chartType: ChartTypeName + chartType: GrapherChartType ): GrapherTabQueryParam { switch (chartType) { - case ChartTypeName.LineChart: - return GrapherTabQueryParam.LineChart - case ChartTypeName.SlopeChart: - return GrapherTabQueryParam.SlopeChart - case ChartTypeName.ScatterPlot: - return GrapherTabQueryParam.ScatterPlot - case ChartTypeName.StackedArea: - return GrapherTabQueryParam.StackedArea - case ChartTypeName.StackedBar: - return GrapherTabQueryParam.StackedBar - case ChartTypeName.DiscreteBar: - return GrapherTabQueryParam.DiscreteBar - case ChartTypeName.StackedDiscreteBar: - return GrapherTabQueryParam.StackedDiscreteBar - case ChartTypeName.Marimekko: - return GrapherTabQueryParam.Marimekko - // TODO: remove once stricter typed - default: - return GrapherTabQueryParam.LineChart + case GRAPHER_CHART_TYPES.LineChart: + return GRAPHER_TAB_QUERY_PARAMS.line + case GRAPHER_CHART_TYPES.SlopeChart: + return GRAPHER_TAB_QUERY_PARAMS.slope + case GRAPHER_CHART_TYPES.ScatterPlot: + return GRAPHER_TAB_QUERY_PARAMS.scatter + case GRAPHER_CHART_TYPES.StackedArea: + return GRAPHER_TAB_QUERY_PARAMS["stacked-area"] + case GRAPHER_CHART_TYPES.StackedBar: + return GRAPHER_TAB_QUERY_PARAMS["stacked-bar"] + case GRAPHER_CHART_TYPES.DiscreteBar: + return GRAPHER_TAB_QUERY_PARAMS["discrete-bar"] + case GRAPHER_CHART_TYPES.StackedDiscreteBar: + return GRAPHER_TAB_QUERY_PARAMS["stacked-discrete-bar"] + case GRAPHER_CHART_TYPES.Marimekko: + return GRAPHER_TAB_QUERY_PARAMS.marimekko } } diff --git a/packages/@ourworldindata/grapher/src/color/ColorSchemes.ts b/packages/@ourworldindata/grapher/src/color/ColorSchemes.ts index ab213d91406..7e553aee094 100644 --- a/packages/@ourworldindata/grapher/src/color/ColorSchemes.ts +++ b/packages/@ourworldindata/grapher/src/color/ColorSchemes.ts @@ -3,28 +3,32 @@ import { ColorScheme } from "./ColorScheme" import { match } from "ts-pattern" import { partition } from "@ourworldindata/utils" import { - ChartTypeName, + GRAPHER_CHART_TYPES, ColorSchemeInterface, ColorSchemeName, + GRAPHER_MAP_TYPE, + GrapherChartOrMapType, } from "@ourworldindata/types" import { getColorBrewerScheme } from "./ColorBrewerSchemes.js" -function getPreferredSchemesByType(type: ChartTypeName): ColorSchemeName[] { - // This function could also be a Map but +function getPreferredSchemesByType( + type: GrapherChartOrMapType +): ColorSchemeName[] { + // This function could also be a Map but // by doing it as a function usign ts-pattern.match we get compile - // time safety that all enum cases in ChartTypeName are always handled here + // time safety that all enum cases in GrapherChartOrMapType are always handled here return match(type) - .with(ChartTypeName.DiscreteBar, () => [ + .with(GRAPHER_CHART_TYPES.DiscreteBar, () => [ ColorSchemeName.SingleColorDenim, ColorSchemeName.SingleColorDustyCoral, ColorSchemeName.SingleColorPurple, ColorSchemeName.SingleColorTeal, ColorSchemeName.SingleColorDarkCopper, ]) - .with(ChartTypeName.LineChart, () => [ + .with(GRAPHER_CHART_TYPES.LineChart, () => [ ColorSchemeName.OwidDistinctLines, ]) - .with(ChartTypeName.Marimekko, () => [ + .with(GRAPHER_CHART_TYPES.Marimekko, () => [ ColorSchemeName.continents, ColorSchemeName.SingleColorDenim, ColorSchemeName.SingleColorDustyCoral, @@ -37,15 +41,15 @@ function getPreferredSchemesByType(type: ChartTypeName): ColorSchemeName[] { ColorSchemeName.OwidCategoricalD, ColorSchemeName.OwidCategoricalE, ]) - .with(ChartTypeName.ScatterPlot, () => [ + .with(GRAPHER_CHART_TYPES.ScatterPlot, () => [ ColorSchemeName.continents, ColorSchemeName.OwidDistinctLines, ]) - .with(ChartTypeName.SlopeChart, () => [ + .with(GRAPHER_CHART_TYPES.SlopeChart, () => [ ColorSchemeName.continents, ColorSchemeName.OwidDistinctLines, ]) - .with(ChartTypeName.StackedArea, () => [ + .with(GRAPHER_CHART_TYPES.StackedArea, () => [ ColorSchemeName["owid-distinct"], ColorSchemeName.OwidCategoricalA, ColorSchemeName.OwidCategoricalB, @@ -58,7 +62,7 @@ function getPreferredSchemesByType(type: ChartTypeName): ColorSchemeName[] { ColorSchemeName.SingleColorGradientDustyCoral, ColorSchemeName.SingleColorGradientDarkCopper, ]) - .with(ChartTypeName.StackedBar, () => [ + .with(GRAPHER_CHART_TYPES.StackedBar, () => [ ColorSchemeName["owid-distinct"], ColorSchemeName.OwidCategoricalA, ColorSchemeName.OwidCategoricalB, @@ -71,7 +75,7 @@ function getPreferredSchemesByType(type: ChartTypeName): ColorSchemeName[] { ColorSchemeName.SingleColorGradientDustyCoral, ColorSchemeName.SingleColorGradientDarkCopper, ]) - .with(ChartTypeName.StackedDiscreteBar, () => [ + .with(GRAPHER_CHART_TYPES.StackedDiscreteBar, () => [ ColorSchemeName["owid-distinct"], ColorSchemeName.OwidCategoricalA, ColorSchemeName.OwidCategoricalB, @@ -84,7 +88,7 @@ function getPreferredSchemesByType(type: ChartTypeName): ColorSchemeName[] { ColorSchemeName.SingleColorGradientDustyCoral, ColorSchemeName.SingleColorGradientDarkCopper, ]) - .with(ChartTypeName.WorldMap, () => [ + .with(GRAPHER_MAP_TYPE, () => [ ColorSchemeName.BinaryMapPaletteA, ColorSchemeName.BinaryMapPaletteB, ColorSchemeName.BinaryMapPaletteC, @@ -129,7 +133,7 @@ const getAllColorSchemes = (): Map => { ) } -export function getColorSchemeForChartType(type: ChartTypeName): { +export function getColorSchemeForChartType(type: GrapherChartOrMapType): { [key in ColorSchemeName]: ColorScheme } { const preferred = new Set(getPreferredSchemesByType(type)) diff --git a/packages/@ourworldindata/grapher/src/controls/ChartIcons.tsx b/packages/@ourworldindata/grapher/src/controls/ChartIcons.tsx index 605c2f7fd7f..00b89c46017 100644 --- a/packages/@ourworldindata/grapher/src/controls/ChartIcons.tsx +++ b/packages/@ourworldindata/grapher/src/controls/ChartIcons.tsx @@ -4,21 +4,22 @@ import { faChartBar, faChartLine, faChartColumn, - faEarthAmericas, } from "@fortawesome/free-solid-svg-icons" -import { ChartTypeName } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES, GrapherChartType } from "@ourworldindata/types" -export const chartIcons: Record = { +export const chartIcons: Record = { // line chart - [ChartTypeName.LineChart]: , + [GRAPHER_CHART_TYPES.LineChart]: , // bar charts - [ChartTypeName.DiscreteBar]: , - [ChartTypeName.StackedBar]: , - [ChartTypeName.StackedDiscreteBar]: , + [GRAPHER_CHART_TYPES.DiscreteBar]: , + [GRAPHER_CHART_TYPES.StackedBar]: , + [GRAPHER_CHART_TYPES.StackedDiscreteBar]: ( + + ), // scatter - [ChartTypeName.ScatterPlot]: ( + [GRAPHER_CHART_TYPES.ScatterPlot]: ( = { ), // marimekko - [ChartTypeName.Marimekko]: ( + [GRAPHER_CHART_TYPES.Marimekko]: ( = { ), // stacked area - [ChartTypeName.StackedArea]: ( + [GRAPHER_CHART_TYPES.StackedArea]: ( = { ), // slope chart - [ChartTypeName.SlopeChart]: ( + [GRAPHER_CHART_TYPES.SlopeChart]: ( = { ), - - // world map (will never be invoked but included for completeness) - [ChartTypeName.WorldMap]: , } diff --git a/packages/@ourworldindata/grapher/src/controls/ContentSwitchers.tsx b/packages/@ourworldindata/grapher/src/controls/ContentSwitchers.tsx index 52504d58dad..6c0eaa289a5 100644 --- a/packages/@ourworldindata/grapher/src/controls/ContentSwitchers.tsx +++ b/packages/@ourworldindata/grapher/src/controls/ContentSwitchers.tsx @@ -4,7 +4,11 @@ import { observer } from "mobx-react" import classnames from "classnames" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js" import { faTable, faEarthAmericas } from "@fortawesome/free-solid-svg-icons" -import { ChartTypeName, GrapherTabName } from "@ourworldindata/types" +import { + GRAPHER_CHART_TYPES, + GrapherTabName, + GRAPHER_TAB_NAMES, +} from "@ourworldindata/types" import { chartIcons } from "./ChartIcons" import { Bounds } from "@ourworldindata/utils" import { TabLabel, Tabs } from "../tabs/Tabs.js" @@ -166,14 +170,14 @@ function TabIcon({ isLineChartThatTurnedIntoDiscreteBar?: boolean }): React.ReactElement { switch (tab) { - case GrapherTabName.Table: + case GRAPHER_TAB_NAMES.Table: return - case GrapherTabName.WorldMap: + case GRAPHER_TAB_NAMES.WorldMap: return default: const chartIcon = isLineChartThatTurnedIntoDiscreteBar - ? chartIcons[ChartTypeName.DiscreteBar] - : chartIcons[tab as unknown as ChartTypeName] + ? chartIcons[GRAPHER_CHART_TYPES.DiscreteBar] + : chartIcons[tab] return chartIcon } } @@ -185,28 +189,28 @@ function makeTabLabelText( hasMultipleChartTypes?: boolean } ): string { - if (tab === GrapherTabName.Table) return "Table" - if (tab === GrapherTabName.WorldMap) return "Map" + if (tab === GRAPHER_TAB_NAMES.Table) return "Table" + if (tab === GRAPHER_TAB_NAMES.WorldMap) return "Map" if (!options.hasMultipleChartTypes) return "Chart" switch (tab) { - case GrapherTabName.LineChart: + case GRAPHER_TAB_NAMES.LineChart: return options.isLineChartThatTurnedIntoDiscreteBar ? "Bar" : "Line" - case GrapherTabName.SlopeChart: + case GRAPHER_TAB_NAMES.SlopeChart: return "Slope" // chart type labels are preliminary - case GrapherTabName.ScatterPlot: + case GRAPHER_TAB_NAMES.ScatterPlot: return "Scatter" - case GrapherTabName.StackedArea: + case GRAPHER_TAB_NAMES.StackedArea: return "Stacked area" - case GrapherTabName.StackedBar: + case GRAPHER_TAB_NAMES.StackedBar: return "Stacked bar" - case GrapherTabName.DiscreteBar: + case GRAPHER_TAB_NAMES.DiscreteBar: return "Bar" - case GrapherTabName.StackedDiscreteBar: + case GRAPHER_TAB_NAMES.StackedDiscreteBar: return "Stacked bar" - case GrapherTabName.Marimekko: + case GRAPHER_TAB_NAMES.Marimekko: return "Marimekko" default: return "Chart" diff --git a/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx b/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx index 200bafc0967..30cbd370147 100644 --- a/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx +++ b/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx @@ -4,7 +4,12 @@ import { observer } from "mobx-react" import classnames from "classnames" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js" import { faGear } from "@fortawesome/free-solid-svg-icons" -import { EntityName, ChartTypeName, FacetStrategy } from "@ourworldindata/types" +import { + EntityName, + GRAPHER_CHART_TYPES, + FacetStrategy, + GrapherChartType, +} from "@ourworldindata/types" import { DEFAULT_BOUNDS } from "@ourworldindata/utils" import { SelectionArray } from "../selection/SelectionArray" import { ChartDimension } from "../chart/ChartDimension" @@ -46,7 +51,7 @@ const { StackedDiscreteBar, StackedBar, Marimekko, -} = ChartTypeName +} = GRAPHER_CHART_TYPES export interface SettingsMenuManager extends AbsRelToggleManager, @@ -67,7 +72,7 @@ export interface SettingsMenuManager hideTableFilterToggle?: boolean // chart state - activeChartType?: ChartTypeName + activeChartType?: GrapherChartType isRelativeMode?: boolean selection?: SelectionArray | EntityName[] canChangeAddOrHighlightEntities?: boolean @@ -104,8 +109,8 @@ export class SettingsMenu extends React.Component<{ return test.showSettingsMenuToggle } - @computed get chartType(): ChartTypeName { - return this.manager.activeChartType ?? ChartTypeName.LineChart + @computed get chartType(): GrapherChartType { + return this.manager.activeChartType ?? GRAPHER_CHART_TYPES.LineChart } @computed get maxWidth(): number { @@ -115,7 +120,8 @@ export class SettingsMenu extends React.Component<{ @computed get showYScaleToggle(): boolean | undefined { if (this.manager.hideYScaleToggle) return false if (this.manager.isRelativeMode) return false - if ([StackedArea, StackedBar].includes(this.chartType)) return false // We currently do not have these charts with log scale + if ([StackedArea, StackedBar].includes(this.chartType as any)) + return false // We currently do not have these charts with log scale return this.manager.yAxis.canChangeScaleType } @@ -164,7 +170,7 @@ export class SettingsMenu extends React.Component<{ ScatterPlot, LineChart, Marimekko, - ].includes(this.chartType) + ].includes(this.chartType as any) } @computed get showFacetControl(): boolean { @@ -187,7 +193,7 @@ export class SettingsMenu extends React.Component<{ StackedBar, StackedDiscreteBar, LineChart, - ].includes(this.chartType) + ].includes(this.chartType as any) const hasProjection = filledDimensions.some( (dim) => dim.display.isProjection diff --git a/packages/@ourworldindata/grapher/src/controls/settings/AbsRelToggle.tsx b/packages/@ourworldindata/grapher/src/controls/settings/AbsRelToggle.tsx index fd9e6c17a55..b90e825960b 100644 --- a/packages/@ourworldindata/grapher/src/controls/settings/AbsRelToggle.tsx +++ b/packages/@ourworldindata/grapher/src/controls/settings/AbsRelToggle.tsx @@ -1,15 +1,19 @@ import React from "react" import { computed, action } from "mobx" import { observer } from "mobx-react" -import { ChartTypeName, StackMode } from "@ourworldindata/types" +import { + GRAPHER_CHART_TYPES, + GrapherChartType, + StackMode, +} from "@ourworldindata/types" import { LabeledSwitch } from "@ourworldindata/components" -const { LineChart, ScatterPlot } = ChartTypeName +const { LineChart, ScatterPlot } = GRAPHER_CHART_TYPES export interface AbsRelToggleManager { stackMode?: StackMode relativeToggleLabel?: string - activeChartType?: ChartTypeName + activeChartType?: GrapherChartType } @observer diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.jsdom.test.ts b/packages/@ourworldindata/grapher/src/core/Grapher.jsdom.test.ts index fd221f0eacd..1b586576981 100755 --- a/packages/@ourworldindata/grapher/src/core/Grapher.jsdom.test.ts +++ b/packages/@ourworldindata/grapher/src/core/Grapher.jsdom.test.ts @@ -1,15 +1,15 @@ #! /usr/bin/env jest import { Grapher, GrapherProgrammaticInterface } from "../core/Grapher" import { - ChartTypeName, + GRAPHER_CHART_TYPES, EntitySelectionMode, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, ScaleType, GrapherInterface, GrapherQueryParams, LegacyGrapherInterface, LegacyGrapherQueryParams, - GrapherTabName, + GRAPHER_TAB_NAMES, } from "@ourworldindata/types" import { TimeBoundValue, @@ -72,7 +72,7 @@ it("can get dimension slots", () => { const grapher = new Grapher() expect(grapher.dimensionSlots.length).toBe(2) - grapher.chartTypes = [ChartTypeName.ScatterPlot] + grapher.chartTypes = [GRAPHER_CHART_TYPES.ScatterPlot] expect(grapher.dimensionSlots.length).toBe(4) }) @@ -99,7 +99,7 @@ it("a bad chart type does not crash grapher", () => { }) it("does not preserve defaults in the object (except for the schema)", () => { - expect(new Grapher({ tab: GrapherTabOption.chart }).toObject()).toEqual({ + expect(new Grapher({ tab: GRAPHER_TAB_OPTIONS.chart }).toObject()).toEqual({ $schema: latestGrapherConfigSchema, // TODO: ideally, selectedEntityNames is not serialised for an empty object @@ -212,24 +212,24 @@ it("can generate a url with country selection even if there is no entity code", describe("hasTimeline", () => { it("charts with timeline", () => { const grapher = new Grapher(legacyConfig) - grapher.chartTypes = [ChartTypeName.LineChart] + grapher.chartTypes = [GRAPHER_CHART_TYPES.LineChart] expect(grapher.hasTimeline).toBeTruthy() - grapher.chartTypes = [ChartTypeName.SlopeChart] + grapher.chartTypes = [GRAPHER_CHART_TYPES.SlopeChart] expect(grapher.hasTimeline).toBeTruthy() - grapher.chartTypes = [ChartTypeName.StackedArea] + grapher.chartTypes = [GRAPHER_CHART_TYPES.StackedArea] expect(grapher.hasTimeline).toBeTruthy() - grapher.chartTypes = [ChartTypeName.StackedBar] + grapher.chartTypes = [GRAPHER_CHART_TYPES.StackedBar] expect(grapher.hasTimeline).toBeTruthy() - grapher.chartTypes = [ChartTypeName.DiscreteBar] + grapher.chartTypes = [GRAPHER_CHART_TYPES.DiscreteBar] expect(grapher.hasTimeline).toBeTruthy() }) it("map tab has timeline even if chart doesn't", () => { const grapher = new Grapher(legacyConfig) grapher.hideTimeline = true - grapher.chartTypes = [ChartTypeName.LineChart] + grapher.chartTypes = [GRAPHER_CHART_TYPES.LineChart] expect(grapher.hasTimeline).toBeFalsy() - grapher.tab = GrapherTabOption.map + grapher.tab = GRAPHER_TAB_OPTIONS.map expect(grapher.hasTimeline).toBeTruthy() grapher.map.hideTimeline = true expect(grapher.hasTimeline).toBeFalsy() @@ -380,7 +380,7 @@ describe("authors can use maxTime", () => { const table = SynthesizeGDPTable({ timeRange: [2000, 2010] }) const grapher = new Grapher({ table, - chartTypes: [ChartTypeName.DiscreteBar], + chartTypes: [GRAPHER_CHART_TYPES.DiscreteBar], selectedEntityNames: table.availableEntityNames, maxTime: 2005, ySlugs: "GDP", @@ -396,7 +396,7 @@ describe("line chart to bar chart and bar chart race", () => { it("can create a new line chart with different start and end times", () => { expect( grapher.typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart - ).toEqual(ChartTypeName.LineChart) + ).toEqual(GRAPHER_CHART_TYPES.LineChart) expect(grapher.endHandleTimeBound).toBeGreaterThan( grapher.startHandleTimeBound ) @@ -408,13 +408,13 @@ describe("line chart to bar chart and bar chart race", () => { expect( grapher.typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart - ).toEqual(ChartTypeName.LineChart) + ).toEqual(GRAPHER_CHART_TYPES.LineChart) grapher.startHandleTimeBound = 2000 grapher.endHandleTimeBound = 2000 expect( grapher.typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart - ).toEqual(ChartTypeName.DiscreteBar) + ).toEqual(GRAPHER_CHART_TYPES.DiscreteBar) it("still has a timeline even though its now a bar chart", () => { expect(grapher.hasTimeline).toBe(true) @@ -450,7 +450,7 @@ describe("line chart to bar chart and bar chart race", () => { ) expect( grapher.typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart - ).toEqual(ChartTypeName.LineChart) + ).toEqual(GRAPHER_CHART_TYPES.LineChart) }) it("turns into a bar chart when constrained start & end handles are equal", () => { @@ -458,7 +458,7 @@ describe("line chart to bar chart and bar chart race", () => { grapher.endHandleTimeBound = Infinity expect( grapher.typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart - ).toEqual(ChartTypeName.DiscreteBar) + ).toEqual(GRAPHER_CHART_TYPES.DiscreteBar) }) }) @@ -483,7 +483,7 @@ describe("urls", () => { isPublished: true, slug: "foo", bakedGrapherURL: "/grapher", - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, }) expect(grapher.embedUrl).toEqual("/grapher/foo?tab=map") }) @@ -514,67 +514,78 @@ describe("urls", () => { it("parses tab=table correctly", () => { const grapher = new Grapher() grapher.populateFromQueryParams({ tab: "table" }) - expect(grapher.activeTab).toEqual(GrapherTabName.Table) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.Table) }) it("parses tab=map correctly", () => { const grapher = new Grapher() grapher.populateFromQueryParams({ tab: "map" }) - expect(grapher.activeTab).toEqual(GrapherTabName.WorldMap) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.WorldMap) }) it("parses tab=chart correctly", () => { - const grapher = new Grapher({ chartTypes: [ChartTypeName.ScatterPlot] }) + const grapher = new Grapher({ + chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot], + }) grapher.populateFromQueryParams({ tab: "chart" }) - expect(grapher.activeTab).toEqual(GrapherTabName.ScatterPlot) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.ScatterPlot) }) it("parses tab=line and tab=slope correctly", () => { const grapher = new Grapher({ - chartTypes: [ChartTypeName.LineChart, ChartTypeName.SlopeChart], + chartTypes: [ + GRAPHER_CHART_TYPES.LineChart, + GRAPHER_CHART_TYPES.SlopeChart, + ], }) grapher.populateFromQueryParams({ tab: "line" }) - expect(grapher.activeTab).toEqual(GrapherTabName.LineChart) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.LineChart) grapher.populateFromQueryParams({ tab: "slope" }) - expect(grapher.activeTab).toEqual(GrapherTabName.SlopeChart) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.SlopeChart) }) it("switches to the first chart tab if the given chart isn't available", () => { const grapher = new Grapher({ - chartTypes: [ChartTypeName.LineChart, ChartTypeName.SlopeChart], + chartTypes: [ + GRAPHER_CHART_TYPES.LineChart, + GRAPHER_CHART_TYPES.SlopeChart, + ], }) grapher.populateFromQueryParams({ tab: "bar" }) - expect(grapher.activeTab).toEqual(GrapherTabName.LineChart) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.LineChart) }) it("switches to the map tab if no chart is available", () => { const grapher = new Grapher({ chartTypes: [], hasMapTab: true }) grapher.populateFromQueryParams({ tab: "line" }) - expect(grapher.activeTab).toEqual(GrapherTabName.WorldMap) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.WorldMap) }) it("switches to the table tab if it's the only tab available", () => { const grapher = new Grapher({ chartTypes: [] }) grapher.populateFromQueryParams({ tab: "line" }) - expect(grapher.activeTab).toEqual(GrapherTabName.Table) + expect(grapher.activeTab).toEqual(GRAPHER_TAB_NAMES.Table) }) it("adds tab=chart to the URL if there is a single chart tab", () => { const grapher = new Grapher({ hasMapTab: true, - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, }) - grapher.setTab(GrapherTabName.LineChart) + grapher.setTab(GRAPHER_TAB_NAMES.LineChart) expect(grapher.changedParams.tab).toEqual("chart") }) it("adds the chart type name as tab query param if there are multiple chart tabs", () => { const grapher = new Grapher({ - chartTypes: [ChartTypeName.LineChart, ChartTypeName.SlopeChart], + chartTypes: [ + GRAPHER_CHART_TYPES.LineChart, + GRAPHER_CHART_TYPES.SlopeChart, + ], hasMapTab: true, - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, }) - grapher.setTab(GrapherTabName.LineChart) + grapher.setTab(GRAPHER_TAB_NAMES.LineChart) expect(grapher.changedParams.tab).toEqual("line") }) }) @@ -902,7 +913,7 @@ describe("year parameter (applies to map only)", () => { }) it(`encode ${test.name}`, () => { const params = toQueryParams({ - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, map: { time: test.param }, }) expect(params.time).toEqual(test.query) @@ -968,7 +979,7 @@ describe("year parameter (applies to map only)", () => { it(`encode ${test.name}`, () => { const grapher = getGrapher() grapher.updateFromObject({ - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, map: { time: test.param }, }) const params = grapher.changedParams @@ -986,7 +997,7 @@ it("correctly identifies activeColumnSlugs", () => { `) const grapher = new Grapher({ table, - chartTypes: [ChartTypeName.ScatterPlot], + chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot], xSlug: "gdp", ySlugs: "child_mortality", colorSlug: "continent", @@ -1024,7 +1035,7 @@ it("considers map tolerance before using column tolerance", () => { const grapher = new Grapher({ table, ySlugs: "gdp", - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, hasMapTab: true, map: new MapConfig({ timeTolerance: 1, columnSlug: "gdp", time: 2002 }), }) @@ -1084,7 +1095,7 @@ describe("tableForSelection", () => { const grapher = new Grapher({ table, - chartTypes: [ChartTypeName.ScatterPlot], + chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot], excludedEntities: [3], xSlug: "x", ySlugs: "y", @@ -1120,7 +1131,7 @@ it("handles tolerance when there are gaps in ScatterPlot data", () => { const grapher = new Grapher({ table, - chartTypes: [ChartTypeName.ScatterPlot], + chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot], xSlug: "x", ySlugs: "y", minTime: 1999, diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.stories.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.stories.tsx index 84248560305..e7b31d2b84b 100644 --- a/packages/@ourworldindata/grapher/src/core/Grapher.stories.tsx +++ b/packages/@ourworldindata/grapher/src/core/Grapher.stories.tsx @@ -6,9 +6,9 @@ import { BlankOwidTable, } from "@ourworldindata/core-table" import { - ChartTypeName, + GRAPHER_CHART_TYPES, FacetStrategy, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, } from "@ourworldindata/types" import { action, observable } from "mobx" import { observer } from "mobx-react" @@ -49,7 +49,7 @@ export const Line = (): React.ReactElement => export const SlopeChart = (): React.ReactElement => { const model = { - chartTypes: [ChartTypeName.SlopeChart], + chartTypes: [GRAPHER_CHART_TYPES.SlopeChart], ...basics, } return @@ -57,7 +57,7 @@ export const SlopeChart = (): React.ReactElement => { export const ScatterPlot = (): React.ReactElement => { const model = { - chartTypes: [ChartTypeName.ScatterPlot], + chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot], ...basics, } return @@ -65,7 +65,7 @@ export const ScatterPlot = (): React.ReactElement => { export const DiscreteBar = (): React.ReactElement => { const model = { - chartTypes: [ChartTypeName.DiscreteBar], + chartTypes: [GRAPHER_CHART_TYPES.DiscreteBar], ...basics, } return @@ -73,7 +73,7 @@ export const DiscreteBar = (): React.ReactElement => { export const StackedBar = (): React.ReactElement => { const model = { - chartTypes: [ChartTypeName.StackedBar], + chartTypes: [GRAPHER_CHART_TYPES.StackedBar], ...basics, } return @@ -81,7 +81,7 @@ export const StackedBar = (): React.ReactElement => { export const StackedArea = (): React.ReactElement => { const model = { - chartTypes: [ChartTypeName.StackedArea], + chartTypes: [GRAPHER_CHART_TYPES.StackedArea], ...basics, } return @@ -90,14 +90,14 @@ export const StackedArea = (): React.ReactElement => { export const MapFirst = (): React.ReactElement => { const model = { ...basics, - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, } return } export const BlankGrapher = (): React.ReactElement => { const model = { - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, table: BlankOwidTable(), hasMapTab: true, } @@ -114,7 +114,7 @@ export const NoMap = (): React.ReactElement => { export const Faceting = (): React.ReactElement => { const model = { - chartTypes: [ChartTypeName.StackedArea], + chartTypes: [GRAPHER_CHART_TYPES.StackedArea], facet: FacetStrategy.entity, ...basics, } @@ -141,11 +141,11 @@ class PerfGrapher extends React.Component { @observable.ref table = basics.table! - @action.bound private changeChartType(type: ChartTypeName): void { + @action.bound private changeChartType(type: GRAPHER_CHART_TYPES): void { this.chartTypeName = type } - @observable chartTypeName = ChartTypeName.LineChart + @observable chartTypeName = GRAPHER_CHART_TYPES.LineChart render(): React.ReactElement { const key = Math.random() // I do this hack to force a rerender until can re-add the grapher model/grapher view that we used to have. @breck 10/29/2020 diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.tsx index 8e8038f5327..6d5c5a103e5 100644 --- a/packages/@ourworldindata/grapher/src/core/Grapher.tsx +++ b/packages/@ourworldindata/grapher/src/core/Grapher.tsx @@ -73,8 +73,7 @@ import { sumTextWrapHeights, } from "@ourworldindata/components" import { - ChartTypeName, - GrapherTabOption, + GrapherChartType, ScaleType, StackMode, EntitySelectionMode, @@ -108,7 +107,11 @@ import { GRAPHER_QUERY_PARAM_KEYS, GrapherTooltipAnchor, GrapherTabName, - GrapherTabQueryParam, + GRAPHER_CHART_TYPES, + GRAPHER_TAB_OPTIONS, + GRAPHER_TAB_NAMES, + GRAPHER_TAB_QUERY_PARAMS, + GrapherTabOption, } from "@ourworldindata/types" import { BlankOwidTable, @@ -360,7 +363,9 @@ export class Grapher SlopeChartManager { @observable.ref $schema = latestGrapherConfigSchema - @observable.ref chartTypes = [ChartTypeName.LineChart] + @observable.ref chartTypes: GrapherChartType[] = [ + GRAPHER_CHART_TYPES.LineChart, + ] @observable.ref id?: number = undefined @observable.ref version = 1 @observable.ref slug?: string = undefined @@ -395,8 +400,8 @@ export class Grapher @observable.ref zoomToSelection?: boolean = undefined @observable.ref showYearLabels?: boolean = undefined // Always show year in labels for bar charts @observable.ref hasMapTab = false - @observable.ref tab = GrapherTabOption.chart - @observable.ref chartTab?: ChartTypeName // TODO: remove map from ChartTypeName + @observable.ref tab: GrapherTabOption = GRAPHER_TAB_OPTIONS.chart + @observable.ref chartTab?: GrapherChartType @observable.ref isPublished?: boolean = undefined @observable.ref baseColorScheme?: ColorSchemeName = undefined @observable.ref invertColorScheme?: boolean = undefined @@ -705,21 +710,20 @@ export class Grapher } @computed get activeTab(): GrapherTabName { - if (this.tab === GrapherTabOption.table) return GrapherTabName.Table - if (this.tab === GrapherTabOption.map) return GrapherTabName.WorldMap - if (this.chartTab) return this.chartTab as unknown as GrapherTabName - return ( - (this.chartType as unknown as GrapherTabName) ?? - GrapherTabName.LineChart - ) + if (this.tab === GRAPHER_TAB_OPTIONS.table) + return GRAPHER_TAB_NAMES.Table + if (this.tab === GRAPHER_TAB_OPTIONS.map) + return GRAPHER_TAB_NAMES.WorldMap + if (this.chartTab) return this.chartTab + return this.chartType ?? GRAPHER_TAB_NAMES.LineChart } - @computed get activeChartType(): ChartTypeName | undefined { + @computed get activeChartType(): GrapherChartType | undefined { if (!this.isOnChartTab) return undefined - return this.activeTab as unknown as ChartTypeName + return this.activeTab as GrapherChartType } - @computed get chartType(): ChartTypeName | undefined { + @computed get chartType(): GrapherChartType | undefined { return this.validChartTypes[0] } @@ -728,15 +732,15 @@ export class Grapher } @computed get isOnChartTab(): boolean { - return this.tab === GrapherTabOption.chart + return this.tab === GRAPHER_TAB_OPTIONS.chart } @computed get isOnMapTab(): boolean { - return this.tab === GrapherTabOption.map + return this.tab === GRAPHER_TAB_OPTIONS.map } @computed get isOnTableTab(): boolean { - return this.tab === GrapherTabOption.table + return this.tab === GRAPHER_TAB_OPTIONS.table } @computed get isOnChartOrMapTab(): boolean { @@ -1295,15 +1299,15 @@ export class Grapher } @action.bound setTab(newTab: GrapherTabName): void { - if (newTab === GrapherTabName.Table) { - this.tab = GrapherTabOption.table + if (newTab === GRAPHER_TAB_NAMES.Table) { + this.tab = GRAPHER_TAB_OPTIONS.table this.chartTab = undefined - } else if (newTab === GrapherTabName.WorldMap) { - this.tab = GrapherTabOption.map + } else if (newTab === GRAPHER_TAB_NAMES.WorldMap) { + this.tab = GRAPHER_TAB_OPTIONS.map this.chartTab = undefined } else { - this.tab = GrapherTabOption.chart - this.chartTab = newTab as unknown as ChartTypeName + this.tab = GRAPHER_TAB_OPTIONS.chart + this.chartTab = newTab } } @@ -1521,7 +1525,7 @@ export class Grapher }) } - @computed get validChartTypes(): ChartTypeName[] { + @computed get validChartTypes(): GrapherChartType[] { const { chartTypes } = this // all single-chart Graphers are valid @@ -1538,18 +1542,15 @@ export class Grapher return chartTypes.slice(0, 1) } - @computed get validChartTypeSet(): Set { + @computed get validChartTypeSet(): Set { return new Set(this.validChartTypes) } @computed get availableTabs(): GrapherTabName[] { const availableTabs: GrapherTabName[] = [] - if (this.hasTableTab) availableTabs.push(GrapherTabName.Table) - if (this.hasMapTab) availableTabs.push(GrapherTabName.WorldMap) - if (!this.hideChartTabs) - availableTabs.push( - ...(this.validChartTypes as unknown as GrapherTabName[]) - ) + if (this.hasTableTab) availableTabs.push(GRAPHER_TAB_NAMES.Table) + if (this.hasMapTab) availableTabs.push(GRAPHER_TAB_NAMES.WorldMap) + if (!this.hideChartTabs) availableTabs.push(...this.validChartTypes) return availableTabs } @@ -1575,7 +1576,7 @@ export class Grapher return !!( !this.forceHideAnnotationFieldsInTitle?.entity && - this.tab === GrapherTabOption.chart && + this.tab === GRAPHER_TAB_OPTIONS.chart && (seriesStrategy !== SeriesStrategy.entity || !this.showLegend) && selectedEntityNames.length === 1 && (showEntityAnnotation || @@ -1649,15 +1650,15 @@ export class Grapher switch (this.tab) { // the map tab has its own `hideTimeline` option - case GrapherTabOption.map: + case GRAPHER_TAB_OPTIONS.map: return !this.map.hideTimeline // use the chart-level `hideTimeline` option - case GrapherTabOption.chart: + case GRAPHER_TAB_OPTIONS.chart: return !this.hideTimeline // use the chart-level `hideTimeline` option for the table, with some exceptions - case GrapherTabOption.table: + case GRAPHER_TAB_OPTIONS.table: // always show the timeline for charts that plot time on the x-axis if (this.hasTimeDimension) return true return !this.hideTimeline @@ -1932,35 +1933,37 @@ export class Grapher } @computed - get typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart(): ChartTypeName { + get typeExceptWhenLineChartAndSingleTimeThenWillBeBarChart(): GrapherChartType { return this.isLineChartThatTurnedIntoDiscreteBar - ? ChartTypeName.DiscreteBar - : this.activeChartType ?? ChartTypeName.LineChart + ? GRAPHER_CHART_TYPES.DiscreteBar + : this.activeChartType ?? GRAPHER_CHART_TYPES.LineChart } @computed get isLineChart(): boolean { - return this.chartType === ChartTypeName.LineChart || !this.chartType + return ( + this.chartType === GRAPHER_CHART_TYPES.LineChart || !this.chartType + ) } @computed get isScatter(): boolean { - return this.chartType === ChartTypeName.ScatterPlot + return this.chartType === GRAPHER_CHART_TYPES.ScatterPlot } @computed get isStackedArea(): boolean { - return this.chartType === ChartTypeName.StackedArea + return this.chartType === GRAPHER_CHART_TYPES.StackedArea } @computed get isSlopeChart(): boolean { - return this.chartType === ChartTypeName.SlopeChart + return this.chartType === GRAPHER_CHART_TYPES.SlopeChart } @computed get isDiscreteBar(): boolean { - return this.chartType === ChartTypeName.DiscreteBar + return this.chartType === GRAPHER_CHART_TYPES.DiscreteBar } @computed get isStackedBar(): boolean { - return this.chartType === ChartTypeName.StackedBar + return this.chartType === GRAPHER_CHART_TYPES.StackedBar } @computed get isMarimekko(): boolean { - return this.chartType === ChartTypeName.Marimekko + return this.chartType === GRAPHER_CHART_TYPES.Marimekko } @computed get isStackedDiscreteBar(): boolean { - return this.chartType === ChartTypeName.StackedDiscreteBar + return this.chartType === GRAPHER_CHART_TYPES.StackedDiscreteBar } @computed get isLineChartThatTurnedIntoDiscreteBar(): boolean { @@ -1991,35 +1994,35 @@ export class Grapher } @computed get isOnLineChartTab(): boolean { - return this.activeChartType === ChartTypeName.LineChart + return this.activeChartType === GRAPHER_CHART_TYPES.LineChart } @computed get isOnScatterTab(): boolean { - return this.activeChartType === ChartTypeName.ScatterPlot + return this.activeChartType === GRAPHER_CHART_TYPES.ScatterPlot } @computed get isOnStackedAreaTab(): boolean { - return this.activeChartType === ChartTypeName.StackedArea + return this.activeChartType === GRAPHER_CHART_TYPES.StackedArea } @computed get isOnSlopeChartTab(): boolean { - return this.activeChartType === ChartTypeName.SlopeChart + return this.activeChartType === GRAPHER_CHART_TYPES.SlopeChart } @computed get isOnDiscreteBarTab(): boolean { - return this.activeChartType === ChartTypeName.DiscreteBar + return this.activeChartType === GRAPHER_CHART_TYPES.DiscreteBar } @computed get isOnStackedBarTab(): boolean { - return this.activeChartType === ChartTypeName.StackedBar + return this.activeChartType === GRAPHER_CHART_TYPES.StackedBar } @computed get isOnMarimekkoTab(): boolean { - return this.activeChartType === ChartTypeName.Marimekko + return this.activeChartType === GRAPHER_CHART_TYPES.Marimekko } @computed get isOnStackedDiscreteBarTab(): boolean { - return this.activeChartType === ChartTypeName.StackedDiscreteBar + return this.activeChartType === GRAPHER_CHART_TYPES.StackedDiscreteBar } @computed get hasLineChart(): boolean { - return this.validChartTypeSet.has(ChartTypeName.LineChart) + return this.validChartTypeSet.has(GRAPHER_CHART_TYPES.LineChart) } @computed get hasSlopeChart(): boolean { - return this.validChartTypeSet.has(ChartTypeName.SlopeChart) + return this.validChartTypeSet.has(GRAPHER_CHART_TYPES.SlopeChart) } @computed get supportsMultipleYColumns(): boolean { @@ -3265,20 +3268,20 @@ export class Grapher hasMapTab, } = this - if (tab === GrapherTabQueryParam.Table) { - return GrapherTabName.Table + if (tab === GRAPHER_TAB_QUERY_PARAMS.table) { + return GRAPHER_TAB_NAMES.Table } - if (tab === GrapherTabQueryParam.WorldMap) { - return GrapherTabName.WorldMap + if (tab === GRAPHER_TAB_QUERY_PARAMS.map) { + return GRAPHER_TAB_NAMES.WorldMap } - if (tab === GrapherTabQueryParam.Chart) { + if (tab === GRAPHER_TAB_QUERY_PARAMS.chart) { if (defaultChartType) { - return defaultChartType as unknown as GrapherTabName + return defaultChartType } else if (hasMapTab) { - return GrapherTabName.WorldMap + return GRAPHER_TAB_NAMES.WorldMap } else { - return GrapherTabName.Table + return GRAPHER_TAB_NAMES.Table } } @@ -3287,24 +3290,25 @@ export class Grapher if (!chartTypeName) return undefined if (validChartTypeSet.has(chartTypeName)) { - return chartTypeName as unknown as GrapherTabName + return chartTypeName } else if (defaultChartType) { - return defaultChartType as unknown as GrapherTabName + return defaultChartType } else if (hasMapTab) { - return GrapherTabName.WorldMap + return GRAPHER_TAB_NAMES.WorldMap } else { - return GrapherTabName.Table + return GRAPHER_TAB_NAMES.Table } } mapGrapherTabToQueryParam(tab: GrapherTabName): string { - if (tab === GrapherTabName.Table) return GrapherTabQueryParam.Table - if (tab === GrapherTabName.WorldMap) - return GrapherTabQueryParam.WorldMap + if (tab === GRAPHER_TAB_NAMES.Table) + return GRAPHER_TAB_QUERY_PARAMS.table + if (tab === GRAPHER_TAB_NAMES.WorldMap) + return GRAPHER_TAB_QUERY_PARAMS.map - if (!this.hasMultipleChartTypes) return GrapherTabQueryParam.Chart + if (!this.hasMultipleChartTypes) return GRAPHER_TAB_QUERY_PARAMS.chart - return mapChartTypeNameToQueryParam(tab as unknown as ChartTypeName) + return mapChartTypeNameToQueryParam(tab) } @computed.struct get allParams(): GrapherQueryParams { diff --git a/packages/@ourworldindata/grapher/src/core/GrapherConstants.ts b/packages/@ourworldindata/grapher/src/core/GrapherConstants.ts index 380f669649a..fd8bc6d38a5 100644 --- a/packages/@ourworldindata/grapher/src/core/GrapherConstants.ts +++ b/packages/@ourworldindata/grapher/src/core/GrapherConstants.ts @@ -1,5 +1,5 @@ +import { GRAPHER_CHART_TYPES } from "@ourworldindata/types" import { defaultGrapherConfig } from "../schema/defaultGrapherConfig.js" -import { ChartTypeName } from "@ourworldindata/types" import type { GrapherProgrammaticInterface } from "./Grapher" export const GRAPHER_EMBEDDED_FIGURE_ATTR = "data-grapher-src" @@ -113,5 +113,5 @@ export const grapherInterfaceWithHiddenTabs: GrapherProgrammaticInterface = { * This also determines the order of chart types in the UI. */ export const validChartTypeCombinations = [ - [ChartTypeName.LineChart, ChartTypeName.SlopeChart], + [GRAPHER_CHART_TYPES.LineChart, GRAPHER_CHART_TYPES.SlopeChart], ] diff --git a/packages/@ourworldindata/grapher/src/core/GrapherWithChartTypes.jsdom.test.tsx b/packages/@ourworldindata/grapher/src/core/GrapherWithChartTypes.jsdom.test.tsx index 467fa2af3c4..6a4c8bb65b1 100755 --- a/packages/@ourworldindata/grapher/src/core/GrapherWithChartTypes.jsdom.test.tsx +++ b/packages/@ourworldindata/grapher/src/core/GrapherWithChartTypes.jsdom.test.tsx @@ -8,7 +8,7 @@ import { import { Grapher, GrapherProgrammaticInterface } from "../core/Grapher" import { MapChart } from "../mapCharts/MapChart" import { legacyMapGrapher } from "../mapCharts/MapChart.sample" -import { ChartTypeName } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES } from "@ourworldindata/types" describe("grapher and map charts", () => { describe("map time tolerance plus query string works with a map chart", () => { @@ -50,7 +50,7 @@ const basicGrapherConfig: GrapherProgrammaticInterface = { describe("grapher and discrete bar charts", () => { const grapher = new Grapher({ - chartTypes: [ChartTypeName.DiscreteBar], + chartTypes: [GRAPHER_CHART_TYPES.DiscreteBar], ...basicGrapherConfig, }) expect(grapher.chartInstance.series.length).toBeGreaterThan(0) diff --git a/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.test.ts b/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.test.ts index c292f2ad16a..c7cac1c958b 100755 --- a/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.test.ts +++ b/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.test.ts @@ -1,7 +1,7 @@ #! /usr/bin/env jest import { - ChartTypeName, + GRAPHER_CHART_TYPES, OwidColumnDef, OwidTableSlugs, StandardOwidColumnDefs, @@ -466,7 +466,7 @@ describe(legacyToOwidTableAndDimensions, () => { it("joins targetTime", () => { const scatterLegacyGrapherConfig = { ...legacyGrapherConfig, - chartTypes: [ChartTypeName.ScatterPlot], + chartTypes: [GRAPHER_CHART_TYPES.ScatterPlot], } const { table } = legacyToOwidTableAndDimensions( diff --git a/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts b/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts index 99c652e5f48..56039ca16b6 100644 --- a/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts +++ b/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts @@ -1,7 +1,7 @@ // todo: Remove this file when we've migrated OWID data and OWID charts to next version import { - ChartTypeName, + GRAPHER_CHART_TYPES, ColumnTypeNames, CoreColumnDef, StandardOwidColumnDefs, @@ -200,8 +200,8 @@ export const legacyToOwidTableAndDimensions = ( const targetTime = dimension?.targetYear const chartType = grapherConfig.chartTypes?.[0] if ( - (chartType === ChartTypeName.ScatterPlot || - chartType === ChartTypeName.Marimekko) && + (chartType === GRAPHER_CHART_TYPES.ScatterPlot || + chartType === GRAPHER_CHART_TYPES.Marimekko) && isNumber(targetTime) ) { variableTable = variableTable diff --git a/packages/@ourworldindata/grapher/src/dataTable/DataTable.jsdom.test.tsx b/packages/@ourworldindata/grapher/src/dataTable/DataTable.jsdom.test.tsx index c52f0c833af..de5bcd27e37 100755 --- a/packages/@ourworldindata/grapher/src/dataTable/DataTable.jsdom.test.tsx +++ b/packages/@ourworldindata/grapher/src/dataTable/DataTable.jsdom.test.tsx @@ -3,7 +3,7 @@ import React from "react" import { DataTable } from "./DataTable" -import { ChartTypeName, GrapherTabOption } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES, GRAPHER_TAB_OPTIONS } from "@ourworldindata/types" import { childMortalityGrapher, GrapherWithIncompleteData, @@ -70,8 +70,8 @@ describe("when you select a range of years", () => { let view: ReactWrapper beforeAll(() => { const grapher = childMortalityGrapher({ - chartTypes: [ChartTypeName.LineChart], - tab: GrapherTabOption.table, + chartTypes: [GRAPHER_CHART_TYPES.LineChart], + tab: GRAPHER_TAB_OPTIONS.table, }) grapher.timelineHandleTimeBounds = [1950, 2019] diff --git a/packages/@ourworldindata/grapher/src/dataTable/DataTable.sample.ts b/packages/@ourworldindata/grapher/src/dataTable/DataTable.sample.ts index 5bf81c3a0bc..885b71afdf8 100644 --- a/packages/@ourworldindata/grapher/src/dataTable/DataTable.sample.ts +++ b/packages/@ourworldindata/grapher/src/dataTable/DataTable.sample.ts @@ -1,6 +1,6 @@ import { DimensionProperty } from "@ourworldindata/utils" import { Grapher } from "../core/Grapher" -import { GrapherTabOption, GrapherInterface } from "@ourworldindata/types" +import { GRAPHER_TAB_OPTIONS, GrapherInterface } from "@ourworldindata/types" import { TestMetadata, createOwidTestDataset, @@ -38,7 +38,7 @@ export const childMortalityGrapher = ( ] return new Grapher({ hasMapTab: true, - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, dimensions, ...props, owidDataset: createOwidTestDataset([ @@ -85,7 +85,7 @@ export const GrapherWithIncompleteData = ( }, ] return new Grapher({ - tab: GrapherTabOption.table, + tab: GRAPHER_TAB_OPTIONS.table, dimensions, ...props, owidDataset: createOwidTestDataset([{ metadata, data }]), @@ -125,7 +125,7 @@ export const GrapherWithAggregates = ( }, ] return new Grapher({ - tab: GrapherTabOption.table, + tab: GRAPHER_TAB_OPTIONS.table, dimensions, ...props, owidDataset: createOwidTestDataset([ @@ -169,7 +169,7 @@ export const GrapherWithMultipleVariablesAndMultipleYears = ( } return new Grapher({ - tab: GrapherTabOption.table, + tab: GRAPHER_TAB_OPTIONS.table, dimensions, ...props, owidDataset: createOwidTestDataset([ diff --git a/packages/@ourworldindata/grapher/src/dataTable/DataTable.stories.tsx b/packages/@ourworldindata/grapher/src/dataTable/DataTable.stories.tsx index e0279bfaf88..495e3140c58 100644 --- a/packages/@ourworldindata/grapher/src/dataTable/DataTable.stories.tsx +++ b/packages/@ourworldindata/grapher/src/dataTable/DataTable.stories.tsx @@ -1,7 +1,7 @@ import React from "react" import { DataTable, DataTableManager } from "./DataTable" import { SynthesizeGDPTable } from "@ourworldindata/core-table" -import { ChartTypeName, GrapherTabOption } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES, GRAPHER_TAB_OPTIONS } from "@ourworldindata/types" import { childMortalityGrapher, GrapherWithIncompleteData, @@ -88,8 +88,8 @@ export const FromLegacy = (): React.ReactElement => { export const FromLegacyWithTimeRange = (): React.ReactElement => { const grapher = childMortalityGrapher({ - type: ChartTypeName.LineChart, - tab: GrapherTabOption.chart, + chartTypes: [GRAPHER_CHART_TYPES.LineChart], + tab: GRAPHER_TAB_OPTIONS.chart, }) grapher.startHandleTimeBound = 1950 grapher.endHandleTimeBound = 2019 diff --git a/packages/@ourworldindata/grapher/src/facetChart/FacetChart.stories.tsx b/packages/@ourworldindata/grapher/src/facetChart/FacetChart.stories.tsx index 486b5149c2f..1bc6a3243b7 100644 --- a/packages/@ourworldindata/grapher/src/facetChart/FacetChart.stories.tsx +++ b/packages/@ourworldindata/grapher/src/facetChart/FacetChart.stories.tsx @@ -6,7 +6,7 @@ import { SynthesizeGDPTable, } from "@ourworldindata/core-table" import { Bounds } from "@ourworldindata/utils" -import { ChartTypeName, FacetStrategy } from "../core/GrapherConstants" +import { FacetStrategy, GRAPHER_CHART_TYPES } from "@ourworldindata/types" import { ChartManager } from "../chart/ChartManager" // See https://storybook.js.org/docs/react/essentials/controls for Control Types @@ -34,7 +34,7 @@ export const OneMetricOneCountryPerChart = (): React.ReactElement => { @@ -49,7 +49,7 @@ export const MultipleMetricsOneCountryPerChart = (): React.ReactElement => { { { } const chart = new FacetChart({ manager, - chartTypeName: ChartTypeName.LineChart, + chartTypeName: GRAPHER_CHART_TYPES.LineChart, }) const yAxisConfigs = chart.placedSeries.map( (series) => series.manager.yAxisConfig @@ -165,7 +165,7 @@ describe("config overrides", () => { } const chart = new FacetChart({ manager, - chartTypeName: ChartTypeName.LineChart, + chartTypeName: GRAPHER_CHART_TYPES.LineChart, }) it("preserves config passed from manager", () => { @@ -187,7 +187,7 @@ describe("config overrides", () => { } const chart = new FacetChart({ manager: newManager, - chartTypeName: ChartTypeName.LineChart, + chartTypeName: GRAPHER_CHART_TYPES.LineChart, }) expect(chart.placedSeries[0].manager.yAxisConfig?.nice).toEqual(true) }) @@ -231,7 +231,7 @@ describe("global legend", () => { } const chart = new FacetChart({ manager, - chartTypeName: ChartTypeName.LineChart, + chartTypeName: GRAPHER_CHART_TYPES.LineChart, }) const legend = chart.categoricalLegendData diff --git a/packages/@ourworldindata/grapher/src/facetChart/FacetChart.tsx b/packages/@ourworldindata/grapher/src/facetChart/FacetChart.tsx index bf54337c070..ee2870aac03 100644 --- a/packages/@ourworldindata/grapher/src/facetChart/FacetChart.tsx +++ b/packages/@ourworldindata/grapher/src/facetChart/FacetChart.tsx @@ -23,7 +23,8 @@ import { shortenForTargetWidth } from "@ourworldindata/components" import { action, computed, observable } from "mobx" import { BASE_FONT_SIZE, GRAPHER_DARK_TEXT } from "../core/GrapherConstants" import { - ChartTypeName, + GRAPHER_CHART_TYPES, + GrapherChartType, FacetAxisDomain, FacetStrategy, SeriesColorMap, @@ -137,8 +138,8 @@ export class FacetChart return this.props.manager } - @computed private get chartTypeName(): ChartTypeName { - return this.props.chartTypeName ?? ChartTypeName.LineChart + @computed private get chartTypeName(): GrapherChartType { + return this.props.chartTypeName ?? GRAPHER_CHART_TYPES.LineChart } @computed get failMessage(): string { @@ -357,9 +358,9 @@ export class FacetChart return ( this.uniformYAxis && ![ - ChartTypeName.StackedDiscreteBar, - ChartTypeName.DiscreteBar, - ].includes(this.chartTypeName) + GRAPHER_CHART_TYPES.StackedDiscreteBar, + GRAPHER_CHART_TYPES.DiscreteBar, + ].includes(this.chartTypeName as any) ) } @@ -367,7 +368,7 @@ export class FacetChart return ( this.uniformXAxis && // TODO: do this for stacked area charts and line charts as well? - this.chartTypeName === ChartTypeName.StackedBar && + this.chartTypeName === GRAPHER_CHART_TYPES.StackedBar && this.facetCount >= SHARED_X_AXIS_MIN_FACET_COUNT ) } @@ -612,7 +613,8 @@ export class FacetChart if (!hasBins) return false if (isNumericLegend) return true if ( - this.props.chartTypeName === ChartTypeName.StackedDiscreteBar && + this.props.chartTypeName === + GRAPHER_CHART_TYPES.StackedDiscreteBar && this.facetStrategy === FacetStrategy.metric ) { return false diff --git a/packages/@ourworldindata/grapher/src/facetChart/FacetChartConstants.ts b/packages/@ourworldindata/grapher/src/facetChart/FacetChartConstants.ts index 1b69756f109..61da277dca1 100644 --- a/packages/@ourworldindata/grapher/src/facetChart/FacetChartConstants.ts +++ b/packages/@ourworldindata/grapher/src/facetChart/FacetChartConstants.ts @@ -1,6 +1,6 @@ import { ChartSeries } from "../chart/ChartInterface" import { ChartManager } from "../chart/ChartManager" -import { ChartTypeName } from "@ourworldindata/types" +import { GrapherChartType } from "@ourworldindata/types" import { Bounds } from "@ourworldindata/utils" export interface FacetChartManager extends ChartManager { @@ -9,7 +9,7 @@ export interface FacetChartManager extends ChartManager { export interface FacetChartProps { bounds?: Bounds - chartTypeName?: ChartTypeName + chartTypeName?: GrapherChartType manager: FacetChartManager } diff --git a/packages/@ourworldindata/grapher/src/mapCharts/MapChart.sample.ts b/packages/@ourworldindata/grapher/src/mapCharts/MapChart.sample.ts index a118a1d6969..c656ab25c9f 100644 --- a/packages/@ourworldindata/grapher/src/mapCharts/MapChart.sample.ts +++ b/packages/@ourworldindata/grapher/src/mapCharts/MapChart.sample.ts @@ -1,10 +1,10 @@ import { DimensionProperty } from "@ourworldindata/utils" import { GrapherProgrammaticInterface } from "../core/Grapher" -import { GrapherTabOption } from "@ourworldindata/types" +import { GRAPHER_TAB_OPTIONS } from "@ourworldindata/types" export const legacyMapGrapher: GrapherProgrammaticInterface = { hasMapTab: true, - tab: GrapherTabOption.map, + tab: GRAPHER_TAB_OPTIONS.map, map: { timeTolerance: 5, }, diff --git a/packages/@ourworldindata/grapher/src/mapCharts/MapChart.tsx b/packages/@ourworldindata/grapher/src/mapCharts/MapChart.tsx index 77d944ae8d7..f641a1b939b 100644 --- a/packages/@ourworldindata/grapher/src/mapCharts/MapChart.tsx +++ b/packages/@ourworldindata/grapher/src/mapCharts/MapChart.tsx @@ -59,7 +59,7 @@ import { getCountriesByProjection } from "./WorldRegionsToProjection" import { ColorSchemeName, MapProjectionName, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, SeriesName, EntityName, } from "@ourworldindata/types" @@ -293,7 +293,7 @@ export class MapChart if (!ev.shiftKey) { this.selectionArray.setSelectedEntities([entityName]) - this.manager.tab = GrapherTabOption.chart + this.manager.tab = GRAPHER_TAB_OPTIONS.chart if ( this.manager.isLineChartThatTurnedIntoDiscreteBar && this.manager.hasTimeline diff --git a/packages/@ourworldindata/grapher/src/mapCharts/MapChartConstants.ts b/packages/@ourworldindata/grapher/src/mapCharts/MapChartConstants.ts index 3e974d98c62..c585d641d7b 100644 --- a/packages/@ourworldindata/grapher/src/mapCharts/MapChartConstants.ts +++ b/packages/@ourworldindata/grapher/src/mapCharts/MapChartConstants.ts @@ -4,7 +4,7 @@ import { MapProjectionName, Color, Time, - ChartTypeName, + GrapherChartType, GrapherTabOption, SeriesName, } from "@ourworldindata/types" @@ -57,7 +57,7 @@ export interface MapChartManager extends ChartManager { mapColumnSlug?: ColumnSlug mapIsClickable?: boolean tab?: GrapherTabOption // Used to switch to chart tab on map click - type?: ChartTypeName // Used to determine the "Click to select" text in MapTooltip + type?: GrapherChartType // Used to determine the "Click to select" text in MapTooltip isLineChartThatTurnedIntoDiscreteBar?: boolean // Used to determine whether to reset the timeline on map click hasTimeline?: boolean // Used to determine whether to reset the timeline on map click resetHandleTimeBounds?: () => void // Used to reset the timeline on map click diff --git a/packages/@ourworldindata/grapher/src/schema/migrations/migrations.ts b/packages/@ourworldindata/grapher/src/schema/migrations/migrations.ts index 2a860c0cb9a..e64a8161603 100644 --- a/packages/@ourworldindata/grapher/src/schema/migrations/migrations.ts +++ b/packages/@ourworldindata/grapher/src/schema/migrations/migrations.ts @@ -15,7 +15,7 @@ import { getSchemaVersion, isLatestVersion, } from "./helpers" -import { ChartTypeName } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES } from "@ourworldindata/types" // see https://github.com/owid/owid-grapher/commit/26f2a0d1790c71bdda7e12f284ca552945d2f6ef const migrateFrom001To002 = ( @@ -64,11 +64,11 @@ const migrateFrom004To005 = ( const migrateFrom005To006 = ( config: AnyConfigWithValidSchema ): AnyConfigWithValidSchema => { - const { type = ChartTypeName.LineChart, hasChartTab = true } = config + const { type = GRAPHER_CHART_TYPES.LineChart, hasChartTab = true } = config // add types field if (!hasChartTab) config.chartTypes = [] - else if (type !== ChartTypeName.LineChart) config.chartTypes = [type] + else if (type !== GRAPHER_CHART_TYPES.LineChart) config.chartTypes = [type] // remove deprecated fields delete config.type diff --git a/packages/@ourworldindata/grapher/src/stackedCharts/MarimekkoChart.jsdom.test.tsx b/packages/@ourworldindata/grapher/src/stackedCharts/MarimekkoChart.jsdom.test.tsx index 306f5376524..c20ed644b8f 100644 --- a/packages/@ourworldindata/grapher/src/stackedCharts/MarimekkoChart.jsdom.test.tsx +++ b/packages/@ourworldindata/grapher/src/stackedCharts/MarimekkoChart.jsdom.test.tsx @@ -4,7 +4,7 @@ import { Bounds, ColumnTypeNames } from "@ourworldindata/utils" import { OwidTable } from "@ourworldindata/core-table" import { DefaultColorScheme } from "../color/CustomSchemes" import { Grapher } from "../core/Grapher" -import { ChartTypeName } from "@ourworldindata/types" +import { GRAPHER_CHART_TYPES } from "@ourworldindata/types" import { MarimekkoChart } from "./MarimekkoChart" import { BarShape, PlacedItem } from "./MarimekkoChartConstants" it("can filter years correctly", () => { @@ -23,7 +23,7 @@ it("can filter years correctly", () => { // TODO: why is it ySlugs and xSlug here instead of yColumnSlugs and xColumnSlug? Unify when we have config migrations? const manager = { - chartTypes: [ChartTypeName.Marimekko], + chartTypes: [GRAPHER_CHART_TYPES.Marimekko], table, selection: table.availableEntityNames, ySlugs: "percentBelow2USD", @@ -133,7 +133,7 @@ it("shows no data points at the end", () => { // TODO: why is it ySlugs and xSlug here instead of yColumnSlugs and xColumnSlug? Unify when we have config migrations? const manager = { - chartTypes: [ChartTypeName.Marimekko], + chartTypes: [GRAPHER_CHART_TYPES.Marimekko], table, selection: table.availableEntityNames, ySlugs: "percentBelow2USD", @@ -233,7 +233,7 @@ test("interpolation works as expected", () => { // TODO: why is it ySlugs and xSlug here instead of yColumnSlugs and xColumnSlug? Unify when we have config migrations? const manager = { - chartTypes: [ChartTypeName.Marimekko], + chartTypes: [GRAPHER_CHART_TYPES.Marimekko], table, selection: table.availableEntityNames, ySlugs: "percentBelow2USD", @@ -344,7 +344,7 @@ it("can deal with y columns with missing values", () => { // TODO: why is it ySlugs and xSlug here instead of yColumnSlugs and xColumnSlug? Unify when we have config migrations? const manager = { - chartTypes: [ChartTypeName.Marimekko], + chartTypes: [GRAPHER_CHART_TYPES.Marimekko], table, selection: table.availableEntityNames, ySlugs: "percentBelow2USD percentBelow10USD", diff --git a/packages/@ourworldindata/types/src/dbTypes/ChartConfigs.ts b/packages/@ourworldindata/types/src/dbTypes/ChartConfigs.ts index d6ad7227811..05e9df99261 100644 --- a/packages/@ourworldindata/types/src/dbTypes/ChartConfigs.ts +++ b/packages/@ourworldindata/types/src/dbTypes/ChartConfigs.ts @@ -1,6 +1,6 @@ import { Base64String, JsonString } from "../domainTypes/Various.js" import { - ChartTypeName, + GrapherChartType, GrapherInterface, } from "../grapherTypes/GrapherTypes.js" @@ -11,7 +11,7 @@ export interface DbInsertChartConfig { full: JsonString fullMd5?: Base64String slug?: string | null - chartType?: ChartTypeName | null // TODO: exclude WorldMap + chartType?: GrapherChartType | null createdAt?: Date updatedAt?: Date | null } diff --git a/packages/@ourworldindata/types/src/grapherTypes/GrapherConstants.ts b/packages/@ourworldindata/types/src/grapherTypes/GrapherConstants.ts index 4819852969b..a00f2c40813 100644 --- a/packages/@ourworldindata/types/src/grapherTypes/GrapherConstants.ts +++ b/packages/@ourworldindata/types/src/grapherTypes/GrapherConstants.ts @@ -3,3 +3,67 @@ export const EPOCH_DATE = "2020-01-21" /** The "plot" is a chart without any header, footer or controls */ export const IDEAL_PLOT_ASPECT_RATIO = 1.8 + +export const GRAPHER_MAP_TYPE = "WorldMap" + +export const GRAPHER_CHART_TYPES = { + LineChart: "LineChart", + ScatterPlot: "ScatterPlot", + StackedArea: "StackedArea", + DiscreteBar: "DiscreteBar", + StackedDiscreteBar: "StackedDiscreteBar", + SlopeChart: "SlopeChart", + StackedBar: "StackedBar", + Marimekko: "Marimekko", +} as const + +export const ALL_GRAPHER_CHART_TYPES = Object.values(GRAPHER_CHART_TYPES) + +/** + * Grapher tab specified in the config that determines the default tab to show. + * If `chart` is selected and Grapher has more than one chart tab, then the + * first chart tab will be active. + */ +export const GRAPHER_TAB_OPTIONS = { + table: "table", + map: "map", + chart: "chart", +} as const + +/** + * Internal tab names used in Grapher. + */ +export const GRAPHER_TAB_NAMES = { + Table: "Table", + WorldMap: "WorldMap", + + // chart types + LineChart: "LineChart", + ScatterPlot: "ScatterPlot", + StackedArea: "StackedArea", + DiscreteBar: "DiscreteBar", + StackedDiscreteBar: "StackedDiscreteBar", + SlopeChart: "SlopeChart", + StackedBar: "StackedBar", + Marimekko: "Marimekko", +} as const + +/** + * Valid values for the `tab` query parameter in Grapher. + */ +export const GRAPHER_TAB_QUERY_PARAMS = { + // generic params + table: "table", + map: "map", + chart: "chart", + + // chart types + line: "line", + scatter: "scatter", + "stacked-area": "stacked-area", + "discrete-bar": "discrete-bar", + "stacked-discrete-bar": "stacked-discrete-bar", + slope: "slope", + "stacked-bar": "stacked-bar", + marimekko: "marimekko", +} as const diff --git a/packages/@ourworldindata/types/src/grapherTypes/GrapherTypes.ts b/packages/@ourworldindata/types/src/grapherTypes/GrapherTypes.ts index 3a7a1c23b43..1d73e6a6470 100644 --- a/packages/@ourworldindata/types/src/grapherTypes/GrapherTypes.ts +++ b/packages/@ourworldindata/types/src/grapherTypes/GrapherTypes.ts @@ -7,6 +7,13 @@ import { AxisAlign, Position } from "../domainTypes/Layout.js" import { Integer, QueryParams } from "../domainTypes/Various.js" import { DetailDictionary } from "../gdocTypes/Gdoc.js" import { observable } from "mobx" +import { + GRAPHER_CHART_TYPES, + GRAPHER_MAP_TYPE, + GRAPHER_TAB_NAMES, + GRAPHER_TAB_OPTIONS, + GRAPHER_TAB_QUERY_PARAMS, +} from "./GrapherConstants.js" export interface Box { x: number @@ -119,18 +126,6 @@ export enum ToleranceStrategy { backwards = "backwards", forwards = "forwards", } -export enum ChartTypeName { - LineChart = "LineChart", - ScatterPlot = "ScatterPlot", - StackedArea = "StackedArea", - DiscreteBar = "DiscreteBar", - StackedDiscreteBar = "StackedDiscreteBar", - SlopeChart = "SlopeChart", - StackedBar = "StackedBar", - Marimekko = "Marimekko", - // special map type that can't be selected by authors - WorldMap = "WorldMap", -} export enum AxisMinMaxValueStr { auto = "auto", @@ -172,53 +167,13 @@ export type SeriesName = string export type SeriesColorMap = Map -/** - * Grapher tab specified in the config that determines the default tab to show. - * If `chart` is selected and Grapher has more than one chart tab, then the - * first chart tab will be active. - */ -export enum GrapherTabOption { - chart = "chart", - map = "map", - table = "table", -} - -/** - * Internal tab names used in Grapher. - */ -export enum GrapherTabName { - Table = "Table", - WorldMap = "WorldMap", - - // chart types - LineChart = "LineChart", - ScatterPlot = "ScatterPlot", - StackedArea = "StackedArea", - DiscreteBar = "DiscreteBar", - StackedDiscreteBar = "StackedDiscreteBar", - SlopeChart = "SlopeChart", - StackedBar = "StackedBar", - Marimekko = "Marimekko", -} +export type GrapherMapType = typeof GRAPHER_MAP_TYPE +export type GrapherChartType = keyof typeof GRAPHER_CHART_TYPES +export type GrapherChartOrMapType = GrapherChartType | GrapherMapType -/** - * Valid values for the `tab` query parameter in Grapher. - */ -export enum GrapherTabQueryParam { - Chart = "chart", - Table = "table", - WorldMap = "map", - - // chart types - LineChart = "line", - ScatterPlot = "scatter", - StackedArea = "stacked-area", - DiscreteBar = "discrete-bar", - StackedDiscreteBar = "stacked-discrete-bar", - SlopeChart = "slope", - StackedBar = "stacked-bar", - Marimekko = "marimekko", -} +export type GrapherTabOption = keyof typeof GRAPHER_TAB_OPTIONS +export type GrapherTabQueryParam = keyof typeof GRAPHER_TAB_QUERY_PARAMS +export type GrapherTabName = keyof typeof GRAPHER_TAB_NAMES export interface RelatedQuestionsConfig { text: string @@ -577,7 +532,7 @@ export interface MapConfigInterface { // under the same rendering conditions it ought to remain visually identical export interface GrapherInterface extends SortConfig { $schema?: string - chartTypes?: ChartTypeName[] + chartTypes?: GrapherChartType[] id?: number version?: number slug?: string diff --git a/packages/@ourworldindata/types/src/index.ts b/packages/@ourworldindata/types/src/index.ts index 9a69ff37537..562dd93191d 100644 --- a/packages/@ourworldindata/types/src/index.ts +++ b/packages/@ourworldindata/types/src/index.ts @@ -44,6 +44,12 @@ export { export { IDEAL_PLOT_ASPECT_RATIO, EPOCH_DATE, + GRAPHER_MAP_TYPE, + GRAPHER_CHART_TYPES, + GRAPHER_TAB_NAMES, + GRAPHER_TAB_OPTIONS, + GRAPHER_TAB_QUERY_PARAMS, + ALL_GRAPHER_CHART_TYPES, } from "./grapherTypes/GrapherConstants.js" export { @@ -73,10 +79,11 @@ export { BinningStrategy, type ColorScaleConfigInterface, ColorSchemeName, - ChartTypeName, - GrapherTabOption, - GrapherTabName, - GrapherTabQueryParam, + type GrapherChartOrMapType, + type GrapherTabOption, + type GrapherTabName, + type GrapherTabQueryParam, + type GrapherChartType, StackMode, EntitySelectionMode, ScatterPointLabelStrategy, diff --git a/packages/@ourworldindata/utils/src/Util.ts b/packages/@ourworldindata/utils/src/Util.ts index ccdd684a6f8..5dc5d615f86 100644 --- a/packages/@ourworldindata/utils/src/Util.ts +++ b/packages/@ourworldindata/utils/src/Util.ts @@ -175,8 +175,8 @@ import { TagGraphRootName, TagGraphNode, GrapherInterface, - ChartTypeName, DimensionProperty, + GRAPHER_CHART_TYPES, } from "@ourworldindata/types" import { PointVector } from "./PointVector.js" import React from "react" @@ -1971,8 +1971,8 @@ export function getParentVariableIdFromChartConfig( ): number | undefined { const { chartTypes, dimensions } = config - const chartType = chartTypes?.[0] ?? ChartTypeName.LineChart - if (chartType === ChartTypeName.ScatterPlot) return undefined + const chartType = chartTypes?.[0] ?? GRAPHER_CHART_TYPES.LineChart + if (chartType === GRAPHER_CHART_TYPES.ScatterPlot) return undefined if (!dimensions) return undefined const yVariableIds = dimensions diff --git a/packages/@ourworldindata/utils/src/grapherConfigUtils.test.ts b/packages/@ourworldindata/utils/src/grapherConfigUtils.test.ts index 882b0d74326..0b879541c0d 100644 --- a/packages/@ourworldindata/utils/src/grapherConfigUtils.test.ts +++ b/packages/@ourworldindata/utils/src/grapherConfigUtils.test.ts @@ -3,8 +3,8 @@ import { DimensionProperty, GrapherInterface, - GrapherTabOption, MapProjectionName, + GRAPHER_TAB_OPTIONS, } from "@ourworldindata/types" import { mergeGrapherConfigs, @@ -243,14 +243,14 @@ describe(diffGrapherConfigs, () => { it("drops redundant entries", () => { expect( diffGrapherConfigs( - { tab: GrapherTabOption.map }, - { tab: GrapherTabOption.map } + { tab: GRAPHER_TAB_OPTIONS.map }, + { tab: GRAPHER_TAB_OPTIONS.map } ) ).toEqual({}) expect( diffGrapherConfigs( - { tab: GrapherTabOption.chart, title: "Chart" }, - { tab: GrapherTabOption.chart, title: "Reference chart" } + { tab: GRAPHER_TAB_OPTIONS.chart, title: "Chart" }, + { tab: GRAPHER_TAB_OPTIONS.chart, title: "Reference chart" } ) ).toEqual({ title: "Chart" }) }) @@ -260,7 +260,7 @@ describe(diffGrapherConfigs, () => { diffGrapherConfigs( { title: "Chart", - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, map: { projection: MapProjectionName.World, hideTimeline: true, @@ -268,7 +268,7 @@ describe(diffGrapherConfigs, () => { }, { title: "Reference chart", - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, map: { projection: MapProjectionName.World, hideTimeline: false, @@ -279,14 +279,14 @@ describe(diffGrapherConfigs, () => { expect( diffGrapherConfigs( { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, map: { projection: MapProjectionName.World, hideTimeline: true, }, }, { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, map: { projection: MapProjectionName.World, hideTimeline: true, @@ -300,11 +300,11 @@ describe(diffGrapherConfigs, () => { expect( diffGrapherConfigs( { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, title: "Chart", subtitle: undefined, }, - { tab: GrapherTabOption.chart, title: "Reference chart" } + { tab: GRAPHER_TAB_OPTIONS.chart, title: "Reference chart" } ) ).toEqual({ title: "Chart" }) }) @@ -361,12 +361,12 @@ describe(diffGrapherConfigs, () => { it("is idempotent", () => { const config: GrapherInterface = { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, title: "Chart", subtitle: undefined, } const reference: GrapherInterface = { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, title: "Reference chart", } const diffedOnce = diffGrapherConfigs(config, reference) @@ -378,12 +378,12 @@ describe(diffGrapherConfigs, () => { describe("diff+merge", () => { it("are consistent", () => { const config: GrapherInterface = { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, title: "Chart", subtitle: "Chart subtitle", } const reference: GrapherInterface = { - tab: GrapherTabOption.chart, + tab: GRAPHER_TAB_OPTIONS.chart, title: "Reference chart", } const diffedAndMerged = mergeGrapherConfigs( diff --git a/site/gdocs/components/KeyIndicatorCollection.tsx b/site/gdocs/components/KeyIndicatorCollection.tsx index 8539a5a70b3..e2347ac622b 100644 --- a/site/gdocs/components/KeyIndicatorCollection.tsx +++ b/site/gdocs/components/KeyIndicatorCollection.tsx @@ -13,6 +13,7 @@ import { import { EnrichedBlockKeyIndicatorCollection, EnrichedBlockKeyIndicator, + GRAPHER_TAB_OPTIONS, GrapherTabOption, } from "@ourworldindata/types" import { Url, urlToSlug, commafyNumber } from "@ourworldindata/utils" @@ -26,9 +27,9 @@ import { Button } from "@ourworldindata/components" const HEIGHT_ANIMATION_DURATION_IN_SECONDS = 0.4 const tabIconMap: Record = { - [GrapherTabOption.chart]: faChartLine, - [GrapherTabOption.map]: faEarthAmericas, - [GrapherTabOption.table]: faTable, + [GRAPHER_TAB_OPTIONS.chart]: faChartLine, + [GRAPHER_TAB_OPTIONS.map]: faEarthAmericas, + [GRAPHER_TAB_OPTIONS.table]: faTable, } export default function KeyIndicatorCollection({ @@ -247,7 +248,7 @@ function KeyIndicatorHeader({ ? queryParams.tab : undefined const activeTab = - tabFromQueryParams || linkedChart.tab || GrapherTabOption.chart + tabFromQueryParams || linkedChart.tab || GRAPHER_TAB_OPTIONS.chart const source = block.source || linkedIndicator.attributionShort @@ -357,5 +358,5 @@ function isElementAtTopOfViewport(element: HTMLElement): boolean { } function isValidGrapherTab(tab: string): tab is GrapherTabOption { - return Object.values(GrapherTabOption).includes(tab as GrapherTabOption) + return Object.values(GRAPHER_TAB_OPTIONS).includes(tab as GrapherTabOption) } diff --git a/site/multiembedder/MultiEmbedder.tsx b/site/multiembedder/MultiEmbedder.tsx index d2ae1a1ba39..b7b84b59516 100644 --- a/site/multiembedder/MultiEmbedder.tsx +++ b/site/multiembedder/MultiEmbedder.tsx @@ -15,7 +15,7 @@ import { getWindowUrl, isPresent, Url, - GrapherTabOption, + GRAPHER_TAB_OPTIONS, merge, MultiDimDataPageConfig, extractMultiDimChoicesFromQueryStr, @@ -213,11 +213,11 @@ class MultiEmbedder { // make sure the tab of the active pane is visible if (figureConfigAttr && !isEmpty(localConfig)) { const activeTab = queryParams.tab || grapherPageConfig.tab - if (activeTab === GrapherTabOption.chart) + if (activeTab === GRAPHER_TAB_OPTIONS.chart) localConfig.hideChartTabs = false - if (activeTab === GrapherTabOption.map) + if (activeTab === GRAPHER_TAB_OPTIONS.map) localConfig.hasMapTab = true - if (activeTab === GrapherTabOption.table) + if (activeTab === GRAPHER_TAB_OPTIONS.table) localConfig.hasTableTab = true }