Commit 43cf0fae authored by Yuri Mikhin's avatar Yuri Mikhin Committed by Yuri Mikhin

Chart refinements.

parent f54a17da
......@@ -2,12 +2,14 @@ import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import appConfig from 'configs/app/config';
import Stats from '../ui/pages/Stats';
const StatsPage: NextPage = () => {
return (
<>
<Head><title>Ethereum Stats</title></Head>
<Head><title>{ appConfig.network.name } Stats</title></Head>
<Stats/>
</>
);
......
import { Box } from '@chakra-ui/react';
import React from 'react';
import appConfig from 'configs/app/config';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -21,7 +22,7 @@ const Stats = () => {
return (
<Page>
<PageTitle text="Ethereum Stats"/>
<PageTitle text={ `${ appConfig.network.name } Stats` }/>
<Box mb={{ base: 6, sm: 8 }}>
<NumberWidgetsList/>
......
......@@ -6,6 +6,7 @@ import React from 'react';
import type { TimeChartItem } from 'ui/shared/chart/types';
interface Props extends React.SVGProps<SVGPathElement> {
id?: string;
xScale: d3.ScaleTime<number, number> | d3.ScaleLinear<number, number>;
yScale: d3.ScaleTime<number, number> | d3.ScaleLinear<number, number>;
color?: string;
......@@ -13,10 +14,11 @@ interface Props extends React.SVGProps<SVGPathElement> {
disableAnimation?: boolean;
}
const ChartArea = ({ xScale, yScale, color, data, disableAnimation, ...props }: Props) => {
const ChartArea = ({ id, xScale, yScale, color, data, disableAnimation, ...props }: Props) => {
const ref = React.useRef(null);
const theme = useTheme();
const gradientColorId = `${ id || 'gradient' }-${ color }-color`;
const gradientStopColor = useToken('colors', useColorModeValue('whiteAlpha.200', 'blackAlpha.100'));
const defaultGradient = {
startColor: useToken('colors', useColorModeValue('blue.100', 'blue.400')),
......@@ -45,11 +47,11 @@ const ChartArea = ({ xScale, yScale, color, data, disableAnimation, ...props }:
return (
<>
<path ref={ ref } d={ d } fill={ color ? `url(#gradient-${ color })` : 'url(#gradient-chart-area-default)' } opacity={ 0 } { ...props }/>
<path ref={ ref } d={ d } fill={ color ? `url(#${ gradientColorId })` : 'url(#gradient-chart-area-default)' } opacity={ 0 } { ...props }/>
{ color ? (
<defs>
<linearGradient id={ `gradient-${ color }` } x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="20%" stopColor={ color }/>
<linearGradient id={ `${ gradientColorId }` } x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stopColor={ color }/>
<stop offset="100%" stopColor={ gradientStopColor }/>
</linearGradient>
</defs>
......
......@@ -9,6 +9,7 @@ import type { Pointer } from 'ui/shared/chart/utils/pointerTracker';
import { trackPointer } from 'ui/shared/chart/utils/pointerTracker';
interface Props {
chartId?: string;
width?: number;
height?: number;
data: TimeChartData;
......@@ -22,7 +23,7 @@ const PADDING = 16;
const LINE_SPACE = 10;
const POINT_SIZE = 16;
const ChartTooltip = ({ xScale, yScale, width, height, data, anchorEl, ...props }: Props) => {
const ChartTooltip = ({ chartId, xScale, yScale, width, height, data, anchorEl, ...props }: Props) => {
const lineColor = useToken('colors', 'gray.400');
const titleColor = useToken('colors', 'blue.100');
const textColor = useToken('colors', 'white');
......@@ -71,10 +72,10 @@ const ChartTooltip = ({ xScale, yScale, width, height, data, anchorEl, ...props
);
const updateDisplayedValue = React.useCallback((d: TimeChartItem, i: number) => {
d3.selectAll('.ChartTooltip__value')
d3.selectAll(`${ chartId ? `#${ chartId }` : '' } .ChartTooltip__value`)
.filter((td, tIndex) => tIndex === i)
.text(data[i].valueFormatter?.(d.value) || d.value.toLocaleString());
}, [ data ]);
}, [ data, chartId ]);
const drawPoints = React.useCallback((x: number) => {
const xDate = xScale.invert(x);
......
......@@ -27,14 +27,15 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) =
const [ range, setRange ] = React.useState<[ number, number ]>([ 0, Infinity ]);
const { width, height, innerWidth, innerHeight } = useChartSize(ref.current, CHART_MARGIN);
const overlayRef = React.useRef<SVGRectElement>(null);
const color = useToken('colors', 'blue.500');
const color = useToken('colors', 'blue.200');
const chartId = useMemo(() => `chart-${ crypto.randomUUID() }`, []);
const displayedData = useMemo(() => items.slice(range[0], range[1]).map((d) =>
({ ...d, date: new Date(d.date) })), [ items, range ]);
const chartData = [ { items: items, name: title, color } ];
const chartData = [ { items: items, name: 'Value', color } ];
const { yTickFormat, xScale, yScale } = useTimeChartController({
data: [ { items: displayedData, name: 'chart', color } ],
data: [ { items: displayedData, name: title, color } ],
width: innerWidth,
height: innerHeight,
});
......@@ -51,7 +52,7 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) =
}, [ isZoomResetInitial ]);
return (
<svg width={ width || '100%' } height={ height || '100%' } ref={ ref } cursor="pointer">
<svg width={ width || '100%' } height={ height || '100%' } ref={ ref } cursor="pointer" id={ chartId }>
<g transform={ `translate(${ CHART_MARGIN?.left || 0 },${ CHART_MARGIN?.top || 0 })` } opacity={ width ? 1 : 0 }>
<ChartGridLine
......@@ -63,6 +64,7 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) =
/>
<ChartArea
id={ chartId }
data={ displayedData }
color={ color }
xScale={ xScale }
......@@ -97,6 +99,7 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) =
/>
<ChartTooltip
chartId={ chartId }
anchorEl={ overlayRef.current }
width={ innerWidth }
height={ innerHeight }
......
......@@ -9,8 +9,7 @@ type Props = {
const NumberWidget = ({ label, value }: Props) => {
return (
<Box
border="1px"
borderColor={ useColorModeValue('gray.200', 'gray.600') }
bg={ useColorModeValue('blue.50', 'blue.800') }
p={ 3 }
borderRadius={ 12 }
>
......
......@@ -6,12 +6,18 @@ import type { StatsInterval, StatsIntervalIds, StatsSection, StatsSectionIds } f
import FilterInput from 'ui/shared/FilterInput';
import { STATS_INTERVALS, STATS_SECTIONS } from './constants';
import { statsChartsScheme } from './constants/charts-scheme';
import StatsDropdownMenu from './StatsDropdownMenu';
const sectionsList = Object.keys(STATS_SECTIONS).map((id: string) => ({
const listedSections = statsChartsScheme
.filter(section => section.charts.length > 0);
const sectionsList = Object.keys(STATS_SECTIONS)
.filter(key => key === 'all' || listedSections.some(section => section.id === key))
.map((id: string) => ({
id: id,
title: STATS_SECTIONS[id as StatsSectionIds],
})) as Array<StatsSection>;
})) as Array<StatsSection>;
const intervalList = Object.keys(STATS_INTERVALS).map((id: string) => ({
id: id,
......
......@@ -14,9 +14,7 @@ function isChartNameMatches(q: string, chart: StatsChart) {
}
export default function useStats() {
const [ isLoading, setIsLoading ] = useState(true);
const [ defaultCharts, setDefaultCharts ] = useState<Array<StatsSection>>();
const [ displayedCharts, setDisplayedCharts ] = useState<Array<StatsSection>>([]);
const [ displayedCharts, setDisplayedCharts ] = useState<Array<StatsSection>>(statsChartsScheme);
const [ section, setSection ] = useState<StatsSectionIds>('all');
const [ interval, setInterval ] = useState<StatsIntervalIds>('all');
const [ filterQuery, setFilterQuery ] = useState('');
......@@ -25,7 +23,7 @@ export default function useStats() {
const debounceFilterCharts = useCallback(debounce(q => setFilterQuery(q), 500), []);
const filterCharts = useCallback((q: string, currentSection: StatsSectionIds) => {
const charts = defaultCharts
const charts = statsChartsScheme
?.map((section: StatsSection) => {
const charts = section.charts.map((chart: StatsChart) => ({
...chart,
......@@ -39,7 +37,7 @@ export default function useStats() {
});
setDisplayedCharts(charts || []);
}, [ defaultCharts ]);
}, []);
const handleSectionChange = useCallback((newSection: StatsSectionIds) => {
setSection(newSection);
......@@ -53,19 +51,12 @@ export default function useStats() {
filterCharts(filterQuery, section);
}, [ filterQuery, section, filterCharts ]);
useEffect(() => {
setDefaultCharts(statsChartsScheme);
setDisplayedCharts(statsChartsScheme);
setIsLoading(false);
}, []);
return React.useMemo(() => ({
section,
handleSectionChange,
interval,
handleIntervalChange,
debounceFilterCharts,
isLoading,
displayedCharts,
}), [
section,
......@@ -74,6 +65,5 @@ export default function useStats() {
handleIntervalChange,
debounceFilterCharts,
displayedCharts,
isLoading,
]);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment