drawTouchTooltip method
void
drawTouchTooltip(
- BuildContext context,
- CanvasWrapper canvasWrapper,
- LineTouchTooltipData tooltipData,
- AFlSpot showOnSpot,
- ShowingTooltipIndicators showingTooltipSpots,
- PaintHolder<
LineChartData> holder,
Implementation
@visibleForTesting
void drawTouchTooltip(
BuildContext context,
CanvasWrapper canvasWrapper,
LineTouchTooltipData tooltipData,
AFlSpot showOnSpot,
ShowingTooltipIndicators showingTooltipSpots,
PaintHolder<LineChartData> holder,
) {
final viewSize = canvasWrapper.size;
const textsBelowMargin = 4;
/// creating TextPainters to calculate the width and height of the tooltip
final drawingTextPainters = <TextPainter>[];
final tooltipItems =
tooltipData.getTooltipItems(showingTooltipSpots.showingSpots);
if (tooltipItems.length != showingTooltipSpots.showingSpots.length) {
throw Exception('tooltipItems and touchedSpots size should be same');
}
for (var i = 0; i < showingTooltipSpots.showingSpots.length; i++) {
final tooltipItem = tooltipItems[i];
if (tooltipItem == null) {
continue;
}
final span = TextSpan(
style: Utils().getThemeAwareTextStyle(context, tooltipItem.textStyle),
text: tooltipItem.text,
children: tooltipItem.children,
);
final tp = TextPainter(
text: span,
textAlign: tooltipItem.textAlign,
textDirection: tooltipItem.textDirection,
textScaleFactor: holder.textScale,
)..layout(maxWidth: tooltipData.maxContentWidth);
drawingTextPainters.add(tp);
}
if (drawingTextPainters.isEmpty) {
return;
}
/// biggerWidth
/// some texts maybe larger, then we should
/// draw the tooltip' width as wide as biggerWidth
///
/// sumTextsHeight
/// sum up all Texts height, then we should
/// draw the tooltip's height as tall as sumTextsHeight
var biggerWidth = 0.0;
var sumTextsHeight = 0.0;
for (final tp in drawingTextPainters) {
if (tp.width > biggerWidth) {
biggerWidth = tp.width;
}
sumTextsHeight += tp.height;
}
sumTextsHeight += (drawingTextPainters.length - 1) * textsBelowMargin;
/// if we have multiple bar lines,
/// there are more than one FlCandidate on touch area,
/// we should get the most top FlSpot Offset to draw the tooltip on top of it
final mostTopOffset = Offset(
getPixelX(showOnSpot.x, viewSize, holder),
getPixelY(showOnSpot.y, viewSize, holder),
);
final tooltipWidth = biggerWidth + tooltipData.tooltipPadding.horizontal;
final tooltipHeight = sumTextsHeight + tooltipData.tooltipPadding.vertical;
double tooltipTopPosition;
if (tooltipData.showOnTopOfTheChartBoxArea) {
tooltipTopPosition = 0 - tooltipHeight - tooltipData.tooltipMargin;
} else {
tooltipTopPosition =
mostTopOffset.dy - tooltipHeight - tooltipData.tooltipMargin;
}
final tooltipLeftPosition = getTooltipLeft(
mostTopOffset.dx,
tooltipWidth,
tooltipData.tooltipHorizontalAlignment,
tooltipData.tooltipHorizontalOffset,
);
/// draw the background rect with rounded radius
var rect = Rect.fromLTWH(
tooltipLeftPosition,
tooltipTopPosition,
tooltipWidth,
tooltipHeight,
);
if (tooltipData.fitInsideHorizontally) {
if (rect.left < 0) {
final shiftAmount = 0 - rect.left;
rect = Rect.fromLTRB(
rect.left + shiftAmount,
rect.top,
rect.right + shiftAmount,
rect.bottom,
);
}
if (rect.right > viewSize.width) {
final shiftAmount = rect.right - viewSize.width;
rect = Rect.fromLTRB(
rect.left - shiftAmount,
rect.top,
rect.right - shiftAmount,
rect.bottom,
);
}
}
if (tooltipData.fitInsideVertically) {
if (rect.top < 0) {
final shiftAmount = 0 - rect.top;
rect = Rect.fromLTRB(
rect.left,
rect.top + shiftAmount,
rect.right,
rect.bottom + shiftAmount,
);
}
if (rect.bottom > viewSize.height) {
final shiftAmount = rect.bottom - viewSize.height;
rect = Rect.fromLTRB(
rect.left,
rect.top - shiftAmount,
rect.right,
rect.bottom - shiftAmount,
);
}
}
final radius = Radius.circular(tooltipData.tooltipRoundedRadius);
final roundedRect = RRect.fromRectAndCorners(
rect,
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
);
_bgTouchTooltipPaint.color = tooltipData.tooltipBgColor;
final rotateAngle = tooltipData.rotateAngle;
final rectRotationOffset =
Offset(0, Utils().calculateRotationOffset(rect.size, rotateAngle).dy);
final rectDrawOffset = Offset(roundedRect.left, roundedRect.top);
final textRotationOffset =
Utils().calculateRotationOffset(rect.size, rotateAngle);
if (tooltipData.tooltipBorder != BorderSide.none) {
_borderTouchTooltipPaint
..color = tooltipData.tooltipBorder.color
..strokeWidth = tooltipData.tooltipBorder.width;
}
canvasWrapper.drawRotated(
size: rect.size,
rotationOffset: rectRotationOffset,
drawOffset: rectDrawOffset,
angle: rotateAngle,
drawCallback: () {
canvasWrapper
..drawRRect(roundedRect, _bgTouchTooltipPaint)
..drawRRect(roundedRect, _borderTouchTooltipPaint);
},
);
/// draw the texts one by one in below of each other
var topPosSeek = tooltipData.tooltipPadding.top;
for (final tp in drawingTextPainters) {
final yOffset = rect.topCenter.dy +
topPosSeek -
textRotationOffset.dy +
rectRotationOffset.dy;
double xOffset;
switch (tp.textAlign.getFinalHorizontalAlignment(tp.textDirection)) {
case HorizontalAlignment.left:
xOffset = rect.left + tooltipData.tooltipPadding.left;
break;
case HorizontalAlignment.right:
xOffset = rect.right - tooltipData.tooltipPadding.right - tp.width;
break;
default:
xOffset = rect.center.dx - (tp.width / 2);
break;
}
final drawOffset = Offset(
xOffset,
yOffset,
);
canvasWrapper.drawRotated(
size: rect.size,
rotationOffset: rectRotationOffset,
drawOffset: rectDrawOffset,
angle: rotateAngle,
drawCallback: () {
canvasWrapper.drawText(tp, drawOffset);
},
);
topPosSeek += tp.height;
topPosSeek += textsBelowMargin;
}
}