Загрузка данных
import { IChartApi } from 'lightweight-charts';
import { BehaviorSubject, Observable, throttleTime } from 'rxjs';
import { DataSource } from '@core/DataSource';
import { DOMObject, DOMObjectParams } from '@core/DOMObject';
import { IndicatorConfig, IndicatorsIds, indicatorsMap } from '@core/Indicators';
import { Pane } from '@core/Pane';
import { PaneManager } from '@core/PaneManager';
import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
import { ChartTypeOptions } from '@src/types';
import { ensureDefined } from '@src/utils';
type IIndicator = DOMObject;
export interface IndicatorParams extends DOMObjectParams {
mainSymbol$: Observable<string>;
lwcChart: IChartApi;
dataSource: DataSource;
paneManager: PaneManager;
chartOptions?: ChartTypeOptions;
config?: IndicatorConfig;
}
export class Indicator extends DOMObject implements IIndicator {
private series: SeriesStrategies[] = [];
private seriesMap: Map<string, SeriesStrategies> = new Map();
private lwcChart: IChartApi;
private associatedPane: Pane;
constructor({
id,
lwcChart,
dataSource,
zIndex,
onDelete,
moveUp,
moveDown,
mainSymbol$,
paneManager,
config,
}: IndicatorParams) {
super({ id: id as string, zIndex, onDelete, moveUp, moveDown });
this.lwcChart = lwcChart;
const indicatorConfig = indicatorsMap[id as IndicatorsIds] ?? config;
const { series, newPane } = ensureDefined(indicatorConfig);
this.associatedPane = newPane ? paneManager.addPane() : paneManager.getMainPane();
series.forEach(({ name, id: serieId, dataFormatter, seriesOptions, priceScaleOptions }) => {
const serie = SeriesFactory.create(name!)({
lwcChart,
dataSource,
customFormatter: dataFormatter,
seriesOptions,
priceScaleOptions,
mainSymbol$,
mainSerie$: this.associatedPane.getMainSerie(),
showSymbolLabel: false,
paneIndex: this.associatedPane.getId(),
indicatorReference: this,
});
this.seriesMap.set(serieId, serie);
this.series.push(serie);
});
this.associatedPane.setIndicator(id as IndicatorsIds, this);
}
public subscribeDataChange(handler: () => void): void {
// todo: возможно нужно переписать завязавшись гна this.associatedPane.getMainSerie()
const firer = new BehaviorSubject<number>(0);
this.series.forEach((serie) => {
serie.subscribeDataChanged(() => {
firer.next(firer.value + 1);
});
});
firer.pipe(throttleTime(500)).subscribe(() => {
handler();
});
}
public getSeriesMap(): Map<string, SeriesStrategies> {
return this.seriesMap;
}
public delete() {
super.delete();
this.associatedPane.removeIndicator(this.id as IndicatorsIds);
}
public show() {
this.series.forEach((s) => {
s.show();
});
super.show();
}
public hide() {
this.series.forEach((s) => {
s.hide();
});
super.hide();
}
public destroy() {
this.series.forEach((s) => {
s.destroy();
});
}
}
import { IChartApi } from 'lightweight-charts';
import { BehaviorSubject, map, Observable } from 'rxjs';
import { DataSource } from '@core/DataSource';
import { DOMModel } from '@core/DOMModel';
import { EventManager } from '@core/EventManager';
import { Indicator } from '@core/Indicator';
import { IndicatorsIds } from '@core/Indicators';
import { PaneManager } from '@core/PaneManager';
import { DOMObject } from '@src/core/DOMObject';
import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
import { ChartTypeOptions } from '@src/types';
interface SeriesParams {
eventManager: EventManager;
dataSource: DataSource;
mainSerie$: BehaviorSubject<SeriesStrategies | null>;
lwcChart: IChartApi;
paneManager: PaneManager;
DOM: DOMModel;
chartOptions?: ChartTypeOptions;
}
export class IndicatorManager {
private eventManager: EventManager;
private lwcChart: IChartApi;
private chartOptions?: ChartTypeOptions;
private entities$: BehaviorSubject<Indicator[]> = new BehaviorSubject<Indicator[]>([]);
private indicatorSeriesMap$: BehaviorSubject<Map<IndicatorsIds, Indicator>> = new BehaviorSubject(new Map());
private DOM: DOMModel;
constructor({ eventManager, dataSource, lwcChart, DOM, chartOptions, mainSerie$, paneManager }: SeriesParams) {
this.eventManager = eventManager;
this.lwcChart = lwcChart;
this.chartOptions = chartOptions;
this.DOM = DOM;
this.eventManager.getUserIndicatorsList().subscribe((ids: Set<IndicatorsIds>) => {
const indicatorSeriesMap = new Map(this.indicatorSeriesMap$.value);
ids.forEach((id: IndicatorsIds) => {
if (!indicatorSeriesMap.has(id)) {
const ind = this.addEntity<Indicator>(
(zIndex: number, moveUp: (id: string) => void, moveDown: (id: string) => void) =>
new Indicator({
id,
lwcChart,
mainSymbol$: this.eventManager.getSymbol(),
dataSource,
chartOptions,
zIndex,
onDelete: this.deleteIndicator,
moveUp,
moveDown,
paneManager,
}),
);
indicatorSeriesMap.set(id, ind);
}
});
// todo: move to deleteSeries
const seriesToDelete = Array.from(indicatorSeriesMap.keys()).filter((existingKey) => {
return !ids.has(existingKey);
});
seriesToDelete.forEach((s: IndicatorsIds) => {
// todo: move to deleteSeries
const serieToDestroy = indicatorSeriesMap.get(s);
if (!serieToDestroy) return;
this.removeEntity(serieToDestroy);
serieToDestroy.destroy();
indicatorSeriesMap.delete(s);
});
this.indicatorSeriesMap$.next(indicatorSeriesMap);
this.entities$.next(Array.from(indicatorSeriesMap.values()));
});
}
public addEntity<T extends Indicator>(
factory: (zIndex: number, moveUp: (id: string) => void, moveDown: (id: string) => void) => T,
): T {
return this.DOM.setEntity(factory);
}
public removeEntity(entity: DOMObject): void {
this.DOM.removeEntity(entity);
}
public deleteIndicator = (id: string) => {
this.eventManager.toggleUserIndicator(id as IndicatorsIds);
};
public entities(): Observable<Indicator[]> {
return this.entities$.asObservable();
}
public activeIndicators(): Observable<IndicatorsIds[]> {
return this.indicatorSeriesMap$.pipe(map((indicators) => Array.from(indicators.keys())));
}
}