Skip to content

Commit ae8d726

Browse files
committed
Add generic graph component and use it for main graph
1 parent dd8f2d6 commit ae8d726

9 files changed

Lines changed: 1786 additions & 26 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React, { ReactNode, useLayoutEffect, useRef, useState } from 'react'
2+
3+
export const GraphTooltipWrapper = ({
4+
x,
5+
y,
6+
maxX,
7+
minWidth,
8+
bucketIndex,
9+
totalBuckets,
10+
children,
11+
className,
12+
onClick
13+
}: {
14+
x: number
15+
y: number
16+
maxX: number
17+
minWidth: number
18+
bucketIndex: number
19+
totalBuckets: number
20+
children: ReactNode
21+
className?: string
22+
onClick?: () => void
23+
}) => {
24+
const ref = useRef<HTMLDivElement>(null)
25+
// distance from cursor to tooltip edge
26+
const offsetFromCursor = 4
27+
// flip the tooltip to left of cursor if it would overflow on the right
28+
// and keep it flipped to the left for all subsequent buckets
29+
// even if they'd fit on the right (prevents excessive flips)
30+
const [firstFlippedToLeftOn, setFirstFlippedToLeftOn] = useState<
31+
number | null
32+
>(null)
33+
const [measuredWidth, setMeasuredWidth] = useState(minWidth)
34+
const position =
35+
firstFlippedToLeftOn !== null && bucketIndex >= firstFlippedToLeftOn
36+
? 'leftOfCursor'
37+
: 'rightOfCursor'
38+
const rawLeft =
39+
position === 'leftOfCursor'
40+
? x - offsetFromCursor - measuredWidth
41+
: x + offsetFromCursor
42+
// prevent tooltip from oveflowing on the left when flipped to left of cursor on smaller screens
43+
const tooltipLeft = Math.max(0, Math.min(rawLeft, maxX - measuredWidth))
44+
45+
useLayoutEffect(() => {
46+
setFirstFlippedToLeftOn(null)
47+
}, [totalBuckets])
48+
49+
useLayoutEffect(() => {
50+
if (!ref.current) {
51+
return
52+
}
53+
const w = ref.current.offsetWidth
54+
setMeasuredWidth(w)
55+
const wouldOverflow = x + offsetFromCursor + w > maxX
56+
setFirstFlippedToLeftOn((prev) => {
57+
if (wouldOverflow) {
58+
return prev === null ? bucketIndex : Math.min(prev, bucketIndex)
59+
}
60+
if (prev !== null && bucketIndex < prev) {
61+
return null
62+
}
63+
return prev
64+
})
65+
}, [x, maxX, bucketIndex])
66+
67+
return (
68+
<div
69+
ref={ref}
70+
className={className}
71+
onClick={onClick}
72+
style={{
73+
minWidth,
74+
left: tooltipLeft,
75+
top: y,
76+
transform: `translateY(-100%) translateY(-${offsetFromCursor}px)`
77+
}}
78+
>
79+
{children}
80+
</div>
81+
)
82+
}

0 commit comments

Comments
 (0)