Skip to content

Commit

Permalink
add hideDelay prop to Tooltip (#391)
Browse files Browse the repository at this point in the history
* downgrade svelte to 5.19.4

* add hideDelay prop

* create an example to demonstrate hide delay

* add section to tooltip docs

* pnpm changeset

* Simplify tooltip hover logic

---------

Co-authored-by: Sean Lynch <techniq35@gmail.com>
  • Loading branch information
ken-zlai and techniq authored Feb 10, 2025
1 parent 3b80ed4 commit 956372a
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 51 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilled-files-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'layerchart': patch
---

Added hideDelay prop to Tooltip for configurable hide behavior
2 changes: 1 addition & 1 deletion packages/layerchart/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"rehype-slug": "^6.0.0",
"shapefile": "^0.6.6",
"solar-calculator": "^0.3.0",
"svelte": "^5.19.9",
"svelte": "5.19.4",
"svelte-check": "^4.1.4",
"svelte-json-tree": "^2.2.0",
"svelte-ux": "^0.90.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
/** Similar to d3-selection's raise, re-insert the e.target as the last child of its parent, so to be the top-most element */
export let raiseTarget = false;
/** Lock tooltip (keep open, do not update on mouse movement). Allows for kicking on tooltip */
/** Lock tooltip (keep open, do not update on mouse movement). Allows for clicking on tooltip */
export let locked = false;
/** quadtree search radius
Expand All @@ -124,6 +124,10 @@
});
setTooltipContext(tooltip);
/** Delay in ms before hiding tooltip */
export let hideDelay = 0;
let isHoveringTooltip = false;
let hideTimeoutId: NodeJS.Timeout;
$: bisectX = bisector((d: any) => {
Expand Down Expand Up @@ -175,7 +179,9 @@
function showTooltip(e: PointerEvent, tooltipData?: any) {
// Cancel hiding tooltip if from previous event loop
clearTimeout(hideTimeoutId);
if (hideTimeoutId) {
clearTimeout(hideTimeoutId);
}
if (locked) {
// Ignore (keep current position / data)
Expand Down Expand Up @@ -294,9 +300,12 @@
}
// Wait an event loop tick in case `showTooltip` is called immediately on another element, to allow tweeneing (ex. moving between bands/bars)
// Additional hideDelay can be configured to extend this delay further
hideTimeoutId = setTimeout(() => {
$tooltip = { ...$tooltip, data: null };
});
if (!isHoveringTooltip) {
$tooltip = { ...$tooltip, data: null };
}
}, hideDelay);
}
let quadtree: Quadtree<[number, number]>;
Expand Down Expand Up @@ -401,9 +410,19 @@
'TooltipContext absolute touch-none',
debug && triggerPointerEvents && 'bg-danger/10 outline outline-danger'
)}
on:pointerenter={triggerPointerEvents ? showTooltip : undefined}
on:pointerenter={(e) => {
isHoveringTooltip = true;
if (triggerPointerEvents) {
showTooltip(e);
}
}}
on:pointermove={triggerPointerEvents ? showTooltip : undefined}
on:pointerleave={triggerPointerEvents ? hideTooltip : undefined}
on:pointerleave={(e) => {
isHoveringTooltip = false;
if (triggerPointerEvents) {
hideTooltip();
}
}}
on:click={(e) => {
if (triggerPointerEvents) {
onclick(e, { data: $tooltip?.data });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,43 @@
</div>
</Preview>

<h2>Fixed tooltip below chart with hide delay</h2>

<Preview data={dateSeriesData}>
<div class="h-[300px] p-4 border rounded">
<AreaChart
data={multiSeriesData}
x="date"
series={[
{ key: 'apples', color: 'hsl(var(--color-danger))' },
{ key: 'bananas', color: 'hsl(var(--color-success))' },
{ key: 'oranges', color: 'hsl(var(--color-warning))' },
]}
{renderContext}
{debug}
tooltip={{ hideDelay: 1000 }}
>
<svelte:fragment slot="tooltip" let:x let:y let:series let:height>
<Tooltip.Root x="data" y={height + 24} pointerEvents let:data>
<Tooltip.Header>
{format(x(data), PeriodType.Day)}
</Tooltip.Header>

<Tooltip.List>
{#each series as s}
{@const valueAccessor = accessor(s.value ?? s.key)}
{@const value = valueAccessor(data)}
<Tooltip.Item label={s.key} color={s.color}>
{format(value)}
</Tooltip.Item>
{/each}
</Tooltip.List>
</Tooltip.Root>
</svelte:fragment>
</AreaChart>
</div>
</Preview>

<h2>Brushing</h2>

<Preview data={dateSeriesData}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export async function load() {
],
'Multiple instances',
'Maintain within chart container, window/viewport, or overflow outside',
'Configurable hide delay to prevent accidental hiding when moving to tooltip',
],
related: ['components/TooltipContext', 'components/Highlight'],
},
Expand Down
Loading

0 comments on commit 956372a

Please sign in to comment.