drawAxisLabels method
void
drawAxisLabels(})
Draw axis labels (optimized with text style caching).
Renders numeric labels along the X and Y axes to help users read values. Uses efficient text rendering with cached styles and smart formatting.
Parameters:
canvas- The canvas to draw onsize- The size of the chart areaminX,maxX,minY,maxY- The data bounds for label values
Labels are automatically formatted (integers when possible, decimals otherwise). The number of labels is automatically adjusted based on the chart size.
The labels will only be drawn if showLabel and showAxis are true.
If dataSets are provided, labels from ChartDataPoint.label will be
used for X-axis labels when available, falling back to numeric values.
Example
drawAxisLabels(canvas, chartSize, 0, 100, 0, 50);
// Or with data points for custom labels:
drawAxisLabels(canvas, chartSize, 0, 100, 0, 50, dataSets: dataSets);
Implementation
void drawAxisLabels(
Canvas canvas,
Size size,
double minX,
double maxX,
double minY,
double maxY, {
List<ChartDataSet>? dataSets,
}) {
if (!showLabel || !showAxis || !theme.showAxis) return;
// Validate size and ranges
if (size.width <= 0 || size.height <= 0) return;
if (!size.width.isFinite || !size.height.isFinite) return;
final xRange = maxX - minX;
final yRange = maxY - minY;
// Validate ranges are valid and non-zero
if (!xRange.isFinite || !yRange.isFinite) return;
// Use theme text style if available
final textStyle = theme.axisLabelStyle ?? TextStyle(
color: theme.axisColor.withValues(alpha: 0.8),
fontSize: 11,
fontWeight: FontWeight.w500,
letterSpacing: 0.2,
);
// X-axis labels - use labels from data points if available
final xLabelsCount =
math.max(1, math.min(6, (xRange > 0 ? xRange : 1).ceil().toInt()));
if (xLabelsCount > 0 && xRange > 0) {
// Try to use labels from data points
if (dataSets != null &&
dataSets.isNotEmpty &&
dataSets.any((ds) => ds.dataPoint.label != null)) {
// Use labels from data points - show labels at actual data point positions
// Use a map to deduplicate labels by x position (only show one label per x value)
final Map<double, String> xLabels = {};
for (final dataSet in dataSets) {
final point = dataSet.dataPoint;
// Skip if no label or invalid x value
if (point.label == null || !point.x.isFinite) continue;
// Store label for this x position (first label wins if duplicates exist)
if (!xLabels.containsKey(point.x)) {
xLabels[point.x] = point.label!;
}
}
// Draw labels for unique x positions
for (final entry in xLabels.entries) {
final xValue = entry.key;
final label = entry.value;
// Calculate x position based on point.x
final normalizedX = xRange > 0 ? (xValue - minX) / xRange : 0.5;
final x = normalizedX * size.width;
// Only draw if within chart bounds
if (!x.isFinite || x < 0 || x > size.width) continue;
final textPainter = TextPainter(
text: TextSpan(text: label, style: textStyle),
textDirection: TextDirection.ltr,
);
textPainter.layout();
_paintRotatedLabel(
canvas,
textPainter,
Offset(x, size.height + 12), // Increased padding
theme.xAxisLabelRotation,
);
}
} else {
// Fall back to numeric labels
final xStep = size.width / xLabelsCount;
for (int i = 0; i <= xLabelsCount; i++) {
final x = xStep * i;
if (!x.isFinite) continue;
final value = minX + xRange * (i / xLabelsCount);
if (!value.isFinite) continue;
final displayValue = value % 1 == 0
? value.toInt().toString()
: value.toStringAsFixed(1);
final textPainter = TextPainter(
text: TextSpan(text: displayValue, style: textStyle),
textDirection: TextDirection.ltr,
);
textPainter.layout();
// For numeric labels, use theme rotation (no per-point rotation available)
_paintRotatedLabel(
canvas,
textPainter,
Offset(x, size.height + 12), // Increased padding
theme.xAxisLabelRotation,
);
}
}
}
// Y-axis labels - better formatting with pre-calculated values
const yLabels = 5;
if (yLabels > 0 && yRange > 0) {
final yStep = size.height / yLabels;
for (int i = 0; i <= yLabels; i++) {
final y = size.height - yStep * i;
if (!y.isFinite) continue;
final value = minY + yRange * (i / yLabels);
if (!value.isFinite) continue;
final displayValue = value % 1 == 0
? value.toInt().toString()
: value.toStringAsFixed(1);
final textPainter = TextPainter(
text: TextSpan(text: displayValue, style: textStyle),
textDirection: TextDirection.ltr,
);
textPainter.layout();
// Position label to the left of the Y-axis, centered vertically
// Ensure we don't go too far left (assuming standard padding)
final labelX = -textPainter.width - 12; // Increased padding
_paintRotatedLabel(
canvas,
textPainter,
Offset(labelX, y),
theme.yAxisLabelRotation,
);
}
}
}