From f299ac2250941db46b6de6da1534a25467848d7e Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Fri, 29 Sep 2023 13:21:56 +0200 Subject: [PATCH] feat: Set up ComboLineDual chart --- app/charts/combo/chart-combo.tsx | 15 ++- .../combo/combo-line-dual-state-props.ts | 97 ++++++++++++++ ...ne-state.tsx => combo-line-dual-state.tsx} | 32 ++--- app/charts/combo/combo-line-dual.tsx | 9 ++ .../combo/combo-line-single-state-props.ts | 87 +++++++++++++ app/charts/combo/combo-line-single-state.tsx | 69 ++++++++++ app/charts/combo/combo-line-single.tsx | 9 ++ app/charts/combo/combo-line-state-props.ts | 123 ------------------ app/charts/combo/combo-line.tsx | 9 -- app/charts/shared/chart-state.ts | 8 +- 10 files changed, 304 insertions(+), 154 deletions(-) create mode 100644 app/charts/combo/combo-line-dual-state-props.ts rename app/charts/combo/{combo-line-state.tsx => combo-line-dual-state.tsx} (66%) create mode 100644 app/charts/combo/combo-line-dual.tsx create mode 100644 app/charts/combo/combo-line-single-state-props.ts create mode 100644 app/charts/combo/combo-line-single-state.tsx create mode 100644 app/charts/combo/combo-line-single.tsx delete mode 100644 app/charts/combo/combo-line-state-props.ts delete mode 100644 app/charts/combo/combo-line.tsx diff --git a/app/charts/combo/chart-combo.tsx b/app/charts/combo/chart-combo.tsx index 422095cc4..d787ebdfa 100644 --- a/app/charts/combo/chart-combo.tsx +++ b/app/charts/combo/chart-combo.tsx @@ -3,7 +3,8 @@ import { memo } from "react"; import { ChartLoadingWrapper } from "@/charts/chart-loading-wrapper"; import { ComboLineColumnChart } from "@/charts/combo/combo-line-column-state"; -import { ComboLineChart } from "@/charts/combo/combo-line-state"; +import { ComboLineDualChart } from "@/charts/combo/combo-line-dual-state"; +import { ComboLineSingleChart } from "@/charts/combo/combo-line-single-state"; import { extractComponentIris } from "@/charts/shared/chart-helpers"; import { ComboConfig, DataSource, QueryFilters } from "@/config-types"; import { @@ -70,9 +71,15 @@ export const ChartCombo = memo((props: ChartProps) => { const { chartConfig } = props; return chartConfig.chartSubtype === "line" ? ( - - ComboLineChart - + chartConfig.fields.y.axisMode === "single" ? ( + + ComboLineSingleChart + + ) : ( + + ComboLineDualChart + + ) ) : ( ComboLineColumnChart diff --git a/app/charts/combo/combo-line-dual-state-props.ts b/app/charts/combo/combo-line-dual-state-props.ts new file mode 100644 index 000000000..36841cbe2 --- /dev/null +++ b/app/charts/combo/combo-line-dual-state-props.ts @@ -0,0 +1,97 @@ +import React from "react"; + +import { BaseYGetter, sortData } from "@/charts/combo/combo-state-props"; +import { getLabelWithUnit } from "@/charts/shared/chart-helpers"; +import { + BaseVariables, + ChartStateData, + TemporalXVariables, + useBaseVariables, + useChartData, + useTemporalXVariables, +} from "@/charts/shared/chart-state"; +import { ComboConfig } from "@/configurator"; + +import { ChartProps } from "../shared/ChartProps"; + +type NumericalYComboLineDualVariables = { + y: { + lineLeft: BaseYGetter; + lineRight: BaseYGetter; + }; +}; + +export type ComboLineDualStateVariables = BaseVariables & + TemporalXVariables & + NumericalYComboLineDualVariables; + +export const useComboLineDualStateVariables = ( + props: ChartProps & { aspectRatio: number } +): ComboLineDualStateVariables => { + const { chartConfig, dimensionsByIri, measuresByIri } = props; + const { fields } = chartConfig; + const { x } = fields; + + const baseVariables = useBaseVariables(chartConfig); + const temporalXVariables = useTemporalXVariables(x, { + dimensionsByIri, + }); + + if (chartConfig.chartSubtype !== "line") { + throw new Error("This hook is only for line charts!"); + } + + if (chartConfig.fields.y.axisMode !== "dual") { + throw new Error("This hook is only for dual axis line charts!"); + } + + const leftIri = chartConfig.fields.y.leftAxisComponentIri; + const rightIri = chartConfig.fields.y.rightAxisComponentIri; + const numericalYVariables: NumericalYComboLineDualVariables = { + y: { + lineLeft: { + iri: leftIri, + label: getLabelWithUnit(measuresByIri[leftIri]), + getY: (d) => { + return d[leftIri] !== null ? Number(d[leftIri]) : null; + }, + }, + lineRight: { + iri: rightIri, + label: getLabelWithUnit(measuresByIri[rightIri]), + getY: (d) => { + return d[rightIri] !== null ? Number(d[rightIri]) : null; + }, + }, + }, + }; + + return { + ...baseVariables, + ...temporalXVariables, + ...numericalYVariables, + }; +}; + +export const useComboLineDualStateData = ( + chartProps: ChartProps & { aspectRatio: number }, + variables: ComboLineDualStateVariables +): ChartStateData => { + const { chartConfig, observations } = chartProps; + // FIXME: handle properly. + const plottableData = observations; + const sortedPlottableData = React.useMemo(() => { + return sortData(plottableData, { + getX: variables.getX, + }); + }, [plottableData, variables.getX]); + const data = useChartData(sortedPlottableData, { + chartConfig, + getXAsDate: variables.getX, + }); + + return { + ...data, + allData: sortedPlottableData, + }; +}; diff --git a/app/charts/combo/combo-line-state.tsx b/app/charts/combo/combo-line-dual-state.tsx similarity index 66% rename from app/charts/combo/combo-line-state.tsx rename to app/charts/combo/combo-line-dual-state.tsx index 479e8e564..35487414a 100644 --- a/app/charts/combo/combo-line-state.tsx +++ b/app/charts/combo/combo-line-dual-state.tsx @@ -1,10 +1,10 @@ import { ScaleLinear, ScaleOrdinal, ScaleTime } from "d3"; import { - ComboLineStateVariables, - useComboLineStateData, - useComboLineStateVariables, -} from "@/charts/combo/combo-line-state-props"; + ComboLineDualStateVariables, + useComboLineDualStateData, + useComboLineDualStateVariables, +} from "@/charts/combo/combo-line-dual-state-props"; import { ChartContext, ChartStateData, @@ -19,8 +19,8 @@ import { Observation } from "@/domain/data"; import { ChartProps } from "../shared/ChartProps"; -export type ComboLineState = CommonChartState & - ComboLineStateVariables & +export type ComboLineDualState = CommonChartState & + ComboLineDualStateVariables & InteractiveXTimeRangeState & { chartType: "combo"; xKey: string; @@ -31,30 +31,30 @@ export type ComboLineState = CommonChartState & getAnnotationInfo: (d: Observation) => TooltipInfo; }; -const useComboLineState = ( +const useComboLineDualState = ( chartProps: ChartProps & { aspectRatio: number }, - variables: ComboLineStateVariables, + variables: ComboLineDualStateVariables, data: ChartStateData -): ComboLineState => { - return {} as unknown as ComboLineState; +): ComboLineDualState => { + return {} as unknown as ComboLineDualState; }; -const ComboLineChartProvider = ( +const ComboLineDualChartProvider = ( props: React.PropsWithChildren< ChartProps & { aspectRatio: number } > ) => { const { children, ...chartProps } = props; - const variables = useComboLineStateVariables(chartProps); - const data = useComboLineStateData(chartProps, variables); - const state = useComboLineState(chartProps, variables, data); + const variables = useComboLineDualStateVariables(chartProps); + const data = useComboLineDualStateData(chartProps, variables); + const state = useComboLineDualState(chartProps, variables, data); return ( {children} ); }; -export const ComboLineChart = ( +export const ComboLineDualChart = ( props: React.PropsWithChildren< ChartProps & { aspectRatio: number } > @@ -62,7 +62,7 @@ export const ComboLineChart = ( return ( - + ); diff --git a/app/charts/combo/combo-line-dual.tsx b/app/charts/combo/combo-line-dual.tsx new file mode 100644 index 000000000..28fa0607b --- /dev/null +++ b/app/charts/combo/combo-line-dual.tsx @@ -0,0 +1,9 @@ +import { ComboLineDualState } from "@/charts/combo/combo-line-dual-state"; +import { useChartState } from "@/charts/shared/chart-state"; + +export const ComboLineDual = () => { + const state = useChartState() as ComboLineDualState; + console.log(state); + + return null; +}; diff --git a/app/charts/combo/combo-line-single-state-props.ts b/app/charts/combo/combo-line-single-state-props.ts new file mode 100644 index 000000000..a7cef055e --- /dev/null +++ b/app/charts/combo/combo-line-single-state-props.ts @@ -0,0 +1,87 @@ +import React from "react"; + +import { BaseYGetter, sortData } from "@/charts/combo/combo-state-props"; +import { getLabelWithUnit } from "@/charts/shared/chart-helpers"; +import { + BaseVariables, + ChartStateData, + TemporalXVariables, + useBaseVariables, + useChartData, + useTemporalXVariables, +} from "@/charts/shared/chart-state"; +import { ComboConfig } from "@/configurator"; + +import { ChartProps } from "../shared/ChartProps"; + +type NumericalYComboLineSingleVariables = { + y: { + lines: BaseYGetter[]; + }; +}; + +export type ComboLineSingleStateVariables = BaseVariables & + TemporalXVariables & + NumericalYComboLineSingleVariables; + +export const useComboLineSingleStateVariables = ( + props: ChartProps & { aspectRatio: number } +): ComboLineSingleStateVariables => { + const { chartConfig, dimensionsByIri, measuresByIri } = props; + const { fields } = chartConfig; + const { x } = fields; + + const baseVariables = useBaseVariables(chartConfig); + const temporalXVariables = useTemporalXVariables(x, { + dimensionsByIri, + }); + + if (chartConfig.chartSubtype !== "line") { + throw new Error("This hook is only for line charts!"); + } + + if (chartConfig.fields.y.axisMode !== "single") { + throw new Error("This hook is only for single axis line charts!"); + } + + const numericalYVariables: NumericalYComboLineSingleVariables = { + y: { + lines: chartConfig.fields.y.componentIris.map((iri) => ({ + iri, + label: getLabelWithUnit(measuresByIri[iri]), + getY: (d) => { + return d[iri] !== null ? Number(d[iri]) : null; + }, + })), + }, + }; + + return { + ...baseVariables, + ...temporalXVariables, + ...numericalYVariables, + }; +}; + +export const useComboLineSingleStateData = ( + chartProps: ChartProps & { aspectRatio: number }, + variables: ComboLineSingleStateVariables +): ChartStateData => { + const { chartConfig, observations } = chartProps; + // FIXME: handle properly. + const plottableData = observations; + const sortedPlottableData = React.useMemo(() => { + return sortData(plottableData, { + getX: variables.getX, + }); + }, [plottableData, variables.getX]); + const data = useChartData(sortedPlottableData, { + chartConfig, + getXAsDate: variables.getX, + }); + + return { + ...data, + allData: sortedPlottableData, + }; +}; diff --git a/app/charts/combo/combo-line-single-state.tsx b/app/charts/combo/combo-line-single-state.tsx new file mode 100644 index 000000000..84e90a7ed --- /dev/null +++ b/app/charts/combo/combo-line-single-state.tsx @@ -0,0 +1,69 @@ +import { ScaleLinear, ScaleOrdinal, ScaleTime } from "d3"; + +import { + ComboLineSingleStateVariables, + useComboLineSingleStateData, + useComboLineSingleStateVariables, +} from "@/charts/combo/combo-line-single-state-props"; +import { + ChartContext, + ChartStateData, + CommonChartState, + InteractiveXTimeRangeState, +} from "@/charts/shared/chart-state"; +import { TooltipInfo } from "@/charts/shared/interaction/tooltip"; +import { InteractionProvider } from "@/charts/shared/use-interaction"; +import { Observer } from "@/charts/shared/use-width"; +import { ComboConfig } from "@/configurator"; +import { Observation } from "@/domain/data"; + +import { ChartProps } from "../shared/ChartProps"; + +export type ComboLineSingleState = CommonChartState & + ComboLineSingleStateVariables & + InteractiveXTimeRangeState & { + chartType: "combo"; + xKey: string; + xScale: ScaleTime; + yScale: ScaleLinear; + colors: ScaleOrdinal; + chartWideData: ArrayLike; + getAnnotationInfo: (d: Observation) => TooltipInfo; + }; + +const useComboLineSingleState = ( + chartProps: ChartProps & { aspectRatio: number }, + variables: ComboLineSingleStateVariables, + data: ChartStateData +): ComboLineSingleState => { + return {} as unknown as ComboLineSingleState; +}; + +const ComboLineSingleChartProvider = ( + props: React.PropsWithChildren< + ChartProps & { aspectRatio: number } + > +) => { + const { children, ...chartProps } = props; + const variables = useComboLineSingleStateVariables(chartProps); + const data = useComboLineSingleStateData(chartProps, variables); + const state = useComboLineSingleState(chartProps, variables, data); + + return ( + {children} + ); +}; + +export const ComboLineSingleChart = ( + props: React.PropsWithChildren< + ChartProps & { aspectRatio: number } + > +) => { + return ( + + + + + + ); +}; diff --git a/app/charts/combo/combo-line-single.tsx b/app/charts/combo/combo-line-single.tsx new file mode 100644 index 000000000..977f40b71 --- /dev/null +++ b/app/charts/combo/combo-line-single.tsx @@ -0,0 +1,9 @@ +import { ComboLineSingleState } from "@/charts/combo/combo-line-single-state"; +import { useChartState } from "@/charts/shared/chart-state"; + +export const ComboLineSingle = () => { + const state = useChartState() as ComboLineSingleState; + console.log(state); + + return null; +}; diff --git a/app/charts/combo/combo-line-state-props.ts b/app/charts/combo/combo-line-state-props.ts deleted file mode 100644 index e808590ee..000000000 --- a/app/charts/combo/combo-line-state-props.ts +++ /dev/null @@ -1,123 +0,0 @@ -import React from "react"; - -import { BaseYGetter, sortData } from "@/charts/combo/combo-state-props"; -import { getLabelWithUnit } from "@/charts/shared/chart-helpers"; -import { - BaseVariables, - ChartStateData, - TemporalXVariables, - useBaseVariables, - useChartData, - useTemporalXVariables, -} from "@/charts/shared/chart-state"; -import { ComboConfig } from "@/configurator"; - -import { ChartProps } from "../shared/ChartProps"; - -type NumericalYComboLineVariables = { - y: - | { - axisMode: "single"; - lines: BaseYGetter[]; - } - | { - axisMode: "dual"; - lineLeft: BaseYGetter; - lineRight: BaseYGetter; - }; -}; - -export type ComboLineStateVariables = BaseVariables & - TemporalXVariables & - NumericalYComboLineVariables; - -export const useComboLineStateVariables = ( - props: ChartProps & { aspectRatio: number } -): ComboLineStateVariables => { - const { chartConfig, dimensionsByIri, measuresByIri } = props; - const { fields } = chartConfig; - const { x } = fields; - - const baseVariables = useBaseVariables(chartConfig); - const temporalXVariables = useTemporalXVariables(x, { - dimensionsByIri, - }); - - if (chartConfig.chartSubtype !== "line") { - throw new Error("This hook is only for line charts!"); - } - - let numericalYVariables: NumericalYComboLineVariables; - switch (chartConfig.fields.y.axisMode) { - case "single": { - numericalYVariables = { - y: { - axisMode: "single", - lines: chartConfig.fields.y.componentIris.map((iri) => ({ - iri, - label: getLabelWithUnit(measuresByIri[iri]), - getY: (d) => { - return d[iri] !== null ? Number(d[iri]) : null; - }, - })), - }, - }; - break; - } - case "dual": - const leftIri = chartConfig.fields.y.leftAxisComponentIri; - const rightIri = chartConfig.fields.y.rightAxisComponentIri; - numericalYVariables = { - y: { - axisMode: "dual", - lineLeft: { - iri: leftIri, - label: getLabelWithUnit(measuresByIri[leftIri]), - getY: (d) => { - return d[leftIri] !== null ? Number(d[leftIri]) : null; - }, - }, - lineRight: { - iri: rightIri, - label: getLabelWithUnit(measuresByIri[rightIri]), - getY: (d) => { - return d[rightIri] !== null ? Number(d[rightIri]) : null; - }, - }, - }, - }; - break; - default: - const _exhaustiveCheck: never = chartConfig.fields.y; - return _exhaustiveCheck; - } - - return { - ...baseVariables, - ...temporalXVariables, - ...numericalYVariables, - }; -}; - -export const useComboLineStateData = ( - chartProps: ChartProps & { aspectRatio: number }, - variables: ComboLineStateVariables -): ChartStateData => { - const { chartConfig, observations } = chartProps; - // FIXME: handle properly. - const plottableData = observations; - const sortedPlottableData = React.useMemo(() => { - return sortData(plottableData, { - getX: variables.getX, - }); - }, [plottableData, variables.getX]); - const data = useChartData(sortedPlottableData, { - chartConfig, - getXAsDate: variables.getX, - }); - - return { - ...data, - allData: sortedPlottableData, - }; -}; diff --git a/app/charts/combo/combo-line.tsx b/app/charts/combo/combo-line.tsx deleted file mode 100644 index 1a2cfa468..000000000 --- a/app/charts/combo/combo-line.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { ComboLineState } from "@/charts/combo/combo-line-state"; -import { useChartState } from "@/charts/shared/chart-state"; - -export const ComboLine = () => { - const state = useChartState() as ComboLineState; - console.log(state); - - return null; -}; diff --git a/app/charts/shared/chart-state.ts b/app/charts/shared/chart-state.ts index ecddad454..c9272de0c 100644 --- a/app/charts/shared/chart-state.ts +++ b/app/charts/shared/chart-state.ts @@ -7,7 +7,9 @@ import { AreasState } from "@/charts/area/areas-state"; import { GroupedColumnsState } from "@/charts/column/columns-grouped-state"; import { StackedColumnsState } from "@/charts/column/columns-stacked-state"; import { ColumnsState } from "@/charts/column/columns-state"; -import { ComboState } from "@/charts/combo/combo-line-state"; +import { ComboLineColumnState } from "@/charts/combo/combo-line-column-state"; +import { ComboLineDualState } from "@/charts/combo/combo-line-dual-state"; +import { ComboLineSingleState } from "@/charts/combo/combo-line-single-state"; import { LinesState } from "@/charts/line/lines-state"; import { MapState } from "@/charts/map/map-state"; import { PieState } from "@/charts/pie/pie-state"; @@ -58,7 +60,9 @@ export type ChartState = | ColumnsState | StackedColumnsState | GroupedColumnsState - | ComboState + | ComboLineSingleState + | ComboLineColumnState + | ComboLineDualState | LinesState | MapState | PieState