Solving Browser Lag in Chart.js with Data Decimation
Stop browser lag in Chart.js when rendering thousands of points. Learn how to implement the Decimation plugin using LTTB and Min-Max algorithms to optimize GPU performance.
13 Dec 2025, 23:57 UTC

The Performance Wall of Large Datasets
When rendering a line chart with a few hundred points, Chart.js is seamless. However, once you push the dataset into the tens of thousands, you will likely encounter "jank"—stuttering animations, unresponsive tooltips, and high CPU usage. This happens because the HTML5 Canvas must calculate the position of every single vertex and execute a draw call for every segment, regardless of whether the user's screen has enough pixels to actually display those points.
The solution is Data Decimation. Instead of forcing the browser to render 50,000 points into a 1,000-pixel wide container, decimation reduces the number of points drawn while preserving the visual shape and critical anomalies of the data.
How Decimation Works
The decimation plugin acts as a pre-processor. Before the chart is drawn, it samples the dataset based on a chosen algorithm. This reduces the GPU overhead and the number of calculations required per frame.
Choosing Your Algorithm
- Min-Max: This algorithm divides the data into buckets and preserves only the minimum and maximum values for each. It is ideal for monitoring systems where seeing a "spike" (an anomaly) is more important than the exact trend line.
- LTTB (Largest Triangle Three Buckets): LTTB is a more sophisticated downsampling method that aims to maintain the visual characteristics of the original line. It is better for financial or scientific data where the overall trend must remain accurate.
Implementation Requirements
Decimation is not a "plug-and-play" feature for every chart. To enable it, your configuration must meet three strict criteria:
- Chart Type: It only works with
type: 'line'. - Axis Type: The x-axis must be
linearortime. - Data Order: Data must be sorted by the x-axis. Unsorted data will result in incorrect sampling and visual glitches.
Worked Example: High-Frequency Signal Rendering
To implement decimation, you must disable internal data parsing to allow the plugin to handle the dataset directly. Run this configuration in your frontend JavaScript environment (requires Chart.js v3.x or v4.x).
const config = {
type: 'line',
data: {
datasets: [{
label: 'Sensor Data',
data: largeDataset, // Array of {x: number, y: number}
parsing: false, // REQUIRED: Disables internal parsing for performance
}]
},
options: {
scales: {
x: { type: 'linear' } // REQUIRED: Must be linear or time
},
plugins: {
decimation: {
enabled: true,
algorithm: 'lttb', // Use 'min-max' for anomaly detection
samples: 500, // Target number of points to render
}
}
}
};
Verification and Diagnostics
To verify the plugin is working, check the browser's performance tab in DevTools. With decimation: { enabled: false }, you will see long "Scripting" and "Rendering" blocks during chart updates. With it enabled, the frame rate should stabilize, and the samples value should limit the number of vertices drawn on the canvas.
Trade-offs and Limitations
Decimation is a compromise between accuracy and performance. The primary risk is over-decimation. If you set the samples value too low (e.g., 50 samples for a highly volatile signal), you may lose subtle trends or small peaks that are technically present in the data but filtered out by the algorithm.
| Algorithm | Best For | Risk |
|---|---|---|
| Min-Max | Spike detection / Alerts | Can look "blocky" or jagged |
| LTTB | Trend analysis / Visual fidelity | Higher computational cost than Min-Max |
Actionable Summary
If your line charts are lagging with large datasets, disable parsing and enable the decimation plugin. Use LTTB for a smooth visual representation and Min-Max if you cannot afford to miss a single outlier. Always ensure your data is pre-sorted by the x-axis before passing it to the chart to avoid sampling errors.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.