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


import type { PriceScaleMode } from 'lightweight-charts';

export interface PriceScaleTarget {
  paneId: number;
  priceScaleId: string;
}

export interface PriceScaleModeSnapshot extends PriceScaleTarget {
  mode: PriceScaleMode;
}



import { PriceScaleMode } from 'lightweight-charts';

import type { Pane } from '@core/Pane';

import type { PriceScaleModeSnapshot, PriceScaleTarget } from './types';

type PriceScaleModeMap = Map<number, Map<string, PriceScaleMode>>;

interface PriceScaleModeControllerParams {
  getPaneById: (paneId: number) => Pane | undefined;
  initialModes?: PriceScaleModeSnapshot[];
  onChange?: () => void;
}

export class PriceScaleModeController {
  private readonly getPaneById: (paneId: number) => Pane | undefined;
  private readonly onChange?: () => void;
  private readonly savedModes: PriceScaleModeMap = new Map();
  private readonly overrideModes: PriceScaleModeMap = new Map();

  constructor({ getPaneById, initialModes = [], onChange }: PriceScaleModeControllerParams) {
    this.getPaneById = getPaneById;
    this.onChange = onChange;
    this.setSnapshot(initialModes);
  }

  public getActiveMode(target: PriceScaleTarget): PriceScaleMode {
    return this.getOverrideMode(target) ?? this.getSavedMode(target);
  }

  public getSavedMode(target: PriceScaleTarget): PriceScaleMode {
    return this.savedModes.get(target.paneId)?.get(target.priceScaleId) ?? PriceScaleMode.Normal;
  }

  public setSavedMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
    if (this.getSavedMode(target) === mode) {
      return;
    }

    this.setMode(this.savedModes, target, mode);
    this.applyMode(target);
    this.onChange?.();
  }

  public toggleSavedMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
    this.setSavedMode(target, this.getSavedMode(target) === mode ? PriceScaleMode.Normal : mode);
  }

  public setOverrideMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
    if (mode === PriceScaleMode.Normal) {
      this.clearOverrideMode(target);
      return;
    }

    if (this.getOverrideMode(target) === mode) {
      return;
    }

    this.setMode(this.overrideModes, target, mode);
    this.applyMode(target);
    this.onChange?.();
  }

  public clearOverrideMode(target: PriceScaleTarget): void {
    if (!this.getOverrideMode(target)) {
      return;
    }

    this.removeMode(this.overrideModes, target);
    this.applyMode(target);
    this.onChange?.();
  }

  public applyAll(): void {
    this.getTargets(this.savedModes).forEach((target) => this.applyMode(target));
    this.getTargets(this.overrideModes).forEach((target) => this.applyMode(target));
  }

  public getSnapshot(): PriceScaleModeSnapshot[] {
    const snapshot: PriceScaleModeSnapshot[] = [];

    this.savedModes.forEach((paneModes, paneId) => {
      if (!this.getPaneById(paneId)) {
        return;
      }

      paneModes.forEach((mode, priceScaleId) => {
        snapshot.push({
          paneId,
          priceScaleId,
          mode,
        });
      });
    });

    return snapshot;
  }

  public setSnapshot(snapshot: PriceScaleModeSnapshot[]): void {
    this.savedModes.clear();

    snapshot.forEach(({ paneId, priceScaleId, mode }) => {
      this.setMode(this.savedModes, { paneId, priceScaleId }, mode);
    });
  }

  public destroy(): void {
    this.savedModes.clear();
    this.overrideModes.clear();
  }

  private getOverrideMode(target: PriceScaleTarget): PriceScaleMode | undefined {
    return this.overrideModes.get(target.paneId)?.get(target.priceScaleId);
  }

  private setMode(modes: PriceScaleModeMap, target: PriceScaleTarget, mode: PriceScaleMode): void {
    if (mode === PriceScaleMode.Normal) {
      this.removeMode(modes, target);
      return;
    }

    const paneModes = modes.get(target.paneId) ?? new Map<string, PriceScaleMode>();

    paneModes.set(target.priceScaleId, mode);
    modes.set(target.paneId, paneModes);
  }

  private removeMode(modes: PriceScaleModeMap, target: PriceScaleTarget): void {
    const paneModes = modes.get(target.paneId);

    paneModes?.delete(target.priceScaleId);

    if (paneModes?.size === 0) {
      modes.delete(target.paneId);
    }
  }

  private getTargets(modes: PriceScaleModeMap): PriceScaleTarget[] {
    const targets: PriceScaleTarget[] = [];

    modes.forEach((paneModes, paneId) => {
      paneModes.forEach((_, priceScaleId) => {
        targets.push({ paneId, priceScaleId });
      });
    });

    return targets;
  }

  private applyMode(target: PriceScaleTarget): void {
    const pane = this.getPaneById(target.paneId);

    if (!pane) {
      return;
    }

    pane.getPriceScale(target.priceScaleId).applyOptions({
      mode: this.getActiveMode(target),
    });
  }
}



export { PriceScaleModeController } from './controller';

export type {
  PriceScaleModeSnapshot,
  PriceScaleTarget,
} from './types';



public paneIndex = (): number => {
  return this.lwcPane.paneIndex();
};

public getPriceScale(priceScaleId: string): IPriceScaleApi {
  return this.lwcChart.priceScale(priceScaleId, this.paneIndex());
}

public getPriceScaleTarget(priceScaleId: string): PriceScaleTarget {
  return {
    paneId: this.id,
    priceScaleId,
  };
}

public getPriceScaleMode(target: PriceScaleTarget): PriceScaleMode {
  return this.priceScaleModeController.getActiveMode(target);
}

public setPriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
  this.priceScaleModeController.setSavedMode(target, mode);
}

public togglePriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
  this.priceScaleModeController.toggleSavedMode(target, mode);
}

public getMainPriceScaleTarget(): PriceScaleTarget {
  return this.paneManager.getMainPane().getPriceScaleTarget(Direction.Right);
}

private applyPolicy(): void {
  const list = Array.from(this.entries.values());
  const mainPane = this.paneManager.getMainPane();

  let percentEnabled = false;

  for (let i = 0; i < list.length; i += 1) {
    if (list[i].mode === CompareMode.Percentage) {
      percentEnabled = true;
      break;
    }
  }

  let hasMainNewScale = false;

  for (let i = 0; i < list.length; i += 1) {
    const pane = list[i].entity.getPane();

    if (pane.isMainPane() && list[i].mode === CompareMode.NewScale) {
      hasMainNewScale = true;
      break;
    }
  }

  const paneIds = new Set<number>();

  for (let i = 0; i < list.length; i += 1) {
    const pane = list[i].entity.getPane();

    if (!pane.isMainPane()) {
      paneIds.add(pane.getId());
    }
  }

  this.chart.applyOptions({
    leftPriceScale: { visible: hasMainNewScale, borderVisible: false },
  });

  this.chart.priceScale(Direction.Right, mainPane.paneIndex()).applyOptions({
    visible: true,
  });

  if (percentEnabled) {
    this.priceScaleModeController.setOverrideMode(
      mainPane.getPriceScaleTarget(Direction.Right),
      PriceScaleMode.Percentage,
    );
  } else {
    this.priceScaleModeController.clearOverrideMode(mainPane.getPriceScaleTarget(Direction.Right));
  }

  this.chart.priceScale(Direction.Left, mainPane.paneIndex()).applyOptions({
    visible: hasMainNewScale,
    borderVisible: false,
  });

  const paneIdsList = Array.from(paneIds.values());

  for (let i = 0; i < paneIdsList.length; i += 1) {
    const pane = this.paneManager.getPaneById(paneIdsList[i]);

    if (!pane) {
      continue;
    }

    this.chart.priceScale(Direction.Right, pane.paneIndex()).applyOptions({
      visible: true,
    });

    if (hasMainNewScale) {
      this.chart.priceScale(Direction.Left, pane.paneIndex()).applyOptions({
        visible: true,
        borderVisible: false,
      });
    }
  }

  for (let i = 0; i < list.length; i += 1) {
    const entry = list[i];
    const pane = entry.entity.getPane();
    const serie = Array.from(entry.entity.getSeriesMap())[0][1];

    if (!pane.isMainPane()) {
      serie.applyOptions({ priceScaleId: Direction.Right });
      continue;
    }

    serie.applyOptions({
      priceScaleId: entry.mode === CompareMode.NewScale ? Direction.Left : Direction.Right,
    });
  }
}

public getPriceScaleMode(target: PriceScaleTarget): PriceScaleMode {
  return this.chart.getPriceScaleMode(target);
}

public setPriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
  this.chart.setPriceScaleMode(target, mode);
}

public togglePriceScaleMode(target: PriceScaleTarget, mode: PriceScaleMode): void {
  this.chart.togglePriceScaleMode(target, mode);
}

public getMainPriceScaleTarget(): PriceScaleTarget {
  return this.chart.getMainPriceScaleTarget();
}

public toggleMainLogarithmicPriceScale(): void {
  this.chart.togglePriceScaleMode(this.chart.getMainPriceScaleTarget(), PriceScaleMode.Logarithmic);
}