Skip to content

Commit

Permalink
fix(web): add chart fixes (#598)
Browse files Browse the repository at this point in the history
* fix(web): do not display gas stats and metrics as ethereum units

* perf(web): prevent unnecessary re-renders in `MetricCard`

Resolved an issue where the increment animation was being triggered n times, where n is the value of the metric

* feat(web): display Ethereum units in the chart title instead of on the axis + show full (non-compacted) amounts in tooltips + align chart's grid positioning

* fix(web): add daily blob size chart improvements:

- Hide y-axis byte units and display it on chart title
- Fix displayed byte unit on y-axis

* chore: add changesets

* chore: update `pnpm-lock.yaml`

* fix(web): display unformatted units in chart headers

* refactor(web): perform trimming when removing commas from numeric values

* refactor: make the target unit optional in the Wei formatting functions

If no unit is provided, automatically determine and use the most appropriate unit

* fix: update eth formatting functions to display unit by default
  • Loading branch information
PJColombo authored Nov 8, 2024
1 parent f93f96f commit 05bdc1d
Show file tree
Hide file tree
Showing 26 changed files with 405 additions and 269 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-clocks-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/web": patch
---

Standarized y-axis units and displayed full amounts on tooltips on charts
5 changes: 5 additions & 0 deletions .changeset/pretty-pigs-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/eth-units": minor
---

Made unit display optional when formatting wei amounts
5 changes: 5 additions & 0 deletions .changeset/thick-trains-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@blobscan/web": patch
---

Displayed full amounts on chart tooltips
1 change: 0 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
"next": "^14.2.5",
"next-themes": "^0.2.1",
"posthog-js": "^1.166.1",
"pretty-bytes": "^6.1.1",
"react": "18.2.0",
"react-blockies": "^1.4.1",
"react-dom": "18.2.0",
Expand Down
59 changes: 34 additions & 25 deletions apps/web/src/components/Cards/MetricCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ import cn from "classnames";
import "react-loading-skeleton/dist/skeleton.css";
import Skeleton from "react-loading-skeleton";

import { findBestUnit, prettyFormatWei } from "@blobscan/eth-units";

import { formatBytes, formatNumber } from "~/utils";
import { prettyFormatWei } from "@blobscan/eth-units";

import {
formatBytes,
formatNumber,
parseDecimalNumber,
parseSuffixedNumber,
} from "~/utils";
import { Card } from "./Card";

export type MetricType = "standard" | "bytes" | "ethereum" | "percentage";
Expand All @@ -24,10 +29,6 @@ export type MetricCardProps = Partial<{
secondaryMetric?: MetricProp;
}>;

function isInteger(value: bigint | number) {
return Number.isInteger(value) || typeof value === "bigint";
}

/**
* Creates a placeholder string that takes up the maximum amount of space the input could take with
* that amount of characters
Expand All @@ -41,7 +42,7 @@ function createPlaceholder(input: string): string {
return replacedString;
}

function formatMetric(
function parseMetricValue(
value: number | bigint,
{
type,
Expand All @@ -66,7 +67,7 @@ function formatMetric(
formattedValue = formatBytes(value);
break;
case "ethereum":
formattedValue = prettyFormatWei(value, findBestUnit(value));
formattedValue = prettyFormatWei(value);
break;
case "percentage":
formattedValue = `${formatNumber(value, mode, {
Expand All @@ -83,9 +84,17 @@ function formatMetric(
}

const [value_ = "0", unit = ""] = formattedValue.split(" ");
const [numericPart, suffix] = parseSuffixedNumber(value_);
const [integerPart, decimalPart] = parseDecimalNumber(
numericPart ? numericPart.toString() : ""
);

return {
value: value_,
numericPart,
integerPart,
decimalPart,
suffix,
unit,
};
}
Expand Down Expand Up @@ -124,16 +133,18 @@ function Metric({
compact,
isSecondary = false,
}: MetricProp & { compact?: boolean; isSecondary?: boolean }) {
const isValueInteger = value && isInteger(value);
const parsedMetric = parseMetricValue(value ?? 0, {
type,
compact,
numberFormatOpts,
});

const valueProps = useSpring({
value: Number(value),
value: parsedMetric.numericPart,
from: { value: 0 },
cancel: !value,
});
const isValueSet = value !== undefined;
const formattedMetric = isValueSet
? formatMetric(value, { type, compact, numberFormatOpts })
: undefined;

return (
<div>
Expand All @@ -142,15 +153,13 @@ function Metric({
<MetricLayout compact={compact} isSecondary={isSecondary}>
{isValueSet ? (
<animated.div>
{valueProps.value.to((x) => {
const x_ = isValueInteger ? Math.trunc(x) : x;
const { value: formattedX } = formatMetric(x_, {
type,
compact,
numberFormatOpts,
});

return formattedX;
{valueProps.value.to((v) => {
const formattedValue = formatNumber(
v.toFixed(parsedMetric.decimalPart?.length ?? 0)
);
const suffix = parsedMetric.suffix ?? "";

return `${formattedValue}${suffix}`;
})}
</animated.div>
) : (
Expand All @@ -164,7 +173,7 @@ function Metric({
*/}
<div className="invisible">
<MetricLayout compact={compact} isSecondary={isSecondary}>
{createPlaceholder(formattedMetric?.value ?? "")}
{createPlaceholder(parsedMetric.value ?? "")}
</MetricLayout>
</div>
<div
Expand All @@ -176,7 +185,7 @@ function Metric({
{ "bottom-0.5 text-xs": isSecondary }
)}
>
{formattedMetric?.unit}
{parsedMetric?.unit}
</div>
</div>
</div>
Expand Down
18 changes: 10 additions & 8 deletions apps/web/src/components/Charts/Blob/DailyBlobSizeChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ export const DailyBlobSizeChart: FC<Partial<DailyBlobsSizeProps>> = function ({
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisLabel: (value: number) =>
formatBytes(value, { maximumFractionDigits: 0 }),
yAxisTooltip: (value: number) => formatBytes(value),
yAxisLabel: (value) =>
formatBytes(Number(value), {
unit: "GiB",
hideUnit: true,
}),
yAxisTooltip: (value) =>
formatBytes(Number(value), { unit: "GiB", displayAllDecimals: true }),
},
yUnit: "bytes",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Blob Size",
Expand All @@ -40,5 +40,7 @@ export const DailyBlobSizeChart: FC<Partial<DailyBlobsSizeProps>> = function ({
],
};

return <ChartCard title="Daily Blob Size" size="sm" options={options} />;
return (
<ChartCard title="Daily Blob Size (in GiB)" size="sm" options={options} />
);
};
5 changes: 1 addition & 4 deletions apps/web/src/components/Charts/Blob/DailyBlobsChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,9 @@ export const DailyBlobsChart: FC<Partial<DailyBlobsChartProps>> = function ({
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatNumber(value, "compact"),
yAxisTooltip: (value) => formatNumber(value),
},
}),
grid: {
containLabel: true,
},
series: [
{
name: "Total Blobs",
Expand Down
17 changes: 9 additions & 8 deletions apps/web/src/components/Charts/Block/DailyAvgBlobFeeChart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { FC } from "react";
import type { EChartOption } from "echarts";

import { findBestUnit, formatWei, prettyFormatWei } from "@blobscan/eth-units";
import { formatWei, prettyFormatWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
Expand All @@ -21,14 +21,11 @@ export const DailyAvgBlobFeeChart: FC<Partial<DailyAvgBlobFeeChartProps>> =
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatWei(value, findBestUnit(value)),
yAxisLabel: (value) => prettyFormatWei(value, unit),
yAxisTooltip: (value) => formatWei(value, { toUnit: unit }),
yAxisLabel: (value) =>
prettyFormatWei(value, { toUnit: unit, hideUnit: true }),
},
yUnit: "ethereum",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Avg. Blob Fees",
Expand All @@ -40,6 +37,10 @@ export const DailyAvgBlobFeeChart: FC<Partial<DailyAvgBlobFeeChartProps>> =
};

return (
<ChartCard title="Daily Avg. Blob Fee" size="sm" options={options} />
<ChartCard
title={`Daily Avg. Blob Fee (in ${unit})`}
size="sm"
options={options}
/>
);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { FC } from "react";
import type { EChartOption } from "echarts";

import { findBestUnit, formatWei, prettyFormatWei } from "@blobscan/eth-units";
import { formatWei, prettyFormatWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
Expand All @@ -22,14 +22,11 @@ export const DailyAvgBlobGasPriceChart: FC<
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatWei(value, findBestUnit(value)),
yAxisLabel: (value) => prettyFormatWei(value, unit),
yAxisTooltip: (value) => formatWei(value, { toUnit: unit }),
yAxisLabel: (value) =>
prettyFormatWei(value, { toUnit: unit, hideUnit: true }),
},
yUnit: "ethereum",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Avg. Blob Gas Prices",
Expand All @@ -41,6 +38,10 @@ export const DailyAvgBlobGasPriceChart: FC<
};

return (
<ChartCard title="Daily Avg. Blob Gas Price" size="sm" options={options} />
<ChartCard
title={`Daily Avg. Blob Gas Price (in ${unit})`}
size="sm"
options={options}
/>
);
};
19 changes: 11 additions & 8 deletions apps/web/src/components/Charts/Block/DailyBlobFeeChart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { FC } from "react";
import type { EChartOption } from "echarts";

import { findBestUnit, formatWei, prettyFormatWei } from "@blobscan/eth-units";
import { formatWei, prettyFormatWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
Expand All @@ -22,14 +22,11 @@ export const DailyBlobFeeChart: FC<Partial<DailyBlobFeeChartProps>> =
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatWei(value, findBestUnit(value)),
yAxisLabel: (value) => prettyFormatWei(value, unit),
yAxisTooltip: (value) => formatWei(value, { toUnit: unit }),
yAxisLabel: (value) =>
prettyFormatWei(value, { toUnit: unit, hideUnit: true }),
},
yUnit: "ethereum",
}),
grid: {
containLabel: true,
},
series: [
{
name: "Blob Fees",
Expand All @@ -40,5 +37,11 @@ export const DailyBlobFeeChart: FC<Partial<DailyBlobFeeChartProps>> =
animationEasing: "cubicOut",
};

return <ChartCard title="Daily Blob Fees" size="sm" options={options} />;
return (
<ChartCard
title={`Daily Blob Fees (in ${unit})`}
size="sm"
options={options}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ import * as echarts from "echarts";
import type { EChartOption } from "echarts";
import { useTheme } from "next-themes";

import { findBestUnit, formatWei, prettyFormatWei } from "@blobscan/eth-units";

import { ChartCard } from "~/components/Cards/ChartCard";
import { useScaledWeiAmounts } from "~/hooks/useScaledWeiAmounts";
import type { DailyBlockStats } from "~/types";
import { buildTimeSeriesOptions } from "~/utils";
import { buildTimeSeriesOptions, formatNumber } from "~/utils";

export type DailyBlobGasComparisonChartProps = Partial<{
days: DailyBlockStats["days"];
Expand All @@ -20,24 +17,18 @@ export type DailyBlobGasComparisonChartProps = Partial<{
export const DailyBlobGasComparisonChart: FC<DailyBlobGasComparisonChartProps> =
function ({ blobAsCalldataGasUsed, blobGasUsed, days, opts = {} }) {
const { resolvedTheme } = useTheme();
const data = blobGasUsed?.map((x) => Number(x));
const { unit } = useScaledWeiAmounts(data);

const options: EChartOption<EChartOption.Series> = {
...buildTimeSeriesOptions({
dates: days,
axisFormatters: {
yAxisTooltip: (value) => formatWei(value, findBestUnit(value)),
yAxisLabel: (value) => prettyFormatWei(value, unit),
yAxisTooltip: (value) => formatNumber(value, "standard"),
},
}),
grid: {
containLabel: true,
},
series: [
{
name: "Blob Gas Used",
data: data,
data: blobGasUsed,
stack: "gas",
type: "bar",

Expand Down
Loading

0 comments on commit 05bdc1d

Please sign in to comment.