React wrapper for Smoothie Charts.
bun add react-smoothie
# or
npm install react-smoothiereact (16.8 or newer) is a peer dependency, so install it alongside if your app doesn't already have it.
smoothie comes along as a regular dependency.
npm i cinderblock/react-smoothieThere are 2 main ways to populate data.
- Original
refbasedaddTimeSeries() - New (added in
0.4.0) props based with reference to TimeSeries
Both import or require work
const { default: SmoothieComponent, TimeSeries } = require('react-smoothie');
import SmoothieComponent, { TimeSeries } from 'react-smoothie';As of 1.0.0 the package ships native ESM alongside CommonJS; bundlers and Node pick the right build automatically.
const ts1 = new TimeSeries({});
const ts2 = new TimeSeries({
resetBounds: true,
resetBoundsInterval: 3000,
});
setInterval(() => {
const time = Date.now();
ts1.append(time, Math.random());
ts2.append(time, Math.random());
}, 500);
function TestComponent() {
return (
<SmoothieComponent
responsive
height={300}
series={[
{
data: ts1,
strokeStyle: { g: 255 },
fillStyle: { g: 255 },
lineWidth: 4,
},
{
data: ts2,
strokeStyle: { r: 255 },
fillStyle: { r: 255 },
lineWidth: 4,
},
]}
/>
);
}class TestComponent extends React.Component {
chart = React.createRef<SmoothieComponent>();
dataGenerator?: ReturnType<typeof setInterval>;
render() {
return <SmoothieComponent ref={this.chart} responsive height={300} />;
}
componentDidMount() {
// Initialize TimeSeries yourself
const ts1 = new TimeSeries({});
this.chart.current!.addTimeSeries(ts1, {
strokeStyle: 'rgba(0, 255, 0, 1)',
fillStyle: 'rgba(0, 255, 0, 0.2)',
lineWidth: 4,
});
// Or let addTimeSeries create a new instance of TimeSeries for us
const ts2 = this.chart.current!.addTimeSeries(
{
resetBounds: true,
resetBoundsInterval: 3000,
},
{
strokeStyle: { r: 255 },
fillStyle: { r: 255 },
lineWidth: 4,
}
);
this.dataGenerator = setInterval(() => {
const time = Date.now();
ts1.append(time, Math.random());
ts2.append(time, Math.random());
}, 500);
}
componentWillUnmount() {
clearInterval(this.dataGenerator);
}
}See examples/SmoothieDemo.tsx for a relatively standalone and complete example.
SmoothieComponent's props are all passed as the options object to the Smoothie Charts constructor.
<SmoothieComponent width={1000} height={300} interpolation="step" />Chart options are read once, when the component mounts.
Changing them afterwards has no effect yet (see #14); give the component a new key to rebuild the chart with new options.
The series, streamDelay and paused props do update live.
There are some extra props that control other behaviors.
Generate a tooltip on mouseover
falsedoes not enable tooltiptrueenables a default tooltip (generated byreact-smoothie)functionthat returns a stateless React component
default: false
Enabling responsive mode automatically sets the width to 100%.
default: false
Control the width of the <canvas> used.
default: 800
Control the height of the <canvas> used.
default: 200
default: 0 (ms)
Delay the displayed chart. This value is passed after the component mounts as the second argument to SmoothieChart.streamTo.
default: false
Freeze this chart (skip its frames) while true.
The chart stays mounted and registered and resumes cleanly when unpaused.
To pause a whole group of charts at once, use <SmoothieProvider paused> instead.
Experimental support for responsive charts was added in 0.3.0.
Simply set the responsive prop to true and canvas will use the full width of the parent container.
Height is still a controlled prop.
TimeSeries is the main class that Smoothie Charts uses internally for each series of data.
There are two ways to access and use these objects, corresponding to the two API versions.
TimeSeries is available as an import.
const ts1 = new TimeSeries();
ts1.append(time, Math.random());TimeSeries is exposed via the addTimeSeries() function.
The optional first argument of addTimeSeries() gets passed as the options to the TimeSeries constructor.
The last argument of addTimeSeries() gets passed as the options argument of SmoothieChart.addTimeSeries().
As of 0.4.0, an instance of TimeSeries can be passed as an argument to addTimeSeries().
const ts = this.chart.current!.addTimeSeries(
// Optional TimeSeries options
{ resetBounds: true },
// SmoothieChart.addTimeSeries options
{ strokeStyle: { g: 255 }, lineWidth: 2 }
);
ts.append(Date.now(), Math.random());Smoothie Charts runs one requestAnimationFrame loop per chart, so ten charts means ten
independent loops redrawing at the display refresh rate.
Since 0.14.0, react-smoothie instead drives all charts from a single shared animation
loop by default — no configuration or provider needed, and no visual difference.
With many charts on one page this is a significant reduction in scheduling and rendering
overhead.
Rendering also stops entirely while the browser tab is hidden and resumes (without a visual jump) when it becomes visible again.
Wrap a subtree in <SmoothieProvider> to control its rendering as a group.
Charts inside it share their own loop, separate from the default global one.
The nearest provider wins.
import SmoothieComponent, { SmoothieProvider } from 'react-smoothie';
<SmoothieProvider fps={30} paused={paused}>
<SmoothieComponent series={...} />
<SmoothieComponent series={...} />
</SmoothieProvider>;default: 0 (uncapped)
Maximum frame rate for the subtree's charts, in frames per second.
0 renders at the display refresh rate.
Charts' own limitFPS options still apply on top of this.
default: false
Freeze all charts in the subtree while true. Unpausing resumes cleanly.
default: true
Set to false to opt the subtree out of synchronized rendering and restore the old
behavior where every chart runs its own Smoothie-driven animation loop.
Charts outside any provider register with a global coordinator, exported as
globalCoordinator, which can be used to cap or pause everything without touching JSX:
import { globalCoordinator } from 'react-smoothie';
globalCoordinator.setFps(30);
globalCoordinator.setPaused(true);This repo uses Bun.
bun install
bun run dev # demo at http://localhost:3456 (examples/index.html, live reload)
bun test # bun:test + happy-dom + Testing Library
bun run typecheck
bun run build # dist/cjs + dist/esmReleases publish from CI: push a v* tag matching package.json's version.
- Development toolchain moves to Bun (
bun.lock,bun test, Bun's dev server for the demo), dropping webpack, vitest and jsdom. No change to the published package beyond the demo moving fromexample.tsxtoexamples/SmoothieDemo.tsx - CI runs on Ubuntu and Windows, against React 18 and 19, and smoke-tests the packed tarball under Node
- Dual CommonJS + ESM builds in
dist/with anexportsmap and TypeScript types for both - Publish via npm Trusted Publishing (OIDC) with provenance — no npm tokens
- GitHub Releases created automatically on each version tag
sideEffects: falsefor better tree-shaking- Remove GitHub Packages publishing (its npm registry requires scoped package names)
- Synchronized rendering, on by default: all charts share a single
requestAnimationFrameloop instead of one loop per chart. Visually identical; opt out with<SmoothieProvider coordinate={false}> - New
<SmoothieProvider>component: per-subtreefpscap,paused, andcoordinateopt-out - New per-chart
pausedprop - Rendering stops while the browser tab is hidden and resumes cleanly
reactis now a peer dependency (>=16.8) instead of a direct dependency, fixing possible duplicate-React installs in consumers- Improve Types for Canvas drawing (setting gradients)
- Rewrite of options processing
- New modern React (with hooks) example
- Switch to Npm
- Update all dependencies (React 19, TypeScript 5.9, webpack-dev-server 5)
- Add test suite (vitest + Testing Library)
- Fix crash in
componentDidUpdatewhen theseriesprop is not used - Fix
CanvasGradientreference error in environments without canvas (SSR)
- Remove Yarn restrictions
- Update dep to latest
- Publish to GitHub Packages
- Use
preparescript to allow installing from GitHub
- Export prop type
- TypeScript
- Fix tooltip positioning relative
- Allow setting class via
classNameCanvas
- Allow setting canvas css class
- Tooltip support
- Single option to set both style colors to be the same
TimeSeriescan be passed as an argument toaddTimeSeries()- Use object to set style colors
- Export as Module
- Allow setting
streamDelayoption
- Fix passing args to Smoothie Charts