From c6e073c5dd77477115ff2165100473cf7d2c0ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D0=BE=D0=B2=20=D0=90=D1=80=D1=82?= =?UTF-8?q?=D0=B5=D0=BC?= Date: Sun, 5 Jul 2026 21:12:07 +0300 Subject: [PATCH] =?UTF-8?q?BUR-39=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D0=B2=D0=B5=D1=80=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B8=20=D0=B3?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=B7=D0=BE=D0=BD=D1=82=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B7=D1=83=D0=BC=D0=B0=20=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20=D1=8D=D1=84=D1=84=D0=B5=D0=BA=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B4=D1=80=D1=83=D0=B3=20=D0=B4=D1=80=D0=B3=D1=83=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../history-chart/HistoryChartArea.tsx | 74 ++++++++++++++++++- src/styles/charts.css | 7 ++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/features/history-chart/HistoryChartArea.tsx b/src/features/history-chart/HistoryChartArea.tsx index 2649a14..1130542 100644 --- a/src/features/history-chart/HistoryChartArea.tsx +++ b/src/features/history-chart/HistoryChartArea.tsx @@ -1,6 +1,7 @@ import type { EChartsOption } from 'echarts'; import ReactEChartsCore from 'echarts-for-react/esm/core.js'; -import { useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; +import type { WheelEvent } from 'react'; import type { DataZoomEventBatch } from './chartTypes'; import { echarts } from './historyChartEcharts'; @@ -12,6 +13,21 @@ type HistoryChartAreaProps = { onDataZoom: (event: DataZoomEventBatch) => void; }; +/** Включает или выключает нативный X-зум колесом, чтобы Shift + колесо работал только по Y. */ +function setXAxisWheelZoom(chart: ReturnType, enabled: boolean): void { + chart.setOption( + { + dataZoom: [ + { + id: 'history-x-inside', + zoomOnMouseWheel: enabled, + }, + ], + }, + { lazyUpdate: true }, + ); +} + /** Отвечает только за визуальную область графика: placeholder или ECharts canvas. */ export function HistoryChartArea({ hasData, @@ -20,12 +36,55 @@ export function HistoryChartArea({ option, onDataZoom, }: HistoryChartAreaProps) { + const chartRef = useRef | null>(null); + const xWheelZoomEnabledRef = useRef(true); const onChartEvents = useMemo( () => ({ datazoom: onDataZoom, }), [onDataZoom], ); + const updateXAxisWheelZoom = useCallback((enabled: boolean) => { + const chart = chartRef.current?.getEchartsInstance(); + + if (!chart || xWheelZoomEnabledRef.current === enabled) { + return; + } + + xWheelZoomEnabledRef.current = enabled; + setXAxisWheelZoom(chart, enabled); + }, []); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Shift') { + updateXAxisWheelZoom(false); + } + }; + const handleKeyUp = (event: KeyboardEvent) => { + if (event.key === 'Shift') { + updateXAxisWheelZoom(true); + } + }; + const handleBlur = () => updateXAxisWheelZoom(true); + + window.addEventListener('keydown', handleKeyDown); + window.addEventListener('keyup', handleKeyUp); + window.addEventListener('blur', handleBlur); + + return () => { + window.removeEventListener('keydown', handleKeyDown); + window.removeEventListener('keyup', handleKeyUp); + window.removeEventListener('blur', handleBlur); + }; + }, [updateXAxisWheelZoom]); + + const handleWheelCapture = useCallback( + (event: WheelEvent) => { + updateXAxisWheelZoom(!event.shiftKey); + }, + [updateXAxisWheelZoom], + ); if (!hasSelection) { return
Разверните список показателей и выберите серию для графика
; @@ -39,5 +98,16 @@ export function HistoryChartArea({ return
Нет данных для выбранного диапазона
; } - return ; + return ( +
+ +
+ ); } diff --git a/src/styles/charts.css b/src/styles/charts.css index 46f8a77..6b8d3b2 100644 --- a/src/styles/charts.css +++ b/src/styles/charts.css @@ -1,8 +1,14 @@ +.history-chart-shell, .history-chart { width: 100%; height: 440px; } +.history-chart-shell .history-chart { + height: 100%; +} + +.chart-section--archive .history-chart-shell, .chart-section--archive .history-chart { flex: 1; min-height: 520px; @@ -67,6 +73,7 @@ } @media (max-width: 680px) { + .chart-section--archive .history-chart-shell, .chart-section--archive .history-chart, .chart-section--archive .chart-placeholder { min-height: 420px;