Commit 1dcc7fb6 authored by tom's avatar tom

refactor chart resize

parent aa4e71b9
import { useToken } from '@chakra-ui/react'; import { useToken } from '@chakra-ui/react';
import _debounce from 'lodash/debounce';
import React from 'react'; import React from 'react';
import type { ChartMargin } from 'ui/shared/chart/types';
import json from 'data/charts_eth_txs.json'; import json from 'data/charts_eth_txs.json';
import ChartArea from 'ui/shared/chart/ChartArea'; import ChartArea from 'ui/shared/chart/ChartArea';
import ChartAxis from 'ui/shared/chart/ChartAxis'; import ChartAxis from 'ui/shared/chart/ChartAxis';
...@@ -10,52 +11,18 @@ import ChartLine from 'ui/shared/chart/ChartLine'; ...@@ -10,52 +11,18 @@ import ChartLine from 'ui/shared/chart/ChartLine';
import ChartOverlay from 'ui/shared/chart/ChartOverlay'; import ChartOverlay from 'ui/shared/chart/ChartOverlay';
import ChartTooltip from 'ui/shared/chart/ChartTooltip'; import ChartTooltip from 'ui/shared/chart/ChartTooltip';
import useBrushX from 'ui/shared/chart/useBrushX'; import useBrushX from 'ui/shared/chart/useBrushX';
import useChartSize from 'ui/shared/chart/useChartSize';
import useTimeChartController from 'ui/shared/chart/useTimeChartController'; import useTimeChartController from 'ui/shared/chart/useTimeChartController';
interface Props { interface Props {
margin?: { margin?: ChartMargin;
top?: number;
right?: number;
bottom?: number;
left?: number;
};
} }
const EthereumDailyTxsChart = ({ margin }: Props) => { const EthereumDailyTxsChart = ({ margin }: Props) => {
const ref = React.useRef<SVGSVGElement>(null); const ref = React.useRef<SVGSVGElement>(null);
const overlayRef = React.useRef<SVGRectElement>(null); const overlayRef = React.useRef<SVGRectElement>(null);
const [ rect, setRect ] = React.useState<{ width: number; height: number}>({ width: 0, height: 0 }); const { width, height, innerWidth, innerHeight } = useChartSize(ref.current, margin);
const calculateRect = React.useCallback(() => {
const rect = ref.current?.getBoundingClientRect();
return { width: rect?.width || 0, height: rect?.height || 0 };
}, []);
React.useEffect(() => {
setRect(calculateRect());
}, [ calculateRect ]);
React.useEffect(() => {
let timeoutId: number;
const resizeHandler = _debounce(() => {
setRect({ width: 0, height: 0 });
timeoutId = window.setTimeout(() => {
setRect(calculateRect());
}, 0);
}, 100);
const resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(document.body);
return function cleanup() {
resizeObserver.unobserve(document.body);
window.clearTimeout(timeoutId);
};
}, [ calculateRect ]);
const { width, height } = rect;
const innerWidth = Math.max(width - (margin?.left || 0) - (margin?.right || 0), 0);
const innerHeight = Math.max(height - (margin?.bottom || 0) - (margin?.top || 0), 0);
const brushLimits = React.useMemo(() => ( const brushLimits = React.useMemo(() => (
[ [ 0, innerHeight ], [ innerWidth, height ] ] as [[number, number], [number, number]] [ [ 0, innerHeight ], [ innerWidth, height ] ] as [[number, number], [number, number]]
......
...@@ -2,17 +2,12 @@ import { useToken, useColorModeValue } from '@chakra-ui/react'; ...@@ -2,17 +2,12 @@ import { useToken, useColorModeValue } from '@chakra-ui/react';
import * as d3 from 'd3'; import * as d3 from 'd3';
import React from 'react'; import React from 'react';
import type { TimeChartItem } from 'ui/shared/chart/types'; import type { TimeChartItem, ChartMargin } from 'ui/shared/chart/types';
interface Props { interface Props {
width?: number; width?: number;
height?: number; height?: number;
margin?: { margin?: ChartMargin;
top?: number;
bottom?: number;
left?: number;
right?: number;
};
data: { data: {
items: Array<TimeChartItem>; items: Array<TimeChartItem>;
}; };
......
...@@ -2,3 +2,10 @@ export interface TimeChartItem { ...@@ -2,3 +2,10 @@ export interface TimeChartItem {
date: Date; date: Date;
value: number; value: number;
} }
export interface ChartMargin {
top?: number;
right?: number;
bottom?: number;
left?: number;
}
...@@ -13,7 +13,7 @@ export default function useBrushX({ limits, anchor }: Props) { ...@@ -13,7 +13,7 @@ export default function useBrushX({ limits, anchor }: Props) {
const brushSelectionBg = useToken('colors', useColorModeValue('blackAlpha.400', 'whiteAlpha.500')); const brushSelectionBg = useToken('colors', useColorModeValue('blackAlpha.400', 'whiteAlpha.500'));
React.useEffect(() => { React.useEffect(() => {
if (!anchor || brushRef.current) { if (!anchor || brushRef.current || limits[1][0] === 0) {
return; return;
} }
...@@ -25,7 +25,7 @@ export default function useBrushX({ limits, anchor }: Props) { ...@@ -25,7 +25,7 @@ export default function useBrushX({ limits, anchor }: Props) {
}); });
const gBrush = svgEl?.append('g') const gBrush = svgEl?.append('g')
.attr('class', 'brush') .attr('class', 'ChartBrush')
.call(brushRef.current); .call(brushRef.current);
gBrush.select('.selection') gBrush.select('.selection')
......
import _debounce from 'lodash/debounce';
import React from 'react';
import type { ChartMargin } from 'ui/shared/chart/types';
export default function useChartSize(svgEl: SVGSVGElement | null, margin?: ChartMargin) {
const [ rect, setRect ] = React.useState<{ width: number; height: number}>({ width: 0, height: 0 });
const calculateRect = React.useCallback(() => {
const rect = svgEl?.getBoundingClientRect();
return { width: rect?.width || 0, height: rect?.height || 0 };
}, [ svgEl ]);
React.useEffect(() => {
setRect(calculateRect());
}, [ calculateRect ]);
React.useEffect(() => {
let timeoutId: number;
const resizeHandler = _debounce(() => {
setRect({ width: 0, height: 0 });
timeoutId = window.setTimeout(() => {
setRect(calculateRect());
}, 0);
}, 100);
const resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(document.body);
return function cleanup() {
resizeObserver.unobserve(document.body);
window.clearTimeout(timeoutId);
};
}, [ calculateRect ]);
return React.useMemo(() => {
return {
width: rect.width,
height: rect.height,
innerWidth: Math.max(rect.width - (margin?.left || 0) - (margin?.right || 0), 0),
innerHeight: Math.max(rect.height - (margin?.bottom || 0) - (margin?.top || 0), 0),
};
}, [ margin?.bottom, margin?.left, margin?.right, margin?.top, rect ]);
}
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