Consolidate draw methods, improve scrollListener

This commit is contained in:
jaredvu 2023-11-25 14:20:56 -08:00
parent e3462b6514
commit a2dfda3481
No known key found for this signature in database
GPG Key ID: B9FE2F3F0A5D523C
4 changed files with 176 additions and 122 deletions

View File

@ -29,6 +29,134 @@ export const useDrawOrderbookHistograms = ({
const canvasRef = useRef<HTMLCanvasElement>(null);
const canvas = canvasRef.current;
/**
* to === 'right' to === 'left'
* |===================| |===================|
* bar: a b c d
* a = 0
* b = depthBarWidth
* c = canvasWidth - depthBarWidth
* d = canvasWidth
*
*/
const getXYValues = ({
barWidth,
canvasWidth,
gradientMultiplier,
}: {
barWidth: number;
canvasWidth: number;
gradientMultiplier: number;
}) => {
const gradient = {
x1: to === 'right' ? barWidth : canvasWidth - barWidth,
x2:
to === 'right'
? 0 - (canvasWidth * gradientMultiplier - canvasWidth)
: canvasWidth * gradientMultiplier,
};
const bar = {
x1: to === 'right' ? 0 : canvasWidth - barWidth,
x2: to === 'right' ? Math.min(barWidth, canvasWidth - 2) : canvasWidth - 2,
};
return {
bar,
gradient,
};
};
const drawBars = ({
value,
canvasWidth,
ctx,
gradientMultiplier,
histogramAccentColor,
idx,
to,
}: {
value: Nullable<number>;
canvasWidth: number;
ctx: CanvasRenderingContext2D;
gradientMultiplier: number;
histogramAccentColor: string;
idx: number;
to: 'left' | 'right';
}) => {
const histogramBarWidth = ctx.canvas.width - 2;
const barWidth = value ? (value / histogramRange) * histogramBarWidth : 0;
const { gradient, bar } = getXYValues({ barWidth, canvasWidth, gradientMultiplier });
const linearGradient = ctx.createLinearGradient(gradient.x1, 10, gradient.x2, 10);
linearGradient.addColorStop(0, histogramAccentColor);
linearGradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
ctx.fillStyle = linearGradient;
ctx.beginPath();
ctx.roundRect
? ctx.roundRect?.(
bar.x1,
idx * 20 + 1,
bar.x2,
18,
to === 'left' ? [2, 0, 0, 2] : [0, 2, 2, 0]
)
: ctx.rect(bar.x1, idx * 20 + 1, bar.x2, 18);
ctx.fill();
};
const drawText = ({
ctx,
idx,
size,
price,
mine,
x,
}: {
ctx: CanvasRenderingContext2D;
idx: number;
size?: Nullable<number>;
price?: Nullable<number>;
mine?: Nullable<number>;
x: number;
}) => {
ctx.font = `12.5px Satoshi`;
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
ctx.imageSmoothingQuality = 'high';
// Size text
if (size) {
ctx.fillStyle = 'white';
ctx.fillText(
MustBigNumber(size).toFixed(stepSizeDecimals ?? TOKEN_DECIMALS),
x - 8,
idx * 20 + 10
);
}
// Price text
if (price) {
ctx.fillStyle = 'white';
ctx.fillText(
MustBigNumber(price).toFixed(tickSizeDecimals ?? SMALL_USD_DECIMALS),
x * 2 - 8,
idx * 20 + 10
);
}
// Mine text
if (mine) {
ctx.fillStyle = 'white';
ctx.fillText(
MustBigNumber(mine).toFixed(stepSizeDecimals ?? TOKEN_DECIMALS),
x * 3 - 8,
idx * 20 + 10
);
}
};
useEffect(() => {
const ctx = canvas?.getContext('2d');
@ -73,119 +201,42 @@ export const useDrawOrderbookHistograms = ({
histogramAlpha = 0.75;
}
const histogramBarWidth = ctx.canvas.width - 2;
const histogramAccentColor =
side === 'bid'
? `hsla(159, 67%, 39%, ${histogramAlpha})`
: `hsla(360, 73%, 61%, ${histogramAlpha})`;
/**
* to === 'right' to === 'left'
* |===================| |===================|
* bar: a b c d
* a = 0
* b = depthBarWidth
* c = canvasWidth - depthBarWidth
* d = canvasWidth
*
*/
const getXYValues = ({
barWidth,
gradientMultiplier,
}: {
barWidth: number;
gradientMultiplier: number;
}) => {
const gradient = {
x1: to === 'right' ? barWidth : canvasWidth - barWidth,
x2:
to === 'right'
? 0 - (canvasWidth * gradientMultiplier - canvasWidth)
: canvasWidth * gradientMultiplier,
};
const bar = {
x1: to === 'right' ? 0 : canvasWidth - barWidth,
x2: to === 'right' ? Math.min(barWidth, canvasWidth - 2) : canvasWidth - 2,
};
return {
bar,
gradient,
};
};
const drawBars = ({
barWidth,
gradientMultiplier,
}: {
barWidth: number;
gradientMultiplier: number;
}) => {
const { gradient, bar } = getXYValues({ barWidth, gradientMultiplier });
const linearGradient = ctx.createLinearGradient(gradient.x1, 10, gradient.x2, 10);
linearGradient.addColorStop(0, histogramAccentColor);
linearGradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
ctx.fillStyle = linearGradient;
ctx.beginPath();
ctx.roundRect
? ctx.roundRect?.(
bar.x1,
idx * 20 + 1,
bar.x2,
18,
to === 'left' ? [2, 0, 0, 2] : [0, 2, 2, 0]
)
: ctx.rect(bar.x1, idx * 20 + 1, bar.x2, 18);
ctx.fill();
};
// Depth Bar
const depthBarWidth = depth ? (depth / histogramRange) * histogramBarWidth : 0;
drawBars({ barWidth: depthBarWidth, gradientMultiplier: 2 });
drawBars({
value: depth,
canvasWidth,
ctx,
gradientMultiplier: 2,
histogramAccentColor,
idx,
to,
});
// Size Bar
const sizeBarWidth = size ? (size / histogramRange) * histogramBarWidth : 0;
drawBars({ barWidth: sizeBarWidth, gradientMultiplier: 5 });
drawBars({
value: size,
canvasWidth,
ctx,
gradientMultiplier: 5,
histogramAccentColor,
idx,
to,
});
const drawText = () => {
ctx.font = `12.5px Satoshi`;
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
ctx.imageSmoothingQuality = 'high';
// Size text
if (size) {
ctx.fillStyle = 'white';
ctx.fillText(
MustBigNumber(size).toFixed(stepSizeDecimals ?? TOKEN_DECIMALS),
columnX - 8,
idx * 20 + 10
);
}
// Price text
if (price) {
ctx.fillStyle = 'white';
ctx.fillText(
MustBigNumber(price).toFixed(tickSizeDecimals ?? SMALL_USD_DECIMALS),
columnX * 2 - 8,
idx * 20 + 10
);
}
// Mine text
if (mine) {
ctx.fillStyle = 'white';
ctx.fillText(
MustBigNumber(mine).toFixed(stepSizeDecimals ?? TOKEN_DECIMALS),
columnX * 3 - 8,
idx * 20 + 10
);
}
};
drawText();
// Size, Price, Mine
drawText({
ctx,
idx,
size,
price,
mine,
x: columnX,
});
});
}, [data, histogramRange, hoveredRow, selectedTheme, stepSizeDecimals, tickSizeDecimals, to]);

View File

@ -1,4 +1,4 @@
import { type RefObject, useEffect, useState } from 'react';
import { type RefObject, useEffect, useState, Dispatch } from 'react';
export const useSpreadRowScrollListener = ({
orderbookRef,
@ -11,18 +11,17 @@ export const useSpreadRowScrollListener = ({
useEffect(() => {
const onScroll = () => {
if (spreadRowRef.current) {
const { top } = spreadRowRef.current.getBoundingClientRect();
const { scrollHeight, scrollTop } = orderbookRef.current || {};
if (spreadRowRef.current && orderbookRef.current) {
const { clientHeight } = orderbookRef.current;
const parent = orderbookRef.current.getBoundingClientRect();
const spread = spreadRowRef.current.getBoundingClientRect();
const spreadTop = spread.top - parent.top;
const spreadBottom = spread.bottom - parent.top;
if (scrollHeight !== undefined && scrollTop !== undefined) {
if (top > scrollHeight / 2) {
setDisplaySide('bottom');
} else if (scrollTop > scrollHeight / 2) {
setDisplaySide('top');
} else {
setDisplaySide(undefined);
}
if (spreadBottom > clientHeight) {
setDisplaySide('bottom');
} else if (spreadTop < 0) {
setDisplaySide('top');
} else {
setDisplaySide(undefined);
}
@ -34,7 +33,7 @@ export const useSpreadRowScrollListener = ({
return () => {
orderbookRef.current?.removeEventListener('scroll', onScroll, false);
};
}, [orderbookRef.current]);
}, [orderbookRef.current, spreadRowRef.current]);
return { displaySide };
return displaySide;
};

View File

@ -92,7 +92,8 @@ export const Orderbook = ({
* Display top or bottom spreadRow when center spreadRow is off screen
*/
const spreadRowRef = useRef<HTMLDivElement>(null);
const { displaySide } = useSpreadRowScrollListener({
const displaySide = useSpreadRowScrollListener({
orderbookRef,
spreadRowRef,
});
@ -143,7 +144,7 @@ export const Orderbook = ({
<span>{showMineColumn && stringGetter({ key: STRING_KEYS.MINE })}</span>
</$Header>
{displaySide === 'top' && (
<SpreadRow
<$SpreadRow
side="top"
spread={spread}
spreadPercent={spreadPercent}
@ -211,7 +212,7 @@ export const Orderbook = ({
)}
</$OrderbookWrapper>
{displaySide === 'bottom' && (
<SpreadRow
<$SpreadRow
side="bottom"
spread={spread}
spreadPercent={spreadPercent}
@ -277,3 +278,7 @@ const $HistogramCanvas = styled(Canvas)`
const $Row = styled(Row)<{ onClick?: () => void }>`
${({ onClick }) => (onClick ? 'cursor: pointer;' : 'cursor: default;')}
`;
const $SpreadRow = styled(SpreadRow)`
position: absolute;
`;

View File

@ -17,7 +17,6 @@ export const Row = styled.div`
min-height: ${ROW_HEIGHT}px;
font: var(--font-mini-book);
cursor: pointer;
position: relative;
padding-right: 0.5rem;