webdevpuneet.com

Chartist.js Animated Bar Race — Growing Bars & update() Snippet

Chartist.js Animated Bar Race · Charts · Plain HTML, CSS & JS · Live preview

CategoryCharts

Copy & paste

Source Code

<div class="cbr-stage">
  <div class="cbr-head">
    <span class="cbr-tag">Chartist.js · draw event · bar</span>
    <h2>Top Products by Revenue</h2>
    <p>Bars grow in from zero on load, and chart.update() replays the same animation with a fresh shuffle.</p>
  </div>
  <div class="cbr-chart" id="cbrChart"></div>
  <button class="cbr-btn" id="cbrShuffle">Shuffle data</button>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Bars grow in from zero on load
x2 animates from the axis baseline (x1) out to its real value.
Baseline read from data, not hardcoded
Using data.x1 keeps the animation correct regardless of axis offset or padding.
Built-in update-transition
chart.update() re-fires draw automatically, replaying the same growth animation with no extra code.
Bars animate between old and new length
A shuffle grows or shrinks each bar relative to its previous value, not from zero every time.
Horizontal bar-race layout
Labels on the left, bars extending right — the standard "race" visual convention.
Randomized shuffle button
Demonstrates the animation repeatedly with fresh data on demand.
Eased growth curve
Chartist.Svg.Easing.easeOutQuint gives bars a natural deceleration as they land.
Fixed value axis range
high/low keep the scale stable across shuffles so bar lengths stay comparable.

About this UI Snippet

Chartist.js Animated Bar Race — Growing Bars and the update() Transition

Screenshot of the Chartist.js Animated Bar Race snippet rendered live

The line and donut snippets in this library animate a static chart once, on load. This one adds a second dimension: what happens when the *data itself* changes after the chart already exists, via chart.update() — and it turns out Chartist has that transition built in almost for free, as long as your draw handler is written the right way.

What a horizontal bar actually is, geometrically

For a Chartist.BarChart with horizontalBars: true, each bar's draw event carries data.x1 and data.x2 — the bar's start and end coordinates along the horizontal value axis (plus y1/y2, which stay constant for a given row since the bar's vertical position doesn't change). x1 is always the axis baseline; x2 is where the bar's value places its far end. A bar's on-screen length is nothing more than x2 - x1.

Growing from zero: animate x2 from x1

js data.element.animate({ x2: { dur: 800, from: data.x1, to: data.x2, easing: ... } });

Setting the animation's from value to data.x1 — the bar's own baseline, not a hardcoded zero — makes the bar start with zero visible length (its start and end coincide) and grow out to its real length. Using data.x1 rather than a literal 0 matters because the baseline position depends on axisY's offset and the chart's padding; hardcoding 0 would grow every bar from the literal left edge of the SVG instead of from the actual axis line, which is wrong the moment the axis has any offset at all.

Why chart.update() replays the animation without extra code

This is the part that looks like magic until you see the mechanism: Chartist doesn't destroy and recreate the SVG on update(). It reuses the existing DOM elements where the shape hasn't structurally changed, and re-runs its internal draw pass, updating each bar's x2 coordinate and — critically — firing the draw event again for every element, exactly as it did on the first render. Because this snippet's chart.on('draw', ...) handler is attached once, outside of any specific render, it doesn't need to be re-attached or re-triggered manually after update() — Chartist calls it again on its own.

The one behavioral difference: on the very first render, data.x1 === the baseline and every bar visibly grows from zero. On a subsequent update(), the bar element already has a real x2 from before the shuffle — but the draw handler still reads whatever data.x1/data.x2 the *new* draw pass computes, and animates between them the same way. In practice this means each shuffle animates every bar from its previous length directly to its new length, which is the actual "race" feeling: bars don't reset to zero and regrow each time, they visibly grow or shrink relative to where they just were.

Why horizontalBars: true suits a "race" layout

Vertical bars racing would need height changes read off y1/y2 instead, but the visual metaphor of a "bar race" — labels on the left, bars extending rightward by value — is a horizontal-bar convention. axisY: { offset: 90 } reserves enough left-hand space for the product name labels to render without truncation.

Step by step

How to Use

  1. 1
    Add both Chartist CDN filesThe JS bundle and index.css.
  2. 2
    Create a horizontal BarChartnew Chartist.BarChart(selector, data, { horizontalBars: true, ... }).
  3. 3
    Animate x2 from x1 on drawdata.type === "bar" gives x1 (baseline) and x2 (real end) to animate between.
  4. 4
    Use data.x1, not a literal 0, as the start valueThe baseline position depends on axis offset and padding, so it must be read, not assumed.
  5. 5
    Call chart.update() with new dataNo extra animation code is needed — the same draw handler fires again automatically.
  6. 6
    Wire a shuffle buttonGenerates fresh random values and calls update(), demonstrating the built-in transition.

Real-world uses

Common Use Cases

Leaderboards and rankings
A product, team, or player ranking chart that visibly reacts to new data.
Live dashboards
Poll an API and call chart.update() on an interval to get automatic re-animation for free.
Teaching Chartist's update lifecycle
A clear demonstration that update() reuses draw handlers rather than requiring new ones.
Sales and revenue snapshots
A top-N chart that feels alive each time the underlying numbers refresh.

Got questions?

Frequently Asked Questions

data.x1 is the bar's actual axis baseline in the chart's current coordinate space, which shifts depending on axisY offset and chart padding. Hardcoding 0 would grow bars from the literal edge of the SVG rather than from the real axis line, which looks wrong as soon as there's any axis offset.

No. The draw event handler attached once with chart.on("draw", ...) fires again automatically every time update() re-runs Chartist's internal render pass, so the exact same x1-to-x2 growth animation replays without any extra setup.

Chartist reuses existing DOM elements on update() rather than destroying and recreating them. The draw handler reads whatever x1/x2 the new render pass computes and animates between those, so a bar that already has a rendered length animates from that length to its new one, not from zero.

For a horizontal bar chart, x1/x2 represent the bar's start and end along the value axis (what changes with the data), while y1/y2 represent its position along the category axis (which stays fixed for a given row). A vertical bar chart would swap which pair encodes the growing length.

The bar-race visual convention is labels on the left with bars extending rightward by value, which is what horizontalBars: true produces. It also makes long product names easier to read than rotated axis labels under vertical bars would.

Auto-scaling recalculates the axis range based on the current data's max value, which would make the same underlying value draw a different bar length on every shuffle. A fixed high/low keeps the scale stable so bar lengths stay visually comparable across updates.

Design your website