diff --git a/src/components/ShieldedPoolChart.tsx b/src/components/ShieldedPoolChart.tsx index 023caf5f..5a5fcf7c 100644 --- a/src/components/ShieldedPoolChart.tsx +++ b/src/components/ShieldedPoolChart.tsx @@ -11,18 +11,26 @@ import { LinearGradient } from '@visx/gradient'; import { max, extent, bisector } from '@visx/vendor/d3-array'; import { timeFormat } from '@visx/vendor/d3-time-format'; -// Define types for data +/** + * Type of values from the shielded pool over time. Each datum is amount + * shielded at a given date. + */ type ShieldedAmountDatum = { - Date: string; - Hashrate: string; + close: string; + supply: number; + Date : string; + Hashrate : any }; interface ShieldedPoolChartProps { dataUrl: string; - color: string; + color : string; } -// Fetch data function +/** + * Loads the historic shielded pool data from a public json file in Github repo + * @returns Promise of shielded pool data + */ async function fetchShieldedSupplyData(url: string): Promise> { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); @@ -41,30 +49,55 @@ const tooltipStyles = { color: 'white', }; -// Date format from data +/** Date format from data, i.e. "01/01/1970" */ const formatDate = timeFormat("%b %d, '%y"); -// Function to extract Date from data -const getDate = (d: ShieldedAmountDatum): Date => new Date(d.Date); +/** + * Native `Date` object from datum + * @param d datum for measurement of shielded amount + * @returns Date object + */ +const getDate = (d: ShieldedAmountDatum): Date => new Date(d.close ?? d.Date); -// Function to extract and convert hashrate value from data -const getShieldedValue = (d: ShieldedAmountDatum): number => { - const hashrate = d.Hashrate ? parseFloat(d.Hashrate.replace(/,/g, '')) : 0; - return hashrate; -}; +/** + * Returns the shielded amount from datum + * @param d + * @returns number + */ +const getShieldedValue = (d: ShieldedAmountDatum): number => d.supply ?? d.Hashrate.replace(/,/g, '') / 100000000000000000000000000000000000; -// Bisector for date -const bisectDate = bisector((d) => new Date(d.Date)).left; +/** Bisector for date */ +const bisectDate = bisector((d) => new Date(d.close ?? d.Date)).left; +/** + * Default width for the chart. It will render 1000px wide, although if this + * happens that means there an error with the `userRef` hook below. + */ const DEFAULT_WIDTH = 1000; + +/* Default height for the chart. It will render 500px tall. */ const DEFAULT_HEIGHT = 500; +/** + * Props to override default layout, all of which are optional. By default, the + * visualization will take up the entire width of the parent container, and the + * height will be 500px. + */ export type AreaProps = { providedWidth?: number; providedHeight?: number; margin?: { top: number; right: number; bottom: number; left: number }; }; +/** + * Area line chart for shielded pool over time + * @param props can be used to override height, width, and margin + * + * Inspired by example from visx documentation: https://visx.dev/examples/gallery?group=Area&show=AreaClosed + * + * @returns Area chart for shielded pool over time + * + */ const ShieldedPoolChart = withTooltip( ({ dataUrl, @@ -79,11 +112,18 @@ const ShieldedPoolChart = withTooltip & ShieldedPoolChartProps) => { + /* State for chart data loaded from server */ const [chartData, setChartData] = useState([] as Array); + const yMax = useMemo(() => max(chartData, getShieldedValue) || 0, [chartData]); + + /* Loading state for chart data in progress */ const [isLoading, setIsLoading] = useState(false); + + /* Error state for chart data */ const [error, setError] = useState(null); + // Fetch data whenever dataUrl changes useEffect(() => { setIsLoading(true); fetchShieldedSupplyData(dataUrl) @@ -92,13 +132,20 @@ const ShieldedPoolChart = withTooltip setIsLoading(false)); }, [dataUrl]); + /** + * Reference to child, which will fill all space available horizontally + */ const ref = useRef(null); + + // State for width and height so that they update as browser size changes const [width, setWidth] = useState(providedWidth); const [height, setHeight] = useState(providedHeight); + // Compute inner height and width based upon margin const innerWidth = width - margin.left - margin.right; const innerHeight = height - margin.top - margin.bottom; + // Update width and height on resize useLayoutEffect(() => { if (ref.current) { setWidth(ref?.current?.clientWidth || providedWidth); @@ -106,6 +153,9 @@ const ShieldedPoolChart = withTooltip scaleTime({ @@ -115,6 +165,9 @@ const ShieldedPoolChart = withTooltip scaleLinear({ @@ -125,6 +178,10 @@ const ShieldedPoolChart = withTooltip | React.MouseEvent) => { const { x } = localPoint(event) || { x: 0 }; @@ -145,10 +202,12 @@ const ShieldedPoolChart = withTooltip { return new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 }).format(number); }; + // Render loading message when loading if (chartData.length === 0 || isLoading) { return (
@@ -157,6 +216,7 @@ const ShieldedPoolChart = withTooltip @@ -165,7 +225,9 @@ const ShieldedPoolChart = withTooltip hideTooltip()} - aria-label="Hover overlay" + aria-label="Shielded pooling over time" /> {tooltipData && ( @@ -233,7 +295,7 @@ const ShieldedPoolChart = withTooltip - ZECHUB DASHBOARD + ZECHUB DASHBOARD