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

Design graph component (CO2 Captured and Canopy Cover) #1984

Open
wants to merge 30 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1213804
add graph
prachigarg19 Feb 20, 2024
9b7385e
modify graph
prachigarg19 Feb 20, 2024
dd0567a
change stories for graph
prachigarg19 Feb 20, 2024
48a56fb
add style for tooltips
prachigarg19 Feb 20, 2024
0fba756
changes made:
prachigarg19 Feb 20, 2024
1d5fc82
add annotation line
prachigarg19 Feb 20, 2024
112cbfb
add title and subtitle
prachigarg19 Feb 20, 2024
0773520
make component common
prachigarg19 Feb 20, 2024
0b580e9
add interface
prachigarg19 Feb 20, 2024
127bf0e
remove unused imports
prachigarg19 Feb 20, 2024
4bfc2ed
resolve ts errors
prachigarg19 Feb 21, 2024
b877681
add chromatic workflow
prachigarg19 Feb 21, 2024
905bef8
add gradient in graph
prachigarg19 Feb 21, 2024
0c17009
add property to make tooltip follow cursor
prachigarg19 Feb 21, 2024
e26e9fb
add styles for annotation
prachigarg19 Feb 21, 2024
af864b8
add translations
prachigarg19 Feb 21, 2024
9081299
add useEffect and useState
prachigarg19 Feb 22, 2024
ee59f93
fix heading style
prachigarg19 Feb 27, 2024
fa4dd15
remove hard coded width
prachigarg19 Feb 27, 2024
e88986a
Merge branch 'feature/redesign-explore-btn' into feature/design-captu…
prachigarg19 Mar 5, 2024
5b48d1f
replace hardcoded colors and fonts
prachigarg19 Mar 5, 2024
32dd91a
fix: fix heading
prachigarg19 Mar 14, 2024
466bbf8
refactor: merge base branch,resolve merge conflict
sunilsabatp Jul 7, 2024
338075b
fix: translation issue, code clean up, remove hardcode value
sunilsabatp Jul 9, 2024
ae8b71a
feat: story for canopy cover, minor code cleanup
sunilsabatp Jul 12, 2024
4029516
refactor: increase the font-size
sunilsabatp Jul 12, 2024
b6227d7
refactor: make text bold
sunilsabatp Jul 12, 2024
c7de0b1
feat: dot notation for project launch verticle line
sunilsabatp Jul 12, 2024
09f4a45
feat: include month in the graph tootip
sunilsabatp Jul 12, 2024
314a4e2
feat: reduce stroke dash array
sunilsabatp Jul 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/chromatic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- develop
- feature/redesign-explore-btn
- feature/merge-from-develop
- feature/design-capture-graph
# List of jobs
jobs:
chromatic-deployment:
Expand Down
9 changes: 8 additions & 1 deletion public/static/locales/en/projectDetails.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
"plantingSeasons": "planting seasons",
"privateProperty": "private property",
"publicProperty": "public property",
"progressReports": "progress reports"
"progressReports": "progress reports",
"co2CapturePerHa": "CO₂ Captured<captureContainer>(per ha.)</captureContainer>",
"comparedToRegionalAverage": "Compared to regional average",
"co2Removed": "{value}t CO₂ removed",
"biomass": "{value}t Biomass",
"yoy": "+{value}% YoY",
"projectLaunch": "Project Launch",
"canopyCover": "Canopy Cover"
}
}
75 changes: 75 additions & 0 deletions src/temp/CarbonCapture/Graph.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
@import '../../theme/theme';

.tooltipContainer {
min-width: 120px;
.header {
padding: 10px 10px 8px 10px;
.title {
color: #333; //to be replaced
font-size: $fontSmall;
font-weight: 500;
margin-bottom: 5px;
}
.subtitle {
font-size: $fontXXSmallNew;
font-weight: 400;
}
}
.body {
background-color: rgba(var(--primary-color-new), 0.1);
padding: 4px 10px;
display: flex;
justify-content: space-between;
align-items: center;
.yoyValue {
color: $secondaryColorNew;
font-weight: 700;
font-size: $fontXXSmallNew;
}
.date {
font-size: 10px;
font-weight: 500;
color: $dark;
opacity: 0.5;
}
}
}

.container {
width: 100%;
max-width: 338px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.graphHeading {
font-size: $fontXXSmall;
color: #2f3336; //to be replaced
display: flex;
align-items: center;
padding: 0 15px;
gap: 2px;
font-weight: 700;
span {
font-weight: 400;
}
}
.graphSubheading {
color: #bdbdbd; //to be replaced
font-size: $fontXXSmallNew;
text-transform: lowercase;
padding: 0 15px;
}
}

.titleContainer {
width: 100%;
max-width: 300px;
}
.newInfoIcon {
margin-left: auto;
margin-right: 6px;
display: flex;
align-items: center;
cursor: pointer;
}
248 changes: 248 additions & 0 deletions src/temp/CarbonCapture/Graph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import React, { useEffect, useState } from 'react';
import ReactApexChart from 'react-apexcharts';
import styles from './Graph.module.scss';
import ReactDOMServer from 'react-dom/server';
import NewInfoIcon from '../icons/NewInfoIcon';
import { ApexOptions } from 'apexcharts';
import { useTranslations } from 'next-intl';
import themeProperties from '../../theme/themeProperties';

interface TooltipProps {
headerTitle: string;
subTitle: string;
yoyValue: string;
date: string;
type: 'canopyCover' | 'carbonCapture';
canopyCoverPercentage: number;
}

export const Tooltip = ({
headerTitle,
subTitle,
yoyValue,
date,
type,
canopyCoverPercentage,
}: TooltipProps) => {
return (
<div className={styles.tooltipContainer}>
<div className={styles.header}>
<p className={styles.title}>
{type === 'carbonCapture' ? headerTitle : `${canopyCoverPercentage}%`}
</p>
{type === 'carbonCapture' && (
<p className={styles.subtitle}>{subTitle}</p>
)}
</div>
<div className={styles.body}>
<p className={styles.yoyValue}>{yoyValue}</p>
<p className={styles.date}>Aug {date}</p>
</div>
</div>
);
};

interface GraphProps {
title: string;
subtitle: string;
years: number[];
byProjectResult: number[];
regionalAverage: number[];
type: 'carbonCapture' | 'canopyCover';
}

interface CustomTooltipProps {
dataPointIndex: number;
w: { config: ApexOptions; globals: any };
}

const Graph = ({
years,
byProjectResult,
regionalAverage,
type,
}: GraphProps) => {
const t = useTranslations('ProjectDetails');
const [xaxisOptions, setXaxisOptions] = useState<
(number | (string | number)[])[]
>([]);
const { light, primaryDarkColorX, darkBlackColor } = themeProperties;
useEffect(() => {
const newOptions = years.map((year, index) => {
if (index === 1) {
return [2020, ` ${t('projectLaunch')}`];
} else {
return year;
}
});
setXaxisOptions(newOptions);
}, []);
Comment on lines +70 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid hardcoding values and update dependency array

In the useEffect hook, the use of a hardcoded year (2020) when setting x-axis options can lead to incorrect labeling if the actual years differ. Additionally, the dependency array is empty, which may cause issues if years or t (translations) change.

Apply this diff to use dynamic year values and update the dependency array:

useEffect(() => {
  const newOptions = years.map((year, index) => {
    if (index === 1) {
-     return [2020, ` ${t('projectLaunch')}`];
+     return [year, ` ${t('projectLaunch')}`];
    } else {
      return year;
    }
  });
  setXaxisOptions(newOptions);
-}, []);
+}, [years, t]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
const newOptions = years.map((year, index) => {
if (index === 1) {
return [2020, ` ${t('projectLaunch')}`];
} else {
return year;
}
});
setXaxisOptions(newOptions);
}, []);
useEffect(() => {
const newOptions = years.map((year, index) => {
if (index === 1) {
return [year, ` ${t('projectLaunch')}`];
} else {
return year;
}
});
setXaxisOptions(newOptions);
}, [years, t]);


const options = {
fill: {
type: 'gradient',
gradient: {
shadeIntensity: 1,
opacityFrom: 0.58,
opacityTo: 0,
},
},
chart: {
type: 'area',
width: 300,
toolbar: {
show: false,
},
},
Comment on lines +90 to +96
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove hardcoded chart width for responsiveness

The chart's width is hardcoded to 300, which may not render well on different screen sizes. Allowing the chart to adapt to its container improves responsiveness.

Remove the hardcoded width:

chart: {
  type: 'area',
- width: 300,
  toolbar: {
    show: false,
  },
},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
chart: {
type: 'area',
width: 300,
toolbar: {
show: false,
},
},
chart: {
type: 'area',
toolbar: {
show: false,
},
},

tooltip: {
custom: function ({ dataPointIndex, w }: CustomTooltipProps) {
const getToolTip = () => {
const headingTranslation = t('co2Removed', {
value: w.globals.series[0][dataPointIndex],
});
const subHeadingTranslation = t('biomass', {
value: w.globals.series[1][dataPointIndex],
});
const yoyTranslation = t('yoy', {
value: 4,
});
const canopyCoverPercentage = 43;
const dataPoint = xaxisOptions[dataPointIndex];
const year = Array.isArray(dataPoint) ? dataPoint[0] : dataPoint;
const date = year.toString();

return (
<Tooltip
headerTitle={headingTranslation}
subTitle={subHeadingTranslation}
yoyValue={yoyTranslation}
date={date}
type={type}
canopyCoverPercentage={canopyCoverPercentage}
/>
);
};

return ReactDOMServer.renderToString(getToolTip());
},
Comment on lines +98 to +127
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use dynamic data in tooltip content

Within the custom tooltip function, the values for yoyTranslation and canopyCoverPercentage are hardcoded (value: 4 and canopyCoverPercentage = 43). This can result in inaccurate tooltip information. Consider calculating these values based on the actual data to ensure accuracy.

Update the code to use dynamic values:

const getToolTip = () => {
  const headingTranslation = t('co2Removed', {
    value: w.globals.series[0][dataPointIndex],
  });
  const subHeadingTranslation = t('biomass', {
    value: w.globals.series[1][dataPointIndex],
  });
- const yoyTranslation = t('yoy', {
-   value: 4,
- });
- const canopyCoverPercentage = 43;
+ const currentValue = w.globals.series[0][dataPointIndex];
+ const previousValue = w.globals.series[0][dataPointIndex - 1] || currentValue;
+ const yoyValue = ((currentValue - previousValue) / previousValue) * 100;
+ const yoyTranslation = t('yoy', {
+   value: yoyValue.toFixed(2),
+ });
+ const canopyCoverPercentage = currentValue;
  const dataPoint = xaxisOptions[dataPointIndex];
  const year = Array.isArray(dataPoint) ? dataPoint[0] : dataPoint;

  return (
    <Tooltip
      headerTitle={headingTranslation}
      subTitle={subHeadingTranslation}
      yoyValue={yoyTranslation}
      date={year.toString()}
      type={type}
      canopyCoverPercentage={canopyCoverPercentage}
    />
  );
};

Ensure that previousValue handles cases where there is no previous data point.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
custom: function ({ dataPointIndex, w }: CustomTooltipProps) {
const getToolTip = () => {
const headingTranslation = t('co2Removed', {
value: w.globals.series[0][dataPointIndex],
});
const subHeadingTranslation = t('biomass', {
value: w.globals.series[1][dataPointIndex],
});
const yoyTranslation = t('yoy', {
value: 4,
});
const canopyCoverPercentage = 43;
const dataPoint = xaxisOptions[dataPointIndex];
const year = Array.isArray(dataPoint) ? dataPoint[0] : dataPoint;
const date = year.toString();
return (
<Tooltip
headerTitle={headingTranslation}
subTitle={subHeadingTranslation}
yoyValue={yoyTranslation}
date={date}
type={type}
canopyCoverPercentage={canopyCoverPercentage}
/>
);
};
return ReactDOMServer.renderToString(getToolTip());
},
custom: function ({ dataPointIndex, w }: CustomTooltipProps) {
const getToolTip = () => {
const headingTranslation = t('co2Removed', {
value: w.globals.series[0][dataPointIndex],
});
const subHeadingTranslation = t('biomass', {
value: w.globals.series[1][dataPointIndex],
});
const currentValue = w.globals.series[0][dataPointIndex];
const previousValue = w.globals.series[0][dataPointIndex - 1] || currentValue;
const yoyValue = ((currentValue - previousValue) / previousValue) * 100;
const yoyTranslation = t('yoy', {
value: yoyValue.toFixed(2),
});
const canopyCoverPercentage = currentValue;
const dataPoint = xaxisOptions[dataPointIndex];
const year = Array.isArray(dataPoint) ? dataPoint[0] : dataPoint;
return (
<Tooltip
headerTitle={headingTranslation}
subTitle={subHeadingTranslation}
yoyValue={yoyTranslation}
date={year.toString()}
type={type}
canopyCoverPercentage={canopyCoverPercentage}
/>
);
};
return ReactDOMServer.renderToString(getToolTip());
},

followCursor: true,
},
markers: {
size: 0,
colors: [`${light.light}`, 'transparent'],
strokeColors: [`${primaryDarkColorX}`, 'transparent'],
strokeOpacity: [1, 1],
strokeWidth: 2.2,
hover: {
size: 6,
},
},

dataLabels: {
enabled: false,
},
stroke: {
curve: 'smooth',
width: 2.2,
},
xaxis: {
type: 'year',
labels: {
formatter: function (index: number) {
if (index === 2) {
return xaxisOptions[1];
} else if (index == xaxisOptions.length) {
return xaxisOptions[index - 1];
} else {
return '';
}
},
Comment on lines +151 to +159
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct x-axis label formatter function

The x-axis label formatter function uses index, but ApexCharts provides value to the formatter. This may result in labels not displaying correctly.

Modify the formatter function to use value:

labels: {
- formatter: function (index: number) {
-   if (index === 2) {
-     return xaxisOptions[1];
-   } else if (index == xaxisOptions.length) {
-     return xaxisOptions[index - 1];
+ formatter: function (value: number, timestamp?: number, opts?: any) {
+   const dataPointIndex = opts?.dataPoints?.findIndex(
+     (point: any) => point.x === value
+   );
+   if (dataPointIndex === 1) {
+     return xaxisOptions[1][1];
+   } else if (dataPointIndex === xaxisOptions.length - 1) {
+     return xaxisOptions[dataPointIndex];
    } else {
      return '';
    }
  },

This ensures labels are displayed correctly based on the x-axis values.

Committable suggestion was skipped due to low confidence.

minHeight: 35,
style: {
colors: `${light.grayFontColorNew}`,
fontSize: 10,
},
},
show: false,
axisTicks: {
show: false,
},
tooltip: {
enabled: false,
},
axisBorder: {
show: false,
},
},
yaxis: {
show: false,
},
grid: {
show: false,
},
legend: {
show: false,
},
annotations: {
xaxis: [
{
x: xaxisOptions[1],
strokeDashArray: 2,
borderColor: `${darkBlackColor}`,
},
],
},
};
const series = [
{
name: 'series1',
data: byProjectResult,
color: `${primaryDarkColorX}`,
zIndex: 2,
},
{
name: 'series2',
data: regionalAverage,
color: `${light.dividerColorNew}`,
zIndex: 1,
},
];

return (
<div className={styles.container}>
<div className={styles.titleContainer}>
<h5 className={styles.graphHeading}>
{type === 'carbonCapture'
? t.rich('co2CapturePerHa', {
captureContainer: (chunk) => <span>{chunk}</span>,
})
: t('canopyCover')}
<div className={styles.newInfoIcon}>
<NewInfoIcon
height={17}
width={17}
color={`${light.dividerColorNew}`}
/>
</div>
</h5>
{type === 'carbonCapture' && (
<p className={styles.graphSubheading}>
{t('comparedToRegionalAverage')}
</p>
)}
</div>
<div id="chart">
<ReactApexChart
options={options}
series={series}
type="area"
height={153}
width={'100%'}
/>
</div>
<div id="html-dist"></div>
</div>
);
};

export default Graph;
29 changes: 29 additions & 0 deletions src/temp/stories/Graph.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Meta, StoryObj } from '@storybook/react';
import Graph from '../CarbonCapture/Graph';

const meta: Meta<typeof Graph> = {
component: Graph,
};

export default meta;
type Story = StoryObj<typeof Graph>;

const years = [2019, 2020, 2021, 2022, 2023];

export const CarbonCapture: Story = {
args: {
years: years,
byProjectResult: [23.4, 23.27, 23.78, 23.7, 23.78],
regionalAverage: [22.54, 22.65, 21.8, 21.85, 22.03],
type: 'carbonCapture',
},
};

export const CanopyCover: Story = {
args: {
years: years,
byProjectResult: [23, 24, 25, 26, 27],
regionalAverage: [19, 20, 21, 22, 23],
type: 'canopyCover',
},
};
1 change: 1 addition & 0 deletions src/theme/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ $dividerColorNew: var(--divider-color-new);
$reviewFontColorNew: var(--review-font-color-new);
$aboutProjectBackgroundColorNew: var(--about-project-background-color-new);
$dangerColorNew: var(--danger-color-new);
$secondaryColorNew: var(--secondary-color-new);
1 change: 1 addition & 0 deletions src/theme/_fonts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ $fontXXXLarge: var(--font-xxx-large);
$secondaryFontFamily: var(--secondary-font-family);
$fontXXXSmallNew: var(--font-xxx-extra-small-new);
$fontXXXXSmallNew: var(--font-xxxx-extra-small-new);
$fontXXSmallNew: var(--font-xx-extra-small-new);
Loading
Loading