Merge pull request 'BUR-39 Добавлена возможность вертикального и горизонтального зума без эффекта друг дргуа' (#21) from bur-39 into dev
Reviewed-on: #21
This commit was merged in pull request #21.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import type { EChartsOption } from 'echarts';
|
import type { EChartsOption } from 'echarts';
|
||||||
import ReactEChartsCore from 'echarts-for-react/esm/core.js';
|
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 type { DataZoomEventBatch } from './chartTypes';
|
||||||
import { echarts } from './historyChartEcharts';
|
import { echarts } from './historyChartEcharts';
|
||||||
|
|
||||||
@@ -12,6 +13,21 @@ type HistoryChartAreaProps = {
|
|||||||
onDataZoom: (event: DataZoomEventBatch) => void;
|
onDataZoom: (event: DataZoomEventBatch) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Включает или выключает нативный X-зум колесом, чтобы Shift + колесо работал только по Y. */
|
||||||
|
function setXAxisWheelZoom(chart: ReturnType<ReactEChartsCore['getEchartsInstance']>, enabled: boolean): void {
|
||||||
|
chart.setOption(
|
||||||
|
{
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
id: 'history-x-inside',
|
||||||
|
zoomOnMouseWheel: enabled,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ lazyUpdate: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** Отвечает только за визуальную область графика: placeholder или ECharts canvas. */
|
/** Отвечает только за визуальную область графика: placeholder или ECharts canvas. */
|
||||||
export function HistoryChartArea({
|
export function HistoryChartArea({
|
||||||
hasData,
|
hasData,
|
||||||
@@ -20,12 +36,55 @@ export function HistoryChartArea({
|
|||||||
option,
|
option,
|
||||||
onDataZoom,
|
onDataZoom,
|
||||||
}: HistoryChartAreaProps) {
|
}: HistoryChartAreaProps) {
|
||||||
|
const chartRef = useRef<InstanceType<typeof ReactEChartsCore> | null>(null);
|
||||||
|
const xWheelZoomEnabledRef = useRef(true);
|
||||||
const onChartEvents = useMemo(
|
const onChartEvents = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
datazoom: onDataZoom,
|
datazoom: onDataZoom,
|
||||||
}),
|
}),
|
||||||
[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<HTMLDivElement>) => {
|
||||||
|
updateXAxisWheelZoom(!event.shiftKey);
|
||||||
|
},
|
||||||
|
[updateXAxisWheelZoom],
|
||||||
|
);
|
||||||
|
|
||||||
if (!hasSelection) {
|
if (!hasSelection) {
|
||||||
return <div className="chart-placeholder">Разверните список показателей и выберите серию для графика</div>;
|
return <div className="chart-placeholder">Разверните список показателей и выберите серию для графика</div>;
|
||||||
@@ -39,5 +98,16 @@ export function HistoryChartArea({
|
|||||||
return <div className="chart-placeholder">Нет данных для выбранного диапазона</div>;
|
return <div className="chart-placeholder">Нет данных для выбранного диапазона</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ReactEChartsCore echarts={echarts} option={option} className="history-chart" onEvents={onChartEvents} lazyUpdate />;
|
return (
|
||||||
|
<div className="history-chart-shell" onWheelCapture={handleWheelCapture}>
|
||||||
|
<ReactEChartsCore
|
||||||
|
ref={chartRef}
|
||||||
|
echarts={echarts}
|
||||||
|
option={option}
|
||||||
|
className="history-chart"
|
||||||
|
onEvents={onChartEvents}
|
||||||
|
lazyUpdate
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
.history-chart-shell,
|
||||||
.history-chart {
|
.history-chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 440px;
|
height: 440px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history-chart-shell .history-chart {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-section--archive .history-chart-shell,
|
||||||
.chart-section--archive .history-chart {
|
.chart-section--archive .history-chart {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 520px;
|
min-height: 520px;
|
||||||
@@ -67,6 +73,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 680px) {
|
@media (max-width: 680px) {
|
||||||
|
.chart-section--archive .history-chart-shell,
|
||||||
.chart-section--archive .history-chart,
|
.chart-section--archive .history-chart,
|
||||||
.chart-section--archive .chart-placeholder {
|
.chart-section--archive .chart-placeholder {
|
||||||
min-height: 420px;
|
min-height: 420px;
|
||||||
|
|||||||
Reference in New Issue
Block a user