|
...
|
...
|
@@ -53,27 +53,6 @@ class ProgressPainter extends CustomPainter { |
|
|
|
width: wh - strokeWidth,
|
|
|
|
height: wh - strokeWidth,
|
|
|
|
);
|
|
|
|
int colorRangeIndex = (sweepAngle / 360).ceil() - 1;
|
|
|
|
if (colorRangeIndex > progressColor.length - 1) {
|
|
|
|
colorRangeIndex = progressColor.length - 1;
|
|
|
|
}
|
|
|
|
if (colorRangeIndex < 0) {
|
|
|
|
colorRangeIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
var shader = SweepGradient(
|
|
|
|
startAngle: 0.toRadians(),
|
|
|
|
endAngle: 360.toRadians(),
|
|
|
|
colors: reverse
|
|
|
|
? progressColor[colorRangeIndex].reversed.toList()
|
|
|
|
: progressColor[colorRangeIndex],
|
|
|
|
).createShader(rect);
|
|
|
|
|
|
|
|
var paint = Paint()
|
|
|
|
..strokeWidth = strokeWidth
|
|
|
|
..shader = shader
|
|
|
|
..strokeCap = StrokeCap.butt
|
|
|
|
..style = PaintingStyle.stroke;
|
|
|
|
|
|
|
|
var backgroundPaint = Paint()
|
|
|
|
..strokeWidth = strokeWidth
|
|
...
|
...
|
@@ -89,49 +68,93 @@ class ProgressPainter extends CustomPainter { |
|
|
|
backgroundPaint,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (sweepAngle >= 0) {
|
|
|
|
if (sweepAngle > 0) {
|
|
|
|
double capAngle = 0;
|
|
|
|
if (radius > 0) {
|
|
|
|
capAngle = asin((strokeWidth / 2) / radius) * 180 / pi;
|
|
|
|
}
|
|
|
|
|
|
|
|
double actualCapAngle = capAngle;
|
|
|
|
if (sweepAngle < 360) {
|
|
|
|
if (sweepAngle < 2 * capAngle) {
|
|
|
|
actualCapAngle = sweepAngle / 2;
|
|
|
|
int fullLaps = (sweepAngle / 360).floor();
|
|
|
|
double remainingAngle = sweepAngle % 360;
|
|
|
|
|
|
|
|
// Draw full laps first
|
|
|
|
for (int i = 0; i < fullLaps; i++) {
|
|
|
|
int colorIdx = i;
|
|
|
|
if (colorIdx > progressColor.length - 1) {
|
|
|
|
colorIdx = progressColor.length - 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
actualCapAngle = 0;
|
|
|
|
var shader = SweepGradient(
|
|
|
|
startAngle: 0.toRadians(),
|
|
|
|
endAngle: 360.toRadians(),
|
|
|
|
colors: reverse
|
|
|
|
? progressColor[colorIdx].reversed.toList()
|
|
|
|
: progressColor[colorIdx],
|
|
|
|
).createShader(rect);
|
|
|
|
|
|
|
|
var lapPaint = Paint()
|
|
|
|
..strokeWidth = strokeWidth
|
|
|
|
..shader = shader
|
|
|
|
..strokeCap = StrokeCap.butt
|
|
|
|
..style = PaintingStyle.stroke;
|
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(centerX, centerY);
|
|
|
|
canvas.rotate((-90).toRadians());
|
|
|
|
canvas.translate(-centerX, -centerY);
|
|
|
|
|
|
|
|
canvas.drawArc(
|
|
|
|
rect,
|
|
|
|
0.toRadians(),
|
|
|
|
reverse ? -360.toRadians() : 360.toRadians(),
|
|
|
|
false,
|
|
|
|
lapPaint,
|
|
|
|
);
|
|
|
|
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
double startAngle = actualCapAngle;
|
|
|
|
double drawnSweepAngle = sweepAngle;
|
|
|
|
if (sweepAngle < 360) {
|
|
|
|
drawnSweepAngle = sweepAngle - 2 * actualCapAngle;
|
|
|
|
// Draw the remaining fractional lap
|
|
|
|
if (remainingAngle > 0.0) {
|
|
|
|
int colorIdx = fullLaps;
|
|
|
|
if (colorIdx > progressColor.length - 1) {
|
|
|
|
colorIdx = progressColor.length - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
var shader = SweepGradient(
|
|
|
|
startAngle: 0.toRadians(),
|
|
|
|
endAngle: 360.toRadians(),
|
|
|
|
colors: reverse
|
|
|
|
? progressColor[colorIdx].reversed.toList()
|
|
|
|
: progressColor[colorIdx],
|
|
|
|
).createShader(rect);
|
|
|
|
|
|
|
|
var lapPaint = Paint()
|
|
|
|
..strokeWidth = strokeWidth
|
|
|
|
..shader = shader
|
|
|
|
..strokeCap = StrokeCap.butt
|
|
|
|
..style = PaintingStyle.stroke;
|
|
|
|
|
|
|
|
double actualCapAngle = capAngle;
|
|
|
|
if (remainingAngle < 2 * capAngle) {
|
|
|
|
actualCapAngle = remainingAngle / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
double startAngle = actualCapAngle;
|
|
|
|
double drawnSweepAngle = remainingAngle - 2 * actualCapAngle;
|
|
|
|
if (drawnSweepAngle < 0) {
|
|
|
|
drawnSweepAngle = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas.save();
|
|
|
|
// Move the canvas origin to the center
|
|
|
|
canvas.translate(centerX, centerY);
|
|
|
|
double rotationAngle = 0;
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(centerX, centerY);
|
|
|
|
canvas.rotate((-90).toRadians());
|
|
|
|
canvas.translate(-centerX, -centerY);
|
|
|
|
|
|
|
|
if (sweepAngle > 360) {
|
|
|
|
rotationAngle = 360 - sweepAngle;
|
|
|
|
}
|
|
|
|
double rotationRadians =
|
|
|
|
reverse ? -rotationAngle.toRadians() : rotationAngle.toRadians();
|
|
|
|
// Rotate the canvas
|
|
|
|
canvas.rotate((-90).toRadians() - rotationRadians);
|
|
|
|
// Move the canvas origin back
|
|
|
|
canvas.translate(-centerX, -centerY);
|
|
|
|
|
|
|
|
if (sweepAngle < 360) {
|
|
|
|
// Draw start cap for this fractional lap
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(centerX, centerY);
|
|
|
|
canvas.rotate(reverse ? -startAngle.toRadians() : startAngle.toRadians());
|
|
|
|
canvas
|
|
|
|
.rotate(reverse ? -startAngle.toRadians() : startAngle.toRadians());
|
|
|
|
canvas.drawArc(
|
|
|
|
Rect.fromCenter(
|
|
|
|
center: Offset(radius, 0),
|
|
...
|
...
|
@@ -141,7 +164,10 @@ class ProgressPainter extends CustomPainter { |
|
|
|
0,
|
|
|
|
reverse ? 180.toRadians() : -180.toRadians(),
|
|
|
|
true,
|
|
|
|
Paint()..color = progressColor[0].first,
|
|
|
|
Paint()
|
|
|
|
..color = reverse
|
|
|
|
? progressColor[colorIdx].last
|
|
|
|
: progressColor[colorIdx].first,
|
|
|
|
);
|
|
|
|
canvas.drawRect(
|
|
|
|
Rect.fromCenter(
|
|
...
|
...
|
@@ -149,31 +175,37 @@ class ProgressPainter extends CustomPainter { |
|
|
|
width: strokeWidth,
|
|
|
|
height: 1,
|
|
|
|
),
|
|
|
|
Paint()..color = progressColor[0].first,
|
|
|
|
Paint()
|
|
|
|
..color = reverse
|
|
|
|
? progressColor[colorIdx].last
|
|
|
|
: progressColor[colorIdx].first,
|
|
|
|
);
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas.drawArc(
|
|
|
|
rect,
|
|
|
|
reverse ? -startAngle.toRadians() : startAngle.toRadians(),
|
|
|
|
reverse
|
|
|
|
? -drawnSweepAngle.toRadians()
|
|
|
|
: drawnSweepAngle.toRadians(),
|
|
|
|
false,
|
|
|
|
paint,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (sweepAngle != 360) {
|
|
|
|
// Draw the fractional arc
|
|
|
|
canvas.drawArc(
|
|
|
|
rect,
|
|
|
|
reverse ? -startAngle.toRadians() : startAngle.toRadians(),
|
|
|
|
reverse ? -drawnSweepAngle.toRadians() : drawnSweepAngle.toRadians(),
|
|
|
|
false,
|
|
|
|
lapPaint,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Draw end cap for this fractional lap
|
|
|
|
final endAngle = startAngle + drawnSweepAngle;
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(centerX, centerY);
|
|
|
|
canvas.rotate(reverse ? -endAngle.toRadians() : endAngle.toRadians());
|
|
|
|
|
|
|
|
final endColor =
|
|
|
|
getColorAtAngle(sweepAngle, progressColor[colorRangeIndex]);
|
|
|
|
|
|
|
|
final bool shouldDrawShadow = sweepAngle > 360 || (sweepAngle > 355 && sweepAngle < 360);
|
|
|
|
final endColor = getColorAtAngleOf360(
|
|
|
|
remainingAngle,
|
|
|
|
reverse
|
|
|
|
? progressColor[colorIdx].reversed.toList()
|
|
|
|
: progressColor[colorIdx],
|
|
|
|
);
|
|
|
|
|
|
|
|
final bool shouldDrawShadow =
|
|
|
|
sweepAngle > 360 || (remainingAngle > 355 && remainingAngle < 360);
|
|
|
|
if (shouldDrawShadow) {
|
|
|
|
//Draw arc shadow
|
|
|
|
var shadowPosition = Offset(
|
|
...
|
...
|
@@ -208,10 +240,9 @@ class ProgressPainter extends CustomPainter { |
|
|
|
Paint()..color = endColor,
|
|
|
|
);
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
// // Restore the canvas to the saved state
|
|
|
|
canvas.restore();
|
|
|
|
canvas.restore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
...
|
...
|
@@ -220,16 +251,19 @@ class ProgressPainter extends CustomPainter { |
|
|
|
return sweepAngle != oldDelegate.sweepAngle;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// get color by and angle
|
|
|
|
Color getColorAtAngle(double angle, List<Color> colors) {
|
|
|
|
double totalAngle = sweepAngle > 360 ? sweepAngle : 360;
|
|
|
|
double fraction = angle / totalAngle;
|
|
|
|
/// get color by angle of a single 360 degree span
|
|
|
|
Color getColorAtAngleOf360(double angle, List<Color> colors) {
|
|
|
|
double fraction = angle / 360.0;
|
|
|
|
if (fraction > 1.0) fraction = 1.0;
|
|
|
|
if (fraction < 0.0) fraction = 0.0;
|
|
|
|
int segments = colors.length - 1;
|
|
|
|
if (segments <= 0) return colors.first;
|
|
|
|
double segmentFraction = fraction * segments;
|
|
|
|
int segmentIndex = segmentFraction.floor();
|
|
|
|
if (segmentIndex >= segments) segmentIndex = segments - 1;
|
|
|
|
double segmentInnerFraction = segmentFraction - segmentIndex;
|
|
|
|
Color startColor = colors[segmentIndex];
|
|
|
|
Color endColor = colors[(segmentIndex + 1) % colors.length];
|
|
|
|
Color endColor = colors[segmentIndex + 1];
|
|
|
|
return Color.lerp(startColor, endColor, segmentInnerFraction)!;
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|