Загрузка данных
import { useEffect, useRef, useState } from 'react';
import { CompareMode, DateFormat, IMoexChart, Locale, MoexChart, Timeframes } from '@lib';
import { Portal } from '@lib/components/Portal';
import { IndicatorsIds } from '@lib/constants';
import { CompareManager } from '@lib/core/CompareManager';
import { SymbolInfoInput } from '@lib/types';
import { dataSourceProvider } from '../common';
import { activate } from '../worker';
import type { Meta, StoryObj } from '@storybook/react';
/**
* ## MB story
* describes an entry point of MoexChart for MB user
*/
activate();
type MBProps = Omit<IMoexChart, 'container'>;
// todo: переписат ьпод новую сигнатуру
const MBEntry = (props: MBProps) => {
const [isCompareOpen, setIsCompareOpen] = useState(false);
const [moexChart, setMoexChart] = useState<MoexChart | undefined>(undefined);
const containerRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const container = containerRef.current;
if (!container) {
return;
}
const chart = new MoexChart({
...props,
container,
chartCollectionPreset: {
...props.chartCollectionPreset,
openCompareModal: () => setIsCompareOpen(true),
},
});
setMoexChart(chart);
return () => {
chart.destroy();
};
}, [props]);
return (
<div
style={{
width: '100%',
height: '100dvh',
display: 'grid',
gridTemplateRows: 'auto minmax(0, 1fr)',
gap: 10,
padding: 20,
boxSizing: 'border-box',
}}
>
<h3
style={{
margin: 0,
}}
>
MB usage
</h3>
<div ref={containerRef} />
{isCompareOpen && (
<Portal>
<Modal
onClose={() => setIsCompareOpen(false)}
compareManager={moexChart?.getCompareManager() ?? null}
/>
</Portal>
)}
</div>
);
};
const meta: Meta<MBProps> = {
title: 'MB',
component: MBEntry,
// argTypes, // todo: пофиксить вместе с переписыванием доки
parameters: {
layout: 'fullscreen',
docs: {
description: {
component: `## MB story
describes an entry point of MoexChart for MB user`,
},
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
const args: MBProps = {
snapshot: {
charts: [
{
timeframe: Timeframes['10s'],
chartSeriesType: 'Candlestick',
symbolId: 'APPL',
panes: [
{
// empty panes deletes automatically
isMain: true, // Be careful. There is only one main pane can be present
id: 0,
indicators: [
{
indicatorType: IndicatorsIds.Volume,
},
],
drawings: [],
},
],
},
],
},
chartCollectionPreset: {
undoRedoEnabled: true,
showMenuButton: true,
showBottomPanel: true,
showControlBar: true,
showFullscreenButton: true,
showSettingsButton: true,
showCompareButton: false,
tooltipConfig: {
showTooltip: false,
time: { visible: true, label: 'Время' },
close: { visible: true, label: 'Закр.' },
change: { visible: true, label: 'Изм.' },
volume: { visible: true, label: 'Объем' },
open: { visible: true, label: 'Откр.' },
high: { visible: true, label: 'Макс.' },
low: { visible: true, label: 'Мин.' },
},
supportedTimeframes: [
Timeframes['1s'],
Timeframes['5s'],
Timeframes['10s'],
Timeframes['1m'],
Timeframes['2m'],
Timeframes['30m'],
Timeframes['1h'],
Timeframes['2h'],
Timeframes['3h'],
Timeframes['4h'],
Timeframes['1d'],
Timeframes['1w'],
],
supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
startRealtime: (getSymbols, getTimeframe, update) =>
dataSourceProvider.startRealtime(getSymbols, getTimeframe, update), // should return unsub
theme: 'mb',
ohlc: {
show: true,
precision: 2,
},
mode: 'dark',
locale: Locale.rus,
},
lwcInheritedChartOptions: {
timeVisible: true,
secondsVisible: false,
timeFormat: '24h',
dateFormat: DateFormat.DD_MM_YYYY_HH_mm_ss,
},
};
export const MB: Story = {
args,
parameters: {
controls: {
expanded: true, // отвечает за расширение колонок(+Description, +Default) в табе controls
},
},
};
const COMPARE_ITEMS: SymbolInfoInput[] = [
{ symbolId: 'TQBR:SBER', symbol: 'SBER', symbolName: 'Сбербанк' },
{ symbolId: 'APAX' },
{ symbolId: 'SOL' },
];
const Modal = ({ onClose, compareManager }: { onClose: () => void; compareManager: CompareManager | null }) => {
const [isNewScaleDisabled, setIsNewScaleDisabled] = useState(false);
useEffect(() => {
if (!compareManager) {
setIsNewScaleDisabled(false);
return;
}
setIsNewScaleDisabled(compareManager.isNewScaleDisabled());
const subscription = compareManager.isNewScaleDisabledObservable().subscribe(setIsNewScaleDisabled);
return () => subscription.unsubscribe();
}, [compareManager]);
const { mode = 'light' } = args.chartCollectionPreset;
const containerStyles =
mode === 'light' ? { backgroundColor: 'white', color: 'black' } : { backgroundColor: 'black', color: 'white' };
const buttonStyles =
mode === 'light'
? { backgroundColor: 'lightgray', color: 'black', padding: '2px 8px' }
: { backgroundColor: 'darkgray', color: 'black', padding: '2px 8px' };
return (
<div
onClick={onClose}
style={{
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#0000004D',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
zIndex: 999,
cursor: 'pointer',
}}
>
<div
onClick={(e) => e.stopPropagation()}
style={{
display: 'grid',
gap: 16,
padding: 16,
...containerStyles,
}}
>
{COMPARE_ITEMS.map((symbolInfo) => (
<div
key={symbolInfo.symbolId}
style={{ display: 'flex', justifyContent: 'space-between', gap: 16 }}
>
<span>{symbolInfo.symbolName ?? symbolInfo.symbol ?? symbolInfo.symbolId}</span>
<div style={{ display: 'flex', gap: 8 }}>
<button
onClick={() => compareManager?.setSymbolMode('Line', symbolInfo, CompareMode.Absolute)}
style={buttonStyles}
type="button"
>
Абсолютная шкала
</button>
<button
onClick={() => compareManager?.setSymbolMode('Line', symbolInfo, CompareMode.Percentage)}
style={buttonStyles}
type="button"
>
%
</button>
<button
onClick={() => compareManager?.setSymbolMode('Line', symbolInfo, CompareMode.NewScale)}
style={{
backgroundColor: isNewScaleDisabled ? 'darkgray' : 'lightgray',
padding: '2px 8px',
cursor: isNewScaleDisabled ? 'not-allowed' : 'cursor',
}}
disabled={isNewScaleDisabled}
type="button"
>
Новая шкала
</button>
<button
onClick={() => compareManager?.setSymbolMode('Line', symbolInfo, CompareMode.NewPane)}
style={buttonStyles}
type="button"
>
Новая панель
</button>
</div>
</div>
))}
</div>
</div>
);
};