mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
* move charts to toolkit * refactor imports * fix tests * change the behavior of the color mode hook and add the noWatermark prop * fix gas tracker test and fix toolkit build
102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
import * as d3 from 'd3';
|
|
import { clamp } from 'es-toolkit';
|
|
import React from 'react';
|
|
|
|
import { POINT_SIZE } from './utils';
|
|
|
|
interface Props {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
const ChartTooltipContent = ({ children }: Props) => {
|
|
return <g className="ChartTooltip__content">{ children }</g>;
|
|
};
|
|
|
|
export default React.memo(ChartTooltipContent);
|
|
|
|
interface UseRenderContentParams {
|
|
chart: {
|
|
width?: number;
|
|
height?: number;
|
|
};
|
|
transitionDuration: number | null;
|
|
}
|
|
|
|
export function useRenderContent(ref: React.RefObject<SVGGElement | null>, { chart, transitionDuration }: UseRenderContentParams) {
|
|
return React.useCallback((x: number, y: number) => {
|
|
const tooltipContent = d3.select(ref.current).select('.ChartTooltip__content');
|
|
|
|
const transformAttributeFn: d3.ValueFn<d3.BaseType, unknown, string> = (_, i, nodes) => {
|
|
const node = nodes[i] as SVGGElement | null;
|
|
const { width: nodeWidth, height: nodeHeight } = node?.getBoundingClientRect() || { width: 0, height: 0 };
|
|
const [ translateX, translateY ] = calculatePosition({
|
|
canvasWidth: chart.width || 0,
|
|
canvasHeight: chart.height || 0,
|
|
nodeWidth,
|
|
nodeHeight,
|
|
pointX: x,
|
|
pointY: y,
|
|
offset: POINT_SIZE,
|
|
});
|
|
return `translate(${ translateX }, ${ translateY })`;
|
|
};
|
|
|
|
if (transitionDuration) {
|
|
tooltipContent
|
|
.transition()
|
|
.duration(transitionDuration)
|
|
.ease(d3.easeLinear)
|
|
.attr('transform', transformAttributeFn);
|
|
} else {
|
|
tooltipContent
|
|
.attr('transform', transformAttributeFn);
|
|
}
|
|
|
|
}, [ chart.height, chart.width, ref, transitionDuration ]);
|
|
}
|
|
|
|
interface CalculatePositionParams {
|
|
pointX: number;
|
|
pointY: number;
|
|
offset: number;
|
|
nodeWidth: number;
|
|
nodeHeight: number;
|
|
canvasWidth: number;
|
|
canvasHeight: number;
|
|
}
|
|
|
|
function calculatePosition({ pointX, pointY, canvasWidth, canvasHeight, nodeWidth, nodeHeight, offset }: CalculatePositionParams): [ number, number ] {
|
|
// right
|
|
if (pointX + offset + nodeWidth <= canvasWidth) {
|
|
const x = pointX + offset;
|
|
const y = clamp(pointY - nodeHeight / 2, 0, canvasHeight - nodeHeight);
|
|
return [ x, y ];
|
|
}
|
|
|
|
// left
|
|
if (nodeWidth + offset <= pointX) {
|
|
const x = pointX - offset - nodeWidth;
|
|
const y = clamp(pointY - nodeHeight / 2, 0, canvasHeight - nodeHeight);
|
|
return [ x, y ];
|
|
}
|
|
|
|
// top
|
|
if (nodeHeight + offset <= pointY) {
|
|
const x = clamp(pointX - nodeWidth / 2, 0, canvasWidth - nodeWidth);
|
|
const y = pointY - offset - nodeHeight;
|
|
return [ x, y ];
|
|
}
|
|
|
|
// bottom
|
|
if (pointY + offset + nodeHeight <= canvasHeight) {
|
|
const x = clamp(pointX - nodeWidth / 2, 0, canvasWidth - nodeWidth);
|
|
const y = pointY + offset;
|
|
return [ x, y ];
|
|
}
|
|
|
|
const x = clamp(pointX / 2, 0, canvasWidth - nodeWidth);
|
|
const y = clamp(pointY / 2, 0, canvasHeight - nodeHeight);
|
|
|
|
return [ x, y ];
|
|
}
|