Particle Flow
A static ribbon carries volume through its width, but nothing about it says which way the flow moves. particleFlow animates particles drifting along each ribbon, so direction and relative volume are readable without reading labels.
Enabling it
const sankey = new ApexSankey(document.getElementById('chart'), {
particleFlow: true,
})
sankey.render(data)
That is the whole configuration. Particle density is proportional to each ribbon's value, so a heavy flow is visibly busier than a light one and the encoding stays consistent with the ribbon widths beside it.
When it earns its place
Particle flow is decorative. It adds no information that width and direction do not already carry, so it is worth it when the animation itself is doing a job:
- Direction is genuinely ambiguous. A diagram with cyclic links, or a chord where flows run both ways between the same pair, benefits from motion that disambiguates.
- The subject is throughput. Packet routing, traffic, pipelines: the animation matches what the diagram is about.
- The diagram is on display. A wall dashboard or a landing page gets attention from motion in a way a static image does not.
It is worth skipping when the diagram is a dense analytical view someone reads for minutes, or sits alongside other charts, where constant motion competes for attention.
Reduced motion
Particles are skipped entirely when the user's system requests reduced motion. No configuration is needed, and no fallback is drawn: the diagram renders as it would with particleFlow: false.
Because the feature is purely decorative, this is a complete substitution rather than a degraded one. Nothing that a reader needs is conveyed by particles alone, which is exactly why it can be dropped safely.
Combining with other motion
Particle flow is independent of the entrance animation and of update():
const sankey = new ApexSankey(el, {
particleFlow: true,
animation: { enabled: true, duration: 800 },
})
sankey.render(data)
// particles keep flowing across the transition
sankey.update({ nodes, edges: nextEdges, options: sankey.options })
Particles continue during and after a data update, and re-derive their density from the new values once the ribbons settle. See Data Updates and Morphing.
It also works on a chord diagram, where it is often more useful than on a layered Sankey because a ring has no left-to-right convention to lean on:
const sankey = new ApexSankey(el, {
type: 'chord',
particleFlow: true,
})
See Chord Diagrams.