Skip to main content

Overview

amCharts 5 is designed to handle large datasets and complex visualizations efficiently. However, when working with massive amounts of data or resource-constrained environments, performance optimization becomes crucial.

Frame Rate Control

Setting Maximum FPS

Control the maximum frames per second (FPS) to balance smoothness with performance. By default, amCharts runs at the highest possible FPS.
import * as am5 from "@amcharts/amcharts5";

let root = am5.Root.new("chartdiv", {
  useSafeResolution: true
});

// Limit to 30 FPS
root.fps = 30;
Setting a lower FPS can significantly improve performance on devices with limited resources or when running multiple charts simultaneously.
If fps is set to undefined (default), the chart will run at the highest FPS possible, typically 60 FPS or higher depending on the browser and display.

Safe Resolution Mode

The useSafeResolution setting helps prevent memory issues on platforms with strict memory limitations, such as Safari.
let root = am5.Root.new("chartdiv", {
  useSafeResolution: true  // Default is true
});
Disabling safe resolution (useSafeResolution: false) may cause crashes on memory-limited platforms when rendering high-resolution charts.

Data Optimization

Limiting Data Points

When working with large datasets, consider showing only a subset of data and using zoom/scroll to navigate.
import * as am5xy from "@amcharts/amcharts5/xy";

// Only process visible data range
let series = chart.series.push(am5xy.LineSeries.new(root, {
  xAxis: xAxis,
  yAxis: yAxis,
  valueYField: "value",
  valueXField: "date"
}));

// Set data
series.data.setAll(largeDataset);

// Use scrollbar to show only portion of data
let scrollbarX = am5xy.XYChartScrollbar.new(root, {
  orientation: "horizontal",
  height: 60
});
chart.set("scrollbarX", scrollbarX);

Aggregate Data Exclusion

Optimize performance by excluding fields from automatic aggregation when aggregate values aren’t needed.
let series = chart.series.push(am5xy.ColumnSeries.new(root, {
  xAxis: xAxis,
  yAxis: yAxis,
  valueYField: "value",
  categoryXField: "category",
  // Exclude fields from aggregation to improve performance
  excludeFromAggregate: ["metadata", "tags", "description"]
}));
The excludeFromAggregate setting is particularly useful when you have data fields that are only used for display purposes and don’t need statistical calculations.

Visual Element Optimization

Hiding Elements Conditionally

Use the forceHidden property to completely hide elements and skip their rendering.
import * as am5 from "@amcharts/amcharts5";

// Hide bullets on small screens
let bullet = series.bullets.push(function() {
  return am5.Bullet.new(root, {
    sprite: am5.Circle.new(root, {
      radius: 5,
      fill: series.get("fill"),
      // Completely hide if chart is too small
      forceHidden: root.width() < 400
    })
  });
});
The difference between forceHidden and visible is that forceHidden completely skips rendering, while visible: false still processes the element but doesn’t display it.

Reducing Bullets

Bullets can significantly impact performance with large datasets. Consider reducing or removing them.
// Only show bullets on hover
series.strokes.template.setAll({
  strokeWidth: 2
});

// Don't add bullets by default for better performance
// Add them only when user interacts with specific data points

Animation Performance

Disabling Animations

For charts with frequent updates or large datasets, consider disabling animations.
import * as am5 from "@amcharts/amcharts5";

// Disable all animations on the series
series.set("interpolationDuration", 0);

// Or disable specific animation
series.appear(0);  // 0 milliseconds = instant

Controlling Animation Duration

// Reduce animation time for better performance
series.set("interpolationDuration", 300);  // 300ms instead of default

// Disable tooltip animations
let tooltip = am5.Tooltip.new(root, {
  animationDuration: 0
});
series.set("tooltip", tooltip);

Memory Management

Proper Disposal

Always dispose of chart instances when they’re no longer needed to prevent memory leaks.
// Create root
let root = am5.Root.new("chartdiv");

// ... create charts and series

// Clean up when done (e.g., when component unmounts)
function cleanup() {
  if (root) {
    root.dispose();
  }
}

// In React:
useEffect(() => {
  let root = am5.Root.new("chartdiv");
  // ... setup chart
  
  return () => {
    root.dispose();
  };
}, []);

Reusing Instances

Instead of creating and destroying chart instances frequently, consider updating existing instances.
// Instead of recreating:
// root.dispose();
// root = am5.Root.new("chartdiv");

// Update existing data:
series.data.setAll(newData);

Rendering Optimization

Pausing Updates

When making multiple changes, pause the chart to batch updates.
// Pause rendering
root._renderer._omitTicks = true;

// Make multiple changes
series.data.setAll(data1);
series2.data.setAll(data2);
chart.set("paddingLeft", 20);

// Resume rendering
root._renderer._omitTicks = false;
root._render();
The _renderer._omitTicks property is internal and should be used carefully. It’s primarily for advanced use cases where you need to make many simultaneous updates.

Auto-Resize Control

Control whether charts automatically resize when the container changes.
let root = am5.Root.new("chartdiv");

// Disable auto-resize for manual control
root.autoResize = false;

// Manually trigger resize when needed
window.addEventListener("resize", () => {
  root.resize();
});

Performance Best Practices

  • Use data grouping and aggregation
  • Implement virtual scrolling with scrollbars
  • Reduce or eliminate bullets
  • Disable tooltips or use pointer-based tooltips only
  • Set a maximum FPS limit (30 FPS)
  • Enable useSafeResolution
  • Reduce animation durations
  • Limit the number of series
  • Use responsive theme to hide elements on small screens
  • Set FPS to 30 or lower
  • Batch data updates instead of updating individual points
  • Use interpolationDuration: 0 for instant updates
  • Consider using a rolling window of data
  • Limit the update frequency to what users can perceive (30-60 FPS)
  • Share a single root instance when possible
  • Stagger chart initialization
  • Use lazy loading for off-screen charts
  • Consider using a lower FPS limit

Profiling and Debugging

Measuring Performance

Use browser DevTools to profile your charts:
root.events.on("framestarted", (ev) => {
  console.log("Frame started:", ev.timestamp);
});

root.events.on("frameended", (ev) => {
  console.log("Frame ended:", ev.timestamp);
});

Identifying Bottlenecks

  1. Check the number of DOM elements created
  2. Monitor memory usage over time
  3. Profile animation performance
  4. Measure data processing time
// Measure data processing time
const startTime = performance.now();
series.data.setAll(largeDataset);
const endTime = performance.now();
console.log(`Data processing took ${endTime - startTime}ms`);

Responsive Design

Learn how to optimize charts for different screen sizes

Data Loading

Best practices for loading and managing data

Build docs developers (and LLMs) love