findRadarPoint static method

ChartInteractionResult? findRadarPoint(
  1. Offset tapPosition,
  2. List<RadarDataSet> dataSets,
  3. Size size,
  4. double maxValue,
  5. double animationProgress,
)

Find radar chart point at tap location.

Searches through all radar data sets to find the point closest to the tap position within the specified tap radius. Radar charts have points arranged in a circle.

Parameters:

  • tapPosition - The position where the user tapped
  • dataSets - List of radar data sets to search through
  • size - Size of the chart area
  • maxValue - Maximum value for scaling radar points
  • animationProgress - Animation progress value (0.0 to 1.0)

Returns a ChartInteractionResult if a point is found, null otherwise.

Implementation

static ChartInteractionResult? findRadarPoint(
  Offset tapPosition,
  List<RadarDataSet> dataSets,
  Size size,
  double maxValue,
  double animationProgress,
) {
  if (dataSets.isEmpty) return null;
  if (!_isValidSize(size) || !_isValidPosition(tapPosition)) {
    return null;
  }
  if (!_isValidPositiveValue(maxValue) ||
      !animationProgress.isFinite ||
      animationProgress < 0.0 ||
      animationProgress > 1.0) {
    return null;
  }

  final firstDataSet = dataSets.first;
  // Note: RadarDataSet has dataPoints property (list), not dataPoint
  // This matches the usage in radar_chart_painter.dart
  final numAxes = firstDataSet.dataPoints.length;
  if (numAxes < 3) return null;

  final center = Offset(size.width / 2, size.height / 2);
  final radius = math.min(size.width, size.height) / 2 - _radarRadiusOffset;
  if (!_isValidPositiveValue(radius)) return null;

  // Pre-calculate constants
  final tapRadius = ChartInteractionConstants.tapRadius;
  final tapRadiusSquared = tapRadius * tapRadius;
  const piOver2 = math.pi / 2;
  const twoPi = 2 * math.pi;
  final angleStep = twoPi / numAxes;

  double minDistanceSquared = double.infinity;
  ChartInteractionResult? nearestResult;

  for (int dsIndex = 0; dsIndex < dataSets.length; dsIndex++) {
    final dataSet = dataSets[dsIndex];
    if (dataSet.dataPoints.length != numAxes) continue;

    for (int ptIndex = 0; ptIndex < numAxes; ptIndex++) {
      final radarPoint = dataSet.dataPoints[ptIndex];
      if (!radarPoint.value.isFinite) continue;

      // Calculate angle and point position
      final angle = angleStep * ptIndex - piOver2;
      final value = radarPoint.value.clamp(0.0, maxValue);
      final normalizedValue = (value / maxValue) * animationProgress;
      final pointRadius = radius * normalizedValue;

      final point = Offset(
        center.dx + pointRadius * math.cos(angle),
        center.dy + pointRadius * math.sin(angle),
      );

      // Quick bounds check before distance calculation
      if (!_isWithinQuickBounds(tapPosition, point, tapRadius)) {
        continue;
      }

      // Calculate squared distance using helper
      final distanceSquared = _squaredDistance(tapPosition, point);
      if (distanceSquared == null) continue;

      // Update nearest result if closer
      if (distanceSquared < tapRadiusSquared &&
          distanceSquared < minDistanceSquared) {
        minDistanceSquared = distanceSquared;
        // Convert RadarDataPoint to ChartDataPoint for compatibility
        final chartPoint = ChartDataPoint(
          x: ptIndex.toDouble(),
          y: radarPoint.value,
          label: radarPoint.label,
        );
        nearestResult = ChartInteractionResult(
          point: chartPoint,
          datasetIndex: dsIndex,
          elementIndex: ptIndex,
          isHit: true,
        );
      }
    }
  }

  return nearestResult;
}