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


import { IChartApi, ISeriesApi, SeriesType } from 'lightweight-charts';
import { BehaviorSubject, distinctUntilChanged, Observable, Subscription } from 'rxjs';

import { DOMObject, DOMObjectParams } from '@core/DOMObject';
import { DrawingInteraction, ISeriesDrawing } from '@core/Drawings/common';
import { DrawingSnapshotItem } from '@core/DrawingsManager';
import { Hotkeys, Keys } from '@core/Hotkeys';

import { DrawingsNames } from '@src/constants';
import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
import { SettingsTab, SettingsValues, ToolbarSettingField } from '@src/types/settings';

type IDrawing = DOMObject;

interface DrawingParams extends DOMObjectParams {
  drawingName: DrawingsNames;
  lwcChart: IChartApi;
  mainSeries: SeriesStrategies;
  onDelete: (id: string) => void;
  construct: (
    chart: IChartApi,
    series: ISeriesApi<SeriesType>,
    interaction: DrawingInteraction,
  ) => ISeriesDrawing;
  selected$: Observable<boolean>;
  isSelected: () => boolean;
  select: () => void;
  isLocked?: boolean;
  hotkeys: Hotkeys;
  setCopyPasteBuffer: (copiedObject: DrawingSnapshotItem) => void;
  resetActiveTool: () => void;
}

export class Drawing extends DOMObject implements IDrawing {
  private lwcDrawing: ISeriesDrawing;
  private mainSeries: SeriesStrategies;
  private drawingName: DrawingsNames;
  private hotkeys: Hotkeys;
  private lockedSubject: BehaviorSubject<boolean>;
  private subscriptions = new Subscription();

  private escapeUnregisterHash: string | null = null;
  private deleteUnregisterHash: string | null = null;
  private copyUnregisterHash: string | null = null;

  constructor({
    lwcChart,
    name,
    mainSeries,
    drawingName,
    id,
    onDelete,
    zIndex,
    moveUp,
    moveDown,
    construct,
    selected$,
    isSelected,
    select,
    isLocked = false,
    paneId,
    hotkeys,
    setCopyPasteBuffer,
    resetActiveTool,
  }: DrawingParams) {
    super({ id, name, zIndex, onDelete, moveUp, moveDown, paneId });

    this.hotkeys = hotkeys;
    this.mainSeries = mainSeries;
    this.drawingName = drawingName;
    this.lockedSubject = new BehaviorSubject(isLocked);

    const interaction: DrawingInteraction = {
      selected$,
      locked$: this.lockedSubject.pipe(distinctUntilChanged()),
      isSelected,
      isLocked: () => this.lockedSubject.value,
      select,
    };

    this.lwcDrawing = construct(lwcChart, mainSeries, interaction);
    this.onDelete = onDelete;

    this.escapeUnregisterHash = hotkeys.register({
      keys: [Keys.escape],
      callback: () => {
        this.delete();
        resetActiveTool();
      },
    });

    this.subscriptions.add(
      selected$.subscribe((isSelected) => {
        if (isSelected) {
          this.registerSelectedHotkeys(setCopyPasteBuffer);

          return;
        }

        this.unregisterSelectedHotkeys();
      }),
    );

    this.afterCreation(() => {
      hotkeys.unregister({
        keys: [Keys.escape],
        hash: this.escapeUnregisterHash,
      });

      this.escapeUnregisterHash = null;
    });
  }

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

  public getDrawingName(): DrawingsNames {
    return this.drawingName;
  }

  public getLwcDrawing(): ISeriesDrawing {
    return this.lwcDrawing;
  }

  public show(): void {
    this.lwcDrawing.show();
    super.show();
  }

  public hide(): void {
    this.lwcDrawing.hide();
    super.hide();
  }

  public rebind = (nextMainSeries: SeriesStrategies): void => {
    this.lwcDrawing.rebind(nextMainSeries);
    this.mainSeries = nextMainSeries;
  };

  public isCreationPending(): boolean {
    return this.lwcDrawing.isCreationPending();
  }

  public subscribeIsLocked(callback: (isLocked: boolean) => void): Subscription {
    return this.lockedSubject.pipe(distinctUntilChanged()).subscribe(callback);
  }

  public subscribeSettings(callback: (settings: SettingsValues) => void): Subscription {
    return this.lwcDrawing.subscribeSettings(callback);
  }

  public isLocked(): boolean {
    return this.lockedSubject.value;
  }

  public toggleLock(): void {
    this.lockedSubject.next(!this.lockedSubject.value);
  }

  public async waitForCreation(): Promise<void> {
    return this.lwcDrawing.waitTillReady();
  }

  public shouldShowInObjectTree(): boolean {
    return this.lwcDrawing.shouldShowInObjectTree();
  }

  public getState(): unknown {
    return this.lwcDrawing.getState();
  }

  public setState(state: unknown): void {
    this.lwcDrawing.setState(state);
  }

  public getSettings(): SettingsValues {
    return this.lwcDrawing.getSettings();
  }

  public updateSettings(settings: SettingsValues): void {
    this.lwcDrawing.updateSettings(settings);
  }

  public getSettingsTabs(): SettingsTab[] {
    return this.lwcDrawing.getSettingsTabs();
  }

  public getToolbarSettings(): ToolbarSettingField[] {
    return this.getSettingsTabs()
      .flatMap((tab) => tab.fields)
      .filter((field): field is ToolbarSettingField => field.toolbar !== undefined);
  }

  public hasSettings(): boolean {
    return this.getSettingsTabs().some((tab) => tab.fields.length > 0);
  }

  public destroy(): void {
    this.subscriptions.unsubscribe();
    this.unregisterSelectedHotkeys();

    this.hotkeys.unregister({
      keys: [Keys.escape],
      hash: this.escapeUnregisterHash,
    });

    this.lockedSubject.complete();
    this.mainSeries.detachPrimitive(this.lwcDrawing);
    this.lwcDrawing.destroy();
  }

  private registerSelectedHotkeys(
    setCopyPasteBuffer: (copiedObject: DrawingSnapshotItem) => void,
  ): void {
    this.deleteUnregisterHash = this.hotkeys.register({
      keys: [Keys.delete],
      callback: () => {
        this.delete();
      },
    });

    this.copyUnregisterHash = this.hotkeys.register({
      keys: [Keys.control, Keys.c],
      callback: () => {
        if (this.isCreationPending()) {
          return;
        }

        setCopyPasteBuffer({
          id: this.id,
          drawingName: this.getDrawingName(),
          state: this.getState(),
          isLocked: this.isLocked(),
        });
      },
    });
  }

  private unregisterSelectedHotkeys(): void {
    this.hotkeys.unregister({
      keys: [Keys.delete],
      hash: this.deleteUnregisterHash,
    });

    this.hotkeys.unregister({
      keys: [Keys.control, Keys.c],
      hash: this.copyUnregisterHash,
    });

    this.deleteUnregisterHash = null;
    this.copyUnregisterHash = null;
  }

  private async afterCreation(callback: () => void): Promise<void> {
    await this.lwcDrawing.waitTillReady();
    callback();
  }
}


import { IChartApi, ISeriesApi, SeriesType } from 'lightweight-charts';

import { DrawingsNames } from '@src/constants';
import { EventManager } from '@src/core';
import { DrawingInteraction, ISeriesDrawing } from '@src/core/Drawings/common';

export type ActiveDrawingTool = DrawingsNames | 'crosshair';

interface DrawingParams {
  chart: IChartApi;
  series: ISeriesApi<SeriesType>;
  eventManager: EventManager;
  container: HTMLElement;
  interaction: DrawingInteraction;
  removeSelf: () => void;
  openSettings: () => void;
}

export interface DrawingConfig {
  singleInstance?: boolean;
  construct: (params: DrawingParams) => ISeriesDrawing;
}