From 56319b1501dc23f813b93b996d025ceae49ca5bd Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:29:40 -0800 Subject: [PATCH] [v10.4.x] VizTooltip: Fix positioning on mobile (#96059) VizTooltip: Fix positioning on mobile --- .../uPlot/plugins/TooltipPlugin2.tsx | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx index e9590c434b2..7a18d549315 100644 --- a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx +++ b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx @@ -288,8 +288,10 @@ export const TooltipPlugin2 = ({ } // only pinnable tooltip is visible *and* is within proximity to series/point else if (_isHovering && closestSeriesIdx != null && !_isPinned) { - _isPinned = true; - scheduleRender(true); + setTimeout(() => { + _isPinned = true; + scheduleRender(true); + }, 0); } } }); @@ -513,8 +515,52 @@ export const TooltipPlugin2 = ({ if (domRef.current != null) { size.observer.observe(domRef.current); + + // since the above observer is attached after container is in DOM, we need to manually update sizeRef + // and re-trigger a cursor move to do initial positioning math + const { width, height } = domRef.current.getBoundingClientRect(); + size.width = width; + size.height = height; + + let event = plot!.cursor.event; + + // if not viaSync, re-dispatch real event + if (event != null) { + // we expect to re-dispatch mousemove, but on mobile we'll get mouseup or click + const isMobile = event.type !== 'mousemove'; + + if (isMobile) { + event = new MouseEvent('mousemove', { + view: window, + bubbles: true, + cancelable: true, + clientX: event.clientX, + clientY: event.clientY, + screenX: event.screenX, + screenY: event.screenY, + }); + } + + // this works around the fact that uPlot does not unset cursor.event (for perf reasons) + // so if the last real mouse event was mouseleave and you manually trigger u.setCursor() + // it would end up re-dispatching mouseleave + const isStaleEvent = isMobile ? false : performance.now() - event.timeStamp > 16; + + !isStaleEvent && plot!.over.dispatchEvent(event); + } else { + plot!.setCursor( + { + left: plot!.cursor.left!, + top: plot!.cursor.top!, + }, + true + ); + } + } else { + size.width = 0; + size.height = 0; } - }, [domRef.current]); + }, [isHovering]); if (plot && isHovering) { return createPortal(