Connection Animation Effects
Add visual effects to connections to show flow direction, data movement, or simply to enhance the visual appeal of your diagrams. Effects can be applied at the theme level (affecting all connections) or per-connection for fine-grained control.
TIP
Why Use Effects? Animation effects help users understand data flow direction, emphasize active connections, and create more engaging, professional-looking diagrams.
Connection Effects Showcase
Animated GIF showing all four effects simultaneously on different connections: FlowingDash (marching ants pattern), ParticleEffect (dots traveling along path), GradientFlow (smooth color wave), PulseEffect (breathing opacity/width). Each connection labeled.
Available Effects
Vyuh Node Flow provides four built-in animation effects:
FlowingDashEffect
Creates a flowing dash pattern along the connection, similar to the classic "marching ants" effect.
FlowingDashEffect(
speed: 2, // Complete cycles per animation period (int)
dashLength: 10, // Length of each dash in pixels (int)
gapLength: 5, // Length of gap between dashes in pixels (int)
)Best for: Showing active or selected connections, indicating data transfer
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: FlowingDashEffect(
speed: 2,
dashLength: 10,
gapLength: 5,
),
)// Faster animation for urgent/priority connections
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: FlowingDashEffect(
speed: 4, // 4x faster
dashLength: 8,
gapLength: 4,
),
)// Slower, calmer animation (speed must be at least 1)
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: FlowingDashEffect(
speed: 1,
dashLength: 15,
gapLength: 8,
),
)// Longer dashes for dramatic effect
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: FlowingDashEffect(
speed: 1,
dashLength: 20, // Longer dashes
gapLength: 10,
),
)ParticleEffect
Shows particles traveling along the connection path, perfect for visualizing data flow or direction.
ParticleEffect(
particleCount: 5, // Number of particles (int)
speed: 1, // Complete cycles per animation period (int)
connectionOpacity: 0.3, // Opacity of base connection (0.0-1.0)
particlePainter: CircleParticle(radius: 4.0), // Particle appearance
)Particle Effect Variations
Animation showing different particle types: (1) circles flowing along path, (2) arrows indicating direction, (3) custom characters/emojis. Each with different particle counts and speeds.
Best for: Data flow visualization, showing direction, active pipelines
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: ParticleEffect(
particleCount: 3,
speed: 1,
connectionOpacity: 0.3,
particlePainter: CircleParticle(radius: 4.0),
),
)// Arrow-shaped particles
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: ParticleEffect(
particleCount: 5,
speed: 2,
connectionOpacity: 0.2,
particlePainter: ArrowParticle(
length: 12.0,
width: 8.0,
),
),
)// Text/emoji particles
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: ParticleEffect(
particleCount: 4,
speed: 1,
connectionOpacity: 0.3,
particlePainter: CharacterParticle(
character: '->',
fontSize: 16.0,
),
),
)// Dense particle stream
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: ParticleEffect(
particleCount: 10, // Many particles
speed: 2, // Fast movement
connectionOpacity: 0.1, // Very faint base line
particlePainter: CircleParticle(radius: 3.0),
),
)Custom Particle Painters
Create your own particle appearance by implementing the ParticlePainter interface:
import 'dart:math';
import 'dart:ui';
class StarParticle implements ParticlePainter {
final double starSize;
final Color? color;
const StarParticle({this.starSize = 8.0, this.color});
@override
Size get size => Size(starSize * 2, starSize * 2);
@override
void paint(Canvas canvas, Offset position, Tangent tangent, Paint basePaint) {
final paint = Paint()
..color = color ?? basePaint.color
..style = PaintingStyle.fill;
canvas.save();
canvas.translate(position.dx, position.dy);
final path = Path();
// Draw a 5-pointed star
for (var i = 0; i < 5; i++) {
final angle = (i * 2 * pi / 5) - pi / 2;
final outerX = cos(angle) * starSize;
final outerY = sin(angle) * starSize;
if (i == 0) {
path.moveTo(outerX, outerY);
} else {
path.lineTo(outerX, outerY);
}
final innerAngle = angle + pi / 5;
final innerX = cos(innerAngle) * (starSize / 2);
final innerY = sin(innerAngle) * (starSize / 2);
path.lineTo(innerX, innerY);
}
path.close();
canvas.drawPath(path, paint);
canvas.restore();
}
}
// Usage
ParticleEffect(
particleCount: 3,
speed: 1,
particlePainter: StarParticle(starSize: 10, color: Colors.yellow),
)GradientFlowEffect
Creates a smoothly flowing gradient along the connection path.
GradientFlowEffect(
colors: [
Colors.blue.withOpacity(0.0),
Colors.blue,
Colors.blue.withOpacity(0.0),
],
speed: 1, // Complete cycles per animation period (int)
gradientLength: 0.25, // Length as fraction of path (< 1) or pixels (>= 1)
connectionOpacity: 1.0, // Opacity of base connection (0.0-1.0)
)Best for: Elegant, subtle animations; showing smooth data flow
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: GradientFlowEffect(
colors: [
Colors.blue.withOpacity(0.0),
Colors.blue,
Colors.lightBlue,
Colors.blue,
Colors.blue.withOpacity(0.0),
],
speed: 1,
gradientLength: 0.3,
),
)connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: GradientFlowEffect(
colors: [
Colors.red,
Colors.orange,
Colors.yellow,
Colors.green,
Colors.blue,
Colors.purple,
],
speed: 1,
gradientLength: 0.5,
),
)// Red alert flow
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: GradientFlowEffect(
colors: [
Colors.red.withOpacity(0.0),
Colors.red,
Colors.red.shade900,
Colors.red,
Colors.red.withOpacity(0.0),
],
speed: 2, // Fast
gradientLength: 0.2,
),
)// Very subtle gradient
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: GradientFlowEffect(
colors: [
Colors.grey.withOpacity(0.0),
Colors.grey.withOpacity(0.5),
Colors.grey.withOpacity(0.0),
],
speed: 1,
gradientLength: 0.15,
connectionOpacity: 0.5,
),
)PulseEffect
Creates a pulsing or breathing effect by animating the connection's opacity and optionally its width.
PulseEffect(
speed: 1, // Complete pulse cycles per animation period (int)
minOpacity: 0.4, // Minimum opacity during pulse
maxOpacity: 1.0, // Maximum opacity during pulse
widthVariation: 1.5, // Width multiplier at peak (>= 1.0)
)Pulse Effect
Animation showing connections pulsing/breathing with opacity and width variation: subtle pulse (minimal change), heartbeat (dramatic), width emphasis, and fast blink. Shows minOpacity to maxOpacity transitions.
Best for: Highlighting connections, showing heartbeat/health, drawing attention
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: PulseEffect(
speed: 1,
minOpacity: 0.7,
maxOpacity: 1.0,
widthVariation: 1.0, // No width change
),
)// Heartbeat-like pulse
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: PulseEffect(
speed: 2, // Faster pulse
minOpacity: 0.3,
maxOpacity: 1.0,
widthVariation: 1.8,
),
)// Emphasize width changes
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: PulseEffect(
speed: 1,
minOpacity: 0.8,
maxOpacity: 1.0,
widthVariation: 2.0, // 2x width at peak
),
)// Rapid blinking for alerts
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: PulseEffect(
speed: 4, // Very fast
minOpacity: 0.2,
maxOpacity: 1.0,
widthVariation: 1.0,
),
)Applying Effects
Theme-Level (All Connections)
Apply an effect to all connections via the theme:
final theme = NodeFlowTheme.light.copyWith(
connectionTheme: ConnectionTheme.light.copyWith(
style: ConnectionStyles.smoothstep,
color: Colors.grey,
strokeWidth: 2.0,
// Default animation effect for ALL connections
animationEffect: ParticleEffect(
particleCount: 3,
speed: 1,
connectionOpacity: 0.3,
),
),
// Control animation cycle duration
connectionAnimationDuration: const Duration(seconds: 2),
);INFO
Animation Duration: The connectionAnimationDuration is a property of NodeFlowTheme (not ConnectionTheme) and controls how long one complete animation cycle takes. Effects with speed: 1 will complete one cycle in this duration.
Per-Connection (Selective)
Override the theme's default effect on individual connections:
// Standard connection with theme default
controller.addConnection(Connection(
id: 'conn-normal',
sourceNodeId: 'node-1',
sourcePortId: 'out',
targetNodeId: 'node-2',
targetPortId: 'in',
// Uses theme's default effect (animationEffect not specified)
));
// Critical connection with custom pulse
final criticalConnection = Connection(
id: 'conn-critical',
sourceNodeId: 'node-2',
sourcePortId: 'out',
targetNodeId: 'node-3',
targetPortId: 'in',
);
// Set animation effect after creation
criticalConnection.animationEffect = PulseEffect(
speed: 2,
minOpacity: 0.5,
maxOpacity: 1.0,
widthVariation: 1.5,
);
controller.addConnection(criticalConnection);
// Connection with effect set in constructor
controller.addConnection(Connection(
id: 'conn-flowing',
sourceNodeId: 'node-3',
sourcePortId: 'out',
targetNodeId: 'node-4',
targetPortId: 'in',
animationEffect: FlowingDashEffect(speed: 2, dashLength: 8, gapLength: 4),
));Controlling Animation Speed
The animation duration is set at the NodeFlowTheme level and affects all effects:
final theme = NodeFlowTheme.light.copyWith(
connectionAnimationDuration: const Duration(seconds: 2),
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: ParticleEffect(
speed: 1, // 1 cycle per 2 seconds
),
),
);final theme = NodeFlowTheme.light.copyWith(
connectionAnimationDuration: const Duration(seconds: 4),
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: FlowingDashEffect(
speed: 1, // 1 cycle per 4 seconds = slow
),
),
);final theme = NodeFlowTheme.light.copyWith(
connectionAnimationDuration: const Duration(milliseconds: 1000),
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: GradientFlowEffect(
speed: 1, // 1 cycle per 1 second = fast
),
),
);// Duration set at 2 seconds
final theme = NodeFlowTheme.light.copyWith(
connectionAnimationDuration: const Duration(seconds: 2),
connectionTheme: ConnectionTheme.light.copyWith(
animationEffect: ParticleEffect(
speed: 2, // 2 cycles per 2 seconds = 1 cycle/second
),
),
);
// Override on specific connection
final fastConnection = Connection(
id: 'fast-conn',
sourceNodeId: 'node-1',
sourcePortId: 'out',
targetNodeId: 'node-2',
targetPortId: 'in',
);
fastConnection.animationEffect = ParticleEffect(
speed: 4, // 4 cycles per 2 seconds = 2 cycles/second
);INFO
Connection effects render at high frequency and can impact performance when overused. Use them selectively to highlight important connections rather than animating everything. Too many animated connections will degrade performance and slow down the user experience.
What's Next?
Explore related topics:
- Theming - Customize the overall appearance
- Connections - Learn more about connections
TIP
Experiment! Try mixing different effects to find what works best for your use case. The effects are designed to work together beautifully.