findBar static method
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;
}