mirror of
https://github.com/jlfwong/speedscope.git
synced 2024-11-22 12:53:23 +03:00
Improve HoverTip placement logic (#395)
This changes the HoverTip placement logic to use measurements from the actual DOM node rather than basing everything on the maximum sizes. This avoids some counter-intuitive behaviour, most importantly situations where the label would overflow off the left side of the screen for no obvious reason. Fixes #394 Fixes #256
This commit is contained in:
parent
48d692c2a3
commit
7ae545a6c3
@ -3,6 +3,7 @@ import {Sizes, FontSize, FontFamily, ZIndex} from './style'
|
||||
import {css, StyleSheet} from 'aphrodite'
|
||||
import {ComponentChildren, h} from 'preact'
|
||||
import {useTheme, withTheme} from './themes/theme'
|
||||
import { useCallback } from 'preact/hooks'
|
||||
|
||||
interface HovertipProps {
|
||||
containerSize: Vec2
|
||||
@ -14,26 +15,50 @@ export function Hovertip(props: HovertipProps) {
|
||||
const style = getStyle(useTheme())
|
||||
|
||||
const {containerSize, offset} = props
|
||||
const width = containerSize.x
|
||||
const height = containerSize.y
|
||||
|
||||
const positionStyle: {[key: string]: number} = {}
|
||||
const containerWidth = containerSize.x
|
||||
const containerHeight = containerSize.y
|
||||
|
||||
const OFFSET_FROM_MOUSE = 7
|
||||
if (offset.x + OFFSET_FROM_MOUSE + Sizes.TOOLTIP_WIDTH_MAX < width) {
|
||||
positionStyle.left = offset.x + OFFSET_FROM_MOUSE
|
||||
} else {
|
||||
positionStyle.right = width - offset.x + 1
|
||||
}
|
||||
|
||||
if (offset.y + OFFSET_FROM_MOUSE + Sizes.TOOLTIP_HEIGHT_MAX < height) {
|
||||
positionStyle.top = offset.y + OFFSET_FROM_MOUSE
|
||||
} else {
|
||||
positionStyle.bottom = height - offset.y + 1
|
||||
}
|
||||
const updateLocation = useCallback((el: HTMLDivElement | null) => {
|
||||
if (!el) return
|
||||
|
||||
const clientRect = el.getBoundingClientRect()
|
||||
|
||||
// Place the hovertip to the right of the cursor.
|
||||
let leftEdgeX = offset.x + OFFSET_FROM_MOUSE
|
||||
|
||||
// If this would cause it to overflow the container, align the right
|
||||
// edge of the hovertip with the right edge of the container.
|
||||
if (leftEdgeX + clientRect.width > containerWidth - 1) {
|
||||
leftEdgeX = containerWidth - clientRect.width - 1
|
||||
|
||||
// If aligning the right edge overflows the container, align the left edge
|
||||
// of the hovertip with the left edge of the container.
|
||||
if (leftEdgeX < 1) { leftEdgeX = 1 }
|
||||
}
|
||||
el.style.left = `${leftEdgeX}px`
|
||||
|
||||
// Place the tooltip below the cursor
|
||||
let topEdgeY = offset.y + OFFSET_FROM_MOUSE
|
||||
|
||||
// If this would cause it to overflow the container, place the hovertip
|
||||
// above the cursor instead. This intentionally differs from the horizontal
|
||||
// axis logic to avoid the cursor being in the middle of a hovertip when
|
||||
// possible.
|
||||
if (topEdgeY + clientRect.height > containerHeight - 1) {
|
||||
topEdgeY = offset.y - clientRect.height - 1
|
||||
|
||||
// If placing the hovertip above the cursor overflows the container, align
|
||||
// the top edge of the hovertip with the top edge of the container.
|
||||
if (topEdgeY < 1) { topEdgeY = 1 }
|
||||
}
|
||||
el.style.top = `${topEdgeY}px`
|
||||
|
||||
}, [containerWidth, containerHeight, offset.x, offset.y])
|
||||
|
||||
return (
|
||||
<div className={css(style.hoverTip)} style={positionStyle}>
|
||||
<div className={css(style.hoverTip)} ref={updateLocation}>
|
||||
<div className={css(style.hoverTipRow)}>{props.children}</div>
|
||||
</div>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user