Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/f 183 categorical chart minor improvements #155

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
40 changes: 20 additions & 20 deletions src/app/elements/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { useState } from 'react';
import AccordionContainer from '@/components/Accordions/AccordionContainer';
import { CustomButton } from '@/components/Buttons/CustomButton';
import { CategoricalChart } from '@/components/Charts/CategoricalChart';
import { LineChart } from '@/components/Charts/LineChart';
import { ContinuousChart } from '@/components/Charts/ContinuousChart';
import MapSkeleton from '@/components/Map/MapSkeleton';
import SearchBar from '@/components/Search/SearchBar';
import { CategoricalChartData } from '@/domain/entities/charts/CategoricalChartData.ts';
import { LineChartData } from '@/domain/entities/charts/LineChartData.ts';
import { LineChartDataType } from '@/domain/enums/LineChartDataType.ts';
import { ContinuousChartData } from '@/domain/entities/charts/ContinuousChartData.ts';
import { ContinuousChartDataType } from '@/domain/enums/ContinuousChartDataType.ts';
import AccordionsOperations from '@/operations/accordions/AccordionOperations';

import { ReactComponent as FoodSvg } from '../../../public/Images/FoodConsumption.svg';
Expand All @@ -21,8 +21,8 @@ import { ReactComponent as FoodSvg } from '../../../public/Images/FoodConsumptio
*/
export default async function Elements() {
const [searchTerm, setSearchTerm] = useState('');
const simpleAndSmallLineChartData: LineChartData = {
type: LineChartDataType.LINE_CHART_DATA,
const simpleAndSmallContinuousChartData: ContinuousChartData = {
type: ContinuousChartDataType.LINE_CHART_DATA,
xAxisType: 'linear',
lines: [
{
Expand All @@ -37,8 +37,8 @@ export default async function Elements() {
],
};

const maxedOutLineChartData: LineChartData = {
type: LineChartDataType.LINE_CHART_DATA,
const maxedOutContinuousChartData: ContinuousChartData = {
type: ContinuousChartDataType.LINE_CHART_DATA,
xAxisType: 'linear',
yAxisLabel: 'yield',
lines: [
Expand Down Expand Up @@ -97,8 +97,8 @@ export default async function Elements() {
],
};

const predictionDummyChartData: LineChartData = {
type: LineChartDataType.LINE_CHART_DATA,
const predictionDummyChartData: ContinuousChartData = {
type: ContinuousChartDataType.LINE_CHART_DATA,
xAxisType: 'linear',
yAxisLabel: 'Mill',
predictionVerticalLineX: 3,
Expand Down Expand Up @@ -129,7 +129,7 @@ export default async function Elements() {
],
};

const categoricalDummyChartData1: CategoricalChartData = {
const categoricalDummyChartData: CategoricalChartData = {
yAxisLabel: 'Mill',
categories: [
{
Expand All @@ -143,8 +143,8 @@ export default async function Elements() {
],
};

const emptyDummyChartData: LineChartData = {
type: LineChartDataType.LINE_CHART_DATA,
const emptyDummyChartData: ContinuousChartData = {
type: ContinuousChartDataType.LINE_CHART_DATA,
xAxisType: 'linear',
yAxisLabel: 'Mill',
predictionVerticalLineX: 3,
Expand Down Expand Up @@ -174,8 +174,8 @@ export default async function Elements() {
<AccordionContainer items={AccordionsOperations.getAccordionData()} />
<div className="w-full h-fit flex flex-row flex-wrap gap-10 justify-around px-8 pt-40 pb-16 border-b border-gray-800">
<div className="w-250px h-fit">
<LineChart
data={simpleAndSmallLineChartData}
<ContinuousChart
data={simpleAndSmallContinuousChartData}
small
disableDownload
disableBarChartSwitch
Expand All @@ -184,20 +184,20 @@ export default async function Elements() {
/>
</div>
<div className="w-400px h-fit">
<LineChart
title="Maxed Out Line Chart"
<ContinuousChart
title="Maxed Out Continuous Chart"
description="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor onsetetur sadipscing elitr."
data={maxedOutLineChartData}
data={maxedOutContinuousChartData}
/>
</div>
<div className="w-400px h-fit">
<LineChart title="" data={predictionDummyChartData} />
<ContinuousChart title="" data={predictionDummyChartData} />
</div>
<div className="w-400px h-fit">
<CategoricalChart title="" data={categoricalDummyChartData1} />
<CategoricalChart title="" data={categoricalDummyChartData} />
</div>
<div className="w-400px h-fit">
<LineChart title="Forecast XYZ" data={emptyDummyChartData} />
<ContinuousChart title="Forecast XYZ" data={emptyDummyChartData} />
</div>
</div>
<MapSkeleton />
Expand Down
29 changes: 15 additions & 14 deletions src/components/Charts/CategoricalChart.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use client';

import Highcharts from 'highcharts';
import { useTheme } from 'next-themes';
import { useEffect, useState } from 'react';
import { useState } from 'react';

import { ChartContainer } from '@/components/Charts/helpers/ChartContainer';
import { ChartType } from '@/domain/enums/ChartType.ts';
Expand All @@ -11,7 +10,7 @@ import CategoricalChartOperations from '@/operations/charts/CategoricalChartOper

/**
* The `CategoricalChart` component is a box that primarily renders a title, description text, and a bar chart.
* It should be used to plot categorical data. For continues data please use the `LineChart` component.
* It should be used to plot categorical data. For continues data please use the `ContinuousChart` component.
* This component has a width of 100%, so it adjusts to the width of its parent element in which it is used.
* The height of the entire box depends on the provided text, while the chart itself has a fixed height.
* It also provides the option to open the chart in a full-screen modal, where one can download the data as well.
Expand All @@ -22,6 +21,8 @@ import CategoricalChartOperations from '@/operations/charts/CategoricalChartOper
* @param small when selected, all components in the line chart box become slightly smaller (optional)
* @param noPadding when selected, the main box has no padding on all sides (optional)
* @param transparentBackground when selected, the background of the entire component is transparent (optional)
* @param chartHeight with this parameter, the height of the actual chart can be set to a fixed value in pixels. If
* chartHeight is not specified, the chart is given a fixed default height depending on `small`.
* @param disableExpandable when selected, the functionality to open the chart in a larger modal is disabled (optional)
* @param disablePieChartSwitch when selected, the functionality to switch to a pie chart is disabled (optional)
* @param disableDownload when selected, the functionality to download the chart is disabled (optional)
Expand All @@ -33,23 +34,21 @@ export function CategoricalChart({
small,
noPadding,
transparentBackground,
chartHeight,
disableExpandable,
disablePieChartSwitch,
disableDownload,
}: CategoricalChartProps) {
const { theme } = useTheme();

// build chart options for 'Highcharts'
const defaultChartOptions: Highcharts.Options | undefined = CategoricalChartOperations.getHighChartOptions(data);

// controlling if a bar or pie chart is rendered; bar chart is the default
const [showPieChart, setShowPieChart] = useState(false);
const [chartOptions, setChartOptions] = useState(defaultChartOptions);
const [showPieChart, setShowPieChart] = useState<boolean>(false);
const [chartOptions, setChartOptions] = useState<Highcharts.Options | undefined>(
CategoricalChartOperations.getHighChartOptions(data, showPieChart)
);

// handling the bar and pie chart switch and the theme switch;
useEffect(() => {
// function to update/recalculate the chart options
const recalculateChartOptions = () => {
setChartOptions(CategoricalChartOperations.getHighChartOptions(data, showPieChart));
}, [showPieChart, theme, data]);
};

const alternativeSwitchButtonProps = disablePieChartSwitch
? undefined
Expand All @@ -62,13 +61,15 @@ export function CategoricalChart({

return (
<ChartContainer
chartOptions={chartOptions}
chartData={data}
chartOptions={chartOptions}
recalculateChartOptions={recalculateChartOptions}
title={title}
description={description}
small={small}
noPadding={noPadding}
transparentBackground={transparentBackground}
chartHeight={chartHeight}
disableExpandable={disableExpandable}
disableDownload={disableDownload}
alternativeSwitchButtonProps={alternativeSwitchButtonProps}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,87 +1,94 @@
'use client';

import Highcharts from 'highcharts';
import { useTheme } from 'next-themes';
import { useEffect, useMemo, useState } from 'react';

import { ChartContainer } from '@/components/Charts/helpers/ChartContainer';
import { LineChartData } from '@/domain/entities/charts/LineChartData';
import { ContinuousChartData } from '@/domain/entities/charts/ContinuousChartData.ts';
import { ChartType } from '@/domain/enums/ChartType.ts';
import LineChartProps from '@/domain/props/LineChartProps';
import LineChartOperations from '@/operations/charts/LineChartOperations';
import ContinuousChartProps from '@/domain/props/ContinuousChartProps';
import ContinuousChartOperations from '@/operations/charts/ContinuousChartOperations.ts';

/**
* The LineChart component is a box that primarily renders a title, description text, and a line chart.
* The ContinuousChart component is a box that primarily renders a title, description text, and a line chart.
* It should be used to plot categorical data. For continues data please use the `CategoricalChart` component.
* This component has a width of 100%, so it adjusts to the width of its parent element in which it is used.
* The height of the entire box depends on the provided text, while the chart itself has a fixed height.
* It also provides the option to open the chart in a full-screen modal, where one can download the data as well.
*
* The data to be displayed in the chart can be provided in different types (see `LineChartProps.data`).
* However, the preferred type is `LineChartData`.
* The data to be displayed in the chart can be provided in different types (see `ContinuousChartProps.data`).
* However, the preferred type is `ContinuousChartData`.
*
* To enable the LineChart component to support an additional `data` type, the following steps are required:
* 1. Define an interface and add it to `LineChartProps.data`.
* 2. Add another switch case in `LineChartOperations.convertToLineChartData` to convert the new interface to `LineChartData`.
* To enable the ContinuousChart component to support an additional `data` type, the following steps are required:
* 1. Define an interface and add it to `ContinuousChartProps.data`.
* 2. Add another switch case in `ContinuousChartOperations.convertToContinuousChartData` to convert the new interface to `ContinuousChartData`.
*
* @param data the actual data to be used in the chart
* @param title chart title (optional)
* @param description chart description text (optional)
* @param small when selected, all components in the line chart box become slightly smaller (optional)
* @param small when selected, all components in the main box become slightly smaller (optional)
* @param noPadding when selected, the main box has no padding on all sides (optional)
* @param transparentBackground when selected, the background of the entire component is transparent (optional)
* @param chartHeight with this parameter, the height of the actual chart can be set to a fixed value in pixels. If
* chartHeight is not specified, the chart is given a fixed default height depending on `small`.
* @param disableExpandable when selected, the functionality to open the chart in a larger modal is disabled (optional)
* @param disableBarChartSwitch when selected, the functionality to switch to a bar chart is disabled (optional)
* @param disableXAxisSlider when selected, the functionality to change the x-axis range via a slider is disabled (optional)
* @param disableDownload when selected, the functionality to download the chart is disabled (optional)
*/
export function LineChart({
export function ContinuousChart({
data,
title,
description,
small,
noPadding,
transparentBackground,
chartHeight,
disableExpandable,
disableBarChartSwitch,
disableXAxisSlider,
disableDownload,
}: LineChartProps) {
const { theme } = useTheme();

// convert data to `LineChartData` and build chart options for 'Highcharts' (line and bar chart)
const lineChartData: LineChartData = LineChartOperations.convertToLineChartData(data);
const lineChartOptions: Highcharts.Options | undefined = LineChartOperations.getHighChartOptions(lineChartData);
}: ContinuousChartProps) {
// make sure data is converted to `continuousChartData`
const continuousChartData: ContinuousChartData = ContinuousChartOperations.convertToContinuousChartData(data);

// the `selectedXAxisRange` saves the to be rendered x-axis range of the chart
// can be changed using the `LineChartXAxisSlider` if the param `xAxisSlider==true`
const [selectedXAxisRange, setSelectedXAxisRange] = useState([0, 0]);
// can be changed using the `LinkeChartXAxisSlider` if the param `xAxisSlider==true`
const xAxisLength = useMemo(() => {
return LineChartOperations.getDistinctXAxisValues(lineChartData).length;
}, [lineChartData]);
return ContinuousChartOperations.getDistinctXAxisValues(continuousChartData).length;
}, [continuousChartData]);
const [selectedXAxisRange, setSelectedXAxisRange] = useState<number[]>([0, xAxisLength - 1]);

// we have to make sure that if the data changes we update the XAxis slider configuration as well
useEffect(() => {
setSelectedXAxisRange([0, xAxisLength - 1]);
}, [xAxisLength]);

// controlling if a line or bar chart is rendered; line chart is the default
const [showBarChart, setShowBarChart] = useState(false);
const [chartOptions, setChartOptions] = useState(lineChartOptions);
const [showBarChart, setShowBarChart] = useState<boolean>(false);
const [chartOptions, setChartOptions] = useState<Highcharts.Options | undefined>(
ContinuousChartOperations.getHighChartOptions(continuousChartData)
);

// handling the line and bar chart switch and the theme switch;
// also handling changing the x-axis range using the `LineChartXAxisSlider`;
// special: if the selected x-axis range has length 1 -> bar chart is displayed
useEffect(() => {
// function to update/recalculate the chart options
const recalculateChartOptions = () => {
// also handling changing the x-axis range using the `ChartXAxisSlider`;
// special: if the selected x-axis range has length 1 -> bar chart is displayed
if (showBarChart || selectedXAxisRange[1] - selectedXAxisRange[0] === 0) {
setChartOptions(
LineChartOperations.getHighChartOptions(lineChartData, selectedXAxisRange[0], selectedXAxisRange[1], true)
ContinuousChartOperations.getHighChartOptions(
continuousChartData,
selectedXAxisRange[0],
selectedXAxisRange[1],
true
)
);
} else {
setChartOptions(
LineChartOperations.getHighChartOptions(lineChartData, selectedXAxisRange[0], selectedXAxisRange[1])
ContinuousChartOperations.getHighChartOptions(continuousChartData, selectedXAxisRange[0], selectedXAxisRange[1])
);
}
}, [showBarChart, theme, selectedXAxisRange, lineChartData]);
};

// chart slider props - to manipulate the shown x-axis range
const sliderProps = disableXAxisSlider
Expand All @@ -105,13 +112,15 @@ export function LineChart({

return (
<ChartContainer
chartData={continuousChartData}
chartOptions={chartOptions}
chartData={lineChartData}
recalculateChartOptions={recalculateChartOptions}
title={title}
description={description}
small={small}
noPadding={noPadding}
transparentBackground={transparentBackground}
chartHeight={chartHeight}
disableExpandable={disableExpandable}
disableDownload={disableDownload}
alternativeSwitchButtonProps={alternativeSwitchButtonProps}
Expand Down
Loading
Loading