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

Fix RSK stats - transaction fees precision #1602

Merged
merged 3 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
2 changes: 1 addition & 1 deletion configs/envs/.env.eth
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ NEXT_PUBLIC_HAS_BEACON_CHAIN=true
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s.blockscout.com
NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s-prod-1.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 9 additions & 9 deletions ui/home/indicators/ChainIndicatorChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,28 @@ const ChainIndicatorChart = ({ data }: Props) => {
const axesConfig = React.useMemo(() => {
return {
x: { ticks: 4 },
y: { ticks: 3, nice: true },
y: { ticks: 3, nice: true, noLabel: true },
};
}, [ ]);

const { rect, ref, axis, innerWidth, innerHeight } = useTimeChartController({
const { rect, ref, axes, innerWidth, innerHeight, chartMargin } = useTimeChartController({
data,
margin: CHART_MARGIN,
axesConfig,
});

return (
<svg width="100%" height="100%" ref={ ref } cursor="pointer">
<g transform={ `translate(${ CHART_MARGIN?.left || 0 },${ CHART_MARGIN?.top || 0 })` } opacity={ rect ? 1 : 0 }>
<g transform={ `translate(${ chartMargin.left || 0 },${ chartMargin.top || 0 })` } opacity={ rect ? 1 : 0 }>
<ChartArea
data={ data[0].items }
xScale={ axis.x.scale }
yScale={ axis.y.scale }
xScale={ axes.x.scale }
yScale={ axes.y.scale }
/>
<ChartLine
data={ data[0].items }
xScale={ axis.x.scale }
yScale={ axis.y.scale }
xScale={ axes.x.scale }
yScale={ axes.y.scale }
stroke={ lineColor }
animation="left"
strokeWidth={ 3 }
Expand All @@ -54,8 +54,8 @@ const ChainIndicatorChart = ({ data }: Props) => {
anchorEl={ overlayRef.current }
width={ innerWidth }
height={ innerHeight }
xScale={ axis.x.scale }
yScale={ axis.y.scale }
xScale={ axes.x.scale }
yScale={ axes.y.scale }
data={ data }
/>
</ChartOverlay>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ui/shared/chart/ChartTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const ChartTooltip = ({ xScale, yScale, width, tooltipWidth = 200, height, data,
.selectAll<Element, TimeChartData>('.ChartTooltip__value')
.filter((td, tIndex) => tIndex === i)
.text(
(data[i].valueFormatter?.(d.value) || d.value.toLocaleString()) +
(data[i].valueFormatter?.(d.value) || d.value.toLocaleString(undefined, { minimumSignificantDigits: 1 })) +
(data[i].units ? ` ${ data[i].units }` : ''),
)
.nodes();
Expand Down
58 changes: 58 additions & 0 deletions ui/shared/chart/ChartWidget.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,61 @@ test('error', async({ mount }) => {

await expect(component).toHaveScreenshot();
});

test('small values', async({ mount, page }) => {
const modifiedProps = {
...props,
items: [
{ date: new Date('2023-02-13'), value: 0.000005041012112611958 },
{ date: new Date('2023-02-14'), value: 0.000004781545670577531 },
{ date: new Date('2023-02-15'), value: 0.00000520510604212437 },
{ date: new Date('2023-02-16'), value: 0.000005274901030625893 },
{ date: new Date('2023-02-17'), value: 0.00000534325322320271 },
{ date: new Date('2023-02-18'), value: 0.00000579140116207668 },
{ date: new Date('2023-02-19'), value: 0.000004878307079043056 },
{ date: new Date('2023-02-20'), value: 0.0000053454186920910215 },
{ date: new Date('2023-02-21'), value: 0.000005770588532081243 },
{ date: new Date('2023-02-22'), value: 0.00000589334810122426 },
{ date: new Date('2023-02-23'), value: 0.00000547040196358741 },
],
};

const component = await mount(
<TestApp>
<ChartWidget { ...modifiedProps }/>
</TestApp>,
);
await page.waitForFunction(() => {
return document.querySelector('path[data-name="chart-Nativecoincirculatingsupply-small"]')?.getAttribute('opacity') === '1';
});
await expect(component).toHaveScreenshot();
});

test('small variations in big values', async({ mount, page }) => {
const modifiedProps = {
...props,
items: [
{ date: new Date('2023-02-13'), value: 8886203 },
{ date: new Date('2023-02-14'), value: 8890184 },
{ date: new Date('2023-02-15'), value: 8893483 },
{ date: new Date('2023-02-16'), value: 8897924 },
{ date: new Date('2023-02-17'), value: 8902268 },
{ date: new Date('2023-02-18'), value: 8906320 },
{ date: new Date('2023-02-19'), value: 8910264 },
{ date: new Date('2023-02-20'), value: 8914827 },
{ date: new Date('2023-02-21'), value: 8918592 },
{ date: new Date('2023-02-22'), value: 8921988 },
{ date: new Date('2023-02-23'), value: 8922206 },
],
};

const component = await mount(
<TestApp>
<ChartWidget { ...modifiedProps }/>
</TestApp>,
);
await page.waitForFunction(() => {
return document.querySelector('path[data-name="chart-Nativecoincirculatingsupply-small"]')?.getAttribute('opacity') === '1';
});
await expect(component).toHaveScreenshot();
});
32 changes: 16 additions & 16 deletions ui/shared/chart/ChartWidgetGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useToken } from '@chakra-ui/react';
import * as d3 from 'd3';
import React from 'react';

import type { ChartMargin, TimeChartItem } from 'ui/shared/chart/types';
import type { ChartMargin, TimeChartData, TimeChartItem } from 'ui/shared/chart/types';

import dayjs from 'lib/date/dayjs';
import useIsMobile from 'lib/hooks/useIsMobile';
Expand All @@ -27,7 +27,7 @@ interface Props {

// temporarily turn off the data aggregation, we need a better algorithm for that
const MAX_SHOW_ITEMS = 100_000_000_000;
const DEFAULT_CHART_MARGIN = { bottom: 20, left: 40, right: 20, top: 10 };
const DEFAULT_CHART_MARGIN = { bottom: 20, left: 10, right: 20, top: 10 };

const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title, margin: marginProps, units }: Props) => {
const isMobile = useIsMobile();
Expand All @@ -51,7 +51,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
}
}, [ isGroupedValues, rangedItems ]);

const chartData = React.useMemo(() => ([ { items: displayedData, name: 'Value', color, units } ]), [ color, displayedData, units ]);
const chartData: TimeChartData = React.useMemo(() => ([ { items: displayedData, name: 'Value', color, units } ]), [ color, displayedData, units ]);

const margin: ChartMargin = React.useMemo(() => ({ ...DEFAULT_CHART_MARGIN, ...marginProps }), [ marginProps ]);
const axesConfig = React.useMemo(() => {
Expand All @@ -72,7 +72,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
innerWidth,
innerHeight,
chartMargin,
axis,
axes,
} = useTimeChartController({
data: chartData,
margin,
Expand All @@ -96,7 +96,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
<g transform={ `translate(${ chartMargin?.left || 0 },${ chartMargin?.top || 0 })` }>
<ChartGridLine
type="horizontal"
scale={ axis.y.scale }
scale={ axes.y.scale }
ticks={ axesConfig.y.ticks }
size={ innerWidth }
disableAnimation
Expand All @@ -106,34 +106,34 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
id={ chartId }
data={ displayedData }
color={ color }
xScale={ axis.x.scale }
yScale={ axis.y.scale }
xScale={ axes.x.scale }
yScale={ axes.y.scale }
/>

<ChartLine
data={ displayedData }
xScale={ axis.x.scale }
yScale={ axis.y.scale }
xScale={ axes.x.scale }
yScale={ axes.y.scale }
stroke={ color }
animation="none"
strokeWidth={ isMobile ? 1 : 2 }
/>

<ChartAxis
type="left"
scale={ axis.y.scale }
scale={ axes.y.scale }
ticks={ axesConfig.y.ticks }
tickFormatGenerator={ axis.y.tickFormatter }
tickFormatGenerator={ axes.y.tickFormatter }
disableAnimation
/>

<ChartAxis
type="bottom"
scale={ axis.x.scale }
scale={ axes.x.scale }
transform={ `translate(0, ${ innerHeight })` }
ticks={ axesConfig.x.ticks }
anchorEl={ overlayRef.current }
tickFormatGenerator={ axis.x.tickFormatter }
tickFormatGenerator={ axes.x.tickFormatter }
disableAnimation
/>

Expand All @@ -143,15 +143,15 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
width={ innerWidth }
tooltipWidth={ isGroupedValues ? 280 : 200 }
height={ innerHeight }
xScale={ axis.x.scale }
yScale={ axis.y.scale }
xScale={ axes.x.scale }
yScale={ axes.y.scale }
data={ chartData }
/>

<ChartSelectionX
anchorEl={ overlayRef.current }
height={ innerHeight }
scale={ axis.x.scale }
scale={ axes.x.scale }
data={ chartData }
onSelect={ handleRangeSelect }
/>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ui/shared/chart/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type TimeChartData = Array<TimeChartDataItem>;
export interface AxisConfig {
ticks?: number;
nice?: boolean;
noLabel?: boolean;
}

export interface AxesConfig {
Expand Down
28 changes: 13 additions & 15 deletions ui/shared/chart/useTimeChartController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { AxesConfig, ChartMargin, TimeChartData } from 'ui/shared/chart/typ
import useClientRect from 'lib/hooks/useClientRect';

import calculateInnerSize from './utils/calculateInnerSize';
import { getAxisParams, DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS } from './utils/timeChartAxis';
import { getAxesParams } from './utils/timeChartAxis';

interface Props {
data: TimeChartData;
Expand All @@ -19,29 +19,27 @@ export default function useTimeChartController({ data, margin, axesConfig }: Pro

// we need to recalculate the axis scale whenever the rect width changes
// eslint-disable-next-line react-hooks/exhaustive-deps
const axisParams = React.useMemo(() => getAxisParams(data, axesConfig), [ data, axesConfig, rect?.width ]);
const axesParams = React.useMemo(() => getAxesParams(data, axesConfig), [ data, axesConfig, rect?.width ]);

const chartMargin = React.useMemo(() => {
const exceedingDigits = (axisParams.y.labelFormatParams.maximumSignificantDigits ?? DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS) -
DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS;
const PIXELS_PER_DIGIT = 7;
const leftShift = PIXELS_PER_DIGIT * exceedingDigits;
const PIXELS_PER_DIGIT = 8;
const leftShift = axesConfig?.y?.noLabel ? 0 : PIXELS_PER_DIGIT * axesParams.y.labelFormatParams.maxLabelLength;

return {
...margin,
left: (margin?.left ?? 0) + leftShift,
};
}, [ axisParams.y.labelFormatParams.maximumSignificantDigits, margin ]);
}, [ axesParams.y.labelFormatParams.maxLabelLength, margin, axesConfig?.y?.noLabel ]);

const { innerWidth, innerHeight } = calculateInnerSize(rect, chartMargin);

const xScale = React.useMemo(() => {
return axisParams.x.scale.range([ 0, innerWidth ]);
}, [ axisParams.x.scale, innerWidth ]);
return axesParams.x.scale.range([ 0, innerWidth ]);
}, [ axesParams.x.scale, innerWidth ]);

const yScale = React.useMemo(() => {
return axisParams.y.scale.range([ innerHeight, 0 ]);
}, [ axisParams.y.scale, innerHeight ]);
return axesParams.y.scale.range([ innerHeight, 0 ]);
}, [ axesParams.y.scale, innerHeight ]);

return React.useMemo(() => {
return {
Expand All @@ -50,16 +48,16 @@ export default function useTimeChartController({ data, margin, axesConfig }: Pro
chartMargin,
innerWidth,
innerHeight,
axis: {
axes: {
x: {
tickFormatter: axisParams.x.tickFormatter,
tickFormatter: axesParams.x.tickFormatter,
scale: xScale,
},
y: {
tickFormatter: axisParams.y.tickFormatter,
tickFormatter: axesParams.y.tickFormatter,
scale: yScale,
},
},
};
}, [ axisParams.x.tickFormatter, axisParams.y.tickFormatter, chartMargin, innerHeight, innerWidth, rect, ref, xScale, yScale ]);
}, [ axesParams.x.tickFormatter, axesParams.y.tickFormatter, chartMargin, innerHeight, innerWidth, rect, ref, xScale, yScale ]);
}
28 changes: 15 additions & 13 deletions ui/shared/chart/utils/timeChartAxis.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as d3 from 'd3';
import _maxBy from 'lodash/maxBy';
import _unique from 'lodash/uniq';

import type { AxesConfig, AxisConfig, TimeChartData } from '../types';
Expand All @@ -8,8 +9,15 @@ import { WEEK, MONTH, YEAR } from 'lib/consts';
export const DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS = 2;
export const DEFAULT_MAXIMUM_FRACTION_DIGITS = 3;
export const MAXIMUM_SIGNIFICANT_DIGITS_LIMIT = 8;
export const DEFAULT_LABEL_LENGTH = 5;

export function getAxisParams(data: TimeChartData, axesConfig?: AxesConfig) {
export interface LabelFormatParams extends Intl.NumberFormatOptions {
maxLabelLength: number;
}

type Data = TimeChartData;

export function getAxesParams(data: Data, axesConfig?: AxesConfig) {
const { labelFormatParams: labelFormatParamsY, scale: yScale } = getAxisParamsY(data, axesConfig?.y);

return {
Expand All @@ -25,7 +33,7 @@ export function getAxisParams(data: TimeChartData, axesConfig?: AxesConfig) {
};
}

function getAxisParamsX(data: TimeChartData) {
function getAxisParamsX(data: Data) {
const min = d3.min(data, ({ items }) => d3.min(items, ({ date }) => date)) ?? new Date();
const max = d3.max(data, ({ items }) => d3.max(items, ({ date }) => date)) ?? new Date();
const scale = d3.scaleTime().domain([ min, max ]);
Expand Down Expand Up @@ -53,7 +61,7 @@ const tickFormatterX = (axis: d3.Axis<d3.NumberValue>) => (d: d3.AxisDomain) =>
return format(d as Date);
};

function getAxisParamsY(data: TimeChartData, config?: AxisConfig) {
function getAxisParamsY(data: Data, config?: AxisConfig) {
const DEFAULT_TICKS_NUM = 3;
const min = d3.min(data, ({ items }) => d3.min(items, ({ value }) => value)) ?? 0;
const max = d3.max(data, ({ items }) => d3.max(items, ({ value }) => value)) ?? 0;
Expand All @@ -72,27 +80,21 @@ function getAxisParamsY(data: TimeChartData, config?: AxisConfig) {

const getTickFormatterY = (params: Intl.NumberFormatOptions) => () => (d: d3.AxisDomain) => {
const num = Number(d);

if (num < 1) {
// for small number there are no algorithm to format label right now
// so we set it to 3 digits after dot maximum
return num.toLocaleString(undefined, { maximumFractionDigits: 3 });
}

return num.toLocaleString(undefined, params);
};

function getYLabelFormatParams(ticks: Array<number>, maximumSignificantDigits = DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS): Intl.NumberFormatOptions {
function getYLabelFormatParams(ticks: Array<number>, maximumSignificantDigits = DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS): LabelFormatParams {
const params = {
maximumFractionDigits: 3,
maximumFractionDigits: DEFAULT_MAXIMUM_FRACTION_DIGITS,
maximumSignificantDigits,
notation: 'compact' as const,
};

const uniqTicksStr = _unique(ticks.map((tick) => tick.toLocaleString(undefined, params)));
const maxLabelLength = _maxBy(uniqTicksStr, (items) => items.length)?.length ?? DEFAULT_LABEL_LENGTH;

if (uniqTicksStr.length === ticks.length || maximumSignificantDigits === MAXIMUM_SIGNIFICANT_DIGITS_LIMIT) {
return params;
return { ...params, maxLabelLength };
}

return getYLabelFormatParams(ticks, maximumSignificantDigits + 1);
Expand Down
Loading