Загрузка данных


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())));
  }
}