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


import {
  getAnchorFromPoint,
  getContainerSize,
  getPriceDelta,
  getXCoordinateFromTime,
  getYCoordinateFromPrice,
  shiftTimeByPixels,
} from '@core/Drawings/helpers';
import { DrawingBase } from '@core/Drawings/DrawingBase';

import type { Anchor, Bounds, ContainerSize, Point } from '@core/Drawings/types';
import type { SettingsValues } from '@src/types';

export type TwoPointAnchorKind = 'start' | 'end';

export interface TwoPointGeometry extends Bounds {
  startPoint: Point;
  endPoint: Point;
}

export abstract class TwoPointDrawingBase<
  TSettings extends SettingsValues = SettingsValues,
  THandleId extends string = string,
> extends DrawingBase<TSettings, THandleId> {
  protected startAnchor: Anchor | null = null;
  protected endAnchor: Anchor | null = null;

  protected getAnchor(kind: TwoPointAnchorKind): Anchor | null {
    return kind === 'start'
      ? this.startAnchor
      : this.endAnchor;
  }

  protected setAnchor(
    kind: TwoPointAnchorKind,
    anchor: Anchor | null,
  ): void {
    if (kind === 'start') {
      this.startAnchor = anchor;
      return;
    }

    this.endAnchor = anchor;
  }

  protected setAnchors(
    startAnchor: Anchor | null,
    endAnchor: Anchor | null,
  ): void {
    this.startAnchor = startAnchor;
    this.endAnchor = endAnchor;
  }

  protected createAnchor(point: Point): Anchor | null {
    return getAnchorFromPoint(
      this.chart,
      this.series,
      point,
    );
  }

  protected getPointFromAnchor(anchor: Anchor | null): Point | null {
    if (!anchor) {
      return null;
    }

    const x = getXCoordinateFromTime(
      this.chart,
      anchor.time,
      this.series,
    );

    const y = getYCoordinateFromPrice(
      this.series,
      anchor.price,
    );

    if (x === null || y === null) {
      return null;
    }

    return {
      x: Number(x),
      y: Number(y),
    };
  }

  protected setAnchorFromPoint(
    kind: TwoPointAnchorKind,
    point: Point,
  ): boolean {
    const anchor = this.createAnchor(point);

    if (!anchor) {
      return false;
    }

    this.setAnchor(
      kind,
      anchor,
    );

    return true;
  }

  protected setAnchorsFromPoints(
    startPoint: Point,
    endPoint: Point,
  ): boolean {
    const startAnchor = this.createAnchor(startPoint);
    const endAnchor = this.createAnchor(endPoint);

    if (!startAnchor || !endAnchor) {
      return false;
    }

    this.setAnchors(
      startAnchor,
      endAnchor,
    );

    return true;
  }

  protected getAnchorTimeCoordinate(
    kind: TwoPointAnchorKind,
  ): number | null {
    const anchor = this.getAnchor(kind);

    if (!anchor) {
      return null;
    }

    const coordinate = getXCoordinateFromTime(
      this.chart,
      anchor.time,
      this.series,
    );

    return coordinate === null
      ? null
      : Number(coordinate);
  }

  protected getAnchorPriceCoordinate(
    kind: TwoPointAnchorKind,
  ): number | null {
    const anchor = this.getAnchor(kind);

    if (!anchor) {
      return null;
    }

    const coordinate = getYCoordinateFromPrice(
      this.series,
      anchor.price,
    );

    return coordinate === null
      ? null
      : Number(coordinate);
  }

  protected moveAnchorsByPixels(
    startAnchor: Anchor | null,
    endAnchor: Anchor | null,
    dragStartPoint: Point | null,
    point: Point,
  ): boolean {
    if (!startAnchor || !endAnchor || !dragStartPoint) {
      return false;
    }

    const offsetX = point.x - dragStartPoint.x;

    const priceOffset = getPriceDelta(
      this.series,
      dragStartPoint.y,
      point.y,
    );

    const nextStartTime = shiftTimeByPixels(
      this.chart,
      startAnchor.time,
      offsetX,
      this.series,
    );

    const nextEndTime = shiftTimeByPixels(
      this.chart,
      endAnchor.time,
      offsetX,
      this.series,
    );

    if (nextStartTime === null || nextEndTime === null) {
      return false;
    }

    this.startAnchor = {
      time: nextStartTime,
      price: startAnchor.price + priceOffset,
    };

    this.endAnchor = {
      time: nextEndTime,
      price: endAnchor.price + priceOffset,
    };

    return true;
  }

  protected getContainerSize(): ContainerSize {
    return getContainerSize(this.container);
  }

  protected getTwoPointGeometry(): TwoPointGeometry | null {
    const startPoint = this.getPointFromAnchor(this.startAnchor);
    const endPoint = this.getPointFromAnchor(this.endAnchor);

    if (!startPoint || !endPoint) {
      return null;
    }

    return {
      startPoint,
      endPoint,
      left: Math.min(startPoint.x, endPoint.x),
      right: Math.max(startPoint.x, endPoint.x),
      top: Math.min(startPoint.y, endPoint.y),
      bottom: Math.max(startPoint.y, endPoint.y),
    };
  }
}