Charts - Performance
Reference for renderer choice, decimation, animation limits, and windowing large or streaming datasets.
#Usage
import { ChartCanvas, ChartDecimation, ChartLine, ChartNavigator, ChartSvg, ChartZoom } from '@primeui/vue-chart';<ChartCanvas :height="360">
<ChartDecimation algorithm="lttb" :threshold="2000" :samples="500">
<ChartLine :data="data" category-x-field="timestamp" value-y-field="value" />
</ChartDecimation>
<ChartZoom mode="x" />
<ChartNavigator />
</ChartCanvas>Use SVG first. Move to Canvas, decimation, zoom, and navigator controls when the chart needs dense marks, live updates, or long ranges.
#Performance
Charts render large and streaming datasets, but the parent application still controls how much data reaches the chart. Pass only the data the view needs, then choose the right renderer and reach for decimation, windowing, and animation tuning as the point count grows.
#Runnable large-data evidence
The examples below are the current public proof points for high-density charts. They use the same components and source tabs as the type pages, but are grouped here so performance guidance is backed by demos users can run.
#100,000 raw scatter points on Canvas
This Canvas-only scatter demo renders the full 100,000-point cloud without decimation. boost mode activates above 50,000 visible points, avoids per-point DOM work, and pairs with quadtree hover lookup after the first pointer move. Use this pattern when the visual task is density, clustering, or outlier scanning and the raw point cloud needs to stay visible.
#100,000 readings with decimation and fidelity notes
This wind-farm scatter demo keeps the original 100,000 readings in the source data, then applies ChartDecimation algorithm="lttb" with a 2,000-sample target for the visible chart. Treat decimation as a visual-summary layer: it preserves the shape and visible extrema better than drawing every mark, but the rendered samples are not a row-for-row audit surface. For workflows that need exact point inspection, pair decimation with zoom, navigator windows, source data export, or a detail table that reads from the un-decimated dataset.
#Streaming with a bounded rolling window
This live server-metrics demo keeps a 60-point rolling window and updates the bound array once per second. Use the Canvas renderer for the high-frequency performance path, and keep the chart input bounded even if the application retains longer history elsewhere: store archival data in the app, worker, or backend, and pass only the current viewport window to the chart. That keeps chart memory proportional to the visible window instead of the total stream lifetime.
#Practical Limits
| Area | Guidance |
|---|---|
| Points per series | Decimate once a series passes a few thousand points |
| Series count | Keep the number of simultaneous series modest; shared tooltips hit-test every one |
| Renderer | Stay on SVG by default; move to Canvas for large or streaming data |
| Markers | Hide point markers (:show-markers="false") on dense series; per-point drawing dominates |
| Tooltips & hover | Default item mode tests the nearest point; shared tests every series, so scope it accordingly |
| Custom renderers | Render and tooltip functions run per element; keep them lightweight |
#SVG vs Canvas
SVG is the right default: crisp, CSS-themeable, and inspectable. Switch to ChartCanvas when pushing past a few thousand marks or for high-frequency streaming updates. The two roots share the same children, so swapping is a one-line change.
| Renderer | Use when |
|---|---|
ChartSvg | Default. Up to a few thousand marks, static or low-frequency updates, CSS theming |
ChartCanvas | Large datasets, real-time streaming, dense scatter and heatmap surfaces |
On Canvas, each series renders to its own compositor layer, so an update repaints only the changed series rather than the whole plot, an advantage for multi-series and live charts.
#Why the renderer choice matters at scale
The key difference is DOM weight. SVG creates one element per mark: a 50k-point bar chart is 50k <rect> nodes, which the browser must lay out, paint, and keep in memory. Canvas draws every mark into a single bitmap, so its DOM stays flat (one <canvas> per layer) no matter how many points you push.
| Points (bar) | ChartSvg DOM nodes | ChartCanvas DOM nodes |
|---|---|---|
| 5,000 | ~5,000 | ~1 per layer |
| 50,000 | ~50,000 | ~1 per layer |
Above ~8k marks on a single SVG series the chart logs a development-mode hint pointing you here. Line and area are cheaper, since a line series is a single <path> regardless of point count, so the ceiling mainly affects per-mark types (bar, scatter). For dense scatter, SVG also auto-batches into flat paths past a high threshold; bar has no such fallback, so prefer ChartCanvas (or ChartDecimation) for very large bar charts.
#Decimation
Add ChartDecimation to downsample a high-point series before it renders. It preserves the overall shape ('lttb'), the peaks and troughs ('min-max'), or scatter density ('k-means'), and only engages once the dataset passes threshold points (target output is samples, default 500).
On time axes the engine is viewport-aware: it filters to the visible window first, so zooming in progressively reveals full-resolution data once fewer than samples points are on screen. For scatter and other analytical views, document whether the chart is showing raw points or a visual summary so users do not mistake a decimated mark for a canonical source row. See Decimation for the full configuration.
#Animation
Animation is auto-disabled once the chart's total point count (summed across all series) exceeds the animation limit, so large datasets paint without tweening jank.
| Setting | Effect |
|---|---|
limit | Auto-disables animation past this total point count across the chart (default 5000) |
:animation="false" | Disables all animation; use for high-frequency or streaming updates |
Fixed axis min/max | Holds the scale steady so updates animate values, not the domain |
#Zoom & Navigator
For large ranges, render a windowed view instead of every point at once. ChartZoom adds wheel and drag-to-select zoom with panning; ChartNavigator adds an overview strip with a draggable selection window. Combined with viewport-aware decimation, users explore long time series at full detail without rendering the whole set up front.
#Live Updates
Streaming charts update on an interval or socket. Use ChartCanvas, keep a fixed-length rolling window, and hold the axis domain fixed with min/max so each tick animates the values rather than re-fitting the scale. Lower or disable animation when ticks arrive faster than they can settle, and update the bound data with a fresh array each tick so the chart diffs and repaints. On line and area charts, updateMode (default 'auto') detects whether a tick appends a point or scrolls the window and animates only the new segment instead of re-tweening the whole series.
Bound memory deliberately. A stream that appends forever will eventually overwhelm any renderer, so cap the chart-facing array (next.slice(-windowSize), a ring buffer, or a worker-owned viewport cache) and dispose timers or socket subscriptions when the chart unmounts. If users need historical replay, keep the full log outside the chart and load a selected range back into the viewport.
#Custom Rendering
Custom renderers and tooltip, label, and annotation render functions run for every element on that surface. Keep the work inside them local, avoid expensive formatting in large loops, and precompute repeated values such as labels and colors outside the render path.