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


import { IChartApi, Time } from 'lightweight-charts';
import { BehaviorSubject, Observable } from 'rxjs';

import { DataSource } from '@core/DataSource';
import { DOMObject, DOMObjectParams } from '@core/DOMObject';
import { IndicatorsIds, indicatorsMap, labelByIndicatorId } from '@core/Indicators';

import { getDefaultMaIndicatorSettings, MaIndicatorSettings } from '@src/core/Indicators/settings';
import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
import { ChartTypeOptions } from '@src/types';
import { IndicatorLegendItem, LegendValueItem } from '@src/types/legend';
import { ensureDefined } from '@src/utils';

type IIndicator = DOMObject;

interface IndicatorParams extends DOMObjectParams {
  mainSymbol$: Observable<string>;
  mainSerie$: BehaviorSubject<SeriesStrategies | null>;
  lwcChart: IChartApi;
  dataSource: DataSource;
  chartOptions?: ChartTypeOptions;
}

export class Indicator extends DOMObject implements IIndicator {
  private series: SeriesStrategies[] = [];
  private seriesMap = new Map<string, SeriesStrategies>();
  private legendSeriesIds: string[] = [];
  private legendSeriesColors = new Map<string, string | undefined>();

  private readonly chartApi: IChartApi;
  private readonly dataSource: DataSource;
  private readonly chartOptions?: ChartTypeOptions;
  private readonly mainSeries: BehaviorSubject<SeriesStrategies | null>;
  private readonly mainSymbol: Observable<string>;

  private maSettings: MaIndicatorSettings | null;

  constructor({
    id,
    lwcChart,
    dataSource,
    chartOptions,
    zIndex,
    onDelete,
    moveUp,
    moveDown,
    mainSerie$,
    mainSymbol$,
  }: IndicatorParams) {
    super({ id: id as string, zIndex, onDelete, moveUp, moveDown });

    this.chartApi = lwcChart;
    this.dataSource = dataSource;
    this.chartOptions = chartOptions;
    this.mainSeries = mainSerie$;
    this.mainSymbol = mainSymbol$;
    this.maSettings = getDefaultMaIndicatorSettings(id as IndicatorsIds);

    this.buildSeries();
  }

  private buildSeries(): void {
    this.series = [];
    this.seriesMap.clear();
    this.legendSeriesIds = [];
    this.legendSeriesColors.clear();

    const indicatorConfig = ensureDefined(indicatorsMap[this.id as IndicatorsIds]);
    const { series, paneIndex } = indicatorConfig;

    series.forEach(
      ({ name, id: seriesId, dataFormatter, seriesOptions, priceScaleOptions, legendVisible, legendColor }) => {
        const strategy = SeriesFactory.create(name!)({
          lwcChart: this.chartApi,
          dataSource: this.dataSource,
          customFormatter: dataFormatter,
          seriesOptions,
          chartOptions: this.chartOptions,
          priceScaleOptions,
          mainSymbol$: this.mainSymbol,
          mainSerie$: this.mainSeries,
          showSymbolLabel: false,
          paneIndex,
          indicatorReference: this,
        });

        this.seriesMap.set(seriesId, strategy);
        this.series.push(strategy);

        if (legendVisible !== false) {
          this.legendSeriesIds.push(seriesId);
          this.legendSeriesColors.set(seriesId, legendColor);
        }
      },
    );
  }

  private rebuildSeries(): void {
    this.series.forEach((series) => {
      series.destroy();
    });

    this.buildSeries();
  }

  public getIndicatorSettings(): MaIndicatorSettings | null {
    return this.maSettings ? { ...this.maSettings } : null;
  }

  public updateIndicatorSettings(nextSettings: MaIndicatorSettings): void {
    if (!this.maSettings) {
      return;
    }

    this.maSettings = { ...nextSettings };
    this.rebuildSeries();
  }

  public resetIndicatorSettings(): void {
    const defaultSettings = getDefaultMaIndicatorSettings(this.id as IndicatorsIds);

    if (!defaultSettings) {
      return;
    }

    this.maSettings = defaultSettings;
    this.rebuildSeries();
  }

  public getLegendItem(time?: Time): IndicatorLegendItem {
    const indicatorId = this.id as IndicatorsIds;

    const values = this.legendSeriesIds
      .map((seriesId): LegendValueItem | null => {
        const strategy = this.seriesMap.get(seriesId);

        if (!strategy) {
          return null;
        }

        const value = strategy.getLegendValue(time);

        if (value == null) {
          return null;
        }

        return {
          id: `${indicatorId}-${seriesId}`,
          value,
          color: this.legendSeriesColors.get(seriesId) ?? strategy.getLegendColor(time) ?? '',
        };
      })
      .filter((item): item is LegendValueItem => item != null);

    return {
      id: indicatorId,
      label: labelByIndicatorId[indicatorId],
      values,
    };
  }

  public getSeriesMap() {
    return this.seriesMap;
  }

  public delete(): void {
    super.delete();
  }

  public show(): void {
    this.series.forEach((series) => {
      series.show();
    });
    super.show();
  }

  public hide(): void {
    this.series.forEach((series) => {
      series.hide();
    });
    super.hide();
  }

  public destroy(): void {
    this.series.forEach((series) => {
      series.destroy();
    });
  }
}