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


diff --git a/src/components/Toolbar/index.tsx b/src/components/Toolbar/index.tsx
index 94f9e9ceaf1031a4a495ca728f349170430bfeff..cb86a0c2185f0020a2529e571af7ca634b8b9012 100644
--- a/src/components/Toolbar/index.tsx
+++ b/src/components/Toolbar/index.tsx
@@ -3,6 +3,8 @@ import { Button, Divider, Tooltip } from 'exchange-elements/v2';
 
 import { Dispatch, SetStateAction, useRef, useState } from 'react';
 
+import { Observable } from 'rxjs';
+
 import { DrawingsNames } from '@core/DrawingsManager';
 
 import { MenuList } from '@src/components/Menu';
@@ -10,7 +12,7 @@ import SplitDropdown from '@src/components/SplitDropdown';
 
 import { geometricShapes, measurementTools, trendLines } from '@src/components/Toolbar/constants';
 
-import { ensureDefined } from '@src/utils';
+import { ensureDefined, useObservable } from '@src/utils';
 
 import {
   CrossIcon,
@@ -33,6 +35,8 @@ import styles from './index.module.scss';
 interface ToolbarProps {
   toggleDOM: () => void;
   addDrawing: (name: DrawingsNames) => void;
+  setEndlessDrawingsMode: (value: boolean) => void;
+  isEndlessDrawingsMode$: Observable<boolean>;
 }
 
 const implemented = {
@@ -46,11 +50,18 @@ const implemented = {
   icons: false,
 };
 
-export default function Toolbar({ toggleDOM, addDrawing }: ToolbarProps) {
+export default function Toolbar({
+  toggleDOM,
+  addDrawing,
+  setEndlessDrawingsMode,
+  isEndlessDrawingsMode$,
+}: ToolbarProps) {
   const [selectedLineType, setSelectedLineType] = useState<DrawingsNames>(DrawingsNames.trendLine);
   const [selectedMeasurementTool, setSelectedMeasurementTool] = useState(DrawingsNames.fixedProfile);
   const [selectedGeometricShape, setSelectedGeometricShape] = useState(DrawingsNames.rectangle);
 
+  const isEndlessDrawingsMode = useObservable(isEndlessDrawingsMode$);
+
   const toolbarRef = useRef<HTMLDivElement | null>(null);
 
   const createDrawingHandler = (setter: Dispatch<SetStateAction<DrawingsNames>>) => (value: DrawingsNames) => {
@@ -230,14 +241,15 @@ export default function Toolbar({ toggleDOM, addDrawing }: ToolbarProps) {
       </div>
       <Divider
         direction="horizontal"
-        pt={{ divider: { className: classNames(styles.divider, styles.notImplemented) } }}
+        pt={{ divider: { className: classNames(styles.divider) } }}
       />
-      <div className={classNames(styles.group, styles.notImplemented)}>
+      <div className={classNames(styles.group)}>
         <Tooltip
           tooltipClassName={styles.tooltipHint}
           showMessageOnFocus
           label="Магнит позволяет притягивать точки объектов к ближайшим ценам (откр., макс., мин., закр.) баров"
           location="right"
+          className={styles.notImplemented}
         >
           <Button
             size="sm"
@@ -255,8 +267,10 @@ export default function Toolbar({ toggleDOM, addDrawing }: ToolbarProps) {
         >
           <Button
             size="sm"
-            className={styles.button}
-            onClick={() => {}}
+            className={`${styles.button} ${isEndlessDrawingsMode ? styles.pressed : ''}`}
+            onClick={() => {
+              setEndlessDrawingsMode(!isEndlessDrawingsMode);
+            }}
             label={<PencilLockerIcon />}
           />
         </Tooltip>
@@ -266,6 +280,7 @@ export default function Toolbar({ toggleDOM, addDrawing }: ToolbarProps) {
           showMessageOnFocus
           label="Зафиксировать все объекты"
           location="right"
+          className={styles.notImplemented}
         >
           <Button
             size="sm"
@@ -280,6 +295,7 @@ export default function Toolbar({ toggleDOM, addDrawing }: ToolbarProps) {
           showMessageOnFocus
           label="Скрыть все объекты рисования"
           location="right"
+          className={styles.notImplemented}
         >
           <Button
             size="sm"
diff --git a/src/core/Drawings.ts b/src/core/Drawings.ts
index e4c3881e748f4e53a1d1d470e8885ef19707ac60..651a7dd649d9111c34acb383afdd3b16d0616999 100644
--- a/src/core/Drawings.ts
+++ b/src/core/Drawings.ts
@@ -1,5 +1,9 @@
 import { IChartApi, ISeriesApi, SeriesType } from 'lightweight-charts';
 
+import { firstValueFrom } from 'rxjs';
+
+import { filter } from 'rxjs/operators';
+
 import { DOMObject, DOMObjectParams } from '@core/DOMObject';
 import { ISeriesDrawing } from '@core/Drawings/common';
 import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
@@ -54,6 +58,10 @@ export class Drawing extends DOMObject implements IDrawing {
     return this.lwcDrawing.isCreationPending();
   }
 
+  public awaitCreation(): Promise<boolean> {
+    return firstValueFrom(this.lwcDrawing.isCreationPendingObs().pipe(filter((value) => !value)));
+  }
+
   public destroy() {
     this.mainSeries.detachPrimitive(this.lwcDrawing);
     this.lwcDrawing.destroy();
diff --git a/src/core/Drawings/axisLine/axisLine.ts b/src/core/Drawings/axisLine/axisLine.ts
index 841ed2208185c5ea945354ecef25bd0237023745..cd7d4626beb7e7ed1b5d1502c46d258f59617fba 100644
--- a/src/core/Drawings/axisLine/axisLine.ts
+++ b/src/core/Drawings/axisLine/axisLine.ts
@@ -10,7 +10,7 @@ import {
   Time,
   UTCTimestamp,
 } from 'lightweight-charts';
-import { Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
 
 import { CustomPriceAxisView, CustomTimeAxisView } from '@core/Drawings/axis';
 import {
@@ -76,6 +76,7 @@ export class AxisLine implements ISeriesDrawing {
   private hidden = false;
   private isActive = false;
   private mode: AxisLineMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private direction: AxisLineDirection;
   private time: Time | null = null;
@@ -163,7 +164,11 @@ export class AxisLine implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): AxisLineState {
@@ -189,6 +194,8 @@ export class AxisLine implements ISeriesDrawing {
 
     if ('mode' in nextState && nextState.mode) {
       this.mode = nextState.mode;
+
+      this.isBusy.next(this.mode === 'idle');
     }
 
     if ('time' in nextState) {
@@ -371,6 +378,7 @@ export class AxisLine implements ISeriesDrawing {
 
       this.updateLine(point);
       this.isActive = true;
+      this.isBusy.next(false);
       this.mode = 'ready';
       this.render();
       return;
@@ -412,6 +420,7 @@ export class AxisLine implements ISeriesDrawing {
     event.stopPropagation();
 
     this.mode = 'dragging';
+    this.isBusy.next(false);
     this.dragPointerId = event.pointerId;
     this.hideCrosshair();
     this.render();
@@ -435,6 +444,7 @@ export class AxisLine implements ISeriesDrawing {
     }
 
     this.mode = 'ready';
+    this.isBusy.next(false);
     this.dragPointerId = null;
     this.showCrosshair();
     this.render();
diff --git a/src/core/Drawings/common.ts b/src/core/Drawings/common.ts
index 0acfe0bfdc32ddae8bd8e492e335cb8a56443f67..1c67536a3b5a1c8928f2218818f838ac7baf05ba 100644
--- a/src/core/Drawings/common.ts
+++ b/src/core/Drawings/common.ts
@@ -1,4 +1,5 @@
 import { Coordinate, ISeriesApi, ISeriesPrimitive, SeriesType, Time } from 'lightweight-charts';
+import { Observable } from 'rxjs';
 
 export interface BitmapPositionLength {
   /** coordinate for use with a bitmap rendering scope */
@@ -24,6 +25,7 @@ export interface ISeriesDrawing extends ISeriesPrimitive<Time> {
   rebind(series: ISeriesApi<SeriesType>): void;
   destroy(): void;
   isCreationPending(): boolean;
+  isCreationPendingObs(): Observable<boolean>;
 }
 
 export function positionsBox(position1Media: number, position2Media: number, pixelRatio: number): BitmapPositionLength {
diff --git a/src/core/Drawings/diapson/diapson.ts b/src/core/Drawings/diapson/diapson.ts
index 3c4ba3d553f706a326eb7e39c3fcd0dafaded05b..a5bbef7dc01939a29762bec9477502b93d2aa811 100644
--- a/src/core/Drawings/diapson/diapson.ts
+++ b/src/core/Drawings/diapson/diapson.ts
@@ -1,4 +1,4 @@
-import { Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -117,6 +117,7 @@ export class Diapson implements ISeriesDrawing {
   private isActive = false;
   private interactionMode: InteractionMode = 'idle';
   private rangeMode: DiapsonRangeMode;
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private startTime: Time | null = null;
   private endTime: Time | null = null;
@@ -231,7 +232,11 @@ export class Diapson implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.interactionMode === 'idle' || this.interactionMode === 'drawing';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public setRangeMode(nextMode: DiapsonRangeMode): void {
@@ -266,6 +271,7 @@ export class Diapson implements ISeriesDrawing {
     this.hidden = typeof nextState.hidden === 'boolean' ? nextState.hidden : this.hidden;
     this.isActive = typeof nextState.isActive === 'boolean' ? nextState.isActive : this.isActive;
     this.interactionMode = nextState.interactionMode ?? this.interactionMode;
+    this.isBusy.next(this.interactionMode === 'idle' || this.interactionMode === 'drawing');
     this.rangeMode = nextState.rangeMode ?? this.rangeMode;
     this.startTime = 'startTime' in nextState ? (nextState.startTime ?? null) : this.startTime;
     this.endTime = 'endTime' in nextState ? (nextState.endTime ?? null) : this.endTime;
@@ -598,6 +604,7 @@ export class Diapson implements ISeriesDrawing {
 
     this.isActive = true;
     this.interactionMode = 'drawing';
+    this.isBusy.next(true);
     this.render();
   }
 
@@ -633,11 +640,13 @@ export class Diapson implements ISeriesDrawing {
     }
 
     this.interactionMode = 'ready';
+    this.isBusy.next(false);
     this.render();
   }
 
   private startDragging(point: Point, pointerId: number, dragTarget: Exclude<DiapsonHandle, null>): void {
     this.interactionMode = 'dragging';
+    this.isBusy.next(false);
     this.activeDragTarget = dragTarget;
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
@@ -648,6 +657,7 @@ export class Diapson implements ISeriesDrawing {
 
   private finishDragging(): void {
     this.interactionMode = 'ready';
+    this.isBusy.next(false);
     this.clearInteractionState();
     this.render();
   }
@@ -663,6 +673,7 @@ export class Diapson implements ISeriesDrawing {
     this.hidden = false;
     this.isActive = false;
     this.interactionMode = 'idle';
+    this.isBusy.next(true);
     this.startTime = null;
     this.endTime = null;
     this.startPrice = null;
diff --git a/src/core/Drawings/ray/ray.ts b/src/core/Drawings/ray/ray.ts
index a677f6e5c4fbe67c8d2c4408d3319832a5b42f32..a8a4160440ee6ea0ae153bc1003f0dca20fecc49 100644
--- a/src/core/Drawings/ray/ray.ts
+++ b/src/core/Drawings/ray/ray.ts
@@ -10,7 +10,7 @@ import {
   Time,
   UTCTimestamp,
 } from 'lightweight-charts';
-import { Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -89,6 +89,7 @@ export class Ray implements ISeriesDrawing {
   private hidden = false;
   private isActive = false;
   private mode: RayMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private startAnchor: Anchor | null = null;
   private directionAnchor: Anchor | null = null;
@@ -195,7 +196,11 @@ export class Ray implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle' || this.mode === 'drawing';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): RayState {
@@ -221,6 +226,7 @@ export class Ray implements ISeriesDrawing {
 
     if ('mode' in nextState && nextState.mode) {
       this.mode = nextState.mode;
+      this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
     }
 
     if ('startAnchor' in nextState) {
@@ -560,6 +566,8 @@ export class Ray implements ISeriesDrawing {
     this.directionAnchor = anchor;
     this.isActive = true;
     this.mode = 'drawing';
+    this.isBusy.next(true);
+
     this.render();
   }
 
@@ -592,11 +600,15 @@ export class Ray implements ISeriesDrawing {
     }
 
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.render();
   }
 
   private startDragging(mode: RayMode, point: Point, pointerId: number): void {
     this.mode = mode;
+    this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
+
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
     this.dragStateSnapshot = this.getState();
@@ -607,6 +619,7 @@ export class Ray implements ISeriesDrawing {
 
   private finishDragging(): void {
     this.mode = 'ready';
+    this.isBusy.next(false);
     this.dragPointerId = null;
     this.dragStartPoint = null;
     this.dragStateSnapshot = null;
diff --git a/src/core/Drawings/rectangle/rectangle.ts b/src/core/Drawings/rectangle/rectangle.ts
index 922d139498fc497655deef675f6fd3d227552f43..58120f5bdd3c1874b252d56c6d5d342b2eb64c07 100644
--- a/src/core/Drawings/rectangle/rectangle.ts
+++ b/src/core/Drawings/rectangle/rectangle.ts
@@ -1,4 +1,4 @@
-import { Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -100,6 +100,7 @@ export class Rectangle implements ISeriesDrawing {
   private hidden = false;
   private isActive = false;
   private mode: RectangleMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private startTime: Time | null = null;
   private endTime: Time | null = null;
@@ -207,7 +208,11 @@ export class Rectangle implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle' || this.mode === 'drawing';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): RectangleState {
@@ -235,6 +240,7 @@ export class Rectangle implements ISeriesDrawing {
 
     if ('mode' in nextState && nextState.mode) {
       this.mode = nextState.mode;
+      this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
     }
 
     if ('startTime' in nextState) {
@@ -577,6 +583,8 @@ export class Rectangle implements ISeriesDrawing {
 
     this.isActive = true;
     this.mode = 'drawing';
+    this.isBusy.next(true);
+
     this.render();
   }
 
@@ -608,11 +616,15 @@ export class Rectangle implements ISeriesDrawing {
     }
 
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.render();
   }
 
   private startDragging(point: Point, pointerId: number, dragTarget: Exclude<RectangleHandle, null>): void {
     this.mode = 'dragging';
+    this.isBusy.next(false);
+
     this.activeDragTarget = dragTarget;
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
@@ -624,6 +636,8 @@ export class Rectangle implements ISeriesDrawing {
 
   private finishDragging(): void {
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.clearInteractionState();
     this.render();
   }
@@ -640,6 +654,8 @@ export class Rectangle implements ISeriesDrawing {
     this.hidden = false;
     this.isActive = false;
     this.mode = 'idle';
+    this.isBusy.next(true);
+
     this.startTime = null;
     this.endTime = null;
     this.startPrice = null;
diff --git a/src/core/Drawings/ruler/ruler.ts b/src/core/Drawings/ruler/ruler.ts
index b1924f2ceb8c1efbac24c20f2f0366bceee52d5d..6c6c704c40e56670baf619e5edabc0fb0b2c1765 100644
--- a/src/core/Drawings/ruler/ruler.ts
+++ b/src/core/Drawings/ruler/ruler.ts
@@ -1,4 +1,4 @@
-import { Observable, skip, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, skip, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -99,6 +99,7 @@ export class Ruler implements ISeriesDrawing {
 
   private hidden = false;
   private mode: RulerMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private startAnchor: Anchor | null = null;
   private endAnchor: Anchor | null = null;
@@ -214,7 +215,11 @@ export class Ruler implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle' || this.mode === 'placingEnd';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): RulerState {
@@ -231,6 +236,8 @@ export class Ruler implements ISeriesDrawing {
 
     this.hidden = nextState.hidden ?? this.hidden;
     this.mode = nextState.mode ?? this.mode;
+    this.isBusy.next(this.mode === 'idle' || this.mode === 'placingEnd');
+
     this.startAnchor = nextState.startAnchor ?? this.startAnchor;
     this.endAnchor = nextState.endAnchor ?? this.endAnchor;
 
@@ -591,6 +598,8 @@ export class Ruler implements ISeriesDrawing {
       this.startAnchor = anchor;
       this.endAnchor = anchor;
       this.mode = 'placingEnd';
+      this.isBusy.next(true);
+
       this.setCrosshairVisible(false);
       this.render();
       return;
@@ -599,6 +608,8 @@ export class Ruler implements ISeriesDrawing {
     if (this.mode === 'placingEnd') {
       this.endAnchor = anchor;
       this.mode = 'ready';
+      this.isBusy.next(false);
+
       this.setCrosshairVisible(true);
       this.render();
     }
diff --git a/src/core/Drawings/sliderPosition/sliderPosition.ts b/src/core/Drawings/sliderPosition/sliderPosition.ts
index fd462d6ba06f244078b45500d910e6db4b937212..cb3003d46053a2a1d0da266a3ed0cc497cc312d3 100644
--- a/src/core/Drawings/sliderPosition/sliderPosition.ts
+++ b/src/core/Drawings/sliderPosition/sliderPosition.ts
@@ -1,4 +1,4 @@
-import { Observable, skip, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, skip, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -121,6 +121,7 @@ export class SliderPosition implements ISeriesDrawing {
   private hidden = false;
   private active = true;
   private mode: SliderMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
   private side: SliderSide;
 
   private startTime: Time | null = null;
@@ -252,7 +253,11 @@ export class SliderPosition implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): SliderPositionState {
@@ -277,6 +282,8 @@ export class SliderPosition implements ISeriesDrawing {
     this.hidden = next.hidden ?? this.hidden;
     this.active = next.active ?? this.active;
     this.mode = next.mode ?? this.mode;
+    this.isBusy.next(this.mode === 'idle');
+
     this.startTime = next.startTime ?? this.startTime;
     this.endTime = next.endTime ?? this.endTime;
     this.entryPrice = next.entryPrice ?? this.entryPrice;
@@ -689,6 +696,8 @@ export class SliderPosition implements ISeriesDrawing {
 
       this.active = true;
       this.mode = 'ready';
+      this.isBusy.next(false);
+
       this.render();
       return;
     }
@@ -718,6 +727,7 @@ export class SliderPosition implements ISeriesDrawing {
     this.dragStateSnapshot = this.getState();
     this.didDrag = false;
     this.mode = 'dragging';
+    this.isBusy.next(false);
   };
 
   private handlePointerMove = (event: PointerEvent): void => {
@@ -745,6 +755,8 @@ export class SliderPosition implements ISeriesDrawing {
     this.dragStateSnapshot = null;
     this.didDrag = false;
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.render();
   };
 
diff --git a/src/core/Drawings/traectory/traectory.ts b/src/core/Drawings/traectory/traectory.ts
index 5705640615949f0c1024ac1bab00104e664dc4dd..2db579f756fbdd549932e60c6684f191a331eb21 100644
--- a/src/core/Drawings/traectory/traectory.ts
+++ b/src/core/Drawings/traectory/traectory.ts
@@ -8,7 +8,7 @@ import {
   SeriesOptionsMap,
   Time,
 } from 'lightweight-charts';
-import { Observable } from 'rxjs';
+import { BehaviorSubject, Observable } from 'rxjs';
 
 import { CustomPriceAxisPaneView, CustomTimeAxisPaneView } from '@core/Drawings/axis';
 import {
@@ -76,6 +76,7 @@ export class Traectory implements ISeriesDrawing {
   private hidden = false;
   private isActive = false;
   private mode: TraectoryMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private points: Anchor[] = [];
   private previewAnchor: Anchor | null = null;
@@ -145,7 +146,11 @@ export class Traectory implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle' || this.mode === 'drawing';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): TraectoryState {
@@ -167,6 +172,8 @@ export class Traectory implements ISeriesDrawing {
     this.hidden = typeof nextState.hidden === 'boolean' ? nextState.hidden : this.hidden;
     this.isActive = typeof nextState.isActive === 'boolean' ? nextState.isActive : this.isActive;
     this.mode = nextState.mode ?? this.mode;
+    this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
+
     this.points = Array.isArray(nextState.points) ? nextState.points : this.points;
 
     this.render();
@@ -457,6 +464,8 @@ export class Traectory implements ISeriesDrawing {
     this.previewAnchor = anchor;
     this.isActive = true;
     this.mode = 'drawing';
+    this.isBusy.next(true);
+
     this.render();
   }
 
@@ -505,11 +514,15 @@ export class Traectory implements ISeriesDrawing {
     this.previewAnchor = null;
     this.isActive = true;
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.render();
   }
 
   private startDraggingPoint(point: Point, pointerId: number, pointIndex: number): void {
     this.mode = 'dragging-point';
+    this.isBusy.next(false);
+
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
     this.dragPointIndex = pointIndex;
@@ -521,6 +534,8 @@ export class Traectory implements ISeriesDrawing {
 
   private startDraggingBody(point: Point, pointerId: number): void {
     this.mode = 'dragging-body';
+    this.isBusy.next(false);
+
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
     this.dragPointIndex = null;
@@ -532,6 +547,8 @@ export class Traectory implements ISeriesDrawing {
 
   private finishDragging(): void {
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.dragPointerId = null;
     this.dragStartPoint = null;
     this.dragPointIndex = null;
@@ -544,6 +561,8 @@ export class Traectory implements ISeriesDrawing {
   private resetToIdle(): void {
     this.isActive = false;
     this.mode = 'idle';
+    this.isBusy.next(true);
+
     this.points = [];
     this.previewAnchor = null;
     this.dragPointerId = null;
diff --git a/src/core/Drawings/trendLine/trendLine.ts b/src/core/Drawings/trendLine/trendLine.ts
index ce78d84c0a73fc8a553db98d7e9390099f45b71c..17c593deb09f0d9efcc3eaf525da92d645a3a1e7 100644
--- a/src/core/Drawings/trendLine/trendLine.ts
+++ b/src/core/Drawings/trendLine/trendLine.ts
@@ -10,7 +10,7 @@ import {
   Time,
   UTCTimestamp,
 } from 'lightweight-charts';
-import { Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -87,6 +87,7 @@ export class TrendLine implements ISeriesDrawing {
   private hidden = false;
   private isActive = false;
   private mode: TrendLineMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private startAnchor: Anchor | null = null;
   private endAnchor: Anchor | null = null;
@@ -193,7 +194,11 @@ export class TrendLine implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle' || this.mode === 'drawing';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): TrendLineState {
@@ -219,6 +224,7 @@ export class TrendLine implements ISeriesDrawing {
 
     if ('mode' in nextState && nextState.mode) {
       this.mode = nextState.mode;
+      this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
     }
 
     if ('startAnchor' in nextState) {
@@ -558,6 +564,8 @@ export class TrendLine implements ISeriesDrawing {
     this.endAnchor = anchor;
     this.isActive = true;
     this.mode = 'drawing';
+    this.isBusy.next(true);
+
     this.render();
   }
 
@@ -590,11 +598,15 @@ export class TrendLine implements ISeriesDrawing {
     }
 
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.render();
   }
 
   private startDragging(mode: TrendLineMode, point: Point, pointerId: number): void {
     this.mode = mode;
+    this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
+
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
     this.dragStateSnapshot = this.getState();
@@ -605,6 +617,8 @@ export class TrendLine implements ISeriesDrawing {
 
   private finishDragging(): void {
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.dragPointerId = null;
     this.dragStartPoint = null;
     this.dragStateSnapshot = null;
diff --git a/src/core/Drawings/volumeProfile/volumeProfile.ts b/src/core/Drawings/volumeProfile/volumeProfile.ts
index 086688853b2c59a41ccac83dd4cf263e47c19b2c..c4e388607986089b038ba814101f65be514f9008 100644
--- a/src/core/Drawings/volumeProfile/volumeProfile.ts
+++ b/src/core/Drawings/volumeProfile/volumeProfile.ts
@@ -11,7 +11,7 @@ import {
   Time,
   UTCTimestamp,
 } from 'lightweight-charts';
-import { Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
 
 import {
   CustomPriceAxisPaneView,
@@ -120,6 +120,7 @@ export class VolumeProfile implements ISeriesDrawing {
   private hidden = false;
   private isActive = false;
   private mode: VolumeProfileMode = 'idle';
+  private isBusy: BehaviorSubject<boolean> = new BehaviorSubject(true);
 
   private startAnchor: Anchor | null = null;
   private endAnchor: Anchor | null = null;
@@ -229,7 +230,11 @@ export class VolumeProfile implements ISeriesDrawing {
   }
 
   public isCreationPending(): boolean {
-    return this.mode === 'idle' || this.mode === 'drawing';
+    return this.isBusy.value;
+  }
+
+  public isCreationPendingObs(): Observable<boolean> {
+    return this.isBusy.asObservable();
   }
 
   public getState(): VolumeProfileState {
@@ -248,6 +253,8 @@ export class VolumeProfile implements ISeriesDrawing {
     this.hidden = typeof nextState.hidden === 'boolean' ? nextState.hidden : this.hidden;
     this.isActive = typeof nextState.isActive === 'boolean' ? nextState.isActive : this.isActive;
     this.mode = nextState.mode ?? this.mode;
+    this.isBusy.next(this.mode === 'idle' || this.mode === 'drawing');
+
     this.startAnchor = nextState.startAnchor ?? this.startAnchor;
     this.endAnchor = nextState.endAnchor ?? this.endAnchor;
 
@@ -582,6 +589,7 @@ export class VolumeProfile implements ISeriesDrawing {
     this.endAnchor = anchor;
     this.isActive = true;
     this.mode = 'drawing';
+    this.isBusy.next(true);
 
     this.calculateProfile();
     this.render();
@@ -614,11 +622,15 @@ export class VolumeProfile implements ISeriesDrawing {
     }
 
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.render();
   }
 
   private startDragging(point: Point, pointerId: number, dragTarget: Exclude<DragTarget, null>): void {
     this.mode = 'dragging';
+    this.isBusy.next(false);
+
     this.activeDragTarget = dragTarget;
     this.dragPointerId = pointerId;
     this.dragStartPoint = point;
@@ -630,6 +642,8 @@ export class VolumeProfile implements ISeriesDrawing {
 
   private finishDragging(): void {
     this.mode = 'ready';
+    this.isBusy.next(false);
+
     this.activeDragTarget = null;
     this.dragPointerId = null;
     this.dragStartPoint = null;
@@ -643,6 +657,8 @@ export class VolumeProfile implements ISeriesDrawing {
     this.hidden = false;
     this.isActive = false;
     this.mode = 'idle';
+    this.isBusy.next(true);
+
     this.startAnchor = null;
     this.endAnchor = null;
     this.profileRows = [];
diff --git a/src/core/DrawingsManager.ts b/src/core/DrawingsManager.ts
index f752c543c93aa15b431d409eb687c1119c279508..d9ebc9ba4437b69f3729872602cb13820584f2b9 100644
--- a/src/core/DrawingsManager.ts
+++ b/src/core/DrawingsManager.ts
@@ -191,7 +191,6 @@ export const drawingsMap: Record<DrawingsNames, DrawingConfig> = {
 export class DrawingsManager {
   private eventManager: EventManager;
   private lwcChart: IChartApi;
-  // private chartOptions?: ChartTypeOptions;
   private drawingsQty = 0; // todo: replace with hash
   private DOM: DOMModel;
   private container: HTMLElement;
@@ -199,12 +198,12 @@ export class DrawingsManager {
   private mainSeries: SeriesStrategies | null = null;
   private subscriptions = new Subscription();
   private drawings$: BehaviorSubject<Drawing[]> = new BehaviorSubject<Drawing[]>([]);
+  private isEndlessDrawingMode$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
 
   constructor({ eventManager, mainSeries$, lwcChart, DOM, container }: DrawingsManagerParams) {
     this.DOM = DOM;
     this.eventManager = eventManager;
     this.lwcChart = lwcChart;
-    // this.chartOptions = chartOptions;
     this.container = container;
 
     this.subscriptions.add(
@@ -217,7 +216,7 @@ export class DrawingsManager {
     );
   }
 
-  public addDrawing(name: DrawingsNames) {
+  public async addDrawing(name: DrawingsNames) {
     if (!this.mainSeries) {
       throw new Error('[Drawings] main series is not defined');
     }
@@ -253,10 +252,27 @@ export class DrawingsManager {
         construct,
       });
 
-    const trendLine = this.DOM.setEntity<Drawing>(drawing);
+    const entity = this.DOM.setEntity<Drawing>(drawing);
 
     this.drawingsQty++;
-    this.drawings$.next([...this.drawings$.value, trendLine]);
+    this.drawings$.next([...this.drawings$.value, entity]);
+
+    if (this.isEndlessDrawingMode$.value) {
+      await entity.awaitCreation();
+      this.addDrawing(name);
+    }
+  }
+
+  public setEndlessDrawingMode = (value: boolean) => {
+    this.isEndlessDrawingMode$.next(value);
+
+    if (!value) {
+      this.removePendingDrawings();
+    }
+  };
+
+  public isEndlessDrawingsMode(): Observable<boolean> {
+    return this.isEndlessDrawingMode$;
   }
 
   private removeDrawing = (id: string) => {
diff --git a/src/core/MoexChart.tsx b/src/core/MoexChart.tsx
index 3fb0d6a2b7b086f12ac105f79b8b739c84d0ed20..624a7cfd953b7c09887f58c9bf88d424f140fa0d 100644
--- a/src/core/MoexChart.tsx
+++ b/src/core/MoexChart.tsx
@@ -232,6 +232,8 @@ export class MoexChart {
             // todo: deal with new panes logic
             this.chart.getDrawingsManager().addDrawing(name);
           }}
+          setEndlessDrawingsMode={this.chart.getDrawingsManager().setEndlessDrawingMode}
+          isEndlessDrawingsMode$={this.chart.getDrawingsManager().isEndlessDrawingsMode()}
         />,
       );
     }