findFunnelSegment static method
Find funnel segment at tap location
Implementation
static ChartInteractionResult? findFunnelSegment(
Offset tapPosition,
List<PieData> data,
Size size,
double animationProgress,
) {
if (data.isEmpty) return null;
if (!size.width.isFinite ||
!size.height.isFinite ||
size.width <= 0 ||
size.height <= 0) {
return null;
}
if (!tapPosition.dx.isFinite || !tapPosition.dy.isFinite) {
return null;
}
// Sort data by value (largest to smallest for funnel)
final sortedData = List<PieData>.from(data)
..sort((a, b) => b.value.compareTo(a.value));
final total = sortedData.fold<double>(0, (sum, item) => sum + item.value);
if (total <= 0 || !total.isFinite) return null;
const padding = 40.0;
final chartWidth = size.width - padding * 2;
final chartHeight = size.height - padding * 2;
final centerX = size.width / 2;
double cumulativeHeight = 0.0;
for (int i = 0; i < sortedData.length; i++) {
final segment = sortedData[i];
final percentage = segment.value / total;
final segmentHeight = chartHeight * percentage * animationProgress;
final topWidth = chartWidth;
final bottomWidth = chartWidth * 0.3;
final currentY = cumulativeHeight;
final nextY = cumulativeHeight + segmentHeight;
final progress = currentY / chartHeight;
final nextProgress = nextY / chartHeight;
final currentWidth = topWidth - (topWidth - bottomWidth) * progress;
final nextWidth = topWidth - (topWidth - bottomWidth) * nextProgress;
// Check if tap is within trapezoid bounds
final topLeft = Offset(centerX - currentWidth / 2, padding + currentY);
final topRight = Offset(centerX + currentWidth / 2, padding + currentY);
final bottomRight = Offset(centerX + nextWidth / 2, padding + nextY);
final bottomLeft = Offset(centerX - nextWidth / 2, padding + nextY);
if (_isPointInTrapezoid(
tapPosition,
topLeft,
topRight,
bottomRight,
bottomLeft,
)) {
// Find original index in unsorted data
final originalIndex = data.indexOf(segment);
return ChartInteractionResult(
segment: segment,
elementIndex: originalIndex >= 0 ? originalIndex : i,
isHit: true,
);
}
cumulativeHeight += segmentHeight;
}
return null;
}