findBar static method

ChartInteractionResult? findBar(
  1. Offset tapPosition,
  2. List<ChartDataSet> dataSets,
  3. Size chartSize,
  4. double minX,
  5. double maxX,
  6. double minY,
  7. double maxY,
  8. double barWidth,
)

Find bar at tap location (optimized with early exit)

Implementation

static ChartInteractionResult? findBar(
  Offset tapPosition,
  List<ChartDataSet> dataSets,
  Size chartSize,
  double minX,
  double maxX,
  double minY,
  double maxY,
  double barWidth,
) {
  // Early exit if no data
  if (dataSets.isEmpty) return null;

  // Validate bounds (check for NaN or Infinity)
  if (!minX.isFinite || !maxX.isFinite || !minY.isFinite || !maxY.isFinite) {
    return null;
  }

  // Validate chart size
  if (!chartSize.width.isFinite ||
      !chartSize.height.isFinite ||
      chartSize.width <= 0 ||
      chartSize.height <= 0) {
    return null;
  }

  // Validate tap position
  if (!tapPosition.dx.isFinite || !tapPosition.dy.isFinite) {
    return null;
  }

  // Validate bar width
  if (!barWidth.isFinite || barWidth <= 0) return null;

  final xRange = maxX - minX;
  if (xRange == 0 || !xRange.isFinite) return null;

  // Pre-calculate half bar width
  final halfBarWidth = barWidth / 2;

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

    for (int barIndex = 0; barIndex < dataSet.dataPoints.length; barIndex++) {
      final point = dataSet.dataPoints[barIndex];

      // Validate point values
      if (!point.x.isFinite || !point.y.isFinite) continue;

      // Calculate bar position with NaN protection
      final canvasX = ((point.x - minX) / xRange) * chartSize.width;

      // Validate calculated position
      if (!canvasX.isFinite) continue;

      // Early exit if tap is clearly to the left or right of bar
      if (tapPosition.dx < canvasX - halfBarWidth ||
          tapPosition.dx > canvasX + halfBarWidth) {
        continue;
      }

      // Validate maxY before division
      if (maxY <= 0 || !maxY.isFinite) continue;

      final barHeight = (point.y / maxY) * chartSize.height;
      if (!barHeight.isFinite) continue;

      final barY = chartSize.height - barHeight;
      if (!barY.isFinite) continue;

      // Check if tap is within bar vertical bounds
      if (tapPosition.dy >= barY && tapPosition.dy <= chartSize.height) {
        return ChartInteractionResult(
          point: point,
          datasetIndex: dsIndex,
          elementIndex: barIndex,
          isHit: true,
        );
      }
    }
  }

  return null;
}