Загрузка данных
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6210266202a47fde78482776dbd48a66325e4ae2..79efc44dca9c2b91e56e9e02dac959f520e565e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# latest
+- Фикс контейнера дровингов. Теперь их контейнер не содержит `priceScale`
+- Рефактор дровингов
+- Фикс названий дровингов связанных с объёмом
+- Исправлено поведение дровинга `fixed range profile volume`
+- `NaN` получающийся в результате деления на ноль при расчете отосительной цены заменён на `0`
+- К форматированию чисел добавлена обработка бесконечностей
- Исправлена обработка событий клика в модальных окнах
# 0.1.13
diff --git a/src/components/Toolbar/constants.tsx b/src/components/Toolbar/constants.tsx
index dc7a9d5df6d0edcd56e5b31cb199d42a90b36cf8..8e64384c4633234dc0a552dd3c59dea0cd09ee64 100644
--- a/src/components/Toolbar/constants.tsx
+++ b/src/components/Toolbar/constants.tsx
@@ -30,11 +30,11 @@ export const measurementTools = (): MenuOption<DrawingsNames>[] => [
{ value: DrawingsNames.sliderShort, icon: <SlidersHorizontalShortDashedIcon />, label: t('Short position') },
{ value: DrawingsNames.diapsonDates, icon: <DiapsonDatesIcon />, label: t('Dates range') },
{ value: DrawingsNames.diapsonPrices, icon: <DiapsonPricesIcon />, label: t('Prices range') },
- { value: DrawingsNames.fixedRangeProfile, icon: <FixedProfileIcon />, label: t('Fixed profile volume') },
+ { value: DrawingsNames.fixedRangeProfile, icon: <FixedProfileIcon />, label: t('Fixed range profile volume') },
{
value: DrawingsNames.visibleRangeProfile,
icon: <VisibleRangeProfileIcon />,
- label: t('Visible profile volume range'),
+ label: t('Anchored volume profile'),
},
];
diff --git a/src/constants/drawing.ts b/src/constants/drawing.ts
index 741bce86f6652085f51763281a0498a49e66e3dd..dc6b47343c76ca7aa28e07c38b60b4c5fa8e2be4 100644
--- a/src/constants/drawing.ts
+++ b/src/constants/drawing.ts
@@ -47,8 +47,8 @@ export const drawingLabelById = (): Record<DrawingsNames, string> => ({
[DrawingsNames.sliderShort]: t('Short position'),
[DrawingsNames.diapsonDates]: t('Dates range'),
[DrawingsNames.diapsonPrices]: t('Prices range'),
- [DrawingsNames.fixedRangeProfile]: t('Fixed profile volume'),
- [DrawingsNames.visibleRangeProfile]: t('Visible profile volume range'),
+ [DrawingsNames.fixedRangeProfile]: t('Fixed range profile volume'),
+ [DrawingsNames.visibleRangeProfile]: t('Anchored volume profile'),
[DrawingsNames.rectangle]: t('Rectangle'),
[DrawingsNames.traectory]: t('Traectory'),
[DrawingsNames.text]: t('Text'),
diff --git a/src/core/Drawings/axisLine/axisLine.ts b/src/core/Drawings/axisLine/axisLine.ts
index 74faefd59ebd9273a6518816e913eb05a29833c5..7d789c2fa7f4734fae7b9a91ad24b6f31a7a4d12 100644
--- a/src/core/Drawings/axisLine/axisLine.ts
+++ b/src/core/Drawings/axisLine/axisLine.ts
@@ -69,8 +69,6 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
protected settings: AxisLineSettings = createDefaultSettings();
- private isBound = false;
-
protected mode: AxisLineMode = 'idle';
private direction: AxisLineDirection;
@@ -251,7 +249,7 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
};
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (kind !== 'main' || this.direction !== 'vertical' || !this.isActive.value || this.time === null) {
return null;
}
@@ -277,7 +275,7 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (kind !== 'main' || this.direction !== 'horizontal' || !this.isActive.value || this.price === null) {
return null;
}
@@ -298,11 +296,11 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ protected getTimeAxisSegments(): AxisSegment[] {
return [];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
return [];
}
@@ -310,35 +308,7 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
console.log('stub');
}
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready') {
return;
}
@@ -368,7 +338,7 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -429,7 +399,7 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
this.render();
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
@@ -441,7 +411,7 @@ export class AxisLine extends SeriesDrawingBase<AxisLineSettings> implements ISe
this.render();
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/common.ts b/src/core/Drawings/common.ts
index 42dfa937937637257735319b92e5cb5272e44868..17b684c44213d139162207869f8b8ae1c85b493e 100644
--- a/src/core/Drawings/common.ts
+++ b/src/core/Drawings/common.ts
@@ -39,6 +39,8 @@ export interface ISeriesDrawing extends ISeriesPrimitive<Time> {
getSettingsTabs(): SettingsTab[];
subscribeIsSelected(cb: (isSelected: boolean) => void): void;
+
+ getRenderData(): unknown;
}
interface SeriesDrawingBaseParams {
@@ -52,10 +54,11 @@ export abstract class SeriesDrawingBase<TSettings extends SettingsValues = Setti
protected chart: IChartApi;
protected series: SeriesApi;
protected subscriptions = new Subscription();
- protected abstract mode: unknown;
+ protected abstract mode: unknown; // todo: хочется иметь единый mode
protected abstract settings: TSettings;
protected readonly container: HTMLElement;
protected isActive: BehaviorSubject<boolean> = new BehaviorSubject(false);
+ protected isBound = false;
protected readyPromise: null | Promise<void> = null;
protected resolveReady: null | (() => void) = null;
@@ -153,6 +156,20 @@ export abstract class SeriesDrawingBase<TSettings extends SettingsValues = Setti
return null;
}
+ public abstract getRenderData(): unknown; // todo: make proper type
+ public abstract getState(): unknown;
+ public abstract getSettingsTabs(): SettingsTab[];
+ public abstract isCreationPending(): boolean;
+ public abstract setState(state: unknown): void;
+
+ public abstract hitTest(x: number, y: number): PrimitiveHoveredItem | null;
+ public abstract updateAllViews(): void;
+ public abstract paneViews(): readonly IPrimitivePaneView[];
+ public abstract priceAxisPaneViews(): readonly IPrimitivePaneView[];
+ public abstract priceAxisViews(): readonly ISeriesPrimitiveAxisView[];
+ public abstract timeAxisPaneViews(): readonly IPrimitivePaneView[];
+ public abstract timeAxisViews(): readonly ISeriesPrimitiveAxisView[];
+
protected render(): void {
this.updateAllViews();
this.requestUpdate?.();
@@ -178,25 +195,48 @@ export abstract class SeriesDrawingBase<TSettings extends SettingsValues = Setti
return getPointerPointFromEvent(this.container, event);
}
- public abstract getRenderData(): any; // todo: make proper type // todo: добавить в интерфейс\точно ли паблик
- public abstract hitTest(x: number, y: number): PrimitiveHoveredItem | null; // todo: добавить в интерфейс\точно ли паблик
- public abstract getTimeAxisSegments(): AxisSegment[]; // todo: добавить в интерфейс\точно ли паблик
- public abstract getPriceAxisSegments(): AxisSegment[]; // todo: добавить в интерфейс\точно ли паблик
- public abstract getTimeAxisLabel(kind: string): AxisLabel | null; // todo: добавить в интерфейс\точно ли паблик
- public abstract getPriceAxisLabel(kind: string): AxisLabel | null; // todo: добавить в интерфейс\точно ли паблик
- protected abstract bindEvents(): void;
- public abstract updateAllViews(): void;
- protected abstract unbindEvents(): void;
- protected abstract getGeometry(): any; // todo: make proper type // todo: добавить в интерфейс\точно ли паблик
+ protected bindEvents(): void {
+ if (this.isBound) {
+ return;
+ }
- public abstract getSettingsTabs(): SettingsTab[];
- public abstract getState(): unknown;
- public abstract isCreationPending(): boolean;
+ this.isBound = true;
- public abstract paneViews(): readonly IPrimitivePaneView[];
- public abstract priceAxisPaneViews(): readonly IPrimitivePaneView[];
- public abstract priceAxisViews(): readonly ISeriesPrimitiveAxisView[];
- public abstract setState(state: unknown): void;
- public abstract timeAxisPaneViews(): readonly IPrimitivePaneView[];
- public abstract timeAxisViews(): readonly ISeriesPrimitiveAxisView[];
+ this.container.addEventListener('dblclick', this.handleDoubleClick);
+ this.container.addEventListener('pointerdown', this.handlePointerDown);
+ this.container.addEventListener('contextmenu', this.handleContextMenu);
+
+ window.addEventListener('pointermove', this.handlePointerMove);
+ window.addEventListener('pointerup', this.handlePointerUp);
+ window.addEventListener('pointercancel', this.handlePointerUp);
+ }
+
+ protected unbindEvents(): void {
+ if (!this.isBound) {
+ return;
+ }
+
+ this.isBound = false;
+
+ this.container.removeEventListener('dblclick', this.handleDoubleClick);
+ this.container.removeEventListener('pointerdown', this.handlePointerDown);
+ this.container.removeEventListener('contextmenu', this.handleContextMenu);
+
+ window.removeEventListener('pointermove', this.handlePointerMove);
+ window.removeEventListener('pointerup', this.handlePointerUp);
+ window.removeEventListener('pointercancel', this.handlePointerUp);
+ }
+
+ // todo: хочется общую реализацию для каждой кнопки
+ protected handleContextMenu(event: MouseEvent): void {}
+ protected handleDoubleClick(event: MouseEvent): void {}
+ protected handlePointerDown(event: PointerEvent): void {}
+ protected handlePointerMove(event: PointerEvent): void {}
+ protected handlePointerUp(event: PointerEvent): void {}
+
+ protected abstract getGeometry(): unknown; // todo: make proper type
+ protected abstract getTimeAxisSegments(): AxisSegment[];
+ protected abstract getPriceAxisSegments(): AxisSegment[];
+ protected abstract getTimeAxisLabel(kind: string): AxisLabel | null;
+ protected abstract getPriceAxisLabel(kind: string): AxisLabel | null;
}
diff --git a/src/core/Drawings/diapson/diapson.ts b/src/core/Drawings/diapson/diapson.ts
index b6f80a2c7f2c950773dfedc12d748c728ac979c7..023a81eefadca2d32b4f3faae1d89ee63ad3a88b 100644
--- a/src/core/Drawings/diapson/diapson.ts
+++ b/src/core/Drawings/diapson/diapson.ts
@@ -110,8 +110,6 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
protected settings: DiapsonSettings = createDefaultSettings();
- private isBound = false;
-
protected mode: DiapsonMode = 'idle';
private rangeMode: DiapsonRangeMode;
@@ -307,7 +305,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ protected getTimeAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -329,7 +327,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -351,7 +349,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'left' && kind !== 'right')) {
return null;
}
@@ -374,7 +372,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'top' && kind !== 'bottom')) {
return null;
}
@@ -437,35 +435,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
};
}
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready') {
return;
}
@@ -482,7 +452,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -537,7 +507,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
this.startDragging(point, event.pointerId, dragTarget);
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.mode === 'drawing') {
@@ -561,7 +531,7 @@ export class Diapson extends SeriesDrawingBase<DiapsonSettings> implements ISeri
this.render();
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/fibonacciRetracement/fibonacciRetracement.ts b/src/core/Drawings/fibonacciRetracement/fibonacciRetracement.ts
index 3b2223fc372812c73ce91276c55cc6035cb3c163..023f081cf26bfd8420cd5fe334803818705fdd3a 100644
--- a/src/core/Drawings/fibonacciRetracement/fibonacciRetracement.ts
+++ b/src/core/Drawings/fibonacciRetracement/fibonacciRetracement.ts
@@ -117,8 +117,6 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
protected settings: FibonacciRetracementSettings = createDefaultSettings();
- private isBound = false;
-
protected mode: FibonacciRetracementMode = 'idle';
private startTime: Time | null = null;
@@ -304,7 +302,39 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
+ if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
+ return null;
+ }
+
+ const point = { x, y };
+
+ if (!this.isActive.value && !this.containsPoint(point)) {
+ return null;
+ }
+
+ const handleTarget = this.isActive.value ? this.getHandleTarget(point) : null;
+
+ if (handleTarget) {
+ return {
+ cursorStyle: 'pointer',
+ externalId: 'fibonacci-retracement-position',
+ zOrder: 'top',
+ };
+ }
+
+ if (!this.containsPoint(point)) {
+ return null;
+ }
+
+ return {
+ cursorStyle: this.isActive.value ? 'grab' : 'pointer',
+ externalId: 'fibonacci-retracement-position',
+ zOrder: 'top',
+ };
+ }
+
+ protected getTimeAxisSegments(): AxisSegment[] {
const bounds = this.isActive.value ? this.getTimeBounds() : null;
if (!bounds) {
@@ -322,7 +352,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
const bounds = this.isActive.value ? this.getPriceBounds() : null;
if (!bounds) {
@@ -340,7 +370,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
const coordinate = this.isActive.value ? this.getTimeCoordinate(kind as TimeLabelKind) : null;
const text = this.getTimeText(kind as TimeLabelKind);
@@ -358,7 +388,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
const coordinate = this.isActive.value ? this.getPriceCoordinate(kind as PriceLabelKind) : null;
const text = this.getPriceText(kind as PriceLabelKind);
@@ -376,67 +406,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
};
}
- public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
- if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
- return null;
- }
-
- const point = { x, y };
-
- if (!this.isActive.value && !this.containsPoint(point)) {
- return null;
- }
-
- const handleTarget = this.isActive.value ? this.getHandleTarget(point) : null;
-
- if (handleTarget) {
- return {
- cursorStyle: 'pointer',
- externalId: 'fibonacci-retracement-position',
- zOrder: 'top',
- };
- }
-
- if (!this.containsPoint(point)) {
- return null;
- }
-
- return {
- cursorStyle: this.isActive.value ? 'grab' : 'pointer',
- externalId: 'fibonacci-retracement-position',
- zOrder: 'top',
- };
- }
-
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
const point = this.getMousePoint(event);
if (this.hidden || this.mode !== 'ready' || (!this.containsPoint(point) && !this.getHandleTarget(point))) {
@@ -449,7 +419,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -497,7 +467,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
this.startDragging(point, event.pointerId, dragTarget);
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.mode === 'drawing') {
@@ -520,7 +490,7 @@ export class FibonacciRetracement extends SeriesDrawingBase<FibonacciRetracement
this.render();
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/ray/ray.ts b/src/core/Drawings/ray/ray.ts
index 6427435c8cebfbccd866ffed64d6a35284b0e30d..7c1c0a8395e8d8b340805253eb78b7c962475495 100644
--- a/src/core/Drawings/ray/ray.ts
+++ b/src/core/Drawings/ray/ray.ts
@@ -75,8 +75,6 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
protected settings: RaySettings = createDefaultSettings();
- private isBound = false;
-
protected mode: RayMode = 'idle';
private startAnchor: Anchor | null = null;
@@ -279,7 +277,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ protected getTimeAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -301,7 +299,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -323,7 +321,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'start' && kind !== 'direction')) {
return null;
}
@@ -345,7 +343,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'start' && kind !== 'direction')) {
return null;
}
@@ -367,35 +365,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
};
}
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready') {
return;
}
@@ -416,7 +386,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -487,7 +457,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
this.render();
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.mode === 'drawing') {
@@ -517,7 +487,7 @@ export class Ray extends SeriesDrawingBase<RaySettings> implements ISeriesDrawin
}
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/rectangle/rectangle.ts b/src/core/Drawings/rectangle/rectangle.ts
index bba8fe1bdb78da2bd9eaf35034fa55934c405f01..117c65b941707f5ecddc0928f04401ae12670563 100644
--- a/src/core/Drawings/rectangle/rectangle.ts
+++ b/src/core/Drawings/rectangle/rectangle.ts
@@ -103,8 +103,6 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
protected settings: RectangleSettings = createDefaultSettings();
- private isBound = false;
-
protected mode: RectangleMode = 'idle';
private startTime: Time | null = null;
@@ -296,7 +294,47 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
+ if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
+ return null;
+ }
+
+ const point = { x, y };
+
+ if (!this.isActive.value) {
+ if (!this.containsPoint(point)) {
+ return null;
+ }
+
+ return {
+ cursorStyle: 'pointer',
+ externalId: 'rectangle-position',
+ zOrder: 'top',
+ };
+ }
+
+ const handleTarget = this.getHandleTarget(point);
+
+ if (handleTarget) {
+ return {
+ cursorStyle: this.getCursorStyle(handleTarget),
+ externalId: 'rectangle-position',
+ zOrder: 'top',
+ };
+ }
+
+ if (!this.containsPoint(point)) {
+ return null;
+ }
+
+ return {
+ cursorStyle: 'grab',
+ externalId: 'rectangle-position',
+ zOrder: 'top',
+ };
+ }
+
+ protected getTimeAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -318,7 +356,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -340,7 +378,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'left' && kind !== 'right')) {
return null;
}
@@ -363,7 +401,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'top' && kind !== 'bottom')) {
return null;
}
@@ -386,75 +424,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
};
}
- public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
- if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
- return null;
- }
-
- const point = { x, y };
-
- if (!this.isActive.value) {
- if (!this.containsPoint(point)) {
- return null;
- }
-
- return {
- cursorStyle: 'pointer',
- externalId: 'rectangle-position',
- zOrder: 'top',
- };
- }
-
- const handleTarget = this.getHandleTarget(point);
-
- if (handleTarget) {
- return {
- cursorStyle: this.getCursorStyle(handleTarget),
- externalId: 'rectangle-position',
- zOrder: 'top',
- };
- }
-
- if (!this.containsPoint(point)) {
- return null;
- }
-
- return {
- cursorStyle: 'grab',
- externalId: 'rectangle-position',
- zOrder: 'top',
- };
- }
-
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready') {
return;
}
@@ -475,7 +445,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -530,7 +500,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
this.startDragging(point, event.pointerId, dragTarget);
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.mode === 'drawing') {
@@ -554,7 +524,7 @@ export class Rectangle extends SeriesDrawingBase<RectangleSettings> implements I
this.render();
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/ruler/ruler.ts b/src/core/Drawings/ruler/ruler.ts
index 29e152426714b958064d2a9c15ff3333ecad52f6..d4f92979645291b56738c7b4f9f3041b2b3a4c71 100644
--- a/src/core/Drawings/ruler/ruler.ts
+++ b/src/core/Drawings/ruler/ruler.ts
@@ -86,8 +86,6 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
private readonly clickHandler: MouseEventHandler<Time>;
private readonly moveHandler: MouseEventHandler<Time>;
- private isBound = false;
-
private readonly paneView: RulerPaneView;
private readonly timeAxisPaneView: CustomTimeAxisPaneView;
private readonly priceAxisPaneView: CustomPriceAxisPaneView;
@@ -377,7 +375,11 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
return formatPrice(Number(anchor.price)) ?? '';
}
- public getTimeAxisSegments(): AxisSegment[] {
+ public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
+ return null;
+ }
+
+ protected getTimeAxisSegments(): AxisSegment[] {
const bounds = this.getTimeBounds();
if (!bounds) {
@@ -395,7 +397,7 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
const bounds = this.getPriceBounds();
if (!bounds) {
@@ -413,7 +415,7 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (kind !== 'start' && kind !== 'end') {
return null;
}
@@ -435,7 +437,7 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (kind !== 'start' && kind !== 'end') {
return null;
}
@@ -457,10 +459,6 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
};
}
- public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
- return null;
- }
-
private findIndexByTime(time: Time): number {
const data = this.series.data() ?? [];
@@ -474,6 +472,7 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
}
protected bindEvents(): void {
+ // todo: попробовать привести к виду базового класса
if (this.isBound) {
return;
}
@@ -488,6 +487,7 @@ export class Ruler extends SeriesDrawingBase implements ISeriesDrawing {
}
protected unbindEvents(): void {
+ // todo: попробовать привести к виду базового класса
if (!this.isBound) {
return;
}
diff --git a/src/core/Drawings/sliderPosition/sliderPosition.ts b/src/core/Drawings/sliderPosition/sliderPosition.ts
index 43153825fe028c751d07a1ee38de32114595d986..d7bc6dd594a1d7e57810081a57a509f37d9ae9da 100644
--- a/src/core/Drawings/sliderPosition/sliderPosition.ts
+++ b/src/core/Drawings/sliderPosition/sliderPosition.ts
@@ -143,7 +143,6 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
private tickSize = 1;
private ignoreNextChartClick = false;
- private isBound = false;
private readonly clickHandler: MouseEventHandler<Time>;
private readonly paneView: SliderPaneView;
@@ -362,111 +361,6 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
};
}
- public getTimeAxisSegments(): AxisSegment[] {
- if (!this.isActive.value) {
- return [];
- }
-
- const bounds = this.getTimeBounds();
-
- if (!bounds) {
- return [];
- }
-
- const { colors } = getThemeStore();
-
- return [
- {
- from: bounds.left,
- to: bounds.right,
- color: colors.axisMarkerAreaFill,
- },
- ];
- }
-
- public getPriceAxisSegments(): AxisSegment[] {
- if (!this.isActive.value) {
- return [];
- }
-
- const geometry = this.getGeometry();
-
- if (!geometry) {
- return [];
- }
-
- const { colors } = getThemeStore();
-
- return [
- {
- from: geometry.profitTop,
- to: geometry.profitBottom,
- color: colors.axisMarkerAreaFill,
- },
- {
- from: geometry.lossTop,
- to: geometry.lossBottom,
- color: colors.axisMarkerAreaFill,
- },
- ];
- }
-
- public getTimeAxisLabel(kind: string): AxisLabel | null {
- if (!this.isActive.value || (kind !== 'start' && kind !== 'end')) {
- return null;
- }
-
- const labelKind = kind as TimeLabelKind;
- const coordinate = this.getTimeCoordinate(labelKind);
- const text = this.getTimeText(labelKind);
-
- if (coordinate === null || !text) {
- return null;
- }
-
- const { colors } = getThemeStore();
-
- return {
- coordinate,
- text,
- textColor: colors.chartPriceLineText,
- backgroundColor: colors.axisMarkerLabelFill,
- };
- }
-
- public getPriceAxisLabel(kind: string): AxisLabel | null {
- if (kind !== 'target' && kind !== 'entry' && kind !== 'stop') {
- return null;
- }
-
- const labelKind = kind as PriceLabelKind;
- const coordinate = this.getPriceCoordinate(labelKind);
- const text = this.getPriceText(labelKind);
-
- if (coordinate === null || !text) {
- return null;
- }
-
- const { colors } = getThemeStore();
-
- let backgroundColor = colors.axisMarkerLabelDefaultFill;
-
- if (labelKind === 'target') {
- backgroundColor = colors.axisMarkerLabelPositiveFill;
- }
-
- if (labelKind === 'stop') {
- backgroundColor = colors.axisMarkerLabelNegativeFill;
- }
-
- return {
- coordinate,
- text,
- textColor: colors.chartPriceLineText,
- backgroundColor,
- };
- }
-
public getTimeBounds(): { left: number; right: number } | null {
const start = this.getTimeCoordinate('start');
const end = this.getTimeCoordinate('end');
@@ -583,7 +477,113 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
};
}
+ protected getTimeAxisSegments(): AxisSegment[] {
+ if (!this.isActive.value) {
+ return [];
+ }
+
+ const bounds = this.getTimeBounds();
+
+ if (!bounds) {
+ return [];
+ }
+
+ const { colors } = getThemeStore();
+
+ return [
+ {
+ from: bounds.left,
+ to: bounds.right,
+ color: colors.axisMarkerAreaFill,
+ },
+ ];
+ }
+
+ protected getPriceAxisSegments(): AxisSegment[] {
+ if (!this.isActive.value) {
+ return [];
+ }
+
+ const geometry = this.getGeometry();
+
+ if (!geometry) {
+ return [];
+ }
+
+ const { colors } = getThemeStore();
+
+ return [
+ {
+ from: geometry.profitTop,
+ to: geometry.profitBottom,
+ color: colors.axisMarkerAreaFill,
+ },
+ {
+ from: geometry.lossTop,
+ to: geometry.lossBottom,
+ color: colors.axisMarkerAreaFill,
+ },
+ ];
+ }
+
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
+ if (!this.isActive.value || (kind !== 'start' && kind !== 'end')) {
+ return null;
+ }
+
+ const labelKind = kind as TimeLabelKind;
+ const coordinate = this.getTimeCoordinate(labelKind);
+ const text = this.getTimeText(labelKind);
+
+ if (coordinate === null || !text) {
+ return null;
+ }
+
+ const { colors } = getThemeStore();
+
+ return {
+ coordinate,
+ text,
+ textColor: colors.chartPriceLineText,
+ backgroundColor: colors.axisMarkerLabelFill,
+ };
+ }
+
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
+ if (kind !== 'target' && kind !== 'entry' && kind !== 'stop') {
+ return null;
+ }
+
+ const labelKind = kind as PriceLabelKind;
+ const coordinate = this.getPriceCoordinate(labelKind);
+ const text = this.getPriceText(labelKind);
+
+ if (coordinate === null || !text) {
+ return null;
+ }
+
+ const { colors } = getThemeStore();
+
+ let backgroundColor = colors.axisMarkerLabelDefaultFill;
+
+ if (labelKind === 'target') {
+ backgroundColor = colors.axisMarkerLabelPositiveFill;
+ }
+
+ if (labelKind === 'stop') {
+ backgroundColor = colors.axisMarkerLabelNegativeFill;
+ }
+
+ return {
+ coordinate,
+ text,
+ textColor: colors.chartPriceLineText,
+ backgroundColor,
+ };
+ }
+
protected bindEvents(): void {
+ // todo: почему то отличается от базового класса
if (this.isBound) {
return;
}
@@ -600,6 +600,7 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
}
protected unbindEvents(): void {
+ // todo: почему то отличается от базового класса
if (!this.isBound) {
return;
}
@@ -615,7 +616,7 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
window.removeEventListener('pointercancel', this.handlePointerUp);
}
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready' || !this.isActive.value) {
return;
}
@@ -675,7 +676,7 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
this.render();
}
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || this.mode !== 'ready' || !this.isActive.value) {
return;
}
@@ -698,7 +699,7 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
this.mode = 'dragging';
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId || !this.dragStateSnapshot) {
return;
}
@@ -710,7 +711,7 @@ export class SliderPosition extends SeriesDrawingBase<SliderPositionSettings> im
this.render();
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/text/text.ts b/src/core/Drawings/text/text.ts
index 3711206afe3a5b53a03dbc961ea1273503e5d8a5..428dad133c9af41a194c4ab50c0111f3a195ede6 100644
--- a/src/core/Drawings/text/text.ts
+++ b/src/core/Drawings/text/text.ts
@@ -74,8 +74,6 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
private readonly removeSelf?: () => void;
private readonly openSettings?: () => void;
- private isBound = false;
-
protected mode: TextMode = 'idle';
private displayFormat: ChartOptionsModel = {
@@ -210,7 +208,23 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
};
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
+ if (this.hidden || this.mode === 'idle') {
+ return null;
+ }
+
+ if (!this.containsPoint({ x, y })) {
+ return null;
+ }
+
+ return {
+ cursorStyle: 'move',
+ externalId: 'text',
+ zOrder: 'top',
+ };
+ }
+
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (kind !== 'main' || !this.isActive.value || !this.point || typeof this.point.time !== 'number') {
return null;
}
@@ -236,7 +250,7 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (kind !== 'main' || !this.isActive.value || !this.point) {
return null;
}
@@ -257,59 +271,15 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
};
}
- public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
- if (this.hidden || this.mode === 'idle') {
- return null;
- }
-
- if (!this.containsPoint({ x, y })) {
- return null;
- }
-
- return {
- cursorStyle: 'move',
- externalId: 'text',
- zOrder: 'top',
- };
- }
-
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
return [];
}
- public getTimeAxisSegments(): AxisSegment[] {
+ protected getTimeAxisSegments(): AxisSegment[] {
return [];
}
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -355,7 +325,7 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
this.render();
};
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready' || !this.isActive.value) {
return;
}
@@ -372,7 +342,7 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
this.openSettings?.();
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
if (this.dragPointerId !== event.pointerId || this.mode !== 'dragging') {
return;
}
@@ -383,7 +353,7 @@ export class Text extends SeriesDrawingBase<TextSettings> implements ISeriesDraw
this.render();
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/traectory/traectory.ts b/src/core/Drawings/traectory/traectory.ts
index 968f22a6d2fe1ac013be3462d5235008996e5a98..fd458aeeea80b0d2d32d344945e6473e621a115c 100644
--- a/src/core/Drawings/traectory/traectory.ts
+++ b/src/core/Drawings/traectory/traectory.ts
@@ -66,8 +66,6 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
protected settings: TraectorySettings = createDefaultSettings();
- private isBound = false;
-
protected mode: TraectoryMode = 'idle';
private points: Anchor[] = [];
@@ -189,7 +187,34 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
+ if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
+ return null;
+ }
+
+ const point = { x, y };
+ const pointIndex = this.getPointIndexAt(point);
+
+ if (pointIndex !== null) {
+ return {
+ cursorStyle: 'move',
+ externalId: 'traectory',
+ zOrder: 'top',
+ };
+ }
+
+ if (!this.isPointNearTraectory(point)) {
+ return null;
+ }
+
+ return {
+ cursorStyle: 'move',
+ externalId: 'traectory',
+ zOrder: 'top',
+ };
+ }
+
+ protected getTimeAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -211,7 +236,7 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -233,72 +258,15 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
];
}
- public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
- if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
- return null;
- }
-
- const point = { x, y };
- const pointIndex = this.getPointIndexAt(point);
-
- if (pointIndex !== null) {
- return {
- cursorStyle: 'move',
- externalId: 'traectory',
- zOrder: 'top',
- };
- }
-
- if (!this.isPointNearTraectory(point)) {
- return null;
- }
-
- return {
- cursorStyle: 'move',
- externalId: 'traectory',
- zOrder: 'top',
- };
- }
-
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
return null;
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
return null;
}
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('contextmenu', this.handleContextMenu);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('contextmenu', this.handleContextMenu);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden) {
return;
}
@@ -330,7 +298,7 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
this.openSettings?.();
};
- private handleContextMenu = (event: MouseEvent): void => {
+ protected handleContextMenu = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'drawing') {
return;
}
@@ -341,7 +309,7 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
this.finishDrawing();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -408,7 +376,7 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
this.startDraggingBody(point, event.pointerId);
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.mode === 'drawing') {
@@ -434,7 +402,7 @@ export class Traectory extends SeriesDrawingBase<TraectorySettings> implements I
}
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/trendLine/trendLine.ts b/src/core/Drawings/trendLine/trendLine.ts
index 514e804fa62d28824ac015e1bf837445d1e9a93b..fc3663cda2fb3288905259aac0bb21e567ee6bff 100644
--- a/src/core/Drawings/trendLine/trendLine.ts
+++ b/src/core/Drawings/trendLine/trendLine.ts
@@ -79,8 +79,6 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
protected settings: TrendLineSettings = createDefaultSettings();
- private isBound = false;
-
protected mode: TrendLineMode = 'idle';
private startAnchor: Anchor | null = null;
@@ -283,7 +281,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ protected getTimeAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -305,7 +303,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
if (!this.isActive.value) {
return [];
}
@@ -327,7 +325,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'start' && kind !== 'end')) {
return null;
}
@@ -349,7 +347,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (!this.isActive.value || (kind !== 'start' && kind !== 'end')) {
return null;
}
@@ -371,35 +369,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
};
}
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
return;
}
@@ -420,7 +390,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -491,7 +461,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
this.render();
};
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.mode === 'drawing') {
@@ -521,7 +491,7 @@ export class TrendLine extends SeriesDrawingBase<TrendLineSettings> implements I
}
};
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.dragPointerId !== event.pointerId) {
return;
}
diff --git a/src/core/Drawings/volumeProfile/volumeProfile.ts b/src/core/Drawings/volumeProfile/volumeProfile.ts
index 3b4ce5137c2a2c8b9a2d3d29dfd50f86756c88ac..d17554e8b2389dd1897869f4b3afd3b60e1d1316 100644
--- a/src/core/Drawings/volumeProfile/volumeProfile.ts
+++ b/src/core/Drawings/volumeProfile/volumeProfile.ts
@@ -123,7 +123,6 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
private readonly profileKind: VolumeProfileKind;
protected settings: VolumeProfileSettings = createDefaultSettings();
- private isBound = false;
protected mode: VolumeProfileMode = 'idle';
private startAnchor: Anchor | null = null;
@@ -364,7 +363,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
};
}
- public getTimeAxisSegments(): AxisSegment[] {
+ protected getTimeAxisSegments(): AxisSegment[] {
if (this.profileKind === 'visibleRange' || !this.isActive.value) {
return [];
}
@@ -386,7 +385,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
];
}
- public getPriceAxisSegments(): AxisSegment[] {
+ protected getPriceAxisSegments(): AxisSegment[] {
if (this.profileKind === 'visibleRange' || !this.isActive.value) {
return [];
}
@@ -408,7 +407,33 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
];
}
- public getTimeAxisLabel(kind: string): AxisLabel | null {
+ public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
+ if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
+ return null;
+ }
+
+ const dragTarget = this.getDragTarget({ x, y });
+
+ if (!dragTarget) {
+ return null;
+ }
+
+ if (dragTarget === 'poc') {
+ return {
+ cursorStyle: 'ew-resize',
+ externalId: 'volume-profile',
+ zOrder: 'top',
+ };
+ }
+
+ return {
+ cursorStyle: this.isActive.value ? 'grab' : 'pointer',
+ externalId: 'volume-profile',
+ zOrder: 'top',
+ };
+ }
+
+ protected getTimeAxisLabel(kind: string): AxisLabel | null {
if (this.profileKind === 'visibleRange') {
return null;
}
@@ -444,7 +469,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
};
}
- public getPriceAxisLabel(kind: string): AxisLabel | null {
+ protected getPriceAxisLabel(kind: string): AxisLabel | null {
if (this.profileKind === 'visibleRange') {
return null;
}
@@ -475,32 +500,6 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
};
}
- public hitTest(x: number, y: number): PrimitiveHoveredItem | null {
- if (this.hidden || this.mode === 'idle' || this.mode === 'drawing') {
- return null;
- }
-
- const dragTarget = this.getDragTarget({ x, y });
-
- if (!dragTarget) {
- return null;
- }
-
- if (dragTarget === 'poc') {
- return {
- cursorStyle: 'ew-resize',
- externalId: 'volume-profile',
- zOrder: 'top',
- };
- }
-
- return {
- cursorStyle: this.isActive.value ? 'grab' : 'pointer',
- externalId: 'volume-profile',
- zOrder: 'top',
- };
- }
-
private handleVisibleLogicalRangeChange = (): void => {
if (this.profileKind !== 'visibleRange') {
return;
@@ -510,35 +509,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
this.render();
};
- protected bindEvents(): void {
- if (this.isBound) {
- return;
- }
-
- this.isBound = true;
-
- this.container.addEventListener('dblclick', this.handleDoubleClick);
- this.container.addEventListener('pointerdown', this.handlePointerDown);
- window.addEventListener('pointermove', this.handlePointerMove);
- window.addEventListener('pointerup', this.handlePointerUp);
- window.addEventListener('pointercancel', this.handlePointerUp);
- }
-
- protected unbindEvents(): void {
- if (!this.isBound) {
- return;
- }
-
- this.isBound = false;
-
- this.container.removeEventListener('dblclick', this.handleDoubleClick);
- this.container.removeEventListener('pointerdown', this.handlePointerDown);
- window.removeEventListener('pointermove', this.handlePointerMove);
- window.removeEventListener('pointerup', this.handlePointerUp);
- window.removeEventListener('pointercancel', this.handlePointerUp);
- }
-
- private handleDoubleClick = (event: MouseEvent): void => {
+ protected handleDoubleClick = (event: MouseEvent): void => {
if (this.hidden || this.mode !== 'ready' || !this.isActive.value) {
return;
}
@@ -555,7 +526,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
this.openSettings?.();
};
- private handlePointerDown = (event: PointerEvent): void => {
+ protected handlePointerDown = (event: PointerEvent): void => {
if (this.hidden || event.button !== 0) {
return;
}
@@ -570,7 +541,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
this.handleFixedRangePointerDown(event, point);
};
- private handleVisibleRangePointerDown(event: PointerEvent, point: Point): void {
+ protected handleVisibleRangePointerDown(event: PointerEvent, point: Point): void {
const dragTarget = this.getVisibleRangeDragTarget(point);
if (!dragTarget) {
@@ -646,7 +617,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
this.startDragging(point, event.pointerId, dragTarget);
}
- private handlePointerMove = (event: PointerEvent): void => {
+ protected handlePointerMove = (event: PointerEvent): void => {
const point = this.getEventPoint(event);
if (this.profileKind === 'visibleRange') {
@@ -691,7 +662,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
this.render();
}
- private handlePointerUp = (event: PointerEvent): void => {
+ protected handlePointerUp = (event: PointerEvent): void => {
if (this.mode !== 'dragging' || this.dragPointerId !== event.pointerId) {
return;
}
@@ -931,14 +902,14 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
private calculateProfile(): void {
if (this.profileKind === 'visibleRange') {
- this.calculateVisibleRangeProfile();
+ this.calculateAnchoredVolumeProfile();
return;
}
- this.calculateFixedRangeProfile();
+ this.calculateFixedRangeVolumeProfile();
}
- private calculateVisibleRangeProfile(): void {
+ private calculateAnchoredVolumeProfile(): void {
const visibleRange = this.chart.timeScale().getVisibleLogicalRange();
if (!visibleRange) {
@@ -953,31 +924,33 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
this.calculateProfileByLogicalRange(start, to);
}
- private calculateFixedRangeProfile(): void {
+ private calculateFixedRangeVolumeProfile(): void {
if (!this.startAnchor || !this.endAnchor) {
this.clearProfile();
return;
}
- const leftTime = Math.min(Number(this.startAnchor.time), Number(this.endAnchor.time));
- const rightTime = Math.max(Number(this.startAnchor.time), Number(this.endAnchor.time));
+ const leftFrameTime = Math.min(Number(this.startAnchor.time), Number(this.endAnchor.time));
+ const rightFrameTime = Math.max(Number(this.startAnchor.time), Number(this.endAnchor.time));
- if (!Number.isFinite(leftTime) || !Number.isFinite(rightTime)) {
- this.clearProfile();
- return;
- }
+ const candles = this.series.data() as SeriesCandleData[];
+ const selectedCandles: SeriesCandleData[] = [];
+
+ let maxFramePrice = Math.max(this.startAnchor.price, this.startAnchor.price);
+ let minFramePrice = Math.min(this.startAnchor.price, this.startAnchor.price);
- const candles = (this.series.data() as SeriesCandleData[]).filter((candle) => {
- const time = Number(candle.time);
+ candles.forEach((candle) => {
+ const candleTime = Number(candle.time);
+
+ if (candleTime >= leftFrameTime && candleTime <= rightFrameTime) {
+ maxFramePrice = Math.max(candle.high ?? candle.value ?? -Infinity, maxFramePrice);
+ minFramePrice = Math.min(candle.low ?? candle.value ?? Infinity, minFramePrice);
- return Number.isFinite(time) && time >= leftTime && time <= rightTime;
+ selectedCandles.push(candle);
+ }
});
- this.calculateProfileByCandles(
- candles,
- Math.min(this.startAnchor.price, this.endAnchor.price),
- Math.max(this.startAnchor.price, this.endAnchor.price),
- );
+ this.calculateProfileByCandles(selectedCandles);
}
private calculateProfileByLogicalRange(fromLogical: number, toLogical: number): void {
@@ -1059,7 +1032,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
const isBuyVolume = this.isBuyVolume(candle);
if (candleHigh === candleLow) {
- this.addPointVolume(profileRows, price, volume, isBuyVolume);
+ addPointVolume(profileRows, candleHigh, volume, isBuyVolume);
return;
}
@@ -1074,7 +1047,7 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
return;
}
- this.addVolumeToRow(row, volume * (overlap / candleRange), isBuyVolume);
+ addVolumeToRow(row, volume * (overlap / candleRange), isBuyVolume);
});
});
@@ -1148,48 +1121,19 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
return close >= open;
}
- private addPointVolume(
- profileRows: VolumeProfileDataRow[],
- price: number,
- volume: number,
- isBuyVolume: boolean,
- ): void {
- const row = profileRows.find((item, index) => {
- const isLastRow = index === profileRows.length - 1;
-
- return price >= item.priceLow && (price < item.priceHigh || isLastRow);
- });
-
- if (!row) {
- return;
- }
-
- this.addVolumeToRow(row, volume, isBuyVolume);
- }
-
- private addVolumeToRow(row: VolumeProfileDataRow, volume: number, isBuyVolume: boolean): void {
- if (isBuyVolume) {
- row.buyVolume += volume;
- } else {
- row.sellVolume += volume;
- }
-
- row.totalVolume += volume;
- }
-
private getNumber(value: unknown): number | null {
return typeof value === 'number' && Number.isFinite(value) ? value : null;
}
protected getGeometry(): VolumeProfileGeometry | null {
if (this.profileKind === 'visibleRange') {
- return this.getVisibleRangeGeometry();
+ return this.getAnchoredVolumeProfileGeometry();
}
- return this.getFixedRangeGeometry();
+ return this.getFixedRangeVolumeProfileGeometry();
}
- private getVisibleRangeGeometry(): VolumeProfileGeometry | null {
+ private getAnchoredVolumeProfileGeometry(): VolumeProfileGeometry | null {
if (this.profileMinPrice === null || this.profileMaxPrice === null) {
return null;
}
@@ -1226,15 +1170,19 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
};
}
- private getFixedRangeGeometry(): VolumeProfileGeometry | null {
+ private getFixedRangeVolumeProfileGeometry(): VolumeProfileGeometry | null {
if (!this.startAnchor || !this.endAnchor) {
return null;
}
+ if (this.profileMinPrice === null || this.profileMaxPrice === null) {
+ return null;
+ }
+
const startX = getXCoordinateFromTime(this.chart, this.startAnchor.time, this.series);
const endX = getXCoordinateFromTime(this.chart, this.endAnchor.time, this.series);
- const startY = getYCoordinateFromPrice(this.series, this.startAnchor.price);
- const endY = getYCoordinateFromPrice(this.series, this.endAnchor.price);
+ const startY = getYCoordinateFromPrice(this.series, this.profileMinPrice);
+ const endY = getYCoordinateFromPrice(this.series, this.profileMaxPrice);
if (startX === null || endX === null || startY === null || endY === null) {
return null;
@@ -1331,3 +1279,32 @@ export class VolumeProfile extends SeriesDrawingBase<VolumeProfileSettings> impl
return clampPointToContainerInElement(point, this.container);
}
}
+
+function addPointVolume(
+ profileRows: VolumeProfileDataRow[],
+ price: number,
+ volume: number,
+ isBuyVolume: boolean,
+): void {
+ const row = profileRows.find((item, index) => {
+ const isLastRow = index === profileRows.length - 1;
+
+ return price >= item.priceLow && (price < item.priceHigh || isLastRow);
+ });
+
+ if (!row) {
+ return;
+ }
+
+ addVolumeToRow(row, volume, isBuyVolume);
+}
+
+function addVolumeToRow(row: VolumeProfileDataRow, volume: number, isBuyVolume: boolean): void {
+ if (isBuyVolume) {
+ row.buyVolume += volume;
+ } else {
+ row.sellVolume += volume;
+ }
+
+ row.totalVolume += volume;
+}
diff --git a/src/core/DrawingsManager.tsx b/src/core/DrawingsManager.tsx
index a879e9903d3c4e64b1b1abf75124edf89612f2b3..e4f85b64aa0f26c156fc1d626fac5eebf046c857 100644
--- a/src/core/DrawingsManager.tsx
+++ b/src/core/DrawingsManager.tsx
@@ -250,12 +250,21 @@ export class DrawingsManager {
let createdDrawing: Drawing | null = null;
- const construct = (chart: IChartApi, series: ISeriesApi<SeriesType>) =>
- config.construct({
+ const construct = (chart: IChartApi, series: ISeriesApi<SeriesType>) => {
+ const paneElement = series.getPane().getHTMLElement();
+
+ if (!paneElement) {
+ throw new Error('[Drawing Manager]: cannot place drawing, there is no pane');
+ }
+
+ const cells = paneElement.querySelectorAll<HTMLTableCellElement>(':scope > td');
+ const canvasElement = cells.item(1);
+
+ return config.construct({
chart,
series,
eventManager: this.eventManager,
- container: this.container,
+ container: canvasElement,
removeSelf: () => this.removeDrawing(drawingId),
openSettings: () => {
if (createdDrawing) {
@@ -263,6 +272,7 @@ export class DrawingsManager {
}
},
});
+ };
const drawingFactory = (zIndex: number, moveUp: (id: string) => void, moveDown: (id: string) => void) =>
new Drawing({
diff --git a/src/core/Series/BaseSeries.ts b/src/core/Series/BaseSeries.ts
index 335be26bfb487b10723c7d1a750d74d83b0f8bdb..ff74500b01d18fed3bcb206e9fe1595082e5de51 100644
--- a/src/core/Series/BaseSeries.ts
+++ b/src/core/Series/BaseSeries.ts
@@ -443,7 +443,7 @@ export function calcCandleChange(
return {
...current,
absoluteChange,
- percentageChange,
+ percentageChange: Number.isNaN(percentageChange) ? 0 : percentageChange,
};
}
@@ -459,7 +459,7 @@ export function calcCandleChange(
high: typeof high === 'number' ? high : current.value,
low: typeof low === 'number' ? low : current.value,
absoluteChange,
- percentageChange,
+ percentageChange: Number.isNaN(percentageChange) ? 0 : percentageChange,
customValues: current.customValues,
};
}
diff --git a/src/translations/russianDict.ts b/src/translations/russianDict.ts
index 97958be08505b6360363667f62e770e8438b329d..6d50a79f1e1bc4cd446434531b5a40804bd76128 100644
--- a/src/translations/russianDict.ts
+++ b/src/translations/russianDict.ts
@@ -46,8 +46,8 @@ export const russian = {
'Short position': 'Короткая позиция',
'Dates range': 'Диапазон дат',
'Prices range': 'Диапазон цен',
- 'Fixed profile volume': 'Фиксированный профиль объема',
- 'Visible profile volume range': 'Профиль объема видимого диапазона',
+ 'Fixed range profile volume': 'Профиль объема в заданном диапазоне',
+ 'Anchored volume profile': 'Профиль объема с привязкой',
'Fibonacci retracement': 'Коррекция Фибоначчи',
Rectangle: 'Прямоугольник',
Traectory: 'Траектория',
diff --git a/src/utils/formatValues.ts b/src/utils/formatValues.ts
index 2b23849eb912f61fa897e97daf0fe02748d6aebe..0b568b64798cbfbd55cd050624a54d1a1eeb4919 100644
--- a/src/utils/formatValues.ts
+++ b/src/utils/formatValues.ts
@@ -13,6 +13,16 @@ export function formatCompactNumber(
locale: Locale = getLocale(),
maxFractionDigits: number = getPricePrecision(),
): string {
+ const formatter = new Intl.NumberFormat(locale, {
+ maximumFractionDigits: maxFractionDigits,
+ minimumFractionDigits: 0,
+ useGrouping: false,
+ });
+
+ if (value === Infinity || value === -Infinity) {
+ return formatter.format(value);
+ }
+
const unitList: {
divisor: number;
suffix: string;
@@ -38,12 +48,6 @@ export function formatCompactNumber(
}
const divided = value / selectedUnit.divisor;
- const formatter = new Intl.NumberFormat(locale, {
- maximumFractionDigits: maxFractionDigits,
- minimumFractionDigits: 0,
- useGrouping: false,
- });
-
return formatter.format(divided) + selectedUnit.suffix;
}