From 9542a5dc96e00a00ccf75de24708a716f8e4193d Mon Sep 17 00:00:00 2001 From: Speros Kokenes Date: Thu, 14 Nov 2024 14:36:30 -0500 Subject: [PATCH] feat: tooltips reposition to fit --- .../src/component/chart/chart.tsx | 6 +- .../src/component/tooltip/tooltip.tsx | 55 ++++++++++++------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/packages/malloy-render/src/component/chart/chart.tsx b/packages/malloy-render/src/component/chart/chart.tsx index 73bcdbca8..ef00e0663 100644 --- a/packages/malloy-render/src/component/chart/chart.tsx +++ b/packages/malloy-render/src/component/chart/chart.tsx @@ -9,7 +9,7 @@ import {Explore, ExploreField, QueryData} from '@malloydata/malloy'; import {VegaChart, ViewInterface} from '../vega/vega-chart'; import {ChartTooltipEntry, RenderResultMetadata} from '../types'; import {Tooltip} from '../tooltip/tooltip'; -import {createEffect, createSignal, lazy, Show} from 'solid-js'; +import {createEffect, createSignal, createMemo, lazy, Show} from 'solid-js'; import {DefaultChartTooltip} from './default-chart-tooltip'; import {EventListenerHandler, Runtime, View} from 'vega'; import {useResultStore, VegaBrushOutput} from '../result-store/result-store'; @@ -183,6 +183,8 @@ export function Chart(props: ChartProps) { setShowDebugModal(true); }; + const showTooltip = createMemo(() => Boolean(tooltipData())); + return (
- + diff --git a/packages/malloy-render/src/component/tooltip/tooltip.tsx b/packages/malloy-render/src/component/tooltip/tooltip.tsx index 64854af6c..f9f453db2 100644 --- a/packages/malloy-render/src/component/tooltip/tooltip.tsx +++ b/packages/malloy-render/src/component/tooltip/tooltip.tsx @@ -3,25 +3,16 @@ import { createSignal, JSXElement, onCleanup, - onMount, Show, } from 'solid-js'; import tooltipCss from './tooltip.css?raw'; import {useConfig} from '../render'; -function isElementOverflowing(element) { - const rect = element.getBoundingClientRect(); - console.log({rect, globalThis}); - return ( - rect.top < 0 || - rect.left < 0 || - rect.bottom > globalThis.innerHeight || - rect.right > globalThis.innerWidth - ); -} - export function Tooltip(props: {show: boolean; children: JSXElement}) { - const [pos, setPos] = createSignal([0, 0]); + const [pos, setPos] = createSignal<[number, number]>([0, 0]); + const [xOffset, setXOffset] = createSignal(0); + const [yOffset, setYOffset] = createSignal(0); + const handler = evt => { if (props.show) { setPos([evt.clientX, evt.clientY]); @@ -39,21 +30,43 @@ export function Tooltip(props: {show: boolean; children: JSXElement}) { let tip; createEffect(() => { - if (props.show) { - console.log(tip, isElementOverflowing(tip)); + if (pos() && tip) { + let frame: number | null = null; + frame = requestAnimationFrame(() => { + if (frame) cancelAnimationFrame(frame); + const threshold = 16; + const rightBorder = pos()[0] + tip.clientWidth + threshold; + const leftBorder = pos()[0]; + const topBorder = pos()[1]; + const bottomBorder = pos()[1] + tip.clientHeight + threshold; + + const overflowX = Math.min(0, globalThis.innerWidth - rightBorder); + const overflowY = Math.min(0, globalThis.innerHeight - bottomBorder); + + // Don't allow overflow past left edge when re-positioning tooltip + if (leftBorder - overflowX < 0) setXOffset(0); + else setXOffset(overflowX); + + const isOverflowingY = overflowY < 0; + // Check new position if moving to top + const topPosition = topBorder - tip.clientHeight - threshold; + // Don't allow overflow past top edge when re-positioning tooltip + if (isOverflowingY && topPosition >= threshold) + setYOffset(-tip.clientHeight - threshold); + else setYOffset(0); + }); } }); return (
-
- {props.children} -
+
{props.children}
);