We've seen it countless times: a client brings a mockup with a chart where bars shoot up one after another and a line flows like a painter's brushstroke. At first glance, it's a simple animation. But when it comes to code, the off-the-shelf library doesn't support that stagger effect, and a custom Canvas implementation demands deep understanding of Core Animation or the Android Canvas API. We take on such tasks and implement animations of any complexity in 1–3 days — be it a bar chart, line chart, or pie chart. In this article, we'll walk through typical problems and how to solve them.
Before choosing a library or writing from scratch, it's important to understand what animations are needed: simple appearance or sequential stagger, touch-event handling and tooltips, working with large datasets (500+ points) without FPS drops. We use profiling (Instruments, Android Profiler) at every stage to guarantee 60fps.
How to Choose Between a Library and Custom Canvas?
The decision between a ready-made library and a custom implementation is key. Libraries like MPAndroidChart or Swift Charts give you 80% of what you need in 20% of the time, but animation customization is limited. For example, MPAndroidChart supports animateX() and animateY(), but customizing easing per bar or creating a stagger animation (bars appearing one by one) is impossible without a custom Renderer. Custom Canvas is justified when you need a non-standard chart type, stagger effect, animation of individual points, or interactive tooltips.
| Criterion | Library (MPAndroidChart, Swift Charts) | Custom Canvas |
|---|---|---|
| Implementation time | Hours | 1–3 days |
| Animation customization | Limited (easing, stagger) | Full (any curve, delays) |
| Performance with 500+ points | Medium (potential lag) | High (downsampling + LOD) |
| Gesture support | Built-in (shallow) | Customizable (any logic) |
Why Stagger Animation Matters for Data Perception
Stagger animation (sequential appearance of elements) draws attention to each bar or point, making the data more readable. Custom Canvas implementation gives you 3 times more control over animation compared to ready-made libraries, which is critical for complex dashboards. We implemented it in Flutter using AnimationController + Interval:
// Each bar animates with an 80ms delay
for (int i = 0; i < bars.length; i++) {
final start = (i * 0.08).clamp(0.0, 1.0);
final end = (start + 0.4).clamp(0.0, 1.0);
animations[i] = Tween(begin: 0.0, end: bars[i].value).animate(
CurvedAnimation(
parent: controller,
curve: Interval(start, end, curve: Curves.easeOutCubic),
),
);
}
On iOS, a similar effect is achieved via CAKeyframeAnimation with keyTimes — each CAShapeLayer (one bar) gets a shifted beginTime:
bars.enumerated().forEach { index, layer in
let anim = CABasicAnimation(keyPath: "bounds.size.height")
anim.beginTime = CACurrentMediaTime() + Double(index) * 0.08
anim.duration = 0.4
anim.timingFunction = CAMediaTimingFunction(name: .easeOut)
layer.add(anim, forKey: nil)
}
A line chart is animated via CAShapeLayer with strokeEnd: 0 → 1. To add marker points that appear as the "brush" passes by, synchronize the appearance of CALayer with the strokeEnd progress. We implement this through CAAnimationDelegate.animationDidStop for each segment or via a displayLink tracking presentation().strokeEnd.
Interactive Tooltip: How to Maintain FPS
A tooltip that follows the finger across the graph is a separate challenge. On iOS: UIGestureRecognizer → map coordinate to data value → UIView.animate for the tooltip. It's crucial to call setNeedsDisplay() only on the part of CALayer that draws the highlight line — redrawing the entire canvas kills FPS during fast finger movement. We guarantee 60fps even with intensive interaction thanks to incremental rendering.
What's Included in Our Work
- Source code of the animated component in Swift/Kotlin/Dart/TypeScript
- Documentation for customization (colors, fonts, animation parameters)
- Integration into your existing project and test environment setup
- Performance optimization (downsampling for sets >500 points, LOD)
- 60fps guarantee on mid-range devices
We have been developing mobile apps for over 5 years and have completed over 15 projects with animated graphics (fintech, analytics dashboards). Our tech stack includes: SwiftUI + Combine, Jetpack Compose + Coroutines, Flutter 3.x. Apple's animation recommendations: use CAMediaTiming for synchronization.
How to Implement Stagger Animation in 4 Steps
- Initialize an
AnimationController(orCADisplayLink). - Create an array of delays:
delay = index * intervalTime. - For each element, apply a
Tweenanimation withCurvedAnimationandInterval. - Start the master controller — elements will animate sequentially.
What is downsampling and why do you need it?
Downsampling (removing points) is applied when rendering large datasets (500+ points) to maintain 60fps. The [Ramer–Douglas–Peucker algorithm](https://ru.wikipedia.org/wiki/Алгоритм_Рамера_—_Дугласа_—_Пекера) removes points that lie within a given epsilon from a straight line, preserving the visual shape of the graph.| Platform | Animation Mechanism | Key Classes |
|---|---|---|
| iOS | Core Animation (CALayer) | CABasicAnimation, CAKeyframeAnimation |
| Android | Canvas + ValueAnimator | ValueAnimator, ObjectAnimator |
| Flutter | AnimationController + Tween | AnimationController, Tween, Interval |
| React Native | Animated API | Animated.Value, Animated.timing |
Contact us to discuss your graph — we'll evaluate your project for free. Order turnkey chart animation development.







