Загрузка данных
import { useRef, useEffect } from 'react';
import {
MoexChart as ChartMoex,
IMoexChart,
MoexChartSnapshot,
} from '@mx-charts/charts';
import { logger } from '~/utils/logger';
import '@mx-charts/charts/dist/styles.css';
import styles from './styles.module.scss';
type TradeRadarChartProps = {
height: number;
chartConfig: Omit<IMoexChart, 'container'>;
storageKey: string | undefined;
};
export const TradeRadarChart = ({
height = 500,
chartConfig,
storageKey,
}: TradeRadarChartProps) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const chartRef = useRef<ChartMoex | null>(null);
const currentSymbol = chartConfig.snapshot?.charts?.[0]?.symbolId || '';
useEffect(() => {
const container = containerRef.current;
if (!container) {
return;
}
const saved = storageKey ? localStorage.getItem(storageKey) : undefined;
let configWithSnapshot = chartConfig;
if (saved) {
try {
const savedSnapshot = JSON.parse(saved) as MoexChartSnapshot;
if (savedSnapshot.charts && savedSnapshot.charts.length > 0) {
savedSnapshot.charts[0].symbol = currentSymbol;
savedSnapshot.charts[0].symbolId = currentSymbol;
}
configWithSnapshot = {
...chartConfig,
snapshot: savedSnapshot,
};
} catch (e) {
logger.error('Failed to parse saved snapshot', { error: e });
}
}
const { supportedTimeframes } = configWithSnapshot.chartCollectionPreset;
const { timeframe } = configWithSnapshot.snapshot.charts[0];
if (!supportedTimeframes.includes(timeframe)) {
configWithSnapshot.snapshot.charts[0].timeframe = supportedTimeframes[0];
}
chartRef.current = new ChartMoex({
...configWithSnapshot,
container,
});
const chart = chartRef.current;
return () => {
chart.destroy();
chartRef.current = null;
};
}, [chartConfig, currentSymbol, storageKey]);
useEffect(() => {
const saveSnapshot = () => {
const chart = chartRef.current;
if (!chart || !storageKey) return;
try {
const snapshot = chartRef.current?.getSnapshot();
if (!snapshot) {
return;
}
const savedData = JSON.stringify({
...snapshot,
charts: snapshot.charts.map((c) => ({
...c,
symbol: currentSymbol,
symbolId: currentSymbol,
panes: c.panes.map((p) => ({
...p,
drawings: [],
indicators: p.indicators.map((i) => ({
...i,
dataSource: undefined,
config: undefined,
})),
})),
})),
});
localStorage.setItem(storageKey, savedData);
} catch (e) {
logger.error('Failed to save advanced chart snapshot', { error: e });
}
};
const handleVisibilityChange = () => {
if (document.visibilityState === 'hidden') {
saveSnapshot();
}
};
const handleBeforeUnload = () => {
saveSnapshot();
};
document.addEventListener('visibilitychange', handleVisibilityChange);
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, [currentSymbol, storageKey]);
return (
<div className={styles.tradeRadarChart} style={{ height: `${height}px` }}>
<div ref={containerRef} />
</div>
);
};
import { IndicatorsIds } from '@mx-charts/charts';
import { useCallback, useMemo } from 'react';
import { fetchCandles } from '~/modules/FutureCard/api';
import { ChartConfigOverride } from '~/modules/TradeRadarChart';
import { FuturesAdvancedChart } from '../../../blocks/FuturesAdvancedChart';
import { useTranslation } from '../../../../translations';
import { FetchChartCandles } from '~/modules/FutureCard/types';
import { mapToChartCandles } from '../utils/mapToChartCandles';
type FuturesChartProps = {
height?: number;
secId: string;
boardGroupId: number;
market: string;
engine: string;
realtimeInterval?: number;
};
export const FuturesChart = (props: FuturesChartProps) => {
const { t } = useTranslation();
const chartConfig: ChartConfigOverride = useMemo(
() => ({
snapshot: {
charts: [
{
panes: [
{
isMain: true,
id: 0,
indicators: [
{
indicatorType: IndicatorsIds.Volume,
},
],
drawings: [],
},
],
},
],
},
}),
[]
);
const fetchChartCandles: FetchChartCandles = useCallback(async (params) => {
const { data: candlesData, isError } = await fetchCandles(params);
return {
data: candlesData
? {
isAuthorized: candlesData.isAuthorized,
data: mapToChartCandles(candlesData.data),
}
: null,
isError,
};
}, []);
return (
<FuturesAdvancedChart
{...props}
fetchChartCandles={fetchChartCandles}
storageKey="moexFuturesChartSnapshot"
chartConfigOverride={chartConfig}
noDataMessage={t.quotes.chartNoDataMessage}
/>
);
};