From 5f249c257102453fcaa3643709e16192f606800b Mon Sep 17 00:00:00 2001 From: Amp Date: Wed, 11 Nov 2026 09:22:03 +0000 Subject: [PATCH] fix(charts): scrolling over a chart scrolls the page Plain mouse-wheel and trackpad scrolling over any chart no longer zooms it; the page scrolls instead. Ctrl+wheel (and trackpad pinch) still zooms, as do the zoom slider and touch pinch. - echarts-theme: stop plain wheel events before they reach any ECharts instance. ECharts swallows the wheel over inside dataZoom, geo roam and echarts-gl views whatever their options say, so this is the only place that covers every chart. - echarts-theme: on touch screens, inside dataZoom no longer swallows one-finger swipes, which intermittently blocked page scrolling on mobile. - Map2D: touch screens pinch-zoom only; one-finger drag scrolls the page instead of panning the map. Mouse drag still pans. - MultiLine: drop its explicit zoomOnMouseWheel override. Amp-Thread-ID: https://ampcode.com/threads/T-01a1c9ca-25ef-77a1-95a5-61b71ea16537 Co-authored-by: Sam Calder-Mason --- src/components/Charts/Map2D/Map2D.tsx | 6 +++++- src/components/Charts/MultiLine/MultiLine.tsx | 2 -- src/utils/echarts-theme.ts | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/components/Charts/Map2D/Map2D.tsx b/src/components/Charts/Map2D/Map2D.tsx index 3e0beec00..8a1d1413c 100644 --- a/src/components/Charts/Map2D/Map2D.tsx +++ b/src/components/Charts/Map2D/Map2D.tsx @@ -10,6 +10,7 @@ import type { Map2DChartProps, PointData, PointNodeData, RouteData } from './Map const EMPTY_ROUTES: RouteData[] = []; const EMPTY_POINTS: PointData[] = []; import { useThemeColors } from '@/hooks/useThemeColors'; +import { useCanHover } from '@/hooks/useCanHover'; import { ECHARTS_THEME } from '@/utils/echarts-theme'; import { ClientLogo } from '@/components/Ethereum/ClientLogo'; @@ -47,6 +48,7 @@ function Map2DChartComponent({ resetKey, }: Map2DChartProps): React.JSX.Element { const themeColors = useThemeColors(); + const canHover = useCanHover(); const [mapLoaded, setMapLoaded] = useState(false); const [hoveredPoint, setHoveredPoint] = useState(null); const chartRef = useRef(null); @@ -307,7 +309,8 @@ function Map2DChartComponent({ : undefined, geo: { map: 'world', - roam: roam, + // A one-finger drag would pan the map instead of scrolling the page, so touch screens only pinch-zoom + roam: roam === true && !canHover ? 'scale' : roam, silent: false, center: [20, 20], // Center slightly towards Europe zoom: 1.2, // Balanced zoom level @@ -336,6 +339,7 @@ function Map2DChartComponent({ lineColor, title, roam, + canHover, createScatterSeries, themeColors.primary, themeColors.foreground, diff --git a/src/components/Charts/MultiLine/MultiLine.tsx b/src/components/Charts/MultiLine/MultiLine.tsx index 39078def0..1e7b33750 100644 --- a/src/components/Charts/MultiLine/MultiLine.tsx +++ b/src/components/Charts/MultiLine/MultiLine.tsx @@ -1165,8 +1165,6 @@ export function MultiLineChart({ type: 'inside' as const, xAxisIndex: 0, filterMode: 'none' as const, - zoomOnMouseWheel: true, - moveOnMouseWheel: false, moveOnMouseMove: true, start: zoomRange.start, end: zoomRange.end, diff --git a/src/utils/echarts-theme.ts b/src/utils/echarts-theme.ts index 081ab037e..571215d01 100644 --- a/src/utils/echarts-theme.ts +++ b/src/utils/echarts-theme.ts @@ -7,4 +7,22 @@ export const ECHARTS_THEME = 'lab'; // Canvas text cannot inherit CSS fonts, so every chart takes the UI typeface from this theme. registerTheme(ECHARTS_THEME, { textStyle: { fontFamily: CHART_FONT_FAMILY }, + // On touch screens a one-finger swipe over a zoomable chart must scroll the page, not get swallowed + dataZoom: { preventDefaultMouseMove: globalThis.matchMedia?.('(hover: hover)').matches ?? true }, }); + +// Scrolling over a chart scrolls the page. ECharts swallows every wheel event over a zoomable or +// roamable chart (inside dataZoom, geo roam, echarts-gl view control), whatever its options say, +// so plain wheel events stop here before they reach any chart. Ctrl+wheel, which trackpad pinch +// also sends, still zooms. +if (typeof window !== 'undefined') { + window.addEventListener( + 'wheel', + event => { + if (!event.ctrlKey && event.target instanceof Element && event.target.closest('[_echarts_instance_]')) { + event.stopPropagation(); + } + }, + { capture: true, passive: true } + ); +}