findNearestPoint static method
Find nearest point to tap location (optimized with early exit and squared distance).
Searches through all data sets to find the point closest to the tap position within the specified tap radius. Uses squared distance calculations for better performance and includes comprehensive input validation.
Algorithm
- Validates all inputs (bounds, size, position)
- Converts each data point to canvas coordinates
- Uses quick bounds check before distance calculation
- Calculates squared distance (avoids sqrt)
- Returns the nearest point within radius
Performance
- O(n) where n is total number of points across all datasets
- Early exit for points clearly outside radius
- Squared distance avoids expensive sqrt operation
Parameters:
tapPosition- The position where the user tapped (in chart coordinates)dataSets- List of chart data sets to search through (must not be empty)chartSize- Size of the chart area (must be positive and finite)minX,maxX,minY,maxY- Data bounds for coordinate conversion (must be finite)tapRadius- Maximum distance from tap position to consider a hit (must be positive)
Returns a ChartInteractionResult if a point is found within tapRadius,
null otherwise. The result includes the point, dataset index, and element index.
Example
final result = ChartInteractionHelper.findNearestPoint(
Offset(100, 150),
dataSets,
Size(400, 300),
0, 100, 0, 50,
20.0,
);
if (result != null && result.isHit) {
print('Found point: ${result.point!.y}');
}
Throws no exceptions, but returns null for invalid inputs.
Implementation
static ChartInteractionResult? findNearestPoint(
Offset tapPosition,
List<ChartDataSet> dataSets,
Size chartSize,
double minX,
double maxX,
double minY,
double maxY,
double tapRadius,
) {
// Early exit if no data
if (dataSets.isEmpty) return null;
// Validate inputs using helper methods
if (!_isValidSize(chartSize) ||
!_isValidPosition(tapPosition) ||
!_isValidBounds(minX, maxX, minY, maxY) ||
!_isValidPositiveValue(tapRadius)) {
return null;
}
// Pre-calculate squared radius to avoid repeated multiplication
final tapRadiusSquared = tapRadius * tapRadius;
double minDistanceSquared = double.infinity;
ChartInteractionResult? nearestResult;
for (int dsIndex = 0; dsIndex < dataSets.length; dsIndex++) {
final dataSet = dataSets[dsIndex];
final point = dataSet.dataPoint;
// Convert to canvas coordinates using helper
final canvasPoint = _toCanvasCoordinates(
point,
chartSize,
minX,
maxX,
minY,
maxY,
);
if (canvasPoint == null) continue;
// Quick bounds check before distance calculation
if (!_isWithinQuickBounds(tapPosition, canvasPoint, tapRadius)) {
continue;
}
// Calculate squared distance using helper
final distanceSquared = _squaredDistance(tapPosition, canvasPoint);
if (distanceSquared == null) continue;
// Update nearest result if closer
if (distanceSquared < tapRadiusSquared &&
distanceSquared < minDistanceSquared) {
minDistanceSquared = distanceSquared;
nearestResult = ChartInteractionResult(
point: point,
datasetIndex: dsIndex,
elementIndex: 0,
isHit: true,
);
}
}
return nearestResult;
}