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


diff --git a/src/core/CompareManager.ts b/src/core/CompareManager.ts
index e289018a3e2a395f445c4c2b8238dbdf486d75d1..3de5f5476c0e76e35a3eb08ac64b7eaf9a2251b3 100644
--- a/src/core/CompareManager.ts
+++ b/src/core/CompareManager.ts
@@ -70,8 +70,11 @@ export class CompareManager {
 
   private async setup(initialIndicators: IndicatorSnapshot[]) {
     for (const indicator of initialIndicators) {
+      if (indicator.indicatorType !== undefined) {
+        continue;
+      }
+
       if (indicator.config && indicator.config.label) {
-        // условие проверки compare ли это
         const serie = indicator.config.series[0];
 
         const compareMode =
diff --git a/src/core/Indicator.ts b/src/core/Indicator.ts
index ebb76629e488befed391a92cdc0fc59b6ccbe785..b0d9ee7fb83a2a45da4a06df81aa5bb3188bb8e5 100644
--- a/src/core/Indicator.ts
+++ b/src/core/Indicator.ts
@@ -75,10 +75,6 @@ export class Indicator extends DOMObject implements ISerializable<IndicatorSnaps
     });
   }
 
-  public deletable = (): boolean => {
-    return this.associatedPane.isMainPane() || this.associatedPane.isLast();
-  };
-
   public getLabel = () => {
     if (this.config.label) {
       return this.config.label;
@@ -207,7 +203,7 @@ export class Indicator extends DOMObject implements ISerializable<IndicatorSnaps
         mainSymbol$: this.mainSymbol$,
         mainSerie$: this.associatedPane.getMainSerie(),
         showSymbolLabel: false,
-        paneIndex: this.associatedPane.getId(),
+        paneIndex: this.associatedPane.paneIndex(),
         indicatorReference: this,
       });
 
diff --git a/src/core/Legend.ts b/src/core/Legend.ts
index 68e535fba69b812517f3a6f6664d4a0182f715aa..dbb1feeabbb5f7b1e11745785ce0aaf743b97108 100644
--- a/src/core/Legend.ts
+++ b/src/core/Legend.ts
@@ -17,6 +17,7 @@ export interface LegendParams {
   subscribeChartEvent: ChartMouseEvents['subscribe'];
   mainSeries: BehaviorSubject<SeriesStrategies | null> | null;
   paneId: number;
+  paneIndex: () => number;
   openIndicatorSettings: (id: IndicatorsIds, indicator: Indicator) => void;
 }
 
@@ -85,6 +86,7 @@ export class Legend {
   private tooltipVisability = new BehaviorSubject<boolean>(false);
   private tooltipPos = new BehaviorSubject<null | Point>(null);
   private paneId: number;
+  private paneIndex: () => number;
 
   private openIndicatorSettings: (id: IndicatorsIds, indicator: Indicator) => void;
   private subscriptions = new Subscription();
@@ -98,11 +100,13 @@ export class Legend {
     subscribeChartEvent,
     mainSeries,
     paneId,
+    paneIndex,
     openIndicatorSettings,
   }: LegendParams) {
     this.config = config;
     this.eventManager = eventManager;
     this.paneId = paneId;
+    this.paneIndex = paneIndex;
     this.openIndicatorSettings = openIndicatorSettings;
 
     this.subscriptions.add(
@@ -210,8 +214,6 @@ export class Legend {
         indicatorSeries.set(serieName, { ...value, name: indicator.getSeriesLabel(serieName) });
       }
 
-      const remove = indicator.deletable() ? () => indicator.delete() : undefined;
-
       model.push({
         id: indicator.getId(),
         name: indicator.getLabel(),
@@ -219,7 +221,7 @@ export class Legend {
           Record<keyof Ohlc, { value: number | string | Time; color: string; name?: string }>
         >,
         isIndicator: true,
-        remove,
+        remove: () => indicator.delete(),
         settings:
           indicatorType && indicator.hasSettings()
             ? () => this.openIndicatorSettings(indicatorType, indicator)
@@ -240,7 +242,7 @@ export class Legend {
       return;
     }
 
-    if (this.paneId === param.paneIndex) {
+    if (this.paneIndex() === param.paneIndex) {
       this.tooltipVisability.next(true);
     } else {
       this.tooltipVisability.next(false);
@@ -289,8 +291,6 @@ export class Legend {
         indicatorSeries.set(serieName, { ...value, name: indicator.getSeriesLabel(serieName) });
       }
 
-      const remove = indicator.deletable() ? () => indicator.delete() : undefined;
-
       model.push({
         id: indicator.getId(),
         name: indicator.getLabel(),
@@ -298,7 +298,7 @@ export class Legend {
           Record<keyof Ohlc, { value: number | string | Time; color: string; name?: string }>
         >,
         isIndicator: true,
-        remove,
+        remove: () => indicator.delete(),
         settings:
           indicatorType && indicator.hasSettings()
             ? () => this.openIndicatorSettings(indicatorType, indicator)
diff --git a/src/core/Pane.tsx b/src/core/Pane.tsx
index 11749e0df614ed28b0b8cb9e83a202d75e9b6d01..1ff22c5f792809b6c289a687ae36470d77db0641 100644
--- a/src/core/Pane.tsx
+++ b/src/core/Pane.tsx
@@ -16,7 +16,7 @@ import { ReactRenderer } from '@core/ReactRenderer';
 import { TooltipService } from '@core/Tooltip';
 import { UIRenderer } from '@core/UIRenderer';
 import { EntitySettingsModal } from '@src/components/EntitySettingsModal';
-import { DrawingsNames, indicatorLabelById } from '@src/constants';
+import { DrawingsNames, indicatorLabelById, MAIN_PANE_INDEX } from '@src/constants';
 import { ModalRenderer } from '@src/core/ModalRenderer';
 import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
 import { t } from '@src/translations';
@@ -73,8 +73,7 @@ export class Pane implements ISerializable<PaneSnapshot> {
   private subscribeChartEvent: ChartMouseEvents['subscribe'];
   private onDelete: () => void;
   private subscriptions = new Subscription();
-
-  private last = false; // временное решение чтобы блочить удаление не последнего пейна
+  private paneContainerSyncFrameId: number | null = null;
 
   constructor({
     lwcChart,
@@ -99,14 +98,14 @@ export class Pane implements ISerializable<PaneSnapshot> {
     this.isMain = isMainPane ?? false;
     this.id = id;
 
-    this.initializeLegend({ ohlcConfig });
-
     if (isMainPane) {
-      this.lwcPane = this.lwcChart.panes()[this.id];
+      this.lwcPane = this.lwcChart.panes()[MAIN_PANE_INDEX];
     } else {
       this.lwcPane = this.lwcChart.addPane(true);
     }
 
+    this.initializeLegend({ ohlcConfig });
+
     this.tooltip = new TooltipService({
       config: tooltipConfig,
       legend: this.legend,
@@ -153,18 +152,10 @@ export class Pane implements ISerializable<PaneSnapshot> {
     );
   }
 
-  public setIsLast(isLast: boolean): void {
-    this.last = isLast;
-  }
-
   public isMainPane = () => {
     return this.isMain;
   };
 
-  public isLast = () => {
-    return this.last;
-  };
-
   public getDrawingsSnapshot(): DrawingsManagerSnapshot {
     return this.drawingsManager.getSnapshot();
   }
@@ -181,6 +172,10 @@ export class Pane implements ISerializable<PaneSnapshot> {
     return this.id;
   };
 
+  public paneIndex = () => {
+    return this.lwcPane.paneIndex();
+  };
+
   public setIndicator(indicatorId: string, indicator: Indicator): void {
     const map = this.indicatorsMap.value;
 
@@ -197,7 +192,7 @@ export class Pane implements ISerializable<PaneSnapshot> {
     this.indicatorsMap.next(map);
 
     if (map.size === 0 && !this.isMain) {
-      this.destroy();
+      this.onDelete();
     }
   }
 
@@ -211,15 +206,7 @@ export class Pane implements ISerializable<PaneSnapshot> {
     this.paneOverlayContainer = paneOverlayContainer;
     this.legendRenderer = new ReactRenderer(legendContainer);
 
-    requestAnimationFrame(() => {
-      setTimeout(() => {
-        const lwcPaneElement = this.lwcPane.getHTMLElement();
-        if (!lwcPaneElement) return;
-        lwcPaneElement.style.position = 'relative';
-        lwcPaneElement.appendChild(legendContainer);
-        lwcPaneElement.appendChild(paneOverlayContainer);
-      }, 0);
-    });
+    this.schedulePaneContainerSync();
 
     // todo: переписать код ниже под логику пейнов
     // /*
@@ -265,6 +252,7 @@ export class Pane implements ISerializable<PaneSnapshot> {
       subscribeChartEvent: this.subscribeChartEvent,
       mainSeries: this.isMain ? this.mainSeries : null,
       paneId: this.id,
+      paneIndex: this.paneIndex,
       openIndicatorSettings: (indicatorId, indicator) => {
         let settings = indicator.getSettings();
 
@@ -310,6 +298,27 @@ export class Pane implements ISerializable<PaneSnapshot> {
     });
   }
 
+  public schedulePaneContainerSync(): void {
+    if (this.paneContainerSyncFrameId !== null) {
+      return;
+    }
+
+    this.paneContainerSyncFrameId = requestAnimationFrame(() => {
+      this.paneContainerSyncFrameId = null;
+      this.syncPaneContainers();
+    });
+  }
+
+  private syncPaneContainers(): void {
+    const lwcPaneElement = this.lwcPane.getHTMLElement();
+    if (!lwcPaneElement) return;
+
+    lwcPaneElement.style.position = 'relative';
+
+    lwcPaneElement.appendChild(this.legendContainer);
+    lwcPaneElement.appendChild(this.paneOverlayContainer);
+  }
+
   public getSnapshot(): PaneSnapshot {
     const indicators: (DOMObjectSnapshot & IndicatorSnapshot)[] = [];
 
@@ -328,12 +337,19 @@ export class Pane implements ISerializable<PaneSnapshot> {
   }
 
   public destroy() {
+    if (this.paneContainerSyncFrameId !== null) {
+      cancelAnimationFrame(this.paneContainerSyncFrameId);
+      this.paneContainerSyncFrameId = null;
+    }
+
     this.subscriptions.unsubscribe();
     this.tooltip?.destroy();
     this.legend?.destroy();
     this.legendRenderer.destroy();
 
     this.tooltipRenderer?.destroy();
+    this.legendContainer.remove();
+    this.paneOverlayContainer.remove();
     this.indicatorsMap.complete();
 
     this.mainSerieSub?.unsubscribe();
@@ -343,12 +359,14 @@ export class Pane implements ISerializable<PaneSnapshot> {
       this.mainSeries?.complete();
     }
 
-    try {
-      this.lwcChart.removePane(this.id);
-    } catch (e) {
-      console.log(e);
-    }
+    const paneIndex = this.paneIndex();
 
-    this.onDelete();
+    if (paneIndex >= 0) {
+      try {
+        this.lwcChart.removePane(paneIndex);
+      } catch (e) {
+        console.log(e);
+      }
+    }
   }
 }
diff --git a/src/core/PaneManager.ts b/src/core/PaneManager.ts
index 158738c3a997c582a5ebc4f6cc9cf76cc1b4d8a7..d87a1ac0ec483a35bc9192192e8977b555ecf1bf 100644
--- a/src/core/PaneManager.ts
+++ b/src/core/PaneManager.ts
@@ -17,22 +17,22 @@ export class PaneManager implements ISerializable<PaneSnapshot[]> {
   private mainPane: Pane;
   private paneChartInheritedParams: PaneManagerParams & { isMainPane: boolean };
   private panesMap: Map<number, Pane> = new Map<number, Pane>();
-  private panesIdIterator = 0;
+  private nextPaneId = 0;
 
   constructor(params: PaneManagerParams) {
     this.paneChartInheritedParams = { ...params, isMainPane: false };
 
     this.mainPane = new Pane({ ...params, isMainPane: true, id: 0, onDelete: () => {} });
 
-    this.panesMap.set(this.panesIdIterator++, this.mainPane);
+    this.panesMap.set(this.nextPaneId++, this.mainPane);
     this.setup(params.panesSnapshot);
   }
 
   private setup(panesSnapshot: PaneSnapshot[]) {
     panesSnapshot.forEach((paneSnap: PaneSnapshot) => {
-      const { isMain, id, indicators, drawings } = paneSnap;
+      const { isMain, id, drawings } = paneSnap;
 
-      this.panesMap.get(id)?.destroy();
+      this.destroyPane(id, false);
 
       if (isMain) {
         this.mainPane = new Pane({ ...this.paneChartInheritedParams, isMainPane: true, id: 0, onDelete: () => {} });
@@ -41,13 +41,12 @@ export class PaneManager implements ISerializable<PaneSnapshot[]> {
 
         this.mainPane.setDrawingsSnapshot(drawings);
       } else {
-        const pane = this.addPane();
+        const pane = this.addPane(undefined, id);
         pane.setDrawingsSnapshot(drawings);
       }
-      const lastPane = Array.from(this.panesMap.values()).at(-1);
-
-      lastPane?.setIsLast(true);
     });
+
+    this.syncPaneContainers();
   }
 
   public getPaneById(id: number): Pane | undefined {
@@ -70,33 +69,45 @@ export class PaneManager implements ISerializable<PaneSnapshot[]> {
     return this.mainPane;
   };
 
-  public addPane(dataSource?: DataSource): Pane {
-    const id = this.panesIdIterator++;
+  private destroyPane(id: number, syncAfter = true): void {
+    const pane = this.panesMap.get(id);
+
+    if (!pane) {
+      return;
+    }
+
+    this.panesMap.delete(id);
+    pane.destroy();
+
+    if (syncAfter) {
+      this.syncPaneContainers();
+    }
+  }
+
+  public addPane(dataSource?: DataSource, paneId?: number): Pane {
+    const id = paneId ?? this.nextPaneId++;
+    this.nextPaneId = Math.max(this.nextPaneId, id + 1);
 
     const newPane = new Pane({
       ...this.paneChartInheritedParams,
       id,
       dataSource: dataSource ?? null,
       basedOn: dataSource ? undefined : this.mainPane,
-      onDelete: () => {
-        this.panesIdIterator--;
-        this.panesMap.delete(id);
-
-        const prevPane = Array.from(this.panesMap.values()).at(-1);
-        prevPane?.setIsLast(true);
-      },
+      onDelete: () => this.destroyPane(id),
     });
 
-    const prevPane = Array.from(this.panesMap.values()).at(-1);
-
-    prevPane?.setIsLast(false);
-    newPane.setIsLast(true);
-
     this.panesMap.set(id, newPane);
+    this.syncPaneContainers();
 
     return newPane;
   }
 
+  private syncPaneContainers(): void {
+    this.panesMap.forEach((pane) => {
+      pane.schedulePaneContainerSync();
+    });
+  }
+
   public getDrawingsManager(): DrawingsManager {
     // todo: temp
     return this.mainPane.getDrawingManager();