Handling 100k+ Data Points in Chart.js with the Decimation Plugin
Learn how to use the Chart.js Decimation plugin to render massive time-series datasets without crashing the browser, using LTTB to preserve data peaks.
02 Oct 2026, 03:24 UTC

The Browser Bottleneck in Time-Series Data
When rendering time-series data, there is a physical limit to how much information a user can actually see. If your chart container is 1,000 pixels wide but you are feeding Chart.js 100,000 data points, the browser is attempting to draw 100 points per pixel. This leads to massive CPU overhead, sluggish zoom/pan interactions, and a browser tab that consumes excessive memory.
The goal isn't just to "make it faster," but to reduce the number of points drawn on the canvas without losing the visual "shape" of the data—specifically the peaks and valleys that usually indicate anomalies or critical events.
How the Decimation Plugin Works
The Decimation plugin acts as a pre-processor. It intercepts the data before it hits the rendering engine and reduces the point count. Crucially, it does not mutate your original data array; it creates a sampled version for the current view.
There are two primary sampling strategies available:
- LTTB (Largest Triangle Three Buckets): A sophisticated algorithm that divides data into buckets and selects a point that maximizes the area of a triangle formed with neighboring buckets. This is the gold standard for preserving the visual characteristics of a waveform.
- Min-Max: A simpler approach that preserves the extreme values in each bucket. It is faster than LTTB but can look more "blocky."
Implementation Requirements
Decimation is not a "plug-and-play" toggle; it requires a specific configuration to function. If these conditions aren't met, Chart.js will silently ignore the decimation settings.
- Chart Type: Must be a
linechart. - Axis Type: The x-axis must be
linearortime. It will not work with categorical scales. - Parsing Disabled: You must set
parsing: false. This tells Chart.js that the data is already in the internal format it expects, bypassing the expensive internal parsing loop. - Data Format: Because parsing is disabled, data must be provided as an array of objects:
{x: number, y: number}.
Worked Example: Configuring LTTB Decimation
In this configuration, we assume you are using Chart.js v3 or v4. This code should be implemented in your frontend JavaScript file where the chart is initialized.
const config = {
type: 'line',
data: {
datasets: [{
label: 'Sensor Data',
data: largeDataSet, // Array of {x: timestamp, y: value}
parsing: false, // REQUIRED for decimation
normalized: true // Optimizes performance further
}]
},
options: {
plugins: {
decimation: {
enabled: true,
algorithm: 'lttb', // Options: 'lttb' or 'min-max'
samples: 500 // Target number of points to render
}
},
scales: {
x: {
type: 'linear', // Must be 'linear' or 'time'
}
}
}
};
Verification Steps
To verify that decimation is actually working, you can use the browser's Performance tab in DevTools:
- Check Main Thread: With 50,000 points and
decimation: false, you will likely see long "Task" blocks during the initial render and zoom events. Withenabled: true, these blocks should shrink significantly. - Visual Check: Zoom into a specific spike in your data. If the spike disappears when you zoom out but reappears when you zoom in, the decimation is working correctly by adjusting the sample rate based on the view.
Trade-offs and Limitations
Decimation is a compromise between accuracy and performance. The primary risk is visual aliasing. If your samples value is set too low, a very narrow but critical spike (a "needle" in the data) might fall between the buckets selected by the algorithm and vanish from the chart entirely.
Additionally, because parsing: false is required, you lose the ability to use simple arrays (e.g., [10, 20, 30]) for your data. You must explicitly map your data to {x, y} objects before passing them to the chart, which may require an extra transformation step in your data pipeline.
Closing Action
If your time-series charts feel sluggish, start by disabling parsing and implementing the lttb algorithm. Set your samples count to roughly 2x the pixel width of your chart container for a balance of smoothness and detail.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.