paint method
void
paint(
- Canvas cv,
- Size size,
- double p,
- Offset center,
- Color baseColor, {
- double radiusMultiplier = 1,
- Offset positionOffset = Offset.zero,
override
Implementation
@override
void paint(Canvas cv, Size size, double p, Offset center, Color baseColor,
{double radiusMultiplier = 1, Offset positionOffset = Offset.zero}) {
final c = center + positionOffset;
final outerR = (math.max(size.width, size.height) / 2 + orbitMargin) *
radiusMultiplier;
// radius setiap ring (dalam → luar)
final List<double> ringR = List.generate(
ringCount,
(i) => outerR - (ringCount - 1 - i) * ringGap * radiusMultiplier,
);
// durasi spawn per dot (agar dot‑N selesai tepat di _spawnEnd)
final spawnSlice = _spawnEnd / particlesPerRing;
for (int ringIdx = 0; ringIdx < ringCount; ringIdx++) {
final rBase = ringR[ringIdx];
for (int j = 0; j < particlesPerRing; j++) {
final angle0 =
(j + (ringIdx.isOdd ? .5 : 0)) * 2 * math.pi / particlesPerRing;
// ─── progress lokal (0‑1) per dot ───
final double delay = j * spawnSlice;
double t;
if (p < delay) continue; // belum lahir
if (p < _spawnEnd) {
t = (p - delay) / spawnSlice; // 0‑1 dalam fase spawn
if (t > 1) t = 1;
} else {
// semua dot sudah muncul
t = 1 + (p - _spawnEnd) / (1 - _spawnEnd); // 1‑2 rentang orbit‑return
}
// ─── radius & sudut ───
double r, theta;
if (t <= 1) {
// fase Spawn (per‑dot)
r = _easeOutBack(t) * rBase;
theta = angle0; // belum berputar
} else if (p < _orbitEnd) {
// fase Orbit
final tt = (p - _spawnEnd) / (_orbitEnd - _spawnEnd);
r = rBase;
theta = angle0 + 2 * math.pi * rotations * tt;
} else {
// fase Return
final tt = (p - _orbitEnd) / (1 - _orbitEnd);
r = rBase * (1 - _easeIn(tt));
theta = angle0 + 2 * math.pi * rotations;
}
final pos = c + Offset(math.cos(theta), math.sin(theta)) * r;
// ─── opacity & skala ───
final globalFade = p < .92 ? 1.0 : 1 - (p - .92) / .08;
final scale = globalFade;
// ─── warna (HSV) ───
Color col = baseColor;
if (enableHueTilt) {
final hsl = HSLColor.fromColor(baseColor);
final shift = (angle0 / (2 * math.pi)) * 360 * hueTiltRange;
col = hsl
.withHue((hsl.hue + shift) % 360)
.withSaturation((hsl.saturation * saturationBoost).clamp(0, 1))
.toColor();
}
col = col.withOpacity(globalFade);
final drawR = circleRadius * radiusMultiplier * scale;
// glow
cv.drawCircle(
pos,
drawR * 1.6,
Paint()
..color = col.withOpacity(.25)
..maskFilter = MaskFilter.blur(BlurStyle.normal, glowSigma));
// dot utama
cv.drawCircle(pos, drawR, Paint()..color = col);
}
}
}