findPieSegment static method
Find pie/donut chart segment at tap location.
Determines which segment of a pie or donut chart contains the tap position by calculating the angle from the center. Returns null if tap is outside the chart or in the center hole (for donut charts).
Parameters:
tapPosition- The position where the user tappeddata- List of pie data segmentssize- Size of the chart areacenterSpaceRadius- Inner radius for donut charts (0 for pie charts)
Returns a ChartInteractionResult if a segment is found, null otherwise.
Implementation
static ChartInteractionResult? findPieSegment(
Offset tapPosition,
List<PieData> data,
Size size,
double centerSpaceRadius,
) {
// Validate inputs
if (data.isEmpty) return null;
if (!_isValidSize(size) || !_isValidPosition(tapPosition)) {
return null;
}
final center = Offset(size.width / 2, size.height / 2);
final radius = math.min(size.width, size.height) / 2 - _defaultRadiusOffset;
// Validate radius
if (!_isValidPositiveValue(radius)) return null;
// Check if tap is within chart bounds using squared distance
final distanceSquared = _squaredDistance(tapPosition, center);
if (distanceSquared == null) return null;
final centerSpaceRadiusSquared = centerSpaceRadius * centerSpaceRadius;
final radiusSquared = radius * radius;
if (distanceSquared < centerSpaceRadiusSquared ||
distanceSquared > radiusSquared) {
return null;
}
// Calculate total value
final total = data.fold<double>(0.0, (sum, item) => sum + item.value);
if (!_isValidPositiveValue(total)) return null;
// Pre-calculate constants
const startAngleOffset = -math.pi / 2;
const twoPi = 2 * math.pi;
double startAngle = startAngleOffset;
// Calculate angle from center to tap point
final dx = tapPosition.dx - center.dx;
final dy = tapPosition.dy - center.dy;
final tapAngle = math.atan2(dy, dx);
// Normalize to 0-2π range
final normalizedAngle = (tapAngle + twoPi) % twoPi;
// Pre-calculate value-to-angle conversion factor
final valueToAngle = twoPi / total;
for (int i = 0; i < data.length; i++) {
final item = data[i];
final sweepAngle = item.value * valueToAngle;
final endAngle = startAngle + sweepAngle;
// Normalize start and end angles
final normalizedStart = (startAngle + twoPi) % twoPi;
final normalizedEnd = (endAngle + twoPi) % twoPi;
// Check if tap angle is within segment
final isInSegment = normalizedEnd > normalizedStart
? normalizedAngle >= normalizedStart &&
normalizedAngle <= normalizedEnd
: normalizedAngle >= normalizedStart ||
normalizedAngle <= normalizedEnd;
if (isInSegment) {
return ChartInteractionResult(
segment: item,
datasetIndex: 0, // Pie charts have a single dataset
elementIndex: i,
isHit: true,
);
}
startAngle = endAngle;
}
return null;
}