Загрузка данных
diff --git a/src/constants/indicator.ts b/src/constants/indicator.ts
index f5a575bcc4af1402ead95cab273b49e705470ae9..4dbfeab8ad167cd71a1d696f482757c7c67d7a87 100644
--- a/src/constants/indicator.ts
+++ b/src/constants/indicator.ts
@@ -1,4 +1,4 @@
-export enum IndicatorsIds {
+export enum IndicatorsIds { // todo: rename to IndicatorsTypes
Volume = 'vol',
SMA = 'sma',
EMA = 'ema',
diff --git a/src/core/Chart.ts b/src/core/Chart.ts
index 3daa904e9d90e4b5a25de9eb231b083233abcbb0..2b1a6d1048846d508fa6d7e17b67d17a03e0ebbf 100644
--- a/src/core/Chart.ts
+++ b/src/core/Chart.ts
@@ -1,3 +1,4 @@
+import { ChartSnapshot, ISerializable, PaneSnapshot } from '@src/types/snapshot';
import dayjs from 'dayjs';
import {
@@ -24,7 +25,6 @@ import { EventManager } from '@core/EventManager';
import { IndicatorManager } from '@core/IndicatorManager';
import { ModalRenderer } from '@core/ModalRenderer';
import { PaneManager } from '@core/PaneManager';
-import { IndicatorsIds } from '@src/constants';
import { CompareManager } from '@src/core/CompareManager';
import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
import { getThemeStore } from '@src/theme/store';
@@ -42,6 +42,7 @@ import { Defaults } from '@src/types/defaults';
import { DayjsOffset, Intervals, intervalsToDayjs } from '@src/types/intervals';
import { createTickMarkFormatter, formatDate } from '@src/utils/formatter';
+import flatten from 'lodash-es/flatten';
export interface ChartConfig extends Partial<ChartOptionsModel> {
container: HTMLElement;
@@ -59,19 +60,22 @@ export enum Resize {
const HISTORY_LOAD_THRESHOLD = 50;
-interface ChartParams extends ChartConfig {
- dataSource: DataSource;
- eventManager: EventManager;
- modalRenderer: ModalRenderer;
- ohlcConfig: OHLCConfig;
- tooltipConfig: TooltipConfig;
- initialIndicators?: IndicatorsIds[];
+interface ChartParams {
+ params: {
+ dataSource: DataSource;
+ eventManager: EventManager;
+ modalRenderer: ModalRenderer;
+ ohlcConfig: OHLCConfig;
+ tooltipConfig: TooltipConfig;
+ panes: PaneSnapshot[];
+ },
+ lwcChartConfig: ChartConfig
}
/**
* Абстракция над библиотекой для построения графиков
*/
-export class Chart {
+export class Chart implements ISerializable<ChartSnapshot>{
private lwcChart!: IChartApi;
private container: HTMLElement;
private eventManager: EventManager;
@@ -97,25 +101,30 @@ export class Chart {
private historyBatchRunning = false;
constructor({
- eventManager,
- dataSource,
- modalRenderer,
- ohlcConfig,
- tooltipConfig,
- initialIndicators,
- ...lwcConfig
+ params,
+ lwcChartConfig
}: ChartParams) {
+
+ const {
+ eventManager,
+ dataSource,
+ modalRenderer,
+ ohlcConfig,
+ tooltipConfig,
+ panes: panesSnapshot,
+ } = params
+
this.eventManager = eventManager;
this.dataSource = dataSource;
- this.container = lwcConfig.container;
- this.chartConfig = lwcConfig;
+ this.container = lwcChartConfig.container;
+ this.chartConfig = lwcChartConfig;
- this.lwcChart = createChart(this.container, getOptions(lwcConfig));
+ this.lwcChart = createChart(this.container, getOptions(lwcChartConfig));
this.optionsSubscription = this.eventManager
.getChartOptionsModel()
.subscribe(({ dateFormat, timeFormat, showTime }) => {
- const configToApply = { ...lwcConfig, dateFormat, timeFormat, showTime };
+ const configToApply = { ...lwcChartConfig, dateFormat, timeFormat, showTime };
this.lwcChart.applyOptions({
...getOptions(configToApply),
@@ -139,6 +148,7 @@ export class Chart {
this.paneManager = new PaneManager({
eventManager: this.eventManager,
+ panesSnapshot,
lwcChart: this.lwcChart,
dataSource,
DOM: this.DOM,
@@ -151,16 +161,17 @@ export class Chart {
this.indicatorManager = new IndicatorManager({
eventManager,
- initialIndicators,
+ initialIndicators: flatten(panesSnapshot.map((pane) => pane.indicators.map((ind) => ({...ind, paneId: pane.id})) )),
DOM: this.DOM,
dataSource: this.dataSource,
lwcChart: this.lwcChart,
paneManager: this.paneManager,
- chartOptions: lwcConfig.chartOptions,
+ chartOptions: lwcChartConfig.chartOptions,
});
this.compareManager = new CompareManager({
chart: this.lwcChart,
+ initialIndicators: flatten(panesSnapshot.map((pane) => pane.indicators.map((ind) => ({...ind, paneId: pane.id})) )),
eventManager: this.eventManager,
dataSource: this.dataSource,
indicatorManager: this.indicatorManager,
@@ -284,6 +295,15 @@ export class Chart {
};
}
+ public getSnapshot(): ChartSnapshot {
+ return {
+ panes: this.paneManager.getSnapshot(),
+ chartSeriesType: this.eventManager.exportChartSettings().seriesSelected,
+ timeframe: this.eventManager.exportChartSettings().timeframe,
+ symbol: this.activeSymbols[0]
+ }
+ }
+
private scheduleHistoryBatch = () => {
if (this.historyBatchRunning) return;
diff --git a/src/core/CompareManager.ts b/src/core/CompareManager.ts
index 1fee19eacd6f0afab165f962a58e2256c53434a4..b2ad48d4390bfe3c1b4b6764d035e1e950d574f8 100644
--- a/src/core/CompareManager.ts
+++ b/src/core/CompareManager.ts
@@ -1,3 +1,4 @@
+import { IndicatorSnapshot } from '@src/types/snapshot';
import { IChartApi, PriceScaleMode, SeriesType } from 'lightweight-charts';
import { BehaviorSubject, distinctUntilChanged, map, Observable } from 'rxjs';
@@ -31,6 +32,7 @@ interface CompareManagerParams {
dataSource: DataSource;
indicatorManager: IndicatorManager;
paneManager: PaneManager;
+ initialIndicators?: IndicatorSnapshot[];
}
const getDefaultCompareIndicatorConfig = (symbol: string): IndicatorConfig => {
@@ -61,7 +63,7 @@ export class CompareManager {
private readonly itemsSubject = new BehaviorSubject<CompareItem[]>([]);
private readonly entitiesSubject = new BehaviorSubject<Indicator[]>([]);
- constructor({ chart, eventManager, dataSource, indicatorManager, paneManager }: CompareManagerParams) {
+ constructor({ chart, eventManager, dataSource, indicatorManager, paneManager, initialIndicators = []}: CompareManagerParams) {
this.chart = chart;
this.eventManager = eventManager;
this.dataSource = dataSource;
@@ -71,18 +73,31 @@ export class CompareManager {
this.eventManager.timeframe().subscribe(() => {
this.applyPolicy();
});
- }
- public itemsObs(): Observable<CompareItem[]> {
- return this.itemsSubject.asObservable();
+ if(!initialIndicators){
+ return
+ }
+
+ this.setup(initialIndicators)
}
- public entitiesObs(): Observable<Indicator[]> {
- return this.entitiesSubject.asObservable();
+ private async setup(initialIndicators: IndicatorSnapshot[]) {
+ for(const indicator of initialIndicators){
+ if(indicator.config && indicator.config.label){ // условие проверки compare ли это
+ const serie = indicator.config.series[0]
+
+ const compareMode = serie.seriesOptions?.priceScaleId === Direction.Left
+ ? CompareMode.NewScale
+ : indicator.config.newPane ? CompareMode.NewPane : CompareMode.Percentage
+
+ // eslint-disable-next-line no-await-in-loop
+ await this.setSymbolMode(serie.name, indicator.config.label, compareMode, indicator.paneId)
+ }
+ }
}
- public snapshot(): CompareItem[] {
- return this.itemsSubject.value;
+ public itemsObs(): Observable<CompareItem[]> {
+ return this.itemsSubject.asObservable();
}
public clear(): void {
@@ -94,7 +109,7 @@ export class CompareManager {
this.publish();
}
- public async setSymbolMode(seriesType: SeriesType, symbolRaw: string, mode: CompareMode): Promise<void> {
+ public async setSymbolMode(seriesType: SeriesType, symbolRaw: string, mode: CompareMode, paneId?: number): Promise<void> {
const symbol = normalizeSymbol(symbolRaw);
if (!symbol) return;
@@ -110,16 +125,16 @@ export class CompareManager {
const entity = this.indicatorManager.addEntity<Indicator>((zIndex, moveUp, moveDown) => {
const config = getDefaultCompareIndicatorConfig(symbol);
+ const associatedPane = mode === CompareMode.NewPane
+ ? paneId !== undefined ? this.paneManager.getPaneById(paneId) : this.paneManager.addPane()
+ : this.paneManager.getMainPane()
+
return new Indicator({
id: key,
lwcChart: this.chart,
mainSymbol$: symbol$,
dataSource: this.dataSource,
- zIndex,
- onDelete: () => this.removeByKey(key),
- moveUp,
- moveDown,
- paneManager: this.paneManager,
+ associatedPane,
config: {
...config,
series: [
@@ -133,6 +148,11 @@ export class CompareManager {
],
newPane: mode === CompareMode.NewPane,
},
+ zIndex,
+ onDelete: () => this.removeByKey(key),
+ moveUp,
+ moveDown,
+ paneId: associatedPane.getId()
});
});
diff --git a/src/core/DOMObject.ts b/src/core/DOMObject.ts
index b9b66cfdd0e54464bcdf4b8c6b71820f075c00c7..53ad642ed5bcbaadbdda5f9343a8539dc05ee981 100644
--- a/src/core/DOMObject.ts
+++ b/src/core/DOMObject.ts
@@ -1,3 +1,4 @@
+import { DOMObjectSnapshot, IndicatorSnapshot, ISerializable } from '@src/types/snapshot';
import { BehaviorSubject } from 'rxjs';
enum DOMObjectType {
@@ -23,30 +24,33 @@ export interface IDOMObject {
export interface DOMObjectParams {
id: string;
- name?: string;
+ paneId: number; // todo: implement for drawings
zIndex: number;
onDelete: (id: string) => void;
moveUp: (id: string) => void;
moveDown: (id: string) => void;
+ name?: string;
}
-export class DOMObject implements IDOMObject {
+export class DOMObject implements IDOMObject, ISerializable<DOMObjectSnapshot> {
public readonly id: string;
public name: string;
public zIndex: number;
public hidden = new BehaviorSubject(false);
public moveUp: () => void;
public moveDown: () => void;
+ public paneId: number;
protected onDelete: (id: string) => void;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
type: DOMObjectType;
- constructor({ id, name, zIndex, onDelete, moveUp, moveDown }: DOMObjectParams) {
+ constructor({ id, name, zIndex, onDelete, moveUp, moveDown, paneId }: DOMObjectParams) {
this.id = id;
this.name = name ?? id;
this.zIndex = zIndex;
+ this.paneId = paneId;
this.onDelete = onDelete;
this.moveUp = () => moveUp(this.id);
this.moveDown = () => moveDown(this.id);
@@ -73,4 +77,14 @@ export class DOMObject implements IDOMObject {
shouldShowInObjectTree(): boolean {
return true;
}
+
+ public getSnapshot(): DOMObjectSnapshot {
+ return {
+ id: this.id,
+ name: this.name,
+ zIndex: this.zIndex,
+ hidden: this.hidden.value,
+ paneId: this.paneId
+ }
+ }
}
diff --git a/src/core/Indicator.ts b/src/core/Indicator.ts
index 58106e4b78ba09e9c19a7f195ec7c077ea1c9624..0fa9351614f3da4f2244ef73293c1380e8b4ec98 100644
--- a/src/core/Indicator.ts
+++ b/src/core/Indicator.ts
@@ -1,3 +1,4 @@
+import { DOMObjectSnapshot, IndicatorSnapshot, ISerializable } from '@src/types/snapshot';
import { IChartApi } from 'lightweight-charts';
import { Observable, Subscription } from 'rxjs';
@@ -15,16 +16,16 @@ import { ensureDefined } from '@src/utils';
type IIndicator = DOMObject;
export interface IndicatorParams extends DOMObjectParams {
- type?: IndicatorsIds;
mainSymbol$: Observable<string>;
lwcChart: IChartApi;
dataSource: DataSource;
- paneManager: PaneManager;
+ associatedPane: Pane;
+ config: IndicatorConfig;
+ type?: IndicatorsIds;
chartOptions?: ChartTypeOptions;
- config?: IndicatorConfig;
}
-export class Indicator extends DOMObject implements IIndicator {
+export class Indicator extends DOMObject implements ISerializable<IndicatorSnapshot> {
private indicatorType?: IndicatorsIds;
private series: SeriesStrategies[] = [];
private seriesMap: Map<string, SeriesStrategies> = new Map();
@@ -48,20 +49,21 @@ export class Indicator extends DOMObject implements IIndicator {
moveUp,
moveDown,
mainSymbol$,
- paneManager,
+ associatedPane,
+ paneId,
config,
}: IndicatorParams) {
- super({ id, name: config?.label ?? id, zIndex, onDelete, moveUp, moveDown });
+ super({ id, name: config?.label ?? id, zIndex, onDelete, moveUp, moveDown, paneId });
this.lwcChart = lwcChart;
this.dataSource = dataSource;
this.mainSymbol$ = mainSymbol$;
this.indicatorType = type;
- this.config = ensureDefined(type ? indicatorsMap[type] : config);
+ this.config = config;
this.name = this.getLabel();
this.settings = this.getDefaultSettings();
- this.associatedPane = this.config.newPane ? paneManager.addPane() : paneManager.getMainPane();
+ this.associatedPane = associatedPane;
this.createSeries();
@@ -76,7 +78,7 @@ export class Indicator extends DOMObject implements IIndicator {
});
}
- public getLabel(): string {
+ public getLabel = () => {
if (this.config.label) {
return this.config.label;
}
@@ -152,6 +154,21 @@ export class Indicator extends DOMObject implements IIndicator {
super.hide();
}
+ public override getSnapshot(): DOMObjectSnapshot & IndicatorSnapshot {
+ const domSnap = super.getSnapshot()
+
+ return {
+ ...domSnap,
+ dataSource: this.dataSource,
+ indicatorType: this.indicatorType,
+ config: this.config,
+ }
+ }
+
+ public setSnapshot(snap: IndicatorSnapshot): void {
+
+ }
+
// destroy и delete принципиально отличаются!
// delete вызовет destroy в конце концов. По сути - это destroy с сайд-эффектом в eventManager
public delete() {
diff --git a/src/core/IndicatorManager.ts b/src/core/IndicatorManager.ts
index b4b1fd0b9a8b10e9e9f248c7a5c8c231e83d6bce..4f6a52733f059a14041efd37b78951be7ed3cb65 100644
--- a/src/core/IndicatorManager.ts
+++ b/src/core/IndicatorManager.ts
@@ -1,14 +1,15 @@
+import { IndicatorSnapshot } from '@src/types/snapshot';
import { IChartApi } from 'lightweight-charts';
import { BehaviorSubject, map, Observable } from 'rxjs';
+import { indicatorsMap as indicatorsConfigMap } from '@src/core/Indicators';
import { DataSource } from '@core/DataSource';
import { DOMModel } from '@core/DOMModel';
import { EventManager } from '@core/EventManager';
import { Indicator } from '@core/Indicator';
import { PaneManager } from '@core/PaneManager';
-import { IndicatorsIds } from '@src/constants';
import { DOMObject } from '@src/core/DOMObject';
-import { ChartTypeOptions } from '@src/types';
+import { ChartTypeOptions, IndicatorConfig } from '@src/types';
interface SeriesParams {
eventManager: EventManager;
@@ -16,7 +17,7 @@ interface SeriesParams {
lwcChart: IChartApi;
paneManager: PaneManager;
DOM: DOMModel;
- initialIndicators?: IndicatorsIds[];
+ initialIndicators?: IndicatorSnapshot[];
chartOptions?: ChartTypeOptions;
}
@@ -52,25 +53,38 @@ export class IndicatorManager {
return this.DOM.setEntity(factory);
}
- public addIndicator(indicatorType: IndicatorsIds): void {
+ public addIndicator(snap: Partial<IndicatorSnapshot>): void {
+ if(!snap.indicatorType) {
+ console.error('[IndicatorManager] Не был получен тип индиктора');
+ return
+ }
const indicatorsMap = new Map(this.indicatorsMap$.value);
- const id = `${indicatorType}-${crypto.randomUUID()}`;
+ const id = snap.id ?? `${snap.indicatorType}-${crypto.randomUUID()}`;
+
+ const config = indicatorsConfigMap[snap.indicatorType] as IndicatorConfig;
+
+ const associatedPane = snap.paneId !== undefined
+ ? this.paneManager.getPaneById(snap.paneId)
+ : config?.newPane ? this.paneManager.addPane() : this.paneManager.getMainPane();
const indicatorToSet = this.addEntity<Indicator>(
(zIndex: number, moveUp: (id: string) => void, moveDown: (id: string) => void) =>
new Indicator({
id,
- type: indicatorType,
- lwcChart: this.lwcChart,
- mainSymbol$: this.eventManager.getSymbol(),
- dataSource: this.dataSource,
- chartOptions: this.chartOptions,
+ paneId: associatedPane.getId(),
zIndex,
onDelete: this.deleteIndicator,
moveUp,
moveDown,
- paneManager: this.paneManager,
+
+ mainSymbol$: this.eventManager.getSymbol(),
+ lwcChart: this.lwcChart,
+ dataSource: this.dataSource,
+ associatedPane,
+ config,
+ type: snap.indicatorType,
+ chartOptions: this.chartOptions,
}),
);
diff --git a/src/core/MoexChart.tsx b/src/core/MoexChart.tsx
index d11fc031a25ed0791f590eb685d73d063f5eeffe..b56c338fb25f6122b3f63489b4f281051c79e7dc 100644
--- a/src/core/MoexChart.tsx
+++ b/src/core/MoexChart.tsx
@@ -1,3 +1,5 @@
+import { Pane } from '@core/Pane';
+import { InitialSnapshot, ISerializable, MoexChartSnapshot } from '@src/types/snapshot';
import { combineLatest, Subscription } from 'rxjs';
import { ControlBar } from '@components/ControlBar';
@@ -33,24 +35,7 @@ import 'exchange-elements/dist/style.css';
import 'exchange-elements/dist/tokens/moex.css';
// todo: forbid @lib in /src
-export interface IMoexChart {
- container: HTMLElement;
- supportedTimeframes: Timeframes[];
- initialTimeframe: Timeframes;
- supportedChartSeriesTypes: ChartSeriesType[];
- initialChartSeriesTypes: ChartSeriesType;
- initialSymbol: string;
- getDataSource: DataSourceParams['getData'];
- theme: ThemeKey; // 'mb' | 'mxt' | 'tr'
- ohlc: OHLCConfig;
- initialIndicators?: IndicatorsIds[];
- size?:
- | {
- width: number;
- height: number;
- }
- | false;
- mode?: ThemeMode; // 'light' | 'dark'
+export interface ChartCollectionPreset {
undoRedoEnabled?: boolean;
showMenuButton?: boolean;
showBottomPanel?: boolean;
@@ -77,13 +62,32 @@ export interface IMoexChart {
* }
*```
*/
- chartSettings?: ChartSettingsSource;
- chartOptions?: ChartTypeOptions; // todo: разнести по разным полям в соответствии с тиами графика
- tooltipConfig?: TooltipConfig;
+ tooltipConfig?: TooltipConfig; // todo: wrap into ChartCollectionSettings
+
+ size?:
+ | {
+ width: number;
+ height: number;
+ }
+ | false;
+ supportedTimeframes: Timeframes[];
+ supportedChartSeriesTypes: ChartSeriesType[];
+ getDataSource: DataSourceParams['getData'];
+ theme: ThemeKey; // 'mb' | 'mxt' | 'tr'
+ ohlc: OHLCConfig;
+ mode?: ThemeMode; // 'light' | 'dark'
openCompareModal?: () => void;
}
-export class MoexChart {
+export interface IMoexChart {
+ snapshot: MoexChartSnapshot; // todo: combine with snapshot
+ chartCollectionPreset: ChartCollectionPreset;
+
+ container: HTMLElement;
+ lwcInheritedChartOptions?: ChartTypeOptions;
+}
+
+export class MoexChart implements ISerializable<MoexChartSnapshot> {
private chart: Chart;
private resizeObserver?: ResizeObserver;
private eventManager: EventManager;
@@ -102,22 +106,30 @@ export class MoexChart {
private fullscreen: FullscreenController;
+ private chartCollectionPresetSettings: ChartCollectionPreset;
+
constructor(config: IMoexChart) {
- setPricePrecision(config.ohlc.precision);
+ this.setup(config)
+ }
+
+ private setup = (config: IMoexChart) => {
+ this.chartCollectionPresetSettings = config.chartCollectionPreset
+ setPricePrecision(config.chartCollectionPreset.ohlc.precision);
this.eventManager = new EventManager({
- initialTimeframe: config.initialTimeframe,
- initialSeries: config.initialChartSeriesTypes,
- initialSymbol: config.initialSymbol,
- initialChartOptions: config.chartOptions,
+ initialTimeframe: config.snapshot.charts[0].timeframe,
+ initialSeries: config.snapshot.charts[0].chartSeriesType,
+ initialSymbol: config.snapshot.charts[0].symbol,
+ initialChartOptions: config.lwcInheritedChartOptions,
});
- if (config.chartSettings) {
- this.setSettings(config.chartSettings);
- }
+ // todo: сюда прокидывается не подходящий под сигнатуру интерфейс. Функция не работает
+ // if (config.lwcInheritedChartOptions) {
+ // this.setSettings(config.lwcInheritedChartOptions);
+ // }
this.dataSource = new DataSource({
- getData: config.getDataSource,
+ getData: config.chartCollectionPreset.getDataSource,
eventManager: this.eventManager,
});
@@ -125,7 +137,7 @@ export class MoexChart {
this.fullscreen = new FullscreenController(this.rootContainer);
- const store = configureThemeStore(config);
+ const store = configureThemeStore(config.chartCollectionPreset);
const {
chartAreaContainer,
@@ -134,27 +146,31 @@ export class MoexChart {
modalContainer,
controlBarContainer,
footerContainer,
- toggleToolbar, // todo: move this function to toolbarRenderer
+ toggleToolbar, // todo: move this function to toolbarModel
} = ContainerManager.createContainers({
parentContainer: this.rootContainer,
- showBottomPanel: config.showBottomPanel, // todo: apply config.showBottomPanel in FullscreenController
- showMenuButton: config.showMenuButton,
+ showBottomPanel: config.chartCollectionPreset.showBottomPanel, // todo: apply config.showBottomPanel in FullscreenController
+ showMenuButton: config.chartCollectionPreset.showMenuButton,
});
this.modalRenderer = new ModalRenderer(modalContainer);
this.chart = new Chart({
- eventManager: this.eventManager,
- modalRenderer: this.modalRenderer,
- container: chartAreaContainer,
- theme: store.theme,
- mode: store.mode,
- seriesTypes: config.supportedChartSeriesTypes,
- dataSource: this.dataSource,
- chartOptions: config.chartOptions, // todo: remove, use only model from eventManager
- ohlcConfig: config.ohlc, // todo: omptimize
- tooltipConfig: config.tooltipConfig ?? {},
- initialIndicators: config.initialIndicators,
+ params: {
+ dataSource: this.dataSource,
+ eventManager: this.eventManager,
+ modalRenderer: this.modalRenderer,
+ ohlcConfig: config.chartCollectionPreset.ohlc, // todo: omptimize
+ tooltipConfig: config.chartCollectionPreset.tooltipConfig ?? {},
+ panes: config.snapshot.charts[0].panes
+ },
+ lwcChartConfig:{
+ container: chartAreaContainer,
+ seriesTypes: config.chartCollectionPreset.supportedChartSeriesTypes,
+ theme: store.theme,
+ mode: store.mode,
+ chartOptions: config.lwcInheritedChartOptions, // todo: remove, use only model from eventManager
+ }
});
this.subscriptions.add(
@@ -169,61 +185,110 @@ export class MoexChart {
this.headerRenderer = new ReactRenderer(headerContainer);
this.toolbarRenderer = new ReactRenderer(toolBarContainer);
- if (config.showControlBar) {
+ if (config.chartCollectionPreset.showControlBar) {
this.controlBarRenderer = new ReactRenderer(controlBarContainer);
}
- if (config.showBottomPanel) {
+ if (config.chartCollectionPreset.showBottomPanel) {
this.footerRenderer = new ReactRenderer(footerContainer);
}
+ this.timeScaleHoverController = new TimeScaleHoverController({
+ eventManager: this.eventManager,
+ controlBarContainer,
+ chartContainer: chartAreaContainer,
+ });
+
+ this.renderAttachments(config, toggleToolbar)
+ }
+
+ public setSettings(settings: ChartSettingsSource): void {
+ this.eventManager.importChartSettings(settings);
+ }
+
+ public getSettings(): ChartSettings {
+ return this.eventManager.exportChartSettings();
+ }
+
+ public getRealtimeApi() {
+ return this.chart.getRealtimeApi();
+ }
+
+ // todo: описать в доке
+ public getCompareManager(): CompareManager {
+ return this.chart.getCompareManager();
+ }
+
+ // todo: описать в доке
+ public setSnapshot(snap: MoexChartSnapshot) {
+ const configConstructorLike: IMoexChart = {
+ snapshot: snap,
+ chartCollectionPreset: this.chartCollectionPresetSettings,
+ container: this.rootContainer,
+ }
+ this.destroy()
+
+ this.setup(configConstructorLike)
+ }
+
+ // todo: описать в доке
+ public getSnapshot(): MoexChartSnapshot {
+ const res = {
+ settings: this.getSettings(),
+ charts: [this.chart.getSnapshot()], // todo: в будущем может быть несколько инстансов чартов
+ }
+
+ return res
+ }
+
+ public setSymbol(symbol: string): void {
+ if (!symbol) return;
+
+ this.eventManager.setSymbol(symbol);
+ }
+
+ private renderAttachments(config: IMoexChart, toggleToolbar: () => boolean) {
this.headerRenderer.renderComponent(
<Header
- timeframes={config.supportedTimeframes}
+ timeframes={config.chartCollectionPreset.supportedTimeframes}
selectedTimeframeObs={this.eventManager.getTimeframeObs()}
setTimeframe={(value) => {
this.eventManager.setTimeframe(value);
}}
- seriesTypes={config.supportedChartSeriesTypes}
+ seriesTypes={config.chartCollectionPreset.supportedChartSeriesTypes}
selectedSeriesObs={this.eventManager.getSelectedSeries()}
setSelectedSeries={(value) => {
this.eventManager.setSeriesSelected(value);
}}
showSettingsModal={
- config.showSettingsButton
+ config.chartCollectionPreset.showSettingsButton
? () =>
- this.modalRenderer.renderComponent(
- <SettingsModal
- // todo: deal with onSave
- changeTimeFormat={(format) => this.eventManager.setTimeFormat(format)}
- changeDateFormat={(format) => this.eventManager.setDateFormat(format)}
- chartDateTimeFormatObs={this.eventManager.getChartOptionsModel()}
- />,
- { title: 'Настройки' },
- )
+ this.modalRenderer.renderComponent(
+ <SettingsModal
+ // todo: deal with onSave
+ changeTimeFormat={(format) => this.eventManager.setTimeFormat(format)}
+ changeDateFormat={(format) => this.eventManager.setDateFormat(format)}
+ chartDateTimeFormatObs={this.eventManager.getChartOptionsModel()}
+ />,
+ { title: 'Настройки' },
+ )
: undefined
}
- addIndicatorToChart={(indicatorsType: IndicatorsIds) =>
- this.chart.getIndicatorManager().addIndicator(indicatorsType)
+ addIndicatorToChart={(indicatorType: IndicatorsIds) =>
+ this.chart.getIndicatorManager().addIndicator({ indicatorType })
}
- showMenuButton={config.showMenuButton}
- showFullscreenButton={config.showFullscreenButton}
+ showMenuButton={!!config.chartCollectionPreset.showMenuButton}
+ showFullscreenButton={!!config.chartCollectionPreset.showFullscreenButton}
fullscreen={this.fullscreen}
- undoRedo={config.undoRedoEnabled ? this.eventManager.getUndoRedo() : undefined}
+ undoRedo={config.chartCollectionPreset.undoRedoEnabled ? this.eventManager.getUndoRedo() : undefined}
toggleToolbarVisible={toggleToolbar}
- showCompareButton={!!config.showCompareButton}
- openCompareModal={config.openCompareModal ? config.openCompareModal : undefined}
- isMXT={config.theme === 'mxt'}
+ showCompareButton={!!config.chartCollectionPreset.showCompareButton}
+ openCompareModal={config.chartCollectionPreset.openCompareModal ? config.chartCollectionPreset.openCompareModal : undefined}
+ isMXT={config.chartCollectionPreset.theme === 'mxt'}
/>,
);
- this.timeScaleHoverController = new TimeScaleHoverController({
- eventManager: this.eventManager,
- controlBarContainer,
- chartContainer: chartAreaContainer,
- });
-
- if (config.showMenuButton) {
+ if (this.toolbarRenderer && config.chartCollectionPreset.showMenuButton) {
this.toolbarRenderer.renderComponent(
<Toolbar
toggleDOM={this.chart.getDom().toggleDOM}
@@ -239,7 +304,7 @@ export class MoexChart {
);
}
- if (this.controlBarRenderer && config.showControlBar) {
+ if (this.controlBarRenderer && config.chartCollectionPreset.showControlBar) {
this.controlBarRenderer.renderComponent(
<ControlBar
scroll={this.chart.scrollTimeScale}
@@ -250,10 +315,10 @@ export class MoexChart {
);
}
- if (this.footerRenderer && config.showBottomPanel) {
+ if (this.footerRenderer && config.chartCollectionPreset.showBottomPanel) {
this.footerRenderer.renderComponent(
<Footer
- supportedTimeframes={config.supportedTimeframes}
+ supportedTimeframes={config.chartCollectionPreset.supportedTimeframes}
setInterval={this.eventManager.setInterval}
intervalObs={this.eventManager.getInterval()}
/>,
@@ -261,29 +326,6 @@ export class MoexChart {
}
}
- public setSettings(settings: ChartSettingsSource): void {
- this.eventManager.importChartSettings(settings);
- }
-
- public getSettings(): ChartSettings {
- return this.eventManager.exportChartSettings();
- }
-
- public getRealtimeApi() {
- return this.chart.getRealtimeApi();
- }
-
- // todo: описать в доке
- public getCompareManager(): CompareManager {
- return this.chart.getCompareManager();
- }
-
- public setSymbol(symbol: string): void {
- if (!symbol) return;
-
- this.eventManager.setSymbol(symbol);
- }
-
/**
* Уничтожение графика и очистка ресурсов
* @returns void
diff --git a/src/core/Pane.tsx b/src/core/Pane.tsx
index 75a0fb608b816edcfaa0f7f36436cf37519716ea..3eb3a91aff04accb3b7d08b54a580527b643ca42 100644
--- a/src/core/Pane.tsx
+++ b/src/core/Pane.tsx
@@ -1,3 +1,4 @@
+import { ISerializable, PaneSnapshot } from '@src/types/snapshot';
import { IChartApi, IPaneApi, Time } from 'lightweight-charts';
import { BehaviorSubject, Subscription } from 'rxjs';
@@ -44,7 +45,7 @@ export interface PaneParams {
// todo: на каждый символ свой DataSource (учитывать что есть MainPane и "главный" DataSource, который инициализиурется во время старта moexChart)
// todo: сделать два разных представления для compare, в зависимости от отображения на главном пейне или на второстепенном
-export class Pane {
+export class Pane implements ISerializable<PaneSnapshot>{
private readonly id: number;
private isMain: boolean;
private mainSeries: BehaviorSubject<SeriesStrategies | null> = new BehaviorSubject<SeriesStrategies | null>(null); // Main Series. Exists in a single copy
@@ -141,7 +142,6 @@ export class Pane {
});
this.subscriptions.add(
- // todo: переедет в пейн
this.drawingsManager.entities().subscribe((drawings) => {
const hasRuler = drawings.some((drawing) => drawing.getDrawingName() === DrawingsNames.ruler);
this.legendContainer.style.display = hasRuler ? 'none' : '';
@@ -294,6 +294,23 @@ export class Pane {
});
}
+ public getSnapshot(): PaneSnapshot {
+ const indicators = []
+
+ this.indicatorsMap.value.forEach((ind) => {
+ indicators.push(ind.getSnapshot())
+ })
+
+ const snap = {
+ isMain: this.isMain,
+ id: this.id,
+ indicators,
+ drawings: this.getDrawingsSnapshot()
+ }
+
+ return snap
+ }
+
public destroy() {
this.subscriptions.unsubscribe();
this.tooltip?.destroy();
@@ -303,6 +320,8 @@ export class Pane {
this.tooltipRenderer?.destroy();
this.indicatorsMap.complete();
+ this.mainSeries.value?.destroy();
+ this.mainSeries?.complete();
this.mainSerieSub?.unsubscribe();
try {
this.lwcChart.removePane(this.id);
diff --git a/src/core/PaneManager.ts b/src/core/PaneManager.ts
index 5bbbc00d5717f42aabeb9535b7a7fb46c633407b..d97d6b60b0b96e25da5b9122936df918a6187912 100644
--- a/src/core/PaneManager.ts
+++ b/src/core/PaneManager.ts
@@ -1,8 +1,11 @@
import { DataSource } from '@core/DataSource';
import { DrawingsManager, DrawingsManagerSnapshot } from '@core/DrawingsManager';
import { Pane, PaneParams } from '@core/Pane';
+import { ISerializable, PaneSnapshot } from '@src/types/snapshot';
-type PaneManagerParams = Omit<PaneParams, 'isMainPane' | 'id' | 'basedOn' | 'onDelete'>;
+interface PaneManagerParams extends Omit<PaneParams, 'isMainPane' | 'id' | 'basedOn' | 'onDelete'> {
+ panesSnapshot: PaneSnapshot[]
+};
// todo: PaneManager, регулирует порядок пейнов. Знает про MainPane.
// todo: Также перекинуть соответствующие/необходимые свойства из чарта, и из чарта удалить
@@ -10,7 +13,8 @@ type PaneManagerParams = Omit<PaneParams, 'isMainPane' | 'id' | 'basedOn' | 'onD
// todo: на каждый символ свой DataSource (учитывать что есть MainPane и "главный" DataSource, который инициализиурется во время старта moexChart)
// todo: сделать два разных представления для compare, в зависимости от отображения на главном пейне или на второстепенном
-export class PaneManager {
+
+export class PaneManager implements ISerializable<PanesSnapshot> {
private mainPane: Pane;
private paneChartInheritedParams: PaneManagerParams & { isMainPane: boolean };
private panesMap: Map<number, Pane> = new Map<number, Pane>();
@@ -22,6 +26,39 @@ export class PaneManager {
this.mainPane = new Pane({ ...params, isMainPane: true, id: 0, onDelete: () => {} });
this.panesMap.set(this.panesIdIterator++, this.mainPane);
+ this.setup(params.panesSnapshot)
+
+ }
+
+ private setup(panesSnapshot: PaneSnapshot[]) {
+ panesSnapshot.forEach((paneSnap: PaneSnapshot) => {
+ const {
+ isMain,
+ id,
+ indicators,
+ drawings
+ } = paneSnap
+
+
+ if(this.panesMap.has(id)){
+ this.panesMap.get(id).destroy()
+ }
+
+ if(isMain){
+ this.mainPane = new Pane({ ...this.paneChartInheritedParams, isMainPane: true, id: 0, onDelete: () => {} });
+
+ this.panesMap.set(id, this.mainPane);
+
+ this.mainPane.setDrawingsSnapshot(drawings)
+ } else {
+ const pane = this.addPane()
+ pane.setDrawingsSnapshot(drawings)
+ }
+ })
+ }
+
+ public getPaneById(id: number): Pane {
+ return this.panesMap.get(id);
}
public getDrawingsSnapshot(): DrawingsManagerSnapshot {
@@ -63,4 +100,13 @@ export class PaneManager {
// todo: temp
return this.mainPane.getDrawingManager();
}
+
+ public getSnapshot(): PaneSnapshot[] {
+ const res: PaneSnapshot[] = []
+ this.panesMap.forEach((pane) => {
+ res.push(pane.getSnapshot())
+ })
+
+ return res
+ }
}
diff --git a/src/types/snapshot.ts b/src/types/snapshot.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a18c1be36a0fcb15f3ebf240d9a83f00454d6b4
--- /dev/null
+++ b/src/types/snapshot.ts
@@ -0,0 +1,50 @@
+import { ChartSettings as ChartSettingsSnapshot, ChartSettingsSource } from '@core/ChartSettings';
+import { DataSource } from '@core/DataSource';
+import { DrawingsManagerSnapshot } from '@core/DrawingsManager';
+import { ChartSeriesType, IndicatorsIds, Timeframes } from '@lib';
+import { IndicatorConfig } from '@src/types/indicator';
+
+export interface ISerializable<T extends object> {
+ getSnapshot: () => T;
+}
+
+export type InitialSnapshot = {
+ timeframe: Timeframes; // todo: move to snap
+ chartSeriesType: ChartSeriesType; // todo: move to snap
+ symbol: string; // todo: move to snap
+}
+
+export type MoexChartSnapshot = {
+ // settings: ChartSettingsSnapshot;
+ charts: ChartSnapshot[];
+}
+
+export type ChartSnapshot = {
+ timeframe: Timeframes;
+ chartSeriesType: ChartSeriesType;
+ symbol: string;
+ panes: PaneSnapshot[];
+}
+
+export type PaneSnapshot = {
+ isMain: boolean,
+ id: number,
+ indicators: IndicatorSnapshot[]
+ drawings: DrawingsManagerSnapshot
+}
+
+export type IndicatorSnapshot = Partial<DOMObjectSnapshot> & {
+ dataSource?: DataSource,
+ indicatorType: IndicatorsIds | undefined, // if indicatorType is undefined, then its compareIndicator
+ config?: IndicatorConfig,
+}
+
+// todo: move DrawingsManagerSnapshot here
+
+export type DOMObjectSnapshot = {
+ id: string;
+ name: string;
+ zIndex: number;
+ hidden: boolean;
+ paneId: number;
+}
\ No newline at end of file
diff --git a/stories/MB/MB.stories.tsx b/stories/MB/MB.stories.tsx
index 54add23fc11a3d2db82dc9c7e28d0fb07e6d27f1..b2ce1a017c63c11e076794e0a50c494519eb4fc1 100644
--- a/stories/MB/MB.stories.tsx
+++ b/stories/MB/MB.stories.tsx
@@ -23,6 +23,7 @@ import 'moex-chart/dist/styles.css';
type MBProps = Omit<IMoexChart, 'container'>;
+// todo: переписат ьпод новую сигнатуру
const MBEntry = (props: MBProps) => {
const [isCompareOpen, setIsCompareOpen] = useState(false);
const [moexChart, setMoexChart] = useState<MoexChart | undefined>(undefined);
@@ -91,53 +92,72 @@ export default meta;
type Story = StoryObj<typeof meta>;
const args: MBProps = {
- supportedTimeframes: [
- Timeframes['1s'],
- Timeframes['5s'],
- Timeframes['10s'],
- Timeframes['1m'],
- Timeframes['2m'],
- Timeframes['30m'],
- Timeframes['1h'],
- Timeframes['2h'],
- Timeframes['1d'],
- Timeframes['1w'],
- ],
- initialTimeframe: Timeframes['10s'],
- supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
- initialChartSeriesTypes: 'Candlestick',
- initialSymbol: 'APPL',
- initialIndicators: [IndicatorsIds.Volume],
- getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
- theme: 'mb',
- ohlc: {
- show: true,
- precision: 4,
+ snapshot:{
+ charts: [{
+ timeframe: Timeframes['10s'],
+ chartSeriesType: 'Candlestick',
+ symbol: '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: []
+ }
+ ],
+ }],
},
- mode: 'dark',
- chartOptions: {
+ 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['1d'],
+ Timeframes['1w'],
+ ],
+ supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
+ getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
+ theme: 'mb',
+ ohlc: {
+ show: true,
+ precision: 4,
+ },
+ mode: 'dark',
+ },
+
+ lwcInheritedChartOptions: {
timeVisible: true,
secondsVisible: false,
timeFormat: '24h',
dateFormat: DateFormat.DD_MM_YYYY_HH_mm_ss,
},
- showMenuButton: true,
- showBottomPanel: true,
- showFullscreenButton: true,
- showCompareButton: false,
- showSettingsButton: true,
- showControlBar: true,
- 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: 'Мин.' },
- },
- undoRedoEnabled: true,
};
export const MB: Story = {
diff --git a/stories/MXT/MXT.stories.tsx b/stories/MXT/MXT.stories.tsx
index 97708742b37df00786bd5d01eee704895af3892a..2a905d06db023345725bdbbbbcbcab9c46fe2b4b 100644
--- a/stories/MXT/MXT.stories.tsx
+++ b/stories/MXT/MXT.stories.tsx
@@ -18,7 +18,7 @@ import 'moex-chart/dist/styles.css';
*/
export type MXTProps = Omit<IMoexChart, 'container'>;
-
+// todo: переписат ьпод новую сигнатуру
const MXTEntry = (props: MXTProps) => {
const containerRef = useRef<HTMLDivElement | null>(null);
@@ -71,49 +71,70 @@ export default meta;
type Story = StoryObj<typeof meta>;
const args: MXTProps = {
- supportedTimeframes: [
- Timeframes['1m'],
- Timeframes['10m'],
- Timeframes['1h'],
- Timeframes['1d'],
- Timeframes['1w'],
- Timeframes['1М'],
- Timeframes['3М'],
- ],
- initialTimeframe: Timeframes['1m'],
- supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
- initialChartSeriesTypes: 'Candlestick',
- initialSymbol: 'APPL',
- initialIndicators: [IndicatorsIds.Volume],
- getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
- theme: 'mxt',
- ohlc: {
- show: false,
- precision: 6,
+ snapshot:{
+ charts: [{
+ timeframe: Timeframes['1m'],
+ chartSeriesType: 'Candlestick',
+ symbol: '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: []
+ }
+ ],
+ }],
},
- mode: 'light',
- chartOptions: {
+ chartCollectionPreset: {
+ undoRedoEnabled: false,
+ showMenuButton: false,
+ showBottomPanel: false,
+ showControlBar: false,
+ showFullscreenButton: false,
+ showSettingsButton: false,
+ showCompareButton: false,
+
+ tooltipConfig: {
+ showTooltip: true,
+ 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['1m'],
+ Timeframes['10m'],
+ Timeframes['1h'],
+ Timeframes['1d'],
+ Timeframes['1w'],
+ Timeframes['1М'],
+ Timeframes['3М'],
+ ],
+ supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
+ getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
+ theme: 'mxt',
+ ohlc: {
+ show: false,
+ precision: 6,
+ },
+ mode: 'light',
+ },
+
+ lwcInheritedChartOptions: {
timeVisible: true,
secondsVisible: false,
timeFormat: '24h',
dateFormat: DateFormat.DD_MM_YYYY_HH_mm_ss,
},
- showMenuButton: false,
- showBottomPanel: false,
- showFullscreenButton: false,
- showCompareButton: false,
- showSettingsButton: false,
- showControlBar: false,
- tooltipConfig: {
- showTooltip: true,
- 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: 'Мин.' },
- },
};
export const MXT: Story = {
diff --git a/stories/TradeRadar/TradeRadar.stories.tsx b/stories/TradeRadar/TradeRadar.stories.tsx
index 10e2e9a4787dedec575df335bd6ce3e436bd49bb..c4b07ce9d7d20a199e0b8c5e8a32a7bcf34bfe58 100644
--- a/stories/TradeRadar/TradeRadar.stories.tsx
+++ b/stories/TradeRadar/TradeRadar.stories.tsx
@@ -1,11 +1,13 @@
+import { DataSource } from '@core/DataSource';
+import { DrawingsSnapshot, IndicatorSnapshot } from '@src/types/snapshot';
import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { CompareManager } from '@core/CompareManager';
-import { DateFormat, IMoexChart, MoexChart, Timeframes } from '@lib';
+import { ChartSeriesType, DateFormat, IMoexChart, Intervals, MoexChart, Timeframes } from '@lib';
import { IndicatorsIds } from '@lib/constants';
-import { CompareMode } from '@lib/types';
+import { CompareMode, IndicatorConfig, TimeFormat } from '@lib/types';
import { argTypes } from '../argTypes';
@@ -25,6 +27,7 @@ type TRProps = Omit<IMoexChart, 'container'>;
const TREntry = (props: TRProps) => {
const [isCompareOpen, setIsCompareOpen] = useState(false);
const [moexChart, setMoexChart] = useState<MoexChart | undefined>(undefined);
+ const [snap, setSnap] = useState<any | undefined>(undefined);
const containerRef = useRef<HTMLDivElement | null>(null);
@@ -38,7 +41,10 @@ const TREntry = (props: TRProps) => {
const chart = new MoexChart({
...props,
container,
- openCompareModal: () => setIsCompareOpen(true),
+ chartCollectionPreset: {
+ ...props.chartCollectionPreset,
+ openCompareModal: () => setIsCompareOpen(true),
+ }
});
setMoexChart(chart);
@@ -54,6 +60,18 @@ const TREntry = (props: TRProps) => {
return (
<div style={{ padding: '20px' }}>
<h3>TradeRadar usage</h3>
+ <button
+ type={'button'}
+ onClick={() => {
+ setSnap(moexChart?.getSnapshot())
+ }}
+ >Сохранить стейт</button>
+ <button
+ type={'button'}
+ onClick={() => {
+ moexChart?.setSnapshot(snap)
+ }}
+ >Применить стейт</button>
<div style={{ height: 'calc(100vh - 64px)', width: '100%' }}>
<div ref={containerRef} />
{isCompareOpen &&
@@ -89,53 +107,82 @@ export default meta;
type Story = StoryObj<typeof meta>;
const args: TRProps = {
- supportedTimeframes: [
- Timeframes['1s'],
- Timeframes['5s'],
- Timeframes['10s'],
- Timeframes['1m'],
- Timeframes['2m'],
- Timeframes['30m'],
- Timeframes['1h'],
- Timeframes['2h'],
- Timeframes['1d'],
- Timeframes['1w'],
- ],
- initialTimeframe: Timeframes['10s'],
- supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
- initialChartSeriesTypes: 'Candlestick',
- initialSymbol: 'APPL',
- initialIndicators: [IndicatorsIds.Volume],
- getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
- theme: 'tr',
- ohlc: {
- show: true,
- precision: 4,
+ snapshot:{
+ charts: [{
+ timeframe: Timeframes['10s'],
+ chartSeriesType: 'Candlestick',
+ symbol: '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: []
+ },
+ {
+ isMain: false,
+ id: 1,
+ indicators: [
+ {
+ indicatorType: IndicatorsIds.MACD,
+ },
+ ],
+ drawings: []
+ },
+ ],
+ }],
+ },
+ chartCollectionPreset: {
+ undoRedoEnabled: true,
+ showMenuButton: true,
+ showBottomPanel: true,
+ showControlBar: true,
+ showFullscreenButton: true,
+ showSettingsButton: true,
+ showCompareButton: true,
+ 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['1d'],
+ Timeframes['1w'],
+ ],
+ supportedChartSeriesTypes: ['Candlestick', 'Line', 'Bar'],
+ getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
+ theme: 'tr',
+ ohlc: {
+ show: true,
+ precision: 4,
+ },
+ mode: 'dark',
},
- mode: 'dark',
- chartOptions: {
+
+ lwcInheritedChartOptions: {
timeVisible: true,
secondsVisible: false,
timeFormat: '24h',
dateFormat: DateFormat.DD_MM_YYYY_HH_mm_ss,
},
- showMenuButton: true,
- showBottomPanel: true,
- showFullscreenButton: true,
- showCompareButton: true,
- showSettingsButton: true,
- showControlBar: true,
- 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: 'Мин.' },
- },
- undoRedoEnabled: true,
};
export const TradeRadar: Story = {