findPyramidSegment static method
Find pyramid chart segment at tap location.
Determines which segment of a pyramid chart contains the tap position by checking if the point is within the trapezoid shape of each segment.
Parameters:
tapPosition- The position where the user tappeddata- List of pie data segments (used for pyramid data)size- Size of the chart areaanimationProgress- Animation progress (0.0 to 1.0)
Returns a ChartInteractionResult if a segment is found, null otherwise.
Implementation
static ChartInteractionResult? findPyramidSegment(
Offset tapPosition,
List<PieData> data,
Size size,
double animationProgress,
) {
if (data.isEmpty) return null;
if (!_isValidSize(size) || !_isValidPosition(tapPosition)) {
return null;
}
if (!animationProgress.isFinite ||
animationProgress < 0.0 ||
animationProgress > 1.0) {
return null;
}
// Sort data by value (largest to smallest for pyramid)
final sortedData = List<PieData>.from(data)
..sort((a, b) => b.value.compareTo(a.value));
final total = sortedData.fold<double>(0.0, (sum, item) => sum + item.value);
if (!_isValidPositiveValue(total)) return null;
final chartWidth = size.width - _defaultPadding * 2;
final chartHeight = size.height - _defaultPadding * 2;
final centerX = size.width / 2;
// Validate chart dimensions after padding
if (chartWidth <= 0 || chartHeight <= 0) return null;
final baseWidth = chartWidth;
final topWidth = chartWidth * _pyramidTopWidthRatio;
final widthDifference = baseWidth - topWidth;
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 currentY = cumulativeHeight;
final nextY = cumulativeHeight + segmentHeight;
final progress = currentY / chartHeight;
final nextProgress = nextY / chartHeight;
final currentWidth = baseWidth - widthDifference * progress;
final nextWidth = baseWidth - widthDifference * nextProgress;
// Check if tap is within trapezoid bounds
final topLeft =
Offset(centerX - currentWidth / 2, _defaultPadding + currentY);
final topRight =
Offset(centerX + currentWidth / 2, _defaultPadding + currentY);
final bottomRight =
Offset(centerX + nextWidth / 2, _defaultPadding + nextY);
final bottomLeft =
Offset(centerX - nextWidth / 2, _defaultPadding + nextY);
if (_isPointInTrapezoid(
tapPosition,
topLeft,
topRight,
bottomRight,
bottomLeft,
)) {
// Find original index in unsorted data
final originalIndex = data.indexOf(segment);
return ChartInteractionResult(
segment: segment,
datasetIndex: 0, // Pyramid charts have a single dataset
elementIndex: originalIndex >= 0 ? originalIndex : i,
isHit: true,
);
}
cumulativeHeight += segmentHeight;
}
return null;
}