Skip to content

Commit

Permalink
Merge pull request #96 from Franpastoragusti/graph-to-highcharts
Browse files Browse the repository at this point in the history
Graph to highcharts
  • Loading branch information
escottalexander authored Jul 24, 2024
2 parents 7703a99 + c2c5a37 commit 6adb45a
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
const SkeletonTable = () =>
[...Array(5)].map(i => (
<tr key={i} className="animate-pulse">
<td>
<div className="flex items-center">
<div className="animate-pulse flex space-x-4">
<div className="rounded-md bg-slate-300 h-6 w-6"></div>
<div className="flex items-center space-y-6">
<div className="h-2 w-28 bg-slate-300 rounded"></div>
[...Array(5).keys()]
.map(i => i + 1)
.map(i => (
<tr key={i} className="animate-pulse">
<td>
<div className="flex items-center">
<div className="animate-pulse flex space-x-4">
<div className="rounded-md bg-slate-300 h-6 w-6"></div>
<div className="flex items-center space-y-6">
<div className="h-2 w-28 bg-slate-300 rounded"></div>
</div>
</div>
</div>
</div>
</td>
<td>
<div className="h-2 w-14 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
</tr>
));
</td>
<td>
<div className="h-2 w-14 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
<td>
<div className="h-2 w-7 bg-slate-300 rounded"></div>
</td>
</tr>
));

export default SkeletonTable;
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const LeaderboardTable = ({ projects, loading, selectedMetricName = "impact_inde
<tr key={item.projectId}>
<td>
<Link href={`/project/${item.projectId}`}>
<div className="flex items-center font-semibold truncate">
<div className="flex items-center font-semibold truncate text-accent">
<Image
width={24}
height={24}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
"use client";

import React from "react";
import React, { useRef } from "react";
import { FilterButton } from "../filterButton/filterButton";
import { Skeleton } from "../skeleton/skeleton";
import { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import * as Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";
import { DatePicker } from "~~/components/impact-vector/inputs/datePicker";
import { IMetric } from "~~/services/mongodb/models/metric";
import { formatDate, stringToColor } from "~~/utils/onchainImpactDashboard/common";
import { stringToColor } from "~~/utils/onchainImpactDashboard/common";

interface IProps {
totalsRecord: any[];
Expand All @@ -32,41 +33,48 @@ export const ProjectTotalsGraph = ({
totalsRecord,
filter,
}: IProps) => {
const formatNumber = (num: number, dec?: number) => {
const m = 1000000;
const k = 1000;
const text = num >= m ? "M" : num >= k ? "K" : "";
if (dec != undefined) {
const divisor = num >= m ? m : num >= k ? k : 1;
const value = new Intl.NumberFormat().format(parseFloat((num / divisor).toFixed(dec)));
return `${value}${text}`;
}
return new Intl.NumberFormat().format(num);
};
const CustomTooltip = ({ active, payload, label }: any) => {
if (active && payload && payload.length) {
return (
<div className="bg-base-300 p-4 rounded-lg shadow">
<p className="m-0 p-0 label font-bold">{formatDate(label)}</p>
{payload.map((entry: any, index: any) => (
<div key={`item-${index}`}>
<p style={{ color: entry.color }} className="m-0 p-0 label">
{formatNumber(entry.value)}
</p>
</div>
))}
</div>
);
}
return null;
const options = {
chart: {
type: "line",
height: 360,
},
title: {
text: "",
},
subtitle: {
text: "",
},
credits: {
enabled: false,
},
xAxis: {
type: "datetime",
title: {
text: "",
},
dateTimeLabelFormats: {
day: "%e %b",
},
},
legend: {
enabled: false,
},
};

const chartComponentRef = useRef<HighchartsReact.RefObject>(null);
const metricToWork = metrics[selectedMetric];
const values = totalsRecord.map(d => d[metricToWork?.name]);
const newValues = totalsRecord.map(d => {
const date = new Date(d["date"]);
return [Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()), d[metricToWork?.name]];
});

let minValue = Math.min(...values);
const maxValue = Math.max(...values);
const isEmpty = maxValue == 0 && minValue == 0;
const buffer = minValue * 0.04 + 5;
const buffer = minValue * 0.03 + 5;
minValue = minValue - buffer > 0 ? minValue : minValue + buffer;

return (
<>
<div className="flex flex-col lg:w-[40%]">
Expand Down Expand Up @@ -143,37 +151,51 @@ export const ProjectTotalsGraph = ({
</div>
)}
</div>

<ResponsiveContainer width="100%" className={"absolute top-14"}>
<div>
{isEmpty ? (
<div className="flex justify-center items-center w-full h-[300px] text-neutral-content">
No data found
</div>
) : (
<AreaChart data={totalsRecord} margin={{ top: 20, right: -16, bottom: 45, left: 2 }}>
<Area
key={metricToWork.name}
type="monotone"
dataKey={metricToWork.name}
stroke={stringToColor(metricToWork.label ?? "")}
fill={stringToColor(metricToWork.label ?? "")}
/>
<CartesianGrid strokeDasharray="3 3" />
<XAxis tick={false} fontSize={10} hide={false} dataKey="date" />
<YAxis
fontSize={10}
type={"number"}
domain={[minValue - buffer, maxValue + buffer]}
hide={false}
allowDataOverflow={true}
orientation="right"
tickFormatter={v => formatNumber(v, 0)}
ticks={[minValue - buffer, maxValue + buffer]}
/>
<Tooltip content={<CustomTooltip />} />
</AreaChart>
<HighchartsReact
highcharts={Highcharts}
options={{
...options,
yAxis: {
title: {
text: null,
},
min: minValue - buffer,
max: maxValue + buffer,
},
tooltip: {
xDateFormat: "%b %e, %Y",
pointFormatter: function (this: Highcharts.TooltipFormatterContextObject) {
const formattedNumber = Highcharts.numberFormat(this.y as number, 0, "", ",");
return (
'<span style="color:' +
this.color +
'">\u25CF</span> ' +
this.series.name +
": <b>" +
formattedNumber +
"</b><br/>"
);
},
},

series: [
{
name: metricToWork.label,
data: newValues,
color: stringToColor(metricToWork.label || ""),
},
],
}}
ref={chartComponentRef}
/>
)}
</ResponsiveContainer>
</div>
</div>
) : (
<div className="mb-4">
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"d3-scale": "^4.0.2",
"daisyui": "^4.4.19",
"fs": "^0.0.1-security",
"highcharts": "^11.4.6",
"highcharts-react-official": "^3.2.1",
"lodash": "^4.17.21",
"mongodb": "^6.8.0",
"next": "^14.0.4",
Expand Down
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,8 @@ __metadata:
eslint-config-prettier: ^8.5.0
eslint-plugin-prettier: ^4.2.1
fs: ^0.0.1-security
highcharts: ^11.4.6
highcharts-react-official: ^3.2.1
lodash: ^4.17.21
mongodb: ^6.8.0
mongoose: ^8.4.5
Expand Down Expand Up @@ -5950,6 +5952,23 @@ __metadata:
languageName: node
linkType: hard

"highcharts-react-official@npm:^3.2.1":
version: 3.2.1
resolution: "highcharts-react-official@npm:3.2.1"
peerDependencies:
highcharts: ">=6.0.0"
react: ">=16.8.0"
checksum: 615f1a352eb95f0e78189506e7d551071438fc11eabff78c55aeb6cc63658f4c284f4920f9e9c85113b319661bf5745c668ef22b71920c1a9f24749e49584aaf
languageName: node
linkType: hard

"highcharts@npm:^11.4.6":
version: 11.4.6
resolution: "highcharts@npm:11.4.6"
checksum: 7aa3871d19892c20a95b36754cc8c0234af0dd310e1fbe9a87cf489c315d55ac99497d1dba87f0bea8356b9e5886231bbb25f6de0b1dba92b31456aeee481cab
languageName: node
linkType: hard

"hmac-drbg@npm:^1.0.1":
version: 1.0.1
resolution: "hmac-drbg@npm:1.0.1"
Expand Down

0 comments on commit 6adb45a

Please sign in to comment.