Root element
All charts and their controls are created in a root element. This tutorial examines some of its functionality and configuration options.
What is root element?
Section titled “What is root element?”A root element is a kind of “wrapper” for everything else - charts, legend, labels, etc.- as well as repository for some chart-wide configuration options, such as locale, formatting options, themes, and others.
Whenever we create a new object in amCharts 5, we also pass in its root element, so that it correctly inherits themes and other settings.
Creating
Section titled “Creating”We instantiate a root element by calling new method of Root class:
const root = am5.Root.new("chartdiv");var root = am5.Root.new("chartdiv");The parameter we pass into new() call is the id or reference of the DOM container we will want to place our chart in.
The root element creation relies on the target container being already available.
In some setups the code might execute before DOM is fully loaded, which would result in error. For such cases amCharts provides a wrapper function:
am5.ready(function() { const root = am5.Root.new("chartdiv");});am5.ready(function() { var root = am5.Root.new("chartdiv");});The above will ensure that the creation of the root element will be delayed until DOM is fully loaded.
Another added benefit of adding chart code to a “ready” wrapper, is that all the code, including variables, will be limited to the anonymous function scope, rather than result in global scope.
As we already mentioned, root element will need to be passed into any other element we will create for the chart.
This is a requirement, so that the system knows which root element is being created for, as parent-child relation is not always apparent.
A reference to the root element is always the first parameter to the new() method call on any element being created, other than root itself.
For example, here’s how root element is passed into an PieChart that is being newly created:
const chart = root.container.children.push( am5pie.PieChart.new(root, {}));var chart = root.container.children.push( am5pie.PieChart.new(root, {}));Multiple Root elements
Section titled “Multiple Root elements”We can have as many Root elements on the same web page as we need. We just need to make sure their id attributes are unique, and that we reference correct id when we create Root element.
E.g. we create three <div> elements with unique IDs: chartdiv1, chartdiv2, and chartdiv3:
<div id="chartdiv1" class="chartdiv"></div><div id="chartdiv2" class="chartdiv"></div><div id="chartdiv3" class="chartdiv"></div>Then we can reference them when creating three unique charts:
const root1 = am5.Root.new("chartdiv1");const root2 = am5.Root.new("chartdiv2");const root3 = am5.Root.new("chartdiv3");var root1 = am5.Root.new("chartdiv1");var root2 = am5.Root.new("chartdiv2");var root3 = am5.Root.new("chartdiv3");Or if we need to create a fairly similar charts, we can reuse the code by wrapping chart creation into a function:
function createChart(div, data) { const root = am5.Root.new(div); // ... the rest of the chart config}
createChart("chartdiv1", data1);createChart("chartdiv2", data2);createChart("chartdiv3", data3);function createChart(div, data) { var root = am5.Root.new(div); // ... the rest of the chart config}
createChart("chartdiv1", data1);createChart("chartdiv2", data2);createChart("chartdiv3", data3);Configuring root
Section titled “Configuring root”Formatters
Section titled “Formatters”Root element holds instances of the three formatters used throughout the charts and their elements:
| Property | Class |
|---|---|
numberFormatter |
NumberFormatter |
dateFormatter |
DateFormatter |
durationFormatter |
DurationFormatter |
Those are global formatters that define formats and related options used in formatting numbers, date/time, and duration.
Performance
Section titled “Performance”amCharts 5 rendering engine will try to render charts and animations as smoothly as possible, cramming as many frames per second as possible.
The more frames per second animation plays, the smoother it looks.
However, if smoothness is not as important as resource usage, or chart-heavy page is suffering from performance-related issues, we can limit number of frames-per-second using root elements fps property:
root.fps = 30;root.fps = 30;The smaller the number, the less resources charts will use, at the expense of smoothness of animations.
Time zone
Section titled “Time zone”Normally, chart’s date/time-related functionality will display date and time in user’s local time zone.
If we need to display them in a specific time zone, wherever the user is, we can use root element’s timezone property.
It needs to be set with an instance of Timezone object, e.g.:
root.timezone = am5.Timezone.new("America/Vancouver");root.timezone = am5.Timezone.new("America/Vancouver");As per example above, Timezone takes string-based time zone identifier as a parameter of its new() call.
A few examples: "Asia/Tokyo", "America/New_York", "Europe/Lisbon", "Asia/Kathmandu" (UTC+5:45).
For a full list of officially supported time zone identifiers, please refer to this IANA page.
The time zone applies to everything date-related on the chart:
- Date axes place their grid at that zone’s midnight, hours, weeks, and months.
- Axis labels, tooltips, and formatted dates show date and time in that zone.
- Data grouping groups data items by that zone’s days, weeks, and months.
- Where the zone’s clocks change for daylight saving, a day is 23 or 25 hours long, and grid, labels, and data groups follow.
- Stock chart’s period selector and date range selector use it, too.
The data itself does not change: timestamps are moments in time, and the time zone only decides which day and hour they fall on.
root.utc = true;root.utc = true;First day of week
Section titled “First day of week”Normally, the locale we are using will determine which week day is considered start of the week.
If we want to override it, we can do so by modifying firstDayOfWeek value in the locale:
// Start the week on Sundayroot.locale.firstDayOfWeek = 0;// Start the week on Sundayroot.locale.firstDayOfWeek = 0;Settings
Section titled “Settings”It’s possible to pass in a root element settings object as a second parameter to its new() call.
Renderer
Section titled “Renderer”Charts are drawn on canvas by default. They can also be drawn as SVG, by setting renderer to am5.SVGRenderer:
const root = am5.Root.new("chartdiv", { renderer: am5.SVGRenderer});var root = am5.Root.new("chartdiv", { renderer: am5.SVGRenderer});To draw every chart on the page as SVG, set the default once, before creating any root elements:
am5.Root.defaultRenderer = am5.SVGRenderer;am5.Root.defaultRenderer = am5.SVGRenderer;The renderer can only be chosen when the root element is created. Charts look and behave the same with either one: text is measured the same way, so labels wrap and truncate identically, and all interactions work as usual.
The only difference: blend modes DST_OVER, SRC_ATOP, and XOR are canvas-only. In SVG they are drawn as normal, with a warning in the console.
Safe resolution
Section titled “Safe resolution”This section deals with the setting: useSafeResolution: boolean (default: true).
The setting means that chart will automatically choose resolution of the chart that is “safe” for the given device.
For example, in iOS 15 and up, there were memory limits imposed on canvas rendering, which means that with large charts, on big tablets, and even larger Apple phones, that limit might get hit, effectively breaking the charts.
For those devices, “safe resolution” will be reduced, to minimize the chance of the issue hitting actual chart setup.
To disable such resolution reduction, we can use root element’s settings:
const root = am5.Root.new("chartdiv", { useSafeResolution: false});var root = am5.Root.new("chartdiv", { useSafeResolution: false});Expanded tooltip bounds
Section titled “Expanded tooltip bounds”Normally, tooltips are constrained to the area of the actual chart.
Using root element’s tooltipContainerBounds setting, it’s possible to add additional margins around chart area for tooltips.
The setting accepts an object with pixel values for top, right, bottom, and left sides of the chart area:
const root = am5.Root.new("chartdiv", { tooltipContainerBounds: { top: 50, right: 100, bottom: 50, left: 100 }});var root = am5.Root.new("chartdiv", { tooltipContainerBounds: { top: 50, right: 100, bottom: 50, left: 100 }});Custom sizing function
Section titled “Custom sizing function”Usually, Root element will automatically size itself correctly.
However, in some rare setups, e.g. when using CSS transform scaling, the built-in sizing mechanism will fail.
In such cases, you as an implementor of the chart setup, will need to provide functionality for custom sizing the Root.
For that, we can use Root’s setting: calculateSize.
It accepts a reference to a function, which dimensions calculated by built-in mechanism, and should return an object with modified, or non-modified dimensions.
let scale = 2;
const root = am5.Root.new("chartdiv", { calculateSize: function(dimensions) { return { width: dimensions.width * scale, height: dimensions.height * scale }; },});var scale = 2;
var root = am5.Root.new("chartdiv", { calculateSize: function(dimensions) { return { width: dimensions.width * scale, height: dimensions.height * scale }; },});The above code will enlarge the chart’s canvas by 2 - a good way to accommodate the custom translate scaling.
We can also use clientWidth and clientHeight to grab actual sizing, which would take the translates into account:
const root = am5.Root.new("chartdiv", { calculateSize: function(dimensions) { return { width: root.dom.clientWidth, height: root.dom.clientHeight }; },});var root = am5.Root.new("chartdiv", { calculateSize: function(dimensions) { return { width: root.dom.clientWidth, height: root.dom.clientHeight }; },});HTML sanitation
Section titled “HTML sanitation”This section deals with the setting: sanitizeHTML: boolean (default: true).
A number of chart elements can display arbitrary HTML content - e.g. html and labelHTML label settings, HTML-based tooltips, modal popups, and export menu labels. This content is injected directly into the page.
Since such content often includes values coming from chart data, which in turn frequently originates from an untrusted back-end, amCharts sanitizes it before displaying.
Sanitation strips out constructs that are practically only used for cross-site scripting (XSS) attacks - e.g. <script> tags, inline event handlers like onerror, and javascript: URLs - while leaving legitimate markup such as formatting, links, and styles intact.
If you fully control all HTML content used in your charts, you can disable sanitation by setting sanitizeHTML to false:
const root = am5.Root.new("chartdiv", { sanitizeHTML: false});var root = am5.Root.new("chartdiv", { sanitizeHTML: false});High contrast mode
Section titled “High contrast mode”When the system is in a forced colors mode, such as Windows High Contrast, chart’s labels, grid, axes, and buttons follow the system colors, so they stay visible. Series colors are kept.
To keep the chart’s own colors instead, set forcedColors to false:
const root = am5.Root.new("chartdiv", { forcedColors: false});var root = am5.Root.new("chartdiv", { forcedColors: false});Other configuration options
Section titled “Other configuration options”Root element contains some other global options, too:
- Locale
- Top-level tab index (accessibility)
Reusing
Section titled “Reusing”If we need to completely replace contents of the chart, we can dispose them, but keep root element for new chart.
To remove all elements from the root, simply clear children of its container:
root.container.children.clear();root.container.children.clear();Root element is now empty (as newly created) and can be used to add any other charts to it.
Reusing root element can be faster than completely destroying it and creating a new element.
Disposing
Section titled “Disposing”If we don’t need root element anymore, we can dispose it, by calling its dispose() method:
root.dispose();root.dispose();Disposing root element will automatically dispose all its children charts as well. No need to dispose them separately.
If we do not have reference to a previously created root element, we can find it among am5.registry.rootElements, which is an array that holds all root elements.
am5.array.each(am5.registry.rootElements, function(root) { if (root.dom.id == divId) { root.dispose(); }});am5.array.each(am5.registry.rootElements, function(root) { if (root.dom.id == divId) { root.dispose(); }});Controlling auto-resize
Section titled “Controlling auto-resize”The root element will automatically resize itself if the size of its parent <div> element changes.
It can be disabled using autoResize property:
root.autoResize = false;root.autoResize = false;If set that way, root element will ignore any size changes in its parent and will remain at the same size it was first initialized with.
To manually trigger a resize for new dimensions, use resize() method:
root.resize();root.resize();Touch-related options
Section titled “Touch-related options”There are a few options that can be used to tweak built-in touch-related functionality of the charts.
Charts that use touch gestures for their functionality, like zooming or panning the chart or map, will hijack page gestures such as scroll.
If we set root element’s tapToActivate property to true, user will first need to tap on the chart before those functions are enabled.
Once “activated” chart’s gesture-based functionality will start to work normally, and will revert back to “inactive” state after 3 seconds of inactivity.
The default timeout can be modified via tapToActivateTimeout property, which accepts time in milliseconds.
root.tapToActivate = true;root.tapToActivateTimeout = 2000;root.tapToActivate = true;root.tapToActivateTimeout = 2000;Chart ready event
Section titled “Chart ready event”In some cases we may need to know when the chart is ready and all initial animations have played out.
While there’s no such event built-in, we can utilize root element’s frameended event with debounced handler to catch precise moment when chart is done painting and animating.
let timeout;
root.events.on("frameended", exportChart);
function exportChart() { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function() { root.events.off("frameended", exportChart); console.log("Chart ready!"); }, 100)}var timeout;
root.events.on("frameended", exportChart);
function exportChart() { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function() { root.events.off("frameended", exportChart); console.log("Chart ready!"); }, 100)}Each time something is updated on the chart and some elements are repainted, its root element’s frameended event kicks in.
Our code waits until there’s an idle moment of at least 100ms, before “deciding” the chart is fully functional and initial animations are played out.
For an even safer approach, we can use a debounced frameended event:
let timeout;
root.events.onDebounced("frameended", exportChart, 500);
function exportChart() { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function() { root.events.off("frameended", exportChart); console.log("Chart ready!"); }, 100)}var timeout;
root.events.onDebounced("frameended", exportChart, 500);
function exportChart() { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function() { root.events.off("frameended", exportChart); console.log("Chart ready!"); }, 100)}This will ensure that the code will not kick in until the chart building is done, including initial animations.
Using in a Web Component
Section titled “Using in a Web Component”We can wrap chart as an HTMLElement.
When creating the Root, you can use an element instead of a string ID of the target chart container:
class MyChart extends HTMLElement { connectedCallback() { const root = am5.Root.new(this);
// Rest of chart code... }}class MyChart extends HTMLElement { connectedCallback() { const root = am5.Root.new(this);
// Rest of chart code... }}