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


private getHandleTarget(point: Point): RectangleHandleKey | null {
  const geometry = this.getGeometry();

  if (!geometry) {
    return null;
  }

  const handleOrder: RectangleHandleKey[] = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];

  let nearestHandle: RectangleHandleKey | null = null;
  let nearestDistance = Number.POSITIVE_INFINITY;

  for (const handleName of handleOrder) {
    const handle = geometry.handles[handleName];

    const dx = point.x - handle.x;
    const dy = point.y - handle.y;

    if (Math.abs(dx) > HANDLE_HIT_TOLERANCE || Math.abs(dy) > HANDLE_HIT_TOLERANCE) {
      continue;
    }

    const distance = dx * dx + dy * dy;

    if (distance < nearestDistance) {
      nearestDistance = distance;
      nearestHandle = handleName;
    }
  }

  return nearestHandle;
}




function getNearestLogicalFromTime(series: SeriesApi, time: Time): number | null {
  const targetTime = getNumericTime(time);

  if (targetTime === null) {
    return null;
  }

  const points = getSeriesTimePoints(series);

  if (!points.length) {
    return null;
  }

  if (points.length === 1) {
    return points[0].logical;
  }

  const lastIndex = points.length - 1;

  if (targetTime === points[0].time) {
    return points[0].logical;
  }

  if (targetTime === points[lastIndex].time) {
    return points[lastIndex].logical;
  }

  if (targetTime < points[0].time) {
    return projectLogicalByTime(points[0], points[1], targetTime);
  }

  if (targetTime > points[lastIndex].time) {
    return projectLogicalByTime(points[lastIndex - 1], points[lastIndex], targetTime);
  }

  let left = 0;
  let right = lastIndex;

  while (left <= right) {
    const middleIndex = Math.floor((left + right) / 2);
    const middleTime = points[middleIndex].time;

    if (middleTime === targetTime) {
      return points[middleIndex].logical;
    }

    if (middleTime < targetTime) {
      left = middleIndex + 1;
    } else {
      right = middleIndex - 1;
    }
  }

  const previousPoint = points[right] ?? null;
  const nextPoint = points[left] ?? null;

  return getNearestLogicalByTime(targetTime, previousPoint, nextPoint);
}

function projectLogicalByTime(leftPoint: TimePoint, rightPoint: TimePoint, targetTime: number): number | null {
  const timeRange = rightPoint.time - leftPoint.time;

  if (timeRange === 0) {
    return leftPoint.logical;
  }

  const ratio = (targetTime - leftPoint.time) / timeRange;

  return leftPoint.logical + (rightPoint.logical - leftPoint.logical) * ratio;
}