From 4bb57e9c475cb32b8ef1cf7428311ac19d1c1268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Wed, 22 Feb 2023 03:01:48 +0100 Subject: [PATCH] fix(market-depth): fix order book priceInCenter calculation and scroll to price (#2901) --- .../src/lib/market-depth-provider.ts | 12 +- libs/market-depth/src/lib/orderbook-data.ts | 94 +++--- .../src/lib/orderbook-manager.tsx | 30 +- libs/market-depth/src/lib/orderbook.spec.tsx | 22 +- libs/market-depth/src/lib/orderbook.tsx | 282 ++++++++---------- 5 files changed, 223 insertions(+), 217 deletions(-) diff --git a/libs/market-depth/src/lib/market-depth-provider.ts b/libs/market-depth/src/lib/market-depth-provider.ts index ac6c17d3e..27353c3da 100644 --- a/libs/market-depth/src/lib/market-depth-provider.ts +++ b/libs/market-depth/src/lib/market-depth-provider.ts @@ -42,10 +42,18 @@ export const update: Update< }, }; if (delta.buy) { - updatedData.depth.buy = updateLevels(data.depth.buy ?? [], delta.buy); + updatedData.depth.buy = updateLevels( + data.depth.buy ?? [], + delta.buy, + false + ); } if (delta.sell) { - updatedData.depth.sell = updateLevels(data.depth.sell ?? [], delta.sell); + updatedData.depth.sell = updateLevels( + data.depth.sell ?? [], + delta.sell, + true + ); } updatedData.depth.sequenceNumber = delta.sequenceNumber; return updatedData; diff --git a/libs/market-depth/src/lib/orderbook-data.ts b/libs/market-depth/src/lib/orderbook-data.ts index 0ee248f38..e24bed573 100644 --- a/libs/market-depth/src/lib/orderbook-data.ts +++ b/libs/market-depth/src/lib/orderbook-data.ts @@ -26,9 +26,19 @@ export interface OrderbookRowData { type PartialOrderbookRowData = Pick; -export type OrderbookData = Partial< - Omit -> & { rows: OrderbookRowData[] | null }; +type OrderbookMarketData = Pick< + MarketData, + | 'bestStaticBidPrice' + | 'bestStaticOfferPrice' + | 'indicativePrice' + | 'indicativeVolume' + | 'marketTradingMode' +>; + +export type OrderbookData = Partial & { + rows: OrderbookRowData[] | null; + midPrice?: string; +}; export const getPriceLevel = (price: string | bigint, resolution: number) => { const p = BigInt(price); @@ -40,6 +50,18 @@ export const getPriceLevel = (price: string | bigint, resolution: number) => { return priceLevel.toString(); }; +export const getMidPrice = ( + sell: PriceLevelFieldsFragment[] | null | undefined, + buy: PriceLevelFieldsFragment[] | null | undefined, + resolution: number +) => + buy?.length && sell?.length + ? getPriceLevel( + (BigInt(buy[0].price) + BigInt(sell[0].price)) / BigInt(2), + resolution + ) + : undefined; + const getMaxVolumes = (orderbookData: OrderbookRowData[]) => ({ bid: Math.max(...orderbookData.map((data) => data.bid)), ask: Math.max(...orderbookData.map((data) => data.ask)), @@ -157,8 +179,15 @@ export const compactRows = ( } orderbookData.push(row); }); - // order by price, it's safe to cast to number price diff should not exceed Number.MAX_SAFE_INTEGER - orderbookData.sort((a, b) => Number(BigInt(b.price) - BigInt(a.price))); + orderbookData.sort((a, b) => { + if (a === b) { + return 0; + } + if (BigInt(a.price) > BigInt(b.price)) { + return -1; + } + return 1; + }); // count cumulative volumes if (orderbookData.length > 1) { const maxIndex = orderbookData.length - 1; @@ -253,28 +282,6 @@ export const updateCompactedRows = ( return data; }; -export const mapMarketData = ( - data: Pick< - MarketData, - | 'staticMidPrice' - | 'bestStaticBidPrice' - | 'bestStaticOfferPrice' - | 'indicativePrice' - > | null, - resolution: number -) => ({ - staticMidPrice: - data?.staticMidPrice && getPriceLevel(data?.staticMidPrice, resolution), - bestStaticBidPrice: - data?.bestStaticBidPrice && - getPriceLevel(data?.bestStaticBidPrice, resolution), - bestStaticOfferPrice: - data?.bestStaticOfferPrice && - getPriceLevel(data?.bestStaticOfferPrice, resolution), - indicativePrice: - data?.indicativePrice && getPriceLevel(data?.indicativePrice, resolution), -}); - /** * Updates raw data with new data received from subscription - mutates input * @param levels @@ -283,7 +290,8 @@ export const mapMarketData = ( */ export const updateLevels = ( draft: PriceLevelFieldsFragment[], - updates: (PriceLevelFieldsFragment | PriceLevelFieldsFragment)[] + updates: (PriceLevelFieldsFragment | PriceLevelFieldsFragment)[], + ascending = true ) => { const levels = [...draft]; updates.forEach((update) => { @@ -295,8 +303,10 @@ export const updateLevels = ( levels[index] = update; } } else if (update.volume !== '0') { - index = levels.findIndex( - (level) => BigInt(level.price) > BigInt(update.price) + index = levels.findIndex((level) => + ascending + ? BigInt(level.price) > BigInt(update.price) + : BigInt(level.price) < BigInt(update.price) ); if (index !== -1) { levels.splice(index, 0, update); @@ -346,22 +356,20 @@ export const generateMockData = ({ numberOfOrders: '', })); const rows = compactRows(sell, buy, resolution); + const marketTradingMode = + overlap > 0 + ? Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION + : Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS; return { rows, resolution, indicativeVolume: indicativeVolume?.toString(), - marketTradingMode: - overlap > 0 - ? Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION - : Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS, - ...mapMarketData( - { - staticMidPrice: '', - bestStaticBidPrice: bestStaticBidPrice.toString(), - bestStaticOfferPrice: bestStaticOfferPrice.toString(), - indicativePrice: indicativePrice?.toString() ?? '', - }, - resolution - ), + marketTradingMode, + midPrice: ((bestStaticBidPrice + bestStaticOfferPrice) / 2).toString(), + bestStaticBidPrice: bestStaticBidPrice.toString(), + bestStaticOfferPrice: bestStaticOfferPrice.toString(), + indicativePrice: indicativePrice + ? getPriceLevel(indicativePrice.toString(), resolution) + : undefined, }; }; diff --git a/libs/market-depth/src/lib/orderbook-manager.tsx b/libs/market-depth/src/lib/orderbook-manager.tsx index 5d630e99e..bca813f55 100644 --- a/libs/market-depth/src/lib/orderbook-manager.tsx +++ b/libs/market-depth/src/lib/orderbook-manager.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import throttle from 'lodash/throttle'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { Orderbook } from './orderbook'; @@ -8,12 +9,14 @@ import type { MarketData } from '@vegaprotocol/market-list'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import type { MarketDepthUpdateSubscription, + MarketDepthQuery, PriceLevelFieldsFragment, } from './__generated__/MarketDepth'; import { compactRows, updateCompactedRows, - mapMarketData, + getMidPrice, + getPriceLevel, } from './orderbook-data'; import type { OrderbookData } from './orderbook-data'; import { usePersistedOrderStore } from '@vegaprotocol/orders'; @@ -31,6 +34,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { }); const dataRef = useRef({ rows: null }); const marketDataRef = useRef(null); + const rawDataRef = useRef(null); const deltaRef = useRef<{ sell: PriceLevelFieldsFragment[]; buy: PriceLevelFieldsFragment[]; @@ -42,7 +46,17 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { throttle(() => { dataRef.current = { ...marketDataRef.current, - ...mapMarketData(marketDataRef.current, resolutionRef.current), + indicativePrice: marketDataRef.current?.indicativePrice + ? getPriceLevel( + marketDataRef.current.indicativePrice, + resolutionRef.current + ) + : undefined, + midPrice: getMidPrice( + rawDataRef.current?.depth.sell, + rawDataRef.current?.depth.buy, + resolution + ), rows: deltaRef.current.buy.length || deltaRef.current.sell.length ? updateCompactedRows( @@ -56,14 +70,16 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { deltaRef.current.buy = []; deltaRef.current.sell = []; setOrderbookData(dataRef.current); - }, 1000) + }, 250) ); const update = useCallback( ({ delta: deltas, + data: rawData, }: { delta?: MarketDepthUpdateSubscription['marketsDepthUpdate']; + data?: MarketDepthQuery['market']; }) => { if (!dataRef.current.rows) { return false; @@ -78,6 +94,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { if (delta.buy) { deltaRef.current.buy.push(...delta.buy); } + rawDataRef.current = rawData; updateOrderbookData.current(); } return true; @@ -134,9 +151,14 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { } dataRef.current = { ...marketDataRef.current, - ...mapMarketData(marketDataRef.current, resolution), + indicativePrice: getPriceLevel( + marketDataRef.current.indicativePrice, + resolution + ), + midPrice: getMidPrice(data.depth.sell, data.depth.buy, resolution), rows: compactRows(data.depth.sell, data.depth.buy, resolution), }; + rawDataRef.current = data; setOrderbookData(dataRef.current); return () => { diff --git a/libs/market-depth/src/lib/orderbook.spec.tsx b/libs/market-depth/src/lib/orderbook.spec.tsx index f047a4ce0..d6f3511b4 100644 --- a/libs/market-depth/src/lib/orderbook.spec.tsx +++ b/libs/market-depth/src/lib/orderbook.spec.tsx @@ -92,7 +92,7 @@ describe('Orderbook', () => { expect(result.getByTestId('scroll').scrollTop).toBe(90 * rowHeight); }); - it('should should keep price it the middle', async () => { + it('should keep price it the middle', async () => { window.innerHeight = 11 * rowHeight; const result = render( { await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`)); const scrollElement = result.getByTestId('scroll'); expect(scrollElement.scrollTop).toBe(91 * rowHeight); - scrollElement.scrollTop = 92 * rowHeight; + scrollElement.scrollTop = 92 * rowHeight + 0.01; fireEvent.scroll(scrollElement); result.rerender( { /> ); await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`)); - expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight); + expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight + 0.01); }); - it('should should get back to mid price on click', async () => { + it('should get back to mid price on click', async () => { window.innerHeight = 11 * rowHeight; const result = render( { await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`)); const scrollElement = result.getByTestId('scroll'); expect(scrollElement.scrollTop).toBe(91 * rowHeight); - scrollElement.scrollTop = 0; + scrollElement.scrollTop = 1; fireEvent.scroll(scrollElement); - expect(result.getByTestId('scroll').scrollTop).toBe(0); + expect(result.getByTestId('scroll').scrollTop).toBe(1); const scrollToMidPriceButton = result.getByTestId('scroll-to-midprice'); fireEvent.click(scrollToMidPriceButton); - expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight); + expect(result.getByTestId('scroll').scrollTop).toBe(91 * rowHeight + 1); }); - it('should should get back to mid price on resolution change', async () => { + it('should get back to mid price on resolution change', async () => { window.innerHeight = 11 * rowHeight; const result = render( { await waitFor(() => screen.getByTestId(`bid-vol-${params.midPrice}`)); const scrollElement = result.getByTestId('scroll'); expect(scrollElement.scrollTop).toBe(91 * rowHeight); - scrollElement.scrollTop = 0; + scrollElement.scrollTop = 1; fireEvent.scroll(scrollElement); - expect(result.getByTestId('scroll').scrollTop).toBe(0); + expect(result.getByTestId('scroll').scrollTop).toBe(1); const resolutionSelect = result.getByTestId( 'resolution' ) as HTMLSelectElement; @@ -181,6 +181,6 @@ describe('Orderbook', () => { onResolutionChange={onResolutionChange} /> ); - expect(result.getByTestId('scroll').scrollTop).toBe(5 * rowHeight); + expect(result.getByTestId('scroll').scrollTop).toBe(6 * rowHeight); }); }); diff --git a/libs/market-depth/src/lib/orderbook.tsx b/libs/market-depth/src/lib/orderbook.tsx index 85208a1b5..eca8786c7 100644 --- a/libs/market-depth/src/lib/orderbook.tsx +++ b/libs/market-depth/src/lib/orderbook.tsx @@ -1,15 +1,7 @@ import styles from './orderbook.module.scss'; import colors from 'tailwindcss/colors'; -import { - useEffect, - useLayoutEffect, - useRef, - useState, - useMemo, - useCallback, - Fragment, -} from 'react'; +import { useEffect, useRef, useState, useCallback, Fragment } from 'react'; import classNames from 'classnames'; import { @@ -21,7 +13,7 @@ import { } from '@vegaprotocol/react-helpers'; import * as Schema from '@vegaprotocol/types'; import { OrderbookRow } from './orderbook-row'; -import { createRow, getPriceLevel } from './orderbook-data'; +import { createRow } from './orderbook-data'; import { Checkbox, Icon, Splash } from '@vegaprotocol/ui-toolkit'; import type { OrderbookData, OrderbookRowData } from './orderbook-data'; @@ -36,7 +28,7 @@ interface OrderbookProps extends OrderbookData { const HorizontalLine = ({ top, testId }: { top: string; testId: string }) => (
@@ -97,7 +89,12 @@ const getRowsToRender = ( }; // 17px of row height plus 5px gap +export const gridGap = 5; export const rowHeight = 22; +// top padding to make space for header +const headerPadding = 30; +// bottom padding to make space for footer +const footerPadding = 25; // buffer size in rows const bufferSize = 30; // margin size in px, when reached scrollOffset will be updated @@ -112,30 +109,30 @@ const getBestStaticBidPriceLinePosition = ( rows: OrderbookRowData[] | null ) => { let bestStaticBidPriceLinePosition = ''; - if (maxPriceLevel !== '0' && minPriceLevel !== '0') { - if ( - bestStaticBidPrice && - BigInt(bestStaticBidPrice) < BigInt(maxPriceLevel) && - BigInt(bestStaticBidPrice) > BigInt(minPriceLevel) - ) { - if (fillGaps) { + if ( + rows?.length && + bestStaticBidPrice && + BigInt(bestStaticBidPrice) < BigInt(maxPriceLevel) && + BigInt(bestStaticBidPrice) > BigInt(minPriceLevel) + ) { + if (fillGaps) { + bestStaticBidPriceLinePosition = ( + ((BigInt(maxPriceLevel) - BigInt(bestStaticBidPrice)) / + BigInt(resolution)) * + BigInt(rowHeight) + + BigInt(headerPadding) - + BigInt(3) + ).toString(); + } else { + const index = rows?.findIndex( + (row) => BigInt(row.price) <= BigInt(bestStaticBidPrice) + ); + if (index !== undefined && index !== -1) { bestStaticBidPriceLinePosition = ( - ((BigInt(maxPriceLevel) - BigInt(bestStaticBidPrice)) / - BigInt(resolution) + - BigInt(1)) * - BigInt(rowHeight) + - BigInt(1) + index * rowHeight + + headerPadding - + 3 ).toString(); - } else { - const index = rows?.findIndex( - (row) => BigInt(row.price) <= BigInt(bestStaticBidPrice) - ); - if (index !== undefined && index !== -1) { - bestStaticBidPriceLinePosition = ( - (index + 1) * rowHeight + - 1 - ).toString(); - } } } } @@ -151,6 +148,7 @@ const getBestStaticOfferPriceLinePosition = ( ) => { let bestStaticOfferPriceLinePosition = ''; if ( + rows?.length && bestStaticOfferPrice && BigInt(bestStaticOfferPrice) <= BigInt(maxPriceLevel) && BigInt(bestStaticOfferPrice) > BigInt(minPriceLevel) @@ -159,9 +157,10 @@ const getBestStaticOfferPriceLinePosition = ( bestStaticOfferPriceLinePosition = ( ((BigInt(maxPriceLevel) - BigInt(bestStaticOfferPrice)) / BigInt(resolution) + - BigInt(2)) * + BigInt(1)) * BigInt(rowHeight) + - BigInt(1) + BigInt(headerPadding) - + BigInt(3) ).toString(); } else { const index = rows?.findIndex( @@ -169,8 +168,9 @@ const getBestStaticOfferPriceLinePosition = ( ); if (index !== undefined && index !== -1) { bestStaticOfferPriceLinePosition = ( - (index + 2) * rowHeight + - 1 + (index + 1) * rowHeight + + headerPadding - + 3 ).toString(); } } @@ -187,7 +187,7 @@ const OrderbookDebugInfo = ({ bestStaticOfferPrice, maxPriceLevel, minPriceLevel, - resolution, + midPrice, }: { decimalPlaces: number; numberOfRows: number; @@ -198,7 +198,7 @@ const OrderbookDebugInfo = ({ bestStaticOfferPrice?: string; maxPriceLevel: string; minPriceLevel: string; - resolution: number; + midPrice?: string; }) => (
(); + // by default mid price is rendered in center - view locked on mid price const [lockOnMidPrice, setLockOnMidPrice] = useState(true); const resolutionRef = useRef(resolution); const [viewportHeight, setViewportHeight] = useState(window.innerHeight); + // show price levels with no orders, can lead to enormous number of rows const [fillGaps, setFillGaps] = useState(!!initialFillGaps); - const numberOfRows = useMemo( - () => (fillGaps ? getNumberOfRows(rows, resolution) : rows?.length ?? 0), - [rows, resolution, fillGaps] - ); - const maxPriceLevel = rows?.[0]?.price ?? '0'; - const minPriceLevel = ( - fillGaps - ? BigInt(maxPriceLevel) - BigInt(Math.floor(numberOfRows * resolution)) - : BigInt(rows?.[rows.length - 1]?.price ?? '0') - ).toString(); const [debug, setDebug] = useState(false); + + const numberOfRows = fillGaps + ? getNumberOfRows(rows, resolution) + : rows?.length ?? 0; + const maxPriceLevel = rows?.[0]?.price ?? '0'; + const minPriceLevel = rows?.[rows.length - 1]?.price ?? '0'; + + let offset = Math.max(0, Math.round(scrollOffset / rowHeight)); + const prependingBufferSize = Math.min(bufferSize, offset); + offset -= prependingBufferSize; + const viewportSize = Math.round(viewportHeight / rowHeight); + const limit = Math.min( + prependingBufferSize + viewportSize + bufferSize, + numberOfRows - offset + ); + const data = fillGaps + ? getRowsToRender(rows, resolution, offset, limit) + : rows?.slice(offset, offset + limit) ?? []; + + const paddingTop = offset * rowHeight + headerPadding; + const paddingBottom = + (numberOfRows - offset - limit) * rowHeight + footerPadding; + const updateScrollOffset = useCallback( (scrollTop: number) => { if (Math.abs(scrollOffset - scrollTop) > marginSize) { @@ -318,23 +325,35 @@ export const Orderbook = ({ }, [scrollOffset] ); + const onScroll = useCallback( (event: React.UIEvent) => { - const { scrollTop } = event.currentTarget; + const { scrollTop, scrollHeight, clientHeight } = event.currentTarget; updateScrollOffset(scrollTop); if (scrollTop === scrollTopRef.current) { return; + } else if ((scrollTop - scrollTopRef.current) % rowHeight === 0) { + if (scrollElement.current) { + scrollElement.current.scrollTop = scrollTopRef.current; + } + return; + } + if (scrollTop === 0 || scrollHeight === clientHeight + scrollTop) { + priceInCenter.current = undefined; + } else { + // top offset in rows to row in the middle + const offsetTop = Math.floor( + (scrollTop + + Math.floor((viewportHeight - footerPadding - headerPadding) / 2)) / + rowHeight + ); + priceInCenter.current = fillGaps + ? ( + BigInt(maxPriceLevel) - + BigInt(offsetTop) * BigInt(resolution) + ).toString() + : rows?.[Math.min(offsetTop, rows.length - 1)].price.toString(); } - const offsetTop = Math.floor( - (scrollTop + Math.floor(viewportHeight / 2)) / rowHeight - ); - priceInCenter.current = fillGaps - ? ( - BigInt(resolution) + // extra row on very top - sticky header - BigInt(maxPriceLevel) - - BigInt(offsetTop) * BigInt(resolution) - ).toString() - : rows?.[Math.min(offsetTop, rows.length - 1)]?.price?.toString(); if (lockOnMidPrice) { setLockOnMidPrice(false); } @@ -361,24 +380,22 @@ export const Orderbook = ({ (Number( (BigInt(maxPriceLevel) - BigInt(price)) / BigInt(resolution) ) + - 1) * // add one row for sticky header - rowHeight + - rowHeight / 2 - - (viewportHeight % rowHeight); + 1) * + rowHeight; } else if (rows) { const index = rows.findIndex( (row) => BigInt(row.price) <= BigInt(price) ); if (index !== -1) { - scrollTop = - index * rowHeight + rowHeight / 2 - (viewportHeight % rowHeight); - if ( - price === rows[index].price || - index === 0 || - BigInt(rows[index].price) - BigInt(price) < - BigInt(price) - BigInt(rows[index - 1].price) - ) { - scrollTop += rowHeight; + scrollTop = rowHeight * (index + 1); + if (index !== 0) { + const diffToCurrentRow = + BigInt(price) - BigInt(rows[index].price); + const diffToPreviousRow = + BigInt(rows[index - 1].price) - BigInt(price); + if (diffToPreviousRow < diffToCurrentRow) { + scrollTop -= rowHeight; + } } } } @@ -389,7 +406,13 @@ export const Orderbook = ({ (scrollTopRef.current % rowHeight) - (scrollTop % rowHeight); const priceCenterScrollOffset = Math.max( 0, - Math.min(scrollTop, numberOfRows * rowHeight - viewportHeight) + Math.min( + scrollTop, + numberOfRows * rowHeight + + headerPadding + + footerPadding + + -viewportHeight + ) ); if (scrollTopRef.current !== priceCenterScrollOffset) { updateScrollOffset(priceCenterScrollOffset); @@ -410,72 +433,31 @@ export const Orderbook = ({ ); const scrollToMidPrice = useCallback(() => { - if (!bestStaticOfferPrice || !bestStaticBidPrice) { + if (!midPrice) { return; } priceInCenter.current = undefined; - let midPrice = getPriceLevel( - BigInt(bestStaticOfferPrice) + - (BigInt(bestStaticBidPrice) - BigInt(bestStaticOfferPrice)) / BigInt(2), - resolution - ); - if (BigInt(midPrice) > BigInt(maxPriceLevel)) { - midPrice = maxPriceLevel; - } else { - if (BigInt(midPrice) < BigInt(minPriceLevel)) { - midPrice = minPriceLevel.toString(); - } - } scrollToPrice(midPrice); setLockOnMidPrice(true); - }, [ - bestStaticOfferPrice, - bestStaticBidPrice, - scrollToPrice, - resolution, - maxPriceLevel, - minPriceLevel, - ]); + }, [midPrice, scrollToPrice]); // adjust scroll position to keep selected price in center - useLayoutEffect(() => { + useEffect(() => { + if (priceInCenter.current) { + scrollToPrice(priceInCenter.current); + } else if (lockOnMidPrice && midPrice) { + scrollToPrice(midPrice); + } + }, [midPrice, scrollToPrice, lockOnMidPrice]); + + useEffect(() => { if (resolutionRef.current !== resolution) { priceInCenter.current = undefined; resolutionRef.current = resolution; + setLockOnMidPrice(true); } - if (priceInCenter.current) { - scrollToPrice(priceInCenter.current); - } else { - scrollToMidPrice(); - } - }, [scrollToMidPrice, scrollToPrice, resolution]); + }, [resolution]); - // handles window resize - useEffect(() => { - function handleResize() { - if (rootElement.current) { - setViewportHeight( - rootElement.current.clientHeight || window.innerHeight - ); - } - } - window.addEventListener('resize', handleResize); - handleResize(); - return () => window.removeEventListener('resize', handleResize); - }, []); - // sets the correct width of header and footer - useLayoutEffect(() => { - if ( - !gridElement.current || - !headerElement.current || - !footerElement.current - ) { - return; - } - const gridWidth = gridElement.current.clientWidth; - headerElement.current.style.width = `${gridWidth}px`; - footerElement.current.style.width = `${gridWidth}px`; - }, [headerElement, footerElement, gridElement]); // handles resizing of the Allotment.Pane (x-axis) // adjusts the header and footer width const gridResizeHandler: ResizeObserverCallback = useCallback( @@ -509,20 +491,6 @@ export const Orderbook = ({ useResizeObserver(gridElement.current, gridResizeHandler); useResizeObserver(rootElement.current, rootElementResizeHandler); - let offset = Math.max(0, Math.round(scrollOffset / rowHeight)); - const prependingBufferSize = Math.min(bufferSize, offset); - offset -= prependingBufferSize; - const viewportSize = Math.round(viewportHeight / rowHeight); - const limit = Math.min( - prependingBufferSize + viewportSize + bufferSize, - numberOfRows - offset - ); - const data = fillGaps - ? getRowsToRender(rows, resolution, offset, limit) - : rows?.slice(offset, offset + limit) ?? []; - - const paddingTop = offset * rowHeight; - const paddingBottom = (numberOfRows - offset - limit) * rowHeight; const tableBody = data && data.length !== 0 ? (