# Table of Contents - [amCharts 5 Documentation](#amcharts-5-documentation) - [Root element – amCharts 5 Documentation](#root-element-amcharts-5-documentation) - [Integrations – amCharts 5 Documentation](#integrations-amcharts-5-documentation) - [Using amCharts 5 with Next.js – amCharts 5 Documentation](#using-amcharts-5-with-next-js-amcharts-5-documentation) - [Using amCharts 5 with React – amCharts 5 Documentation](#using-amcharts-5-with-react-amcharts-5-documentation) - [Using amCharts 5 with Angular – amCharts 5 Documentation](#using-amcharts-5-with-angular-amcharts-5-documentation) - [Getting started – amCharts 5 Documentation](#getting-started-amcharts-5-documentation) - [Using amCharts 5 with Nuxt 3 – amCharts 5 Documentation](#using-amcharts-5-with-nuxt-3-amcharts-5-documentation) - [Using amCharts 5 with SvelteKit – amCharts 5 Documentation](#using-amcharts-5-with-sveltekit-amcharts-5-documentation) - [XY chart – amCharts 5 Documentation](#xy-chart-amcharts-5-documentation) - [Charts – amCharts 5 Documentation](#charts-amcharts-5-documentation) - [Using amCharts 5 with Jest – amCharts 5 Documentation](#using-amcharts-5-with-jest-amcharts-5-documentation) - [Using amCharts 5 with Remix – amCharts 5 Documentation](#using-amcharts-5-with-remix-amcharts-5-documentation) - [Using amCharts 5 with Ember.js – amCharts 5 Documentation](#using-amcharts-5-with-ember-js-amcharts-5-documentation) - [Using amCharts 5 with Vue.js – amCharts 5 Documentation](#using-amcharts-5-with-vue-js-amcharts-5-documentation) - [Testing amCharts 5 with Cypress – amCharts 5 Documentation](#testing-amcharts-5-with-cypress-amcharts-5-documentation) - [Axes – amCharts 5 Documentation](#axes-amcharts-5-documentation) - [XY chart series – amCharts 5 Documentation](#xy-chart-series-amcharts-5-documentation) - [Zoom and pan – amCharts 5 Documentation](#zoom-and-pan-amcharts-5-documentation) - [Pie chart – amCharts 5 Documentation](#pie-chart-amcharts-5-documentation) - [Scrollbars – amCharts 5 Documentation](#scrollbars-amcharts-5-documentation) - [Cursor – amCharts 5 Documentation](#cursor-amcharts-5-documentation) - [Legend and XY series – amCharts 5 Documentation](#legend-and-xy-series-amcharts-5-documentation) - [Funnel, pyramid, and pictorial charts – amCharts 5 Documentation](#funnel-pyramid-and-pictorial-charts-amcharts-5-documentation) - [Containers of an XY chart – amCharts 5 Documentation](#containers-of-an-xy-chart-amcharts-5-documentation) - [Radar axes – amCharts 5 Documentation](#radar-axes-amcharts-5-documentation) - [Radar series – amCharts 5 Documentation](#radar-series-amcharts-5-documentation) - [Grouping slices – amCharts 5 Documentation](#grouping-slices-amcharts-5-documentation) - [Legend and Pie/Sliced series – amCharts 5 Documentation](#legend-and-pie-sliced-series-amcharts-5-documentation) - [Pie and sliced charts – amCharts 5 Documentation](#pie-and-sliced-charts-amcharts-5-documentation) - [Gauge charts – amCharts 5 Documentation](#gauge-charts-amcharts-5-documentation) - [Radar chart – amCharts 5 Documentation](#radar-chart-amcharts-5-documentation) - [Map chart – amCharts 5 Documentation](#map-chart-amcharts-5-documentation) - [Map polygon series – amCharts 5 Documentation](#map-polygon-series-amcharts-5-documentation) - [Map line series – amCharts 5 Documentation](#map-line-series-amcharts-5-documentation) - [Clustered point series – amCharts 5 Documentation](#clustered-point-series-amcharts-5-documentation) - [Map point series – amCharts 5 Documentation](#map-point-series-amcharts-5-documentation) - [Graticule series – amCharts 5 Documentation](#graticule-series-amcharts-5-documentation) - [Country data – amCharts 5 Documentation](#country-data-amcharts-5-documentation) - [Panning and zooming the map – amCharts 5 Documentation](#panning-and-zooming-the-map-amcharts-5-documentation) - [Map drill-down – amCharts 5 Documentation](#map-drill-down-amcharts-5-documentation) - [Map API – amCharts 5 Documentation](#map-api-amcharts-5-documentation) - [Hierarchy charts – amCharts 5 Documentation](#hierarchy-charts-amcharts-5-documentation) - [Treemap – amCharts 5 Documentation](#treemap-amcharts-5-documentation) - [Map name translations – amCharts 5 Documentation](#map-name-translations-amcharts-5-documentation) - [Force-directed – amCharts 5 Documentation](#force-directed-amcharts-5-documentation) - [Partition – amCharts 5 Documentation](#partition-amcharts-5-documentation) - [Tree – amCharts 5 Documentation](#tree-amcharts-5-documentation) - [Sunburst – amCharts 5 Documentation](#sunburst-amcharts-5-documentation) - [Pack – amCharts 5 Documentation](#pack-amcharts-5-documentation) - [Voronoi Treemap – amCharts 5 Documentation](#voronoi-treemap-amcharts-5-documentation) - [Hierarchy node colors – amCharts 5 Documentation](#hierarchy-node-colors-amcharts-5-documentation) - [Hierarchy drill-down – amCharts 5 Documentation](#hierarchy-drill-down-amcharts-5-documentation) - [Breadcrumb navigation – amCharts 5 Documentation](#breadcrumb-navigation-amcharts-5-documentation) - [Legend and hierarchy series – amCharts 5 Documentation](#legend-and-hierarchy-series-amcharts-5-documentation) - [Hierarchy link bullets – amCharts 5 Documentation](#hierarchy-link-bullets-amcharts-5-documentation) - [Hierarchy API – amCharts 5 Documentation](#hierarchy-api-amcharts-5-documentation) - [Flow charts – amCharts 5 Documentation](#flow-charts-amcharts-5-documentation) - [Sankey diagram – amCharts 5 Documentation](#sankey-diagram-amcharts-5-documentation) - [Chord diagram – amCharts 5 Documentation](#chord-diagram-amcharts-5-documentation) - [Arc Diagram – amCharts 5 Documentation](#arc-diagram-amcharts-5-documentation) - [Flow chart bullets – amCharts 5 Documentation](#flow-chart-bullets-amcharts-5-documentation) - [Word cloud – amCharts 5 Documentation](#word-cloud-amcharts-5-documentation) - [Venn diagram – amCharts 5 Documentation](#venn-diagram-amcharts-5-documentation) - [Stock chart – amCharts 5 Documentation](#stock-chart-amcharts-5-documentation) - [Panels – amCharts 5 Documentation](#panels-amcharts-5-documentation) - [Stock annotations – amCharts 5 Documentation](#stock-annotations-amcharts-5-documentation) - [Stock legend – amCharts 5 Documentation](#stock-legend-amcharts-5-documentation) - [Serializing indicators and annotations – amCharts 5 Documentation](#serializing-indicators-and-annotations-amcharts-5-documentation) - [Stock toolbar – amCharts 5 Documentation](#stock-toolbar-amcharts-5-documentation) - [Indicators – amCharts 5 Documentation](#indicators-amcharts-5-documentation) - [Element states – amCharts 5 Documentation](#element-states-amcharts-5-documentation) - [Percent scale – amCharts 5 Documentation](#percent-scale-amcharts-5-documentation) - [Concepts – amCharts 5 Documentation](#concepts-amcharts-5-documentation) - [Translating Stock Chart – amCharts 5 Documentation](#translating-stock-chart-amcharts-5-documentation) - [Settings – amCharts 5 Documentation](#settings-amcharts-5-documentation) - [List templates – amCharts 5 Documentation](#list-templates-amcharts-5-documentation) - [Template fields – amCharts 5 Documentation](#template-fields-amcharts-5-documentation) - [Adapters – amCharts 5 Documentation](#adapters-amcharts-5-documentation) - [Heat rules – amCharts 5 Documentation](#heat-rules-amcharts-5-documentation) - [Getting the most out of net.load utility – amCharts 5 Documentation](#getting-the-most-out-of-net-load-utility-amcharts-5-documentation) - [Data – amCharts 5 Documentation](#data-amcharts-5-documentation) - [Gradients – amCharts 5 Documentation](#gradients-amcharts-5-documentation) - [Shadows – amCharts 5 Documentation](#shadows-amcharts-5-documentation) - [Legend – amCharts 5 Documentation](#legend-amcharts-5-documentation) - [Heat legend – amCharts 5 Documentation](#heat-legend-amcharts-5-documentation) - [Filters – amCharts 5 Documentation](#filters-amcharts-5-documentation) - [Common elements – amCharts 5 Documentation](#common-elements-amcharts-5-documentation) - [Bullets – amCharts 5 Documentation](#bullets-amcharts-5-documentation) - [Colors, gradients, and patterns – amCharts 5 Documentation](#colors-gradients-and-patterns-amcharts-5-documentation) - [Patterns – amCharts 5 Documentation](#patterns-amcharts-5-documentation) - [Graphics – amCharts 5 Documentation](#graphics-amcharts-5-documentation) - [Buttons – amCharts 5 Documentation](#buttons-amcharts-5-documentation) - [Labels – amCharts 5 Documentation](#labels-amcharts-5-documentation) - [Images – amCharts 5 Documentation](#images-amcharts-5-documentation) - [Containers – amCharts 5 Documentation](#containers-amcharts-5-documentation) - [Layers – amCharts 5 Documentation](#layers-amcharts-5-documentation) - [HTML content – amCharts 5 Documentation](#html-content-amcharts-5-documentation) - [Tooltips – amCharts 5 Documentation](#tooltips-amcharts-5-documentation) - [Formatters – amCharts 5 Documentation](#formatters-amcharts-5-documentation) - [Modal popups – amCharts 5 Documentation](#modal-popups-amcharts-5-documentation) - [Formatting durations – amCharts 5 Documentation](#formatting-durations-amcharts-5-documentation) - [Formatting numbers – amCharts 5 Documentation](#formatting-numbers-amcharts-5-documentation) - [Data placeholders – amCharts 5 Documentation](#data-placeholders-amcharts-5-documentation) - [Text styling – amCharts 5 Documentation](#text-styling-amcharts-5-documentation) - [Events – amCharts 5 Documentation](#events-amcharts-5-documentation) - [Formatting dates – amCharts 5 Documentation](#formatting-dates-amcharts-5-documentation) --- # amCharts 5 Documentation Welcome to documentation website for **amCharts 5**! Use the navigation on the left to select a topic. Most contain multiple sub-pages. --- # Root element – amCharts 5 Documentation 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? --------------------- 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 -------- 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. Using ----- 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 ---------------------- 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 `
` elements with unique IDs: `chartdiv1`, `chartdiv2`, and `chartdiv3`:
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); See the Pen Week start on Sunday by amCharts team (@amcharts) on CodePen. Configuring root ---------------- ### 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. MORE INFOFor more information, please refer to "Formatters: [Global formatters](https://www.amcharts.com/docs/v5/concepts/formatters/#Global_formatters) ". ### 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 Normally, chart's date/time-related functionality will display date and time in user's local time zone. If we need to force displaying of the information in a specific time zone, 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 constructor parameter. A few examples: `"UTC"`, `"Asia/Tokyo"`, `"America/New_York"`, `"Europe/Lisbon"`. For a full list of officially supported time zone identifiers, please refer to [this IANA page](https://www.iana.org/time-zones) . NOTEPlease note that if you are using `"UTC"` it's better to use `root.utc = true`. It will work faster than via named `root.timezone = "UTC"`. IMPORTANTUsing time zone feature may noticeable affect performance of the chart, especially with large data sets, since every single date will need to be recalculated. ### First day of week Normally, the [locale](https://www.amcharts.com/docs/v5/concepts/locales/) 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 Sunday root.locale.firstDayOfWeek = 0; // Start the week on Sunday root.locale.firstDayOfWeek = 0; See the Pen Week start on Sunday by amCharts team (@amcharts) on CodePen. ### Settings It's possible to pass in a root element settings object as a second parameter to its `new()` call. ### 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 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 } }); MORE INFOFor more information and a demo, visit "Tooltips: [Tooltips outside chart area](https://www.amcharts.com/docs/v5/concepts/common-elements/tooltips/#Tooltips_outside_chart_area) ". ### 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 }; }, }); ### Other configuration options Root element contains some other global options, too: * [Locale](https://www.amcharts.com/docs/v5/concepts/locales/) * [Top-level tab index](https://www.amcharts.com/docs/v5/concepts/accessibility/) (accessibility) 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 --------- 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. NOTETrying to create a new root element in a container before disposing the old one that is currently residing there, will result in an error. 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(); } }); See the Pen Disposing previously created Root element by amCharts team (@amcharts) on CodePen. Controlling auto-resize ----------------------- The root element will automatically resize itself if the size of its parent `
` element changes. It can be disabled using `[autoResize](https://www.amcharts.com/docs/v5/reference/root/#autoResize_property) ` 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()](https://www.amcharts.com/docs/v5/reference/root/#resize_method) ` method: root.resize(); root.resize(); 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 ----------------- 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. 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... } } --- # Integrations – amCharts 5 Documentation This section is a collection of tutorial related to various frameworks and their usage with amCharts 5. Select a tutorial related to the framework you are using. --- # Using amCharts 5 with Next.js – amCharts 5 Documentation Next.js is a React framework, so the code in [our React tutorial](https://www.amcharts.com/docs/v5/getting-started/integrations/react/) will work. However, Next.js also uses SSR, which does not work with amCharts. In order to use amCharts with Next.js, [you must add `"use client";`](https://nextjs.org/docs/app/building-your-application/rendering/client-components) at the top of your `Chart.jsx` file: "use client"; import { useLayoutEffect } from 'react'; import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import am5themes\_Animated from "@amcharts/amcharts5/themes/Animated"; function Chart(props) { ... } export default Chart; Older versions of NextJS ------------------------ Older versions of NextJS do not have `"use client"`, so instead [you must use `dynamic`](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#with-no-ssr) to load the Chart component: import dynamic from 'next/dynamic'; const Chart = dynamic(() => import('./Chart'), { ssr: false }); function App() { return ; } --- # Using amCharts 5 with React – amCharts 5 Documentation This tutorial will show you every step you need to use amCharts 5 with React + Vite. Creating a project ------------------ npm create vite@latest my-project -- --template react cd my-project npm install npm install @amcharts/amcharts5 Create a new `src/Chart.jsx` file: import { useLayoutEffect } from 'react'; import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import am5themes\_Animated from "@amcharts/amcharts5/themes/Animated"; function Chart(props) { useLayoutEffect(() => { let root = am5.Root.new("chartdiv"); root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); let chart = root.container.children.push( am5xy.XYChart.new(root, { panY: false, layout: root.verticalLayout }) ); // Define data let data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; // Create Y-axis let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); // Create X-Axis let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(data); // Create series let series1 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value1", categoryXField: "category" }) ); series1.data.setAll(data); let series2 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value2", categoryXField: "category" }) ); series2.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // Add cursor chart.set("cursor", am5xy.XYCursor.new(root, {})); return () => { root.dispose(); }; }, \[\]); return (
); } export default Chart; You can now import and use the `Chart` component inside of `src/App.jsx`: import { useState } from 'react' import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import Chart from './Chart'; import './App.css'; function App() { return ( <> ) } export default App Updating the chart ------------------ You can update the chart by storing the amCharts objects inside of a `useRef`, and then using `useLayoutEffect` multiple times to update it: import { useRef, useLayoutEffect } from 'react'; import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import am5themes\_Animated from "@amcharts/amcharts5/themes/Animated"; function Chart(props) { const chartRef = useRef(null); // Creates the chart, this code only runs one time useLayoutEffect(() => { let root = am5.Root.new("chartdiv"); root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); let chart = root.container.children.push( am5xy.XYChart.new(root, { panY: false, layout: root.verticalLayout }) ); // Define data let data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; // Create Y-axis let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); // Create X-Axis let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(data); // Create series let series1 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value1", categoryXField: "category" }) ); series1.data.setAll(data); let series2 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value2", categoryXField: "category" }) ); series2.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // Add cursor chart.set("cursor", am5xy.XYCursor.new(root, {})); chartRef.current = chart; return () => { root.dispose(); }; }, \[\]); // When the paddingRight prop changes it will update the chart useLayoutEffect(() => { chartRef.current.set("paddingRight", props.paddingRight); }, \[props.paddingRight\]); return (
); } export default Chart; And then you can pass in props to the Chart component: Examples -------- ### Simple chart ### With data binding ### Stock chart --- # Using amCharts 5 with Angular – amCharts 5 Documentation This tutorial will provide basic information, needed to run amCharts 5 with [Angular](https://angular.io/) framework. Requirements ------------ amCharts 5 requires **TypeScript 4.3** or later to run. This in turn means that it will run on **Angular 12** or later. For running amCharts in lower versions of Angular than 12, see "Before Angular 12" section. Using amCharts -------------- First, create a new Angular project: npx -p @angular/cli ng new my-project cd my-project You can now run your project by using this command: npm start If you load `http://localhost:4200/` in a browser, you should see your new project! Now it's time to add in an amCharts 5 chart. First create a new chart component: npm run -- ng generate component chart --module app Then use this command to install amCharts 5: npm install @amcharts/amcharts5 Then add in the following code to the `src/app/chart/chart.component.html` file:
And use the following code in `src/app/chart/chart.component.ts`: import { Component, Inject, NgZone, PLATFORM\_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; // amCharts imports import \* as am5 from '@amcharts/amcharts5'; import \* as am5xy from '@amcharts/amcharts5/xy'; import am5themes\_Animated from '@amcharts/amcharts5/themes/Animated'; @Component({ selector: 'app-chart', templateUrl: './chart.component.html', styleUrls: \['./chart.component.css'\] }) export class ChartComponent { private root!: am5.Root; constructor(@Inject(PLATFORM\_ID) private platformId: Object, private zone: NgZone) {} // Run the function only in the browser browserOnly(f: () => void) { if (isPlatformBrowser(this.platformId)) { this.zone.runOutsideAngular(() => { f(); }); } } ngAfterViewInit() { // Chart code goes in here this.browserOnly(() => { let root = am5.Root.new("chartdiv"); root.setThemes(\[am5themes\_Animated.new(root)\]); let chart = root.container.children.push( am5xy.XYChart.new(root, { panY: false, layout: root.verticalLayout }) ); // Define data let data = \[\ {\ category: "Research",\ value1: 1000,\ value2: 588\ },\ {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ },\ {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\ \]; // Create Y-axis let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); // Create X-Axis let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(data); // Create series let series1 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value1", categoryXField: "category" }) ); series1.data.setAll(data); let series2 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value2", categoryXField: "category" }) ); series2.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // Add cursor chart.set("cursor", am5xy.XYCursor.new(root, {})); this.root = root; }); } ngOnDestroy() { // Clean up chart when the component is removed this.browserOnly(() => { if (this.root) { this.root.dispose(); } }); } } The chart code goes inside the `ngAfterViewInit` method. Lastly, add `` to your `src/app.component.html` file. Now you can run `npm start` again and you should see a chart. Working example --------------- Lazy loading amCharts --------------------- Pardon the mess. We're still working on this section. Before Angular 12 ----------------- If your app is using Angular version lower than 12, you will need to use script version of amCharts 5. Instead of importing amCharts 5 modules, add them as a ` As well as declare amCharts globals that are created by scripts: declare const am5: any; declare const am5xy: any; declare const am5themes\_Animated: any; --- # Getting started – amCharts 5 Documentation During the course of this tutorial we'll get acquainted with the general concepts behind amCharts 5, terminology used, and other things to get you started. Installation ------------ amCharts 5 comes in two flavors: as a [JavaScript module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (ES6) files or as compiled standalone JavaScript files. Depending on the type of your application, you may need to to grab one or another. ### JavaScript module (ES6) These are available via NPM or GitHub. You can use our official npm package `@amcharts/amcharts5` to install amCharts 5 into your application. It will even pull in all the required dependencies. npm install @amcharts/amcharts5 For those of you using Yarn, you can use its `add` command to install our official npm package: yarn add @amcharts/amcharts5 ### Compiled JavaScript ### CDN All amCharts 5 standalone JavaScript files are available via our free high-availability CDN service. Using CDN will eliminate the need to install the library alotgether. All amCharts libraries and plugins are available as a ready-to-include CDN resources. They are all accessible via `http(s)://cdn.amcharts.com/lib/5/` URL prefix. ### Download You can download also standalone ZIP archives containing everything you need to independently run amCharts 5 on our [Downloads page](https://www.amcharts.com/download/) . Modules ------- All functionality in amCharts 5 is divvied up into small logical chunks - modules - each representing some set of functionality. For example, an "xy" module includes everything needed to build `XYChart`. Modules can be co-dependent on one another. Like for instance, "radar" module (which can be used to build `RadarChart`) requires "xy" module because it reuses some of the functionality from the latter. ### Core module Just like "radar" module depends on "xy", every single module depends on the "core" module, which needs to be included for anything to work in amCharts 5. NOTE "core" module must always be imported first - before any other modules. ### Importing in TypeScript / ES6 apps In an TypeScript or ES6 app, e.g. one created using Angular or React, you would want to import amCharts as a module: import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; You can name and scope imported modules as you need, but for the sake of simplicity as well as consistency across all code snippets we will be importing "core" module as `am5`, while other modules will take in the `am5[module name]` naming syntax. NOTEamCharts 5 needs TypeScript 4.3 or later to compile. If you must use earlier version, please use script version of amCharts 5. ### Loading script files Loading an amCharts 5 module file is done via ` CDN URLs will always load the latest version of the library. Version-specific URLs are also available. Refer to our [Downloads page](https://www.amcharts.com/download/) for more details. Or, you can download, set up and load them from your own web server. E.g.: Creating a chart ---------------- ### Root element The central object of each chart starts with a central object. We call it "the root". The root is super important, as you will need it to create every single object in the chart. Let's create one right now: const root = am5.Root.new("chartdiv"); var root = am5.Root.new("chartdiv"); `Root` is part of our `core` package, so we use `am5.*` namespace to access it. Also notice how we are not creating a `Root` instance using `new [ClassName]` notion, but rather using class' static method `new()`. We will use that for everything in amCharts 5, but more on that later. Final notice about creating a "root" element, is that we need to pass in an `id` of the `
` container we want to put our chart in. The parameter can also accept a reference of the actual element, too. MORE INFOFor more information, refer to "[Root element](https://www.amcharts.com/docs/v5/getting-started/root-element/) " tutorial. ### New element syntax As we've just seen, we do not create instances of amCharts 5 classes using conventional `new [Classname]` option. The following **is wrong** and **should never be used**: // ERROR: the following will result in error const root = new am5.Root("chartdiv"); // ERROR: the following will result in error var root = new am5.Root("chartdiv"); Instead we use class' static method `new()` which will return an instance of the class for us, as well as will take care of other stuff for us. // SUCCESS: this is correct const root = am5.Root.new("chartdiv"); // SUCCESS: this is correct var root = am5.Root.new("chartdiv"); This true not just for `Root` but for every single class in amCharts 5. The difference from root's `new()` syntax when we create other elements is that instead of taking `
` element id, it will take an instance to the the root itself as well as any settings we want to set on the object. We will see how it works further in this tutorial. ### Chart elements Now that we have the root element, we can start putting actual stuff in it: chart instance (or even several instances), labels, containers, legends, anything we want. Root does have a special container element, that we'll push our elements into. Let's go ahead and create a `PieChart`. Before we can do that, we will need to import some more packages. Remember how we have each group of functionality in separate modules? Our "core" package does not include `PieChart` so we will need to import another module "percent". Incidentally, "percent" module itself relies on another module - "percent". In TypeScript / ES6 applications we don't need to import these kind of dependencies, because our compiler will do it for us. So we just need to import "core" and "percent" packages: import \* as am5 from "@amcharts/amcharts5/index"; import \* as am5percent from "@amcharts/amcharts5/percent"; For ` It's a good time now to recall about the namespaces. Remember how we mentioned that we will namespace each import by its module name? So whatever comes from "percent" module (or `percent.js`) will be prefixed with `am5percent`. Now, that we have that out of the way, we can create our chart: const chart = root.container.children.push( am5percent.PieChart.new( root, {} ) ); var chart = root.container.children.push( am5percent.PieChart.new( root, {} ) ); Let's examine the above. We create an instance of `PieChart` using its static method `new()`. Differently than with `Root` element, `new()` method for all other classes take root instance as the first parameter, and an object with key-value pairs to set settings on a newly created object. Also note how we push newly-created `PieChart` object into `root.container.children`. This ensures that the object will actually appear on screen. `push()` method returns the instance that was inserted into root's children, so that we can assign it to a variable for later reuse if we need to. This saves us a line of code, but if we wanted, we could create standalone instances, then push later: const chart = am5percent.PieChart.new(root, {}); root.container.children.push(chart); var chart = am5percent.PieChart.new(root, {}); root.container.children.push(chart); ### Settings As we briefly mentioned earlier in this tutorial, our `new()` method allows passing in a second parameter, which is a collection of settings we want to set on the created element. Whatever settings the object will have will be set on the target object as well. We passed in an empty object when we created `PieChart` because we didn't want to set any settings. Let's continue building our chart and create a `PieSeries`, which will definitely need some settings set. const series = chart.series.push( am5percent.PieSeries.new( root, { valueField: "value", categoryField: "category" } ) ); var series = chart.series.push( am5percent.PieSeries.new( root, { valueField: "value", categoryField: "category" } ) ); Examining the above we notice familiar pattern: * We create an object instance using `new()` static method. * We pass in our root instance as the first parameter. * We pass in settings for the object as the second parameter. Setting settings via `new()` is not the only way to do it. We can do that with object's `set()` (to set single key) or `setAll()` (to set multiple keys in one go) methods as well. The above can be refactored this: const series = chart.series.push( am5percent.PieSeries.new(root, {}) ); series.set("valueField", "value"); series.set("categoryField", "category"); var series = chart.series.push( am5percent.PieSeries.new(root, {}) ); series.set("valueField", "value"); series.set("categoryField", "category"); Or even like this: const series = chart.series.push( am5percent.PieSeries.new(root, {}) ); series.setAll({ valueField: "value", categoryField: "category" }); var series = chart.series.push( am5percent.PieSeries.new(root, {}) ); series.setAll({ valueField: "value", categoryField: "category" }); All three approaches are correct and will produce identical output. MORE INFO For more information on this topic please refer to the "[Settings](https://www.amcharts.com/docs/v5/concepts/settings/) " tutorial. ### Data Data in amCharts 5 is set directly on objects that are its users. In most cases those are series of the chart. For that objects that use data have a special property, called `data`, which in turn is an object that can be used to supply data, modify it, etc. The most common method for setting data is its `setAll()` method: series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFO There's a lot more to data in amCharts 5 than the above. For more information - dynamic data, incremental loads, external data, etc. - refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. Disposing charts ---------------- Every element within chart can be disposed using its `dispose()` method. Please keep in mind, that to completely dispose the whole chart it's not enough to dispose chart element - we need to dispose the root element instead: root.dispose(); root.dispose(); Trying to create a new root element in a `
` container before disposing the old one that is currently residing there, will result in an error. --- # Using amCharts 5 with Nuxt 3 – amCharts 5 Documentation Follow the directions for [installing Nuxt 3](https://v3.nuxtjs.org/getting-started/installation/) . Then create a `components/Chart.vue` file which contains the Vue code from our [Vue tutorial](https://www.amcharts.com/docs/v5/getting-started/integrations/vue/) . Lastly, you can use the Chart component like this: --- # Using amCharts 5 with SvelteKit – amCharts 5 Documentation This tutorial will show you every step you need to use amCharts 5 with SvelteKit. First, create a new SvelteKit project by following the directions in [their docs](https://kit.svelte.dev/docs/creating-a-project) : npm create svelte@latest my-app cd my-app npm install Second, run the command `npm install --save-dev vite-plugin-iso-import @amcharts/amcharts5` to install amCharts. Third, add `vite-plugin-iso-import` into your `vite.config.ts` file: import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; import { isoImport } from 'vite-plugin-iso-import'; export default defineConfig({ plugins: \[sveltekit(), isoImport()\] }); Fourth, create a new `src/lib/Chart.svelte` file which contains your amCharts code:
You must add `?client` at the end of the amCharts imports. Lastly you can import the Chart component and use it: Now you can use `npm run dev` in order to run your project. --- # XY chart – amCharts 5 Documentation XY chart is basically used to represent any linear or scatter data in two dimensions. This tutorial will get you started in creating these charts. To keep it simple, we will touch only basic topics in this tutorial. For a list of advanced topics related to XY chart, check link section at the end of this page. Loading required modules ------------------------ XY charts require two amCharts 5 modules: "index" and "xy". You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Instantiating the chart ----------------------- As with any chart type in amCharts 5, we'll need to start with creation of the `Root` element. In it we will create an instance of `XYChart` class. let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5xy.XYChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var chart = root.container.children.push( am5xy.XYChart.new(root, {}) ); MORE INFO The notion of creating class instances using `.new()` method is described in "[Creating a chart](https://www.amcharts.com/docs/v5/getting-started/#Creating_a_chart) " section in the "Getting started" tutorial. Make sure you check it out. Adding axes ----------- An XY chart requires at least one horizontal (X) and one vertical (Y) axis, although it can support any number of axes. The chart has two properties: `xAxes` and `yAxes` that hold instances of its X and Y axes respectively. To add axes to chart we just push their instances to the respective list: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); The above will create an Y axis of type `ValueAxis`, which is used to indicate numeric value. There are number of different axes types. We will examine those in subsequent sections. ### Axis renderer The axis object itself provides logic functionality. It relies on a helper class to actually render it. That's where "renderer" comes in. To put it differently, axis knows how to treat data, calculate scale, etc. It does not care about how it should be displayed. Renderer, knows how to put the axis on screen. For example, a `ValueAxis` on X would be drawn differently than on Y. That's why we need to specify a renderer, which "specializes" of displaying an axis in specific direction. XY chart uses two types of renderers: `AxisRendererX` and `AxisRendererY`. We used `AxisRendererY` for our previous example, because we were creating an Y axis, and we need to use a proper renderer that knows how to display such axis. NOTE Other chart types that extend XY chart, such as Radar Chart will add additional renderer types, so that same axis types can be displayed in a number of different ways. ### Axis types XY chart supports 4 axis types: | Class | Comment | | | --- | --- | --- | | `CategoryAxis` | For plotting data with string identifiers - categories. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/category-axis/) | | `CategoryDateAxis` | For plotting time-based data without maintaining actual time scale. Grid/labels are displayed only where there is actual data. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/#Category_date_axis) | | `DateAxis` | For plotting time-based data. The axis will maintain natural time scale regardless on how actual data points are spaced out. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) | | `ValueAxis` | For plotting numeric values. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/) | Some axis types require additional configuration besides renderer to work. For example `CategoryAxis` needs `categoryField` which specifies a field in data that holds category names, as well as the actual data, so that it knows which categories to display: let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(\[{\ category: "Research"\ }, {\ category: "Marketing"\ }, {\ category: "Sales"\ }\]; var xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(\[{\ category: "Research"\ }, {\ category: "Marketing"\ }, {\ category: "Sales"\ }\]; Similarly, `DateAxis` needs to know granularity of your data, set via `baseInterval` property: let xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), baseInterval: { timeUnit: "day", count: 1 } }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), baseInterval: { timeUnit: "day", count: 1 } }) ); MORE INFO For information on configuring and using each axis type, please refer to the dedicated "[Axes](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/) " tutorial, or click on an axis class name in the table above. Adding series ------------- XY chart is a "serial" chart, meaning it needs at least one series to display anything. As with anything else in amCharts 5, we create a series object using [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) of its class. There is also a number of properties that need to be set for series, like its X and Y axis, as well as data fields. We will look at those shortly, but here's a very basic example of `ColumnSeries` usage: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); Let's examine the above. ### Assigning series to axis This is pretty much self-explanatory. We use series `xAxis` property to tell which axis object will be series X-axis, and `yAxis` to specify which axis is responsible for its Y plot. Each series can have only one X and one Y axis, whereas an axis can have any number of series attached to it. ### Data fields Since XY chart is a two-dimensional chart, each point in its series requires at least two values to be plotted: X and Y. Data fields are used to specify which fields in data hold both of those values. The name of the data field reflects its axis direction, as well as its type. "value" indicates numeric value, including time. "category" indicates string-based category. The type of data field depends on the type of axis we are using. For example, if we have a `ValueAxis` as a Y-axis, and a `CategoryAxis` as an X-axis, our series will need to define `valueYField` and `categoryXField`. Depending on series type, it may need additional fields. For example `CandlestickSeries` needs four values, so it will need four data fields as well. MORE INFO For more information about data fields refer to "[Data fields](https://www.amcharts.com/docs/v5/concepts/series/#Data_fields) " section in our "Series" tutorial. ### Types of series XY chart currently supports these types of series: | Class | Comment | | | --- | --- | --- | | `CandlestickSeries` | Series that displays candles with open, high, low, and close values. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/candlestick-series/) | | `ColumnSeries` | Displays columns or bars. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/column-series/) | | `LineSeries` | Displays lines or area. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/line-series/) | | `OHLCSeries` | Series that displays sticks with open, high, low, and close values. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/candlestick-series/) | | `SmoothedXLineSeries` | Displays smoothed lines or area with configurable horizontal tension. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/smoothed-series/) | | `SmoothedXYLineSeries` | Displays smoothed lines or area with configurable horizontal and vertical tension. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/smoothed-series/) | | `SmoothedYLineSeries` | Displays smoothed lines or area with configurable vertical tension. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/smoothed-series/) | | `StepLineSeries` | Displays stepped line or area. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/step-line-series/) | Setting data ------------ Data in XY chart is set directly to series. There is no chart-wide data storage. For that, each series has a property named `data`, which in turn is an object that can be used to supply data. The most common method for setting data is its `setAll()` method: series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); If we have more than one series, we will need to set data for each and everyone one of them, even if the data is identical. That's why it makes sense to have repeating data in a separate variable. E.g.: let data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; series1.data.setAll(data); series2.data.setAll(data); var data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; series1.data.setAll(data); series2.data.setAll(data); IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFO There's more ways to set, update, add, or load data. For more information please refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. ### Date-based data A quick note about date-based charts (with a `DateAxis`): they expect data to be passed in as integer numbers - JavaScript timestamps (milliseconds elapsed since the UNIX epoch). If you we have dates in any other format (as strings or `Date` objects), we'll need to set up a data processor to convert our dates to timestamps. MORE INFO For description how it works, please refer to "[Date-based data](https://www.amcharts.com/docs/v5/concepts/data/#Date_based_data) " section in our "Data" tutorial. Additional controls ------------------- ### Legend To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "index" package), push it to chart's children (or any other place we want it to be), as well as set its data (in case of XY chart, we will probably want to use series as legend items). let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); var legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); MORE INFO For more information on how to configure the content for legend on an XY chart, refer to "[Legend and XY series](https://www.amcharts.com/docs/v5/charts/xy-chart/legend-xy-series/) " tutorial. For generic tips on how to configure legend and its items, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. ### Cursor Adding chart cursor, which is a very useful tool, providing crosshairs and other functionality, like series and axis tooltips is pretty straightforward: we just need to create an instance of `XYCursor` (from "xy" module) and set it to chart's `cursor` property: chart.set("cursor", am5xy.XYCursor.new(root, {})); chart.set("cursor", am5xy.XYCursor.new(root, {})); MORE INFO For more information on how to configure the chart cursor make sure you visit "[Cursor](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/) " tutorial. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; // Create root and chart let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5xy.XYChart.new(root, { panY: false, layout: root.verticalLayout }) ); // Define data let data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; // Create Y-axis let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); // Create X-Axis let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(data); // Create series let series1 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value1", categoryXField: "category" }) ); series1.data.setAll(data); let series2 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value2", categoryXField: "category" }) ); series2.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // Add cursor chart.set("cursor", am5xy.XYCursor.new(root, {}));
See the Pen Clustered column chart by amCharts team (@amcharts) on CodePen. Configuring stuff ----------------- ### Configuring axes * [Configuring axes](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/) * [Working with a Date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) * [Working with a Category axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/category-axis/) * [Working with a Value axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/) * [Working with Gapless Date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/gapless-date-axis/) ### Configuring series * [Adding tooltips to series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/#Tooltips) * [Using date-based data](https://www.amcharts.com/docs/v5/concepts/data/#Parsing_dates) * [Loading external data](https://www.amcharts.com/docs/v5/concepts/data/#External_data) * [Smoothed series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/smoothed-series/) ### Other topics * [Configuring zooming and panning](https://www.amcharts.com/docs/v5/charts/xy-chart/zoom-and-pan/) * [Configuring legend](https://www.amcharts.com/docs/v5/concepts/legend/) * [Configuring cursor](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/) * [Using themes](https://www.amcharts.com/docs/v5/concepts/themes/) --- # Charts – amCharts 5 Documentation Use the navigation on the left to select a chart type. Clicking a link will open a sub-menu. --- # Using amCharts 5 with Jest – amCharts 5 Documentation This tutorial will show you how to create unit tests for [Jest](https://jestjs.io/) . Jest does not support ES6 modules by default, but you can still use ES6 modules if you use Babel. Installation ============ You must install the following packages in your `package.json`: "dependencies": { "@amcharts/amcharts5": "^5.2.17" }, "devDependencies": { "@babel/core": "^7.18.10", "@babel/preset-env": "^7.18.10", "@babel/preset-typescript": "^7.18.6", "babel-jest": "^28.1.3", "jest-environment-jsdom": "^28.1.3", "jest": "^28.1.3", "canvas": "^2.9.3" } And you must add this `"jest"` configuration to your `package.json`: "jest": { "testEnvironment": "jsdom", "transformIgnorePatterns": \[\ "/node\_modules/(?!@amcharts|d3-|internmap)"\ \] } Now you must do `npm install` or `yarn install`. Lastly create a `babel.config.js` file: module.exports = { presets: \[\ \['@babel/preset-env', {targets: {node: 'current'}}\],\ '@babel/preset-typescript',\ \], }; Writing tests ============= Now that you have everything setup, you can write your unit tests. Let's say that your chart code is in a `chart.js` file: import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; export function makeChart() { const root = am5.Root.new("chartdiv"); const chart = root.container.children.push(am5xy.XYChart.new(root, { panX: false, panY: false, wheelX: "panX", wheelY: "zoomX" })); // Rest of chart code... return { root, chart }; } You can write your unit tests in a `chart.test.js` file, like this: // Import chart code import { makeChart } from "./chart"; beforeEach(() => { // Create
which is needed by the chart document.body.innerHTML = \`
\`; }); test("chart exists", () => { const { root, chart } = makeChart(); // Test chart expect(root).toBeDefined(); expect(chart).toBeDefined(); expect(chart.get("wheelX")).toBe("panX"); }); Example ------- [Open in StackBlitz](https://stackblitz.com/edit/node-mm8hqa?file=src%2FApp.js) . --- # Using amCharts 5 with Remix – amCharts 5 Documentation This tutorial will show you every step you need to use amCharts 5 with Remix. Create a new project. npx create-remix@latest my-project cd my-project npm install @amcharts/amcharts5 npm install remix-utils Create an `app/components/Chart.client.tsx` file: import { useLayoutEffect } from "react"; import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import am5themes\_Animated from "@amcharts/amcharts5/themes/Animated"; export default function Chart() { useLayoutEffect(() => { let root = am5.Root.new("chartdiv"); root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); let chart = root.container.children.push( am5xy.XYChart.new(root, { panY: false, layout: root.verticalLayout }) ); // Define data let data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; // Create Y-axis let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); // Create X-Axis let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(data); // Create series let series1 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value1", categoryXField: "category" }) ); series1.data.setAll(data); let series2 = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value2", categoryXField: "category" }) ); series2.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // Add cursor chart.set("cursor", am5xy.XYCursor.new(root, {})); return () => { root.dispose(); }; }, \[\]); return (
); } Now you can import and use the `Chart` component in the `app/routes/_index.tsx` file: import type { MetaFunction } from "@remix-run/node"; import { ClientOnly } from "remix-utils/client-only"; import Chart from "../components/Chart.client.tsx"; export const meta: MetaFunction = () => { return \[\ { title: "New Remix App" },\ { name: "description", content: "Welcome to Remix!" },\ \]; }; export default function Index() { return (
{() => }
); } You need to wrap it in `` because amCharts is a browser library, amCharts cannot run on the server. --- # Using amCharts 5 with Ember.js – amCharts 5 Documentation This tutorial will show you every step you need to use amCharts 5 with [Ember.js](https://emberjs.com/) . Installation ------------ ​First, create a new Ember project: npx -p ember-cli@latest ember new my-project --lang en cd my-project ​You can now run your project by using this command: npm start ​If you open up the URL `http://localhost:4200/` you should see a working app. ​Now it's time to add in an amCharts 5 chart. Use this command to install amCharts 5: npm install --save-dev @ember/render-modifiers @amcharts/amcharts5 ​Create a new `app/components/chart.hbs` file:
​Also create a new `app/components/chart.js` file: import Component from "@glimmer/component"; import { action } from "@ember/object"; ​ import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import am5themes\_Animated from "@amcharts/amcharts5/themes/Animated"; ​ export default class ChartComponent extends Component { @action create(element) { const root = am5.Root.new(element); ​ root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); ​ root.dateFormatter.setAll({ dateFields: \["valueX"\] }); ​ const chart = root.container.children.push(am5xy.XYChart.new(root, { panX: false, panY: false, wheelX: "panX", wheelY: "zoomX" })); ​ const cursor = chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "zoomX" })); cursor.lineY.set("visible", false); ​ const xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, { maxDeviation: 0.5, baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { pan:"zoom" }), tooltip: am5.Tooltip.new(root, {}) })); ​ const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, { maxDeviation:1, renderer: am5xy.AxisRendererY.new(root, { pan:"zoom" }) })); ​ const series = chart.series.push(am5xy.LineSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "{valueX}: {valueY}" }) })); ​ chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" })); ​ const data = \[\ {\ "date": 1686034800000,\ "value": 103\ },\ {\ "date": 1686121200000,\ "value": 99\ },\ {\ "date": 1686207600000,\ "value": 97\ },\ {\ "date": 1686294000000,\ "value": 101\ },\ {\ "date": 1686380400000,\ "value": 104\ },\ {\ "date": 1686466800000,\ "value": 106\ },\ {\ "date": 1686553200000,\ "value": 109\ },\ {\ "date": 1686639600000,\ "value": 114\ },\ {\ "date": 1686726000000,\ "value": 117\ },\ {\ "date": 1686812400000,\ "value": 113\ }\ \]; series.data.setAll(data); ​ series.appear(1000); chart.appear(1000, 100); ​ this.series = series; this.root = root; } ​ @action cleanup() { if (this.root) { this.root.dispose(); } } } ​ Lastly, change the `app/templates/application.hbs` file and add the `` component: {{page-title "MyProject"}} ​ ​ {{outlet}} ​Now if you run `npm start` you should see a working chart.​ Updating the chart ================== ​If you want to update the chart when an attribute changes, you can use the `did-update` modifier. For this example, let's update the chart data whenever the `data` attribute changes. ​First, let's change the chart code so that it uses the data from the attributes: series.data.setAll(this.args.data); ​Next, add in a new `@action` to the `ChartComponent` which will update the data: @action updateData() { if (this.series) { this.series.data.setAll(this.args.data); } } ​Lastly, add the `did-update` modifier into your `app/components/chart.hbs` file:​
​Now you can pass in data to the `` component:​ ​If you want to update the chart when multiple different attributes change, you can use the `did-update` modifier multiple times:​
--- # Using amCharts 5 with Vue.js – amCharts 5 Documentation This tutorial contains some guidelines for usage of amCharts in a [Vue.js](https://vuejs.org/) project. Setting up ---------- We will use [Vue CLI](https://cli.vuejs.org/) to scaffold the starter Vue app like this: npx @vue/cli create my-chart-project We will choose the "default" preset (babel, eslint) for the most common scenario. Let’s make sure that everything got created as expected. Switch to our project directory: cd my-chart-project And run the dev server: npm run serve You should see a standard Vue.js starter page when you navigate to `http://localhost:8080`. Now open the HelloWorld component (/src/components/HelloWorld.vue) in your code editor of choice and remove everything inside the root DIV in the template, unnecessary CSS declarations and code. And add CSS to set the size of our main DIV and a REF that we will use later to tell amCharts where to render the chart. Your component should look something like this: Adding charts ------------- Now let’s add amCharts. Install amCharts 5 from `npm`: npm install @amcharts/amcharts5 Import amCharts libraries in the script portion of your component: import \* as am5 from '@amcharts/amcharts5'; import \* as am5xy from '@amcharts/amcharts5/xy'; import am5themes\_Animated from '@amcharts/amcharts5/themes/Animated'; Add the `mounted()` method to your component: export default { name: 'HelloWorld', mounted() { // we will create the chart here } } And implement chart creation code in it so you whole component looks like this: You're all set! Important note -------------- Don't put amCharts objects inside of the component's `data`, it will cause errors. Instead, just use a regular property (like in the above example). For the same reason, you cannot use `[ref](https://v3.vuejs.org/api/refs-api.html#ref) ` with amCharts objects. Instead, you must use `[shallowRef](https://v3.vuejs.org/api/refs-api.html#shallowref) `. You can still use `data` and props, but you will need to use lifecycle hooks in order to update amCharts when they change: export default { data() { return { foo: 5, }; }, props: { bar: Number, }, watch: { foo(newValue, oldValue) { if (this.root) { // Update chart based on foo data ... } } }, updated() { if (this.root) { // Update chart based on props ... } }, ... } --- # Testing amCharts 5 with Cypress – amCharts 5 Documentation This tutorial looks at how we can use a robust [Cypress testing framework](https://www.cypress.io/) for end-to-end testing of amCharts components. Accessing amCharts objects -------------------------- amCharts 5 maintains a global variable `am5` which in turn has a property `registry`. In Cypress we can access it via `cy.window()` call, then use `am5.registry.rootElements` to access actual `Root` elements created on the page. The following code will grab the first Root and its child chart of the page: describe("Check Legend", () => { it("passes", () => { cy.visit("https://my-test-url/"); // Wait for window cy.window().then((win) => { // Grab first chart const root = win.am5.registry.rootElements\[0\]; const chart = root.container.children.getIndex(0); // ... }); }); Throwing errors --------------- We can use standard `throw` syntax to trigger errors of our custom tests. Cypress will fail the test on encountering an exception. describe("Check Legend", () => { it("passes", () => { cy.visit("https://my-test-url/"); // Wait for window cy.window().then((win) => { // Grab first chart const root = win.am5.registry.rootElements\[0\]; const chart = root.container.children.getIndex(0); // Check the type if (chart.className != "XYChart") { throw new Error("Wrong chart type"); } }); }); Testing DOM elements -------------------- amCharts 5 is rendered using Canvas, and thus does not have DOM elements for each of its internal objects. That being said, some of the elements in amCharts 5 are focusable by default, or can be made so by setting `focusable: true`. For example, all buttons and legend items are focusable by default. Focusable elements have actual DOM elements created under main chart container `
` and can be queried using Cypress, or more precisely in a sub-div with a class name of `"am5-focus-container"`. As an example, the following Cypress query will select the first legend item focus element of a chart contained in a div with `"chartdiv"` id. cy.get("#chartdiv .am5-focus-container div\[role=checkbox\]:first") Full code --------- We can combine object and DOM tests. The following Cypress test will: * Go to a demo page on amCharts website. * Select the first available chart. * Focus its first legend item. * Simulate pressing SPACE to toggle related series on. * Verify that the target series is indeed hidden via API. * Then toggle it back on by another simulated SPACE press. describe("Check Legend", () => { it("passes", () => { cy.viewport(1200, 1000); cy.visit("https://www.amcharts.com/demos/100-stacked-column-chart/"); cy.wait(1000); // Wait for window cy.window().then((win) => { // Grab first chart const root = win.am5.registry.rootElements\[0\]; const chart = root.container.children.getIndex(0); const series = chart.series.getIndex(0); // Select first legend item focus cy.get(root.dom).get(".am5-focus-container div\[role=checkbox\]:first").focus(); cy.wait(1000); // Toggle legend item off cy.get("body").type(" "); // Wait and check if series is actually hidden cy.wait(1000).then(() => { if (!series.isHidden()) { throw new Error("Series was not hidden"); } }); // Toggle series back on cy.get("body").type(" "); // Wait and check if series is unhidden cy.wait(1000).then(() => { if (series.isHidden()) { throw new Error("Series was not unhidden"); } }); }) }) }) --- # Axes – amCharts 5 Documentation This tutorial looks into how to get the most of the axes on an XY chart. Adding axes ----------- Creating axes, assigning them to charts and series, as well as the concept of axis renderer is explained in the the "[Adding axes](https://www.amcharts.com/docs/v5/charts/xy-chart/#Adding_axes) " section of the main "XY Chart" article. This tutorial will look into various ways we can configure the axes. Grid ---- ### Grid lines Grid lines are configured using grid template accessible via axis renderer's grid template: `grid.template`. It's a `Template` object, which allows specifying settings, events, and adapters for each new grid line created for the axis. To specify settings we can use template's `set()` method (to set single key) or `setAll()` method (to set a bunch of keys all at once): let yRenderer = yAxis.get("renderer"); yRenderer.grid.template.setAll({ stroke: am5.color(0xFF0000), strokeWidth: 2 }); var yRenderer = yAxis.get("renderer"); yRenderer.grid.template.setAll({ stroke: am5.color(0xFF0000), strokeWidth: 2 }); The above will make Y axis grid lines 2px wide red. Or, if we want to modify grid lines for all axes all at once, we can create a [quick theme](https://www.amcharts.com/docs/v5/concepts/themes/#Quick_custom_theme) : const myTheme = am5.Theme.new(root); myTheme.rule("Grid").setAll({ stroke: am5.color(0xFF0000), strokeWidth: 2 }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("Grid").setAll({ stroke: am5.color(0xFF0000), strokeWidth: 2 }); root.setThemes(\[\ myTheme\ \]); ### Base grid There is no template for base grid line - a grid line that is displayed on a zero value. Should we like to modify it, we'll need to either create a custom theme, or [create a](https://www.amcharts.com/docs/v5/concepts/themes/#Modifying_default_theme) [quick theme](https://www.amcharts.com/docs/v5/concepts/themes/#Quick_custom_theme) [:](https://www.amcharts.com/docs/v5/concepts/themes/#Modifying_default_theme) const myTheme = am5.Theme.new(root); myTheme.rule("Grid", \["base"\]).setAll({ strokeOpacity: 1 }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("Grid", \["base"\]).setAll({ strokeOpacity: 1 }); root.setThemes(\[\ myTheme\ \]); ### Axis line The actual axis line is represented by the axis renderer itself. That means if we need to configure the appearance of it, we need to use renderers visual settings to do it. let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { strokeOpacity: 1, strokeWidth: 2 }) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { strokeOpacity: 1, strokeWidth: 2 }) }) ); ### Grid above series Normally, grid is drawn behind series. If we'd like it to be drawn above, we can simply move chart's `gridContainer` to front: chart.gridContainer.toFront(); chart.gridContainer.toFront(); ### Grid density We can control how densely packed together grid lines (as well as related ticks and labels) are using axis renderer's `minGridDistance` setting. Basically, it means "minimum distance in pixels between any two grid lines". The axis will adjust its scale, number of grid lines, and their position to accommodate this setting. let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { minGridDistance: 20 }) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { minGridDistance: 20 }) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/grid_distance_50.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/grid_distance_50.png) `minGridDistance: 50` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/grid_distance_20.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/grid_distance_20.png) `minGridDistance: 20` ### Minor grid #### Enabling minor grid We can re-enable display of grid lines that were skipped due to the lack of space according to `minGridDistance` setting in an axis renderer. To do that, we can set renderer's `minorGridEnabled: true` setting (since `5.6.0`). var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 100, minorGridEnabled: true }) }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 100, minorGridEnabled: true }) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/minor_grid_on-1024x782.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/minor_grid_on.png) `minorGridEnabled: true` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/minor_grid_off-1024x782.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/minor_grid_off.png) `minorGridEnabled: false` (default) #### Enabling minor grid labels Similarly to minor grid enabling via `minorGridEnabled`, we can enable its labels via `minorLabelsEnabled` setting. NOTEEnabling minor labels will automatically enable minor grid, even if `minorGridEnabled` is not set. var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 100, minorGridEnabled: true, minorLabelsEnabled: true }) }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 100, minorGridEnabled: true, minorLabelsEnabled: true }) }) ); #### Styling minor grid and labels Minor grid is styled using the same settings as the regular grid, which can be applied [via templates or themes](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/#grid-lines) . This means that any setting, applied to regular grid will apply to minor grid, too. The only difference is that minor grid has a slightly `strokeOpacity` set by default. If we want to change the default opacity of the minor grid, or we want to use some other settings that would apply only to minor grid, we can use a custom theme: const myTheme = am5.Theme.new(root); myTheme.rule("Grid", \["minor"\])).setAll({ stroke: am5.color(0xFF0000), strokeWidth: 2, strokeOpacity: 0.05 }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("Grid", \["minor"\])).setAll({ stroke: am5.color(0xFF0000), strokeWidth: 2, strokeOpacity: 0.05 }); root.setThemes(\[\ myTheme\ \]); Similarly, minor grid labels will inherit all the settings for regular labels. The only difference is that minor labels have a different default value of `fontSize` (`0.6em`). Again, overriding their settings, would require a custom theme: const myTheme = am5.Theme.new(root); myTheme.rule("AxisLabel", \["minor"\])).setAll({ fill: am5.color(0xFF0000), fontSize: 10 }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("AxisLabel", \["minor"\])).setAll({ fill: am5.color(0xFF0000), fontSize: 10 }); root.setThemes(\[\ myTheme\ \]); Ticks ----- Like many axis elements, ticks are configurable by accessing their template on the renderer: `ticks.template`. Please note, that ticks are disabled by default, so we will need to set their `visible` setting to `true` in order for them to appear: let yRenderer = yAxis.get("renderer"); yRenderer.ticks.template.setAll({ stroke: am5.color(0xFF0000), visible: true }); var yRenderer = yAxis.get("renderer"); yRenderer.ticks.template.setAll({ stroke: am5.color(0xFF0000), visible: true }); Naturally, we can do that by creating a custom theme as well: const myTheme = am5.Theme.new(root); myTheme.rule("AxisTick").setAll({ stroke: am5.color(0xFF0000), visible: true }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("AxisTick").setAll({ stroke: am5.color(0xFF0000), visible: true }); root.setThemes(\[\ myTheme\ \]); Labels ------ ### Label appearance Labels too have a template in axis renderer: `labels.template`. We can use that to set appearance settings, as well as other stuff like adapters, that modify label content. let yRenderer = yAxis.get("renderer"); yRenderer.labels.template.setAll({ fill: am5.color(0xFF0000), fontSize: "1.5em" }); let yRenderer = yAxis.get("renderer"); yRenderer.labels.template.setAll({ fill: am5.color(0xFF0000), fontSize: "1.5em" }); Or, via custom quick theme, to apply settings to all axes at once: const myTheme = am5.Theme.new(root); myTheme.rule("AxisLabel").setAll({ fill: am5.color(0xFF0000), fontSize: "1.5em" }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("AxisLabel").setAll({ fill: am5.color(0xFF0000), fontSize: "1.5em" }); root.setThemes(\[\ myTheme\ \]); ### Label background Setting `background` on a label template won't work as complex objects are not copied over to template clones. For that we'll need to use template's `setup()` method. For more information, refer to "[Containers: Background](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Templates) " tutorial. ### Label format Some axis types (e.g. value axis or date axis) will apply formatting to their labels. This is described in greater details in their respective tutorials: "[Value axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/) " and "[Date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) ". ### Label rotation In some cases, when there are more labels to fit them nicely, we can rotate them. An axis can accommodate more labels if they are rotated to vertical or diagonal. We can use a `rotation` setting on an axis' label template to set the angle at which to rotate the angle. Please note, that rotation is applied around "center" of an element, which is defined by its `centerX` and `centerY` settings. In case of axis' labels, their `centerY` is set to top (0%). If would leave it like that, the rotated labels would appear off-center, so we need to to reset it to 50%, so that they are rotated against label's vertical center: let xRenderer = xAxis.get("renderer"); xRenderer.labels.template.setAll({ rotation: -90, centerY: am5.p50 }); var xRenderer = xAxis.get("renderer"); xRenderer.labels.template.setAll({ rotation: -90, centerY: am5.p50 }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/axis_label_rotation_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/axis_label_rotation_0.png) `rotation: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/axis_label_rotation_-90.png.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/axis_label_rotation_-90.png.png) `rotation: -90` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/axis_label_rotation_-90_centered.png.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/axis_label_rotation_-90_centered.png.png) `rotation: -90` `centerY: am5.p50` See the Pen Untitled by amCharts team (@amcharts) on CodePen. Here's how the rotation works with out default centering options: [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/2018-06-17_09-39-18.gif)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/2018-06-17_09-39-18.gif) `centerX: am5.p50` (50% - middle) `centerY: am5.p0` (0% - top) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/2018-06-17_09-49-07.gif)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/2018-06-17_09-49-07.gif) `centerX: am5.p0` (0% - left) `centerY: am5.p50` (50% - middle) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/2018-06-17_09-46-01.gif)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/01/2018-06-17_09-46-01.gif) `centerX: am5.p50` (50% - middle) `centerY: am5.p50` (50% - middle) Location of axis elements ------------------------- We can control where axis elements (grid, ticks, labels, bullets) are displayed in relation to the axis cell they represent. An axis cell is a logical increment, e.g. a day on a date axis, or a category on a category axis. ### Basic location Each axis element has a setting `location` which is a relative number from `0` (zero) meaning the start of the cell to `1` (one) denoting end of the cell. So, if we'd like our grid to to be displayed in the middle of the cell, rather than default start position, we would set `location` to `0.5`: let xRenderer = xAxis.get("renderer"); xRenderer.grid.template.setAll({ location: 0.5 }); var xRenderer = xAxis.get("renderer"); xRenderer.grid.template.setAll({ location: 0.5 }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png) `location: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/grid_location_middle.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/grid_location_middle.png) `location: 0.5` ### Multi-location In some cases, in order to prevent chart to become to crammed with grid and labels, the axis will start skipping grid lines, and displaying every second, third, fourth, etc. grid line. This is called multi-location scenario. For such scenarios axis labels and ticks have an additional setting: `multiLocation`. It basically acts as a `location` except it is used only in situations where grid lines are being skipped, so that we can apply different positioning of those elements. let xRenderer = xAxis.get("renderer"); xRenderer.ticks.template.setAll({ location: 0.5, multiLocation: 0, visible: true }); var xRenderer = xAxis.get("renderer"); xRenderer.ticks.template.setAll({ location: 0.5, multiLocation: 0, visible: true }); The above will make axis tick appear in the middle of the cell when all grid lines are visible, but will move it to the start when chart starts skipping grid. ### Location on a weekly Date axis A `DateAxis` with weekly data granularity (`baseInterval` set to `"week"`) is a special case. Due to internal reasons, it still uses days for calculation of cell width, so therefore `location` must be adjusted for that. For example, if we would like to position the label at the center of the week, we would need to label's `location: 3.5` (instead of `0.5`). ### Related label tutorials * [Axis labels on base line](https://www.amcharts.com/docs/v5/tutorials/axis-labels-on-base-line/) * [Show range of dates in a multi-interval DateAxis label](https://www.amcharts.com/docs/v5/tutorials/show-range-of-dates-in-a-multi-interval-dateaxis-label/) Start/end labels and ticks -------------------------- Normally, all axis labels and ticks are shown, even those at the very start and end of the axis. We can set a "no go" zone on either end of the axis using label or ticks template's `minPosition` and `maxPosition` settings. It's a relative numeric value where `0` (zero) means start of the axis, and `1` (end). let yRenderer = yAxis.get("renderer"); yRenderer.ticks.template.setAll({ minPosition: 0.1, maxPosition: 0.9, visible: true }); yRenderer.labels.template.setAll({ minPosition: 0.1, maxPosition: 0.9 }); let yRenderer = yAxis.get("renderer"); yRenderer.ticks.template.setAll({ minPosition: 0.1, maxPosition: 0.9, visible: true }); yRenderer.labels.template.setAll({ minPosition: 0.1, maxPosition: 0.9 }); The above ensures that no label or tick is shown closer than 10% to either ends of the axis. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/min_max_position.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/min_max_position.png) `minPosition` and `maxPosition` set Labels/ticks inside plot area ----------------------------- We can make the axis display its labels and ticks inside plot area instead of outside by setting `inside` to `true` either on respective templates (`labels.template` and/or `ticks.template`): let yRenderer = yAxis.get("renderer"); yRenderer.ticks.template.setAll({ inside: true, visible: true }); yRenderer.labels.template.setAll({ inside: true }); let yRenderer = yAxis.get("renderer"); yRenderer.ticks.template.setAll({ inside: true, visible: true }); yRenderer.labels.template.setAll({ inside: true }); Alternatively, we can set it directly on axis renderer: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { inside: true }) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { inside: true }) }) ); Inversed axes ------------- Normally, the axes start from lower-left corner of the XY chart. Setting axis renderer's `inversed` setting to `true` will flip the scale of the axis, and all associated series accordingly: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { inversed: true }) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { inversed: true }) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png) Regular axis [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_true.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_true.png) Inversed axis Axis position ------------- By default, vertical axes are displayed to the left of the plot area, whereas horizontal ones are displayed below. We can move the axis to the other side of the plot area by setting `opposite` to `true` on in the settings of their renderer: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { opposite: true }) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { opposite: true }) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/xy_axis_inversed_false.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/opposite_axis.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/opposite_axis.png) `opposite: true` Cell start/end locations ------------------------ Axis makes all the width/height of its cells available for series to use. This means that if we have column series with columns set to width at 100%, they will take up the whole width of each cell. We can control this available space using axis renderer's `cellStartLocation` and `cellEndLocation` settings. Both are relative numbers with `0` (zero) indicating start of the actual visible cell, and `1` (one) - the end. let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, { cellStartLocation: 0.2, cellEndLocation: 0.8 }), categoryField: "category" }) ); var xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, { cellStartLocation: 0.2, cellEndLocation: 0.8 }), categoryField: "category" }) ); The above will restrict the space available for actual series to 60% of the actual cell. ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/full_cell_width.png) Full cell width ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/cell_width_reduced.png) Cell start and end restricted Axis start/end locations ------------------------ Normally axis starts at the beginning of its first cell and ends at the end of the last one. We can use axis' `startLocation` and `endLocation` to change it. For example, if we'd like axis to start and end in the middle of the first and last cells, we'd set those settings to `0.5`: let xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), startLocation: 0.5, endLocation: 0.5 }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5xy.AxisRendererX.new(root, {}), startLocation: 0.5, endLocation: 0.5 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/axis_endlocation1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/axis_endlocation1.png) (Default) `startLocation: 0` `endLocation: 1` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/axis_endlocation08.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/axis_endlocation08.png) `startLocation: 0.2` `endLocation: 0.8` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/axis_endlocation05.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/axis_endlocation05.png) `startLocation: 0.5` `endLocation: 0.5` See the Pen Axis start and end locations by amCharts team (@amcharts) on CodePen. Axis bullets ------------ #### Adding axis bullets Along with grid, ticks, and labels an axis can also create bullets. To set that up, we can use axis' `bullet` setting, which accepts function that returns an `[AxisBullet](https://www.amcharts.com/docs/v5/reference/axisbullet/) ` object. The function will be called each time, an axis needs to create a bullet, that is for every grid location. The function will receive 3 parameters: * A reference to root element. * A reference to the axis itself. * Axis data item bullet is being created for. let xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}), bullet: function (root, axis, dataItem) { return am5xy.AxisBullet.new(root, { location: 0.5, sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); } })); var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}), bullet: function (root, axis, dataItem) { return am5xy.AxisBullet.new(root, { location: 0.5, sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); } })); The above will add a red circle for each category in a category axis. We can also use the third parameter - data item - to dynamically modify content, i.e. `sprite` parameter of the bullet: let xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}), bullet: function (root, axis, dataItem) { return am5xy.AxisBullet.new(root, { location: 0.5, sprite: am5.Picture.new(root, { dy: 10, width: 24, height: 24, src: dataItem.dataContext.icon }) }); } })); var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}), bullet: function (root, axis, dataItem) { return am5xy.AxisBullet.new(root, { location: 0.5, sprite: am5.Picture.new(root, { dy: 10, width: 24, height: 24, src: dataItem.dataContext.icon }) }); } })); The above code will add an image to each category using information form actual data. See the Pen amCharts 5: Bullet chart by amCharts team (@amcharts) on CodePen. Axis bullets will be placed directly on the axis. If we would like to move those somewhere else, like for instance on top of plot container, we will need to adjust their `y` setting using an adapter: let xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, { }), bullet: function (root, axis, dataItem) { let bullet = am5.Picture.new(root, { width: 24, height: 24, centerY: am5.p50, centerX: am5.p50, src: dataItem.dataContext.icon }); bullet.adapters.add("y", function(y, target) { return -1 \* chart.plotContainer.getPrivate("height"); }); return am5xy.AxisBullet.new(root, { location: 0.5, sprite: bullet }); } })); var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, { }), bullet: function (root, axis, dataItem) { var bullet = am5.Picture.new(root, { width: 24, height: 24, centerY: am5.p50, centerX: am5.p50, src: dataItem.dataContext.icon }); bullet.adapters.add("y", function(y, target) { return -1 \* chart.plotContainer.getPrivate("height"); }); return am5xy.AxisBullet.new(root, { location: 0.5, sprite: bullet }); } })); See the Pen amCharts 5: Strip count plot by amCharts team (@amcharts) on CodePen. #### Stacked axis bullets It's possible to make axis bullets stack on each other if they fall on the same base interval or category. For that, we need to set `stacked: true` in axis bullet's settings: let xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}), bullet: function (root, axis, dataItem) { return am5xy.AxisBullet.new(root, { stacked: true, sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); } })); var xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}), bullet: function (root, axis, dataItem) { return am5xy.AxisBullet.new(root, { stacked: true, sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); } })); Axis fills ---------- Gaps between each grid line can be made to be filled with a color. Those are called "axis fills" and can be configured using axis renderer's axis fill template: `axisFills.template`. ### Enabling fills Similarly to ticks, fills are disabled by default, so we will need to enable by setting their `visible` to `true`. let yRenderer = yAxis.get("renderer"); yRenderer.axisFills.template.setAll({ fill: am5.color(0xFF0000), fillOpacity: 0.1, visible: true }); var yRenderer = yAxis.get("renderer"); yRenderer.axisFills.template.setAll({ fill: am5.color(0xFF0000), fillOpacity: 0.1, visible: true }); They can be modified/enabled by creating a quick theme, too: const myTheme = am5.Theme.new(root); myTheme.rule("Graphics", \["axis", "fill"\]).setAll({ stroke: am5.color(0xFF0000), fillOpacity: 0.1, visible: true }); root.setThemes(\[\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("Graphics", \["axis", "fill"\]).setAll({ stroke: am5.color(0xFF0000), fillOpacity: 0.1, visible: true }); root.setThemes(\[\ myTheme\ \]); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/normal_zoom.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/normal_zoom.png) Axis fills disabled (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/axis_fills.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/axis_fills.png) Axis fills enabled ### Fill rules By default, axis will enable fills for every second gab between grid lines. We can change that by using axis' `fillRule` setting. It is a function, which dynamically can modify fills `visible` setting (and possible other settings) based on some criteria. The function receives axis data item as well as index, which can help it decide what to do with particular fill. As an example, `fillRule` can be set to a function, that highlights weekends: let xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, fillRule: function(dataItem) { const axisFill = dataItem.get("axisFill"); const date = new Date(dataItem.get("value")); axisFill.setPrivate("visible", (date.getDay() == 6 || date.getDay() == 0)); }, renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 20 }) })); var xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, fillRule: function(dataItem) { var axisFill = dataItem.get("axisFill"); var date = new Date(dataItem.get("value")); axisFill.setPrivate("visible", (date.getDay() == 6 || date.getDay() == 0)); }, renderer: am5xy.AxisRendererX.new(root, { minGridDistance: 20 }) })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/axis_fills_date_axis-1024x313.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/axis_fills_date_axis.png) Custom fill rule on a date axis Stacked axes ------------ ### Turning on stacking If a chart has multiple axes on the same side, they are put into the same container and arranged so they are next to each other. For example all Y-axes are put into chart's `leftAxesContainer` which has a layout of type "horizontal". That's why axes are put next to each other. If we would like to stack axes vertically, all we need to do is to change the `layout` setting of the `leftAxesContainer`: chart.leftAxesContainer.set("layout", root.verticalLayout); chart.leftAxesContainer.set("layout", root.verticalLayout); The axes, including all the grid and related series will now occupy separate parts of the the plot area. For more information about XY chart's containers, refer "[Layout and containers of the XY chart](https://www.amcharts.com/docs/v5/charts/xy-chart/xy-chart-containers/) " tutorial. For more about container layouts, please take a look at "[Containers: Layout](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Layout) ". ### Variable axis heights Stacked axis will divide the available space equally between them. If we need them to be different, we can use axis' `height` setting with percent values, e.g.: let yAxis1 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(70), renderer: am5xy.AxisRendererY.new(root, {}) }) ); let yAxis2 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(30), renderer: am5xy.AxisRendererY.new(root, {}) }) ); var yAxis1 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(70), renderer: am5xy.AxisRendererY.new(root, {}) }) ); var yAxis2 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(30), renderer: am5xy.AxisRendererY.new(root, {}) }) ); ### Gaps between stacked axes There normally is no gap between, two stacked axes. The best way to put such gap between them, is to use [axis headers](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-headers/) with some or no information in them: yAxis1.axisHeader.children.push(am5.Label.new(root, { text: "Value", fontWeight: "500" })); yAxis2.axisHeader.set("paddingTop", 10); yAxis2.axisHeader.children.push(am5.Label.new(root, { text: "Volume", fontWeight: "500" })); yAxis1.axisHeader.children.push(am5.Label.new(root, { text: "Value", fontWeight: "500" })); yAxis2.axisHeader.set("paddingTop", 10); yAxis2.axisHeader.children.push(am5.Label.new(root, { text: "Volume", fontWeight: "500" })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/multiaxes_nonstack.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/multiaxes_nonstack.png) Regular multi-Y-axis setup [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/multiaxes_stacked.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/multiaxes_stacked.png) Stacked Y axes See the Pen Stacked axes by amCharts team (@amcharts) on CodePen. ### Aligning stacked axes Stacked are left-aligned by default. If number scale are different across different axes, that might not look good on a left-side Y axis. The solution is to right-align all axes, by using their `x` and `centerX` settings: let yAxis1 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(70), x: am5.percent(100), centerX: am5.percent(100), renderer: am5xy.AxisRendererY.new(root, {}) }) ); let yAxis2 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(30), x: am5.percent(100), centerX: am5.percent(100), renderer: am5xy.AxisRendererY.new(root, {}) }) ); var yAxis1 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(70), x: am5.percent(100), centerX: am5.percent(100), renderer: am5xy.AxisRendererY.new(root, {}) }) ); var yAxis2 = chart.yAxes.push( am5xy.ValueAxis.new(root, { height: am5.percent(30), x: am5.percent(100), centerX: am5.percent(100), renderer: am5xy.AxisRendererY.new(root, {}) }) ); Right-side axes do not need any modification because they are already left-aligned. ### Horizontally-stacked axes It works the same way for horizontal axes, too. The exception is that we will need to use `bottomAxesContainer` (or `topAxesContainer` if we have our axes on top) and we will need to set its layout to `root.horizontalLayout`. Axis title ---------- Adding an axis title consists of creating a `Label` element, as well as pushing it into axis' `children` list. xAxis.children.push( am5.Label.new(root, { text: "GDP per Capita, USD", x: am5.p50, centerX:am5.p50 }) ); yAxis.children.unshift( am5.Label.new(root, { rotation: -90, text: "Life expectancy, years", y: am5.p50, centerX: am5.p50 }) ); xAxis.children.push( am5.Label.new(root, { text: "GDP per Capita, USD", x: am5.p50, centerX:am5.p50 }) ); yAxis.children.unshift( am5.Label.new(root, { rotation: -90, text: "Life expectancy, years", y: am5.p50, centerX: am5.p50 }) ); A few comments about the code above. Notice how we do `push()` on an X axis, but `unshift()` on Y axis. There are other elements in the axis (lines, labels, etc.), and we need our title to be the last on bottom axis (hence `push()`) and for the left axis, we need it to be the first child, so it's left-most of the other elements (hence `unshift()`). We also need to apply rotation of the label for the vertical axis, as well as properly position it using relative values for `x` or `y` and `centerX`. See the Pen XY scatter chart with heat rules on bullets by amCharts team (@amcharts) on CodePen. Axis tooltips ------------- Axis can display tooltips indicating position of a chart cursor if its available. For more information visit "[Cursor: Axis tooltips](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/#axis-tooltips) " tutorial. If you would like to add labels to axis labels, check out "[Labels: Interactive axis labels](https://www.amcharts.com/docs/v5/concepts/common-elements/labels/#interactive-axis-labels) ". Zoomable axes ------------- We can also enable drag-zooming of axes by adding `pan: "zoom"` to settings of their renderer: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { pan: "zoom" }) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, { pan: "zoom" }) }) ); See the Pen Zoomable value axes by amCharts team (@amcharts) on CodePen. Removing axes ------------- ### Effect to related series To remove an axis from a chart, we need to remove its instance from `chart.xAxes` (or `chart.yAxes`) list. It's important to know, that there might still be series that are using the axis we're about to remove. Since series cannot function without X and Y axis, just removing the axis might result in an error. So, before removing an axis, we need to do one of these things: * Assign related series a different axis, or... * Remove those series as well. The following function will take care of the latter: function removeAxis(axis) { am5.array.each(axis.series, function(series) { chart.series.removeValue(series); }); chart.yAxes.removeValue(axis); } function removeAxis(axis) { am5.array.each(axis.series, function(series) { chart.series.removeValue(series); }); chart.yAxes.removeValue(axis); } See the Pen Removing axes by amCharts team (@amcharts) on CodePen. ### Auto-disposing `chart.xAxes` and `chart.yAxes` are auto-disposable lists, meaning that removing an item (an axis in this case) from it, will automatically dispose that item. If we want to remove the axis only temporarily, and do not want it to be disposed, we need to disable auto-disposing: chart.yAxes.autoDispose = false; chart.yAxes.autoDispose = false; Related tutorials ----------------- * [Position X-axis on zero-value](https://www.amcharts.com/docs/v5/tutorials/position-x-axis-on-zero-value/) * [Simulating axis gaps](https://www.amcharts.com/docs/v5/tutorials/simulating-axis-gaps/) * [Syncing axis zooms across multiple charts](https://www.amcharts.com/docs/v5/tutorials/syncing-axis-zooms-across-multiple-charts/) * [Handling long category axis labels](https://www.amcharts.com/docs/v5/tutorials/handling-long-category-axis-labels/) --- # XY chart series – amCharts 5 Documentation This tutorial looks at general concepts behind series - a centerpiece of an XY chart. Adding series ------------- let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); For more info, refer to "[Adding series](https://www.amcharts.com/docs/v5/charts/xy-chart/#Adding_series) " section of the main "XY Chart" tutorial. Setting data ------------ series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); For more info, refer to "[Setting data](https://www.amcharts.com/docs/v5/getting-started/xy-chart/#Setting_data) " section of the main "XY Chart" tutorial. IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. Data fields ----------- Data fields specify how series relates to data and how it uses that data to plot itself. There are two types of data fields: input data fields and display data fields. ### Data input fields XY chart is a two-dimensional chart, so its series will require at least two values in order to be plotted: one for X and one for Y. Series data field settings will specify which key in data holds values for each data field. The actual name of the data field depends on the type of data we are plotting. For example, a series that is plotted on a category axis (X) and a value axis (Y) will need to define at least two data fields: `categoryXField` and `valueYField`. let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "budget", categoryXField: "department" }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "budget", categoryXField: "department" }) ); Date axis operates in tiemstamps, that are numeric values, that's why we need to use `value*Field` for it, just like for value axis: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "budget", valueXField: "date" }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "budget", valueXField: "date" }) ); Some series types, like candlestick or OHLC, need more than two values. They will need more data fields defined. For more info refer to "[Candlestick and OHLC series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/candlestick-series/) " tutorial. IMPORTANTIn order to work properly data fields need to be set when series object is created (via its `.new()` method). Setting them later on will not work as expected. ### Open data input fields Besides `valueXField` and `valueYField` data fields, series can also have "open" data fields, named `openValueXField` and `openValueYField`. If set, series will not use axis base value (zero) as a start for each data item, but rather the actual "open" value. For example, for line series that will mean the fill will extend to that value, rather than axis. For column series, it will mean that actual columns will start at some value, rather than axis. For more information and examples, check "[Line series: Open data fields](https://www.amcharts.com/docs/v5/charts/xy-chart/series/line-series/#Open_data_fields) " and "[Column series: floating columns](https://www.amcharts.com/docs/v5/charts/xy-chart/series/column-series/#Floating_columns) " sections. ### Display fields If we need our series to be plotted using raw input values, we're all set. However, if we need to plot it using some sort of other derived value, like change, percent, or similar derived/calculated value, we will need to set display fields as well. Basically, display field tells series to "use this calculated value instead of input value when plotting yourself". Display fields are named similarly as input fields, except they end with an `"*Show"`, indicating that this is a value for a show. The value that needs to be used for display fields is a pre-set list of available calculated values: | Value | Comment | | --- | --- | | `valueXChange`
`valueYChange` | Change from the first value in a data set. | | `valueXChangePercent`
`valueYChangePercent` | Change from the first value in data set in percent. | | `valueXChangeSelection`
`valueYChangeSelection` | Change from the first value in current visible scope. | | `valueXChangeSelectionPercent`
`valueYChangeSelectionPercent` | Change from the first value in current visible scope in percent. | | `valueXChangePrevious`
`valueYChangePrevious` | Change from the previous value. | | `valueXChangePreviousPercent`
`valueYChangePreviousPercent` | Change from the previous value in percent. | | `valueXTotal`
`valueYTotal` | Sum of all absolute values (cast to positive) from all series on the same value axis in same category/interval. | | `valueXTotalPercent`
`valueYTotalPercent` | Percent value of the value from the sum of all absolute values (cast to positive) from all series on the same value axis in same category/interval. | | `valueXSum`
`valueYSum` | Sum of all previous values from the same series on the same value axis. | Let's say we need to display a 100% stacked chart with 3 column series. We would need to use `valueYTotalPercent` for `valueYShow` to make it work: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueYShow: "valueYTotalPercent", categoryXField: "year", stacked: true }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueYShow: "valueYTotalPercent", categoryXField: "year", stacked: true }) ); ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/stacked_regular_values.png) Stack using regular data fields ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/stacked_total_percent.png) `valueYShow: "valueYTotalPercent"` See the Pen Stacked column chart 100% by amCharts team (@amcharts) on CodePen. ### Changing data fields All data fields that need to be used by series need to absolutely be set when series is created using `.new()` method. Setting data fields later via `set()` or `setAll()` methods will not work. let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value" }) ); // ERROR: This will not work as expected! series.set("categoryXField", "year"); series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value" }) ); // ERROR: This will not work as expected! series.set("categoryXField", "year"); Changing of the data field is only possible if it was first set when creating the series: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category" }) ); // This will now work! series.set("categoryXField", "year"); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category" }) ); // This will now work! series.set("categoryXField", "year"); Please note that changing data fields dynamically will not automatically reparse data. This means that data always needs to be set after all data fields are set or changed: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category" }) ); // This will now work! series.set("categoryXField", "year"); // Data needs to be set after data fields are set series.data.setAll(\[ ... \]); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category" }) ); // This will now work! series.set("categoryXField", "year"); // Data needs to be set after data fields are set series.data.setAll(\[ ... \]); Series colors ------------- A color for series plays an important role in its identification. It is used in a number of places, like drawing actual plots (lines, columns, etc.) as well as identifying series in chart's legend. ### Auto-assigned colors If we do not specify any color settings (`fill` and `stroke`) when creating series, an XY chart will assign those automatically, from its own [color set](https://www.amcharts.com/docs/v5/reference/xychart/#colors_setting) . Should we want to, we can override the whole list of colors by either setting it directly on series color set, creating a [quick theme](https://www.amcharts.com/docs/v5/concepts/themes/#Quick_custom_theme) , or a [reusable full theme](https://www.amcharts.com/docs/v5/concepts/themes/creating-themes/) , e.g.: chart.get("colors").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); chart.get("colors").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); MORE INFO A "[Color sets](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/#Setting_own_list_of_colors) " section of our color tutorial has more details and code samples. ### Manual colors We can set colors to newly-created series manually, too. For that we will need to set series' `fill` and `stroke` settings: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", fill: am5.color(0x095256), stroke: am5.color(0x095256) }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", fill: am5.color(0x095256), stroke: am5.color(0x095256) }) ); Configuring appearance ---------------------- Each series consists of certain visual elements, depending on its type. For example, line series will consist of line segments we can set stroke settings on. Column series will have columns, and we can control how they are filled, etc. To set those up, series have properties holding template object we can modify settings for, that will be applied to the actual elements when series is plotted. As an example, let's take column series. It has a property `columns.template` which is a `Template` accepting settings for a `RoundedRectangle` objects. If we need to make columns rounded on top, all we need to do is to modify the template: series.columns.template.setAll({ cornerRadiusTL: 5, cornerRadiusTR: 5 }); series.columns.template.setAll({ cornerRadiusTL: 5, cornerRadiusTR: 5 }); Please refer to dedicated series type tutorials for further info: * [Line and area series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/line-series/) * [Column series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/column-series/) * [Step line series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/step-line-series/) * [Candlestick and OHLC series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/candlestick-series/) * [Smoothed series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/smoothed-series/) Binding settings to data ------------------------ It's possible to bind settings of a series element templates to values in data. For more information on how to do it, refer to "[Template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) " tutorial. Stacked series -------------- ### Data requirements IMPORTANTStacking requires that all stacked series have equal number of data items with the same timestamps / categories. Mismatched datasets will have visually odd results when series are plotted. For a workaround, please visit tutorial "[Stacking series with mismatched categories/dates](https://www.amcharts.com/docs/v5/tutorials/stacking-series-with-mismatched-categories-dates/) ". ### Enabling stacking To make series stack to each other, it's enough to set their `stacked` setting to `true`. The chart will automatically arrange everything else accordingly. let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: field, categoryXField: "year", stacked: true }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: field, categoryXField: "year", stacked: true }) ); ### Negative value stacking In situations where there are both negative and positive values in stacks, we might also consider another setting: `stackToNegative`. If it's set to `true` (default for column series) columns with positive values will stack from zero line upwards, whereas columns with negative value will start their stacking from zero line downwards. IMPORTANTThere is no way to make series stack correctly if it contains both positive and negative values in its data, regardless of the value set on `stackToNegative` setting. ### 100% stacks Enabling 100% stacks require few manipulation to chart setup: * Specifying [display data fields](https://www.amcharts.com/docs/v5/getting-started/xy-chart/series/#Display_fields) for series to use calculated percent values instead of absolute values. * Setting `calculateTotals: true` on a value axis so that percent values are calculated and available for use in display data fields. * Capping value axis scale at `0` and `100` values. * Optionally, adding "%" sign to axis values using adapter or value axis' `[numberFormat](https://www.amcharts.com/docs/v5/reference/valueaxis/#numberFormat_setting) ` setting. let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { min: 0, max: 100, calculateTotals: true, numberFormat: "#'%'", renderer: am5xy.AxisRendererY.new(root, {}) }) ); let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueYShow: "valueYTotalPercent", categoryXField: "year", stacked: true }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { min: 0, max: 100, calculateTotals: true, numberFormat: "#'%'", renderer: am5xy.AxisRendererY.new(root, {}) }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueYShow: "valueYTotalPercent", categoryXField: "year", stacked: true }) ); See the Pen Stacked column chart 100% by amCharts team (@amcharts) on CodePen. ### Stack totals Refer to "[Totals on column stacks](https://www.amcharts.com/docs/v5/tutorials/totals-on-column-stacks/) " tutorial for information on how to display labels with totals over the stacks. Relation to axes ---------------- ### Assigning to axes Each series needs to know its X and Y axes. Settings `xAxis` and `yAxis` must be set to instances of the axes. As per data fields section above, assigning certain types of axis, will dictate what names data fields will have to use when setting up the series. ### Base axis A base axis is an axis which indicates linear progress of the series, e.g. a date axis or category axis. If series uses fills, the fill will be towards that axis. Columns will also will be drawn perpendicularly to base axis. If base axis is not set, it is assigned automatically per the following logic: * If Y axis is either category axis or date axis, it will become base axis. * All other setups will use X axis as a base axis. To explicitly set a base axis for a series, us its `baseAxis` setting: var series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, baseAxis: xAxis, openValueYField: "start", valueYField:"end", categoryXField: "category" })); var series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, baseAxis: xAxis, openValueYField: "start", valueYField:"end", categoryXField: "category" })); Bullets ------- NOTE Bullets are not exclusive to XY chart. We are going to touch the topic briefly here, but for more information make sure to visit our dedicated "[Bullets](https://www.amcharts.com/docs/v5/concepts/common-elements/bullets/) " tutorial. ### Adding bullets Bullets in series are added by pushing custom functions into series' `bullets` list. The functions must return a new `Bullet` object with its `sprite` property pre-populated with actual visual elements. Those can be literally any visual element: from a simple `Circle` or `Label` to a whole other chart. series.bullets.push(function() { return new am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 4, fill: series.get("fill") }) }); }); series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 4, fill: series.get("fill") }) }); }); See the Pen Smoothed line series by amCharts team (@amcharts) on CodePen. ### Relation to data Among other things, series will also pass relevant data item to the bullet. That's why bullets can use [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) to populate text, as well as heat rules. ### Positioning bullets A `Bullet` object has two properties that help position them within the parent element/data item: `[locationX](https://www.amcharts.com/docs/v5/reference/bullet/#locationX_setting) ` and `[locationY](https://www.amcharts.com/docs/v5/reference/bullet/#locationY_setting) `. Those accept numeric values from `0` (zero) to `1` (one) indicating relative position within target element, with zero indicating beginning and one the end. Some series (e.g. line series) do not have any dimension, so location settings will be ignored. However in those series that do have elements with actual shapes (e.g. column series), location settings are super useful as it gives us flexibility over positioning of a bullet. Let's put a `Label` bullet in the middle of a column in a column series: series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueY}", centerX: am5.percent(50), centerY: am5.percent(50), populateText: true }) }); }); series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueY}", centerX: am5.percent(50), centerY: am5.percent(50), populateText: true }) }); }); NOTE Please note the `populateText` use above. This is needed to force `Label` to populate data placeholders with actual data. See the Pen Line series with bullets by amCharts team (@amcharts) on CodePen. ### Auto-hiding bullets We can set up series to automatically hide its bullets if there are a lot of data points and bullets would just overcrowd the chart. For that purpose, XY chart series has a setting `minBulletDistance`. It's a numeric value which means this: if the distance between data items in series is less than X pixels, hide all bullets. This setting is dynamic, and will react to changing conditions. I.e. when chart is zoomed in and distances between data items increase, hidden bullets may reappear. Tooltips -------- ### Series-wide tooltips If our chart setup has a cursor, we can assign a `Tooltip` object to series' `tooltip` setting, so that tooltip relevant to closest data item will be shown when cursor is hovering over the plot area. let series = chart.series.push( am5xy.LineSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }) }) ); series.data.setAll(data); var series = chart.series.push( am5xy.LineSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }) }) ); series.data.setAll(data); See the Pen Chart with cursor by amCharts team (@amcharts) on CodePen. ### Tooltips on series elements We can also make tooltips appear when hovered on individual series elements directly, e.g. on a column. To make that happen, all we need to do is to set `tooltipText` on that elements template: series.columns.template.set("tooltipText", "{valueY}"); series.columns.template.set("tooltipText", "{valueY}"); Animation --------- Normally, created series will appear on chart right away. Should we want to make it play out initial animation, we can call it's `appear()` method right after creating its object: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); series.appear(); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); series.appear(); Pre-hiding series ----------------- The correct way to pre-hide series is to set its `visible` setting to `false`. let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", visible: false }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", visible: false }) ); NOTECalling series `appear()` method will knock off `visible` setting value, and will make it visible again. To keep series pre-hidden, do not call this method. If you are also using a legend, for best results use series `hide()` method instead, called after the legend data is set. let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); legend.data.push(series); series.hide(); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); legend.data.push(series); series.hide(); See the Pen amCharts 5: Pre-hiding series by amCharts team (@amcharts) on CodePen. Data item location ------------------ Some series (e.g. line series) have control over where their data item can be placed when plotting them. We do have series settings `locationX` and `locationY` for that. The concept is explained in detail in "[Line series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/line-series/#Data_item_location) " tutorial. Related tutorials and demos --------------------------- * [Adding XY series dynamically](https://www.amcharts.com/docs/v5/tutorials/adding-xy-series-dynamically/) --- # Zoom and pan – amCharts 5 Documentation An XY chart can be zoomed and panned in a number of ways. This tutorial takes a closer look at all of them. Panning ------- An XY chart has two settings that can be used to enable panning: `[panX](https://www.amcharts.com/docs/v5/reference/xychart/#panX_setting) ` and `[panY](https://www.amcharts.com/docs/v5/reference/xychart/#panY_setting) `. They're both are boolean values, with `true` meaning that chart can be panned by dragging it horizontally (`panX`) and/or vertically (`panY`). let chart = root.container.children.push( am5xy.XYChart.new(root, { panX: true, panY: false }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { panX: true, panY: false }) ); The above will enable horizontal panning, but will disable vertical one. Mouse-wheel behavior -------------------- ### Setting behavior Chart can also be configured to react in a number of ways to a mouse wheel. It has two settings for that: `[wheelX](https://www.amcharts.com/docs/v5/reference/xychart/#wheelX_setting) ` and `[wheelY](https://www.amcharts.com/docs/v5/reference/xychart/#wheelY_setting) `. `wheelX` is responsible for specifying what needs to happen when mouse wheel is rotated horizontally, whereas `wheelY` will set action for vertical wheel rotations. Both settings can have a number of values: | Value | Comment | | --- | --- | | `"zoomX"` | Zoom chart horizontally. | | `"zoomY"` | Zoom chart vertically. | | `"zoomXY"` | Zoom chart both horizontally and vertically. | | `"panX"` | Pan chart horizontally. | | `"panY"` | Pan chart vertically. | | `"panXY"` | Pan chart both horizontally and vertically. | | `"none"` (default) | Do nothing. | The following code will set up the chart to be panned on drag, but will zoom horizontally when mouse wheel is used: let chart = root.container.children.push( am5xy.XYChart.new(root, { panX: true, panY: false, wheelX: "zoomX" }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { panX: true, panY: false, wheelX: "zoomX" }) ); ### Wheel zoom center When zooming or panning using mouse-wheel, the action will center around actual position of the mouse cursor. We can hardcode the position using chart's `wheelZoomPositionX` setting (or `wheelZoomPositionY` for vertical whee-zooming). It accepts numeric value from `0` (zero) to `1` (one), which indicates relative position within plot area. E.g. the below will make chart zoom using right side of the plot area as a center: let chart = root.container.children.push( am5xy.XYChart.new(root, { panX: true, panY: false, wheelX: "zoomX", wheelZoomPositionX: 1 }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { panX: true, panY: false, wheelX: "zoomX", wheelZoomPositionX: 1 }) ); ### Control+scroll Enabling mouse-wheel behavior will make the chart zoom/pan but may disrupt scrolling of the whole page when mouse cursor is over the chart. The common practice is to enable zoom/pan only when CTRL key is pressed. To implement that we can disable all wheel behavior by default, and only enable it when CTRL key is down: chart.plotContainer.events.on("wheel", function(ev) { if (ev.originalEvent.ctrlKey) { ev.originalEvent.preventDefault(); chart.set("wheelX", "panX"); chart.set("wheelY", "zoomX"); } else { chart.set("wheelX", "none"); chart.set("wheelY", "none"); } }); chart.plotContainer.events.on("wheel", function(ev) { if (ev.originalEvent.ctrlKey) { ev.originalEvent.preventDefault(); chart.set("wheelX", "panX"); chart.set("wheelY", "zoomX"); } else { chart.set("wheelX", "none"); chart.set("wheelY", "none"); } }); See the Pen amCharts: Zooming with CTRL key and mouse wheel by amCharts team (@amcharts) on CodePen. We can enhance this behavior with Google-like message over the chart when scroll is used without CTRL key pressed. // Create curtain + message to show when wheel is used over chart without CTRL let overlay = root.container.children.push(am5.Container.new(root, { width: am5.p100, height: am5.p100, layer: 100, visible: false })); let curtain = overlay.children.push(am5.Rectangle.new(root, { width: am5.p100, height: am5.p100, fill: am5.color(0x000000), fillOpacity: 0.3 })); let message = overlay.children.push(am5.Label.new(root, { text: "Use CTRL + Scroll to zoom", fontSize: 30, x: am5.p50, y: am5.p50, centerX: am5.p50, centerY: am5.p50 })); chart.plotContainer.events.on("wheel", function(ev) { // Show overlay when wheel is used over chart if (ev.originalEvent.ctrlKey) { ev.originalEvent.preventDefault(); chart.set("wheelX", "panX"); chart.set("wheelY", "zoomX"); } else { chart.set("wheelX", "none"); chart.set("wheelY", "none"); overlay.show(); overlay.setTimeout(function() { overlay.hide() }, 800); } }); // Create curtain + message to show when wheel is used over chart without CTRL var overlay = root.container.children.push(am5.Container.new(root, { width: am5.p100, height: am5.p100, layer: 100, visible: false })); var curtain = overlay.children.push(am5.Rectangle.new(root, { width: am5.p100, height: am5.p100, fill: am5.color(0x000000), fillOpacity: 0.3 })); var message = overlay.children.push(am5.Label.new(root, { text: "Use CTRL + Scroll to zoom", fontSize: 30, x: am5.p50, y: am5.p50, centerX: am5.p50, centerY: am5.p50 })); chart.plotContainer.events.on("wheel", function(ev) { // Show overlay when wheel is used over chart if (ev.originalEvent.ctrlKey) { ev.originalEvent.preventDefault(); chart.set("wheelX", "panX"); chart.set("wheelY", "zoomX"); } else { chart.set("wheelX", "none"); chart.set("wheelY", "none"); overlay.show(); overlay.setTimeout(function() { overlay.hide() }, 800); } }); See the Pen amCharts: Zooming with CTRL key and mouse wheel by amCharts team (@amcharts) on CodePen. Zooming with cursor ------------------- If an XY chart has a [cursor](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/) attached to it, its `behavior` can be set to `"zoomX"`, `"zoomY"`, or `"zoomXY"` to zoom the chart. chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "zoomX" })); chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "zoomX" })); NOTE Enabling cursor zooming will override the chart's own `panX` and `panY` settings. Zooming with scrollbars ----------------------- The chart can also be zoomed using horizontal and vertical scrollbars. Adding scrollbars to chart will automatically enable such zooming: chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" })); chart.set("scrollbarY", am5.Scrollbar.new(root, { orientation: "vertical" })); chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" })); chart.set("scrollbarY", am5.Scrollbar.new(root, { orientation: "vertical" })); MORE INFO For more information about chart scrollbars visit "[Scrollbars](https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/) " tutorial. Zooming by panning axis ----------------------- It's also possible to enable axis zooming by panning it. If enabled, user would be able to grab and drag by the axis label area to zoom it in and out. Use axis renderer's `[pan](https://www.amcharts.com/docs/v5/reference/axisrenderer/#pan_setting) ` setting: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { maxDeviation: 1, renderer: am5xy.AxisRendererY.new(root, { pan: "zoom" }) }) ); let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { maxDeviation: 1, renderer: am5xy.AxisRendererY.new(root, { pan: "zoom" }) }) ); See the Pen amCharts 5: Zooming by axis pan by amCharts team (@amcharts) on CodePen. NOTEThis setting will work only with `AxisRendererX` and `AxisRendererY`. For best results use `maxDeviation: 1` on your axis settings. Pinch zoom ---------- To enable pinch zooming of an XY chart we can use its `pinchZoomX` and `pinchZoomY` settings. Both accept Boolean values and are set to `false` by default. Setting `pinchZoomX` to `true` would enable horizontal zooming of the chart by "pinch" gesture on touch devices. Similarly, `pinchZoomY` can be enabled for vertical pinch-zooming. let chart = root.container.children.push( am5xy.XYChart.new(root, { pinchZoomX: true }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { pinchZoomX: true }) ); Over-zooming ------------ To allow for a "bird's eye" view, a chart can zoom/pan a bit outside of the range of the actual values / axis scale. That is controlled by axis setting `[maxDeviation](https://www.amcharts.com/docs/v5/reference/axis/#maxDeviation_setting) `. With default at `0.1`, it is a numeric value indicating relative distance from the whole width of the axis it can go "outside" actual data range. For example, `0.2` will mean that we can "over-zoom" axis 20% outside its actual range. This setting is set for each axis individually: let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { maxDeviation: 0.2, categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}) }), ); var xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { maxDeviation: 0.2, categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}) }) ); ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/normal_zoom.png) Normal zoom ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/overzoomed.png) Overzoomed by 20% Excluding axes from pan or zoom ------------------------------- We can also prevent any axis from horizontal and/or vertical zooming and/or panning using their `zoomX`/`zoomY` and `panX`/`panY` settings. These settings accept boolean values, e.g.: let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { zoomY: false, renderer: am5xy.AxisRendererY.new(root, {}) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { zoomY: false, renderer: am5xy.AxisRendererY.new(root, {}) }) ); The following will prevent this particular Y axis to be zoomed vertically. Limiting zoom scope ------------------- We can prevent the chart from either zooming in to deep, or zooming out too wide. For those axes have two settings: `[minZoomCount](https://www.amcharts.com/docs/v5/reference/axis/#minZoomCount_setting) ` and `[maxZoomCount](https://www.amcharts.com/docs/v5/reference/axis/#maxZoomCount_setting) `. The "count" notion differs between axis types. In data axis, it would mean number of base intervals, such as day for example. In category axis, it would mean a single category. If `minZoomCount` is set, the chart will not allow zooming in the chart deeper beyond number of intervals or categories. Similarly, if `maxZoomCount` is set, the chart will automatically zoom in to show only this number of intervals or categories, and will not allow zooming out further. let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { minZoomCount: 3, maxZoomCount: 10, categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}) }) ); var xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { minZoomCount: 3, maxZoomCount: 10, categoryField: "category", renderer: am5xy.AxisRendererX.new(root, {}) }) ); The above will prevent X category axis to display less than 3 or more than 10 categories at a time. Pre-zooming axes ---------------- ### Relative pre-zoom To relatively pre-zoom axis on chart init, we can use axis' settings `start` and `end`. Those are numeric values, relative to the whole range of the axis, with `0` (zero) indicating beginning, and `1` (one) the end. let xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { start: 0.9, renderer: am5xy.AxisRendererX.new(root, {}) }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { start: 0.9, renderer: am5xy.AxisRendererX.new(root, {}) }) ); The above will pre-zoom our date axis to the last 10% percent of its scope. NOTE If your chart has a [scrollbar](https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/) with the same orientation as the axis being pre-zoomed, you will need to set the same `start` and `end` values in scrollbar's settings, too. ### Specific range Each axis has its own methods for zooming to a range, suitable for units it uses. Those methods can be executed when axis scale is ready, i.e. when its `datavalidated` event some series kicks. Since most of the axes get their range based on actual data, which is set on series, hence we need to use series event for zooming axis. series.events.on("datavalidated", function(ev) { // Zoom the axis // ... }); series.events.on("datavalidated", function(ev) { // Zoom the axis // ... }); For more information on zooming axes, refer to their respective tutorials: * [Zooming a value axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/#Zooming) * [Zooming a date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/#Zooming) * [Zooming a category date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/category-date-axis/#Zooming) * [Zooming a category axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/category-axis/#Zooming) See the Pen Data grouping by amCharts team (@amcharts) on CodePen. Zoom-out button --------------- A zoom-out button appears automatically whenever chart is not ideally fully zoomed out, or is over-zoomed. An instance of the button which is of class `[Button](https://www.amcharts.com/docs/v5/reference/button/) ` is accessible directly via chart's `[zoomOutButton](https://www.amcharts.com/docs/v5/reference/xychart/#zoomOutButton_property) ` property. We can configure appearance using `Button` settings, or disable it by setting its `visible` to `false`: chart.zoomOutButton.set("forceHidden", true); chart.zoomOutButton.set("forceHidden", true); Related tutorials ----------------- * [Bubble chart with zoom in and out buttons](https://www.amcharts.com/docs/v5/tutorials/bubble-chart-with-zoom-in-and-out-buttons/) * [Position the zoom-out button to bottom-right](https://www.amcharts.com/docs/v5/tutorials/position-the-zoom-out-button-to-bottom-right/) * [Custom period selector on XYChart](https://www.amcharts.com/docs/v5/tutorials/custom-period-selector-on-xychart/) --- # Pie chart – amCharts 5 Documentation This tutorial will walk through most common aspects of creating pie and donut charts. Loading required modules ------------------------ Everything required to create pie charts are two amCharts 5 modules: "index" and "percent". You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5percent from "@amcharts/amcharts5/percent"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Instantiating the chart ----------------------- As with any chart type in amCharts 5, we'll need to start with creation of the `Root` element. In it we will create an instance of `PieChart` class to create a pie chart let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5percent.PieChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var chart = root.container.children.push( am5percent.PieChart.new(root, {}) ); MORE INFO The notion of creating class instances using `.new()` method is described in "[Creating a chart](https://www.amcharts.com/docs/v5/getting-started/#Creating_a_chart) " section in the "Getting started" tutorial. Make sure you check it out. Series ------ ### Adding Pie chart supports one series type: `PieSeries`. Like everywhere else, we use its `new()` method to instantiate series, then push it into `series` list of the chart: let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); var series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); ### Data fields Pie chart series require two to dimensions of data: a string-based category and a numeric value. Data fields basically mean which keys in data objects to look for specific value. They can be set via series' settings `categoryField` and `valueField`. Let's take sample data: \[{\ country: "France",\ sales: 100000\ }, {\ country: "Spain",\ sales: 160000\ }, {\ country: "United Kingdom",\ sales: 80000\ }\] The following data fields would need to describe data fields like this: let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); var series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); ### Setting data The data is set directly on series via its `data` property: series.data.setAll(\[{\ country: "France",\ sales: 100000\ }, {\ country: "Spain",\ sales: 160000\ }, {\ country: "United Kingdom",\ sales: 80000\ }\]); series.data.setAll(\[{\ country: "France",\ sales: 100000\ }, {\ country: "Spain",\ sales: 160000\ }, {\ country: "United Kingdom",\ sales: 80000\ }\]); IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFO There are more ways to set, update, add, or load data. For more information please refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. ### Series appearance For more information about configuring appearance of the pie series, refer to "[Pie series](https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/pie-series/) ". Legend ------ To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "core" package), push it to chart's children (or any other place we want it to be), as well as set its data (in case of percent chart, we will probably want to have each slice as a legend item). let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems); var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems); MORE INFO For more information on how to configure the legend, set its contents, and other tricks, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5percent from "@amcharts/amcharts5/percent"; // Create root and chart let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalHorizontal }) ); // Define data let data = \[{\ country: "France",\ sales: 100000\ }, {\ country: "Spain",\ sales: 160000\ }, {\ country: "United Kingdom",\ sales: 80000\ }\]; // Create series let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", valueField: "sales", categoryField: "country" }) ); series.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems);
See the Pen Pie chart by amCharts team (@amcharts) on CodePen. Start/end angles ---------------- A pie chart is not limited to a full circle. It can start and end at any angle. For that we have to set chart's settings: `[startAngle](https://www.amcharts.com/docs/v5/reference/piechart/#startAngle_setting) ` and `[endAngle](https://www.amcharts.com/docs/v5/reference/piechart/#endAngle_setting) `. These are numeric values denoting degrees. A zero angle is one that goes from the center of the chart directly to right. Defaults are `-90` (`startAngle`) and `270` (`endAngle`) forming full circle starting at vertical line up. We can change that any way we want. IMPORTANT For angles to work properly, we also need to replicate same angle settings on series, too. let chart = root.container.children.push( am5percent.PieChart.new(root, { startAngle: -180, endAngle: 0 }) ); let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", valueField: "sales", categoryField: "country", startAngle: -180, endAngle: 0 }) ); var chart = root.container.children.push( am5percent.PieChart.new(root, { startAngle: -180, endAngle: 0 }) ); var series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", valueField: "sales", categoryField: "country", startAngle: -180, endAngle: 0 }) ); The above will result in a horizontal semi-circle: [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/pie_default_full_circle.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/pie_default_full_circle.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/pie_custom_angle.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/pie_custom_angle.png) `{ startAngle: -180, endAngle: 0 }` See the Pen Start and end angles of a pie chart by amCharts team (@amcharts) on CodePen. Pie radius ---------- ### Outer radius Chart's outer radius can be set using its `[radius](https://www.amcharts.com/docs/v5/reference/piechart/#radius_setting) ` setting. It can be either percent value (relative to available space) or fixed pixel value. Pie chart's `radius` is set to `80%` by default to leave some space for possible ticks and labels. If we do not need that extra space, we can increase the radius: let chart = root.container.children.push( am5percent.PieChart.new(root, { radius: am5.percent(95) }) ); var chart = root.container.children.push( am5percent.PieChart.new(root, { radius: am5.percent(95) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/pie_default_full_circle-1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/pie_default_full_circle-1.png) `radius: am5.percent(80)` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_95.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_95.png) `radius: am5.percent(95)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_50px.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_50px.png) `radius: 50` ### Inner radius Chart's `innerRadius` settings controls the "hole" inside the pie. As with `radius` it can be either a percent value or fixed pixel value. The difference is that `innerRadius` percent value is relative to the chart radius, rather than available space. We can also use negative values in `innerRadius`. Those will mean pixel distance from the outer radius. This allows creating fixed-width slices. let chart = root.container.children.push( am5percent.PieChart.new(root, { radius: am5.percent(95), innerRadius: am5.percent(50) }) ); var chart = root.container.children.push( am5percent.PieChart.new(root, { radius: am5.percent(95), innerRadius: am5.percent(50) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_95.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_95.png) `innerRadius: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/donut.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/donut.png) `innerRadius: am5.percent(50)` See the Pen Start and end angles of a pie chart by amCharts team (@amcharts) on CodePen. Nested pie series ----------------- Pie chart supports multiple series. If we add several series to the chart, it will automatically divvy up available the radius (as set by its `radius` and `innerRadius` settings) between all series, giving them equal space. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nested_pie_series.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nested_pie_series.png) Nested series [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nested_pie_series_inner_radius.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nested_pie_series_inner_radius.png) Nested series with `innerRadius` See the Pen Pie chart with inner radius (donut) by amCharts team (@amcharts) on CodePen. Animation --------- Normally, created series will appear on chart right away. Should we want to make it play out initial animation, we can call it's `appear()` method right after creating its object. `appear()` method can also be called on the chart itself. let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); series.appear(); chart.appear(); var series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); series.appear(); chart.appear(); Related tutorials ----------------- * [Applying custom formatting logic to PieChart legend values](https://www.amcharts.com/docs/v5/tutorials/applying-custom-formatting-logic-to-piechart-legend-values/) * [Using slice color for PieChart label backgrounds](https://www.amcharts.com/docs/v5/tutorials/using-slice-color-for-piechart-label-backgrounds/) * [Adding sum labels inside Donut chart](https://www.amcharts.com/docs/v5/tutorials/adding-sum-labels-inside-donut-chart/) * [Pie chart with a custom legend](https://www.amcharts.com/docs/v5/tutorials/pie-chart-with-a-custom-legend/) --- # Scrollbars – amCharts 5 Documentation Scrollbars are useful controls that allow zooming chart's axis. Adding scrollbars ----------------- We create a scrollbar like everything else in amCharts 5: by calling `new()` [method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) of its class - `Scrollbar`. Please note that scrollbar requires at least one setting to be present during instantiation: `orientation`. Newly created Scrollbar object needs to be set on chart's `scrollbarX` setting (if we are adding a horizontal scrollbar), or `scrollbarY` (for vertical scrolling). chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" })); chart.set("scrollbarY", am5.Scrollbar.new(root, { orientation: "vertical" })); chart.set("scrollbarX", am5.Scrollbar.new(root, { orientation: "horizontal" })); chart.set("scrollbarY", am5.Scrollbar.new(root, { orientation: "vertical" })); Horizontal scrollbar will zoom/pan all horizontal axes, whereas vertical one will affect all vertical axes. ### Scrollbar elements Scrollbar has three properties to access its three elements: `startGrip`, `endGrip`, and `thumb`. The first two are elements of type `[Button](https://www.amcharts.com/docs/v5/reference/button/) `, whereas `thumb` is a `[RoundedRectangle](https://www.amcharts.com/docs/v5/reference/roundedrectangle/) `. All three are fully customizable as we can override their default settings with our own. let scrollbarX = chart.get("scrollbarX"); scrollbarX.thumb.setAll({ fill: am5.color(0x550000), fillOpacity: 0.1 }); scrollbarX.startGrip.setAll({ visible: false }); scrollbarX.endGrip.setAll({ visible: false }); let scrollbarX = chart.get("scrollbarX"); scrollbarX.thumb.setAll({ fill: am5.color(0x550000), fillOpacity: 0.1 }); scrollbarX.startGrip.setAll({ visible: false }); scrollbarX.endGrip.setAll({ visible: false }); The above will make thumb semi-transparent red, while disabling both grips. ### Scrollbar background When created, scrollbar will have its setting `background` set to an element of type `RoundedRectangle`. We can modify any of its [settings](https://www.amcharts.com/docs/v5/reference/roundedrectangle/#Settings) to configure scrollbar's background. let scrollbarX = chart.get("scrollbarX"); scrollbarX.get("background").setAll({ fill: am5.color(0x000000), fillOpacity: 0.2, cornerRadiusTR: 0, cornerRadiusBR: 0, cornerRadiusTL: 0, cornerRadiusBL: 0 }); var scrollbarX = chart.get("scrollbarX"); scrollbarX.get("background").setAll({ fill: am5.color(0x000000), fillOpacity: 0.2, cornerRadiusTR: 0, cornerRadiusBR: 0, cornerRadiusTL: 0, cornerRadiusBL: 0 }); Sizing scrollbar ---------------- ### Width or height To set scrollbar's height (or width for the vertical scrollbar) we can use its `height` (or `width`) setting. let scrollbarX = am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 }); var scrollbarX = am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 }); There's a caveat, though. By default, each scrollbar has its `minHeight` (or `minWidth`) set to `12`. If we need our scrollbar smaller than that, we'll need to use `minHeight` (or `minWidth`) instead: let scrollbarX = am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", minHeight: 3 }); var scrollbarX = am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", minHeight: 3 }); ### Size of the grips The easiest way to size scrollbar grips is to use their `scale` setting: scrollbarX.startGrip.set("scale", 0.7); scrollbarX.endGrip.set("scale", 0.7); scrollbarX.startGrip.set("scale", 0.7); scrollbarX.endGrip.set("scale", 0.7); See the Pen Sizing scrollbar elements by amCharts team (@amcharts) on CodePen. Scrollbar with chart preview ---------------------------- The scrollbar with chart preview acts like a regular one, except it can also display actual XY series in it. To create a scrollbar like that, we need to use a class `XYChartScrollbar` instead of `Scrollbar`. We will also want to set its `height` setting to something bigger than default to accommodate chart preview in it. let scrollbarX = am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 }); chart.set("scrollbarX", scrollbarX); var scrollbarX = am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 }); chart.set("scrollbarX", scrollbarX); That creates a scrollbar with a standalone instance of an XY chart in it, accessible via scrollbar's `[chart](https://www.amcharts.com/docs/v5/reference/xychartscrollbar/#chart_property) ` property. It's full on `XYChart` instance, which means that we'll need to configure it like any other XY chart: * Add axes. * Add series and their data. var sbxAxis = scrollbarX.chart.xAxes.push( am5xy.DateAxis.new(root, { groupData: true, groupIntervals: \[{ timeUnit: "year", count: 1 }\], baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { opposite: false, strokeOpacity: 0 }) }) ); var sbyAxis = scrollbarX.chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); var sbseries = scrollbarX.chart.series.push( am5xy.LineSeries.new(root, { xAxis: sbxAxis, yAxis: sbyAxis, valueYField: "value", valueXField: "date" }) ); sbseries.data.setAll(data); let sbxAxis = scrollbarX.chart.xAxes.push( am5xy.DateAxis.new(root, { groupData: true, groupIntervals: \[{ timeUnit: "year", count: 1 }\], baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, { opposite: false, strokeOpacity: 0 }) }) ); let sbyAxis = scrollbarX.chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) }) ); let sbseries = scrollbarX.chart.series.push( am5xy.LineSeries.new(root, { xAxis: sbxAxis, yAxis: sbyAxis, valueYField: "value", valueXField: "date" }) ); sbseries.data.setAll(data); The nice thing about this approach is that we can configure the output down to last bit, including [dynamic data point grouping](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/#Dynamic_data_item_grouping) of the preview series, to control its granularity. See the Pen Pre-zooming date axis by amCharts team (@amcharts) on CodePen. Repositioning scrollbars ------------------------ Normally, vertical scrollbar will be placed on chart's right, while horizontal one will be positioned on the top. To put it another way, when you assign a `Scrollbar` instance to chart's `scrollbarY` setting, it is automatically assigned as a child of chart's `rightAxesContainer`, whereas assigning it to `scrollbarX` will put it into `topAxesContainer`. Read more about build in XY chart containers in "[Containers of an XY chart](https://www.amcharts.com/docs/v5/charts/xy-chart/xy-chart-containers/) " tutorial. Re-positioning scrollbars is as easy as moving them to some other container. For example, the following code will move vertical scrollbar to the left of the chart, and horizontal one to bottom: // Scrollbar X var scrollbarX = am5.Scrollbar.new(root, { orientation: "horizontal" }); chart.set("scrollbarX", scrollbarX); chart.bottomAxesContainer.children.push(scrollbarX); // Scrollbar Y var scrollbarY = am5.Scrollbar.new(root, { orientation: "vertical" }); chart.set("scrollbarY", scrollbarX); chart.leftAxesContainer.children.push(scrollbarY); // Scrollbar X var scrollbarX = am5.Scrollbar.new(root, { orientation: "horizontal" }); chart.set("scrollbarX", scrollbarX); chart.bottomAxesContainer.children.push(scrollbarX); // Scrollbar Y var scrollbarY = am5.Scrollbar.new(root, { orientation: "vertical" }); chart.set("scrollbarY", scrollbarX); chart.leftAxesContainer.children.push(scrollbarY); See the Pen Scrollbar with chart preview by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Start/end labels on scrollbar grips](https://www.amcharts.com/docs/v5/tutorials/start-end-labels-on-scrollbar-grips/) * [Start/end labels on a scrollbar](https://www.amcharts.com/docs/v5/tutorials/adding-start-and-end-labels-to-a-scrollbar/) * [Customizing scrollbar grips](https://www.amcharts.com/docs/v5/tutorials/customizing-scrollbar-grips/) --- # Cursor – amCharts 5 Documentation Cursor is an optional functional component of an XY chart. It can be used to display crosshair over the hover/touch area, tooltips for some or all nearby series data items, as well as tooltips on axes. Adding to chart --------------- To add a cursor to an XY chart, we simply create an instance of an `[XYCursor](https://www.amcharts.com/docs/v5/reference/xycursor/) ` using its `new()` method, then assign it to chart's `cursor` setting: chart.set("cursor", am5xy.XYCursor.new(root, {})); chart.set("cursor", am5xy.XYCursor.new(root, {})); Behavior -------- Adding a cursor to charts adds a corsshair, shown when hovering the chart. We can use cursor's `behavior` setting to specify what else it can do. NOTE Enabling cursor behavior will disable chart's [pan settings](https://www.amcharts.com/docs/v5/charts/xy-chart/zoom-and-pan/#Panning) . ### Zooming To enabling zooming using cursor, we can set `behavior` to one of these values: | Value | Comment | | --- | --- | | `zoomX` | Enables horizontal selection-zooming. | | `zoomY` | Enables vertical selection-zooming. | | `zoomXY` | Enables bi-directional zooming. | chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "zoomX" })); chart.set("cursor", am5xy.XYCursor.new(root, { behavior: "zoomX" })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/zoomX.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/zoomX.png) `behavior: "zoomX"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/zoomY.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/zoomY.png) `behavior: "zoomY"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/zoomXY.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/zoomXY.png) `behavior: "zoomXY"` ### Selection We can also make cursor to just select the area of the chart, without actually zooming it using these `behavior` values: | Value | Comment | | --- | --- | | `selectX` | Enables horizontal selection. | | `selectY` | Enables vertical selection. | | `selectXY` | Enables bi-directional selection. | It will work the same way as zooming, except the selection area will stay selected after user releases mouse/touch. It can be useful in conjunction with selection-related [event handlers](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/#Events) . Relation to series ------------------ ### Tooltips #### Adding tooltip info to series If series has `tooltip` property assigned to it, cursor will try to show multiple tooltips for all series in the currently hovered/touched category/interval. For information on how to add tooltip to series, please refer to "[XY chart series: Tooltips](https://www.amcharts.com/docs/v5/charts/xy-chart/series/#Tooltips) ". See the Pen Chart with cursor by amCharts team (@amcharts) on CodePen. #### Limiting number of tooltips shown at a time If our chart has many series with tooltips enabled, using cursor might result in quite a mess, that does not fit into the chart. In such cases we can use XY chart's own `[maxTooltipDistance](https://www.amcharts.com/docs/v5/reference/xychart/#maxTooltipDistance_setting) ` setting to make cursor show only closest tooltips. It's a numeric value which means "show a tooltip to a closest data item as well as tooltips for data items that are visually no further from it by X pixels". For example, setting it to `0` (zero) will make it show tooltip for the closest data item only. let chart = root.container.children.push( am5xy.XYChart.new(root, { maxTooltipDistance: 0 }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { maxTooltipDistance: 0 }) ); `maxTooltipDistance` also has a special value: `-1`. Setting it will ensure that only one tooltip will be shown, no matter what. Even in case there are multiple data items in exact space spot. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/multiple_tooltips.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/multiple_tooltips.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/maxtooltipdistance_used.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/maxtooltipdistance_used.png) `maxTooltipDisatnce: 0` The following demo shows how we can use `maxTooltipDistance` to show only single consolidated tooltip for multiple series. See the Pen amCharts 5: Inversed value axis by amCharts team (@amcharts) on CodePen. The distance used by `maxTooltipDistance` is measured by both X and Y coordinates by default. If we'd like to measure only horizontal or vertical distance, we can use another setting: `[maxTooltipDistanceBy](https://www.amcharts.com/docs/v5/reference/xychart/#maxTooltipDistanceBy_setting) `: let chart = root.container.children.push( am5xy.XYChart.new(root, { maxTooltipDistance: 10, maxTooltipDistanceBy: "x" }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { maxTooltipDistance: 10, maxTooltipDistanceBy: "x" }) ); #### Auto-arranging tooltips When cursor triggers multiple tooltips to be shown, they are automatically arranged to not overlap. Should we want to disable this check, we can use chart's `arrangeTooltips` setting to `false`: let chart = root.container.children.push( am5xy.XYChart.new(root, { arrangeTooltips: false }) ); var chart = root.container.children.push( am5xy.XYChart.new(root, { arrangeTooltips: false }) ); ### Snapping to series A cursor can be made to snap to actual series data items. To enable it we need to assign actual series objects we want cursor to snap to into cursor's `[snapToSeries](https://www.amcharts.com/docs/v5/reference/xycursor/#snapToSeries_setting) ` setting. chart.set("cursor", am5xy.XYCursor.new(root, { snapToSeries: \[ series1, series2 \] })); chart.set("cursor", am5xy.XYCursor.new(root, { snapToSeries: \[ series1, series2 \] })); By default, cursor will choose closest data item based on proximity by both X and Y coordinate. If we'd like it to rather snap horizontally or vertically we can set `[snapToSeriesBy](https://www.amcharts.com/docs/v5/reference/xycursor/#snapToSeriesBy_setting) ` to either `"x"` or `"y"`, respectively. chart.set("cursor", am5xy.XYCursor.new(root, { snapToSeries: \[ series1, series2 \], snapToSeriesBy: "x" })); chart.set("cursor", am5xy.XYCursor.new(root, { snapToSeries: \[ series1, series2 \], snapToSeriesBy: "x" })); `snapToSeriesBy` supports two additional values: `"x!"` and `"y!"`. They work similarly to `"x"` and `"y"` respectively, except they will only snap in intervals there are values in, reverting to free-move on intervals/categories there is no data for series that cursor is being snapped to. IMPORTANTCursor relies on axis' tooltip for snapping position. This is why above settings won't function as expected if the related axis does not have tooltip enabled. If we don't want the tooltip to be visible, we can hide it using `forceHidden` setting: xAxis.set("tooltip", am5.Tooltip.new(root, { forceHidden: true })); yAxis.set("tooltip", am5.Tooltip.new(root, { forceHidden: true })); xAxis.set("tooltip", am5.Tooltip.new(root, { forceHidden: true })); yAxis.set("tooltip", am5.Tooltip.new(root, { forceHidden: true })); ### Irregularly spaced data The cursor will snap to the closest data item from all the series it is supposed to snap to. If series contain irregularly spaced data, e.g. series is missing a data item for the same timestamp that tooltip is currently snapped to based on a data item from another series, the tooltip for the former series will not be shown. To force showing of a tooltip to the closest data item - even if its timestamp does not match currently snapped data item - set `snapTooltip: true` in series settings: let series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "{valueX}: {valueY}", }), snapTooltip: true }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "{valueX}: {valueY}", }), snapTooltip: true }) ); Relation to axes ---------------- ### Axis tooltips A cursor may display a tooltip with an exact value corresponding to the position of its vertical and horizontal crosshair lines. To make that happen, we simply need to assign `Tooltip` instances to the `tooltip` setting of the axes we want to show tooltips on: xAxis.set("tooltip", am5.Tooltip.new(root, {})); yAxis.set("tooltip", am5.Tooltip.new(root, {})); xAxis.set("tooltip", am5.Tooltip.new(root, {})); yAxis.set("tooltip", am5.Tooltip.new(root, {})); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/without_axis_tooltips.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/without_axis_tooltips.png) Without axis tooltips [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/axis_tooltips.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/axis_tooltips.png) With axis tooltips ### Snapping to axis cells The crosshair lines will follow mouse/touch pointer by default. We can make it rather snap to axis cell by setting cursor's `xAxis` or `yAxis` settings: chart.set("cursor", am5xy.XYCursor.new(root, { xAxis: xAxis })); chart.set("cursor", am5xy.XYCursor.new(root, { xAxis: xAxis })); Appearance ---------- ### Lines An XY cursor has two properties: `[lineX](https://www.amcharts.com/docs/v5/reference/xycursor/#lineX_property) ` and `[lineY](https://www.amcharts.com/docs/v5/reference/xycursor/#lineY_property) ` that represent vertical and horizontal crosshair lines respectively. Those are elements of type `[Grid](https://www.amcharts.com/docs/v5/reference/grid/) ` that we can use to configure cursor's lines: let cursor = chart.get("cursor"); cursor.lineX.setAll({ stroke: am5.color(0x550000), strokeWidth: 2, strokeDasharray: \[\] }); cursor.lineY.setAll({ visible: false }); let cursor = chart.get("cursor"); cursor.lineX.setAll({ stroke: am5.color(0x550000), strokeWidth: 2, strokeDasharray: \[\] }); cursor.lineY.setAll({ visible: false }); The above will apply color, remove dashing, and make vertical line thicker, while completely hide horizontal line. ### Selection If cursor's `behavior` is set to zoom or select it will draw a shaded area to indicate selection when dragged on plot area. That shading is done by displaying a custom element (`[Graphics](https://www.amcharts.com/docs/v5/reference/graphics/) `) over plot area. It's accessible via `selection` property, and can be configured as needed: let cursor = chart.get("cursor"); cursor.selection.setAll({ fill: am5.color(0x000055), fillOpacity: 0.2 }); let cursor = chart.get("cursor"); cursor.selection.setAll({ fill: am5.color(0x000055), fillOpacity: 0.2 }); Events ------ Cursor defines a few [events](https://www.amcharts.com/docs/v5/concepts/events/) that are dispatched when something happens. For example, we can use its `selectstarted` and `selectended` events to track when selection using the cursor began and ended. There's also `cursormoved` event which we can use to [track cursor movement](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/#Tracking_cursor_movement) . For a complete list of events supported by `XYCursor`, check its [class reference](https://www.amcharts.com/docs/v5/reference/xycursor/#Events) . Tracking/setting position ------------------------- ### Tracking cursor movement We can use cursor's `cursormoved` event to invoke custom handler whenever cursor position on the plot area changes. In event handler we can access its [private properties](https://www.amcharts.com/docs/v5/concepts/settings/#Private_settings) `positionX` and `positionY` wich in turn can be converted to real position on axis using axis' methods: cursor.events.on("cursormoved", function(ev) { let x = ev.target.getPrivate("positionX"); let y = ev.target.getPrivate("positionY"); let dateX = xAxis.positionToDate(x); let valueY = yAxis.positionToValue(y); }); cursor.events.on("cursormoved", function(ev) { var x = ev.target.getPrivate("positionX"); var y = ev.target.getPrivate("positionY"); var dateX = xAxis.positionToDate(x); var valueY = yAxis.positionToValue(y); }); Please note, that the above will work correctly only when axis is fully zoomed out. To be on the safe side, and account for zoomed-in sates, we should also use axis' `toAxisPosition()` method: cursor.events.on("cursormoved", function(ev) { let x = ev.target.getPrivate("positionX"); let y = ev.target.getPrivate("positionY"); let dateX = xAxis.positionToDate(xAxis.toAxisPosition(x)); let valueY = yAxis.positionToValue(xAxis.toAxisPosition(y)); }); cursor.events.on("cursormoved", function(ev) { var x = ev.target.getPrivate("positionX"); var y = ev.target.getPrivate("positionY"); var dateX = xAxis.positionToDate(xAxis.toAxisPosition(x)); var valueY = yAxis.positionToValue(xAxis.toAxisPosition(y)); }); See the Pen Tracking XYCursor position by amCharts team (@amcharts) on CodePen. ### Manually positioning cursor We can manually position the cursor using its `[positionX](https://www.amcharts.com/docs/v5/reference/xycursor/#positionX_setting) ` and `[positionY](https://www.amcharts.com/docs/v5/reference/xycursor/#positionY_setting) ` settings. We also want the cursor to display without hovering over plot area (which is default behavior), so we need to set `[alwaysShow](https://www.amcharts.com/docs/v5/reference/xycursor/#alwaysShow_setting) ` to `true` as well. Position is a numeric value relative to plot area, with `0` (zero) denoting beginning, and `1` (one) - the end. So if we'd like to place the cursor in the exact middle of the chart, we'd use `0.5` for the setting value: cursor.setAll({ positionX: 0.5, positionY: 0.5, alwaysShow: true }); cursor.setAll({ positionX: 0.5, positionY: 0.5, alwaysShow: true }); And, since we are using axes, we can use their methods to find out positions for specific values, e.g. on a date axis. For that we need to use two functions: * Axis' `dateToPosition()` - converts a `Date` object into a position. (similarly for `CategoryAxis` use `categoryToPosition()`, and for `ValueAxis` - `valueToPosition()`) * Axis renderer's `toGlobalPosition()` - converts the position to a "global" position, which accounts for a possible axis zoom. cursor.set("positionX", xAxis.get("renderer").toGlobalPosition( xAxis.dateToPosition(new Date(2021, 6, 12)) )); cursor.set("positionX", xAxis.get("renderer").toGlobalPosition( xAxis.dateToPosition(new Date(2021, 6, 12)) )); Setting cursor position requires respective axes to have a scale. If we are setting cursor on chart load, we will need to use series `datavalidated` event: series.events.on("datavalidated", function() { chart.get("cursor").setAll({ positionX: 0.5, positionY: 0.5, alwaysShow: true }); }); series.events.on("datavalidated", function() { chart.get("cursor").setAll({ positionX: 0.5, positionY: 0.5, alwaysShow: true }); }); See the Pen Setting xycursor position by amCharts team (@amcharts) on CodePen. Syncing cursors --------------- amCharts allows automatically syncing positions of cursors from several charts. To enable this feature, all we need to do is to set cursor's `syncWith` setting with an array of cursor objects to sync it with: let cursor1 = am5xy.XYCursor.new(root1, {}); let cursor2 = am5xy.XYCursor.new(root2, {}); let cursor3 = am5xy.XYCursor.new(root3, {}); cursor1.set("syncWith", \[cursor2, cursor3\]); cursor2.set("syncWith", \[cursor1, cursor3\]); cursor3.set("syncWith", \[cursor1, cursor2\]); chart1.set("cursor", cursor1); chart2.set("cursor", cursor2); chart3.set("cursor", cursor3); var cursor1 = am5xy.XYCursor.new(root1, {}); var cursor2 = am5xy.XYCursor.new(root2, {}); var cursor3 = am5xy.XYCursor.new(root3, {}); cursor1.set("syncWith", \[cursor2, cursor3\]); cursor2.set("syncWith", \[cursor1, cursor3\]); cursor3.set("syncWith", \[cursor1, cursor2\]); chart1.set("cursor", cursor1); chart2.set("cursor", cursor2); chart3.set("cursor", cursor3); IMPORTANTSyncing is performed using actual X/Y coordinates of the point of mouse cursor's position or touch. It means that they will not sync by axis positions, but rather by screen coordinates. For example vertical lines will not sync across horizontally laid out charts, and vice versa. See the Pen amCharts 5: Syncing cursors across several charts by amCharts team (@amcharts) on CodePen. MORE INFOFor syncing cursors across non-vertically arranged charts, refer to "[Syncing cursors across multiple horizontally-arranged charts](https://www.amcharts.com/docs/v5/tutorials/syncing-cursors-across-multiple-horizontally-arranged-charts/) ". Keyboard control ---------------- Cursor can also be controlled using directional keys on a keyboard. For more information, refer to "[Accessibility: XY cursor](https://www.amcharts.com/docs/v5/concepts/accessibility/#XY_Cursor) " tutorial. Related tutorials ----------------- * [Triggering bullet hover with an XY cursor](https://www.amcharts.com/docs/v5/tutorials/triggering-bullet-hover-with-an-xy-cursor/) * [Getting data items within cursor selection](https://www.amcharts.com/docs/v5/tutorials/getting-data-items-within-cursor-selection/) * [Cursor with “corner” crosshair lines](https://www.amcharts.com/docs/v5/tutorials/cursor-with-corner-crosshair-lines/) * [Changing XYCursor's behavior based on SHIFT key](https://www.amcharts.com/docs/v5/tutorials/changing-xycursors-behavior-based-on-shift-key/) * [Syncing cursors across multiple horizontally-arranged charts](https://www.amcharts.com/docs/v5/tutorials/syncing-cursors-across-multiple-horizontally-arranged-charts/) --- # Legend and XY series – amCharts 5 Documentation This tutorial will walk through configuration options for legend content on an XY chart. Adding legend ------------- To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "index" package), push it to chart's children (or any other place we want it to be), as well as set its data (in case of XY chart, we will probably want to use series as legend items). let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); var legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); MORE INFO For more information on how to configure legend, its items, and layout, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. Legend label content -------------------- ### Setting content What goes into legend labels on an XY chart is controlled by four of the series' settings: | Setting key | Default | Comment | | --- | --- | --- | | `legendLabelText` | `{name}` | Text for the legend item label when specific series data item is selected with a chart cursor. | | `legendValueText` | \- | Text for the legend item value label when specific series data item is selected with a chart cursor. | | `legendRangeLabelText` | `{name}` | Text for the legend item label when no specific data item is selected. | | `legendRangeValueText` | \- | Text for the legend item value label when no specific data item is selected. | To change contents of the legend, we simply need to set corresponding setting value: let series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", legendLabelText: "Series: {name}", legendRangeLabelText: "Series: {name}" }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", legendLabelText: "Series: {name}", legendRangeLabelText: "Series: {name}" }) ); ### Specific data item vs range By default, series will use `legendRangeLabelText` to fill its legend item label. If our chart has a cursor, moving it over plot area will grab closest data item from the series, and will use `legendLabelText` for the legend item label. Let's take an example: let series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", legendLabelText: "Cursor over plot area", legendRangeLabelText: "Cursor inactive" }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", legendLabelText: "Cursor over plot area", legendRangeLabelText: "Cursor inactive" }) ); When chart loads it will show `"Cursor inactive"` text in series' legend label. As soon as we move cursor of chart's plot area, it will be replaced with a `"Cursor over plot area"` text. When cursor leaves the plot area again, the text will be replaced back with the `"Cursor inactive"` text. ### Dynamic values Since labels support [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (references to data item settings in curly brackets), text will be populated with actual data and values. When there is no data cursor on chart, or cursor is not over plot area, labels will be populated from series' settings, e.g. `LineSeries` [settings](https://www.amcharts.com/docs/v5/reference/lineseries/#settings) or [private settings](https://www.amcharts.com/docs/v5/reference/lineseries/#Private_settings) . If cursor is hovering on plot area, closest data item will be used to populate the label, e.g. `[LineSeriesDataItem](https://www.amcharts.com/docs/v5/reference/ilineseriesdataitem/) `. let series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category", legendLabelText: "{name}: {categoryX}", legendRangeLabelText: "{name}" }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category", legendLabelText: "{name}: {categoryX}", legendRangeLabelText: "{name}" }) ); Let's examine what happens in the above config. #### Cursor is outside plot area In this case, `legendRangeLabelText` is used and is populated by series data. Text formatter, when populating text `"{name}"` looks for the placeholders in a number of places. It finds `name` in `LineSeries`' [settings](https://www.amcharts.com/docs/v5/reference/lineseries/#name_setting) . The result is a text with a text with series name, e.g.: `"Sales"`. #### Cursor over plot area Now, legend label text is replaced with a `"{name}: {categoryX}"`. Now, instead of series' object, a specific series data item is used. In case of line series, it's an `[ILineSeriesDataItem](https://www.amcharts.com/docs/v5/reference/ilineseriesdataitem/) `. It does not have a `name` in it, so text formatter looks in a parent, which is series, so it finds `name` in series' settings. Then it looks up `categoryX` which [does exist](https://www.amcharts.com/docs/v5/reference/ilineseriesdataitem/#categoryX_property) in series data item. Depending on which category cursor is closest to, we'll end up with a legend label similar to this: `Sales: Q3`. As we move cursor over plot area and the closest data item changes, so does label in legend gets repopulated. See the Pen Cursor and legend labels by amCharts team (@amcharts) on CodePen. ### In-line formatting Besides regular text and data placeholders, labels support square bracket [in-line formatting](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) blocks. E.g.: let series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category", legendLabelText: "\[{stroke}\]{name}\[/\]: \[bold #888\]{categoryX}\[/\]", legendRangeLabelText: "\[{stroke}\]{name}\[/\]" }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category", legendLabelText: "\[{stroke}\]{name}\[/\]: \[bold #888\]{categoryX}\[/\]", legendRangeLabelText: "\[{stroke}\]{name}\[/\]" }) ); The above will use series' `stroke` (color) for series name, as well as make category names bold and gray. Value labels ------------ Value labels are additional set of labels placed next to regular labels. They are usually used to display value of the item, hence the name "value labels". Value labels function exactly the same way as regular labels, including support for data placeholders and in-line formatting. The content for value labels is supplied via `legendValueText` and `legendRangeValueText` settings: let series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category", calculateAggregates: true, tooltip: am5.Tooltip.new(root, {}), legendLabelText: "\[{stroke}\]{name}\[/\]: \[bold #888\]{categoryX}\[/\]", legendRangeLabelText: "\[{stroke}\]{name}\[/\]", legendValueText: "\[bold {stroke}\]{valueY}\[/\]", legendRangeValueText: "\[{stroke}\]{valueYClose}\[/\]" }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { name: "Sales", xAxis: xAxis, yAxis: yAxis, valueYField: "value", categoryXField: "category", calculateAggregates: true, tooltip: am5.Tooltip.new(root, {}), legendLabelText: "\[{stroke}\]{name}\[/\]: \[bold #888\]{categoryX}\[/\]", legendRangeLabelText: "\[{stroke}\]{name}\[/\]", legendValueText: "\[bold {stroke}\]{valueY}\[/\]", legendRangeValueText: "\[{stroke}\]{valueYClose}\[/\]" }) ); See the Pen Cursor and legend labels by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Aligning a legend with plot container](https://www.amcharts.com/docs/v5/tutorials/aligning-a-legend-with-plot-container/) --- # Funnel, pyramid, and pictorial charts – amCharts 5 Documentation This tutorial will walk through common steps of creating sliced charts with funnel, pyramid, and pictorial stacked series. Loading required modules ------------------------ Everything required to create percent charts are two amCharts 5 modules: "index" and "percent". You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5percent from "@amcharts/amcharts5/percent"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Instantiating the chart ----------------------- As with any chart type in amCharts 5, we'll need to start with creation of the `Root` element. In it we will create an instance of `SliceChart` class to create a pie chart let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5percent.SlicedChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var chart = root.container.children.push( am5percent.SlicedChart.new(root, {}) ); MORE INFO The notion of creating class instances using `.new()` method is described in "[Creating a chart](https://www.amcharts.com/docs/v5/getting-started/#Creating_a_chart) " section in the "Getting started" tutorial. Make sure you check it out. Series ------ ### Adding Like everywhere else, we use series' `new()` method to instantiate series, then push it into `series` list of the chart: let series = chart.series.push( am5percent.FunnelSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales", orientation: "vertical" }) ); var series = chart.series.push( am5percent.FunnelSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales", orientation: "vertical" }) ); NOTE Series of a sliced chart require setting `orientation` so that chart knows how to orient the series. The following series types are supported in a sliced chart: These series types are available for percent charts: | Class | Comment | | | --- | --- | --- | | `FunnelSeries` | A horizontal or vertical funnel. | [More info](https://www.amcharts.com/docs/v5/charts/percent-charts/sliced-chart/funnel-series/) | | `PyramidSeries` | A horizontal or vertical pyramid. | [More info](https://www.amcharts.com/docs/v5/charts/percent-charts/sliced-chart/pyramid-series/) | | `PictorialStackedSeries` | A horizontal or vertical custom shape. | [More info](https://www.amcharts.com/docs/v5/charts/percent-charts/sliced-chart/pictorial-stacked-series/) | ### Data fields Sliced chart series require two to dimensions of data: a string-based category and a numeric value. Data fields basically mean which keys in data objects to look for specific value. They can be set via series' settings `categoryField` and `valueField`. Let's take sample data: \[{\ stage: "Stage #1",\ sales: 100000\ }, {\ stage: "Stage #2",\ applicants: 70000\ }, {\ stage: "Stage #3",\ applicants: 5500\ }\] The following data fields would need to describe data fields like this: let series = chart.series.push( am5xy.FunnelSeries.new(root, { name: "Series", categoryField: "stage", valueField: "applicants" }) ); var series = chart.series.push( am5xy.FunnelSeries.new(root, { name: "Series", categoryField: "stage", valueField: "applicants" }) ); ### Setting data The data is set directly on series via its `data` property: series.data.setAll(\[{\ stage: "Stage #1",\ applicants: 100000\ }, {\ stage: "Stage #2",\ applicants: 70000\ }, {\ stage: "Stage #3",\ applicants: 5500\ }\]); series.data.setAll(\[{\ stage: "Stage #1",\ sales: 100000\ }, {\ stage: "Stage #2",\ applicants: 70000\ }, {\ stage: "Stage #3",\ applicants: 5500\ }\]); For more information about setting data to series, refer to "[Percent series: Setting data](https://www.amcharts.com/docs/v5/charts/percent-charts/percent-series/#Setting_data) ". IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. Slice colors ------------ A series will automatically assign a different color to each of its slice. The colors are defined in a theme used by the chart, and can be overridden in a number of ways. For more information about it, refer to "[Percent series: Slice colors](https://www.amcharts.com/docs/v5/charts/percent-charts/percent-series/#Slice_colors) ". Legend ------ To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "core" package), push it to chart's children (or any other place we want it to be), as well as set its data (in case of percent chart, we will probably want to have each slice as a legend item). let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems); var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems); MORE INFO For more information on how to configure the legend, set its contents, and other tricks, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5percent from "@amcharts/amcharts5/percent"; let chart = root.container.children.push( am5percent.SlicedChart.new(root, { layout: root.horizontalLayout }) ); // Define data var data = \[{\ country: "Stage #1",\ sales: 100000\ }, {\ country: "Stage #2",\ sales: 70000\ }, {\ country: "Stage #3",\ sales: 5500\ }\]; // Create series let series = chart.series.push( am5percent.FunnelSeries.new(root, { name: "Series", valueField: "sales", categoryField: "country", orientation: "vertical", alignLabels: true }) ); series.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), y: am5.percent(50), layout: root.verticalLayout })); legend.data.setAll(series.dataItems);
See the Pen Funnel chart by amCharts team (@amcharts) on CodePen. Multiple series --------------- Sliced chart supports multiple series of any type: funnel, pyramid, or pictorial stacked. We can also mix and match different types of series on a single chart. All series we add, will be placed next to each other horizontally, divvying up the space in equal spaces. See the Pen Funnel chart by amCharts team (@amcharts) on CodePen. If we'd like to rather arrange series vertically, we will need to change layout for chart's `seriesContainer`: chart.seriesContainer.set("layout", root.verticalLayout); chart.seriesContainer.set("layout", root.verticalLayout); ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/sliced_horizontal_layout-1024x715.png) `chart.seriesContainer.set("layout", root.verticalLayout)` ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/sliced_vertical_layout-1024x715.png) `chart.seriesContainer.set("layout", root.verticalLayout)` Animation --------- Normally, created series will appear on chart right away. Should we want to make it play out initial animation, we can call it's `appear()` method right after creating its object. `appear()` method can also be called on the chart itself. let series = chart.series.push( am5percent.FunnelSeries.new(root, { name: "Series", categoryField: "stage", valueField: "applicants" }) ); series.appear(); chart.appear(); var series = chart.series.push( am5percent.FunnelSeries.new(root, { name: "Series", categoryField: "stage", valueField: "applicants" }) ); series.appear(); chart.appear(); --- # Containers of an XY chart – amCharts 5 Documentation This tutorial looks at the container elements comprising internal structure of an XY chart, and how we can configure them. Built-in chart containers ------------------------- An XY chart comes with a predefined list of container hierarchy, accessible via chart's properties: | Property | Default layout | Comment | | --- | --- | --- | | N/A (chart itself) | `none` | Main chart container. | | `topAxesContainer` | `vertical` | X axes with `renderer.opposite: true` set are put into this container. | | `bottomAxesContainer` | `vertical` | X axes are put into this container | | `yAxesAndPotContainer` | `horizontal` | Houses sub-containers for Y axes and plots (series). | | `leftAxesContainer` | `horizontal` | Y axes are put into this container. | | `rightAxesContainer` | `horizontal` | Y axes with `renderer.opposite: true` set are put into this container. | | `plotContainer` | `none` | Series are plot in this container. | Container structure ------------------- ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/V5_-Containter-structure.png) Configuring containers ---------------------- All XY chart containers are elements of type `[Container](https://www.amcharts.com/docs/v5/reference/container/) `. We can use to configure them as we see fit. ### Adding outline/background Configuring outlines or background is done like with any other container: but adding a `Rectangle` element into its [`background` setting](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Background) . The following code will add a fill and an outline for the whole chart's area: chart.set("background", am5.Rectangle.new(root, { stroke: am5.color(0x297373), strokeOpacity: 0.5, fill: am5.color(0x297373), fillOpacity: 0.2 })); chart.set("background", am5.Rectangle.new(root, { stroke: am5.color(0x297373), strokeOpacity: 0.5, fill: am5.color(0x297373), fillOpacity: 0.2 })); `plotContainer` already has background created for it for internal reasons, so we can just re-use it instead of creating a new one: chart.plotContainer.get("background").setAll({ stroke: am5.color(0x297373), strokeOpacity: 0.5, fill: am5.color(0x297373), fillOpacity: 0.2 }); chart.plotContainer.get("background").setAll({ stroke: am5.color(0x297373), strokeOpacity: 0.5, fill: am5.color(0x297373), fillOpacity: 0.2 }); See the Pen by amCharts team (@amcharts) on CodePen. ### Changing layout Changing layout of the container may alter the way and order chart elements are laid out. For example, if we push the legend into chart's children list, setting its `layout` to vertical will put legend below everything else, while setting it to horizontal, will put legend to the right of the chart. For more information, visit "Legend: [Positioning](https://www.amcharts.com/docs/v5/concepts/legend/#Positioning) ". Adding custom elements ---------------------- We can use any chart container to add elements to it. The following code will add a chart title to the top of the chart by pushing a `Label` element into `topAxesContainer` which is always on top: chart.topAxesContainer.children.push(am5.Label.new(root, { text: "Sales breakdown by region", fontSize: 20, fontWeight: "400", x: am5.p50, centerX: am5.p50 })); chart.topAxesContainer.children.push(am5.Label.new(root, { text: "Sales breakdown by region", fontSize: 20, fontWeight: "400", x: am5.p50, centerX: am5.p50 })); See the Pen Fill on a plot container by amCharts team (@amcharts) on CodePen. --- # Radar axes – amCharts 5 Documentation Radar chart reuses same axes types as XY chart. However it uses different axis renderers. While those are very similar to XY renderers in configuration, there some differences. This tutorial will address those. Labels on a circular axis ------------------------- Configuration of labels on an axis is done via axis renderer's `labels.template` property. For more information about it, please refer to "[Axes: Labels](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/#Labels) " tutorial ### Label type Circular axis renderer positions its labels neatly curved along the axis line by default. This can be configured via label template's `[textType](https://www.amcharts.com/docs/v5/reference/radiallabel/#textType_setting) ` setting. Available options for use on a radar chart are: `"circular"` (default), `"radial"`, and `"adjusted"`. xAxis.get("renderer").labels.template.setAll({ fontSize: 12, textType: "radial" }); xAxis.get("renderer").labels.template.setAll({ fontSize: 12, textType: "radial" }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_labels_circular.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_labels_circular.png) `textType: "circular"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_labels_adjusted-2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_labels_adjusted-2.png) `textType: "radial"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_labels_adjusted.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_labels_adjusted.png) `textType: "adjusted"` See the Pen Radar chart with custom angles by amCharts team (@amcharts) on CodePen. ### Label radius Label setting `radius` that can be set via its template controls distance from the axis line. It's a number in pixels. The higher the radius, the further from the slice edge the label will be: xAxis.get("renderer").labels.template.setAll({ fontSize: 12, textType: "radial", radius: 10 }); xAxis.get("renderer").labels.template.setAll({ fontSize: 12, textType: "radial", radius: 10 }); ### Labels inside plot area We can set `inside` setting to `true` on the label template, if we want the labels to appear inside charts plot area. If we do so, the `radius` setting will revert: it will mean radius in pixels inwards, rather than outwards from the axis line. xAxis.get("renderer").labels.template.setAll({ fontSize: 12, textType: "radial", radius: 10, inside: true }); xAxis.get("renderer").labels.template.setAll({ fontSize: 12, textType: "radial", radius: 10, inside: true }); Axis radii and angles --------------------- Just like radar chart itself can have `radius`, `innerRadius`, `startAngle`, and `endAngle` settings, so can circular axis renderer. Percent value on `radius` and `innerRadius` work in relation to the radar chart itself, not chart container. We can also use negative values in `innerRadius`. Those will mean pixel distance from the outer radius. This allows creating fixed-width axis. `startAngle` and `endAngle` work just like for radar chart: we can specify where each axis starts and where it ends precisely, even if it is not the same values as the chart itself. Here's an example of a radar chart using two circular axes with different angle settings: [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/dual_radar_axis.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/dual_radar_axis.png) The above chart has following setup: let chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(70), innerRadius: am5.percent(50), startAngle: -160, endAngle: -20 }) ); let xAxis1 = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5radar.AxisRendererCircular.new(root, { startAngle: -160, endAngle: -95 }) }) ); let xAxis2 = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5radar.AxisRendererCircular.new(root, { startAngle: -85, endAngle: -20 }) }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(70), innerRadius: am5.percent(50), startAngle: -160, endAngle: -20 }) ); var xAxis1 = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5radar.AxisRendererCircular.new(root, { startAngle: -160, endAngle: -95 }) }) ); var xAxis2 = chart.xAxes.push( am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5radar.AxisRendererCircular.new(root, { startAngle: -85, endAngle: -20 }) }) ); See the Pen Radar chart axis labels by amCharts team (@amcharts) on CodePen. --- # Radar series – amCharts 5 Documentation While radar series resemble their equivalents in XY chart in how they are configured, there are some differences. This tutorial will address those. Connecting ends --------------- Line-based series like `RadarLineSeries` and `SmoothedRadarLineSeries` will automatically connect their first and last data points to complete the circle. We can disable this behavior using series' `connectEnds` setting: let series = chart.series.push( am5radar.RadarLineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", connectEnds: false }) ); var series = chart.series.push( am5radar.RadarLineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", connectEnds: false }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/connectends_true.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/connectends_true.png) `connectEnds: true` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/connectends_false.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/connectends_false.png) `connectEnds: false` See the Pen Disabling radar line series end connection by amCharts team (@amcharts) on CodePen. --- # Grouping slices – amCharts 5 Documentation This tutorial will show how we can use Slice Grouper plugin to automatically group small slices. Purpose ------- "Percent" charts such as Pie, Funnel, Pyramid, or Pictorial Stacked depict each data item as a relatively-sized "slice". The smaller the slice's value in comparison to other slices, the smaller the slice itself. While this provide proportional information prominent, some relatively small slices, might be insignificant for conveying the "big picture, and contribute to the noise. [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/chrome_2019-04-08_22-41-44-1024x765.png)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/chrome_2019-04-08_22-41-44-1024x765.png) [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-42-14-1024x765.png)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-42-14-1024x765.png) [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-43-05-1024x765.png)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-43-05-1024x765.png) What a clutter! If we examine the charts closer, we'll see that the last four items have their own place, label and even legend item that take up space, even though their collective value barely comprises 10% of the whole chart. The purpose of SliceGrouper plugin is to automatically group those slices like that into a single "Other" slice. [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-51-35-1024x765.png)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-51-35-1024x765.png) [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-52-07-1024x765.png)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-52-07-1024x765.png) [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-53-16-1024x765.png)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_22-53-16-1024x765.png) Loading ------- Slice grouper plugin needs to be loaded in order for it to be used. You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5plugins\_sliceGrouper from "@amcharts/amcharts5/plugins/sliceGrouper"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFOFor more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Enabling -------- Slice grouper plugin is instantiated just like any other object in amCharts 5: by calling [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) of its class, passing in [root element](https://www.amcharts.com/docs/v5/getting-started/#Root_element) and settings object. let grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { }); var grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { }); Setting up ---------- ### Available settings Plugin is configured via its instances settings: | | | | | | --- | --- | --- | --- | | **Setting** | **Type** | **Default** | **Comment** | | `clickBehavior` | `"none"` \| `"break"` \| `"zoom"` | `"none"` | What happens when you click on "Other" slice?
See "Click behavior" section below. | | `groupName` | `string` | `"Other"` | Name of the group slice. | | `limit` | `number` | | If set, only first X slices will be left alone (regardless of their value and `threshold` setting), the rest will be grouped into "Other" slice. | | `legend` | `Legend` | | Target legend. | | `series` | `PercentSeries` | | Target series. | | `threshold` | `number` | `5` | Slices that comprise this percent or less of the total will be grouped into "Other" slice. | For plugin to work, we need to at least set its `series` setting. It needs to be a reference to the series, which we want to group slices in, e.g. a `PieSeries`. let grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { series: pieSeries }); var grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { series: pieSeries }); ### Group thresholds The plugin will automatically group all slices that are less than 5% into a single slice. We can change this value via `threshold` setting, which accepts numeric values. There's also a `limit` setting. It also accepts a numeric value which means number of first slices to leave as they are, automatically grouping the rest. Both of the setting scan be combined and used together: let grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { series: pieSeries, threshold: 10, limit: 5 }); var grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { series: pieSeries, threshold: 10, limit: 5 }); ### Click behavior By default, the "Other" slice acts like any other slice on the chart. For example, on a Pie Chart it would pull it out on click or tap. We can use `clickBehavior` to alter this functionality. Setting it to `"break"` will hide "Other" slice and will reveal actual small slices that comprise it instead. A "Zoom out" button will be shown that would allow collapsing small slices back into their group slice. `"zoom"` setting will act similarly, except big slices will be hidden as well, in order for us to be able to concentrate on the actual relation between small slices. [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_23-14-30.gif)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_23-14-30.gif) `clickBehavior: "none"` (default) [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_23-17-26.gif)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_23-17-26.gif) `clickBehavior: "break"` [![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_23-18-29.gif)](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/04/2019-04-08_23-18-29.gif) `clickBehavior: "zoom"` ### Legend If our chart uses a legend, and we want plugin to automatically hide legend items for hidden slices, we need to set `legend` setting as well: let grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { series: pieSeries, legend: legend }); var grouper = am5plugins\_sliceGrouper.SliceGrouper.new(root, { series: pieSeries, legend: legend }); Examples -------- Here's a basic Pie chart with grouped slices. See the Pen Untitled by amCharts team (@amcharts) on CodePen. Here's another one, which users adapter to break down grouped slice info in the tooltip of the "Other" slice: See the Pen Slice grouper with breakdown of the "Other" slice in a tooltip by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Grouping slices](https://www.amcharts.com/docs/v5/charts/percent-charts/grouping-slices/) --- # Legend and Pie/Sliced series – amCharts 5 Documentation This tutorial will walk through configuration options for legend content on a pie or other percent chart. Adding legend ------------- To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "index" package), push it to chart's children (or any other place we want it to be), as well as set its data (in case of a percent chart, we will probably want to use series data items as legend items). let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(series.dataItems); var legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(series.dataItems); MORE INFOFor more information on how to configure legend, its items, and layout, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. Legend label content -------------------- ### Setting content What goes into legend labels on a percent chart is controlled by four of the series' settings: | Setting key | Default | Comment | | --- | --- | --- | | `legendLabelText` | `{category}` | Text for the legend item label. | | `legendValueText` | `{valuePercentTotal.formatNumber('0.00p')}` | Text for the legend item value label. | To change contents of the legend, we simply need to set corresponding setting value: let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales", legendLabelText: "{category}", legendValueText: "{value}" }) ); var series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales", legendLabelText: "{category}", legendValueText: "{value}" }) ); Labels support [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (references to data item settings in curly brackets) so the text will be populated with actual data and values. Since each legend item is constructed out of the series data items, their data will be used to populate it, e.g. `[PieSeriesDataItem](https://www.amcharts.com/docs/v5/reference/ipieseriesdataitem/) `. ### In-line formatting Besides regular text and data placeholders, labels support square bracket [in-line formatting](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) blocks. E.g.: let series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales", legendLabelText: "\[{fill}\]{category}\[/\]", legendValueText: "\[bold {fill}\]{value}\[/\]" }) ); var series = chart.series.push( am5percent.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales", legendLabelText: "\[{fill}\]{category}\[/\]", legendValueText: "\[bold {fill}\]{value}\[/\]" }) ); The above will use slice's `fill` (color) for category and value, as well as make category names bold. Example ------- See the Pen Pie chart with external legend by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Toggle pie slice pullout via legend](https://www.amcharts.com/docs/v5/tutorials/toggle-pie-slice-pullout-via-legend/) * [Applying custom formatting logic to PieChart legend values](https://www.amcharts.com/docs/v5/tutorials/applying-custom-formatting-logic-to-piechart-legend-values/) * [Toggle multiple pie slices via legend](https://www.amcharts.com/docs/v5/tutorials/toggle-multiple-pie-slices-via-legend/) * [Toggle slices of multiple nested Pie Series with a single legend](https://www.amcharts.com/docs/v5/tutorials/toggle-slices-of-multiple-nested-pie-series-with-a-single-legend/) * [Pie chart with a custom legend](https://www.amcharts.com/docs/v5/tutorials/pie-chart-with-a-custom-legend/) --- # Pie and sliced charts – amCharts 5 Documentation This tutorial is an introduction to percent charts: pie and sliced (funnel, pyramid). It will go over the common basics before we can move on to chart-type-specific documents. Loading and creating -------------------- Both pie and sliced charts share the same module, but use different classes. Refer to the dedicated tutorials for each chart type: * [Pie chart](https://www.amcharts.com/docs/v5/charts/percent-charts/pie-chart/) * [Sliced chart](https://www.amcharts.com/docs/v5/charts/percent-charts/sliced-chart/) (funnel, pyramid, pictorial) Other topics ------------ * [Configuring percent series](https://www.amcharts.com/docs/v5/charts/percent-charts/percent-series/) * [Configuring legend](https://www.amcharts.com/docs/v5/concepts/legend/) * [Loading external data](https://www.amcharts.com/docs/v5/concepts/data/#External_data) * [Using themes](https://www.amcharts.com/docs/v5/concepts/themes/) --- # Gauge charts – amCharts 5 Documentation This tutorial will address how to build gauges using radar chart components. Creating chart -------------- In amCharts 5, we use radar chart to create gauges. That means that the process of creating a gauge is identical as creating a [radar chart](https://www.amcharts.com/docs/v5/charts/radar-chart/) : ### Loading required modules import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import \* as am5radar from "@amcharts/amcharts5/radar"; ### Creating chart instance let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5radar.RadarChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var chart = root.container.children.push( am5radar.RadarChart.new(root, {}) ); Axes ---- ### Adding axes Gauges are one-dimensional chart, that's why we will only need one circular axis here. We can use any axis type in gauge/radar, by pushing it into chart's `xAxes` list: let axis = chart.xAxes.push( am5xy.ValueAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); var axis = chart.xAxes.push( am5xy.ValueAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); ### Axis scale Since gauges do not have any actual series, its axis can't calculate it's own scale, so we will need to set it manually using axis' `min` and `max` settings: let axis = chart.xAxes.push( am5xy.ValueAxis.new(root, { min: 0, max: 100, renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); var axis = chart.xAxes.push( am5xy.ValueAxis.new(root, { min: 0, max: 100, renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); ### Grid and ticks Grid and ticks can be configured using like on any other axis: via its `grid.template` and `ticks.template`: // Create axis renderer let axisRenderer = am5radar.AxisRendererCircular.new(root, { strokeOpacity: 0.1, minGridDistance: 30 }); // Enable ticks axisRenderer.ticks.template.setAll({ visible: true, strokeOpacity: 0.5 }); // Disable grid axisRenderer.grid.template.setAll({ visible: false }); // Create axis renderer var axisRenderer = am5radar.AxisRendererCircular.new(root, { strokeOpacity: 0.1, minGridDistance: 30 }); // Enable ticks axisRenderer.ticks.template.setAll({ visible: true, strokeOpacity: 0.5 }); // Disable grid axisRenderer.grid.template.setAll({ visible: false }); For more information about configuration of grid and ticks, refer to "[Axes: Grid](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/#Grid) " and "[Axes: Ticks](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/#Ticks) ". ### Axis configuration For more information on how to configure axes - labels, ticks, grid, individual radii and angles - refer to the "[Radar axes](https://www.amcharts.com/docs/v5/charts/radar-chart/radar-axes/#Axis_radii_and_angles) " tutorial. Start/end angles ---------------- Gauges (radar chart) is not limited to a full circle. It can start and end at any angle. For that we have to chart's settings: `[startAngle](https://www.amcharts.com/docs/v5/reference/radarchart/#startAngle_setting) ` and `[radarAngle](https://www.amcharts.com/docs/v5/reference/piechart/#endAngle_setting) `. These are numeric values denoting degrees. A zero angle is one that goes from the center of the chart directly to right. Defaults are `-90` (`startAngle`) and `270` (`endAngle`) forming full circle starting at vertical line up. We can change that any way we want. let chart = root.container.children.push( am5radar.RadarChart.new(root, { startAngle: -180, endAngle: 0 }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { startAngle: -180, endAngle: 0 }) ); The above will result in a horizontal semi-circle: [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_full_circle.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_full_circle.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_half_circle.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_half_circle.png) `{ startAngle: -180, endAngle: 0 }` See the Pen Radar chart with custom angles by amCharts team (@amcharts) on CodePen. Chart radius ------------ Radar chart (which is used for gauges) have two radius settings: * `radius` - outer radius. * `innerRadius` - inner radius. Both can be either percent value (relative to available space) or fixed pixel value. `radius` is set to `80%` by default to leave some space for possible ticks and labels. `innerRadius` (default: `0`) percent value is relative to the chart's radius, rather than available space. We can also use negative values in `innerRadius`. Those will mean pixel distance from the outer radius. This allows creating fixed-width bands. The inner radius will affect grid length as well as width of the [bands](#Bands) . let chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(95), innerRadius: -20 }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(95), innerRadius: -20 }) ); For more information about chart radii settings, refer to "[Radar chart: Radius](https://www.amcharts.com/docs/v5/charts/radar-chart/#Chart_radius) ". Bands ----- To add colored bands to axis, we can use [axis ranges](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/) . ### Creating a range Creating an axis range requires: * Creating an axis data item using axis' `makeDataItem()` method. * Creating an axis range from a data item using axis' `createAxisRange()` method. * Specifying start and end value/date/category (depending on axis type used) for the range. // Create range axis data item let rangeDataItem = axis.makeDataItem({ value: 0, endValue: 70 }); // Create a range let range = axis.createAxisRange(rangeDataItem); // Create range axis data item var rangeDataItem = axis.makeDataItem({ value: 0, endValue: 70 }); // Create a range var range = axis.createAxisRange(rangeDataItem); For more information about setting start and end values depending on axis type, refer to "[Axis ranges: Range start and end](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/#Range_start_and_end) " tutorial. ### Setting fill Range fills are not visible by default. We need to configure them using `axisFill` setting, which is a generic object of type `[Graphics](https://www.amcharts.com/docs/v5/reference/graphics/) `. rangeDataItem.get("axisFill").setAll({ fill: color, fillOpacity: 0.2 }); rangeDataItem.get("axisFill").setAll({ fill: color, fillOpacity: 0.2 }); ### Band width Bad widths depend on the chart's [`radius` and `innerRadius` settings](https://www.amcharts.com/docs/v5/charts/radar-chart/gauge-charts/#Chart_radius) . let chart = root.container.children.push( am5radar.RadarChart.new(root, { innerRadius: -20 }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { innerRadius: -20 }) ); The above will make bands 2% the radius of the chart itself. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_innerradius_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_innerradius_0.png) `innerRadius: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_innerradius_90.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_innerradius_90.png) `innerRadius: -30` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_innerradius_98.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gauge_innerradius_98.png) `innerRadius: am5.percent(98)` ### Variable-width bands We can set `radius` and `innerRadius` directly on axis range fill data item, too. This way we can make each range/band specific width: rangeDataItem.get("axisFill").setAll({ visible: true, fill: color, fillOpacity: 0.8, innerRadius: -45 }); rangeDataItem.get("axisFill").setAll({ visible: true, fill: color, fillOpacity: 0.8, innerRadius: -45 }); See the Pen Gauge chart by amCharts team (@amcharts) on CodePen. ### Band labels To add labels to a band/axis range, use `label` setting: rangeDataItem.get("label").setAll({ text: "Warning", inside: true, radius: 5, fontSize: "0.9em", fill: am5.color(0xffffff) }); rangeDataItem.get("label").setAll({ text: "Warning", inside: true, radius: 5, fontSize: "0.9em", fill: am5.color(0xffffff) }); See the Pen Gauge chart by amCharts team (@amcharts) on CodePen. For more information about labels on a circular axis, refer to "[Radar axes: Labels](https://www.amcharts.com/docs/v5/charts/radar-chart/radar-axes/#Labels_on_a_circular_axis) ". Clock hands ----------- ### Adding In amCharts 5, clock hands are added as an [axis range bullet](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/#Bullet) . As a "sprite" for the axis bullet, we are going to be using special element of type `[ClockHand](https://www.amcharts.com/docs/v5/reference/clockhand/) `: let handDataItem = axis.makeDataItem({ value: 0 }); let hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, { sprite: am5radar.ClockHand.new(root, { radius: am5.percent(99) }) })); axis.createAxisRange(handDataItem); var handDataItem = axis.makeDataItem({ value: 0 }); var hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, { sprite: am5radar.ClockHand.new(root, { radius: am5.percent(99) }) })); axis.createAxisRange(handDataItem); ### Setting value #### Initial value As per code snippet above, initial hand value is set via data item's `value` setting: let handDataItem = axis.makeDataItem({ value: 55 }); var handDataItem = axis.makeDataItem({ value: 55 }); #### Dynamic value To move the clock hand to different value, all we need to do is to set `value` setting of the data item again: handDataItem.set("value", 20); handDataItem.set("value", 20); Or, if we want the hand to smoothly turn to a new value, we can [animate its `value` setting](https://www.amcharts.com/docs/v5/concepts/animations/#Animating_settings) : handDataItem.animate({ key: "value", to: 20, duration: 800, easing: am5.ease.out(am5.ease.cubic) }); handDataItem.animate({ key: "value", to: 20, duration: 800, easing: am5.ease.out(am5.ease.cubic) }); ### Radius There are three clock hand settings that effect its radii: * `radius` - radius from the center of the chart to the tip of the hand. * `innerRadius` - radius from the center of the chart to the base of the hand. * `pinRadius` - radius of the pin - a circle at the center of the chart. All radii can be either set in absolute pixel values from the center of the chart, as well as percent values. Percent values are relative to the axis radius. Radii can also be set in negative absolute value. In such case the radius will be counted from the axis, rather then from the center of the chart. let hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, { sprite: am5radar.ClockHand.new(root, { radius: am5.percent(85), innerRadius: 15, pinRadius: 10 }) })); var hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, { sprite: am5radar.ClockHand.new(root, { radius: am5.percent(85), innerRadius: 15, pinRadius: 10 }) })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_radius1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_radius1.png) (Default) `radius: am5.percent(90)` `innerRadius: 0` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_radius2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_radius2.png) `radius: am5.percent(98)` `innerRadius: 15` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_radius3.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_radius3.png) `radius: -3` `innerRadius: -15` ### Configuring hand elements #### Setting colors There are two properties on a clock hand: `hand` and `pin`. They are both elements of type `Graphics` that can be used to set basic settings like `fill` and `stroke`. hand.get("sprite").pin.setAll({ fill: am5.color(0x946b49), fillOpacity: 0.5 }); hand.get("sprite").hand.setAll({ fill: am5.color(0x946b49), fillOpacity: 0.9 }); hand.get("sprite").pin.setAll({ fill: am5.color(0x946b49), fillOpacity: 0.5 }); hand.get("sprite").hand.setAll({ fill: am5.color(0x946b49), fillOpacity: 0.9 }); Or, if we need to disable an element, we can simply set its `visible` setting: hand.get("sprite").pin.set("visible", false); hand.get("sprite").pin.set("visible", false); #### Setting hand end widths Besides radius settings, a clock hand also has two additional settings that control widths of hand's ends: * `[topWidth](https://www.amcharts.com/docs/v5/reference/clockhand/#topWidth_setting) ` - width of the hand's tip, in pixels (default: `1`). * `[bottomWidth](https://www.amcharts.com/docs/v5/reference/clockhand/#bottomWidth_setting) ` - width of the hand's base, in pixels (default: `10`). let hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, { sprite: am5radar.ClockHand.new(root, { topWidth: 5, bottomWidth: 5 }) })); var hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, { sprite: am5radar.ClockHand.new(root, { radius: am5.percent(85), topWidth: 5, bottomWidth: 5 }) })); The above will create a straight hand line, 5 pixel wide. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_hadnwidths1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_hadnwidths1.png) `topWidth: 5` `bottomWidth: 5` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_hadnwidths2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_hadnwidths2.png) `topWidth: 5` `bottomWidth: 20` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_hadnwidths3.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/clockhand_hadnwidths3.png) `topWidth: 20` `bottomWidth: 1` `radius: am5.percent(110)` `innerRadius: am5percent(102)` ### Disabling ticks and grid Clock hand is an axis data item, which in turn may have a tick and grid enabled. If we don't want those to show up next to our hand, we need to disable them: handDataItem.get("grid").set("visible", false); handDataItem.get("tick").set("visible", false); handDataItem.get("grid").set("visible", false); handDataItem.get("tick").set("visible", false); Example ------- See the Pen Gauge chart with hand by amCharts team (@amcharts) on CodePen. And here's a more advanced example, using multiple axes and hands at different start/end angles: See the Pen amCharts 5: Multi-part Gauge by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Gauge chart with custom ClockHand](https://www.amcharts.com/docs/v5/tutorials/gauge-chart-with-custom-clockhand/) (demo) --- # Radar chart – amCharts 5 Documentation Radar chart is used to create circular axis-based two-dimensional plots as well as gauges. Radar vs XY ----------- We can think of a radar chart as a round [XY chart](https://www.amcharts.com/docs/v5/charts/xy-chart/) . Under the hood, it is in fact an XY chart, inheriting all of its capabilities and functionality, except for a few differences and additions, which we will discuss during this tutorial. To keep it simple, we are going to provide bare basics here, and will not repeat vas information outlined in XY-related tutorials. In a nutshell, radar chart acts and is configured much like XY chart, except it uses different classes: | Radar class | Equivalent XY class | | --- | --- | | `RadarChart` | `XYChart` | | `RadarColumnSeries` | `ColumnSeries` | | `RadarLineSeries` | `LineSeries` | | `SmoothedRadarLineSeries` | `SmoothedXLineSeries` | | `RadarCursor` | `XYCursor` | | `AxisRendererCircular` | `AxisRendererX` | | `AxisRendererRadial` | `AxisRendererY` | Now that we have this out of the way, let's look at common components that radar chart is made of. Loading required modules ------------------------ XY Charts require three amCharts 5 modules: "index", "xy", and "radar". You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import \* as am5radar from "@amcharts/amcharts5/radar"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Instantiating the chart ----------------------- As with any chart type in amCharts 5, we'll need to start with creation of the `Root` element. In it we will create an instance of `RadarChart` class. let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5radar.RadarChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var chart = root.container.children.push( am5radar.RadarChart.new(root, {}) ); MORE INFO The notion of creating class instances using `.new()` method is described in "[Creating a chart](https://www.amcharts.com/docs/v5/getting-started/#Creating_a_chart) " section in the "Getting started" tutorial. Make sure you check it out. Adding axes ----------- A radar requires at least one circular (round axis that form a (semi)circle around the chart) and one radial (axis that start in the middle of the chart and go outwards in a straight line) axis, although it can support any number of axes. The chart has two properties: `xAxes` and `yAxes`. `xAxes` hold circular axes. `yAxes` hold radial axes. To add axes to chart we just push their instances to the respective list: let xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5radar.AxisRendererRadial.new(root, {}) }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5radar.AxisRendererRadial.new(root, {}) }) ); The above will create an radial axis of type `ValueAxis`, which is used to indicate numeric value, as well as a `DateAxis` to be used as circular axis. There are number of different axes types. We will examine those in subsequent sections. ### Axis renderer The axis object itself provides logic functionality. It relies on a helper class to actually render it. That's where "renderer" comes in. To put it differently, axis knows how to treat data, calculate scale, etc. It does not care about how it should be displayed. Renderer, knows how to put the axis on screen. For example, a `ValueAxis` on X would be drawn differently than on Y. That's why we need to specify a renderer, which "specializes" of displaying an axis in specific direction. Radar chart uses two types of renderers: `AxisRendererCircular` and `AxisRendererRadial`. ### Axis types Radar chart supports 4 axis types: | Class | Comment | | | --- | --- | --- | | `CategoryAxis` | For plotting data with string identifiers - categories. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/category-axis/) | | `CategoryDateAxis` | For plotting time-based data without maintaining actual time scale. Grid/labels are displayed only where there is actual data. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/#Category_date_axis) | | `DateAxis` | For plotting time-based data. The axis will maintain natural time scale regardless on how actual data points are spaced out. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) | | `ValueAxis` | For plotting numeric values. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/) | Some axis types require additional configuration besides renderer to work. For example `CategoryAxis` needs `categoryField` which specifies a field in data that holds category names, as well as the actual data, so that it knows which categories to display: let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(\[{\ category: "Research"\ }, {\ category: "Marketing"\ }, {\ category: "Sales"\ }\]; var xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}), categoryField: "category" }) ); xAxis.data.setAll(\[{\ category: "Research"\ }, {\ category: "Marketing"\ }, {\ category: "Sales"\ }\]; Similarly, `DateAxis` needs to know granularity of your data, set via `baseInterval` property: let xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}), baseInterval: { timeUnit: "day", count: 1 } }) ); var xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}), baseInterval: { timeUnit: "day", count: 1 } }) ); MORE INFO For information on configuring and using each axis type, please refer to the dedicated "[Axes](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/) " tutorial, or click on an axis class name in the table above. ### Configuring series For more information on how to configure axes, please visit these tutorials: * [Configuring XY (and radar) axes](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/) * [Radar-specific axes configuration](https://www.amcharts.com/docs/v5/charts/radar-chart/radar-axes/) Adding series ------------- Radar chart is a "serial" chart, meaning it needs at least one series to display anything. As with anything else in amCharts 5, we create a series object using [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) of its class. There is also a number of properties that need to be set for series, like its X and Y axis, as well as data fields. We will look at those shortly, but here's a very basic example of `RadarColumnSeries` usage: let series = chart.series.push( am5radar.RadarColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); var series = chart.series.push( am5radar.RadarColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); Let's examine the above. ### Assigning series to axis This is pretty much self-explanatory. We use series `xAxis` property to tell which axis object will be series X-axis (or circular axis), and `yAxis` to specify which axis is responsible for its Y (radial) plot. Each series can have only on X and one Y axis, whereas an axis can have any number of series attached to it. ### Data fields Since radar chart is a two-dimensional chart, each point in its series requires at least two values to be plotted: X and Y. Data fields are used to specify which fields in data hold both of those values. The name of the data field reflects its axis direction, as well as its type. "value" indicates numeric value, including time. "category" indicates string-based category. The type of data field depends on the type of axis we are using. For example, if we have a `ValueAxis` as a Y-axis, and a `CategoryAxis` as an X-axis, our series will need to define `valueYField` and `categoryXField`. Some series can define additional data fields (e.g. for open values) to draw floating columns, or semi-filled area series. MORE INFO For more information about data fields refer to "[Data fields](https://www.amcharts.com/docs/v5/concepts/series/#Data_fields) " section in our "Series" tutorial. ### Types of series Radar chart currently supports these types of series: | Class | Comment | | | --- | --- | --- | | `RadarColumnSeries` | Displays columns or bars. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/column-series/) | | `RadarLineSeries` | Displays lines or area. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/line-series/) | | `SmoothedRadarLineSeries` | Displays smoothed lines or area with configurable horizontal tension. | [More info](https://www.amcharts.com/docs/v5/charts/xy-chart/series/smoothed-series/) | NOTE The links in the above table point to tutorial for XY chart equivalent series. Don't be alarmed, it's not a mistake. Radar and XY series are configured identically. ### Configuring series For more information on how to configure series, please visit these tutorials: * [Configuring XY (and radar) series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/) * [Radar-specific series configuration](https://www.amcharts.com/docs/v5/charts/radar-chart/radar-series/) Setting data ------------ Data in radar chart is set directly to series. There is no chart-wide data storage. For that, each series has a property named `data`, which in turn is an object that can be used to supply data. The most common method for setting data is its `setAll()` method: series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); If we have more than one series, we will need to set data for each and everyone one of them, even if the data is identical. That's why it makes sense to have repeating data in a separate variable. E.g.: let data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; series1.data.setAll(data); series2.data.setAll(data); var data = \[{\ category: "Research",\ value1: 1000,\ value2: 588\ }, {\ category: "Marketing",\ value1: 1200,\ value2: 1800\ }, {\ category: "Sales",\ value1: 850,\ value2: 1230\ }\]; series1.data.setAll(data); series2.data.setAll(data); IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFO There's more ways to set, update, add, or load data. For more information please refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. ### Date-based data A quick note about date-based charts (with a `DateAxis`): they expect data to be passed in as integer numbers - JavaScript timestamps (milliseconds elapsed since the UNIX epoch). If you we have dates in any other format (as strings or `Date` objects), we'll need to set up a data processor to convert our dates to timestamps. MORE INFO For description how it works, please refer to "[Date-based data](https://www.amcharts.com/docs/v5/concepts/data/#Date_based_data) " section in our "Data" tutorial. Additional controls ------------------- ### Legend To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "index" package), push it to chart's children (or any other place we want it to be), as well as set its data (in case of XY chart, we will probably want to use series as legend items). let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); var legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); MORE INFO For more information on how to configure the legend, set its contents, and other tricks, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. ### Cursor Adding chart cursor, which is a very useful tool, providing crosshairs and other functionality, like series and axis tooltips is pretty straightforward: we just need to create an instance of `RadarCursor` (from "radar" module) and set it to chart's `cursor` property: chart.set("cursor", am5radar.RadarCursor.new(root, {})); chart.set("cursor", am5radar.RadarCursor.new(root, {})); MORE INFO For more information on how to configure the chart cursor make sure you visit "[Cursor](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/) " tutorial. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import \* as am5radar from "@amcharts/amcharts5/radar"; // Create root and chart let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5radar.RadarChart.new(root, {}) ); // Define data let data = \[{\ date: new Date(2021, 0, 1).getTime(),\ value: 100,\ value2: 220\ }, {\ date: new Date(2021, 0, 2).getTime(),\ value: 320,\ value2: 300\ }, {\ date: new Date(2021, 0, 3).getTime(),\ value: 216,\ value2: 120\ }, {\ date: new Date(2021, 0, 4).getTime(),\ value: 150,\ value2: 190\ }, {\ date: new Date(2021, 0, 5).getTime(),\ value: 156,\ value2: 190\ }, {\ date: new Date(2021, 0, 6).getTime(),\ value: 199,\ value2: 120\ }, {\ date: new Date(2021, 0, 7).getTime(),\ value: 114,\ value2: 300\ }, {\ date: new Date(2021, 0, 8).getTime(),\ value: 269,\ value2: 290\ }, {\ date: new Date(2021, 0, 9).getTime(),\ value: 190,\ value2: 290\ }, {\ date: new Date(2021, 0, 10).getTime(),\ value: 380,\ value2: 170\ }, {\ date: new Date(2021, 0, 11).getTime(),\ value: 250,\ value2: 200\ }, {\ date: new Date(2021, 0, 12).getTime(),\ value: 110,\ value2: 210\ }, {\ date: new Date(2021, 0, 13).getTime(),\ value: 185,\ value2: 85\ }, {\ date: new Date(2021, 0, 14).getTime(),\ value: 105,\ value2: 244\ }\]; // Create axes let xAxis = chart.xAxes.push( am5xy.DateAxis.new(root, { renderer: am5radar.AxisRendererCircular.new(root, {}) }) ); let yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5radar.AxisRendererRadial.new(root, {}) }) ); // Create series let series1 = chart.series.push( am5radar.RadarColumnSeries.new(root, { name: "Series #1", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date" }) ); series1.data.setAll(data); let series2 = chart.series.push( am5radar.RadarColumnSeries.new(root, { name: "Series #2", xAxis: xAxis, yAxis: yAxis, valueYField: "value2", valueXField: "date" }) ); series2.data.setAll(data); // Add legend let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // Add cursor chart.set("cursor", am5radar.RadarCursor.new(root, {}));
See the Pen Radar chart with date axis by amCharts team (@amcharts) on CodePen. Start/end angles ---------------- A radar chart is not limited to a full circle. It can start and end at any angle. For that we have to chart's settings: `[startAngle](https://www.amcharts.com/docs/v5/reference/radarchart/#startAngle_setting) ` and `[endAngle](https://www.amcharts.com/docs/v5/reference/piechart/#endAngle_setting) `. These are numeric values denoting degrees. A zero angle is one that goes from the center of the chart directly to right. Defaults are `-90` (`startAngle`) and `270` (`endAngle`) forming full circle starting at vertical line up. We can change that any way we want. let chart = root.container.children.push( am5radar.RadarChart.new(root, { startAngle: -180, endAngle: 0 }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { startAngle: -180, endAngle: 0 }) ); The above will result in a horizontal semi-circle: [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_full.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_full.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_half_circle.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_half_circle.png) `{ startAngle: -180, endAngle: 0 }` See the Pen Radar chart with date axis by amCharts team (@amcharts) on CodePen. Chart radius ------------ ### Outer radius Radar chart's outer radius can be set using its `[radius](https://www.amcharts.com/docs/v5/reference/radarchart/#radius_setting) ` setting. It can be either percent value (relative to available space) or fixed pixel value. Radar chart's `radius` is set to `80%` by default to leave some space for possible ticks and labels. If we do not need that extra space, we can increase the radius: let chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(95) }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(95) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_full-1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_full-1.png) `radius: am5.percent(80)` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_90p.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_90p.png) `radius: am5.percent(90)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_100.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radius_100.png) `radius: 100` ### Inner radius Chart's `[innerRadius](https://www.amcharts.com/docs/v5/reference/radarchart/#innerRadius_setting) ` settings controls the "hole" inside the radar. As with `radius` it can be either a percent value or fixed pixel value. The difference is that `innerRadius` percent value is relative to the chart radius, rather than available space. We can also use negative values in `innerRadius`. Those will mean pixel distance from the outer radius. This allows creating fixed-width bands. let chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(95), innerRadius: am5.percent(50) }) ); var chart = root.container.children.push( am5radar.RadarChart.new(root, { radius: am5.percent(95), innerRadius: am5.percent(50) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_full.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/radar_full.png) `innerRadius: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/innerradius_20.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/innerradius_20.png) `innerRadius: am5.percent(20)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/innerradius_50.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/innerradius_50.png) `innerRadius: am5.percent(50)` Gauge charts ------------ amCharts 5 does not have a separate gauge chart type. Please refer to "[Gauge charts](https://www.amcharts.com/docs/v5/charts/radar-chart/gauge-charts/) " tutorial on how to use radar chart to create full-featured gauges. --- # Map chart – amCharts 5 Documentation Map chart is a chart type used to display geographical maps. This tutorial walks through the basics of creating such charts. Loading required modules ------------------------ Map charts require two amCharts 5 modules: "index" and "map". You can import those in your TypeScript / ES6 application as JavScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5map from "@amcharts/amcharts5/map"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Geodata (maps) -------------- Besides modules that bring in actual functionality, we will also need to load a specific map we need to use. We call such map data "geodata". Map chart uses geodata in [GeoJSON](https://geojson.org/) format. There are hundreds of maps available for use with amCharts 5. They are available as a zipped download from our [downloads page](https://www.amcharts.com/download/) , or as an NPM package `@amcharts/amcharts5-geodata`, or via CDN. ### Geodata detail Most of the maps come in two detail versions: "low" and "high". Some global world and region maps come in three: "low", "high", and "ultra". High and ultra detail maps offer finer maps, but they're much bigger files to load, so we, as a developer, would need to weight pros and cons before choosing the correct file to use. For most setups "low" detail should be enough. ### File and directory structure #### World/country maps The name of the geodata files consist of a camel-cased country or region name, as well as detail suffix ("Low", "High", "Ultra"), e.g.: `franceHigh` or `worldLow`. World and country-maps are located in the root directory of the geodata package. They can be loaded like this: import am5geodata\_worldLow from "@amcharts/amcharts5-geodata/worldLow"; #### Regional maps Regional maps are located in their respective sub-directories, e.g. `region/usa/*`. The global name of the regional map will reflect its sub-directory structure. For example, congressional district map of Florida would load like this: import am5geodata\_region\_usa\_congressional2022\_worldLow from "@amcharts/amcharts5-geodata/region/usa/congressional2022/flLow"; MORE INFOFor more information on how to use regional maps, visit "[Using regional maps](https://www.amcharts.com/docs/v5/tutorials/using-regional-maps/) " tutorial. Instantiating the chart ----------------------- As with any chart type in amCharts 5, we'll need to start with creation of the `Root` element. In it we will create an instance of `[MapChart](https://www.amcharts.com/docs/v5/reference/mapchart/) ` class. let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5map.MapChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var chart = root.container.children.push( am5map.MapChart.new(root, {}) ); MORE INFO The notion of creating class instances using `.new()` method is described in "[Creating a chart](https://www.amcharts.com/docs/v5/getting-started/#Creating_a_chart) " section in the "Getting started" tutorial. Make sure you check it out. Adding series ------------- Map chart, like most of the charts, is a serial chart, which means that it requires at least one series to operate. We create a series by calling its [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) and pushing the new object into chart's `series` list: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow }) ); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow }) ); NOTE A `MapPolygonSeries` requires its `geoJSON` setting to bet set to a geodata of a particular map we need to show, but we'll get to that later. ### Available series types Map chart currently supports these four types of series: | Class | Comment | | | --- | --- | --- | | `MapPolygonSeries` | Used to display shapes of countries and other regions (polygons). | [More info](https://www.amcharts.com/docs/v5/charts/map-chart/map-polygon-series/) | | `MapLineSeries` | Used to draw lines on the map. | [More info](https://www.amcharts.com/docs/v5/charts/map-chart/map-line-series/) | | `MapPointSeries` | Used to put markers on the map. | [More info](https://www.amcharts.com/docs/v5/charts/map-chart/map-point-series/) | | `GraticuleSeries` | Used to display a map grid. | [More info](https://www.amcharts.com/docs/v5/charts/map-chart/graticule-series/) | For most of the map chart setups, it will require at least one polygon series to make sense. Projections ----------- ### Setting a projection There's a lot of ways to translate spherical surface of a planet into a flat map. In cartography those are called projections. To specify which projection to use, set chart's `[projection](https://www.amcharts.com/docs/v5/reference/mapchart/#projection_setting) ` setting: let chart = root.container.children.push( am5map.MapChart.new(root, { projection: am5map.geoMercator() }) ); var chart = root.container.children.push( am5map.MapChart.new(root, { projection: am5map.geoMercator() }) ); ### Built-in projections Map chart supports a number of built-in projections: | Projection | Function name | Sample | | --- | --- | --- | | Albers USA (only suitable for U.S. maps) | `am5map.geoAlbersUsa()` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_usaalbers.png) | | Equal Earth | `am5map.geoEqualEarth()` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_qualearth.png) | | Equirectangular | `am5map.geoEquirectangular()` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_equirectangular.png) | | Mercator (default) | `am5map.geoMercator()` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_mercator.png) | | Natural Earth 1 | `am5map.geoNaturalEarth1()` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_naturalearth1.png) | | Orthographic (globe) | `am5map.geoOrthographic()` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_orthographic.png) | ### Using D3 projections There are more projections available than the list above. Map chart supports projections from the [d3-geo-projection](https://github.com/d3/d3-geo-projection) library. Since those are not bundled with amCharts, you may need to load load them as modules from [d3-geo-projection NPM package](https://www.npmjs.com/package/d3-geo-projection) or compiled JS binaries from some CDN: import {geoAitoff} from "d3-geo-projection@4"; Then it's just as easy as setting `projection` on a `MapChart`: let chart = root.container.children.push( am5map.MapChart.new(root, { projection: geoAitoff }) ); var chart = root.container.children.push( am5map.MapChart.new(root, { projection: d3.geoAitoff }) ); See the Pen amCharts 5: Using D3 map projections by amCharts team (@amcharts) on CodePen. Panning ------- There is a number of options for us when it comes how map behaves when is dragged (either with mouse or by touch). Those are controlled by map chart's `panX` and `panY` settings. The former controls what happens when dragged horizontally, and the latter - vertically. For example, we can set up the map to rotate endlessly horizontally using `panX: "rotateX"`: let chart = root.container.children.push( am5map.MapChart.new(root, { panX: "rotateX" }) ); var chart = root.container.children.push( am5map.MapChart.new(root, { panX: "rotateX" }) ); For more information, refer to "[Panning and zooming the map](https://www.amcharts.com/docs/v5/charts/map-chart/map-pan-zoom/) " tutorial. Zooming ------- Zooming of the map can be done in a number of ways: zoom control, mouse wheel or pinch gestures, API, or custom events. For more information, refer to "[Panning and zooming the map](https://www.amcharts.com/docs/v5/charts/map-chart/map-pan-zoom/) " tutorial. Centering the map ----------------- The map will center itself in the coordinate between its boundaries. On a world map that is usually zero coordinate: 0 latitude / 0 longitude. We can re-center the map using its `rotationX` (longitude), `rotationY` (latitude), and/or `rotationZ` (Z axis). ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/rotationX.png) `rotationX` ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/rotationY.png) `rotationY` ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/rotationZ.png) `rotationZ` They are numeric settings to shift map center by certain amount of degrees. To have a map centered on a Pacific ocean, we could do this: let chart = root.container.children.push( am5map.MapChart.new(root, { rotationX: -160 }) ); var chart = root.container.children.push( am5map.MapChart.new(root, { rotationX: -160 }) ); Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5map from "@amcharts/amcharts5/map"; import am5geodata\_worldLow from "@amcharts/amcharts5-geodata/worldLow"; // Create root and chart let root = am5.Root.new("chartdiv"); let chart = root.container.children.push( am5map.MapChart.new(root, { panX: "rotateX", projection: am5map.geoNaturalEarth1() }) ); // Create polygon series let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow, exclude: \["AQ"\] }) );
See the Pen Map chart by amCharts team (@amcharts) on CodePen. Map background -------------- There are a couple of ways to attach a background (water fill) for the map. Both of them are described in "[Map polygon series: Background polygon](https://www.amcharts.com/docs/v5/charts/map-chart/map-polygon-series/#Background_polygon) " tutorial. Heat maps --------- It's possible to create heat maps (choropleth) maps using heat rules. For detailed instructions and live samples, make sure to check "[Heat rules](https://www.amcharts.com/docs/v5/concepts/settings/heat-rules/) " tutorial. Additional controls ------------------- ### Zoom control Map chart supports built-in control that adds zooming chart via handy buttons. To add it, simply instantiate a `ZoomControl` and set it to map chart's `zoomControl` setting. chart.set("zoomControl", am5map.ZoomControl.new(root, {})); chart.set("zoomControl", am5map.ZoomControl.new(root, {})); For more information, refer to "[Panning and zooming the map: Zoom control](https://www.amcharts.com/docs/v5/charts/map-chart/map-pan-zoom/#Zoom_control) " tutorial. Related tutorials ----------------- * [MapChart with an auto-populated legend](https://www.amcharts.com/docs/v5/tutorials/mapchart-with-an-auto-populated-legend/) --- # Map polygon series – amCharts 5 Documentation Map polygon series are responsible for drawing actual map areas (countries, regions, etc.). This tutorial takes a look at various angles we can use them. Adding series ------------- To create a map polygon series we need to call its [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) and push the new object into chart's `series` list: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow }) ); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow }) ); Data ---- As with any series, polygon series needs some kind of data to operate. In case of a map series it can be either GeoJSON format or a plain data format. ### Geodata/GeoJSON The GeoJSON data is set via series `geodata` setting. amCharts 5 has a number of various country and region maps in a separate geodata package available as a downloadable ZIP file, NPM package, or CDN. File locations and naming for specific maps, as well as various detail version is described in main "[Map chart: Geodata (maps)](https://www.amcharts.com/docs/v5/charts/map-chart/#Geodata_maps_) " tutorial. Please make sure to visit it for reference. Ads an example, let's load a map of France: import worldLow from "@amcharts/amcharts5/geodata/franceLow"; Then use it for a polygon series: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_franceLow }) ); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_franceLow }) ); ### Plain data It's also possible to pass in generic data to series via its `data` property. The items in map polygon series need to be in GeoJSON geometry format, e.g.: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, {}) ); polygonSeries.data.push({ geometry: { type: "Polygon", coordinates: \[\ \[\ \[26.5936, 55.6676\],\ \[26.175, 55.0033\],\ \[25.8594, 54.9192\],\ \[25.5473, 54.3317\],\ \[24.7683, 53.9746\],\ \[23.4845, 53.9398\],\ \[23.37, 54.2005\],\ \[22.7663, 54.3568\],\ \[22.8311, 54.8384\],\ \[21.2358, 55.2641\],\ \[21.0462, 56.07\],\ \[22.0845, 56.4067\],\ \[24.1206, 56.2642\],\ \[24.9032, 56.3982\],\ \[26.5936, 55.6676\]\ \]\ \] } }); let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, {}) ); polygonSeries.data.push({ geometry: { type: "Polygon", coordinates: \[\ \[\ \[26.5936, 55.6676\],\ \[26.175, 55.0033\],\ \[25.8594, 54.9192\],\ \[25.5473, 54.3317\],\ \[24.7683, 53.9746\],\ \[23.4845, 53.9398\],\ \[23.37, 54.2005\],\ \[22.7663, 54.3568\],\ \[22.8311, 54.8384\],\ \[21.2358, 55.2641\],\ \[21.0462, 56.07\],\ \[22.0845, 56.4067\],\ \[24.1206, 56.2642\],\ \[24.9032, 56.3982\],\ \[26.5936, 55.6676\]\ \]\ \] } }); The above will create a polygon series with a rough outline of Lithuania as a single polygon in it. amCharts 5 also comes with some handy utility functions, that can generate geometry data for a square or a circle: | Function | Comment | | --- | --- | | `[am5map.getGeoCircle](https://www.amcharts.com/docs/v5/reference/maputils_module/#getGeoCircle_method) (geoPoint, radius)` | Returns a geography data representing a circle with a center at specific latitude/longitude (first parameter) and radius (degrees). | | `[am5map.getGeoRectangle](https://www.amcharts.com/docs/v5/reference/maputils_module/#getGeoRectangle_method) (north, east, south, west)` | Returns a geography data representing a square with boundaries at passed in via the four parameters. | Here's how we would put a circle-shaped polygon, over Paris, France: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, {}) ); polygonSeries.data.push({ geometry: am5map.getGeoCircle({ latitude: 48.86, longitude: 2.35 }, 2) }); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, {}) ); polygonSeries.data.push({ geometry: am5map.getGeoCircle({ latitude: 48.86, longitude: 2.35 }, 2) }); NOTE Regardless of how we add data to the polygon series, it will be reshaped according to the [projection](https://www.amcharts.com/docs/v5/charts/map-chart/#Projections) used on the map. ### Using geodata and data together It's also possible to set both `geodata` and `data`. It's a good way to supplement geodata with additional values and other properties via data. Polygon series will automatically merge data located in both data sources using `id` field as a binding link. For example, we can assign name and value to certain polygons from geodata using entries in `data`: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow }) ); polygonSeries.data.setAll(\[{\ id: "FR",\ name: "France",\ value: 100\ }, {\ id: "ES",\ name: "Spain",\ value: 200\ }\]); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow }) ); polygonSeries.data.setAll(\[{\ id: "FR",\ name: "France",\ value: 100\ }, {\ id: "ES",\ name: "Spain",\ value: 200\ }\]); Now, the series will use items from `worldLow` map, but will also attach additional `value` to France and Spain, as well as override their `name` attribute. IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. Configuring polygon appearance ------------------------------ Polygon appearance can be configured via its template, accessible via series' `mapPolygons.template`. A polygon is an object of type `MapPolygon`. Any of [its settings](https://www.amcharts.com/docs/v5/reference/mappolygon/#Settings) can be set via template. polygonSeries.mapPolygons.template.setAll({ stroke: am5.color(0xffffff), strokeWidth: 2, fillOpacity: 0.5 }); polygonSeries.mapPolygons.template.setAll({ stroke: am5.color(0xffffff), strokeWidth: 2, fillOpacity: 0.5 }); Polygon fill and outline colors can also be set directly via polygon series' settings `fill` and `stroke`: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow, fill: am5.color(0x22ff55), stroke: am5.color(0xffffff) }) ); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: am5geodata\_worldLow, fill: am5.color(0x22ff55), stroke: am5.color(0xffffff) }) ); Binding to data --------------- Polygons can take values for theirs settings from data as well, using [template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) . Template fields allow binding an object's properties in series' data, to polygon template's settings. polygonSeries.mapPolygons.template.setAll({ tooltipText: "{name}", templateField: "polygonSettings" }); polygonSeries.mapPolygons.template.setAll({ tooltipText: "{name}", templateField: "polygonSettings" }); An here's how the data on series might look like if we wanted to add specific color for Canada, United States, and Mexico: polygonSeries.data.setAll(\[{\ id: "US",\ polygonSettings: {\ fill: am5.color(0xFF3C38)\ }\ }, {\ id: "CA",\ polygonSettings: {\ fill: am5.color(0xA23E48)\ }\ }, {\ id: "MX",\ polygonSettings: {\ fill: am5.color(0xFF8C42)\ }\ }\]) polygonSeries.data.setAll(\[{\ id: "US",\ polygonSettings: {\ fill: am5.color(0xFF3C38)\ }\ }, {\ id: "CA",\ polygonSettings: {\ fill: am5.color(0xA23E48)\ }\ }, {\ id: "MX",\ polygonSettings: {\ fill: am5.color(0xFF8C42)\ }\ }\]) See the Pen Using templateDield in MapPolygonSeries by amCharts team (@amcharts) on CodePen. Hover behavior -------------- ### Adding tooltips To add a tooltip to the polygons, we can use `tooltipText` on polygon template. We can set `tooltipText` along any other polygon's settings. The value may contain [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) as well as [in-line text styles](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) . polygonSeries.mapPolygons.template.setAll({ tooltipText: "{name}" }); polygonSeries.mapPolygons.template.setAll({ tooltipText: "{name}" }); ### Hover states We can set setting values to apply to polygons when it is hovered by creating a "hover" [state](https://www.amcharts.com/docs/v5/concepts/settings/states/) for it. polygonSeries.mapPolygons.template.setAll({ tooltipText: "{name}", interactive: true }); polygonSeries.mapPolygons.template.states.create("hover", { fill: am5.color(0x677935) }); polygonSeries.mapPolygons.template.setAll({ tooltipText: "{name}", interactive: true }); polygonSeries.mapPolygons.template.states.create("hover", { fill: am5.color(0x677935) }); NOTE Adding a "hover" state does not automatically turn on interactivity for the element, so we need to do that manually by setting its `interactive` setting to `true`. See the Pen Map chart by amCharts team (@amcharts) on CodePen. Click events ------------ If we need to handle a click event on series' polygons, we can add it to its template, too: polygonSeries.mapPolygons.template.events.on("click", function(ev) { console.log("Clicked on", ev.target.dataItem.get("name")); }); polygonSeries.mapPolygons.template.events.on("click", function(ev) { console.log("Clicked on", ev.target.dataItem.get("name")); }); This can be used to add click-through to polygons, by adding target URL into data: polygonSeries.data.setAll(\[{\ id: "US",\ url: "https://en.wikipedia.org/wiki/United\_States"\ }, {\ id: "CA",\ url: "https://en.wikipedia.org/wiki/Canada"\ }, {\ id: "MX",\ url: "https://en.wikipedia.org/wiki/Mexico"\ }\]); polygonSeries.data.setAll(\[{\ id: "US",\ url: "https://en.wikipedia.org/wiki/United\_States"\ }, {\ id: "CA",\ url: "https://en.wikipedia.org/wiki/Canada"\ }, {\ id: "MX",\ url: "https://en.wikipedia.org/wiki/Mexico"\ }\]); And implementing the "click" event handler: polygonSeries.mapPolygons.template.events.on("click", function(ev) { const url = ev.target.dataItem.dataContext.url; if(url) { window.location.href = ev.target.dataItem.dataContext.url; } }); polygonSeries.mapPolygons.template.events.on("click", function(ev) { var url = ev.target.dataItem.dataContext.url; if(url) { window.location.href = ev.target.dataItem.dataContext.url; } }); Excluding or including polygons ------------------------------- Series can be set up to either exclude certain polygons out of the loaded geodata, or only include specific ones. To exclude polygons use series setting `exclude`, which is an array of polygon ids: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: worldLow, exclude: \["AQ"\] }) ); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: worldLow, exclude: \["AQ"\] }) ); The above will remove Antarctica from the map. If we'd like to include only specific polygons from map, we can use `include` setting instead: let polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: worldLow, include: \["US", "CA", "MX"\] }) ); var polygonSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: worldLow, include: \["US", "CA", "MX"\] }) ); The above will shown countries from North America, even though `worldLow` contains all the countries of the world. Overlaid polygon series ----------------------- Map chart allows any number of series to be added. We can use several series with different geodata to create hybrid maps, for example a world map with U.S. state subdivisions: let worldSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: worldLow, exclude: \["AQ"\] }) ); let usaSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: usaLow }) ); var worldSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: worldLow, exclude: \["AQ"\] }) ); var usaSeries = chart.series.push( am5map.MapPolygonSeries.new(root, { geoJSON: usaLow }) ); Background polygon ------------------ We can set background fill color for our map chart by creating a background rectangle on the chart itself: chart.chartContainer.set("background", am5.Rectangle.new(root, { fill: am5.color(0xd4f1f9), fillOpacity: 1 })); chart.chartContainer.set("background", am5.Rectangle.new(root, { fill: am5.color(0xd4f1f9), fillOpacity: 1 })); While it may work for some maps, it might look awkward for others, because chart background is just a square and is not affected by projection. To create a true background, which would follow projection, we can create a separate polygon series with a single item - a square spanning the whole scope of longitude and latitude of the world. We can create the square geometry using helper function `am5map.getGeoRectangle()`: let backgroundSeries = chart.series.unshift( am5map.MapPolygonSeries.new(root, {}) ); backgroundSeries.mapPolygons.template.setAll({ fill: am5.color(0xd4f1f9), stroke: am5.color(0xd4f1f9), }); backgroundSeries.data.push({ geometry: am5map.getGeoRectangle(90, 180, -90, -180) }); var backgroundSeries = chart.series.unshift( am5map.MapPolygonSeries.new(root, {}) ); backgroundSeries.mapPolygons.template.setAll({ fill: am5.color(0xd4f1f9), stroke: am5.color(0xd4f1f9), }); backgroundSeries.data.push({ geometry: am5map.getGeoRectangle(90, 180, -90, -180) }); NOTE Series follow the order in which they were added to the chart. To ensure that background series is in the back, we need to add it first, or (as per code snippet above) we can ensure that it is inserted at index zero using `unshift()` method instead of `push()`. ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_background.png) Setting background on chart ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/map_background_via_series.png) Using background series with projected rectangle See the Pen Map chart by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Country-specific world maps](https://www.amcharts.com/docs/v5/tutorials/country-specific-world-maps/) * [Getting series object by its ID](https://www.amcharts.com/docs/v5/charts/map-chart/map-api/#Getting_object_by_ID) * [Maps with displaced areas and dividers](https://www.amcharts.com/docs/v5/tutorials/maps-with-displaced-areas-and-dividers/) * [MapChart with an auto-populated legend](https://www.amcharts.com/docs/v5/tutorials/mapchart-with-an-auto-populated-legend/) --- # Map line series – amCharts 5 Documentation Map line series are used to plot projected lines on the map. Adding series ------------- To create a map line series we need to call its [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) and push the new object into chart's `series` list: let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { // ... }) ); var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { // ... }) ); Configuring lines ----------------- ### Appearance Lines are configured using series' `mapLines.template`, which can be used to set any `MapLine` [setting](https://www.amcharts.com/docs/v5/reference/mapline/#Settings) . lineSeries.mapLines.template.setAll({ stroke: am5.color(0xff0000), strokeWidth: 2, strokeOpacity: 0.5 }); lineSeries.mapLines.template.setAll({ stroke: am5.color(0xff0000), strokeWidth: 2, strokeOpacity: 0.5 }); Line color can also be set directly via polygon series' setting `stroke`: let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { stroke: am5.color(0x22ff55) }) ); var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { stroke: am5.color(0x22ff55) }) ); ### Curved or straight Lines between two points will follow shortest distance, meaning that it will most probably look curved, based on the projection of the map. This can be configured using `lineType` setting of the series. There are two options: * `"curved"` (default) - follows shortest distance. Can cross -180/180 longitude. * `"straight"` - will connect two points with a visually straight line. Will not cross -180/180 longitude. let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { lineType: "straight" }) ); var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { lineType: "straight" }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/chrome_2022-09-27_12-29-01-1024x637.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/chrome_2022-09-27_12-29-01.png) `lineType: "curved"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/2022-09-27_12-29-14-1024x637.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/2022-09-27_12-29-14.png) `lineType: "straight"` Data ---- There is a number of ways to add data to series. Let's explore them. ### GeoJSON Line series accepts data in GeoJSON format. It will pick out features of type `LineString` and `MultiLineString`. Here's an example of a simple GeoJSON data, depicting flight route: JFK > Heathrow > Beijing. { "type": "FeatureCollection", "features": \[{\ "type": "Feature",\ "properties": {\ },\ "geometry": {\ "type": "LineString",\ "coordinates": \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \]\ }\ }\] } We can set such data directly to series `geoJSON` property: let routes = { "type": "FeatureCollection", "features": \[{\ "type": "Feature",\ "properties": {\ },\ "geometry": {\ "type": "LineString",\ "coordinates": \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \]\ }\ }\] }; // Create line series let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { geoJSON: routes }) ); var routes = { "type": "FeatureCollection", "features": \[{\ "type": "Feature",\ "properties": {\ },\ "geometry": {\ "type": "LineString",\ "coordinates": \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \]\ }\ }\] }; // Create line series var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, { geoJSON: routes }) ); See the Pen Map with line series by amCharts team (@amcharts) on CodePen. ### Plain data Another way to set data is via series `data` interface. Each item in data needs to have at least `geometry` key in it, that identifies line points. Basically, it's a subset of a GeoJSON format: lineSeries.data.setAll(\[{\ "geometry": {\ "type": "LineString",\ "coordinates": \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \]\ }\ }\]); lineSeries.data.setAll(\[{\ "geometry": {\ "type": "LineString",\ "coordinates": \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \]\ }\ }\]); See the Pen Map with line series by amCharts team (@amcharts) on CodePen. ### Individual data items We can also use series `pushDataItem()` method to add data lines one-by-one. The parameter is an object that adheres to `[IMapLineSeriesDataItem](https://www.amcharts.com/docs/v5/reference/imaplineseriesdataitem/) ` interface. lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \] } }); lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \] } }); See the Pen Mal line and point series used together by amCharts team (@amcharts) on CodePen. Or, if we have a map line series with points we'd like to connect, we can use `pointsToConnect` instead of `geometry`. See "[Connecting line series points](#Connecting_line_series_points) " section of this tutorial for further info. Relation to point series ------------------------ ### Connecting line series points We can use actual data items from a [map point series](https://www.amcharts.com/docs/v5/charts/map-chart/map-point-series/) as points for the line. This eliminates the need to define `geometry` for our lines, as we can use `pointsToConnect` setting instead, which is an array of map line series' data items: // Create point series let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); let nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 }); let london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 }); let beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 }); // Create line series let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); lineSeries.pushDataItem({ pointsToConnect: \[nyc, london, beijing\] }); // Create point series var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); var nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 }); var london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 }); var beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 }); // Create line series var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); lineSeries.pushDataItem({ pointsToConnect: \[nyc, london, beijing\] }); See the Pen Map with line series via data by amCharts team (@amcharts) on CodePen. ### Points on a line This can also work the other way around: we can make a data item form map line series "stick" to any point on a line. All we have to do is to set `lineDataItem` to a data item of the specific line, as well as `positionOnLine` to indicate relative position, when creating a point series data item: // Create line series let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); let route = lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \] } }); // Create point series let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); }); let plane = pointSeries.pushDataItem({ lineDataItem: route, positionOnLine: 0.7, autoRotate: true }); // Create line series var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); var route = lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \] } }); // Create point series var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); }); var plane = pointSeries.pushDataItem({ lineDataItem: route, positionOnLine: 0.7, autoRotate: true }); Let's examine the code above. The `pointSeries.pushDataItem()` creates a new point in point (item) series. Normally it would contain a latitude/longitude information, but since we're sticking it to a line, we use different settings: | Setting key | Comment | | --- | --- | | `lineDataItem` | A data item from map line series. Created with `pushDataItem()` on a line series, or extracted from series `dataItems`. | | `positionOnLine` | Relative position on the line. `0` (zero) means the beginning, and `1` (one) the end. Any intermediate number will indicate relative position along the whole line.
In case the line is multi-segmented, the position is calculated from the beginning of the first segment to the end of the last one. | | `autoRotate` | If set to `true`, point bullet will be automatically rotated to the angle of the exact point in line. | | `autoRotateAngle` | If set, this will be added to the angle calculated by `autoRotate`. Can be used to reverse the direction. | The below example uses above code, albeit with the slightly more sophisticated image as a point bullet: See the Pen Map line and point series used together by amCharts team (@amcharts) on CodePen. --- # Clustered point series – amCharts 5 Documentation Clustered point series (`ClusteredPointSeries`) is basically a regular map point series (`MapPointSeries`) except with an added capability of automatically closely located bullets into groups, so they do not overlap. The groups would update automatically when zooming and panning the map. Creating series --------------- We create clustered point series, configure itself and its bullets, set data, exactly the same way as regular map point series, except instead of using `MapPointSeries` class, we use `ClusteredPointSeries`. let pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { // ... }) ); var pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { // ... }) ); MORE INFOPlease refer to "[Map point series](https://www.amcharts.com/docs/v5/charts/map-chart/map-point-series/) " documentation for info on how to configure series markers (bullets), series itself, as well as set data. Configuring ----------- ### Minimal distance Clustered point series automatically groups bullets that are closer than 20 pixels between each other. We can change this value using series' `minDistance` setting: let pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { minDistance: 30 }) ); var pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { minDistance: 30 }) ); ### Scatter settings When the map is nearing its maximum allowed zoom level (95% by default), all groups are exploded to reveal all bullets, even if they are located closer than `minDistance`. In such case, in order for them to not overlap, they will be automatically scattered. We can control the distance and presumed radius of such bullet so they are scattered in such a way that they do not overlap, or overlap only partially, using series settings `scatterDistance` and `scatterRadius` respectively. We can also control the zoom point at which the scattering is applied using `stopClusterZoom` setting (default: `0.95`). let pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { minDistance: 30, scatterDistance: 10, scatterRadius: 10, stopClusterZoom: 0.9 }) ); var pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { minDistance: 30, scatterDistance: 10, scatterRadius: 10, stopClusterZoom: 0.9 }) ); ### Group segregation In some cases we might want to restrict bullets to group only with a set of other bullets. For example, we might want to force bullets from one continent to group only with bullets from the same continent. That's where series setting `groupIdField` comes in. Using it, we can specify which field on series' data holds group id. let pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { groupIdField: "group" }) ); var pointSeries = chart.series.push( am5map.ClusteredPointSeries.new(root, { groupIdField: "group" }) ); Group bullet ------------ We also need to define a special bullet to be used when several regular bullets are grouped. It is defined like regular bullet in series, except instead of pushing it into `bullets`, we set it as a series' `clusteredBullet` setting. As with any regular bullets, it should return a `Bullet` object, and can contain any visual elements. ### Basic bullet Let's start with a very basic bullet, which shows a circle: pointSeries.set("clusteredBullet", function(root) { let circle = am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) }); return am5.Bullet.new(root, { sprite: circle }); }); pointSeries.set("clusteredBullet", function(root) { var circle = am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) }); return am5.Bullet.new(root, { sprite: circle }); }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/image-1024x717.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/image.png) ### Multi-element bullet Bullet can contain any elements, including a `Container` with multiple children. Let's enhance the bullet to use multiple concentric circles. pointSeries.set("clusteredBullet", function(root) { const container = am5.Container.new(root, { }); const circle1 = container.children.push(am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) })); const circle2 = container.children.push(am5.Circle.new(root, { radius: 12, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); const circle3 = container.children.push(am5.Circle.new(root, { radius: 16, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); return am5.Bullet.new(root, { sprite: container }); }); pointSeries.set("clusteredBullet", function(root) { var container = am5.Container.new(root, {}); var circle1 = container.children.push(am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) })); var circle2 = container.children.push(am5.Circle.new(root, { radius: 12, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var circle3 = container.children.push(am5.Circle.new(root, { radius: 16, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); return am5.Bullet.new(root, { sprite: container }); }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/image-1-1024x717.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/image-1.png) ### Bullet with count We can also add a `Label` element to our bullet to show the number of regular bullets that went into a group bullet. Since every bullet element has also access to bullet's data item, we can use [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) to dynamically populate our label. pointSeries.set("clusteredBullet", function(root) { const container = am5.Container.new(root, {}); const circle1 = container.children.push(am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) })); const circle2 = container.children.push(am5.Circle.new(root, { radius: 12, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); const circle3 = container.children.push(am5.Circle.new(root, { radius: 16, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var label = container.children.push(am5.Label.new(root, { centerX: am5.p50, centerY: am5.p50, fill: am5.color(0xffffff), populateText: true, fontSize: "8", text: "{value}" })); return am5.Bullet.new(root, { sprite: container }); }); pointSeries.set("clusteredBullet", function(root) { var container = am5.Container.new(root, {}); var circle1 = container.children.push(am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) })); var circle2 = container.children.push(am5.Circle.new(root, { radius: 12, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var circle3 = container.children.push(am5.Circle.new(root, { radius: 16, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var label = container.children.push(am5.Label.new(root, { centerX: am5.p50, centerY: am5.p50, fill: am5.color(0xffffff), populateText: true, fontSize: "8", text: "{value}" })); return am5.Bullet.new(root, { sprite: container }); }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/image-2-1024x717.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/image-2.png) Drill-down ---------- Now, let's set up drill-down, so that when you click on a group bullet, the map zooms just enough so that all elements in that group become visible separately. For that we need to set up `click` event on our bullet, which would in turn invoke series' `zoomToCluster()` method. `zoomToCluster()` method accepts group bullet's data item as a parameter. It also has an optional second Boolean parameter, which indicates whether we want to rotate the map so that it is centered on the group. It is recommended to use `true` as a second parameter on a map with Orthographic (globe) projection. pointSeries.set("clusteredBullet", function(root) { const container = am5.Container.new(root, { cursorOverStyle:"pointer" }); const circle1 = container.children.push(am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) })); const circle2 = container.children.push(am5.Circle.new(root, { radius: 12, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); const circle3 = container.children.push(am5.Circle.new(root, { radius: 16, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var label = container.children.push(am5.Label.new(root, { centerX: am5.p50, centerY: am5.p50, fill: am5.color(0xffffff), populateText: true, fontSize: "8", text: "{value}" })); container.events.on("click", function(e) { pointSeries.zoomToCluster(e.target.dataItem); }); return am5.Bullet.new(root, { sprite: container }); }); pointSeries.set("clusteredBullet", function(root) { var container = am5.Container.new(root, { cursorOverStyle:"pointer" }); var circle1 = container.children.push(am5.Circle.new(root, { radius: 8, tooltipY: 0, fill: am5.color(0xff8c00) })); var circle2 = container.children.push(am5.Circle.new(root, { radius: 12, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var circle3 = container.children.push(am5.Circle.new(root, { radius: 16, fillOpacity: 0.3, tooltipY: 0, fill: am5.color(0xff8c00) })); var label = container.children.push(am5.Label.new(root, { centerX: am5.p50, centerY: am5.p50, fill: am5.color(0xffffff), populateText: true, fontSize: "8", text: "{value}" })); container.events.on("click", function(e) { pointSeries.zoomToCluster(e.target.dataItem); }); return am5.Bullet.new(root, { sprite: container }); }); Examples -------- #### World map with clustered points See the Pen Map with clustered points by amCharts team (@amcharts) on CodePen. #### US map with segregated clusters by state See the Pen US map with state-grouped clustered points by amCharts team (@amcharts) on CodePen. --- # Map point series – amCharts 5 Documentation Map point series can be used to add points (markers) at specific coordinates on the map. Adding series ------------- To create a map line series we need to call its [`new()` method](https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax) and push the new object into chart's `series` list: let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... }) ); var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... }) ); Markers ------- ### Marker template Markers (or points) on a map point series are bullets. We create them like on any other series: by pushing a function that returns `Bullet` object into `bullets` list of the series. It can be any visual element, from as simple as a `Circle` or a `Label`, to a full-fledged chart. pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); }); pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); }); Whenever a point/marker will need to be created (as per data explained below), series will call the bullet function to create an actual element. ### Auto-scaling markers Markers (bullets) will stay the same size when map is panned or zoomed. If we'd rather they grew when zoomed in (and shrank when zoomed out), we can set series' `autoScale` property to `true`. let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... autoScale: true }) ); var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... autoScale: true }) ); Data ---- There is a number of ways to add data to series. Let's explore them. ### GeoJSON Point series accepts data in GeoJSON format. It will pick out features of type `Point` and `MultiPoint`. Here's an example of a simple GeoJSON data, depicting three points: New York City, London, and Beijing. { "type": "FeatureCollection", "features": \[{\ "type": "Feature",\ "properties": {\ "name": "New York City"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[-73.778137, 40.641312\]\ }\ }, {\ "type": "Feature",\ "properties": {\ "name": "London"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[-0.454296, 51.470020\]\ }\ }, {\ "type": "Feature",\ "properties": {\ "name": "Beijing"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[116.597504, 40.072498\]\ }\ }\] } We can set such data directly to series `geoJSON` property: let cities = { "type": "FeatureCollection", "features": \[{\ "type": "Feature",\ "properties": {\ "name": "New York City"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[-73.778137, 40.641312\]\ }\ }, {\ "type": "Feature",\ "properties": {\ "name": "London"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[-0.454296, 51.470020\]\ }\ }, {\ "type": "Feature",\ "properties": {\ "name": "Beijing"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[116.597504, 40.072498\]\ }\ }\] }; let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { geoJSON: cities }) ); var cities = { "type": "FeatureCollection", "features": \[{\ "type": "Feature",\ "properties": {\ "name": "New York City"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[-73.778137, 40.641312\]\ }\ }, {\ "type": "Feature",\ "properties": {\ "name": "London"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[-0.454296, 51.470020\]\ }\ }, {\ "type": "Feature",\ "properties": {\ "name": "Beijing"\ },\ "geometry": {\ "type": "Point",\ "coordinates": \[116.597504, 40.072498\]\ }\ }\] }; var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { geoJSON: cities }) ); See the Pen Map line and point series used together by amCharts team (@amcharts) on CodePen. ### Plain data Another way to set data is via series `data` interface. There are two ways to do that: * Arrays containing objects with GeoJSON-like geometry syntax. * Arrays of objects containing proprietary keys bound to series via its `latitudeField` and `longitudeField` settings. #### Using GeoJSON-like geometry With this approach, each item in data needs to have at least `geometry` key in it, that identifies points. Basically, it's a subset of a GeoJSON format: pointSeries.data.setAll(\[{\ geometry: {\ type: "Point",\ coordinates: \[-73.778137, 40.641312\]\ }\ }, {\ geometry: {\ type: "Point",\ coordinates: \[-0.454296, 51.470020\]\ }\ }, {\ geometry: {\ type: "Point",\ coordinates: \[116.597504, 40.072498\]\ }\ }\]); pointSeries.data.setAll(\[{\ geometry: {\ type: "Point",\ coordinates: \[-73.778137, 40.641312\]\ }\ }, {\ geometry: {\ type: "Point",\ coordinates: \[-0.454296, 51.470020\]\ }\ }, {\ geometry: {\ type: "Point",\ coordinates: \[116.597504, 40.072498\]\ }\ }\]); See the Pen Map point series with GeoJSON by amCharts team (@amcharts) on CodePen. #### Using custom data fields This approach requires setting series' `latitudeField` and `longitudeField` to indicate which keys in data hold latitude and longitude values. While it requires additional configuration, it allows data to be considerably simpler: var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "long" })); pointSeries.data.setAll(\[{\ long: -73.778137,\ lat: 40.641312\ }, {\ long: -0.454296,\ lat: 51.470020\ }, {\ long: 116.597504,\ lat: 40.072498\ }\]); var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "long" })); pointSeries.data.setAll(\[{\ long: -73.778137,\ lat: 40.641312\ }, {\ long: -0.454296,\ lat: 51.470020\ }, {\ long: 116.597504,\ lat: 40.072498\ }\]); See the Pen Map point series with data and datafields by amCharts team (@amcharts) on CodePen. IMPORTANT It's a good practice to make sure setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. ### Individual data items We can also use series `pushDataItem()` method to add data points one-by-one. The parameter is an object that adheres to `[IMapPointSeriesDataItem](https://www.amcharts.com/docs/v5/reference/imappointseriesdataitem/) ` interface. let nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 }); let london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 }); let beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 }); var nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 }); var london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 }); var beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 }); See the Pen Map point series with data by amCharts team (@amcharts) on CodePen. Relation to polygon series -------------------------- Point series can use a [map polygon series](https://www.amcharts.com/docs/v5/charts/map-chart/map-polygon-series/) to position its markers. ### Via ID data field If we are using series `data` to points, we can include an ID of the related polygon in it, then set `polygonIdField` setting to let series know we are providing polygon ids. let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { polygonIdField: "country" }) ); pointSeries.data.setAll(\[{\ country: "CA",\ name: "Canada"\ }, {\ country: "US",\ name: "United States"\ },{\ country: "MX",\ name: "Mexico"\ }\]); var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { polygonIdField: "country" }) ); pointSeries.data.setAll(\[{\ country: "CA",\ name: "Canada"\ }, {\ country: "US",\ name: "United States"\ },{\ country: "MX",\ name: "Mexico"\ }\]); See the Pen Map point series creating individual data items by amCharts team (@amcharts) on CodePen. ### Via data items We can do that with custom-created point data items, too: let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); pointSeries.pushDataItem({ polygonId: "CA", name: "Canada" }); pointSeries.pushDataItem({ polygonId: "US", name: "United States" }); pointSeries.pushDataItem({ polygonId: "MX", name: "Mexico" }); var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); pointSeries.pushDataItem({ polygonId: "CA", name: "Canada" }); pointSeries.pushDataItem({ polygonId: "US", name: "United States" }); pointSeries.pushDataItem({ polygonId: "MX", name: "Mexico" }); See the Pen Map point series creating individual data items by amCharts team (@amcharts) on CodePen. ### Automatic labels We can also automate the above process, by utilizing polygon series' `datavalidated` event, to automatically build data for our point series: polygonSeries.events.on("datavalidated", function(ev) { let series = ev.target; let labelData = \[\]; series.mapPolygons.each(function(polygon) { labelData.push({ polygonId: polygon.dataItem.get("id"), name: polygon.dataItem.get("name") }) }) pointSeries.data.setAll(labelData); }); polygonSeries.events.on("datavalidated", function(ev) { var series = ev.target; var labelData = \[\]; series.mapPolygons.each(function(polygon) { var id = polygon.dataItem.get("id"); labelData.push({ polygonId: polygon.dataItem.get("id"), name: polygon.dataItem.get("name") }); }) pointSeries.data.setAll(labelData); }); See the Pen State abbreviations on a US map by amCharts team (@amcharts) on CodePen. Relation to line series ----------------------- ### Connecting line series points We can use actual data items from a map line series as points for the line from a [map line series](https://www.amcharts.com/docs/v5/charts/map-chart/map-line-series/) . This eliminates the need to define `geometry` for our lines, as we can use `pointsToConnect` setting instead, which is an array of map line series' data items: // Create point series let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); let nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 }); let london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 }); let beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 }); // Create line series let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); lineSeries.pushDataItem({ pointsToConnect: \[nyc, london, beijing\] }); // Create point series var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); var nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 }); var london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 }); var beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 }); // Create line series var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); lineSeries.pushDataItem({ pointsToConnect: \[nyc, london, beijing\] }); See the Pen Map with line series via data by amCharts team (@amcharts) on CodePen. ### Points on a line This can also work the other way around: we can make a data item form map line series "stick" to any point on a line. All we have to do is to set `lineDataItem` to a data item of the specific line, as well as `positionOnLine` to indicate relative position, when creating a point series data item: // Create line series let lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); let route = lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \] } }); // Create point series let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); }); let plane = pointSeries.pushDataItem({ lineDataItem: route, positionOnLine: 0.7, autoRotate: true }); // Create line series var lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}) ); var route = lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: \[\ \[ -73.778137, 40.641312 \],\ \[ -0.454296, 51.470020 \],\ \[ 116.597504, 40.072498 \]\ \] } }); // Create point series var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}) ); pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) }); }); var plane = pointSeries.pushDataItem({ lineDataItem: route, positionOnLine: 0.7, autoRotate: true }); Let's examine the code above. The `pointSeries.pushDataItem()` creates a new point in point (item) series. Normally it would contain a latitude/longitude information, but since we're sticking it to a line, we use different settings: | Setting key | Comment | | --- | --- | | `lineDataItem` | A data item from map line series. Created with `pushDataItem()` on a line series, or extracted from series `dataItems`. | | `positionOnLine` | Relative position on the line. `0` (zero) means the beginning, and `1` (one) the end. Any intermediate number will indicate relative position along the whole line.
In case the line is multi-segmented, the position is calculated from the beginning of the first segment to the end of the last one. | | `autoRotate` | If set to `true`, point bullet will be automatically rotated to the angle of the exact point in line. | | `autoRotateAngle` | If set, this will be added to the angle calculated by `autoRotate`. Can be used to reverse the direction. | The below example uses above code, albeit with the slightly more sophisticated image as a point bullet: See the Pen Map line and point series used together by amCharts team (@amcharts) on CodePen. Hover behavior -------------- ### Adding tooltips To add a tooltip to the points/markers, we can use `tooltipText` on a related bullet. The value may contain [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) as well as [in-line text styles](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) . pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }) }); }); pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }) }); }); ### Hover states We can set values to apply to point bullets when it is hovered by creating a "hover" [state](https://www.amcharts.com/docs/v5/concepts/settings/states/) for them. pointSeries.bullets.push(function() { let circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }); circle.states.create("hover", { fill: am5.color(0x00ff00) }); return am5.Bullet.new(root, { sprite: circle }); }); pointSeries.bullets.push(function() { var circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }); circle.states.create("hover", { fill: am5.color(0x00ff00) }); return am5.Bullet.new(root, { sprite: circle }); }); Events ------ To attach events like click and hover on map point series we will need to add them on its bullets when they are created. pointSeries.bullets.push(function() { let circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }); circle.events.on("click", function(ev) { console.log(ev.target.dataItem); }); return am5.Bullet.new(root, { sprite: circle }); }); pointSeries.bullets.push(function() { var circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }); circle.events.on("click", function(ev) { console.log(ev.target.dataItem); }); return am5.Bullet.new(root, { sprite: circle }); }); See the Pen Map point series with data and datafields by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Map point series with rounded image bullets](https://www.amcharts.com/docs/v5/tutorials/map-point-series-with-rounded-image-bullets/) (demo) * [Get points within current viewport of a MapChart](https://www.amcharts.com/docs/v5/tutorials/get-points-within-current-viewport-of-a-mapchart/) (demo) * [Map with custom markers and data-bound colors](https://www.amcharts.com/docs/v5/tutorials/map-with-custom-markers-and-data-bound-colors/) (demo) --- # Graticule series – amCharts 5 Documentation Graticule is a special kind of map series that will draw a map grid. Adding ------ To add a graticule grid to map we need to do two things: * Add `GraticuleSeries` instance to map. * Configure its line settings. let graticuleSeries = chart.series.unshift( am5map.GraticuleSeries.new(root, {}) ); graticuleSeries.mapLines.template.setAll({ stroke: am5.color(0x000000), strokeOpacity: 0.1 }); var graticuleSeries = chart.series.unshift( am5map.GraticuleSeries.new(root, {}) ); graticuleSeries.mapLines.template.setAll({ stroke: am5.color(0x000000), strokeOpacity: 0.1 }); The `unshift()` call above is used to insert graticule series at the beginning of the series list so it stays behind all the other series we may have. Please note that graticule series is actually a line series under the hood. Please refer to the "[Map line series](https://www.amcharts.com/docs/v5/charts/map-chart/map-line-series/) " tutorial for further info on how to configure appearance of the lines. See the Pen Map chart with orthographic projection (globe) by amCharts team (@amcharts) on CodePen. Grid density ------------ Normally. graticule series places a line every 10 degrees of latitude and longitude. We can change the density using series' `[step](https://www.amcharts.com/docs/v5/reference/graticuleseries/#step_setting) ` setting: let graticuleSeries = chart.series.unshift( am5map.GraticuleSeries.new(root, { step: 20 }) ); var graticuleSeries = chart.series.unshift( am5map.GraticuleSeries.new(root, { step: 20 }) ); ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/graticule_step_10-1024x621.png) `step: 10` (default) ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/graticule_step_20-1024x621.png) `step: 20` ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/graticule_step_5-1024x621.png) `step: 5` --- # Country data – amCharts 5 Documentation amCharts 5 geodata package is bundled with some data country data sets. Let's take a look at those. Loading ------- There are two data country sets bundled with amCharts geodata, located in `geodata/data` folder. It containers two files: `countries` and `countries2`. We'll explore their contents shortly. We can load them just like we would load geodata: import am5geodata\_data\_countries from "@amcharts/amcharts5-geodata/data/countries"; import am5geodata\_data\_countries2 from "@amcharts/amcharts5-geodata/data/countries2"; Loading data files via ` MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Series ------ Hierarchy charts are chart-less. This means that rather than creating a chart element, we add series directly to the root container. ### Adding There are following types of series supported in hierarchy charts: | Class | Example | | | --- | --- | --- | | `ForceDirected` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/forcedirected.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/force-directed/) | | `Pack` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pack.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/pack/) | | `Partition` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/partition.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/partition/) | | `Sunburst` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sunburst.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/sunburst/) | | `Tree` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/tree.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/tree/) | | `Treemap` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/treemap/) | | `VoronoiTreemap` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/2023-07-04_11-26-06.png) | [More info](https://www.amcharts.com/docs/v5/charts/hierarchy/voronoi-treemap/) | Like everywhere else, we use its `new()` method to instantiate series, then push it into `series` list of the chart: let series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children" }) ); var series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children" }) ); ### Data fields Most hierarchy charts require three data fields: * Category: a field in data that holds a string-based identifier, like a name. * Children: a field in data that holds array of data objects for child nodes. * Value of the node: a field in data that holds numeric value of the node. Data fields basically mean which keys in data objects to look for specific value. They can be set via series' settings `categoryField`, `childDataField`, and `valueField`. Let's take sample data: \[{\ name: "Root",\ children: \[{\ name: "A0",\ children: \[{\ name: "A00",\ value: 71\ }, {\ name: "A01",\ value: 33\ }, {\ name: "A02",\ value: 2\ }\]\ }, {\ name: "B0",\ children: \[{\ name: "B10",\ value: 78\ }, {\ name: "B11",\ value: 36\ }\]\ }, {\ name: "C0",\ children: \[{\ name: "C20",\ value: 46\ }, {\ name: "C21",\ value: 28\ }, {\ name: "C22",\ value: 18\ }\]\ }\]\ }\] The following data fields would need to describe data fields like this: let series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children" }) ); var series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children" }) ); ### Optional data fields Besides the three required data fields, hierarchy charts can also have a number of other data fields, that can be used to control initial state of the nodes (`disabledField`) or their color (`colorField`). The following code show how we can use `disabledField` to pre-collapse individual nodes. Here's the data" \[{\ name: "Root",\ children: \[{\ name: "A0",\ collapsed: true,\ children: \[{\ name: "A00",\ value: 71\ }, {\ name: "A01",\ value: 33\ }, {\ name: "A02",\ value: 2\ }\]\ }, {\ name: "B0",\ children: \[{\ name: "B10",\ value: 78\ }, {\ name: "B11",\ value: 36\ }\]\ }, {\ name: "C0",\ collapsed: true,\ children: \[{\ name: "C20",\ value: 46\ }, {\ name: "C21",\ value: 28\ }, {\ name: "C22",\ value: 18\ }\]\ }\]\ }\] And he code: let series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", disabledField: "collapsed" }) ); var series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", disabledField: "collapsed" }) ); The above will make the chart start with "A0" and "C0" nodes collapsed, while "B0" expanded. ### Data structure IMORTANT A data for all hierarchy charts requires to have just one top item. Having several items on top level might break the chart. If we don't want this top item to appear on the chart itself, we can hide it by providing `topLevel: 1` in series settings. Refer to "[Tree depth](https://www.amcharts.com/docs/v5/getting-started/hierarchy/#Tree_depth) " section of this tutorial for more info. ### Setting data In all hierarchy charts, each entry in data represents a node. If it has data for children (as identified by `childDataField`), it also may have child nodes, which in turn can have their own children, etc. Node can also have a value, which in most hierarchy charts will determine its size. Basically, if node has value in its data, this value will be used. If node does not have value set in data, but has children, than its value will be the sum of all child values. The data is set directly on series via its `data` property: series.data.setAll(\[{\ name: "Root",\ children: \[{\ name: "A0",\ children: \[{\ name: "A00",\ value: 71\ }, {\ name: "A01",\ value: 33\ }, {\ name: "A02",\ value: 2\ }\]\ }, {\ name: "B0",\ children: \[{\ name: "B10",\ value: 78\ }, {\ name: "B11",\ value: 36\ }\]\ }, {\ name: "C0",\ children: \[{\ name: "C20",\ value: 46\ }, {\ name: "C21",\ value: 28\ }, {\ name: "C22",\ value: 18\ }\]\ }\]\ }\]); series.data.setAll(\[{\ name: "Root",\ children: \[{\ name: "A0",\ children: \[{\ name: "A00",\ value: 71\ }, {\ name: "A01",\ value: 33\ }, {\ name: "A02",\ value: 2\ }\]\ }, {\ name: "B0",\ children: \[{\ name: "B10",\ value: 78\ }, {\ name: "B11",\ value: 36\ }\]\ }, {\ name: "C0",\ children: \[{\ name: "C20",\ value: 46\ }, {\ name: "C21",\ value: 28\ }, {\ name: "C22",\ value: 18\ }\]\ }\]\ }\]); IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFO There are more ways to set, update, add, or load data. For more information please refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. Pre-selected branch ------------------- In order for our chart to function properly, we need to tell series which node is currently selected. It ensures that: * Current active node is correctly set. * Initial chart tree depths are respected. We do that by setting series `selectedDataItem`. Please note that this is a data item, not a node itself. For the most uses, this will be the root data item, which will always come first in series' `dataItems` list: series.set("selectedDataItem", series.dataItems\[0\]); series.set("selectedDataItem", series.dataItems\[0\]); IMPORTANT The `selectedDataItem` needs to be set **after** data is set to the series. For more information about configuring appearance of the flow series, refer to respective tutorials: * [Configuring Force-directed series](https://www.amcharts.com/docs/v5/getting-started/hierarchy/force-directed/) . * [Configuring Pack series](https://www.amcharts.com/docs/v5/getting-started/hierarchy/pack/) . * [Configuring Partition](https://www.amcharts.com/docs/v5/getting-started/hierarchy/partition/) . * [Configuring Sunburst](https://www.amcharts.com/docs/v5/getting-started/hierarchy/sunburst/) . * [Configuring Tree](https://www.amcharts.com/docs/v5/getting-started/hierarchy/tree/) . * [Configuring Treemap](https://www.amcharts.com/docs/v5/getting-started/hierarchy/treemap/) . Node value ---------- Each node in a hierarchy has its value, which mainly affects its size. Value of a node is calculated this way: * Value is retrieved from data via `valueField` data field if present. * If value is not present in data, but node has children, its value will be the sum of values of all its children. To paraphrase the above, there are two "correct" ways to set values in hierarchy data: 1. Set values only on "end" nodes (nodes that do not have children). 2. Set value for all nodes, including the top node. Node colors ----------- There is a number of ways we can specify all colors for hierarchy nodes. For information on how to do that, refer to "[Hierarchy node colors](https://www.amcharts.com/docs/v5/charts/hierarchy/hierarchy-node-colors/) " tutorial. Tooltips -------- Nodes are pre-set to display a tooltip on hover containing name of the category and its value. We can modify contents of the tooltips using `tooltipText` on node's template: series.nodes.template.set("tooltipText", "{category}: \[bold\]{sum}\[/\]"); series.nodes.template.set("tooltipText", "{category}: \[bold\]{sum}\[/\]"); Contents of the tooltip can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). Refer to `[IHierarchyDataItem](https://www.amcharts.com/docs/v5/reference/ihierarchydataitem/) ` for available keys for the data placeholders. Tree depth ---------- There are two hierarchy settings that control depth of the tree: `[initialDepth](https://www.amcharts.com/docs/v5/reference/hierarchy/#initialDepth_setting) ` and `[topDepth](https://www.amcharts.com/docs/v5/reference/hierarchy/#topDepth_setting) `. `initialDepth` specifies how mane levels to show initially, when the chart loads. It will also be used when resetting the chart to the top level. `topDepth` indicates the level, which should be considered top level. Any level in data above that will be ignored and not shown on the chart. let series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", initialDepth: 2, topDepth: 1 }) ); var series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", initialDepth: 2, topDepth: 1 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-01-44.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-01-44.png) `topDepth: 0` `initialDepth: 1` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-01-55.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-01-55.png) `topDepth: 0` `initialDepth: 2` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-02-07.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-02-07.png) `topDepth: 0` `initialDepth: 3` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-01-24.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/2021-08-01_11-01-24.png) `topDepth: 1` `initialDepth: 1` NOTE In hierarchy charts that size their nodes relatively, like a force-directed, top node will affect the size of other nodes even if it is hidden using `topDepth` is set to `1` (hiding top node). To work around it, simply set value for the top node to zero. Drill-down ---------- Hierarchy nodes that have children are clickable. Depending on series type and settings, certain drill-down actions happen, like zooming in on the node, exploding a children tree, etc. For more information about this, please refer to "[Hierarchy drill-down](https://www.amcharts.com/docs/v5/charts/hierarchy/hierarchy-drill-down/) " tutorial. Additional controls ------------------- Hierarchy is a "container-less" chart. This means that there's no wrapper "chart" element, that can be used to add series and external controls to. If we don't need anything else besides series, we can add it directly to the container of the root element. However, if we need to add other elements, we'll need to first create a "wrapper (or main) container", we'll be using add all the stuff to: let container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); var container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); NOTEThe `layout` setting of the wrapper container will determine how chart elements are laid out. For more information, refer to "Containers: [Layout](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Layout) ". ### Chart title Chart title can be added as a `Label` element child to the wrapper container: var title = container.children.push(am5.Label.new(root, { text: "Network Schema", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); var title = container.children.push(am5.Label.new(root, { text: "Network Schema", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); ### Breadcrumb navigation All hierarchy charts support breadcrumb control, which will show current drill-down path, as well as allow jumping to specific level/node in the path. We can add as wrapper container's child: container.children.unshift( am5hierarchy.BreadcrumbBar.new(root, { series: series }) ); container.children.unshift( am5hierarchy.BreadcrumbBar.new(root, { series: series }) ); For more information on how to use breadcrumb control, refer to "[Breadcrumb navigation](https://www.amcharts.com/docs/v5/getting-started/hierarchy/breadcrumbs/) " tutorial. ### Legend To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "core" package), push it to wrapper container's children (or any other place we want it to be), as well as set its data (in case of hierarchy chart, we will probably want to have series data items in legend). Since legend needs to have a data, and hierarchy charts have multi-level nested data items, we will need to specify what exactly we want in the legend. In most cases it will be the first level data items (ones directly below the root): let legend = container.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems\[0\].get("children")); var legend = container.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.horizontalLayout })); legend.data.setAll(series.dataItems\[0\].get("children")); MORE INFO For more information on how to configure the legend, set its contents, and other tricks, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. See the Pen Force-directed chart with fixed nodes by amCharts team (@amcharts) on CodePen. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5hierarchy from "@amcharts/amcharts5/hierarchy"; // Create root and main container let root = am5.Root.new("chartdiv"); root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); let container = root.container.children.push( am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout }) ); // Create series and set data let series = container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", initialDepth: 2 }) ); series.data.setAll(\[{\ name: "Root",\ children: \[{\ name: "A0",\ children: \[{\ name: "A0A1",\ children: \[{\ name: "A0A0A2",\ value: 71\ }, {\ name: "A0A0B2",\ children: \[{\ name: "A0A0B1A3",\ value: 69\ }, {\ name: "A0A0B1B3",\ value: 85\ }\]\ }, {\ name: "A0A0C2",\ value: 48\ }\]\ }, {\ name: "A0B1",\ value: 27\ }, {\ name: "A0C1",\ children: \[{\ name: "A0C2A2",\ value: 2\ }, {\ name: "A0C2B2",\ children: \[{\ name: "A0C2B1A3",\ value: 54\ }, {\ name: "A0C2B1B3",\ value: 16\ }\]\ }\]\ }, {\ name: "A0D1",\ value: 89\ }\]\ }, {\ name: "B0",\ children: \[{\ name: "B1A1",\ value: 9\ }, {\ name: "B1B1",\ children: \[{\ name: "B1B1A2",\ children: \[{\ name: "B1B1A0A3",\ value: 35\ }, {\ name: "B1B1A0B3",\ value: 40\ }\]\ }, {\ name: "B1B1B2",\ value: 55\ }\]\ }\]\ }, {\ name: "C0",\ children: \[{\ name: "C2A1",\ children: \[{\ name: "C2A0A2",\ value: 24\ }, {\ name: "C2A0B2",\ value: 89\ }, {\ name: "C2A0C2",\ children: \[{\ name: "C2A0C2A3",\ children: \[{\ name: "C2A0C2A0A4",\ children: \[{\ name: "C2A0C2A0A00",\ value: 90\ }, {\ name: "C2A0C2A0A01",\ value: 70\ }, {\ name: "C2A0C2A0A02",\ value: 66\ }, {\ name: "C2A0C2A0A03",\ value: 58\ }\]\ }, {\ name: "C2A0C2A0B4",\ children: \[{\ name: "C2A0C2A0B10",\ value: 80\ }, {\ name: "C2A0C2A0B11",\ value: 40\ }\]\ }\]\ }, {\ name: "C2A0C2B3",\ value: 44\ }\]\ }, {\ name: "C2A0D2",\ children: \[{\ name: "C2A0D3A3",\ value: 28\ }, {\ name: "C2A0D3B3",\ value: 14\ }\]\ }\]\ }, {\ name: "C2B1",\ value: 40\ }, {\ name: "C2C1",\ children: \[{\ name: "C2C2A2",\ children: \[{\ name: "C2C2A0A3",\ value: 28\ }, {\ name: "C2C2A0B3",\ children: \[{\ name: "C2C2A0B1A4",\ value: 19\ }, {\ name: "C2C2A0B1B4",\ children: \[{\ name: "C2C2A0B1B10",\ value: 11\ }, {\ name: "C2C2A0B1B11",\ value: 10\ }, {\ name: "C2C2A0B1B12",\ value: 97\ }, {\ name: "C2C2A0B1B13",\ value: 47\ }\]\ }, {\ name: "C2C2A0B1C4",\ children: \[{\ name: "C2C2A0B1C20",\ value: 40\ }, {\ name: "C2C2A0B1C21",\ value: 37\ }, {\ name: "C2C2A0B1C22",\ value: 53\ }\]\ }\]\ }, {\ name: "C2C2A0C3",\ value: 96\ }\]\ }, {\ name: "C2C2B2",\ value: 66\ }\]\ }\]\ }\]\ }\]); series.set("selectedDataItem", series.dataItems\[0\]); // Add breadcrumbs container.children.unshift( am5hierarchy.BreadcrumbBar.new(root, { series: series }) );
See the Pen Treemap chart by amCharts team (@amcharts) on CodePen. --- # Treemap – amCharts 5 Documentation This tutorial will look at how to configure treemap series. Nodes ----- ### Layout algorithm Treemap can use different ways to layout algorithms. It's controlled by the setting `layoutAlgorithm`: let series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", layoutAlgorithm: "sliceDice" }) ); var series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", layoutAlgorithm: "sliceDice" }) ); Available settings are as follows: | Setting value | Example | | --- | --- | | `"binary"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_binary.png) | | `"squarify"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_squarify.png) | | `"slice"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_slice.png) | | `"dice"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_dice.png) | | `"sliceDice"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_slicedice.png) | ### Margins By default, the rectangles of the nodes are plotted without any gaps between them. We do have a few settings at our disposal that we can use to control the gaps. All accept numeric value in pixels. | Setting | Comment | | --- | --- | | `nodePaddingInner` | Gap between nodes. | | `nodePaddingOuter` | Gap between nodes and outer edge of the chart. | | `nodePaddingTop` | Gap between nodes and top edge. Will be ignored if `nodePaddingOuter` is set. | | `nodePaddingBottom` | Gap between nodes and bottomedge. Will be ignored if `nodePaddingOuter` is set. | | `nodePaddingLeft` | Gap between nodes and left edge. Will be ignored if `nodePaddingOuter` is set. | | `nodePaddingRight` | Gap between nodes and bottom edge. Will be ignored if `nodePaddingOuter` is set. | let series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", nodePaddingOuter: 20, nodePaddingInner: 10 }) ); var series = root.container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", nodePaddingOuter: 20, nodePaddingInner: 10 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_no_padding.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_no_padding.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_padding.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_padding.png) `nodePaddingOuter: 20` `nodePaddingInner: 10` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_top_padding.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/treemap_top_padding.png) `nodePaddingInner: 10` `nodePaddingTop: 100` `nodePaddingBottom: 20` `nodePaddingLeft: 20` `nodePaddingRight: 20` ### Node appearance The appearance of node rectangles can be configured using their template, accessible on series property: `rectangles.template`. The template can have contain any `RoundedRectangle` [setting](https://www.amcharts.com/docs/v5/reference/roundedrectangle/#Settings) . series.rectangles.template.setAll({ fillOpacity: 0.7, cornerRadiusTL: 4, cornerRadiusTR: 4, cornerRadiusBL: 4, cornerRadiusBR: 4 }); series.rectangles.template.setAll({ fillOpacity: 0.7, cornerRadiusTL: 4, cornerRadiusTR: 4, cornerRadiusBL: 4, cornerRadiusBR: 4 }); ### Hover behavior We can set setting values to apply to a rectangle when it is hovered by creating a "hover" [state](https://www.amcharts.com/docs/v5/concepts/settings/states/) for it. series.rectangles.template.states.create("hover", { fill: am5.color(0x677935), fillOpacity: 1 }); series.rectangles.template.states.create("hover", { fill: am5.color(0x677935), fillOpacity: 1 }); Labels ------ ### Configuring labels Series label configuration is done via its template, accessible via series property `labels.template`. series.labels.template.setAll({ fontSize: 20, fill: am5.color(0x550000), text: "{category}" }); series.labels.template.setAll({ fontSize: 20, fill: am5.color(0x550000), text: "{category}" }); Partition series uses `[Label](https://www.amcharts.com/docs/v5/reference/label/) ` for its labels. Check out its class reference for all the [possible settings](https://www.amcharts.com/docs/v5/reference/label/#Settings) . ### Label content Node labels are pre-set to display name of the category and its percent value. We can modify contents of the tooltips using `text` setting on a series label template: series.labels.template.setAll({ text: "{category}: \[bold\]{sum}\[/\]", fontSize: 14 }); series.labels.template.setAll({ text: "{category}: \[bold\]{sum}\[/\]", fontSize: 14 }); Contents of the tooltip can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). ### Disabling labels To disable series labels, we can set `forceHidden` setting to `true` in their template: series.labels.template.set("forceHidden", true); series.labels.template.set("forceHidden", true); Tooltips -------- Rectangles series are pre-set to display a tooltip on hover containing name of the category and its value. We can modify contents of the tooltips using `tooltipText` on node's template: series.nodes.template.set("tooltipText", "{category}: \[bold\]{sum}\[/\]"); series.nodes.template.set("tooltipText", "{category}: \[bold\]{sum}\[/\]"); Contents of the tooltip can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). Example ------- See the Pen Partition chart by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Adaptive label colors on a Treemap](https://www.amcharts.com/docs/v5/tutorials/adaptive-label-colors-on-a-treemap/) * [Treemap with partial fills in nodes](https://www.amcharts.com/docs/v5/tutorials/treemap-with-partial-fills-in-nodes/) (demo) * [Treemap with auto-colored labels](https://www.amcharts.com/docs/v5/tutorials/treemap-with-auto-colored-labels/) (demo) * [Treemap with highlight of parent node on hover](https://www.amcharts.com/docs/v5/tutorials/treemap-with-highlight-of-parent-node-on-hover/) (demo) Related class references ------------------------ * [Treemap](https://www.amcharts.com/docs/v5/reference/treemap) --- # Map name translations – amCharts 5 Documentation Maps in amCharts 5 will display names of the countries and other places in English by default. This tutorial will show how you can use bundled translation files to display country names in different languages. Loading translation files ------------------------- Translation files are included with the Geodata package, in a sub-directory `lang`. Loading those will depend on your development environment: import am5geodata\_lang\_ES from "@amcharts/amcharts5-geodata/lang/ES"; NOTE If you are using ` MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Series ------ Flow charts are chart-less. This means that rather than creating a chart element, we add series directly to the root container. ### Adding There are following types of series supported in flow charts: | Class | Comment | | | --- | --- | --- | | `Chord` | A regular chord diagram. | [More info](https://www.amcharts.com/docs/v5/charts/flow-charts/chord-diagram/#Regular_series) | | `ChordDirected` | A chord diagramwith arrowed links/ribbons. | [More info](https://www.amcharts.com/docs/v5/charts/flow-charts/chord-diagram/#Directed_series) | | `ChordNonRibbon` | A chord diagram with narrow links lines. | [More info](https://www.amcharts.com/docs/v5/charts/flow-charts/chord-diagram/#Non_ribbon_series) | | `Sankey` | A Sankey diagram. | [More info](https://www.amcharts.com/docs/v5/charts/flow-charts/sankey-diagram/) | | `ArcDiagram` | An Arc diagram. | [More info](https://www.amcharts.com/docs/v5/charts/flow-charts/arc-diagram/) | Like everywhere else, we use its `new()` method to instantiate series, then push it into `series` list of the chart: let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value" }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value" }) ); ### Data fields Flow diagrams require three data fields: * ID of the source node. * ID of the target node. * Value of the link between two nodes. Data fields basically mean which keys in data objects to look for specific value. They can be set via series' settings `sourceIdField`, `targetIdField`, and `valueField`. Let's take sample data: \[{\ country: "France",\ sales: 100000\ }, {\ country: "Spain",\ sales: 160000\ }, {\ country: "United Kingdom",\ sales: 80000\ }\] The following data fields would need to describe data fields like this: let series = chart.series.push( am5xy.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); var series = chart.series.push( am5xy.PieSeries.new(root, { name: "Series", categoryField: "country", valueField: "sales" }) ); ### Setting data In flow charts, each entry in data represents a link. It identifies source and target nodes, as well as numeric value of the link. The links can be multi-level, meaning that nodes that don't have any other nodes linking to them will form the first level, then the nodes they link to, and so on. The data is set directly on series via its `data` property: series.data.setAll(\[\ { from: "A", to: "B", value: 10 },\ { from: "B", to: "C", value: 8 },\ { from: "C", to: "D", value: 4 },\ { from: "C", to: "E", value: 3 },\ { from: "D", to: "G", value: 5 },\ { from: "D", to: "I", value: 2 },\ { from: "D", to: "H", value: 3 },\ { from: "E", to: "H", value: 6 },\ { from: "G", to: "J", value: 5 },\ { from: "I", to: "J", value: 1 },\ { from: "H", to: "J", value: 9 }\ \]); series.data.setAll(\[\ { from: "A", to: "B", value: 10 },\ { from: "B", to: "C", value: 8 },\ { from: "C", to: "D", value: 4 },\ { from: "C", to: "E", value: 3 },\ { from: "D", to: "G", value: 5 },\ { from: "D", to: "I", value: 2 },\ { from: "D", to: "H", value: 3 },\ { from: "E", to: "H", value: 6 },\ { from: "G", to: "J", value: 5 },\ { from: "I", to: "J", value: 1 },\ { from: "H", to: "J", value: 9 }\ \]); IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFO There are more ways to set, update, add, or load data. For more information please refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. ### Minimum node size Nodes/links in flow diagrams are sized by their value relatively to the sum of all values. In some cases, this may result in very small nodes. To ensure that that does not happen, there is a setting: `[minSize](https://www.amcharts.com/docs/v5/reference/flow/#minSize_setting) `. If set to a number it will override value for small nodes with a bigger value calculated from a sum of all the nodes. For example, if we set `minSize: 0.01` the minimum value a node would be sized again would be 1% of the sum of values of all of the nodes in series. let series = root.container.children.push(am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", minSize: 0.03 })); var series = root.container.children.push(am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", minSize: 0.03 })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/02/minSize_not_set.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/02/minSize_not_set.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/02/minSize.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/02/minSize.png) `minSize: 0.05` ### Node toggling Nodes in all Flow series (Sankey, Chord, and Arc) are togglable by default. #### Disabling toggling To disable toggling, use `toggleKey` and `cursorOverStyle` settings of the node template: series.nodes.nodes.template.setAll({ toggleKey:"none", cursorOverStyle:"default" }); series.nodes.nodes.template.setAll({ toggleKey:"none", cursorOverStyle:"default" }); #### Configuring toggled off nodes By default, a toggled off node will shrink down and fade out, it's links will be hidden completely. The relative size of the shrunken node can be controlled with the series' `hiddenSize` (default: `0.05`), and `minHiddenValue` (default: `0`) settings. Similarly to `minSize` (explained above), it means a relative fraction of the sum of all node values. E.g. if all nodes sum up to `100`, a `hiddenSize: 0.05` will mean that hidden node will be sized like it would have a value of `5`. `minHiddenValue` (default: `0`) can be used to not allow the relative value - used for sizing the hidden node - to go below certain threshold. E.g. if it is set to `1`, and it's hidden value gets down to `0.5`, it will still be sized like it would have a value of `1`. let series = root.container.children.push(am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", hiddenSize: 0.03, minHiddenValue: 1 })); var series = root.container.children.push(am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", hiddenSize: 0.03, minHiddenValue: 1 })); #### Pre-hidden nodes It's also possible to pre-hide nodes using node series setting `disabledField` and separate node data, e.g.: series.nodes.setAll({ disabledField: "disabled", }); series.nodes.data.setAll(\[\ { id: "A", name: "A", disabled: true },\ { id: "H", name: "H", disabled: true }\ \]); series.nodes.setAll({ disabledField: "disabled", }); series.nodes.data.setAll(\[\ { id: "A", name: "A", disabled: true },\ { id: "H", name: "H", disabled: true }\ \]); See the Pen Pre-hidden nodes in Sankey by amCharts team (@amcharts) on CodePen. ### Series appearance For more information about configuring appearance of the flow series, refer to respective tutorials: * [Configuring Sankey series](https://www.amcharts.com/docs/v5/charts/flow-charts/sankey-diagram/) . * [Configuring chord series](https://www.amcharts.com/docs/v5/charts/flow-charts/chord-diagram/) . Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5flow from "@amcharts/amcharts5/flow"; // Create root and chart let root = am5.Root.new("chartdiv"); // Set themes root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); // Create series let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", paddingRight: 50 }) ); series.nodes.get("colors").set("step", 2); // Set data series.data.setAll(\[\ { from: "A", to: "B", value: 10 },\ { from: "B", to: "C", value: 8 },\ { from: "C", to: "D", value: 4 },\ { from: "C", to: "E", value: 3 },\ { from: "D", to: "G", value: 5 },\ { from: "D", to: "I", value: 2 },\ { from: "D", to: "H", value: 3 },\ { from: "E", to: "H", value: 6 },\ { from: "G", to: "J", value: 5 },\ { from: "I", to: "J", value: 1 },\ { from: "H", to: "J", value: 9 }\ \]);
See the Pen Radar chart axis labels by amCharts team (@amcharts) on CodePen. Additional controls ------------------- Flow is a "container-less" chart. This means that there's no wrapper "chart" element, that can be used to add series and external controls to. If we don't need anything else besides series, we can add it directly to the container of the root element. However, if we need to add other elements, we'll need to first create a "wrapper (or main) container", we'll be using add all the stuff to: let container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); var container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); NOTEThe `layout` setting of the wrapper container will determine how chart elements are laid out. For more information, refer to "Containers: [Layout](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Layout) ". ### Chart title Chart title can be added as a `Label` element child to the wrapper container: let title = container.children.push(am5.Label.new(root, { text: "User flow", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); var title = container.children.push(am5.Label.new(root, { text: "User flow", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); Further reading --------------- For more information about configuring each type of series visit these tutorials: * [Configuring Sankey series](https://www.amcharts.com/docs/v5/charts/flow-charts/sankey-diagram/) . * [Configuring chord series](https://www.amcharts.com/docs/v5/charts/flow-charts/chord-diagram/) . --- # Sankey diagram – amCharts 5 Documentation Flow chart ---------- A Sankey diagram is a flow chart. For generic flow chart related information, please visit "[Flow charts](https://www.amcharts.com/docs/v5/charts/flow-charts/) " tutorial. Orientation ----------- Sankey diagram is drawn horizontal (links flow from left to right) by default. We can change it using series' `orientation` setting: let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", orientation: "vertical" }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", orientation: "vertical" }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/horizontal_sankey.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/horizontal_sankey.png) `orientation: "horizontal"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/vertical_sankey.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/vertical_sankey.png) `orientation: "vertical"` Nodes ----- ### Width Nodes (colored bands) are 10 pixel wide by default. We can use series setting `[nodeWidth](https://www.amcharts.com/docs/v5/reference/sankey/#nodeWidth_setting) ` to change that: let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodeWidth: 5 }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodeWidth: 5 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png) `nodeWidth: 10` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_5.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_5.png) `nodeWidth: 5` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_30.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_30.png) `nodeWidth: 30` ### Configuring nodes Nodes in flow diagrams are represented by their own series, accessible via read-only property `nodes` which is an object of type `[SankeyNodes](https://www.amcharts.com/docs/v5/reference/sankeynodes/) `. It subsequently has a property `rectangles` which is a list of all nodes in series. Since it's a "list template", we can use its `template` property to set any setting for the node, which is of type `[RoundedRectangle](https://www.amcharts.com/docs/v5/reference/slice/) `: series.nodes.rectangles.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeWidth: 1, cornerRadiusTL: 4, cornerRadiusTR: 4, cornerRadiusBL: 4, cornerRadiusBR: 4 }); series.nodes.rectangles.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeWidth: 1, cornerRadiusTL: 4, cornerRadiusTR: 4, cornerRadiusBL: 4, cornerRadiusBR: 4 }); See the Pen Sankey diagram by amCharts team (@amcharts) on CodePen. ### Node data #### Setting node data In Sankey diagrams, node ids (and names) are derived from link data (via `sourceIdField` and `targetIdField`). In some cases, we might need more than just node id which comes from Sankey data. For that we can set own data on `series.nodes.data`: series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); #### Modifying data fields Node series (which is `SankeyNodes`) is automatically set up for these data fields: | Data field | Default value | Comment | | --- | --- | --- | | `idField` | `"id"` | ID of the node. | | `nameField` | `"id"` | Name of the node. | | `fillField` | `"fill"` | Fill color for the node. | We can modify those to suit our data: series.nodes.setAll({ idField: "id", nameField: "name" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); series.nodes.setAll({ idField: "id", nameField: "name" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); IMPORTANTData fields need to be set before data or they will not work as expected. #### Node colors via data We can also specify custom colors for nodes via node data: series.nodes.data.setAll(\[\ { id: "A", name: "Node A", fill: am5.color(0xFF621F) },\ { id: "B", name: "Node B", fill: am5.color(0x297373) },\ { id: "C", name: "Node C", fill: am5.color(0x946B49) }\ \]); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", fill: am5.color(0xFF621F) },\ { id: "B", name: "Node B", fill: am5.color(0x297373) },\ { id: "C", name: "Node C", fill: am5.color(0x946B49) }\ \]); The fill color will be lookup up in a `"fill"` field of the data. If we need to use something else, we will need to configure node series' `fillField` as well: series.nodes.setAll({ idField: "id", nameField: "name", fillField: "color" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", color: am5.color(0xFF621F) },\ { id: "B", name: "Node B", color: am5.color(0x297373) },\ { id: "C", name: "Node C", color: am5.color(0x946B49) }\ \]); series.nodes.setAll({ idField: "id", nameField: "name", fillField: "color" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", color: am5.color(0xFF621F) },\ { id: "B", name: "Node B", color: am5.color(0x297373) },\ { id: "C", name: "Node C", color: am5.color(0x946B49) }\ \]); See the Pen amCharts 5: Custom Sankey node colors by amCharts team (@amcharts) on CodePen. ### Gaps between nodes Sankey diagrams display a tiny gap between each node by default. We can control the size of it using series' `[nodePadding](https://www.amcharts.com/docs/v5/reference/sankey/#nodePadding_setting) ` setting. It accepts a numeric value in degrees. let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodePadding: 5 }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodePadding: 5 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png) `nodePadding: 10` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodepadding_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodepadding_0.png) `nodePadding: 0` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodepadding_100.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodepadding_100.png) `nodePadding: 100` ### Alignment Sankey will position all of its nodes aligned to left, which might not work for complex flows. To control it, we have a Sankey setting: `[nodeAlign](https://www.amcharts.com/docs/v5/reference/sankey/#nodeAlign_setting) `. It accepts four values: `"left"` (default), `"right"`, `"center"`, and `"justify"`. let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodeAlign: "justify" }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodeAlign: "justify" }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_left-1024x771.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_left.png) `nodeAlign = "left"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_right-1024x771.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_right.png) `nodeAlign = "right"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_justify-1024x771.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_justify.png) `nodeAlign = "justify"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_center-1024x771.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodealign_center.png) `nodeAlign: "center"` See the Pen Sankey diagram by amCharts team (@amcharts) on CodePen. ### Disabling dragging and toggling Nodes are draggable and click-togglable in Sankey diagram by default. To disable it, simply set `draggable: false` and `toggleKey: "none"` settings on node template: series.nodes.nodes.template.setAll({ draggable: false, // disables dragging toggleKey: "none" // disables toggling }); series.nodes.nodes.template.setAll({ draggable: false, // disables dragging toggleKey: "none" // disables toggling }); Links ----- ### Tension Sankey links are smooth curves by default. We can configure how "tight" the curve is via series `[linkTension](https://www.amcharts.com/docs/v5/reference/sankey/#linkTension_setting) ` setting. With default of `0.5` it accepts a numeric value between `0` (zero) and `1` (one). The smaller the number, the more loose the curve. `1` will result in maximum tension, i.e. perfectly straight line. let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkTension: 1 }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkTension: 1 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png) `linkTension: 0.5` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_linktension_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_linktension_0.png) `linkTension: 0` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_linktension_1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_linktension_1.png) `linkTension: 1` ### Configuring links We can configure links using series property `links.template`. Via template, we can set any [`SankeyLink` setting](https://www.amcharts.com/docs/v5/reference/sankeylink/#Settings) . series.links.template.setAll({ fillOpacity: 0.5 }); series.links.template.setAll({ fillOpacity: 0.5 }); ### Color mode Sankey links can be colored in a number of ways via link template's `fillStyle` setting: series.links.template.setAll({ fillStyle: "solid" }); series.links.template.setAll({ fillStyle: "solid" }); These values are available for `fillStyle`: | `fillStyle` | Comment | Example | | --- | --- | --- | | `"solid"` | Solid color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_fillstyle_solid.png) | | `"gradient"` (default) | Gradient from source node color to target node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_nodewidth_10.png) | | `"source"` | Source node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_fillstyle_source.png) | | `"target"` | Target node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/sankey_fillstyle_target.png) | ### Bend point A bend (or control point) is a position where link's elbows bend forming an "elbow". By default this happens 20% of either end of the link. We can control it using link setting: `[controlPointDistance](https://www.amcharts.com/docs/v5/reference/sankeylink/#controlPointDistance_setting) `. It accepts numeric values between `0` (zero) and `1` (one). The smaller the number the closer the elbow will be to the ends of the link. series.links.template.setAll({ controlPointDistance: 0.4 }); series.links.template.setAll({ controlPointDistance: 0.4 }); ### Link sort order Links on a Sankey diagram are sorted using built-in fuzzy logic. We can modify the logic using `linkSort` setting. It accepts two types of values: 1. `null`. Setting it to `null` will make links appear exactly in the same order as they are set in data. 2. `function`. The setting can also accept a reference to a custom function that accepts two parameters with a D3 sankey link objects. #### Sorting by data Setting `linkSort` to `null` will make the links appear in exact same order as they are defined in data: let series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkSort: null }) ); var series = root.container.children.push( am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkSort: null }) ); #### Sorting with custom function `linkSort` can also accept a reference to a custom sort function. Similarly to JavaScript's `Array.sort(a, b)` function, `linkSort` function will receive two instances of a D3 link objects, and should return `-1` if the first link should precede the second, `1` if it's the other way around, or `0` if they are both equal in priority. let series = root.container.children.push(am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", paddingRight: 50, linkSort: function(a, b) { if (a.value < b.value) return -1; if (a.value > b.value) return 1; return 0; } })); var series = root.container.children.push(am5flow.Sankey.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", paddingRight: 50, linkSort: function(a, b) { if (a.value > b.value) return -1; if (a.value < b.value) return 1; return 0; } })); The above will order all links by their value in descending order. Labels ------ Sankey diagram will display a label next to its nodes by default. ### Configuring labels Labels in Sankey diagram are attached to nodes, so they can be configured via `nodes` sub-series, specifically `nodes.labels.template`: series.nodes.labels.template.setAll({ fontSize: 20, maxWidth: 150, oversizedBehavior: "wrap" }); series.nodes.labels.template.setAll({ fontSize: 20, maxWidth: 150, oversizedBehavior: "wrap" }); Refer to [`Label` class reference](https://www.amcharts.com/docs/v5/reference/label/#Settings) for a full list of available settings. ### Label content To change label content, we only need to set `text` property of the label template: series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})" }); series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})" }); Contents of the label can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). For available data placeholder fields refer to `[ISankeyNodesDataItem](https://www.amcharts.com/docs/v5/reference/isankeynodesdataitem/) `. ### Positioning labels Labels are positioned to the right (or bottom) of the node by default. There are a few settings that can be used to control position of the label: | Setting key | Comment | | --- | --- | | `x` | Horizontal position: absolute pixel values or percent relative to node height. | | `y` | Vertical position: absolute pixel values or percent relative to node height. | | `centerX` | Horizontal center of the label: absolute pixel value or percent relative to the width of the label. | | `centerY` | Vertical center of the label: absolute pixel value or percent relative to the width of the label. | | `paddingTop` | Top padding in pixels. | | `paddingRight` | Right padding in pixels. | | `paddingBottom` | Bottom padding in pixels. | | `paddingLeft` | Left padding in pixels. | The below code will put labels inside and up top on the node: series.nodes.labels.template.setAll({ x: am5.percent(50), centerX: am5.percent(50), y: am5.percent(0), centerY: am5.percent(0), paddingLeft: 0, paddingRight: 0 }); series.nodes.labels.template.setAll({ x: am5.percent(50), centerX: am5.percent(50), y: am5.percent(0), centerY: am5.percent(0), paddingLeft: 0, paddingRight: 0 }); See the Pen Sankey diagram by amCharts team (@amcharts) on CodePen. MORE INFOFor selectively aligning labels, check out "[Selectively positioning Sankey diagram labels](https://www.amcharts.com/docs/v5/tutorials/selectively-positioning-sankey-diagram-labels/) ". ### Disabling labels To disable labels, we can simply set their `visible` to `false`: series.nodes.labels.template.set("visible", false); series.nodes.labels.template.set("visible", false); Tooltips -------- ### On links Links will display a tooltip when hovered/touched. The default content is `"{sourceId} - {targetId}: {value}"` which will show source node ID, followed by target node ID, and link value. To change it, we can use link's `tooltipText` setting: series.links.template.setAll({ tooltipText: "From: \[bold\]{sourceId}\[/\]\\nTo: \[bold\]{targetId}\\nValue: \[bold\]{value}\[/\]" }); series.links.template.setAll({ tooltipText: "From: \[bold\]{sourceId}\[/\]\\nTo: \[bold\]{targetId}\\nValue: \[bold\]{value}\[/\]" }); Contents of the tooltip can include data placeholders (codes in curly brackets that will be replaced by actual data) and in-line formatting blocks (formatting instructions enclosed in square brackets). For available data placeholder fields refer to `[ISankeyDataItem](https://www.amcharts.com/docs/v5/reference/isankeydataitem/) `. ### On nodes To add tooltips to nodes, simple set `tooltipText` on node template: series.nodes.rectangles.template.setAll({ tooltipText: "\[bold\]{name}\[/\]\\nOutgoing: {sumOutgoing}\\nIncoming: {sumIncoming}" }); series.nodes.rectangles.template.setAll({ tooltipText: "\[bold\]{name}\[/\]\\nOutgoing: {sumOutgoing}\\nIncoming: {sumIncoming}" }); For available data placeholder fields refer to `[ISankeyNodesDataItem](https://www.amcharts.com/docs/v5/reference/isankeynodesdataitem/) `. Using template fields --------------------- [Template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) can also be used to configure various diagram elements, such as node rectangles and link graphics. series.nodes.rectangles.template.set("templateField", "nodeSettings"); series.links.template.set("templateField", "linkSettings"); series.nodes.data.setAll(\[\ { id: "A", nodeSettings: { fill: am5.color(0xFF621F), stroke: am5.color(0x000000 } },\ { id: "B", nodeSettings: { fill: am5.color(0x297373), stroke: am5.color(0x000000 } },\ { id: "C", nodeSettings: { fill: am5.color(0xFF621F), stroke: am5.color(0x000000 } },\ \]) series.data.setAll(\[\ { from: "A", to: "B", value: 10, linkSettings: { fill: am5.color(0x297373), fillOpacity: 0.5, fillStyle: "solid" } },\ { from: "B", to: "C", value: 8, linkSettings: { fill: am5.color(0xFF621F), fillOpacity: 0.5, fillStyle: "solid" } }\ \]); series.nodes.rectangles.template.set("templateField", "nodeSettings"); series.links.template.set("templateField", "linkSettings"); series.nodes.data.setAll(\[\ { id: "A", nodeSettings: { fill: am5.color(0xFF621F), stroke: am5.color(0x000000 } },\ { id: "B", nodeSettings: { fill: am5.color(0x297373), stroke: am5.color(0x000000 } },\ { id: "C", nodeSettings: { fill: am5.color(0xFF621F), stroke: am5.color(0x000000 } },\ \]) series.data.setAll(\[\ { from: "A", to: "B", value: 10, linkSettings: { fill: am5.color(0x297373), fillOpacity: 0.5, fillStyle: "solid" } },\ { from: "B", to: "C", value: 8, linkSettings: { fill: am5.color(0xFF621F), fillOpacity: 0.5, fillStyle: "solid" } }\ \]); See the Pen amCharts 5: Custom Sankey node colors by amCharts team (@amcharts) on CodePen. NOTEFor more information on how template fields work, visit "[Template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) " tutorial. Related tutorials ----------------- * [Images in Sankey nodes](https://www.amcharts.com/docs/v5/tutorials/images-in-sankey-nodes/) * [Selectively positioning Sankey diagram labels](https://www.amcharts.com/docs/v5/tutorials/selectively-positioning-sankey-diagram-labels/) --- # Chord diagram – amCharts 5 Documentation Flow chart ---------- A chord diagram is a flow chart. For generic flow chart related information, please visit "[Flow charts](https://www.amcharts.com/docs/v5/charts/flow-charts/) " tutorial. Types of chord -------------- There are three main types of chord series: regular, directed, and non-ribbon. The type of the series not only affects how links look, but also how value of the node is calculated, which in turn affects its width. | Regular series | Directed series | Non-ribbon series | | --- | --- | --- | | **`Chord`** | **`ChordDirected`** | **`ChordNonRibbon`** | | Node size depends on a sum of all outgoing links. | Node size depends on a sum of all incoming and outgoing links. | Node size is fixed regardless of actual values. | | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/cord_regular.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chord_directed.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/courd_non_ribbon.png) | Regular series -------------- Regular chord series is created using `Chord` class. It sizes nodes based on a sum of values of all outgoing links. let series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value" }) ); var series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value" }) ); See the Pen Sankey diagram by amCharts team (@amcharts) on CodePen. There are no special regular-chord-only settings. Directed series --------------- Chord directed sizes its nodes base on sum of **both** the outgoing and incoming links. It also indicates the direction of the link by adding an arrowhead at the target end. The length of the arrowhead is 10 pixels by default. We can change it by setting series' `linkHeadRadius` setting. We can also disable arrowhead altogether by setting `[linkHeadRadius](https://www.amcharts.com/docs/v5/reference/chorddirected/#linkHeadRadius_setting) ` to `null`: let series = root.container.children.push( am5flow.ChordDirected.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkHeadRadius: null }) ); var series = root.container.children.push( am5flow.ChordDirected.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkHeadRadius: null }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png) `linkHeadRadius: 10` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_20.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_20.png) `linkHeadRadius: 20` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_null.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_null.png) `linkHeadRadius: null` See the Pen Chord diagram by amCharts team (@amcharts) on CodePen. Non-ribbon series ----------------- Non-ribbon chord series does not take any value into account when sizing its nodes. It also displays links as thin lines, that are curved from source to target node. We can make them display as straight lines by setting series `[linkType](https://www.amcharts.com/docs/v5/reference/chordnonribbon/#linkType_setting) ` setting to `"line"`: let series = root.container.children.push( am5flow.ChordNonRibbon.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkType: "line" }) ); var series = root.container.children.push( am5flow.ChordNonRibbon.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", linkType: "line" }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linktype_curve.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linktype_curve.png) `linkType: "curve"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linktype_line.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linktype_line.png) `linkType: "line"` See the Pen Chord directed diagram by amCharts team (@amcharts) on CodePen. Nodes ----- ### Width Nodes (colored bands) are 10 pixel wide by default. We can use series setting `[nodeWidth](https://www.amcharts.com/docs/v5/reference/chord/#nodeWidth_setting) ` to change that: let series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodeWidth: 5 }) ); var series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", nodeWidth: 5 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png) `nodeWidth: 10` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nodewidth_30.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nodewidth_30.png) `nodeWidth: 30` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nodewidth_5.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/nodewidth_5.png) `nodeWidth: 5` ### Configuring nodes Nodes in flow diagrams are represented by their own series, accessible via read-only property `nodes` which is an object of type `ChordNodes`. It subsequently has a property `rectangles` which is a list of all nodes in series. Since it's a "list template", we can use its `template` property to set any setting for the node, which is of type `[Slice](https://www.amcharts.com/docs/v5/reference/slice/) `: series.nodes.rectangles.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeWidth: 1 }); series.nodes.rectangles.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeWidth: 1 }); See the Pen Chord diagram by amCharts team (@amcharts) on CodePen. ### Node data #### Setting node data In chord diagrams, node ids (and names) are derived from link data (via `sourceIdField` and `targetIdField`). In some cases, we might need more than just node id which comes from chord data. For that we can set own data on `series.nodes.data`: series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); #### Modifying data fields Node series (which is `ChordNodes`) is automatically set up for these data fields: | Data field | Default value | Comment | | --- | --- | --- | | `idField` | `"id"` | ID of the node. | | `nameField` | `"id"` | Name of the node. | | `fillField` | `"fill"` | Fill color for the node. | We can modify those to suit our data: series.nodes.setAll({ idField: "id", nameField: "name" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); series.nodes.setAll({ idField: "id", nameField: "name" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); IMPORTANTData fields need to be set before data or they will not work as expected. #### Node colors via data We can also specify custom colors for nodes via node data: series.nodes.data.setAll(\[\ { id: "A", name: "Node A", fill: am5.color(0xFF621F) },\ { id: "B", name: "Node B", fill: am5.color(0x297373) },\ { id: "C", name: "Node C", fill: am5.color(0x946B49) }\ \]); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", fill: am5.color(0xFF621F) },\ { id: "B", name: "Node B", fill: am5.color(0x297373) },\ { id: "C", name: "Node C", fill: am5.color(0x946B49) }\ \]); The fill color will be lookup up in a `"fill"` field of the data. If we need to use something else, we will need to configure node series' `fillField` as well: series.nodes.setAll({ idField: "id", nameField: "name", fillField: "color" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", color: am5.color(0xFF621F) },\ { id: "B", name: "Node B", color: am5.color(0x297373) },\ { id: "C", name: "Node C", color: am5.color(0x946B49) }\ \]); series.nodes.setAll({ idField: "id", nameField: "name", fillField: "color" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", color: am5.color(0xFF621F) },\ { id: "B", name: "Node B", color: am5.color(0x297373) },\ { id: "C", name: "Node C", color: am5.color(0x946B49) }\ \]); ### Gaps between nodes Chord diagrams display a tiny gap between each node by default. We can control the size of it using series' `[padAngle](https://www.amcharts.com/docs/v5/reference/chord/#padAngle_setting) ` setting. It accepts a numeric value in degrees. let series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", padAngle: 5 }) ); var series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", padAngle: 5 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png) `padAngle: 1` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/padangle_10.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/padangle_10.png) `padAngle: 10` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/padangle_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/padangle_0.png) `padAngle: 0` ### Ordering nodes Nodes in a chord diagram are ordered by their value: from biggest to smallest. To change the order, there's a series setting `[sort](https://www.amcharts.com/docs/v5/reference/chord/#sort_setting) ` with possible values: `"descending"` (default), `"ascending"`, and `"none"`. If set to `"none"` the nodes will appear in the same order by their first appearance in data. let series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", order: "none" }) ); var series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", order: "none" }) ); Radius ------ Chart's outer radius can be set using its `[radius](https://www.amcharts.com/docs/v5/reference/chord/#radius_setting) ` setting. It can be either percent value (relative to available space) or fixed pixel value. Chord diagram's `radius` is set to `90%` by default to leave some space for possible labels. let series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", radius: am5.percent(90) }) ); var series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", radius: am5.percent(90) }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png) `radius: am5.percent(90)` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chord_radius_95.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chord_radius_95.png) `radius: am5.percent(95)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chord_radius_50.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chord_radius_50.png) `radius: 100` Start angle ----------- Chord diagram usually starts at zero angle (or the "right" edge of the circle). That's where first node is drawn. We can change that using series' setting `[startAngle](https://www.amcharts.com/docs/v5/reference/chord/#startAngle_setting) `, which is a numeric value in degrees. The angle can also be negative number: let series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", startAngle: -90 }) ); var series = root.container.children.push( am5flow.Chord.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", startAngle: -90 }) ); ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/linkheadradius_default.png) `startAngle: 0` (default) ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chort_startangle_90.png) `startAngle: -90` Links ----- ### Configuring links We can configure links using series property `links.template`. Via template, we can set any [`ChordLink` setting](https://www.amcharts.com/docs/v5/reference/chordlink/#Settings) . series.links.template.setAll({ fillOpacity: 0.5 }); series.links.template.setAll({ fillOpacity: 0.5 }); ### Color mode Chord links can be colored in a number of ways via link template's `fillStyle` setting: series.links.template.setAll({ fillStyle: "solid" }); series.links.template.setAll({ fillStyle: "solid" }); These values are available for `fillStyle`: | `fillStyle` | Comment | Example | | --- | --- | --- | | `"solid"` (default) | Solid color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_fillstyle_solid.png) | | `"gradient"` | Gradient from source node color to target node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_fillstyle_gradient.png) | | `"source"` | Source node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_fillstyle_source.png) | | `"target"` | Target node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_fillstyle_target.png) | Labels ------ Chord diagram will display a label next to its nodes by default. ### Configuring labels Labels in chord diagram are attached to nodes, so they can be configured via `nodes` sub-series, specifically `nodes.labels.template`: series.nodes.labels.template.setAll({ fontSize: 20, maxWidth: 150, wrap: true }); series.nodes.labels.template.setAll({ fontSize: 20, maxWidth: 150, wrap: true }); Refer to [`RadialLabel` class reference](https://www.amcharts.com/docs/v5/reference/radiallabel/#Settings) for a full list of available settings. ### Label content To change label content, we only need to set `text` property of the label template: series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})" }); series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})" }); Contents of the label can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). For available data placeholder fields refer to `[IChordNodesDataItem](https://www.amcharts.com/docs/v5/reference/ichordnodesdataitem/) `. ### Label type Normally, chord series will use circular labels: ones that follow the curve of the node itself. This can be changed using label setting: `[textType](https://www.amcharts.com/docs/v5/reference/radiallabel/#textType_setting) `. Available values are: `"circular"` (default), `"radial"`, and `"adjusted"`. series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})", textType: "radial" }); series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})", textType: "radial" }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_labels_circular.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_labels_circular.png) `textType: "circular"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_labels_radial.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_labels_radial.png) `textType: "radial"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_labels_adjusted-1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/chord_labels_adjusted-1.png) `textType: "adjusted"` See the Pen Chord directed diagram by amCharts team (@amcharts) on CodePen. ### Label radius The distance between label and outer edge of the node is controlled by label's `radius` setting. It accepts numeric values in pixels, including negative values. The latter would put label inside the node. series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})", textType: "radial", radius: 20 }); series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})", textType: "radial", radius: 20 }); ### Disabling labels To disable labels, we can simply set their `forceHidden` to `true`: series.nodes.labels.template.set("forceHidden", true); series.nodes.labels.template.set("forceHidden", true); Tooltips -------- ### On links Links will display a tooltip when hovered/touched. The default content is `"{sourceId} - {targetId}: {value}"` which will show source node ID, followed by target node ID, and link value. To change it, we can use link's `tooltipText` setting: series.links.template.setAll({ tooltipText: "From: \[bold\]{sourceId}\[/\]\\nTo: \[bold\]{targetId}\\nValue: \[bold\]{value}\[/\]" }); series.links.template.setAll({ tooltipText: "From: \[bold\]{sourceId}\[/\]\\nTo: \[bold\]{targetId}\\nValue: \[bold\]{value}\[/\]" }); Contents of the tooltip can include data placeholders (codes in curly brackets that will be replaced by actual data) and in-line formatting blocks (formatting instructions enclosed in square brackets). For available data placeholder fields refer to `[IChordDataItem](https://www.amcharts.com/docs/v5/reference/ichorddataitem/) `. ### On nodes To add tooltips to nodes, simple set `tooltipText` on node template: series.nodes.rectangles.template.setAll({ tooltipText: "\[bold\]{name}\[/\]\\nOutgoing: {sumOutgoing}\\nIncoming: {sumIncoming}" }); series.nodes.rectangles.template.setAll({ tooltipText: "\[bold\]{name}\[/\]\\nOutgoing: {sumOutgoing}\\nIncoming: {sumIncoming}" }); For available data placeholder fields refer to `[IChordNodesDataItem](https://www.amcharts.com/docs/v5/reference/ichordnodesdataitem/) `. --- # Arc Diagram – amCharts 5 Documentation This tutorial contains information for creating Arc diagram. Flow chart ---------- An Arc diagram is a flow chart. For generic flow chart related information, please visit "[Flow charts](https://www.amcharts.com/docs/v5/charts/flow-charts/) " tutorial. Orientation ----------- Arc diagram is drawn horizontal by default. We can change it using series' `orientation` setting: let series = root.container.children.push( am5flow.ArcDiagram.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", orientation: "vertical" }) ); var series = root.container.children.push( am5flow.ArcDiagram.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", orientation: "vertical" }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_diagram_horizontal-1024x816.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_diagram_horizontal.png) `orientation: "horizontal"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_diagram_vertical-1024x816.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_diagram_vertical.png) `orientation: "vertical"` Nodes (circles) --------------- Nodes in Arc diagram are represented by circles. ### Circle radius The radius of the circles in an Arc diagram represent its relative value: the bigger the value, the bigger the circle. The value of a node is determined by sum of all incoming and outgoing links. We can change the value used in calculation of node's size using diagram's `radiusKey` setting: let series = root.container.children.push( am5flow.ArcDiagram.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", radiusKey: "sumIncoming" }) ); var series = root.container.children.push( am5flow.ArcDiagram.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", radiusKey: "sumIncoming" }) ); | Value | Comment | | --- | --- | | `"sum"` (default) | Sum of values of all incoming and outgoing links. | | `"sumIncoming"` | Sum of values of all incoming links. | | `"sumOutgoing"` | Sum of values of all outgoing links. | | `"none"` | No values are calculated. All circles will be the same size. | ### Minimal radius When sizing nodes, the diagram takes into account available space: the circle of each node will have its radius set proportionally to the highest available value. However, the diagram will not allow circles to get smaller than 5px radius, even if their value would call for a smaller circle. We can change this threshold using `minRadius` setting: let series = root.container.children.push( am5flow.ArcDiagram.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", minRadius: 10 }) ); var series = root.container.children.push( am5flow.ArcDiagram.new(root, { sourceIdField: "from", targetIdField: "to", valueField: "value", minRadius: 10 }) ); ### Configuring circles Nodes in Arc diagrams are represented by their own series, accessible via read-only property `nodes` which is an object of type `ArcDiagramNodes`. It subsequently has a property `circles` which is a list of all nodes in series. Since it's a "list template", we can use its `template` property to set any setting for the node, which is of type `[Circle](https://www.amcharts.com/docs/v5/reference/circle/) `: series.nodes.circles.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeWidth: 1 }); series.nodes.circles.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeWidth: 1 }); ### Node data #### Setting node data In Arc diagrams, node ids (and names) are derived from link data (via `sourceIdField` and `targetIdField`). In some cases, we might need more than just node id which comes from chord data. For that we can set own data on `series.nodes.data`: series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); IMPORTANTSetting node data must come **before** setting series data. #### Modifying data fields Node series (which is `ArcDiagramNodes`) is automatically set up for these data fields: | Data field | Default value | Comment | | --- | --- | --- | | `idField` | `"id"` | ID of the node. | | `nameField` | `"id"` | Name of the node. | | `fillField` | `"fill"` | Fill color for the node. | We can modify those to suit our data: series.nodes.setAll({ idField: "id", nameField: "name" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); series.nodes.setAll({ idField: "id", nameField: "name" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A" },\ { id: "B", name: "Node B" },\ { id: "C", name: "Node C" }\ \]); IMPORTANTData fields need to be set before data or they will not work as expected. #### Node colors via data We can also specify custom colors for nodes via node data: series.nodes.data.setAll(\[\ { id: "A", name: "Node A", fill: am5.color(0xFF621F) },\ { id: "B", name: "Node B", fill: am5.color(0x297373) },\ { id: "C", name: "Node C", fill: am5.color(0x946B49) }\ \]); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", fill: am5.color(0xFF621F) },\ { id: "B", name: "Node B", fill: am5.color(0x297373) },\ { id: "C", name: "Node C", fill: am5.color(0x946B49) }\ \]); The fill color will be lookup up in a `"fill"` field of the data. If we need to use something else, we will need to configure node series' `fillField` as well: series.nodes.setAll({ idField: "id", nameField: "name", fillField: "color" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", color: am5.color(0xFF621F) },\ { id: "B", name: "Node B", color: am5.color(0x297373) },\ { id: "C", name: "Node C", color: am5.color(0x946B49) }\ \]); series.nodes.setAll({ idField: "id", nameField: "name", fillField: "color" }); series.nodes.data.setAll(\[\ { id: "A", name: "Node A", color: am5.color(0xFF621F) },\ { id: "B", name: "Node B", color: am5.color(0x297373) },\ { id: "C", name: "Node C", color: am5.color(0x946B49) }\ \]); Links ----- ### Configuring links The links can be configured using `series.links.template`: series.links.template.setAll({ stroke: am5.color(0xff0000), strokeWidth: 5, strokeOpacity: 0.3 }); series.links.template.setAll({ stroke: am5.color(0xff0000), strokeWidth: 5, strokeOpacity: 0.3 }); Refer to the [class reference of the `ArcDiagramLink`](https://www.amcharts.com/docs/v5/reference/arcdiagramlink/#Settings) for more settings. ### Color mode The links can be colored in a number of ways via link template's `strokeStyle` setting: series.links.template.setAll({ fillStyle: "solid" }); series.links.template.setAll({ fillStyle: "solid" }); These values are available for `fillStyle`: | `fillStyle` | Comment | Example | | --- | --- | --- | | `"solid"` (default) | Solid color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_link_solid.png) | | `"gradient"` | Gradient from source node color to target node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_link_gradient.png) | | `"source"` | Source node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_link_source.png) | | `"target"` | Target node color. | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/07/arc_link_target.png) | Labels ------ ### Configuring labels Labels in an Arc diagram are attached to nodes, so they can be configured via `nodes` sub-series, specifically `nodes.labels.template`: series.nodes.labels.template.setAll({ fontSize: 20, maxWidth: 150, wrap: true }); series.nodes.labels.template.setAll({ fontSize: 20, maxWidth: 150, wrap: true }); Refer to [`Label` class reference](https://www.amcharts.com/docs/v5/reference/label/#Settings) for a full list of available settings. ### Label content To change label content, we only need to set `text` property of the label template: series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})" }); series.nodes.labels.template.setAll({ text: "\[bold\]{name}\[/\] ({sumOutgoing})" }); Contents of the label can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). For available data placeholder fields refer to `[IArcDiagramNodesDataItem](https://www.amcharts.com/docs/v5/reference/iarcdiagramnodesdataitem/) `. ### Alignment By default, labels are aligned to the center of the node (rotated vertically for the horizontal version of the diagram). We can use a combination of label's settings to control how they are aligned, positioned, and rotated: | Setting | Default (horizontal) | Default (vertical) | Comment | | --- | --- | --- | --- | | `centerY` | `am5.percent(50)` | `am5.percent(50)` | Vertical center of the label | | `centerX` | `am5.percent(100)` | `am5.percent(100)` | HNorizontal center of the label | | `rotation` | `-90` | \- | Rotation in degrees | | `paddingRight` | \- | `15` | Top padding | The following code will "unrotate" horizontal diagram's labels, as well as place them in the middle of the circle: series.nodes.labels.template.setAll({ rotation: 0, centerX: am5.percent(50) }); series.nodes.labels.template.setAll({ rotation: 0, centerX: am5.percent(50) }); ### Disabling labels To disable labels, we can simply set their `forceHidden` to `true`: series.nodes.labels.template.set("forceHidden", true); series.nodes.labels.template.set("forceHidden", true); Examples -------- ### Horizontal See the Pen Horizontal Arc Diagram by amCharts team (@amcharts) on CodePen. ### Vertical See the Pen Horizontal Arc Diagram by amCharts team (@amcharts) on CodePen. --- # Flow chart bullets – amCharts 5 Documentation This tutorial will look at how we can use bullets on flow charts. Adding bullets -------------- Flow charts are basically series, so bullets are added just like with any other series: by pushing bullet creation function into series' `bullets` list: series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0x000000) }) }); }); series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0x000000) }) }); }); This will add a bullet on each link in series. Location within link -------------------- By default, bullets will appear at the start of the link. We can use bullet's setting `locationX` or `locationY` to specify relative location within the span of the link. Chord bullets will always use `locationY`. Sankey bullets will depend on its orientation: horizontal Sankey bullets will use `locationX`, whereas vertical one will need their bullets to use `locationY`. It accepts numeric values from `0` (one, which means beginning of the link) and `1` (one, which means end of the link). The following will place bullets in the middle of the Sankey links: series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { location: 0.5, sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0x000000) }) }); }); series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { location: 0.5, sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0x000000) }) }); }); Inheriting bullet color ----------------------- Whenever bullet creation function kicks in, it will receive a related series data item (link) as a third parameter. We can use it to either access link's color, or a color of a source or destination nodes. The following will use `fill` of the link's source node: series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { locationX: 0.5, sprite: am5.Circle.new(root, { radius: 5, fill: dataItem.get("source").get("fill") }) }); }); series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { locationX: 0.5, sprite: am5.Circle.new(root, { radius: 5, fill: dataItem.get("source").get("fill") }) }); }); Relative rotation ----------------- A flow bullet can also be rotated automatically to follow the direction of the link in the location of the bullet. It doesn't matter for a circle bullet, but might make perfect sense for other shapes, e.g. a triangle or a label. We have a bullet setting `autoRotate` (default: `false`) for that: series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { locationX: 0.5, autoRotate: true, sprite: am5.Label.new(root, { text: "{sourceId} - {targetId}", fill: dataItem.get("source").get("fill"), centerX: am5.percent(50), textAlign: "middle", populateText: true }) }); }); series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { locationX: 0.5, autoRotate: true, sprite: am5.Label.new(root, { text: "{sourceId} - {targetId}", fill: dataItem.get("source").get("fill"), centerX: am5.percent(50), textAlign: "middle", populateText: true }) }); }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/sankey_bullet-1024x878.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/sankey_bullet.png) `autoRotate: false` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/sankey_bullet_autorotate-1024x878.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/sankey_bullet_autorotate.png) `autoRotate: true` See the Pen Sankey diagram with bullets by amCharts team (@amcharts) on CodePen. Relative rotation can also be further tweaked using another bullet setting: `autoRotateAngle`. If set, it will add additional degrees to the angle, calculated automatically. The following will create triangle arrowheads for bullets, and the `autoRotateAngle: 180` will make the point backwards: series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { locationX: 0.5, autoRotate: true, autoRotateAngle: 180, sprite: am5.Graphics.new(root, { fill: dataItem.get("source").get("fill"), centerY: am5.percent(50), centerX: am5.percent(50), draw: function (display) { display.moveTo(0, -6); display.lineTo(16, 0); display.lineTo(0, 6); display.lineTo(0, -6); } }) }); }); series.bullets.push(function(root, series, dataItem) { return am5.Bullet.new(root, { locationX: 0.5, autoRotate: true, autoRotateAngle: 180, sprite: am5.Graphics.new(root, { fill: dataItem.get("source").get("fill"), centerY: am5.percent(50), centerX: am5.percent(50), draw: function (display) { display.moveTo(0, -6); display.lineTo(16, 0); display.lineTo(0, 6); display.lineTo(0, -6); } }) }); }); See the Pen Sankey diagram with bullets by amCharts team (@amcharts) on CodePen. Dynamic updates and animation ----------------------------- We can update any bullet setting, including `locationX`/`locationY`, dynamically. bullet.set("locationX", 0.8); bullet.set("locationX", 0.8); We can also animate settings by creating a [setting animation](https://www.amcharts.com/docs/v5/concepts/animations/#Animating_settings) : bullet.animate({ key: "locationX", to: 0.8, from: 0.2, duration: Math.random() \* 1000 + 2000, loops: Infinity, easing: am5.ease.quad }); bullet.animate({ key: "locationX", to: 0.8, from: 0.2, duration: Math.random() \* 1000 + 2000, loops: Infinity, easing: am5.ease.quad }); See the Pen Sankey diagram with bullets by amCharts team (@amcharts) on CodePen. --- # Word cloud – amCharts 5 Documentation [Word clouds](https://en.wikipedia.org/wiki/Tag_cloud) (or tag clouds) help visualize weight or importance of individual words from a keyword list or a free-form text. Loading required modules ------------------------ Everything required to create word cloud are two amCharts 5 modules: "index" and "wordcloud". You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5wc from "@amcharts/amcharts5/wc"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. WordCloud series ---------------- Word clouds are chart-less. This means that rather than creating a chart element, we start by creating a series. Like everywhere else, we use its `new()` method to instantiate series, then push it `children` of a parent container. If we are not intending to add any other controls (e.g. legend, or title) to the chart, we can push directly to `root.container.children`, or we can create a [wrapper container](https://www.amcharts.com/docs/v5/charts/venn/#Additional_controls) as explained later on in this tutorial. let series = root.container.children.push( am5wc.WordCloud.new(root, { text: "One two three. One two. One." }) ); var series = root.container.children.push( am5wc.WordCloud.new(root, { text: "One two three. One two. One." }) ); Setting words ------------- There are two ways to set words to be displayed in the cloud: * Providing a plain text. * Providing a parsed list of words with their weight value. ### Using plain text #### Setting the source text If we have a text we need to analyze word frequency from, we can just set it as a `text` setting for the series: let series = root.container.children.push( am5wc.WordCloud.new(root, { text: "One two three. One two. One." }) ); var series = root.container.children.push( am5wc.WordCloud.new(root, { text: "One two three. One two. One." }) ); Word cloud will parse text, and will auto-assign weight to each unique word based on its frequency in text. #### Configuring word parser There are a few settings that text parser will take into account when generating list of words: | Setting key | Default | Comment | | --- | --- | --- | | `excludeWords` | \- | An array of words we don't want to appear in the word list. | | `maxCount` | \- | Maximum number of words in the final list. If there are more words than this settings, ones with the lowest weight (occurrence count) will be omitted. | | `minValue` | \- | The minimum number of occurrences for the word for it to be included in the list. | | `minWordLength` | `1` | The minimum number of characters in a word for it to be included in the list. | let series = root.container.children.push( am5wc.WordCloud.new(root, { excludeWords: \["the", "a", "an"\], // words "the", "a", and "an" will not appear in cloud maxCount: 100, // the cloud will limited to 100 words minValue: 2, // only words that appear twice or more in sourceText will appear in the cloud minWordLength: 2, // words must be 2 characters in length or more text: sourceText }) ); var series = root.container.children.push( am5wc.WordCloud.new(root, { excludeWords: \["the", "a", "an"\], // words "the", "a", and "an" will not appear in cloud maxCount: 100, // the cloud will limited to 100 words minValue: 2, // only words that appear twice or more in sourceText will appear in the cloud minWordLength: 2, // words must be 2 characters in length or more text: sourceText }) ); ### Using a word list We can also provide a list of words with their value (weight) as a series data: series.data.setAll(\[\ { category: "JavaScript", value: 64.96 },\ { category: "HTML/CSS", value: 56.07 },\ { category: "Python", value: 48.24 },\ { category: "SQL", value: 47.08 },\ { category: "Java", value: 35.35 },\ { category: "Node.js", value: 33.91 },\ { category: "TypeScript", value: 30.19 }\ \]); series.data.setAll(\[\ { category: "JavaScript", value: 64.96 },\ { category: "HTML/CSS", value: 56.07 },\ { category: "Python", value: 48.24 },\ { category: "SQL", value: 47.08 },\ { category: "Java", value: 35.35 },\ { category: "Node.js", value: 33.91 },\ { category: "TypeScript", value: 30.19 }\ \]); If we use `category` key for word, and `value` for word weight, we don't need to do anything else. Otherwise we would also need to set up `categoryField` and `valueField` for our series: let series = root.container.children.push(am5wc.WordCloud.new(root, { categoryField: "tag", valueField: "weight", })); series.data.setAll(\[\ { tag: "JavaScript", weight: 64.96 },\ { tag: "HTML/CSS", weight: 56.07 },\ { tag: "Python", weight: 48.24 },\ { tag: "SQL", weight: 47.08 },\ { tag: "Java", weight: 35.35 },\ { tag: "Node.js", weight: 33.91 },\ { tag: "TypeScript", weight: 30.19 }\ \ \]); var series = root.container.children.push(am5wc.WordCloud.new(root, { categoryField: "tag", valueField: "weight", })); series.data.setAll(\[\ { tag: "JavaScript", weight: 64.96 },\ { tag: "HTML/CSS", weight: 56.07 },\ { tag: "Python", weight: 48.24 },\ { tag: "SQL", weight: 47.08 },\ { tag: "Java", weight: 35.35 },\ { tag: "Node.js", weight: 33.91 },\ { tag: "TypeScript", weight: 30.19 }\ \ \]); Configuring ----------- ### Layout There is a number of settings that affect how words in the word cloud series are laid out. | Setting | Type | Default | Comment | | --- | --- | --- | --- | | `minFontSize` | `number` \| `Percent` | `2%` | The size of the smallest words. It can be set in pixels, or in `Percent`.

When using percent value, it will take series width or height (whichever is smaller) as a reference point. | | `maxFontSize` | `number \| Percent` | `20%` | The size of the biggest words. It can be set in pixels, or in `Percent`.

When using percent value, it will take series width or height (whichever is smaller) as a reference point. | | `randomness` | `number` (0-1) | `0.2` | How scattered words should be.

Zero means no randomness - all biggest words will be concentrated in the middle with smallest on the outside.

`1` means complete randomness, or each word can appear anywhere, regardless of its weight. | Below figures show how `randomness` affects the layout of the cloud: ![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/02/chrome_2019-02-24_17-19-09-1024x544.png) `randomness = 0` ![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/02/2019-02-24_17-19-58-1024x544.png) `randomness = 0.9` ![](https://www.amcharts.com/docs/v4/wp-content/uploads/sites/2/2019/02/2019-02-24_17-19-24-1024x544.png) `randomness = 0.5` ### Rotation Word cloud will alternate angle of words for a better fit. This will result in some words being horizontal, and some vertical. #### Setting possible angles Series setting responsible for identifying possible angles is named `angles`. It's an array of numbers, and the default is `[0, -90]` meaning that words can come at zero (horizontal) or 90 (vertical) angle. The only supported values are `0`, `90`, and `-90`. To make all words horizontal, set it to `[0]`. To make all vertical, use `[90]`. #### Rotating whole series Even though non-horizontal/vertical angles are not supported, the whole series can easily be rotated to achieve intermediate angle effect by `rotation` and relative centering settings to the series itself. let series = root.container.children.push( am5wc.WordCloud.new(root, { rotation: -45, centerX: am5.percent(50), centerY: am5.percent(50), x: am5.percent(50), y: am5.percent(50) text: sourceText }) ); var series = root.container.children.push( am5wc.WordCloud.new(root, { rotation: -45, centerX: am5.percent(50), centerY: am5.percent(50), x: am5.percent(50), y: am5.percent(50) text: sourceText }) ); Colors ------ There is a number of ways to set colors to all words or each word individually. ### Universal color To set a color to be used universally for all words, simply set `fill` setting for the label template: series.labels.template.setAll({ fontFamily: "Courier New", fill: am5.color(0x85FFC4) }); series.labels.template.setAll({ fontFamily: "Courier New", fill: am5.color(0x85FFC4) }); ### Via color set Word cloud series can automatically assign a new color out of a [color set](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/#Color_sets) . To make it happen we just need to assign an instance of `ColorSet` to `colors` setting of the series: let series = root.container.children.push( am5wc.WordCloud.new(root, { colors: am5.ColorSet.new(root, {}); text: sourceText }) ); var series = root.container.children.push( am5wc.WordCloud.new(root, { colors: am5.ColorSet.new(root, {}); text: sourceText }) ); Color set will use current theme when generating or using colors for each individual word. We can even provide our own list: let series = root.container.children.push( am5wc.WordCloud.new(root, { colors: am5.ColorSet.new(root, { colors: \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \] }); text: sourceText }) ); var series = root.container.children.push( am5wc.WordCloud.new(root, { colors: am5.ColorSet.new(root, { colors: \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \] }); text: sourceText }) ); ### Via data We can also use [template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) to specify which field in data holds object with label's setting values we want to override: series.labels.template.setAll({ fontFamily: "Courier New", templateField: "labelSettings" }); series.data.setAll(\[\ { category: "JavaScript", value: 64.96, labelSettings: { fill: am5.color(0x85FFC4) } },\ { category: "HTML/CSS", value: 56.07, labelSettings: { fill: am5.color(0x297373) } },\ { category: "Python", value: 48.24, labelSettings: { fill: am5.color(0x946B49) } },\ { category: "SQL", value: 47.08, labelSettings: { fill: am5.color(0xFF621F) } },\ { category: "Java", value: 35.35, labelSettings: { fill: am5.color(0x39393A) } }\ \]); series.labels.template.setAll({ fontFamily: "Courier New", templateField: "labelSettings" }); series.data.setAll(\[\ { category: "JavaScript", value: 64.96, labelSettings: { fill: am5.color(0x85FFC4) } },\ { category: "HTML/CSS", value: 56.07, labelSettings: { fill: am5.color(0x297373) } },\ { category: "Python", value: 48.24, labelSettings: { fill: am5.color(0x946B49) } },\ { category: "SQL", value: 47.08, labelSettings: { fill: am5.color(0xFF621F) } },\ { category: "Java", value: 35.35, labelSettings: { fill: am5.color(0x39393A) } }\ \]); MORE INFOFor more information, refer to "[Template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) " tutorial. ### Via heat rules We can automatically assign a color (or any other label setting value) from a range based on its weight (value) using a [heat rule](https://www.amcharts.com/docs/v5/concepts/settings/heat-rules/) . let series = root.container.children.push(am5wc.WordCloud.new(root, { calculateAggregates: true, minFontSize: am5.percent(5), maxFontSize: am5.percent(5), text: sourceText })); series.set("heatRules", \[{\ target: series.labels.template,\ dataField: "value",\ min: am5.color(0xFFB899),\ max: am5.color(0xCC3D00),\ key: "fill"\ }\]); var series = root.container.children.push(am5wc.WordCloud.new(root, { calculateAggregates: true, minFontSize: am5.percent(5), maxFontSize: am5.percent(5), text: sourceText })); series.set("heatRules", \[{\ target: series.labels.template,\ dataField: "value",\ min: am5.color(0xFFB899),\ max: am5.color(0xCC3D00),\ key: "fill"\ }\]); The above setup will make all words same size, but will apply different color based on their value. MORE INFOFor more information, refer to "[Heat rules](https://www.amcharts.com/docs/v5/concepts/settings/heat-rules/) " tutorial. Tooltips -------- Labels in a word cloud can display a tooltip if we set `tooltipText` on label's template: series.labels.template.set("tooltipText", "{category}: \[bold\]{value}\[/\]"); series.labels.template.set("tooltipText", "{category}: \[bold\]{value}\[/\]"); Contents of the tooltip can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5wc from "@amcharts/amcharts5/wc"; // Create root let root = am5.Root.new("chartdiv"); // Create series var wc = root.container.children.push(am5wc.WordCloud.new(root, { rotationThreshold: 0.7, maxCount: 200, minWordLength: 2, minFontSize: am5.percent(0.5), maxFontSize: am5.percent(30), text: "Though yet of Hamlet our dear brother's death The memory be green, and that it us befitted To bear our hearts in grief and our whole kingdom To be contracted in one brow of woe, Yet so far hath discretion fought with nature That we with wisest sorrow think on him, Together with remembrance of ourselves. Therefore our sometime sister, now our queen, The imperial jointress to this warlike state, Have we, as 'twere with a defeated joy,-- With an auspicious and a dropping eye, With mirth in funeral and with dirge in marriage, In equal scale weighing delight and dole,-- Taken to wife: nor have we herein barr'd Your better wisdoms, which have freely gone With this affair along. For all, our thanks. Now follows, that you know, young Fortinbras, Holding a weak supposal of our worth, Or thinking by our late dear brother's death Our state to be disjoint and out of frame, Colleagued with the dream of his advantage, He hath not fail'd to pester us with message, Importing the surrender of those lands Lost by his father, with all bonds of law, To our most valiant brother. So much for him. Now for ourself and for this time of meeting: Thus much the business is: we have here writ To Norway, uncle of young Fortinbras,-- Who, impotent and bed-rid, scarcely hears Of this his nephew's purpose,--to suppress His further gait herein; in that the levies, The lists and full proportions, are all made Out of his subject: and we here dispatch You, good Cornelius, and you, Voltimand, For bearers of this greeting to old Norway; Giving to you no further personal power To business with the king, more than the scope Of these delated articles allow. Farewell, and let your haste commend your duty. Tis sweet and commendable in your nature, Hamlet,To give these mourning duties to your father: But, you must know, your father lost a father; That father lost, lost his, and the survivor bound In filial obligation for some term To do obsequious sorrow: but to persever In obstinate condolement is a course Of impious stubbornness; 'tis unmanly grief; It shows a will most incorrect to heaven, A heart unfortified, a mind impatient, An understanding simple and unschool'd: For what we know must be and is as common As any the most vulgar thing to sense, Why should we in our peevish opposition Take it to heart? Fie! 'tis a fault to heaven, A fault against the dead, a fault to nature, To reason most absurd: whose common theme Is death of fathers, and who still hath cried, From the first corse till he that died to-day, 'This must be so.' We pray you, throw to earth This unprevailing woe, and think of us As of a father: for let the world take note, You are the most immediate to our throne; And with no less nobility of love Than that which dearest father bears his son, Do I impart toward you. For your intent In going back to school in Wittenberg, It is most retrograde to our desire: And we beseech you, bend you to remain Here, in the cheer and comfort of our eye, Our chiefest courtier, cousin, and our son." }));
See the Pen amCharts 5: Word cloud by amCharts team (@amcharts) on CodePen. Additional controls ------------------- Word cloud is a "container-less" chart. This means that there's no wrapper "chart" element, that can be used to add series and external controls to. If we don't need anything else besides series, we can add it directly to the container of the root element. However, if we need to add other elements, we'll need to first create a "wrapper (or main) container", we'll be using add all the stuff (including the word cloud series) to: let container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); let series = root.container.children.push( am5wc.WordCloud.new(root, { text: "One two three. One two. One." }) ); var container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); var series = root.container.children.push( am5wc.WordCloud.new(root, { text: "One two three. One two. One." }) ); NOTEThe `layout` setting of the wrapper container will determine how chart elements are laid out. For more information, refer to "Containers: [Layout](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Layout) ". ### Chart title Chart title can be added as a `Label` element child to the wrapper container: let title = container.children.push(am5.Label.new(root, { text: "Most common programming languages", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); var title = container.children.push(am5.Label.new(root, { text: "Most common programming languages", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); Events ------ We can add events like `click` on label template: series.labels.template.events.on("click", (ev: any) => { const category = ev.target.dataItem.get("category"); window.open("https://www.google.com/search?q=" + encodeURIComponent(category)); }); series.labels.template.events.on("click", (ev: any) => { const category = ev.target.dataItem.get("category"); window.open("https://www.google.com/search?q=" + encodeURIComponent(category)); }); The above will open a Google search with the clicked word. See the Pen amCharts 5: Word cloud by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Adding words to existing WordCloud](https://www.amcharts.com/docs/v5/tutorials/adding-words-to-existing-wordcloud/) * [WordCloud with hover effects on words](https://www.amcharts.com/docs/v5/tutorials/wordcloud-with-hover-effects-on-words/) * [Auto-exporting a WordCloud](https://www.amcharts.com/docs/v5/tutorials/auto-exporting-a-wordcloud/) --- # Venn diagram – amCharts 5 Documentation [Venn diagrams](https://en.wikipedia.org/wiki/Venn_diagram) are used to depict common qualities between different items by visualizing them as overlapping circles. Loading required modules ------------------------ Everything required to create Venn diagrams are two amCharts 5 modules: "index" and "venn". You can import those in your TypeScript / ES6 application as JavaScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5venn from "@amcharts/amcharts5/venn"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Venn series ----------- Venn diagrams are chart-less. This means that rather than creating a chart element, we start by creating a series. ### Adding Like everywhere else, we use its `new()` method to instantiate series, then push it `children` of a parent container. If we are not intending to add any other controls (e.g. legend, or title) to the chart, we can push directly to `root.container.children`, or we can create a [wrapper container](https://www.amcharts.com/docs/v5/charts/venn/#Additional_controls) as explained later on in this tutorial. let series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets" }) ); var series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets" }) ); ### Data fields Venn diagram uses these data fields: * Category. * Value. * List of overlapping categories (optional). Data fields basically mean which keys in data objects to look for specific value. They can be set via series' settings `categoryField`, `valueField`, and `intersectionsField`. Let's take sample data: \[\ { name: "A", value: 10 },\ { name: "B", value: 8 },\ { name: "C", value: 5 },\ { name: "X", value: 2, sets: \["A", "B"\] },\ { name: "Y", value: 2, sets: \["A", "C"\] },\ { name: "Z", value: 2, sets: \["B", "C"\] },\ { name: "Q", value: 1, sets: \["A", "B", "C"\]\ \] The following data fields would need to describe data fields like this: let series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets" }) ); var series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets" }) ); ### Setting data Each data item can mean either a separate category/circle or an intersection. If there's a value in a data item for `intersectionsField`, the item will be an intersection. Otherwise data item will be treated as a separate circle. The data is set directly on series via its `data` property: series.data.setAll(\[\ { name: "A", value: 10 },\ { name: "B", value: 8 },\ { name: "C", value: 5 },\ { name: "X", value: 2, sets: \["A", "B"\] },\ { name: "Y", value: 2, sets: \["A", "C"\] },\ { name: "Z", value: 2, sets: \["B", "C"\] },\ { name: "Q", value: 1, sets: \["A", "B", "C"\]\ \]); series.data.setAll(\[\ { name: "A", value: 10 },\ { name: "B", value: 8 },\ { name: "C", value: 5 },\ { name: "X", value: 2, sets: \["A", "B"\] },\ { name: "Y", value: 2, sets: \["A", "C"\] },\ { name: "Z", value: 2, sets: \["B", "C"\] },\ { name: "Q", value: 1, sets: \["A", "B", "C"\]\ \]); IMPORTANTIt's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. MORE INFOThere are more ways to set, update, add, or load data. For more information please refer to our dedicated "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. ### Circles vs intersections If data for the item contains only category and value, it will be shown as a full circle. If there's also am array of intersecting categories (circles), it will be shown as an intersection of listed circles. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/venn.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/venn.png) Data: `{ name: "A", value: 10 }` `{ name: "B", value: 10 }` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/venn_intersecting.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/10/venn_intersecting.png) Data: `{ name: "A", value: 10 }` `{ name: "B", value: 10 }` `{ name: "X", value: 4, sets: ["A", "B"] }` Let's take a look at the above two examples. The first one defines two circles with identical values. There are no intersections defined between the two, so they are drawn as separate circles. The second example adds an extra item in data, which defines a value for an intersection between "A" and "B". This results in proportional overlap of the two circles. ### Data order Slices are drawn in the same order as they appear in data. This means that we need to make sure that smaller slices (especially intersections) that need to be displayed on to come last in the data, so they are not obstructed by larger chart elements. Slices ------ Venn diagram consist of circles and intersections. For the sake of simplicity, let's call all of them "slices". ### Colors Slice colors are important. They identify a slice and connect it to its legend item visually. There are a few ways to control how colors are assigned to slices. #### Auto-assigned colors A series will automatically assign a unique color to each slice from its own [color set](https://www.amcharts.com/docs/v5/reference/xychart/#colors_setting) . Should we want to, we can override the whole list of colors by either setting it directly on series color set, creating a [quick theme](https://www.amcharts.com/docs/v5/concepts/themes/#Quick_custom_theme) , or a [reusable full theme](https://www.amcharts.com/docs/v5/concepts/themes/creating-themes/) , e.g.: series.get("colors").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); series.get("colors").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); MORE INFOA "[Color sets](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/#Setting_own_list_of_colors) " section of our color tutorial has more details and code samples. #### Color data field We can use Venn's setting `fillField` to bind slice color to a field in data. let series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets", fillField: "color" }) ); series.data.setAll(\[\ { name: "A", value: 10, color: am5.color(0x095256) },\ { name: "B", value: 10, color: am5.color(0x087f8c) },\ { name: "X", value: 5, sets: \["A", "B"\], color: am5.color(0x5aaa95) }\ }\]); var series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets", fillField: "color" }) ); series.data.setAll(\[\ { name: "A", value: 10, color: am5.color(0x095256) },\ { name: "B", value: 10, color: am5.color(0x087f8c) },\ { name: "X", value: 5, sets: \["A", "B"\], color: am5.color(0x5aaa95) }\ }\]); #### Template fields We can also specify color for each slice through data and template fields. Template fields allow binding element's properties to an object in data: series.slices.template.setAll({ tooltipText: "{category}", templateField: "sliceSettings" }); series.data.setAll(\[\ { name: "A", value: 10, sliceSettings: { fill: am5.color(0x095256) } },\ { name: "B", value: 10, sliceSettings: { fill: am5.color(0x087f8c) } },\ { name: "X", value: 5, sets: \["A", "B"\], sliceSettings: { fill: am5.color(0x5aaa95) } }\ }\]); series.slices.template.setAll({ tooltipText: "{category}", templateField: "sliceSettings" }); series.data.setAll(\[\ { name: "A", value: 10, sliceSettings: { fill: am5.color(0x095256) } },\ { name: "B", value: 10, sliceSettings: { fill: am5.color(0x087f8c) } },\ { name: "X", value: 5, sets: \["A", "B"\], sliceSettings: { fill: am5.color(0x5aaa95) } }\ }\]); For more information on how template fields work, refer to "[Template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) " tutorial. ### Configuring slices Configuration of a slice is done via its template, which is accessible via series template list: `series.slices.template`. We can set any setting via template: series.slices.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0xffffff), strokeWidth: 2 }); series.slices.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0xffffff), strokeWidth: 2 }); NOTESetting a value on a template will also update existing slices created using it. ### Hovers When a slice is hovered, a special visual element is shown over it to highlight the shape of a hovered slice. We can configure it using Venn's `hoverGraphics` which holds an instance of `[Graphics](https://www.amcharts.com/docs/v5/reference/graphics/) ` to configure its appearance. series.hoverGraphics.setAll({ strokeDasharray: \[3, 3\], stroke: am5.color(0xffffff), strokeWidth: 2 }); series.hoverGraphics.setAll({ strokeDasharray: \[3, 3\], stroke: am5.color(0xffffff), strokeWidth: 2 }); The above will make the chart show a white dashed outline of the circle or intersection hovered. Labels ------ ### Configuring labels Label configuration is done via its template, accessible via series property `labels.template`. series.labels.template.setAll({ fontSize: 20, fill: am5.color(0x550000), text: "{category}" }); series.labels.template.setAll({ fontSize: 20, fill: am5.color(0x550000), text: "{category}" }); Pie series uses `[Label](https://www.amcharts.com/docs/v5/reference/label/) ` elements for its labels. Check out its class reference for all the [possible settings](https://www.amcharts.com/docs/v5/reference/label/#Settings) . ### Label content Slice labels are pre-set to display name of the category. We can modify contents of the tooltips using `text` setting on a series label template: series.labels.template.set("text", "{category}: \[bold\]{value}\[/\])"); series.labels.template.set("text", "{category}: \[bold\]{value}\[/\])"); Contents of the label can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). ### Disabling labels To disable series labels, we can set `forceHidden` setting to `true` in their template: series.labels.template.set("forceHidden", true); series.labels.template.set("forceHidden", true); Tooltips -------- Slices in a Venn diagram are pre-set to display a tooltip on hover containing name of the category value. We can modify contents of the tooltips using `tooltipText` on slice's template: series.slices.template.set("tooltipText", "{category}: \[bold\]{value}\[/\]"); series.slices.template.set("tooltipText", "{category}: \[bold\]{value}\[/\]"); Contents of the tooltip can include [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) (codes in curly brackets that will be replaced by actual data) and [in-line formatting blocks](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) (formatting instructions enclosed in square brackets). Additional controls ------------------- Venn diagram is a "container-less" chart. This means that there's no wrapper "chart" element, that can be used to add series and external controls to. If we don't need anything else besides series, we can add it directly to the container of the root element. However, if we need to add other elements, we'll need to first create a "wrapper (or main) container", we'll be using add all the stuff (including Venn diagram itself) to: let container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); let series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets" }) ); var container = root.container.children.push(am5.Container.new(root, { width: am5.percent(100), height: am5.percent(100), layout: root.verticalLayout })); var series = root.container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets" }) ); NOTEThe `layout` setting of the wrapper container will determine how chart elements are laid out. For more information, refer to "Containers: [Layout](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Layout) ". ### Chart title Chart title can be added as a `Label` element child to the wrapper container: let title = container.children.push(am5.Label.new(root, { text: "Types of coffee", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); var title = container.children.push(am5.Label.new(root, { text: "Types of coffee", fontSize: 20, x: am5.percent(50), centerX: am5.percent(50) })); ### Legend To add a legend, we simply need to create an instance of a `Legend` class (which is a part of "index" package), push it to our wrapper container's children (or any other place we want it to be), as well as set its data (in case of a Venn diagram, we will probably want to use series data items as legend items). let legend = container.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.dataItems); var legend = container.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.dataItems); MORE INFOFor more information on how to configure legend, its items, and layout, please visit our dedicated "[Legend](https://www.amcharts.com/docs/v5/concepts/legend/) " tutorial. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5venn from "@amcharts/amcharts5/venn"; // Create root let root = am5.Root.new("chartdiv"); // Create wrapper container let container = root.container.children.push( am5.Container.new(root, { width: am5.p100, height: am5.p100, layout: root.verticalLayout }) ); // Create venn series let series = container.children.push( am5venn.Venn.new(root, { categoryField: "name", valueField: "value", intersectionsField: "sets", paddingTop: 40, paddingBottom: 40, paddingLeft: 40, paddingRight: 40 }) ); // Set data series.data.setAll(\[\ { name: "A", value: 10 },\ { name: "B", value: 10 },\ { name: "C", value: 5 },\ { name: "X", value: 4, sets: \["A", "B"\] },\ { name: "Y", value: 2, sets: \["A", "C"\] },\ { name: "Z", value: 2, sets: \["B", "C"\] },\ { name: "Q", value: 1, sets: \["A", "B", "C"\]\ }\]); // Set tooltip content series.slices.template.set("tooltipText", "{category}: {value}"); // Set up hover appearance series.hoverGraphics.setAll({ strokeDasharray: \[3, 3\], stroke: am5.color(0xffffff), strokeWidth: 2 }); // Add legend let legend = container.children.push( am5.Legend.new(root, { centerX: am5.p50, x: am5.p50 }) ); legend.data.setAll(series.dataItems);
See the Pen amCharts 5: Venn diagram by amCharts team (@amcharts) on CodePen. --- # Stock chart – amCharts 5 Documentation Stock chart is a powerful tool - part of amCharts 5 library - used to visualize date/time-based data and analyze it. This tutorial walks through steps of creating, configuring, and using it. Introduction ------------ During the course of this tutorial, we will review what it takes to build an absolute minimum stock chart. Where applicable we will link to related tutorials, with more advanced functionality. Chart components ---------------- Before we dive in deeper, let's get familiar with essential terminology and components comprising stock chart. The chart itself consist of the following components: * Stock chart - it's basically a wrapper for everything else. * Panels - instances of `StockPanel` (which is basically an `XYChart`), synced with each other in zoom and cursor, arranged vertically, with ability to resize, add new ones. * Series, indicators, annotations - plotted info using data or user-drawn interactions. * Tools - a toolbar with stock tools: drawing, comparisons, indicators, settings, etc. We will cover all these in this and related tutorials. Loading required modules ------------------------ Stock chart requires three amCharts 5 modules: `"index"`, `"xy"`, and `"stock"`. You can import those in your TypeScript / ES6 application as JavScript modules: import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import \* as am5stock from "@amcharts/amcharts5/stock"; For vanilla JavaScript applications and web pages, you can use "script" version: MORE INFO For more information on installing amCharts 5 as well as loading modules refer to our "[Getting started](https://www.amcharts.com/docs/v5/getting-started/) " tutorial. Instantiating the chart ----------------------- As with any chart type in amCharts 5, we'll need to start with creation of the `Root` element. In it we will create an instance of a `StockChart` class: let root = am5.Root.new("chartdiv"); let stockChart = root.container.children.push( am5stock.StockChart.new(root, {}) ); var root = am5.Root.new("chartdiv"); var stockChart = root.container.children.push( am5stock.StockChart.new(root, {}) ); MORE INFO The notion of creating class instances using `.new()` method is described in "[Creating a chart](https://www.amcharts.com/docs/v5/getting-started/#Creating_a_chart) " section in the "Getting started" tutorial. Make sure you check it out. Panels ------ A "panel" in a stock chart is an instance of a `StockPanel` which in turn extends `XYChart` pushed into `panels` list. Basically, anything you can and need do with an XY chart, you can do with a stock panel. MORE INFOFor a complete guide on how to configure an XY chart, please refer to "[XY chart](https://www.amcharts.com/docs/v5/charts/xy-chart/) " tutorial section. The following code will add a single panel (chart). Let's call it a "main chart". let mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); var mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); MORE INFOPanels/charts are configurable. For a complete rundown of their configuration features, visit "[Panels](https://www.amcharts.com/docs/v5/charts/stock/panels/) " tutorial. Stock chart will also take care of syncing zoom across multiple panels, automatically. Adding axes ----------- Since an XY chart requires at least two axes (X and Y) to function, we'll need to add those to panel's (chart), too. While regular XY chart can accept any combination of axes types, when used as a panel, it needs its X axis to be a [date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) , and its Y axis to be a [value axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/) - we'll be plotting a date/time-based value data. let valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) })); let dateAxis = mainPanel.xAxes.push(am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); var valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) })); var dateAxis = mainPanel.xAxes.push(am5xy.DateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); MORE INFOFor more information on adding and configuring axes on an XY chart, refer to "[Axes](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/) " tutorial. Series ------ ### Adding series Series in stock chart are added to `series` list of its panels. Technically, a panel (which is an XY chart) or its series do not even know they're part of something bigger - a stock chart. Let's add a simple line series to our "main" panel. let valueSeries = mainPanel.series.push(am5xy.LineSeries.new(root, { name: "STCK", valueXField: "Date", valueYField: "Close", xAxis: dateAxis, yAxis: valueAxis, })); valueSeries.data.setAll(data); var valueSeries = mainPanel.series.push(am5xy.LineSeries.new(root, { name: "STCK", valueXField: "Date", valueYField: "Close", xAxis: dateAxis, yAxis: valueAxis, })); valueSeries.data.setAll(data); MORE INFORefer to "[Series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/) " tutorial for more information about configuration options. ### Setting main series Stock chart goes beyond regular XY charts by providing a lot of additional analytical tools like indicators, trend drawing, as well as comparisons of different indexes. Those rely on data from main series. Stock chart recognizes two main series: value and volume. Some indicators and tools just use "value main series", others rely on "volume main series", while some need both. We can use stock chart's settings `valueSeries` and `volumeSeries` to set which series to use for those analytical tools. stockChart.set("stockSeries", valueSeries); stockChart.set("stockSeries", valueSeries); While volume series is less frequently required, value series is relied upon quite heavily throughout stock chart, so it's a good practice to set it, even if we're not sure we'll need it. stockChart.set("volumeSeries", volumeSeries); stockChart.set("volumeSeries", volumeSeries); In case we don't need it displayed, we can create a hidden volume series: let volumeValueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, { forceHidden: true, renderer: am5xy.AxisRendererY.new(root, {}) })); volumeValueAxis.get("renderer").grid.template.set("forceHidden", true); volumeValueAxis.get("renderer").labels.template.set("forceHidden", true); let volumeSeries = mainPanel.series.push(am5xy.ColumnSeries.new(root, { valueXField: "Date", valueYField: "Volume", xAxis: dateAxis, yAxis: volumeValueAxis, forceHidden: true })); stockChart.set("volumeSeries", volumeSeries); var volumeValueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, { forceHidden: true, renderer: am5xy.AxisRendererY.new(root, {}) })); volumeValueAxis.get("renderer").grid.template.set("forceHidden", true); volumeValueAxis.get("renderer").labels.template.set("forceHidden", true); var volumeSeries = mainPanel.series.push(am5xy.ColumnSeries.new(root, { valueXField: "Date", valueYField: "Volume", xAxis: dateAxis, yAxis: volumeValueAxis, forceHidden: true })); stockChart.set("volumeSeries", volumeSeries); ### Positive/negative colors Main value series (set on `stockSeries`) and main volume series (set on `volumeSeries`) will use two colors if they are of type column, candlestick, or OHLC. They will use "negative" and "positive" colors from the default [interface color set](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/#Interface_colors) . Negative color will be used for items that have their close value lower than their open. Positive color will be used for the rest of the series items. Unless we want to modify default theme, we ca use these for stock chart settings to control those colors: * `stockPositiveColor` * `stockNegativeColor` * `volumePositiveColor` * `volumeNegativeColor` Values in `stockPositiveColor` and `stockNegativeColor` will affect only main value series, while `valuePostiveColor` and `valueNegativeColor` will affect main volume series. These settings do not have any effect on any other series of the chart. let stockChart = root.container.children.push( am5stock.StockChart.new(root, { stockPositiveColor: am5.color(0x999999), stockNegativeColor: am5.color(0x000000), volumePositiveColor: am5.color(0x999999), volumeNegativeColor: am5.color(0x000000) }) ); var stockChart = root.container.children.push( am5stock.StockChart.new(root, { stockPositiveColor: am5.color(0x999999), stockNegativeColor: am5.color(0x000000), volumePositiveColor: am5.color(0x999999), volumeNegativeColor: am5.color(0x000000) }) ); To completely remove built-in coloring, you can use `null` in place of the actual color: let stockChart = root.container.children.push( am5stock.StockChart.new(root, { stockPositiveColor: null, stockNegativeColor: null, volumePositiveColor: null, volumeNegativeColor: null }) ); var stockChart = root.container.children.push( am5stock.StockChart.new(root, { stockPositiveColor: null, stockNegativeColor: null, volumePositiveColor: null, volumeNegativeColor: null }) ); Legend ------ In stock chart, we can use both the [regular legend](https://www.amcharts.com/docs/v5/charts/xy-chart/legend-xy-series/) that we'd use in an XY chart, as well as advanced special "sock legend". The latter offers enhanced view as well as tools to edit related series/indicators. To ad a stock legend, we'll use a `StockLegend` class instead of `Legend`: let valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, { stockChart: stockChart })); valueLegend.data.setAll(\[valueSeries\]); var valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, { stockChart: stockChart })); valueLegend.data.setAll(\[valueSeries\]); The important difference from regular legend is that stock legend is designed to be displayed over the plot area, so we push it into main panel's `plotContainer`. Another difference is that because of additional functionality, stock legend requires to know what its stock chart it, hence us setting `stockChart` in the above code. If we wanted we could use a regular legend here as well: let valueLegend = valueAxis.axisHeader.children.push(am5.Legend.new(root, {})); valueLegend.data.setAll(\[valueSeries\]); var valueLegend = valueAxis.axisHeader.children.push(am5.Legend.new(root, {})); valueLegend.data.setAll(\[valueSeries\]); NOTEFor more about stock legend, visit "[Stock legend](https://www.amcharts.com/docs/v5/charts/stock/stock-legend/) " tutorial. Cursors ------- Cursors work the same way as in XY charts: by creating an instance of `XYCursor` and supplying it to panel's (chart's) `cursor` setting. mainPanel.set("cursor", am5xy.XYCursor.new(root, { yAxis: valueAxis, xAxis: dateAxis })); mainPanel.set("cursor", am5xy.XYCursor.new(root, { yAxis: valueAxis, xAxis: dateAxis })); Cursor needs to be added to each panel individually. Stock chart will take care of syncing cursor position across all panels, automatically. MORE INFORefer to "[Cursor](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/) " tutorial for more information. Scrollbar --------- Adding a scrollbar is identical how we would do it in an XY chart, except for pushing it into chart/panel's children, we use a special container on a stock chart: `toolsContainer`: let scrollbar = mainPanel.set("scrollbarX", am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 })); stockChart.toolsContainer.children.push(scrollbar); let sbDateAxis = scrollbar.chart.xAxes.push(am5xy.GaplessDateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); let sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) })); let sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, { valueYField: "Close", valueXField: "Date", xAxis: sbDateAxis, yAxis: sbValueAxis })); sbSeries.fills.template.setAll({ visible: true, fillOpacity: 0.3 }); sbSeries.data.setAll(data); var scrollbar = mainPanel.set("scrollbarX", am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 })); stockChart.toolsContainer.children.push(scrollbar); var sbDateAxis = scrollbar.chart.xAxes.push(am5xy.GaplessDateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); var sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) })); var sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, { valueYField: "Close", valueXField: "Date", xAxis: sbDateAxis, yAxis: sbValueAxis })); sbSeries.fills.template.setAll({ visible: true, fillOpacity: 0.3 }); sbSeries.data.setAll(data); If we'd like to place the scrollbar at the bottom of the panel instead, we can push it into panel's `bottomAxesContainer` instead: mainPanel.bottomAxesContainer.children.push(scrollbar); mainPanel.bottomAxesContainer.children.push(scrollbar); MORE INFOLook for more info about adding scrollbars in our "[Scrollbars](https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/) " tutorial. Complete example ---------------- import \* as am5 from "@amcharts/amcharts5"; import \* as am5xy from "@amcharts/amcharts5/xy"; import \* as am5xy from "@amcharts/amcharts5/stock"; // Define source data let data = \[\ { Date: 1636495200000, Open: 106.75, High: 119.459999, Low: 95.199997, Close: 100.730003, Volume: 103679500 },\ { Date: 1636581600000, Open: 114.625, High: 125, Low: 108.010002, Close: 122.989998, Volume: 83668200 },\ { Date: 1636668000000, Open: 128.645004, High: 135.199997, Low: 125.25, Close: 129.949997, Volume: 50437500 },\ { Date: 1636927200000, Open: 130.800003, High: 152.529999, Low: 127.510002, Close: 149.360001, Volume: 64982300 },\ { Date: 1637013600000, Open: 163.800003, High: 179.470001, Low: 153.779999, Close: 172.009995, Volume: 94036600 },\ { Date: 1637100000000, Open: 160.880005, High: 163, Low: 140.350006, Close: 146.070007, Volume: 71765600 },\ { Date: 1637186400000, Open: 136.809998, High: 138.779999, Low: 120.150002, Close: 123.379997, Volume: 63603600 },\ { Date: 1637272800000, Open: 129.979996, High: 139.899994, Low: 125.599998, Close: 128.600006, Volume: 49479400 },\ { Date: 1637532000000, Open: 123.879997, High: 124.93, Low: 106.910004, Close: 118.110001, Volume: 40993900 },\ { Date: 1637618400000, Open: 117.830002, High: 124, Low: 113, Close: 119.849998, Volume: 24967900 },\ { Date: 1637704800000, Open: 119.379997, High: 120, Low: 113.449997, Close: 114.849998, Volume: 11539200 },\ { Date: 1637877600000, Open: 111, High: 114.5, Low: 106.139999, Close: 112.129997, Volume: 9871200 },\ { Date: 1638136800000, Open: 115.849998, High: 122.25, Low: 113.599998, Close: 119.769997, Volume: 13923900 },\ { Date: 1638223200000, Open: 119.900002, High: 121.489998, Low: 114.099998, Close: 119.760002, Volume: 20204900 },\ { Date: 1638309600000, Open: 120.540001, High: 126.75, Low: 113.099998, Close: 115.690002, Volume: 13289700 },\ { Date: 1638396000000, Open: 114.169998, High: 118.449997, Low: 107.75, Close: 110.769997, Volume: 10835500 },\ { Date: 1638482400000, Open: 110.489998, High: 111.870003, Low: 100, Close: 104.669998, Volume: 13802500 },\ { Date: 1638741600000, Open: 106.360001, High: 117.480003, Low: 100.32, Close: 116.779999, Volume: 19725400 },\ { Date: 1638828000000, Open: 119.519997, High: 120.209999, Low: 112.400002, Close: 116.18, Volume: 12173300 },\ { Date: 1638914400000, Open: 116.220001, High: 123.400002, Low: 112.82, Close: 122.120003, Volume: 12816000 },\ { Date: 1639000800000, Open: 119.949997, High: 121.32, Low: 114.400002, Close: 115.400002, Volume: 8474800 },\ { Date: 1639087200000, Open: 115.709999, High: 118.010002, Low: 110.801003, Close: 114.660004, Volume: 8336800 },\ { Date: 1639346400000, Open: 118.139999, High: 121.639999, Low: 113.949997, Close: 118.900002, Volume: 14737500 },\ { Date: 1639432800000, Open: 114.769997, High: 117.900002, Low: 112.709999, Close: 117.139999, Volume: 8057700 },\ { Date: 1639519200000, Open: 115.470001, High: 116.738998, Low: 109.209999, Close: 115, Volume: 10828600 },\ { Date: 1639605600000, Open: 116.760002, High: 117, Low: 107.059998, Close: 108.870003, Volume: 13627600 },\ { Date: 1639692000000, Open: 99.919998, High: 100.599998, Low: 92.620003, Close: 97.699997, Volume: 44454800 },\ { Date: 1639951200000, Open: 94.800003, High: 96.400002, Low: 88.400002, Close: 89.980003, Volume: 16072700 },\ { Date: 1640037600000, Open: 92.190002, High: 98.419998, Low: 92.050003, Close: 96.82, Volume: 12915100 },\ { Date: 1640124000000, Open: 96.388, High: 98.900002, Low: 93.391998, Close: 96.339996, Volume: 8644100 },\ { Date: 1640210400000, Open: 96.350998, High: 97.821999, Low: 93.814003, Close: 96.839996, Volume: 5670100 },\ { Date: 1640556000000, Open: 96.900002, High: 107.489998, Low: 96.800003, Close: 107.089996, Volume: 15497000 },\ { Date: 1640642400000, Open: 105.040001, High: 106, Low: 101, Close: 102.870003, Volume: 8821300 },\ { Date: 1640728800000, Open: 101.190002, High: 102.580002, Low: 96.620003, Close: 99.339996, Volume: 8754900 },\ { Date: 1640815200000, Open: 98.851997, High: 105.290001, Low: 98.660004, Close: 103.419998, Volume: 10874700 },\ { Date: 1640901600000, Open: 102.440002, High: 106.120003, Low: 102.279999, Close: 103.690002, Volume: 5814900 },\ { Date: 1641160800000, Open: 106.139999, High: 106.550003, Low: 100.25, Close: 102.720001, Volume: 8346800 },\ { Date: 1641247200000, Open: 102.989998, High: 106.800003, Low: 99.014, Close: 101.389999, Volume: 12152200 },\ { Date: 1641333600000, Open: 98.32, High: 99.214996, Low: 89.279999, Close: 90.010002, Volume: 18645100 },\ { Date: 1641420000000, Open: 91.879997, High: 92.029999, Low: 75.129997, Close: 87.330002, Volume: 39827100 },\ { Date: 1641506400000, Open: 87.019997, High: 89.269997, Low: 81.621002, Close: 86.279999, Volume: 17497700 },\ { Date: 1641765600000, Open: 83.519997, High: 83.75, Low: 77.650002, Close: 81.440002, Volume: 17289800 },\ { Date: 1641852000000, Open: 78.940002, High: 86.580002, Low: 78.120003, Close: 83.550003, Volume: 19970600 },\ { Date: 1641938400000, Open: 84.900002, High: 88.07, Low: 82.629997, Close: 86.480003, Volume: 14422800 },\ { Date: 1642024800000, Open: 86.940002, High: 86.940002, Low: 79.889999, Close: 80.309998, Volume: 13677500 },\ { Date: 1642111200000, Open: 79.57, High: 81.690002, Low: 77.010002, Close: 79.949997, Volume: 15792300 },\ { Date: 1642456800000, Open: 77.525002, High: 77.839996, Low: 72.855003, Close: 73.160004, Volume: 16803700 },\ { Date: 1642543200000, Open: 74.82, High: 76.32, Low: 68.949997, Close: 69.400002, Volume: 15068400 },\ { Date: 1642629600000, Open: 70.858002, High: 72.080002, Low: 64.809998, Close: 65.019997, Volume: 18642700 },\ { Date: 1642716000000, Open: 63.865002, High: 67.160004, Low: 60.509998, Close: 64.510002, Volume: 19323400 },\ { Date: 1642975200000, Open: 60.110001, High: 64.300003, Low: 55.099998, Close: 63.900002, Volume: 24134800 },\ { Date: 1643061600000, Open: 61.105, High: 61.93, Low: 58, Close: 59.610001, Volume: 16557200 },\ { Date: 1643148000000, Open: 62.349998, High: 68.07, Low: 59.009998, Close: 60.27, Volume: 23694100 },\ { Date: 1643234400000, Open: 61.330002, High: 61.700001, Low: 53.331001, Close: 53.939999, Volume: 23385500 },\ { Date: 1643320800000, Open: 53.599998, High: 57.299999, Low: 50, Close: 57.119999, Volume: 23942400 }\ \]; // Create root element // https://www.amcharts.com/docs/v5/getting-started/#Root\_element let root = am5.Root.new("chartdiv"); // Set themes // https://www.amcharts.com/docs/v5/concepts/themes/ root.setThemes(\[\ am5themes\_Animated.new(root)\ \]); // Create a stock chart // https://www.amcharts.com/docs/v5/charts/stock-chart/#Instantiating\_the\_chart let stockChart = root.container.children.push(am5stock.StockChart.new(root, { })); /\*\* \* Main (value) panel \*/ // Create a main stock panel (chart) // https://www.amcharts.com/docs/v5/charts/stock-chart/#Adding\_panels let mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); // Create axes // https://www.amcharts.com/docs/v5/charts/xy-chart/axes/ let valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) })); let dateAxis = mainPanel.xAxes.push(am5xy.GaplessDateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); // Add series // https://www.amcharts.com/docs/v5/charts/xy-chart/series/ let valueSeries = mainPanel.series.push(am5xy.LineSeries.new(root, { name: "STCK", valueXField: "Date", valueYField: "Close", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY}" })); valueSeries.data.setAll(data); // Set main value series // https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting\_main\_series stockChart.set("stockSeries", valueSeries); // Add a stock legend // https://www.amcharts.com/docs/v5/charts/stock-chart/stock-legend/ let valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, { stockChart: stockChart })); valueLegend.data.setAll(\[valueSeries\]); /\*\* \* Secondary (volume) panel \*/ // Create a main stock panel (chart) // https://www.amcharts.com/docs/v5/charts/stock-chart/#Adding\_panels let volumePanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true, height: am5.percent(30) })); // Create axes // https://www.amcharts.com/docs/v5/charts/xy-chart/axes/ let volumeValueAxis = volumePanel.yAxes.push(am5xy.ValueAxis.new(root, { numberFormat: "#.#a", renderer: am5xy.AxisRendererY.new(root, {}) })); let volumeDateAxis = volumePanel.xAxes.push(am5xy.GaplessDateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); // Add series // https://www.amcharts.com/docs/v5/charts/xy-chart/series/ let volumeSeries = volumePanel.series.push(am5xy.ColumnSeries.new(root, { name: "STCK", valueXField: "Date", valueYField: "Volume", xAxis: volumeDateAxis, yAxis: volumeValueAxis, legendValueText: "{valueY}" })); volumeSeries.data.setAll(data); // Set main value series // https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting\_main\_series stockChart.set("volumeSeries", volumeSeries); // Add a stock legend // https://www.amcharts.com/docs/v5/charts/stock-chart/stock-legend/ let volumeLegend = volumePanel.plotContainer.children.push(am5stock.StockLegend.new(root, { stockChart: stockChart })); volumeLegend.data.setAll(\[volumeSeries\]); // Add cursor(s) // https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/ mainPanel.set("cursor", am5xy.XYCursor.new(root, { yAxis: valueAxis, xAxis: dateAxis, snapToSeries: \[valueSeries\], snapToSeriesBy: "y!" })); volumePanel.set("cursor", am5xy.XYCursor.new(root, { yAxis: volumeValueAxis, xAxis: volumeDateAxis, snapToSeries: \[volumeSeries\], snapToSeriesBy: "y!" })); // Add scrollbar // https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/ let scrollbar = mainPanel.set("scrollbarX", am5xy.XYChartScrollbar.new(root, { orientation: "horizontal", height: 50 })); stockChart.toolsContainer.children.push(scrollbar); let sbDateAxis = scrollbar.chart.xAxes.push(am5xy.GaplessDateAxis.new(root, { baseInterval: { timeUnit: "day", count: 1 }, renderer: am5xy.AxisRendererX.new(root, {}) })); let sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}) })); let sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, { valueYField: "Close", valueXField: "Date", xAxis: sbDateAxis, yAxis: sbValueAxis })); sbSeries.fills.template.setAll({ visible: true, fillOpacity: 0.3 }); sbSeries.data.setAll(data);
See the Pen Basic stock chart by amCharts team (@amcharts) on CodePen. Advanced functionality ---------------------- ### Indicators Stock chart comes with a number of most popular stock indicators built-in. These are special series, that provide analysis of data in existing value and volume main series. Refer to "[Indicators](https://www.amcharts.com/docs/v5/charts/stock/indicators/) " tutorial for further information. ### Drawing/annotation tools Provided are also various drawing and annotation tools, accessible via API and built-in toolbar. Those include basic annotations like adding basic shapes and text, as well as advanced analytical tools, like drawing trend lines. Refer to "[Stock annotations](https://www.amcharts.com/docs/v5/charts/stock/stock-annotations/) " tutorial for further information. ### Toolbar Stock chart also includes a special pre-made toolbar, which can be used as graphical user interface to select drawing tools, add indicators and comparisons, control chart zoom and granularity, types, etc. Refer to "[Stock toolbar](https://www.amcharts.com/docs/v5/charts/stock/toolbar/) " tutorial for further information. ### Percent mode If turned on, stock chart can switch to a "percent change mode" when comparison series are added, or when switched on via API. Refer to "[Percent mode](https://www.amcharts.com/docs/v5/charts/stock/percent-mode/) " tutorial for further information. ### Zoom behavior Stock chart works differently when mouse wheel is used over its panels. It will zoom in and out using right side of the panel(s) as a reference point, i.e. the right-most position will stay fixed while the right side is zoomed out or in. If we'd like to revert to default functionality, where zooming is centered around actual position of the mouse cursor, we need to reset `wheelZoomPositionX` on all of our panels: let volumePanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true, height: am5.percent(30), wheelZoomPositionX: null })); var volumePanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true, height: am5.percent(30), wheelZoomPositionX: null })); Related tutorials ----------------- * [Infinite dynamic data loading on Stock Chart](https://www.amcharts.com/docs/v5/tutorials/infinite-dynamic-data-loading-on-stock-chart/) --- # Panels – amCharts 5 Documentation Panels are instances of `StockPanel` class (which in turn extends an `XYChart`) comprising the [Stock chart](https://www.amcharts.com/docs/v5/charts/stock/) . Zoom state of their X axes as well as cursor are automatically synced by the stock chart itself. Adding panels ------------- To add a panel, we need to: * Create an instance of an `StockPanel`. * Configure it fully (remember it's an `XYChart` so we can use any configuration options available to it), including axes and series that will go into it. * Push it into stock chart's `panels` list. The following code will add a single panel. Let's call it a "main chart". let mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); var mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); MORE INFOFor a complete guide on how to configure an a panel (XY chart), please refer to "[XY chart](https://www.amcharts.com/docs/v5/charts/xy-chart/) " tutorial section. Panel controls -------------- If the stock chart has more than one panel, a special set of controls is enabled on each panel. Controls are buttons that allow: * Moving panel up and down. * Expanding panel to full chart size. * Closing panel. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/04/stock_panel_controls.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/04/stock_panel_controls.png) Panel controls is an object of type `PanelControls`, and is accessible via panel's `panelControls` property. ### Disabling panel controls To disable panel controls, simply set its `forceHidden: true`: mainPanel.panelControls.set("forceHidden"); mainPanel.panelControls.set("forceHidden"); ### Disabling individual buttons Individual button elements from the controls are available via the following properties of the `PanelControls` instance: * `upButton` * `downButton` * `expandButton` * `closeButton` To selectively disable them, use their `forceHidden` setting: mainPanel.panelControls.expandButton.set("forceHidden"); mainPanel.panelControls.closeButton.set("forceHidden"); mainPanel.panelControls.expandButton.set("forceHidden"); mainPanel.panelControls.closeButton.set("forceHidden"); NOTEClose button will be automatically disabled for the panel that holds the [main series](https://www.amcharts.com/docs/v5/charts/stock/#Setting_main_series) , if there's one set. ### Disabling panel resizer The easiest way to disabling resizing of panels is via custom theme: let myTheme = am5.Theme.new(root); myTheme.rule("Rectangle", \["panelresizer"\]).setAll({ forceInactive: true }); root.setThemes(\[\ am5themes\_Animated.new(root),\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.rule("Rectangle", \["panelresizer"\]).setAll({ forceInactive: true }); root.setThemes(\[\ am5themes\_Animated.new(root),\ myTheme\ \]); Order ----- ### Initial order We can push as many `StockPanel` instances into stock chart's `panels` list as we need to. They will appear in the same order as the were pushed: the first panel will be displayed on top, with the rest following. ### Reordering via UI Panels can also be re-ordered by user via panel controls, described earlier in this tutorial. ### Reordering via API Each panel instance offers two methods, that allow changing its position: `moveUp()` and `moveDown()`. Their functionality is self-explanatory. Sizing ------ ### Via settings Normally, all panels will divide the vertical space between them equally. We can modify that manually, using panel/chart's `height` setting. It accepts both absolute pixel as well as percent values. let mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); let volumePanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true, height: am5.percent(30) })); var mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true })); var volumePanel = stockChart.panels.push(am5stock.StockPanel.new(root, { wheelY: "zoomX", panX: true, panY: true, height: am5.percent(30) })); In the above example, only "volumePanel" has its height set to 30%. That means that it will take 30% of the height of the stock chart, with "mainPanel" taking up the rest 70% even if it does not have height explicitly set. ### Via user interface The panels are resizable out-of-the-box. User can drag space between panels to resize them manually. Syncing cursors --------------- Cursors between panels will be automatically synced across all panels. To disable it, use this line of code for each panel **after** it has been added to the chart: panel.removePrivate("otherCharts"); panel.removePrivate("otherCharts"); Removing panels --------------- ### Via API To remove a panel programmatically, all we need to do is call panel's `close()` method: volumePanel.close(); volumePanel.close(); NOTEClosing a panel will automatically dispose it. If we want to keep the instance (perhaps if we are intending to add it back to the the chart) we need to disable auto-disposing: stockChart.panels.autoDispose = false; stockChart.panels.autoDispose = false; ### Via controls If panel/chart has [panel controls](#Panel_controls) added to it, it can be removed by the user by pressing the "close" button in control bar. Events ------ Panels have a few events you can tap into: | Event | Kicks in when | | --- | --- | | `closed` | Panel is closed (removed). | | `collapsed` | Panel returns from its expanded state. | | `expanded` | Panel is expanded. | | `moved` | Panel is moved up and down using its controls or API. | volumePanel.events.on("closed", function(ev) { console.log("Buh bye, Volume Panel"); }); volumePanel.events.on("closed", function(ev) { console.log("Buh bye, Volume Panel"); }); Example ------- Below is a working multi-panel stock chart: See the Pen Stock chart with comparison by amCharts team (@amcharts) on CodePen. --- # Stock annotations – amCharts 5 Documentation [Stock chart](https://www.amcharts.com/docs/v5/charts/stock/) can be annotated using a vast array of tools ranging from simple shapes and doodles, to complex calculated indicators. Enabling UI ----------- To enable annotation user interface, we need to add a [drawing control](https://www.amcharts.com/docs/v5/charts/stock/toolbar/drawing-control/) to the stock toolbar. let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ am5stock.DrawingControl.new(root, {\ stockChart: stockChart\ })\ \] }); var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ am5stock.DrawingControl.new(root, {\ stockChart: stockChart\ })\ \] }); See the Pen Stock chart controls by amCharts team (@amcharts) on CodePen. Removing annotations -------------------- ### Eraser tool Once chart is in drawing mode - when user clicks drawing control - they can select an eraser tool from the drawing menu. When eraser tool is selected, clicking on any annotation will remove it. ### Reset control If the toolbar contains a [reset control](https://www.amcharts.com/docs/v5/charts/stock/toolbar/reset-control/) , it can be clicked to automatically remove all annotations from the chart. Drawing on fills ---------------- Normally, annotation/drawing fill is part of it and will react on click/drags, which makes it impossible to draw other annotations on top. E.g. if we draw a rectangle, we can't draw a doodle inside it. Should we want to have such capability, we need to disable interactivity of drawings' fills. This can be done by implementing a [custom theme](https://www.amcharts.com/docs/v5/concepts/themes/creating-themes/) : const myTheme = am5.Theme.new(root); myTheme.this.rule("Graphics", \["series", "fill", "drawing"\]).setAll({ forceInactive: true }); root.setThemes(\[\ am5themes\_Animated.new(root),\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.this.rule("Graphics", \["series", "fill", "drawing"\]).setAll({ forceInactive: true }); root.setThemes(\[\ am5themes\_Animated.new(root),\ myTheme\ \]); Or, if we'd like to target only specific drawing tools only: const myTheme = am5.Theme.new(root); myTheme.this.rule("Graphics", \["series", "parallelchannel", "fill", "drawing"\]).setAll({ forceInactive: true }); root.setThemes(\[\ am5themes\_Animated.new(root),\ myTheme\ \]); var myTheme = am5.Theme.new(root); myTheme.this.rule("Graphics", \["series", "parallelchannel", "fill", "drawing"\]).setAll({ forceInactive: true }); root.setThemes(\[\ am5themes\_Animated.new(root),\ myTheme\ \]); Serializing annotations ----------------------- At this moment serializing and restoring annotations is not yet supported. The functionality is under development and will be available soon, at which point this section will be updated. --- # Stock legend – amCharts 5 Documentation This tutorial looks at various aspects of using the stock chart legend. Adding ------ In stock chart, we can use both the [regular legend](https://www.amcharts.com/docs/v5/charts/xy-chart/legend-xy-series/) that we'd use in an XY chart, as well as advanced special "sock legend". The latter offers enhanced view as well as tools to edit related series/indicators. To ad a stock legend, we'll use a `StockLegend` class instead of `Legend`: let valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, { stockChart: stockChart })); valueLegend.data.setAll(\[valueSeries\]); var valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, { stockChart: stockChart })); valueLegend.data.setAll(\[valueSeries\]); The important difference from regular legend is that stock legend is designed to be displayed over the plot area, so we push it into main panel's `plotContainer`. Another difference is that because of additional functionality, stock legend requires to know what its stock chart it, hence us setting `stockChart` in the above code. If we wanted we could use a regular legend here as well: let valueLegend = valueAxis.axisHeader.children.push(am5.Legend.new(root, {})); valueLegend.data.setAll(\[valueSeries\]); var valueLegend = valueAxis.axisHeader.children.push(am5.Legend.new(root, {})); valueLegend.data.setAll(\[valueSeries\]); Settings and close buttons -------------------------- ### Global settings Stock legend, besides textual information, also displays settings icon, and in some cases close/remove buttons. Those can be configured using `legend.settingsButtons.template` and `legend.closeButtons.template`. Those are list templates, meaning that any setting we set on them will be automatically set on any new items that are created in legend. The following code will disable both of them: valueLegend.settingsButtons.template.set("forceHidden", true); valueLegend.closeButtons.template.set("forceHidden", true); valueLegend.settingsButtons.template.set("forceHidden", true); valueLegend.closeButtons.template.set("forceHidden", true); Both of the templates are of type `Button`. Refer to its [class reference](https://www.amcharts.com/docs/v5/reference/button/#Settings) , for a complete list of settings and events we can set. See the Pen Stock Chart with settings and close buttons disabled in the legend by amCharts team (@amcharts) on CodePen. ### Individual settings The above section was dealing with applying settings to all legend items. We are now going to look at ways to apply settings to individual legend items. Whenever we insert series into legend's data, its setting `legendDataItem` is set automatically. For stock legend, that is an object of type `IStockLegendDataItem`. Among other things, it has `settingsButton` and `closeButton` settings, that are set to a `Button` instances for settings and close respectively. We can grab those instances to configure them individually. The following code will disable settings icon for "valueSeries": valueLegend.data.setAll(\[valueSeries, volumeSeries\]); valueSeries.get("legendDataItem").get("settingsButton").set("forceHidden", true); valueLegend.data.setAll(\[valueSeries, volumeSeries\]); valueSeries.get("legendDataItem").get("settingsButton").set("forceHidden", true); See the Pen Stock Chart with settings and close buttons disabled in the legend by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Moving icons of a StockLegend to left](https://www.amcharts.com/docs/v5/tutorials/moving-icons-of-a-stocklegend-to-left/) Related class references ------------------------ * [StockLegend](https://www.amcharts.com/docs/v5/reference/stocklegend) --- # Serializing indicators and annotations – amCharts 5 Documentation User-added drawings (annotations) and indicators, can be serialized into simple JavaScript objects or JSON strings. That information can be saved and later restored using built-in functions. This tutorial explains how to use the API to do just that. Requirements ------------ The serialization / parsing of annotation data and added indicators is a functionality built-in into the [Drawing control](https://www.amcharts.com/docs/v5/charts/stock/toolbar/drawing-control/) and [Indicator control](https://www.amcharts.com/docs/v5/charts/stock/toolbar/indicator-control/) respectively. We will need those to be present and initialized in order to use the functionality. const indicatorControl = am5stock.IndicatorControl.new(root, { stockChart: stockChart, legend: valueLegend }); const drawingControl = am5stock.DrawingControl.new(root, { stockChart: stockChart }); const toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols")!, stockChart: stockChart, controls: \[\ indicatorControl,\ drawingControl\ \] }); var indicatorControl = am5stock.IndicatorControl.new(root, { stockChart: stockChart, legend: valueLegend }); var drawingControl = am5stock.DrawingControl.new(root, { stockChart: stockChart }); var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ indicatorControl,\ drawingControl\ \] }); MORE INFOFor more information about managing toolbars, refer to the "[Stock toolbar](https://www.amcharts.com/docs/v5/charts/stock/toolbar/) " tutorial. Serializing ----------- ### Methods To serialize current drawings, we can use `serializeDrawings()` method of the Drawing control. Similarly, to serialize indicators, we can use `serializeIndicators()` method of the Indicator control. const drawings = drawingControl.serializeDrawings("string", " "); const indicators = indicatorControl.serializeIndicators("string", " "); var drawings = drawingControl.serializeDrawings("string", " "); var indicators = indicatorControl.serializeIndicators("string", " "); Both functions will return an array of serialized objects, representing drawings and indicators. In case we use `"string"` as an output format, the array (and all its contents) will be stringified into a JSON format. ### String vs. object A second parameter to both serialization functions can be either `"string"` or `"object"` (default). `"string"` will return a fully formatted JSON text, which can be stored in a database, saved in a file, or stored anywhere else, that text can be stored. When `"string"` is used, the second parameter will be used to as a prefix for indenting JSON lines. If nothing is specified, resulting JSON will be a single unformatted line. `"object"` will return a simple JavaScript object, containing just string, number, and boolean values. { "\_\_stockSeries": true, "\_\_volumeSeries": true, "\_\_indicator": { "type": "MACD", "settings": { "fastPeriod": 16, "slowPeriod": 26, "signalPeriod": 9 } } } Restoring --------- Restoring drawings can be done by passing in serialized data (either in as an array of simple objects, or as a JSON string) to `unserializeDrawings()` method of the Drawing control, or `userializeIndicators()` of the Indicator control. drawingControl.unserializeDrawings(drawings); indicatorControl.unserializeIndicators(indicators); drawingControl.unserializeDrawings(drawings); indicatorControl.unserializeIndicators(indicators); The methods will recognize if the data was passed as a simple array of objects or a JSON string automatically, so there's no parameter to indicator format. Events ------ Stock chart provides two events which can be used to dynamically monitor to any changes in drawings and/or indicators: `drawingsupdated` and `indicatorsupdated`. They can be used to serialize and update current chart state in storage. stockChart.events.on("drawingsupdated", function(ev) { // Serialize drawings and store them // ... }); stockChart.events.on("indicatorsupdated", function(ev) { // Serialize indicators and store them // ... }); stockChart.events.on("drawingsupdated", function(ev) { // Serialize drawings and store them // ... }); stockChart.events.on("indicatorsupdated", function(ev) { // Serialize indicators and store them // ... }); Please note, when drawing freestyle annotations (e.g. doodle), `drawingsupdated` event will be invoked multiple times. In such cases, debouncing serialization/storage code is a good idea: let drawingDebouncer; stockChart.events.on("drawingsupdated", function(ev) { if (drawingDebouncer) { clearTimeout(drawingDebouncer); } drawingDebouncer = setTimeout(function() { // Serialize drawings and store them, // but only if there was 2 seconds of inactivity // ... }, 2000); }); let indicatorDebouncer; stockChart.events.on("indicatorsupdated", function(ev) { if (indicatorDebouncer) { clearTimeout(indicatorDebouncer); } indicatorDebouncer= setTimeout(function() { // Serialize indicatorsand store them, // but only if there was 2 seconds of inactivity // ... }, 2000); }); var drawingDebouncer; stockChart.events.on("drawingsupdated", function(ev) { if (drawingDebouncer) { clearTimeout(drawingDebouncer); } drawingDebouncer = setTimeout(function() { // Serialize drawings and store them, // but only if there was 2 seconds of inactivity // ... }, 2000); }); var indicatorDebouncer; stockChart.events.on("indicatorsupdated", function(ev) { if (indicatorDebouncer) { clearTimeout(indicatorDebouncer); } indicatorDebouncer= setTimeout(function() { // Serialize indicatorsand store them, // but only if there was 2 seconds of inactivity // ... }, 2000); }); Example ------- See the Pen Stock Chart with serialized drawings and indicators by amCharts team (@amcharts) on CodePen. --- # Stock toolbar – amCharts 5 Documentation Stock toolbar is a tool bundled with our [Stock chart](https://www.amcharts.com/docs/v5/charts/stock/) that can hold a number of chart-related controls, built-in or custom. Creating -------- A toolbar will need to be placed into its own container `
`, separate from the chart's container.
NOTEThe container for toolbar should not be constricted with specific height using CSS, as its content is adjusted dynamically, thus the height might change based on user's interactions. To create a toolbar we will need to instantiate a `StockToolbar` class, using its `new()` method. let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ // ...\ \] }); var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ // ...\ \] }); To work properly it needs three settings to be set: * `container` - a reference to a `
` element to place toolbar elements in. * `stockChart` - a reference to our stock chart. * `controls` - a list of controls to put into toolbar (more about it later). Controls -------- ### Adding controls A toolbar is just a shell. To add actual functionality, we need to add controls designed for it. Stock chart comes with a number of controls: | Class | Comment | | | --- | --- | --- | | `ComparisonControl` | A control designed to add additional series to compare against main series. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/comparison-control/) | | `DataSaveControl` | Allows saving/restoring current annotations, as well as enabling auto-saving. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/data-save-control/) | | `DateRangeSelector` | Allows selecting date range the chart to zoom to, using date picker. | [Info](https://www.amcharts.com/docs/v5/date-range-selector/) | | `DrawingControl` | Toggles drawing tools on and off. Puts chart into "[annotation mode](https://www.amcharts.com/docs/v5/charts/stock/stock-annotations/)
". | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/drawing-control/) | | `IndicatorControl` | Allows adding [technical indicators](https://www.amcharts.com/docs/v5/charts/stock/indicators/)
. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/indicator-control/) | | `IntervalControl` | Allows switching data granularity. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/interval-control/) | | `PeriodSelector` | Displays a pre-defined list of periods for quick zoom of the chart. | [Info](https://www.amcharts.com/docs/v5/period-selector/) | | `ResetControl` | Removes all annotations and indicators added by user. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/reset-control/) | | `SeriesTypeControl` | Allows switching type of the main series. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/series-type-control/) | | `SettingsControl` | Allows changing some settings of the chart, such as Y-axis scale and axis fills. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/settings-control/) | Besides these functional controls, stock chart offers generic controls that we can use to add custom functionality: | Class | Comment | | | --- | --- | --- | | `DropdownListControl` | A control that can be used to add searchable list of any item for selection. | [Info](https://www.amcharts.com/docs/v5/charts/stock/toolbar/dropdown-list-control/) | | `StockControl` | A simple clickable or togglable button. | Info | Some controls are completely automated, while some will require custom code attached to its events for proper implementation. All controls require `stockChart` set to an instance of the stock chart they are used for. let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ am5stock.DrawingControl.new(root, {\ stockChart: stockChart\ }),\ am5stock.ResetControl.new(root, {\ stockChart: stockChart\ }),\ am5stock.SettingsControl.new(root, {\ stockChart: stockChart\ })\ \] }); var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ am5stock.DrawingControl.new(root, {\ stockChart: stockChart\ }),\ am5stock.ResetControl.new(root, {\ stockChart: stockChart\ }),\ am5stock.SettingsControl.new(root, {\ stockChart: stockChart\ })\ \] }); The above code will add three controls: drawing control which toggles annotation tools, as well as reset and settings controls. See the Pen Stock chart with comparison by amCharts team (@amcharts) on CodePen. ### Configuring controls As we mentioned before, some controls work without any configuration out-of-the-box, whereas others require additional custom code or configuration. As an example, `SeriesTypeControl` control cannot change type of the series itself. It will rely on developer configuring an event handler which, when user selects new series type, destroys the old series, creates a new one, and sets it on the stock chart. let seriesSwitcher = am5stock.SeriesTypeControl.new(root, { stockChart: stockChart }); seriesSwitcher.events.on("selected", function(ev) { setSeriesType(am5.type.isString(ev.item) ? ev.item : ev.item.id); }); function setSeriesType(seriesType) { // Remove previous series let currentSeries = stockChart.get("stockSeries"); let data = currentSeries.data.values; mainPanel.series.removeValue(currentSeries); // Create new series let series; switch (seriesType) { case "line": series = mainPanel.series.push(am5xy.LineSeries.new(root, { // ... })); break; case "candlestick": case "procandlestick": series = mainPanel.series.push(am5xy.CandlestickSeries.new(root, { // ... })); if (seriesType == "procandlestick") { series.columns.template.get("themeTags").push("pro"); } break; case "ohlc": series = mainPanel.series.push(am5xy.OHLCSeries.new(root, { // ... })); break; } // Set new series as stockSeries if (series) { valueLegend.data.removeValue(currentSeries); series.data.setAll(data); stockChart.set("stockSeries", series); const cursor = mainPanel.get("cursor"); if (cursor) { cursor.set("snapToSeries", \[series\]); } valueLegend.data.insertIndex(0, series); } } var seriesSwitcher = am5stock.SeriesTypeControl.new(root, { stockChart: stockChart }); seriesSwitcher.events.on("selected", function(ev) { setSeriesType(am5.type.isString(ev.item) ? ev.item : ev.item.id); }); function setSeriesType(seriesType) { // Remove previous series var currentSeries = stockChart.get("stockSeries"); var data = currentSeries.data.values; mainPanel.series.removeValue(currentSeries); // Create new series var series; switch (seriesType) { case "line": series = mainPanel.series.push(am5xy.LineSeries.new(root, { // ... })); break; case "candlestick": case "procandlestick": series = mainPanel.series.push(am5xy.CandlestickSeries.new(root, { // ... })); if (seriesType == "procandlestick") { series.columns.template.get("themeTags").push("pro"); } break; case "ohlc": series = mainPanel.series.push(am5xy.OHLCSeries.new(root, { // ... })); break; } // Set new series as stockSeries if (series) { valueLegend.data.removeValue(currentSeries); series.data.setAll(data); stockChart.set("stockSeries", series); const cursor = mainPanel.get("cursor"); if (cursor) { cursor.set("snapToSeries", \[series\]); } valueLegend.data.insertIndex(0, series); } } See the Pen Stock chart controls by amCharts team (@amcharts) on CodePen. MIRE INFOFor more information about each control follow links on the table earlier in this chapter, or in navigation menu on the left. Accessibility ------------- To enable accessibility of the toolbar (make it controllable via keyboard), simply set `focusable: true`: let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, focusable: true, controls: \[\ // ...\ \] }); var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, focusable: true, controls: \[\ // ...\ \] }); Styling controls ---------------- The toolbar controls are all DOM elements, that can be targeted via CSS to override their look. The following CSS will make toolbar's button dark green: #chartcontrols .am5stock-control-button { background: #171c1c; color: #fff; } #chartcontrols .am5stock-control-button:hover { background: #98AEAB; color: #171c1c; } #chartcontrols .am5stock-control-icon path { stroke: #fff; } #chartcontrols .am5stock-control-button:hover .am5stock-control-icon path { stroke: #171c1c!important; } As you can see, various elements can be targeted using built-in class names. NOTENotice the `#charttools` prefix in the CSS queries above. Since Stock Toolbar adds own CSS dynamically, simple targeting like `.am5stock-control-button` might not work, since default CSS might get loaded after your own custom CSS. More precise targeting like prefixing with the id of your toolbar container ensures that your queries will take precedence. The following table lists a few of those. | Class name | Comment | | --- | --- | | `am5stock-control` | Wrapper for any control. | | `am5stock-control-button` | Button wrapper. | | `am5stock-control-dropdown` | Dropdown wrapper. | | `am5stock-control-icon` | Icon in the button. | | `am5stock-control-label` | Label. | There are more. We suggest right-clicking on any toolbar element, and selecting "Inspect element" item, which would open up browser's DOM tool. You can use it to explore actual structure of the toolbar's elements, their assigned class names, and built-in CSS that affects it. Here's an example: See the Pen Customizing colors of a StockToolbar by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Stock Chart with custom indicator add button](https://www.amcharts.com/docs/v5/tutorials/stock-chart-with-custom-indicator-add-button/) --- # Indicators – amCharts 5 Documentation Stock chart comes with a selection of automatic indicators that can be added to the chart via toolbar or API. Adding via toolbar ------------------ To enable adding of indicators via UI, we need to add [indicator control](https://www.amcharts.com/docs/v5/charts/stock/toolbar/indicator-control/) to our stock toolbar: let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ am5stock.IndicatorControl.new(root, {\ stockChart: stockChart\ })\ \] }); var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: \[\ am5stock.IndicatorControl.new(root, {\ stockChart: stockChart\ })\ \] }); See the Pen Stock chart controls by amCharts team (@amcharts) on CodePen. Adding via API -------------- ### Creating indicator Indicators can be added by instantiating an appropriate class, then pushing it into chart's `indicators` list. Each indicator will need its `stockChart` (target stock chart) and `stockSeries` (value series) set, at the very least. Some indicators, such as `Volume`, will need `volumeSeries` set as well, as they rely on both value and volume data. stockChart.indicators.push(am5stock.BollingerBands.new(root, { stockChart: stockChart, stockSeries: valueSeries, legend: valueLegend, type: "simple" })); stockChart.indicators.push(am5stock.BollingerBands.new(root, { stockChart: stockChart, stockSeries: valueSeries, legend: valueLegend, type: "simple" })); ### Configuring Pardon the mess. We're still working on this section. ### Available indicators Refer to the links next to each indicator for settings reference. | Indicator | Needs `stockSeries` | Needs `volumeSeries` | | | --- | --- | --- | --- | | `AccumulationDistribution` | **Yes** | Optional | [Settings](https://www.amcharts.com/docs/v5/reference/accumulationdistribution/#Settings) | | `AccumulativeSwingIndex` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/accumulativeswingindex/#Settings) | | `Aroon` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/aroon/#Settings) | | `AwesomeOscillator` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/awesomeoscillator/#Settings) | | `BollingerBands` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/bollingerbands/#Settings) | | `ChaikinMoneyFlow` | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/chaikinmoneyflow/#Settings) | | `ChaikinOscillator` | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/chaikinoscillator/#Settings) | | `CommodityChannelIndex` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/commoditychannelindex/#Settings) | | `DisparityIndex` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/disparityindex/#Settings) | | `MACD` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/macd/#Settings) | | `MedianPrice` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/medianprice/#Settings) | | `MovingAverage` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/movingaverage/#Settings) | | `MovingAverageCross` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/movingaveragecross/#Settings) | | `MovingAverageDeviation` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/movingaveragedeviation/#Settings) | | `MovingAverageEnvelope` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/movingaverageenvelope/#Settings) | | `OnBalanceVolume` | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/onbalancevolume/#Settings) | | `PVT` (Price Volume Trend) | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/pvt/#Settings) | | `RelativeStrengthIndex` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/relativestrengthindex/#Settings) | | `StandardDeviation` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/standarddeviation/#Settings) | | `StochasticOscillator` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/stochasticoscillator/#Settings) | | `Trix` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/trix/#Settings) | | `TypicalPrice` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/typicalprice/#Settings) | | `Volume` | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/volume/#Settings) | | `VolumeProfile` | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/volumeprofile/#Settings) | | `VWAP` | **Yes** | **Yes** | [Settings](https://www.amcharts.com/docs/v5/reference/vwap/#Settings) | | `WilliamsR` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/williamsr/#Settings) | | `ZigZag` | **Yes** | | [Settings](https://www.amcharts.com/docs/v5/reference/zigzag/#Settings) | Creating custom indicators -------------------------- Refer to "[Creating custom indicators for a Stock Chart](https://www.amcharts.com/docs/v5/tutorials/creating-custom-indicators-for-a-stock-chart/) " tutorial. Related tutorials ----------------- * [Stock Chart with custom indicator add button](https://www.amcharts.com/docs/v5/tutorials/stock-chart-with-custom-indicator-add-button/) --- # Element states – amCharts 5 Documentation A state is basically a collection of element's settings to be applied on certain events, e.g. when element is hovered. How states work? ---------------- A state is an object of type `State` which, like regular elements, can have a collection of key/value pairs, known as settings. By default the state does nothing, until it is applied to the element, at which point it sets values of its settings to the target element. State application can happen automatically for some built-in states, such as `"hover"`, or it can be initiated by custom code. Built-in states --------------- amCharts will try to apply these states in certain situations automatically: | State name | Comment | | --- | --- | | `"hover"` | Applied when interactive element is hovered by mouse cursor, or touched on a screen. | | `"hidden"` | Applied when element is hidden. | | `"active"` | Applied when element is set as active, e.g. by `active` setting, or toggle behavior. | | `"disabled"` | Applied when element is set as active, e.g. by `disabled` setting, or toggle behavior. | | `"default"` | Applied whenever element status that applies state is removed, e.g. element is no longer hovered.
Default state is also applied when element is first initialized. | There are more built-in states that are applied in some specialized cases, like for instance on a [candlestick series](https://www.amcharts.com/docs/v5/charts/xy-chart/series/candlestick-series/#Stroke_and_fill_colors) . Creating or modifying --------------------- To create a state on an element, we simply use `states.create()` method on an element, or its template. The method accepts two parameters: * State name. * Set of settings to apply when state is applied. columnSeries.columns.template.set("interactive", true); columnSeries.columns.template.states.create("hover", { fill: am5.color(0x297373), stroke: am5.color(0x297373) }); columnSeries.columns.template.set("interactive", true); columnSeries.columns.template.states.create("hover", { fill: am5.color(0x297373), stroke: am5.color(0x297373) }); The above will make all columns in a column series to change color when hovered. See the Pen Stacked column chart by amCharts team (@amcharts) on CodePen. NOTE If a state with the same name already exists on an element when `states.create()` is called, an existing state object will be returned instead, and supplied setting key/values applied to it. Custom states ------------- ### Creating We can use any alphanumeric string as a name for a state when creating it, e.g.: columnSeries.columns.template.states.create("highlight", { fill: am5.color(0x297373), stroke: am5.color(0x297373) }); columnSeries.columns.template.states.create("highlight", { fill: am5.color(0x297373), stroke: am5.color(0x297373) }); These states will not be used until we explicitly apply them. ### Applying To apply a state use `states.apply()` or `states.applyAnimate()` methods. Both methods take state name as a first parameter. `states.apply()` will apply its settings right way, whereas `states.applyAnimate()` will try to morph all settings from current to target values. `states.applyAnimate()` also accepts a second parameter: duration of the animation in milliseconds. series.columns.template.states.create("highlight", { fill: am5.color(0x297373), stroke: am5.color(0x297373) }); let selectedColumn; series.columns.template.events.on("click", function(ev) { let column = ev.target; if (selectedColumn) { selectedColumn.states.applyAnimate("default"); selectedColumn = undefined; } column.states.applyAnimate("highlight"); selectedColumn = column; }); series.columns.template.states.create("highlight", { fill: am5.color(0x297373), stroke: am5.color(0x297373) }); var selectedColumn; series.columns.template.events.on("click", function(ev) { var column = ev.target; if (selectedColumn) { selectedColumn.states.applyAnimate("default"); selectedColumn = undefined; } column.states.applyAnimate("highlight"); selectedColumn = column; }); See the Pen Columns with custom states by amCharts team (@amcharts) on CodePen. Animations ---------- If enabled (via settings or animated theme), setting values will animate between the states. For more information on how to control this, refer to "[Animations: Animating between the states](https://www.amcharts.com/docs/v5/concepts/animations/#Animating_between_states) ". Related tutorials ----------------- * [Applying custom hover/active states on legend markers](https://www.amcharts.com/docs/v5/tutorials/applying-custom-hover-active-states-on-legend-markers/) --- # Percent scale – amCharts 5 Documentation Percent scale in a [Stock chart](https://www.amcharts.com/docs/v5/charts/stock/) allows applying special setting values to chart series and axes when there are more than one series displayed, or when turned on in API or via stock [toolbar](https://www.amcharts.com/docs/v5/charts/stock-chart/toolbar/) . Intended use ------------ While percent scale can override any series or value axis settings, the primary use of it in stock charts is to switch chart from absolute values to percentual change when there are more than one indices being plotted. Since values can differ fundamentally, it might be hard to compare those on an absolute value scale. Prerequisites ------------- ### Main series Percent scale will work only if the chart has its "main" series set. That is its `stockSeries` setting is set. stockChart.set("stockSeries", valueSeries); stockChart.set("stockSeries", valueSeries); Stock chart needs to know which series is the "main" series, so that there's a known target other series are compared against. MORE INFORead more about it in "Stock chart: [Setting main series](https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series) ". ### Calculation of aggregates Main series, as well as all the other series that will be used in percent scale, need their `calculateAggregates` set to `true`. This is needed, because percent scale uses derivative change values in series. Configuring ----------- To configure what happens when percent scale is active, stock chart provides two settings: `percentScaleSeriesSettings` and `percentScaleValueAxisSettings`. There's also a third setting: `autoSetPercentScale`, which indicates whether chart should switch to percent scale when compared series is added. Both are objects that can hold key/value pairs from `XYSeries` and `ValueAxis`, respectively. They also come with defaults: { percentScaleSeriesSettings: { valueYShow: "valueYChangePercent", openValueYShow: "openValueYChangePercent", highValueYShow: "highValueYChangePercent", lowValueYShow: "lowValueYChangePercent", }, percentScaleValueAxisSettings: { numberFormat: "#.##'%'" }, autoSetPercentScale: true } You can override it the way you need to: let stockChart = root.container.children.push(am5stock.StockChart.new(root, { percentScaleSeriesSettings: { valueYShow: "valueYChangePercent", openValueYShow: "openValueYChangePercent", highValueYShow: "highValueYChangePercent", lowValueYShow: "lowValueYChangePercent", }, percentScaleValueAxisSettings: { numberFormat: "#.##'%'" }, autoSetPercentScale: true })); var stockChart = root.container.children.push(am5stock.StockChart.new(root, { percentScaleSeriesSettings: { valueYShow: "valueYChangePercent", openValueYShow: "openValueYChangePercent", highValueYShow: "highValueYChangePercent", lowValueYShow: "lowValueYChangePercent", }, percentScaleValueAxisSettings: { numberFormat: "#.0'%'" }, autoSetPercentScale: false })); In the above example, when percent scale kicks in, the "main series" as well as all the other series that are attached to the same value axis, would get new values for their `valueYShow`, `openValueYShow`, `highValueYShow`, and `lowValueYShow` settings. This will cause series to be plotted not from absolute value, but from their percent change. Additionally, a new `numberFormat` will be applied to related value axis. Enabling -------- ### Automatically If `autoSetPercentScale` is set to `true` (default setting), the stock chart will go into percent scale automatically when new series is added via chart's `addComparingSeries()` method. let series = stockChart.addComparingSeries(am5xy.LineSeries.new(root, { name: "MSFT", valueYField: "Close", calculateAggregates: true, valueXField: "Date", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY.formatNumber('#.00')}" })); series.data.setAll(data); var series = stockChart.addComparingSeries(am5xy.LineSeries.new(root, { name: "MSFT", valueYField: "Close", calculateAggregates: true, valueXField: "Date", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY.formatNumber('#.00')}" })); series.data.setAll(data); Pushing new series into panel's (chart's) `series` list will not trigger percent scale. ### Via API Percent scale can also be toggled on and off using stock chart's `setPercentScale()` method. It accepts boolean values. It can also be called without any parameters at all. | Parameter | Comment | | --- | --- | | `true` | Percent scale is on | | `false` | Percent scale is off | | _no value_ | Will turn Percent scale on if there are any compared series added. | strockChart.setPercentScale(true); // turn percent scale on strockChart.setPercentScale(true); // turn percent scale on ### Via toolbar If [stock toolbar](https://www.amcharts.com/docs/v5/charts/stock-chart/toolbar/) is enabled and contains `SettingsControl`, switching to "Change percent" Y-axis scale would trigger percent scale, regardless how many series there are currently on the chart. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/stock_change_percent_scale.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/stock_change_percent_scale.png) Example ------- See the Pen Stock chart with comparison by amCharts team (@amcharts) on CodePen. --- # Concepts – amCharts 5 Documentation Use the navigation menu on the left to select a topic. --- # Translating Stock Chart – amCharts 5 Documentation This tutorial will show how amCharts 5 built-in locale functionality can be used to apply [custom translations](https://www.amcharts.com/docs/v5/concepts/locales/creating-translations/#Extending_locale_with_custom_prompts) to a Stock Chart. Translating ----------- We can use Root element's language object's `setTranslationsAny()` method to set prompt translations. root.language.setTranslationsAny({ "Settings": "Ajustes", "Draw": "Dibujar" }); root.language.setTranslationsAny({ "Settings": "Ajustes", "Draw": "Dibujar" }); The below code provides a template for translation containing all of the prompts and names used in StockChart. Use it to create your full or partial translations: root.language.setTranslationsAny({ // Misc prompts "Line": "", "Candles": "", "Hollow Candles": "", "Sticks": "", "Fills": "", "Color": "", "Positive color": "", "Negative color": "", "Fill": "", "Save": "", "Cancel": "", "Apply": "", "Reset": "", "Comparison": "", "to": "", "Scroll to increment": "", "Click to toggle": "", "Search": "", "Search results are limited to %1.": "", // Settings "Settings": "", "Y-axis scale": "", "Change percent": "", "Regular": "", "Logarithmic": "", // Date-range selectors "Date Range": "", "Period selector": "", "D": "", "M": "", "YTD": "", "Y": "", "Max": "", "minute": "", "minutes": "", "hour": "", "hours": "", "day": "", "week": "", "month": "", "year": "", "Year": "", "Month": "", "Hour": "", "Minute": "", "Wk": "", // Drawing "Draw": "", "Drawing tool": "", "Snap icon to data": "", "Line color": "", "Line thickness": "", "Line style": "", "Fill color": "", "Text": "", "Text color": "", "Label font size": "", "Bold": "", "Italic": "", "Label font family": "", "Show line extension": "", "Eraser": "", "Clear": "", "Clear all drawings": "", "Callout": "", "Doodle": "", "Ellipse": "", "Fibonacci": "", "Fibonacci Timezone": "", "Horizontal Line": "", "Horizontal Ray": "", "Arrows & Icons": "", "Label": "", "Polyline": "", "Quadrant Line": "", "Rectangle": "", "Regression": "", "Trend Line": "", "Vertical Line": "", // Indicators "Indicators": "", "Increase": "", "Decrease": "", "Accumulation Distribution": "", "Accumulative Swing Index": "", "Use Volume": "", "Limit move value": "", "Period": "", "Aroon up": "", "Aroon down": "", "Increasing": "", "Decreasing": "", "Upper": "", "Average": "", "Lower": "", "Field": "", "Type": "", "Fast period": "", "Slow period": "", "Overbought": "", "Oversold": "", "Moving Average Type": "", "Fast MA period": "", "Slow MA period": "", "Signal period": "", "MACD": "", "Signal": "", "Offset": "", "Points/Percent": "", "Shift type": "", "Shift": "", "Top": "", "Median": "", "Bottom": "", "%K Smoothing": "", "%D Smoothing": "", "Fast": "", "Slow": "", "Signal color": "", "Up volume": "", "Down volume": "", "Deviation": "", "Depth": "", "Aroon": "", "Awesome Oscillator": "", "Bollinger Bands": "", "Chaikin Money Flow": "", "Chaikin Oscillator": "", "Commodity Channel Index": "", "Disparity Index": "", "Moving Average": "", "Moving Average Deviation": "", "Moving Average Envelope": "", "On Balance Volume": "", "Relative Strength Index": "", "Standard Deviation": "", "Stochastic Oscillator": "", "Trix": "", "Typical Price": "", "Volume": "", "VWAP": "", "Williams R": "", "Median Price": "", "ZigZag": "" }); root.language.setTranslationsAny({ // Misc prompts "Line": "", "Candles": "", "Hollow Candles": "", "Sticks": "", "Fills": "", "Color": "", "Positive color": "", "Negative color": "", "Fill": "", "Save": "", "Cancel": "", "Apply": "", "Reset": "", "Comparison": "", "to": "", "Scroll to increment": "", "Click to toggle": "", "Search": "", "Search results are limited to %1.": "", // Settings "Settings": "", "Y-axis scale": "", "Change percent": "", "Regular": "", "Logarithmic": "", // Date-range selectors "Date Range": "", "Period selector": "", "D": "", "M": "", "YTD": "", "Y": "", "Max": "", "minute": "", "minutes": "", "hour": "", "hours": "", "day": "", "week": "", "month": "", "year": "", "Year": "", "Month": "", "Hour": "", "Minute": "", "Wk": "", // Drawing "Draw": "", "Drawing tool": "", "Snap icon to data": "", "Line color": "", "Line thickness": "", "Line style": "", "Fill color": "", "Text": "", "Text color": "", "Label font size": "", "Bold": "", "Italic": "", "Label font family": "", "Show line extension": "", "Eraser": "", "Clear": "", "Clear all drawings": "", "Callout": "", "Doodle": "", "Ellipse": "", "Fibonacci": "", "Fibonacci Timezone": "", "Horizontal Line": "", "Horizontal Ray": "", "Arrows & Icons": "", "Label": "", "Polyline": "", "Quadrant Line": "", "Rectangle": "", "Regression": "", "Trend Line": "", "Vertical Line": "", // Indicators "Indicators": "", "Increase": "", "Decrease": "", "Accumulation Distribution": "", "Accumulative Swing Index": "", "Use Volume": "", "Limit move value": "", "Period": "", "Aroon up": "", "Aroon down": "", "Increasing": "", "Decreasing": "", "Upper": "", "Average": "", "Lower": "", "Field": "", "Type": "", "Fast period": "", "Slow period": "", "Overbought": "", "Oversold": "", "Moving Average Type": "", "Fast MA period": "", "Slow MA period": "", "Signal period": "", "MACD": "", "Signal": "", "Offset": "", "Points/Percent": "", "Shift type": "", "Shift": "", "Top": "", "Median": "", "Bottom": "", "%K Smoothing": "", "%D Smoothing": "", "Fast": "", "Slow": "", "Signal color": "", "Up volume": "", "Down volume": "", "Deviation": "", "Depth": "", "Aroon": "", "Awesome Oscillator": "", "Bollinger Bands": "", "Chaikin Money Flow": "", "Chaikin Oscillator": "", "Commodity Channel Index": "", "Disparity Index": "", "Moving Average": "", "Moving Average Deviation": "", "Moving Average Envelope": "", "On Balance Volume": "", "Relative Strength Index": "", "Standard Deviation": "", "Stochastic Oscillator": "", "Trix": "", "Typical Price": "", "Volume": "", "VWAP": "", "Williams R": "", "Median Price": "", "ZigZag": "" }); Demo ---- Below demo uses custom translations to translate Stock Chart into Lithuanian: See the Pen Stock chart with custom translation by amCharts team (@amcharts) on CodePen. --- # Settings – amCharts 5 Documentation Settings is a set of key - value pairs that each and every element of the chart has, that are used to configure its appearance and behavior. Settings can be manipulated in a number of ways, and, as we will see later in this tutorial, is the main method of configuring most of the things. Setting values -------------- There are three main ways to set settings directly on the elment: 1. By passing in an object as a second parameter to `new()` method when instantiating an element. 2. By using `set()` method of the element object. 3. By using `setAll()` method of the element object. ### When creating an element The most common and convenient way to specify element's settings is to pass those in when creating it by its `new()` method: const series = chart.series.push( am5pie.PieSeries.new( root, { valueField: "value", categoryField: "category" } ) ); var series = chart.series.push( am5pie.PieSeries.new( root, { valueField: "value", categoryField: "category" } ) ); ### On an element object Once we have element object, we can also set settings via its `set()` (to set single key) or `setAll()` (to set multiple keys in one go) methods as well. The above can be refactored to this: const series = chart.series.push( am5pie.PieSeries.new(root, {}) ); series.set("valueField", "value"); series.set("categoryField", "category"); var series = chart.series.push( am5pie.PieSeries.new(root, {}) ); series.set("valueField", "value"); series.set("categoryField", "category"); Or even like this: const series = chart.series.push( am5pie.PieSeries.new(root, {}) ); series.setAll({ valueField: "value", categoryField: "category" }); var series = chart.series.push( am5pie.PieSeries.new(root, {}) ); series.setAll({ valueField: "value", categoryField: "category" }); All three approaches are correct and will produce identical output. Available setting keys ---------------------- We can find out what settings each element has by consulting the class reference of its class. Each class' reference will have a separate section named "Settings", accessible via right-hand menu: ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/image-1-1024x873.png) As an example, check out `DateAxis` settings [here](https://www.amcharts.com/docs/v5/reference/dateaxis/#Settings) . Binding to data --------------- Element's settings can be bound to a value in its data via its `templateField` setting. [More info](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) . Dynamic modification -------------------- Value for each setting can be manipulated dynamically by a custom function, called adapter. [More info](https://www.amcharts.com/docs/v5/concepts/settings/adapters/) . Applying states --------------- Each element can have any number of states attached to it. A state is basically a collection of setting values to be applied to the element when certain conditions are met or as required. For example, we might want to change button's fill color when it is hovered by a mouse cursor. For more information refer to the "[Sates](https://www.amcharts.com/docs/v5/concepts/settings/states/) " tutorial. Settings via themes ------------------- We can use themes - either built-in or custom ones - to automatically set setting values to certain elements. "[Themes](https://www.amcharts.com/docs/v5/concepts/themes/) " tutorial explains how. Tracking changes ---------------- An element can invoke a custom function when value of particular setting changes. [More info](https://www.amcharts.com/docs/v5/concepts/events/#Settings_value_change) . Animating setting values ------------------------ Element can smoothly animate between two values of its settings, like colors, positions, scale, etc. [More info](https://www.amcharts.com/docs/v5/concepts/animations/#Animating_settings) . Private settings ---------------- Some objects have "private" settings. Those are mostly informational values that can be retrieved using `getPrivate()` method. let cursorPosition = cursor.getPrivate("positionX"); var cursorPosition = cursor.getPrivate("positionX"); IMPORTANT Private settings are read-only and cannot be set by any user code. --- # List templates – amCharts 5 Documentation List templates (or objects of type `[ListTemplate](https://www.amcharts.com/docs/v5/reference/listtemplate/) `) are combination of a list of items of certain type as well as collection of default settings for those objects. List templates are used throughout amCharts 5. Use case -------- List templates are used in many cases where some object - mainly series - needs to create a number of specific elements and make those elements user-configurable. For example, pie series would create a bunch of slices. The list template for those would be accessible via pie series' `slices` property, and would hold instances of all actual `Slice` elements in series, as well as a property: `template`, which can be used to configure slices. Templates --------- Templates of a list template is accessible via its `template` property. For example: `pieSeries.slices.template`. It can be used to set: * Settings * Events * Adapters * States * Object setup function Each of those work exactly like we would use them on an object of a real element. ### Settings We set settings using `set()` (for setting single key) or `setAll()` (for setting multiple key/values at once). pieSeries.slices.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeOpacity: 1 }); pieSeries.slices.template.setAll({ fillOpacity: 0.5, stroke: am5.color(0x000000), strokeOpacity: 1 }); When new elements are created in this list, the will be set the settings from the template. These settings will override whatever defaults actual element may have. For more information about setting, refer to "[Settings](https://www.amcharts.com/docs/v5/concepts/settings/) " tutorial. ### Setup handler Templates can also have a custom function which will be run on a newly created object. The following will show how we can make axis labels add a background: yAxis.get("renderer").labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0xff0000) })) } yAxis.get("renderer").labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0xff0000) })) } IMPORTANT The `template.setup` needs to be set **before** any data is set on the the series. ### Events Events can also be set on a template, just like we would do on a real element: columnSeries.columns.template.events.on("click", function(ev) { console.log("Clicked on a clumn"); }); columnSeries.columns.template.events.on("click", function(ev) { console.log("Clicked on a clumn"); }); Events added on a template, will be automatically replicated on any new object created in the list. For more information about events, refer to "[Events](https://www.amcharts.com/docs/v5/concepts/events/) " tutorial. ### Adapters Similarly to events, adapters added to a template will also be copied over to any new element created in the list: columnSeries.columns.template.adapters.add("fill", function(fill, target) { if (target.dataItem.valueY < 0) { return am5.color(0xff0000); else { return fill; } }); columnSeries.columns.template.adapters.add("fill", function(fill, target) { if (target.dataItem.valueY < 0) { return am5.color(0xff0000); else { return fill; } }); For more information about adapters, refer to "[Adapters](https://www.amcharts.com/docs/v5/concepts/settings/adapters/) " tutorial. ### States States can also be created on a template, and will carry over to the newly created elements: columnSeries.columns.template.set("interactive", true); columnSeries.columns.template.states.create("hover", { fill: am5.color(0x0ff00f) }); columnSeries.columns.template.set("interactive", true); columnSeries.columns.template.states.create("hover", { fill: am5.color(0x0ff00f) }); For more information about states, refer to "[Sates](https://www.amcharts.com/docs/v5/concepts/settings/states/) " tutorial. List items ---------- ### Getting specific item To get a specific item from the list, we can use its `getIndex()` method: pieSeries.slices.getIndex(0); // get the first slice pieSeries.slices.getIndex(0); // get the first slice ### Iterating List template has a handy method `each()` that can be used to iterate through all of the list items: pieSeries.slices.each(function(slice) { console.log(slice); }); pieSeries.slices.each(function(slice) { console.log(slice); }); For more methods and properties available in list templates, refer to `ListTemplate` [class reference](https://www.amcharts.com/docs/v5/reference/listtemplate/) . --- # Template fields – amCharts 5 Documentation Template fields is a way to bind element's settings to data. Any element that has a data item can bind its settings to values in it. Setting up ---------- Template fields are similar to series data fields (see "[XY chart series: Data fields](https://www.amcharts.com/docs/v5/charts/xy-chart/series/#Data_fields) "). In a nutshell it means this: "this field in data holds an object with setting values to be used for the element". It is set via setting `templateField`. It can be set directly on an object or objects template, like for example `columns.template` on a column series, or `slices.template` on a pie series. In fact, the most common usage of template fields is in series (because they are primary users of data), so we'll be using series as example in this tutorial. series.columns.template.setAll({ fillOpacity: 0.5, strokeWidth: 2, templateField: "columnSettings" }); series.columns.template.setAll({ fillOpacity: 0.5, strokeWidth: 2, templateField: "columnSettings" }); Now, we can add objects with key `"columnSettings"` and setting values in it. Those settings will be applied to relevant columns. \[{\ date: new Date(2021, 0, 1).getTime(),\ value: 1000,\ columnSettings: {\ fill: am5.color(0xd6e681)\ }\ }, {\ date: new Date(2021, 0, 2).getTime(),\ value: 800,\ columnSettings: {\ fill: am5.color(0xbabf95)\ }\ }, {\ date: new Date(2021, 0, 3).getTime(),\ value: 700,\ columnSettings: {\ fill: am5.color(0xc4ad83)\ }\ }, {\ date: new Date(2021, 0, 4).getTime(),\ value: 1200,\ columnSettings: {\ fill: am5.color(0xc6b677)\ }\ }, {\ date: new Date(2021, 0, 5).getTime(),\ value: 740,\ columnSettings: {\ fill: am5.color(0xdbb957)\ }\ }\] See the Pen Using templateField with ColumnSeries by amCharts team (@amcharts) on CodePen. Another example using `PieSeries`: series.slices.template.setAll({ templateField: "sliceSettings" }); series.slices.template.setAll({ templateField: "sliceSettings" }); And the data: \[{\ country: "France",\ sales: 100000,\ sliceSettings: {\ fill: am5.color(0xd6e681),\ stroke: am5.color(0xd6e681)\ }\ }, {\ country: "Spain",\ sales: 160000,\ sliceSettings: {\ fill: am5.color(0xbabf95),\ stroke: am5.color(0xbabf95)\ }\ }, {\ country: "United Kingdom",\ sales: 80000,\ sliceSettings: {\ fill: am5.color(0xc4ad83),\ stroke: am5.color(0xc4ad83)\ }\ }\]; See the Pen PieSeries slice colors via data by amCharts team (@amcharts) on CodePen. Bullets ------- There are some caveats involved when using template fields with bullets. For more information, please visit "Bullets: [Template fields](https://www.amcharts.com/docs/v5/concepts/common-elements/bullets/#template-fields) " tutorial. --- # Adapters – amCharts 5 Documentation Adapters are custom functions that can be used to dynamically alter value of an element's setting. Adding ------ And adapter can be added directly to an object or to template using its `adapters.add()` method. This method requires two parameters: * Key of the setting the adapter will be used to modify value for. * Function that will be run every time setting value is requested, which can modify the value. The following code can be used to modify fill color of the column series columns based on their value: series.columns.template.adapters.add("fill", function(fill, target) { if (target.dataItem.get("valueY") < 1000) { return am5.color(0xff621f); } else { return fill; } }); series.columns.template.adapters.add("fill", function(fill, target) { if (target.dataItem.get("valueY") < 1000) { return am5.color(0xff621f); } else { return fill; } }); The above means that before column is drawn, its default fill color will be ran through our custom function. It will check related data item value and if it's less than 1000, it will use reddish color instead of default series color. See the Pen Styling ColumnSeries by amCharts team (@amcharts) on CodePen. Removing -------- There are two ways to remove an adapter: dispose it or use `remove()` method. ### Disposing The `add()` method used to add an adapter will return a `Disposer` object. It means that you can use its `dispose()` method to destroy it: let myAdapter = series.columns.template.adapters.add("fill", function(fill, target) { if (target.dataItem.get("valueY") < 1000) { return am5.color(0xff621f); } else { return fill; } }); // ... myAdapter.dispose(); // destroy the adapter var myAdapter = series.columns.template.adapters.add("fill", function(fill, target) { if (target.dataItem.get("valueY") < 1000) { return am5.color(0xff621f); } else { return fill; } }); // ... myAdapter.dispose(); // destroy the adapter ### Using remove() method Another way to remove an adapter is using `remove()` method: series.columns.template.adapters.remove("fill"); series.columns.template.adapters.remove("fill"); This method is easier, because you don't need to maintain reference to actual adapter. However, it will disable all adapters for the same key. If the target object has multiple adapters added for the same key, they will all be removed. Disabling --------- If we don't need to remove the adapter, but just want to temporarily disable it, we can use `disable()` method: series.columns.template.adapters.disable("fill"); series.columns.template.adapters.disable("fill"); If adapter for certain key is disabled, it will not kick in when settings value is requested. To re-enable the adapter, use `enable()` method: series.columns.template.adapters.enable("fill"); series.columns.template.adapters.enable("fill"); Mutating target element ----------------------- Adapters can also be used permanently update target element's settings. Those can be other settings, not necessarily ones that the adapter is for. The following adapter will modify `fill` setting of a tooltip, but will also modify related `tooltipY` setting so that tooltips appear at the bottom of the negative-value columns: series.columns.template.adapters.add("fill", function(fill, target) { let dataItem = target.dataItem; if (dataItem.get("valueY") < 0) { target.set("tooltipY", am5.p100); return am5.color(0xff0000); } return fill; }); series.columns.template.adapters.add("fill", function(fill, target) { var dataItem = target.dataItem; if (dataItem.get("valueY") < 0) { target.set("tooltipY", am5.p100); return am5.color(0xff0000); } return fill; }); See the Pen Column chart with adapters for the tooltips by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Using adapters on category axis labels](https://www.amcharts.com/docs/v5/tutorials/using-adapters-on-category-axis-labels/) * [Labels on negative columns](https://www.amcharts.com/docs/v5/tutorials/labels-on-negative-columns/) (dynamic placement of bullets using an adapter) --- # Heat rules – amCharts 5 Documentation Heat rules is a way to apply value-dependent setting values on series elements. Prerequisites ------------- In order for heat rules to function properly on series, it needs aggregate values (high and low) to be calculated for the series. Normally, series does not do that in order not to waste resources. To enable, we just need to set `[calculateAggregates](https://www.amcharts.com/docs/v5/reference/series/#calculateAggregates_setting) ` setting to `true`: let series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", calculateAggregates: true }) ); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Series", xAxis: xAxis, yAxis: yAxis, valueYField: "value", valueXField: "date", calculateAggregates: true }) ); Creating -------- A heat rule is a generic object that corresponds to `[IHeatRule](https://www.amcharts.com/docs/v5/reference/Iheatrule/) ` interface. It has the following required properties: | Property | Comment | | --- | --- | | `target` | A template for target element that heat rules will be applied to. E.g. column series' `columns.template`. | | `key` | A settings key to apply heat value to on actual elements. | | `min` | Lower end value of the spectrum, corresponding to the lowest value in all elements affected by the heat rule. | | `max` | Higher end value of the spectrum, corresponding to the highest value in all elements affected by the heat rule. | | `dataField` | A data field to look for element's "value". | Series elements --------------- To apply heat rules to series elements, like a column, we can use its template as a `target` for the heat rule. Here's an example of a heat rule that applies color to column series columns based on their `valueY` data field (same data field that is used to determine column height). series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "valueY",\ min: am5.color(0xff621f),\ max: am5.color(0x661F00),\ key: "fill"\ }\]) series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "valueY",\ min: am5.color(0xff621f),\ max: am5.color(0x661F00),\ key: "fill"\ }\]) See the Pen Using templateField with ColumnSeries by amCharts team (@amcharts) on CodePen. Arbitrary value --------------- We're not limited to binding to a data field that is used for actually plotting the series. Each series also defines a generic `"value"` data field, which can be used for heat rules. var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueField: "heatValue", valueYField: field, valueXField: "date", calculateAggregates: true }) ); series.setAll({ heatRules: \[{\ target: series.columns.template,\ dataField: "value",\ min: am5.color(0xff621f),\ max: am5.color(0x661F00),\ key: "fill"\ }\] }); var series = chart.series.push( am5xy.ColumnSeries.new(root, { name: name, xAxis: xAxis, yAxis: yAxis, valueField: "heatValue", valueYField: field, valueXField: "date", calculateAggregates: true }) ); series.setAll({ heatRules: \[{\ target: series.columns.template,\ dataField: "value",\ min: am5.color(0xff621f),\ max: am5.color(0x661F00),\ key: "fill"\ }\] }); See the Pen Heat rules on ColumnSeries by amCharts team (@amcharts) on CodePen. Bullets ------- Bullets do not have a dedicated template in series, so they need their template (for use in a heat rule) to be created explicitly: let circleTemplate: am5.Template = am5.Template.new({}); series.bullets.push(function() { const bulletCircle = am5.Circle.new(root, { radius: 5, fill: series.get("fill"), fillOpacity: 0.8 }, circleTemplate); return am5.Bullet.new(root, { sprite: bulletCircle }); }); // Add heat rules series.set("heatRules", \[{\ target: circleTemplate,\ min: 3,\ max: 60,\ dataField: "value",\ key: "radius"\ }\]); let circleTemplate = am5.Template.new({}); series.bullets.push(function() { const bulletCircle = am5.Circle.new(root, { radius: 5, fill: series.get("fill"), fillOpacity: 0.8 }, circleTemplate); return am5.Bullet.new(root, { sprite: bulletCircle }); }); // Add heat rules series.set("heatRules", \[{\ target: circleTemplate,\ min: 3,\ max: 60,\ dataField: "value",\ key: "radius"\ }\]); var circleTemplate = am5.Template.new({}); series.bullets.push(function() { var bulletCircle = am5.Circle.new(root, { radius: 5, fill: series.get("fill"), fillOpacity: 0.8 }, circleTemplate); return am5.Bullet.new(root, { sprite: bulletCircle }); }); // Add heat rules series.set("heatRules", \[{\ target: circleTemplate,\ min: 3,\ max: 60,\ dataField: "value",\ key: "radius"\ }\]); The above creates a `Template` object, which is then passed in as a second parameter to `new()` method of a `Circle` class, so it is tied to a template. We can then use that template in a heat rule to use on circle's `radius` setting. See the Pen XY scatter chart with heat rules on bullets by amCharts team (@amcharts) on CodePen. Custom value range ------------------ Heat rules will use aggregated high and low values from the data items of involved elements. We can override that with absolutely custom values using heat rules `minValue` and `maxValue` settings. series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "valueY",\ min: am5.color(0xff621f),\ max: am5.color(0x661F00),\ minValue: 0,\ maxValue: 1000,\ key: "fill"\ }\]) series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "valueY",\ min: am5.color(0xff621f),\ max: am5.color(0x661F00),\ minValue: 0,\ maxValue: 1000,\ key: "fill"\ }\]) NOTE If we set `minValue` and `maxValue` we don't need series to aggregate values, so the `calculateAggregates` does not need to be set. Custom functions ---------------- If we need to do something fancier than just set value of a setting, we can use heat rule's `customFunction` property. If set, instead of setting value of the setting directly on an element, this function will be called passing in the following parameters: * Target element (not a template, but an actual live element). * Min value * Max value * Value of the target element It'll be up to the custom function to determine what settings and to what values to set. series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "value",\ customFunction: function(sprite, min, max, value) {\ if (value < 100) {\ sprite.set("fill", am5.color(0xff0000));\ }\ else {\ sprite.set("fill", am5.color(0x00ff00));\ }\ }\ }\]) series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "value",\ customFunction: function(sprite: am5.Sprite, min, max, value) {\ if (value < 100) {\ (sprite as am5.Graphics).set("fill", am5.color(0xff0000));\ }\ else {\ (sprite as am5.Graphics).set("fill", am5.color(0x00ff00));\ }\ }\ }\]) series.set("heatRules", \[{\ target: series.columns.template,\ dataField: "value",\ customFunction: function(sprite, min, max, value) {\ if (value < 100) {\ sprite.set("fill", am5.color(0xff0000));\ }\ else {\ sprite.set("fill", am5.color(0x00ff00));\ }\ }\ }\]) Examples -------- ### Map chart See the Pen Map point series creating individual data items by amCharts team (@amcharts) on CodePen. --- # Getting the most out of net.load utility – amCharts 5 Documentation This tutorial walks through advanced uses of the `net.load` utility, which is used to load data in external URLs. Prerequisites ------------- We're assuming that you are familiar with what `net.load` utility is, what is it used for, and how. For basic usage refer to the "[External data](https://www.amcharts.com/docs/v5/concepts/data/#External_data) " section in "Data" tutorial. Specifying data user -------------------- `net.load` utility is completely standalone, but we can pass in its intended data user via second parameter. Doing so will not modify it, or set data on it, but will rather contain reference to it in all success/error handlers, so we can use generic load handler functions. E.g.: function dataLoaded(result) { // Set data on all series of the chart const data = am5.JSONParser.parse(result.response); result.target.series.each(function(series) { series.data.setAll(data); }); } am5.net.load("/data/mydata.json", chart).then(dataLoaded); function dataLoaded(result) { // Set data on all series of the chart var data = am5.JSONParser.parse(result.response); result.target.series.each(function(series) { series.data.setAll(data); }); } am5.net.load("/data/mydata.json", chart).then(dataLoaded); HTTP request options -------------------- It's possible to pass in options to the HTTP request via third parameter to the `net.load()` function. Supported properties are as follows: | Option | Comment | | --- | --- | | `requestHeaders` | An array of objects that define key and value of additional information to pass as a HTTP(S) request headers. | | `responseType` | A response type expected from the server. ([more info](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
) | | `withCredentials` | Whether to pass in web authentication credentials with the request. ([more info](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
) | function dataLoaded(result) { // Set data on all series of the chart const data = am5.JSONParser.parse(result.response); result.target.series.each(function(series) { series.data.setAll(data); }); } am5.net.load("/data/mydata.json", chart, { requestHeaders: \[{\ key: "x-user-token",\ value: "123456789"\ }\] }).then(dataLoaded); function dataLoaded(result) { // Set data on all series of the chart var data = am5.JSONParser.parse(result.response); result.target.series.each(function(series) { series.data.setAll(data); }); } am5.net.load("/data/mydata.json", chart, { requestHeaders: \[{\ key: "x-user-token",\ value: "123456789"\ }\] }).then(dataLoaded); Result object ------------- The result object passed in to load handler function contains much more than the `response`: | Field | Comment | | --- | --- | | `xhr` | The original `XMLHttpRequest` object used to make HTTP(S) request. ([more info](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
) | | `response` | A string response loaded from the web server. | | `blob` | Response `Blob` if `responseType` in request options was set to `"blob"`. | | `type` | A response type. ([more info](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType)
) | | `error` | `false` if loaded successfully; `true` if error occurred when loading. | | `target` | A target data user object if it was specified. ([more info](https://www.amcharts.com/docs/v5/tutorials/advanced-use-of-net-load-utility/#Specifying_data_user)
) | --- # Data – amCharts 5 Documentation This tutorial will look at how data is loaded, updated, and used in amCharts 5. The data object --------------- All amCharts 5 components that use data have a property named `data`. It's not a simple storage for data but rather object based on class `ListData`. Any data manipulation - setting data, inserting, removing, or updating values for data points - is done via many of the `ListData` methods. The object will take care of the rest - no need to let the chart know we've updated something - it will just happen. In this tutorial, we will cover the most common of `ListData`'s methods, but make sure you visit its [full class reference](https://www.amcharts.com/docs/v5/reference/datalist/#Methods) for more options. Setting data ------------ Data set set via `ListData` object of the component that is direct user of the data. For example, in XY Chart the users of data are its series, not the chart itself. Chart's [legend](https://www.amcharts.com/docs/v5/concepts/legend/) is another example of a data user. To set initial data or replace all of the current data, we use `setAll()` method: series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: 1200\ }, {\ category: "Sales",\ value: 850\ }\]); Using `setAll()` will overwrite any data that may have been set previously. The series will be immediately redrawn to reflect the new data. IMPORTANT It's a good practice to make sure that setting data happens as late into code as possible. Once you set data, all related objects are created, so any configuration settings applied afterwards might not carry over. Data order ---------- IMPORTANT[Date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) expects series data to be sorted in ascending order. Otherwise, chart will be prone to all kinds of plotting anomalies. Incremental updates ------------------- ### Adding single data point To add a single data point to the end of the data, we use `push()` method: series.data.push({ category: "HR", value: 500 }); series.data.push({ category: "HR", value: 500 }); Should we want to add data points to the beginning of data, we would use `unshift()` instead: series.data.unshift({ category: "HR", value: 500 }); series.data.unshift({ category: "HR", value: 500 }); We can insert new data point at specific index, too. For that we'd use `insertIndex()`. The function takes index (zero-based) and value to insert into data: series.data.insertIndex(2, { category: "HR", value: 500 }); series.data.insertIndex(2, { category: "HR", value: 500 }); ### Adding multiple data points Similarly, to add multiple data points to the end of the data, we can use `pushAll()` method: series.data.pushAll(\[{\ category: "HR",\ value: 500\ }, {\ category: "Logistics",\ value: 450\ }\]); series.data.pushAll(\[{\ category: "HR",\ value: 500\ }, {\ category: "Logistics",\ value: 450\ }\]); Updating existing data ---------------------- To update existing data points, we use method `setIndex()`. The method takes index (zero-based) and new data as parameters. For example, let's update values of the second data point: series.data.setIndex(1, { category: "Marketing", value: 1000 }); series.data.setIndex(1, { category: "Marketing", value: 1000 }); Calling `setIndex()` will take care of all the recalculation and redrawing of the required elements. It will even animate from one value to another, if we have animations enabled. See the Pen Stacked column chart by amCharts team (@amcharts) on CodePen. Removing data items ------------------- If we need to remove data items, we can use `removeIndex()` method: series.data.removeIndex(0); series.data.removeIndex(0); The above will remove the first data item from series. Pre-processing data ------------------- `ListData` comes with a capability to pre-process the data before it is passed onto a chart. For that it has a property: `processor`. It can be set to an instance of `DataProcessor`, which can do the following: * Convert string-based dates or `Date` objects into timestamps, which is expected format for time-based data in amCharts 5. * Convert string-based numbers into proper numeric values. * Replace empty values with something else. ### Creating a processor Like with any object in amCharts 5, data processor is created using its `new()` static method: series.data.processor = am5.DataProcessor.new(root, {}); series.data.processor = am5.DataProcessor.new(root, {}); The above will create the processor, which will do nothing, until we set some of its properties. IMPORTANT In amCharts 5, data is parsed and processed immediately after it is set (e.g. via `data.setAll()` call), so the processor needs to be set **before** setting actual data, or it won't kick in. ### Data mutation Data processor will manipulate values in the source array! If you need your source data to remain intact, you may need to make a hard copy of the data and pass it into series instead. This is also why you don't need to define data processors for multiple series if they use the same data. // Source data let data = \[{\ date: "2021-01-01",\ value: "1000"\ }, {\ date: "2021-01-02",\ value: "800"\ }\]; // Creating processor only for the first series series1.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\] }); // Setting data series1.data.setAll(data); series2.data.setAll(data); series3.data.setAll(data); // Source data var data = \[{\ date: "2021-01-01",\ value: "1000"\ }, {\ date: "2021-01-02",\ value: "800"\ }\]; // Creating processor only for the first series series1.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\] }); // Setting data series1.data.setAll(data); series2.data.setAll(data); series3.data.setAll(data); ### Parsing numeric values Chart expects numbers in data where numeric data fields are used. If we have values supplied as strings in our data, the chart will fail. We can use data processor to automatically convert those strings into numeric values, by setting `numericFields` property: // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\] }); series.data.setAll(\[{\ date: "2021-01-01",\ value: "1000"\ }, {\ date: "2021-01-02",\ value: "800"\ }\]); // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\] }); series.data.setAll(\[{\ date: "2021-01-01",\ value: "1000"\ }, {\ date: "2021-01-02",\ value: "800"\ }\]); ### Parsing dates If we use a date axis in our chart, the values that specify date/time will need to come in JavaScript timestamp format, which is number of milliseconds since "UNIX epoch". If our data is in any other way we may need to tell data processor to convert those dates into timestamp. To specify what fields hold dates we use `dateFields`: // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], dateFields: \["date"\] }); series.data.setAll(\[{\ date: new Date(2021, 0, 1),\ value: "1000"\ }, {\ date: new Date(2021, 0, 2),\ value: "800"\ }\]); // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], dateFields: \["date"\] }); series.data.setAll(\[{\ date: new Date(2021, 0, 1),\ value: "1000"\ }, {\ date: new Date(2021, 0, 2),\ value: "800"\ }\]); The above example uses `Date` objects to specify dates. If our data holds dates as strings, we will additionally have to specify `dateFormat` so that processor knows how to parse it into a timestamp: // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], dateFields: \["date"\], dateFormat: "yyyy-MM-dd" }); series.data.setAll(\[{\ date: "2021-01-01",\ value: "1000"\ }, {\ date: "2021-01-02",\ value: "800"\ }\]); // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], dateFields: \["date"\], dateFormat: "yyyy-MM-dd" }); series.data.setAll(\[{\ date: "2021-01-01",\ value: "1000"\ }, {\ date: "2021-01-02",\ value: "800"\ }\]); MORE INFO The date format is described in "[Formatting dates](https://www.amcharts.com/docs/v5/concepts/formatters/formatting-dates/) " tutorial. The following format codes are supported when parsing dates: | Period | Code | No. | Example | Comment | | --- | --- | --- | --- | --- | | **era** | G | 1 | AD | "AD" or "BC" | | | | | | | | **year** | y | 1..n | 1996 | Calendar year. | | | Y | 1..n | 1997 | Week year. | | | | | | | | **month** | M | 1..2 | 09 | One or two digit month number. | | | | 3 | Sep | Short month name. | | | | 4 | September | Full month name. | | | | | | | | **week** | w | 1..2 | 27 | Week of the year. | | | W | 1 | 3 | Week of the month. | | | | | | | | **day** | d | 1..2 | 1 | Day of the month. | | | D | 1..3 | 345 | Day of the year. | | | | | | | | **am/pm** | a | 1 | AM | "AM" or "PM" | | | | 2 | A.M. | "A.M." or "P.M." | | | | 3 | A | "A" or "P" | | | | | | | | **hour** | h | 1..2 | 11 | Hour \[1-12\]. | | | H | 1..2 | 13 | Hour \[0-23\]. | | | K | 1..2 | 0 | Hour \[0-11\]. | | | k | 1..2 | 24 | Hour \[1-24\]. | | | | | | | | **minute** | m | 1..2 | 59 | Minute. | | | | | | | | **second** | s | 1..2 | 12 | Second. | | | S | 1..2 | 3456 | Fractional Second. | | | x | 1..n | 1507908460868 | Timestamp. | | | n | 1..3 | 029 | Milliseconds. | | | | | | | | **zone** | Z | 1 | GMT-08:00 | Time zone in GMT format. | | | | 2 | \-0800 | Time zone in RFC 822 format. | | | | | | | | **other** | i | 1 | 2017-10-14T05:24:17.872Z | Date/time formatted according to [ISO8601 format](http://en.wikipedia.org/wiki/ISO_8601)
. | NOTE If `dateFormat` is not set, and processor encounters a string-based value it needs to parse, it will use chart-wide date format (`root.dateFormatter.dateFormat`). See the Pen amCharts v5: Stacked step lines by amCharts team (@amcharts) on CodePen. ### Parsing colors Colors in amCharts 4 are represented by `Color` objects. If you need data processor to automatically convert string-based or hex color codes to `Color` objects, you can use `colorFields`. Data processor recognizes the following formats: * Hex strings: `"#ff0000"` * RGBA notation: `"rgb(255, 0, 0)"` or `"rgba(255, 0, 0, 1)"` * Hex numbers: `0xff0000` or `16711680` // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], colorFields: \["color"\] }); series.data.setAll(\[{\ date: "2021-01-01",\ value: "1000",\ color: "#ff0000"\ }, {\ date: "2021-01-02",\ value: "800",\ color: "#ff0000"\ }\]); // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], colorFields: \["color"\] }); series.data.setAll(\[{\ date: "2021-01-01",\ value: "1000",\ color: "#ff0000"\ }, {\ date: "2021-01-02",\ value: "800",\ color: "#ff0000"\ }\]); ### Deep processing Processor can convert input values from deeper objects, too. `numericFields`, `dateFields`, and `colorFields` accept strings using dot notation to identify hierarchy. For example consider data like this: \[{\ date: new Date(2021, 0, 1),\ value: 1000,\ columnSettings: {\ fill: "#d6e681"\ }\ }, {\ date: new Date(2021, 0, 2),\ value: 800,\ columnSettings: {\ fill: "#babf95"\ }\ }, {\ date: new Date(2021, 0, 3),\ value: 700,\ columnSettings: {\ fill: "#c4ad83"\ }\ }, {\ date: new Date(2021, 0, 4),\ value: 1200,\ columnSettings: {\ fill: "#c6b677"\ }\ }, {\ date: new Date(2021, 0, 5),\ value: 740,\ columnSettings: {\ fill: "#dbb957"\ }\ }\] We can use `"columnSettings.fill"` to allow processor to get to resolving `fill` color: series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], dateFields: \["date"\], colorFields: \["columnSettings.fill"\] }); series.data.processor = am5.DataProcessor.new(root, { numericFields: \["value"\], dateFields: \["date"\], colorFields: \["columnSettings.fill"\] }); ### Replacing empty values In some cases we need to replace empty values (e.g. `null` or empty strings) with something else. That's where processors `emptyAs` setting comes in: // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { emptyAs: 0 }); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: null\ }, {\ category: "Sales",\ value: 850\ }\]); // Processor needs to be set before data series.data.processor = am5.DataProcessor.new(root, { emptyAs: 0 }); series.data.setAll(\[{\ category: "Research",\ value: 1000\ }, {\ category: "Marketing",\ value: null\ }, {\ category: "Sales",\ value: 850\ }\]); In the above, without the processor, a data point for "Marketing" would be not plotted. With data processor, it will be replaced with a zero, which is a proper numeric value and thus will plot the data point. External data ------------- ### Loading amCharts 5 comes with a helper utility `am5.net.load()`. It takes at least one argument (a URL of the request) and returns a `Promise` object with net load result (`INetLoadResult`). am5.net.load("/data/mydata.json").then(function(result) { // This gets executed when data finishes loading // ... do something console.log(result.response); }).catch(function(result) { // This gets executed if there was an error loading URL // ... handle error console.log("Error loading " + result.xhr.responseURL); }); am5.net.load("/data/mydata.json").then(function(result) { // This gets executed when data finishes loading // ... do something console.log(result.response); }).catch(function(result) { // This gets executed if there was an error loading URL // ... handle error console.log("Error loading " + result.xhr.responseURL); }); The `result` passed to handler functions is an object that implements `INetLoadResult` interface. It contains a bunch of useful references, but the most important one is `response`, which contains the actual output of the requested URL. MORE INFO There are more to `am5.net.load()` than the bare minimum outlined above. Please refer to "[Getting the most out of net.load utility](https://www.amcharts.com/docs/v5/concepts/data/net-load-utility/) " tutorial for information about passing in target data user object, setting HTTP request options, and more. ### Parsing Now that we've set up loading of data, we need to parse it before it can be used by chart. amCharts 5 comes with two build-in parsers: CSV and JSON. Those are represented by classes `CSVParser` and `JSONParser` respetively, both of which have a static method `parse()` so they do not need to be instantiated as objects. `parse()` method takes two parameters: * `data` - input data as a string. * `options` (optional) - format-specific options. It returns parsed data, which can be set directly to its intended user, e.g. series: am5.net.load("/data/mydata.json").then(function(result) { // This gets executed when data finishes loading series.data.setAll(am5.JSONParser.parse(result.response)); }).catch(function(result) { // This gets executed if there was an error loading URL // ... handle error console.log("Error loading " + result.xhr.responseURL); }); am5.net.load("/data/mydata.json").then(function(result) { // This gets executed when data finishes loading series.data.setAll(am5.JSONParser.parse(result.response)); }).catch(function(result) { // This gets executed if there was an error loading URL // ... handle error console.log("Error loading " + result.xhr.responseURL); }); CSV format can have a lot of configuration options, such as column delimiters, column names, etc. am5.net.load("/data/mydata.csv").then(function(result) { // This gets executed when data finishes loading series.data.setAll(am5.CSVParser.parse(result.response, { delimiter: ";", reverse: true, skipEmpty: true, useColumnNames: true })); }).catch(function(result) { // This gets executed if there was an error loading URL // ... handle error console.log("Error loading " + result.xhr.responseURL); }); am5.net.load("/data/mydata.csv").then(function(result) { // This gets executed when data finishes loading series.data.setAll(am5.CSVParser.parse(result.response, { delimiter: ";", reverse: true, skipEmpty: true, useColumnNames: true })); }).catch(function(result) { // This gets executed if there was an error loading URL // ... handle error console.log("Error loading " + result.xhr.responseURL); }); We can also use standalone data parser to parse date/numeric/color fields in data after it is parsed: am5.net.load("/data/mydata.csv").then(function(result) { // Parse data let data = am5.CSVParser.parse(result.response, { delimiter: ";", reverse: true, skipEmpty: true, useColumnNames: true }); // Process data let processor = am5.DataProcessor.new(root, { dateFields: \["date"\], dateFormat: "yyyy-MM-dd", numericFields: \["value", "volume"\] }); processor.processMany(data); // Use parsed/processed data series.data.setAll(data); }); am5.net.load("/data/mydata.csv").then(function(result) { // Parse data var data = am5.CSVParser.parse(result.response, { delimiter: ";", reverse: true, skipEmpty: true, useColumnNames: true }); // Process data var processor = am5.DataProcessor.new(root, { dateFields: \["date"\], dateFormat: "yyyy-MM-dd", numericFields: \["value", "volume"\] }); processor.processMany(data); // Use parsed/processed data series.data.setAll(data); }); ### External data example The following Gantt chart example combines a few techniques described above, like loading and parsing external data, as well as using data processor to parse date and color fields. See the Pen Gantt Chart with external data by amCharts team (@amcharts) on CodePen. User data --------- Each element in amCharts 5 can have any arbitrary data attached to it using its `userData` setting. This setting is not used by chart in any way, and acts purely as custom data storage for later retrieval/use from the object. It can be set using `set()` or `setAll()` methods: chart.set("userData", { foo: "bar" }); chart.set("userData", { foo: "bar" }); Or via `new()` syntax: let yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, { extraTooltipPrecision: 1, userData: { foo: "bar", someArbitraryValue: 100 }, renderer: am5xy.AxisRendererY.new(root, { minGridDistance: 30 }) })); var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, { extraTooltipPrecision: 1, userData: { foo: "bar", someArbitraryValue: 100 }, renderer: am5xy.AxisRendererY.new(root, { minGridDistance: 30 }) })); As with any other setting, it can be retrieved using `get()` method: chart.get("userData"); chart.get("userData"); Related content --------------- * [Getting the most out of net.load utility](https://www.amcharts.com/docs/v5/concepts/data/net-load-utility/) * [Binding element's settings to values in data](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) * [Show "no data" warning on a chart](https://www.amcharts.com/docs/v5/tutorials/show-no-data-warning-on-a-chart/) * [Gantt chart with external data](https://www.amcharts.com/docs/v5/tutorials/gantt-chart-with-external-data/) (demo) --- # Gradients – amCharts 5 Documentation This tutorial looks at how we can create gradients to use for element fills ant outlines. To apply a gradient fill to an element, we need to do two things: * Create a gradient object. * Assign it to element's `fillGradient` and/or `strokeGradient`. Creating a gradient ------------------- Gradient object is created using its `new()` method: let gradient = am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xFF621F)\ }, {\ color: am5.color(0x946B49)\ }\] }); var gradient = am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xFF621F)\ }, {\ color: am5.color(0x946B49)\ }\] }); Available gradient types ------------------------ | Pattern class | Example | | --- | --- | | `[LinearGradient](https://www.amcharts.com/docs/v5/reference/lineargradient/) ` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/linear_gradient.png) | | `[RadialGradient](https://www.amcharts.com/docs/v5/reference/radialgradient/) ` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/radial_gradient.png) | Setting gradient ---------------- To set a gradient fill on an element, we need to assign it to element's `fillGradient` setting. Similarly, to assign it to element's stroke (line), we can use `strokeGradient`. columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xFF621F)\ }, {\ color: am5.color(0x946B49)\ }\], rotation: 90 })); columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xFF621F)\ }, {\ color: am5.color(0x946B49)\ }\], rotation: 90 })); Gradient stops -------------- Each step in gradient is called a "stop". Gradient needs to have two or more stops. Those are set via gradient's `stops` setting which is an array of `[IGradientStop](https://www.amcharts.com/docs/v5/reference/igradientstop/) ` objects. ### Colors To set a color for the step, we a `color` property. If color is not set, the gradient will try to reuse a color of the target element. columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xff621f)\ }, {\ color: am5.color(0x946b49)\ }\] })); columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xff621f)\ }, {\ color: am5.color(0x946b49)\ }\] })); The whole area of the target element that needs to be filled will be divided between stops. Gradient will start at the color of the first stop, then progress to the intermediate stop colors, and end with the color of the last stop. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_2colors.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_2colors.png) 2 stop gradient [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_3colors.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_3colors.png) 3 stop gradient [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_4colors.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_4colors.png) 4 stop gradient See the Pen Patterns by amCharts team (@amcharts) on CodePen. ### Opacity Each step can also specify opacity. This allows creating transitions not only between color, but also opacities: columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xff621f),\ opacity: 1\ }, {\ color: am5.color(0x946b49),\ opacity: 0.2\ }\] })); columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0xff621f),\ opacity: 1\ }, {\ color: am5.color(0x946b49),\ opacity: 0.2\ }\] })); The above will make column fill start at color `#946b49` fully opaque and end in `#946b49` at 20% opacity. `color` attribute is optional, so we can omit it and just set opacities. This will make gradient use target elements color, but apply different opacities to it. Here's an example of such fill on a line series: lineSeries.fills.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ opacity: 1\ }, {\ opacity: 0.5\ }\] })); lineSeries.fills.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ opacity: 1\ }, {\ opacity: 0.5\ }\] })); See the Pen Gradients with line series by amCharts team (@amcharts) on CodePen. ### Brightness Just like each step can modify color opacity, it can also brighten or darken color. There are two step properties for that: `lighten` and `brighten`. Both accept numeric values (0-1), that mean how to make color lighter/brighter (positive number) or dimmer/darker (negative number). The difference between the two are subtle: `lighten` is basically a saturation control, keeping same gamma of color, whereas `brighten` controls actual vividness of the color. Increasing brightness makes color visually brighter, whereas increasing lightness makes it just closer to white. lineSeries.fills.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ opacity: 1\ }, {\ opacity: 0.5\ }\] })); lineSeries.fills.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ brighten: 1\ }, {\ brighten: -0.5\ }\] })); The below two fills use the same color as a base [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/solid_color.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/solid_color.png) Base color without gradient [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/brighten.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/brighten.png) `brighten: 1`, `brighten: -0.2` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/lighten.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/lighten.png) `lighten: 1`, `lighten: -0.2` See the Pen Gradients by amCharts team (@amcharts) on CodePen. ### Offsets Normally, the stops will divvy up the whole space equally between them. For example if there are 3 stops, there transition between 1st and 2nd stop will take up 50% of the space, and transition between 2n to 3rd another 50%. We can use stop's `offset` property to change that. `offset` accepts numeric value from `0` (zero) to `1` (one), indicating relative distance to area of the fill. columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0x297373),\ offset: 0.7\ }, {\ color: am5.color(0x946b49)\ }\], rotation: 90 })); columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0x297373),\ offset: 0.7\ }, {\ color: am5.color(0x946b49)\ }\], rotation: 90 })); The above will make the first color to start at 70%, leaving only 30% for the actual gradient to second stop's color. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_offset_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_offset_0-e1628792950241.png) `offset: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_offset_07.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/gradient_offset_07-e1628792932888.png) `offset: 0.7` Sizing ------ Normally, gradient will start and end at the edges of the target element. In some cases we might need it to size differently. For example, we if we set gradient fill on a `LineSeries` it will be start at the top point and will end at the lowest point. Similarly, on a `ColumnSeries` each individual column will have differently sized gradient because of their varying height. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_1.png) Default bheavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_2.png) Default bheavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_6.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_6.png) Default bheavior But we might want to apply gradient based on axis scale. That's where gradient's `target` setting comes in. We can set it to any other element on the chart, for example `chart.plotContainer`: columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0x297373)\ }, {\ color: am5.color(0x946b49)\ }\], rotation: 90, target: chart.plotContainer })); columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0x297373),\ offset: 0.7\ }, {\ color: am5.color(0x946b49)\ }\], rotation: 90, target: chart.plotContainer })); Now the gradient will be applied using sizing of the chart's plot container, rather than individual sizing of each series element. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_4.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_4.png) `target: chart.plotContainer` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_3.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_3.png) `target: chart.plotContainer` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_5.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/03/gradient_target_5.png) `target: chart.plotContainer` See the Pen Gradients by amCharts team (@amcharts) on CodePen. Rotation -------- Linear gradient has a property `rotation` which can be used to set direction of the gradient: * `0` - horizontal. * `90` - vertical. * `45` - diagonal. columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0x297373)\ }, {\ color: am5.color(0x946b49)\ }\], rotation: 90 })); columnSeries.columns.template.set("fillGradient", am5.LinearGradient.new(root, { stops: \[{\ color: am5.color(0x297373),\ offset: 0.7\ }, {\ color: am5.color(0x946b49)\ }\], rotation: 90 })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/horizontal_gradient.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/horizontal_gradient.png) `rotation: 0` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/vertical_gradient.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/vertical_gradient.png) `rotation: 90` Examples -------- ### Radial 3D effect We can use 5-step gradient with just `brighten` values, to produce a 3D "shine" effect on a pie series: pieSeries.slices.template.set("fillGradient", am5.RadialGradient.new(root, { stops: \[{\ brighten: -0.8\ }, {\ brighten: -0.8\ }, {\ brighten: -0.5\ }, {\ brighten: 0\ }, {\ brighten: -0.5\ }\] })); pieSeries.slices.template.set("fillGradient", am5.RadialGradient.new(root, { stops: \[{\ brighten: -0.8\ }, {\ brighten: -0.8\ }, {\ brighten: -0.5\ }, {\ brighten: 0\ }, {\ brighten: -0.5\ }\] })); See the Pen Pie chart with inner radius (donut) by amCharts team (@amcharts) on CodePen. --- # Shadows – amCharts 5 Documentation This tutorial looks at how we can add shadows to graphic elements. Enabling -------- Shadows can be enabled on any `Graphics`, `Picture`, and `Label` elements. To do that, we need to set shadow-related settings: | Setting key | Comment | | --- | --- | | `shadowColor` | Shadow color. | | `shadowBlur` | Blurriness of the shadow.
The bigger the number, the blurrier and wider shadow will be.
`0` will mean completely sharp shadow, ideally replicating lines of the target element. | | `shadowOffsetX` | Horizontal offset in pixels. Can accept negative number to move it left. | | `shadowOffsetY` | Vertical offset in pixels. Can accept negative number to move it up. | | `shadowOpacity` | Opacity of the shadow. If not set, will use elements `fillOpacity`. | For shadow to work `shadowColor` and at least one of the `shadowBlur`, `shadowOffsetX`, and/or `shadowOffsetY` needs to be set. Examples -------- ### Standalone objects The following will add shadow to the chart's plot container using its background element: chart.plotContainer.get("background").setAll({ shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); chart.plotContainer.get("background").setAll({ shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); ### Column series series.columns.template.setAll({ strokeOpacity: 0, shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); series.columns.template.setAll({ strokeOpacity: 0, shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); See the Pen Column series with shadows by amCharts team (@amcharts) on CodePen. ### Line series and bullets series.strokes.template.setAll({ strokeWidth: 2, shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 10, shadowOpacity: 0.5 }); series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill"), shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 10, shadowOpacity: 0.3 }) }) }); series.strokes.template.setAll({ strokeWidth: 2, shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 10, shadowOpacity: 0.5 }); series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill"), shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 10, shadowOpacity: 0.3 }) }) }); See the Pen Smoothed line series by amCharts team (@amcharts) on CodePen. ### Tooltips We can enable shadows on tooltips using specific tooltip's settings: series.get("tooltip").get("background").setAll({ shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); series.get("tooltip").get("background").setAll({ shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); Or, we can use default theme to apply tooltip to all tooltips: // Add shadow to all tooltips... root.defaultTheme.rule("PointedRectangle", \["tooltip", "background"\]).setAll({ shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); // ... except axis root.defaultTheme.rule("PointedRectangle", \["tooltip", "background", "axis"\]).setAll({ shadowColor: null }); // Add shadow to all tooltips... root.defaultTheme.rule("PointedRectangle", \["tooltip", "background"\]).setAll({ shadowColor: am5.color(0x000000), shadowBlur: 10, shadowOffsetX: 4, shadowOffsetY: 4 }); // ... except axis root.defaultTheme.rule("PointedRectangle", \["tooltip", "background", "axis"\]).setAll({ shadowColor: null }); See the Pen amCharts 5: Consolidated tooltip by amCharts team (@amcharts) on CodePen. --- # Legend – amCharts 5 Documentation Legend is a universal control that can be used on virtually any chart type, fed by series or other sources. This tutorial will cover common techniques of using a legend. Adding ------ We create a legend just like any other visual element: by calling its class' `new()` method and pushing it to some sore of container, most commonly a chart: let legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); var legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); Legend data ----------- As per code snipped above, legend data is set via its `data` property. It has a number of methods to add single or a few data items at once. For more information, refer to the "[Data](https://www.amcharts.com/docs/v5/concepts/data/) " tutorial. Now, let's take a look at two types of data we can set on legend. ### Data item list The most common and convenient way is to pass in an array of `[DataItem](https://www.amcharts.com/docs/v5/reference/dataitem/) ` objects. The good news is that most things that may be represented by legend already have such list readily available. For example, chart's `series` property is a list, which has `values` property, which is an array of data items representing each series. We can use that to automatically feed the legend: legend.data.setAll(chart.series.values); legend.data.setAll(chart.series.values); Or, if we would like each data item in series to have its own legend item, we can use series' `dataItems` property, which too is an array of data items: legend.data.setAll(series.dataItems); legend.data.setAll(series.dataItems); Please note, that non-standard setups might need a little extra configuration. For example if we would try to use column series' data items as data for the legend, we would need to specify which data field holds the name to use in legend: let legend = chart.children.push(am5.Legend.new(root, { nameField: "categoryX" })); legend.data.setAll(series.dataItems); var legend = chart.children.push(am5.Legend.new(root, { nameField: "categoryX" })); legend.data.setAll(series.dataItems); Here's an example of legend feed its items from actual columns in a column series: See the Pen Stacked column chart by amCharts team (@amcharts) on CodePen. NOTE Not all series types support passing in their data items as data for the legend. For example, `LineSeries` does not have notion of fill for each individual data item, so it won't work for legend. For a more advanced version of the above demo (with hover support), check out "[Individual legend item for each column in series](https://www.amcharts.com/docs/v5/tutorials/individual-legend-item-for-each-column-in-series/) ". ### Standalone data Another option to supply data to legend is via plain array of objects, e.g.: let legend = chart.children.push(am5.Legend.new(root, { nameField: "name", fillField: "color", strokeField: "color", centerX: am5.percent(50), x: am5.percent(50) })); legend.data.setAll(\[{\ name: "Under budget",\ color: am5.color(0x297373)\ }, {\ name: "Over budget",\ color: am5.color(0xff621f)\ }\]); var legend = chart.children.push(am5.Legend.new(root, { nameField: "name", fillField: "color", strokeField: "color", centerX: am5.percent(50), x: am5.percent(50) })); legend.data.setAll(\[{\ name: "Under budget",\ color: am5.color(0x297373)\ }, {\ name: "Over budget",\ color: am5.color(0xff621f)\ }\]); Since we are supplying completely custom data, we will need to specify which keys in data hold item name and colors using `nameField`, `fillField`, and `strokeField` respectively. See the Pen Legend with column series data items by amCharts team (@amcharts) on CodePen. Positioning ----------- Legend does not have any specific position setting. Where it is placed is determined by the `layout` setting of parent container. In most chart setups, legend container will be chart itself. By default, chart does not have any layout, so pushing a legend will just plop it on the top. It will also not affect size of the plot itself. If we need to arrange chart and legend neatly, in a non-overlapping, orderly way, we need to add a `layout` setting to the chart. let chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalLayout }) ); let legend = chart.children.push(am5.Legend.new(root, {})); var chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalLayout }) ); var legend = chart.children.push(am5.Legend.new(root, {})); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_bottom-1024x590.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_bottom.png) `layout: root.verticalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_right-1024x590.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_right.png) `layout: root.horizontalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_unpositioned-1024x590.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_unpositioned.png) `layout` not set The legend appears on the bottom (or right) because it's the last element we've added to the chart. If we'd like the legend to appear on top (or left), we'd need to ensure it's the first child of the chart by using `children.unshift()` method instead of `push()`. let chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalLayout }) ); let legend = chart.children.unshift(am5.Legend.new(root, {})); var chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalLayout }) ); var legend = chart.children.unshift(am5.Legend.new(root, {})); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_top-1024x590.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_top.png) `layout: root.verticalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_left-1024x590.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_left.png) `layout: root.horizontalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_unpositioned-1024x590.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_unpositioned.png) `layout` not set MORE INFO For more information about layouts, visit our "[Containers: Layout](https://www.amcharts.com/docs/v5/concepts/containers/#Layout) " tutorial. Aligning -------- We can also fine-tune legend's position by specifying `x` and/or `y` values as well as using `centerX` and `centerY` settings to indicate what should be considered the center of the legend. The following will align the legend vertically to the middle of the chart: let legend = chart.children.push(am5.Legend.new(root, { y: am5.percent(50), centerY: am5.percent(50) })); legend = chart.children.push(am5.Legend.new(root, { y: am5.percent(50), centerY: am5.percent(50) })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_top_align.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_top_align.png) `y: am5.percent(0)` `centerY: am5.percent(0)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_bottom_align.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_bottom_align.png) `y: am5.percent(50)` `centerY: am5.percent(50)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_center_align.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_center_align.png) `y: am5.percent(100)` `centerY: am5.percent(100)` Layout ------ ### Setting layout Legend's items can be arranged horizontally, vertically, or as a grid (default). Just like with any container, e.g. chart, it is controlled by the `layout` setting. In legend, it's set to `root.gridLayout` by default, which means that legend items are arranged horizontally in rows, wrapping to new lines when they don't fit, as well as aligned into columns. let legend = chart.children.push(am5.Legend.new(root, { x: am5.percent(50), centerX: am5.percent(50), layout: root.verticalLayout })); legend = chart.children.push(am5.Legend.new(root, { x: am5.percent(50), centerX: am5.percent(50), layout: root.verticalLayout })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_grid_layout.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_grid_layout.png) `layout: root.gridLayout` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_horizontal_layout.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_horizontal_layout.png) `layout: root.horizontalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_vertical_layout.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_vertical_layout.png) `layout: root.verticalLayout` Obviously, when choosing layout, we need to think of the place the legend will appear in, as well as a number of potential items in it. MORE INFO For more information about layouts, visit our "[Containers: Layout](https://www.amcharts.com/docs/v5/concepts/containers/#Layout) " tutorial. ### Grid layout Grid layout can also be tweaked with a couple of settings of its own: * `maxColumns` - maximum number of columns to allow in the grid. * `fixedWidthGrid` - if set to `true` will make all columns equal in width, as opposed to best fit. Since we don't want to modify a global instance of the grid layout (it may be used by other chart elements), we will need to create a unique instance of `GridLayout` specifically for the legend: let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: am5.GridLayout.new(root, { maxColumns: 3, fixedWidthGrid: true }) })); var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: am5.GridLayout.new(root, { maxColumns: 3, fixedWidthGrid: true }) })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_grid_layout.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_grid_layout.png) `fixedWidthGrid: false` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_fixedwidthcolumns.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_fixedwidthcolumns.png) `fixedWidthGrid: true` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_maxcolumns_2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/legend_maxcolumns_2.png) `maxColumns: 2` See the Pen Pie chart legend alignment by amCharts team (@amcharts) on CodePen. MORE INFO For more information about grid layout, visit our "[Containers: Grid](https://www.amcharts.com/docs/v5/concepts/containers/#Layout) " tutorial. Markers ------- There are a few ways a legend can build its markers: * Markers that resemble actual look of the item, e.g. series. * Default square markers. * Completely custom markers. ### Marker size Markers are 18 x18 pixels by default. We can change that using `markers.template`: legend.markers.template.setAll({ width: 24, height: 24 }); legend.markers.template.setAll({ width: 24, height: 24 }); Note that marker template is just a container but not actual element, so there's not much we can do here besides the size, and some other settings like padding. ### Look-resembling markers By default legend will try to build a marker that resembles its items, e.g. series. For example, marker for line series will look like line with the same color. Since the markers are build by each target, e.g. series, and can contain a number of elements, there's little we can do about configuring the look for those. ### Default markers If we want to have more control on look of the markers, we can enable default markers by setting legend's setting `[useDefaultMarker](https://www.amcharts.com/docs/v5/reference/legend/#useDefaultMarker_setting) ` to `true`. let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), useDefaultMarker: true })); var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), useDefaultMarker: true })); Now the legend will create its own markers for each item, using `RoundedRectangle` elements. We can configure those rectangles using `markerRectangles.template`. It accepts all [`RoundedRectangle` settings](https://www.amcharts.com/docs/v5/reference/roundedrectangle/#Settings) . legend.markerRectangles.template.setAll({ cornerRadiusTL: 10, cornerRadiusTR: 10, cornerRadiusBL: 10, cornerRadiusBR: 10 }); legend.markerRectangles.template.setAll({ cornerRadiusTL: 10, cornerRadiusTR: 10, cornerRadiusBL: 10, cornerRadiusBR: 10 }); The above will make all legend markers round: See the Pen Pie chart legend alignment by amCharts team (@amcharts) on CodePen. NOTE Some series like pie, column, and similar do not have their own custom look of the marker and will use default markers regardless of the `useDefaultMarker` setting. ### Images as markers Markers can also be completely customized. After we insert an item into legend's data, it creates a related data item and all the marker elements - such as rectangles. We can grab that data item, use it to access visual elements, then modify them. The following code will remove built-in marker elements and will replace them with an image. let legendDataItem = legend.dataItems\[legend.dataItems.length - 1\]; let marker = legendDataItem.get("marker") marker.children.push(am5.Picture.new(root, { width: 20, height: 20, src: "/myImage.svg" })); legendDataItem.get("markerRectangle").set("forceHidden", true); var legendDataItem = legend.dataItems\[legend.dataItems.length - 1\]; var marker = legendDataItem.get("marker") marker.children.push(am5.Picture.new(root, { width: 20, height: 20, src: "/myImage.svg" })); legendDataItem.get("markerRectangle").set("forceHidden", true); See the Pen Images as legend markers by amCharts team (@amcharts) on CodePen. Another way to modify legend markers is to use template's [setup function](https://www.amcharts.com/docs/v5/concepts/settings/list-templates/#Setup_handler) . Same result, different approach. legend.markers.template.setup = function(marker) { marker.events.on("dataitemchanged", function() { let dataItem = marker.\_dataItem let series = dataItem.dataContext; marker.children.push(am5.Picture.new(root, { width: 20, height: 20, src: "https://www.amcharts.com/wp-content/uploads/flags/" + series.get("name").toLowerCase() + ".svg" })); dataItem.on("markerRectangle", function(rectangle) { rectangle.set("forceHidden", true); }) }); }; legend.markers.template.setup = function(marker) { marker.events.on("dataitemchanged", function() { var dataItem = marker.\_dataItem var series = dataItem.dataContext; marker.children.push(am5.Picture.new(root, { width: 20, height: 20, src: "https://www.amcharts.com/wp-content/uploads/flags/" + series.get("name").toLowerCase() + ".svg" })); dataItem.on("markerRectangle", function(rectangle) { rectangle.set("forceHidden", true); }) }); }; See the Pen Images as legend markers by amCharts team (@amcharts) on CodePen. Labels ------ ### Configuring labels Legend has two properties related to labels: `labels` and `valueLabels`. One contains all instances of name labels, the other - value labels. Both are "list templates", meaning that we can use their `template` property to specify any setting for those labels. `template` accepts any [`Label` setting](https://www.amcharts.com/docs/v5/reference/label/#Settings) . legend.labels.template.setAll({ fontSize: 16, fontWeight: "300" }); legend.valueLabels.template.setAll({ fontSize: 16, fontWeight: "400" }); legend.labels.template.setAll({ fontSize: 16, fontWeight: "300" }); legend.valueLabels.template.setAll({ fontSize: 16, fontWeight: "400" }); ### Disabling value labels Legend comes with both labels and value labels, with space reserved for both of them. If you are not using the latter, you might consider disabling them, so that the legend becomes more compact, possibly freeing up more space for the chart itself. legend.valueLabels.template.set("forceHidden", true); legend.valueLabels.template.set("forceHidden", true); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/07/legend_with_valuelabels.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/07/legend_with_valuelabels.png) Value labels enabled (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/07/legend_without_valuelabels.png.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/07/legend_without_valuelabels.png.png) Value labels disabled ### Dynamic label content In most charts legend's labels will be populated by its series. The content of labels will depend on whether legend is displaying list of series, or series data items, and how those series are set up. For series-specific configuration options refer to these tutorials: * [Legend and XY series](https://www.amcharts.com/docs/v5/charts/xy-chart/legend-xy-series/) . * [Legend and Pie/Sliced series](https://www.amcharts.com/docs/v5/charts/percent-charts/legend-percent-series/) . * [Legend and Hierarchy series](https://www.amcharts.com/docs/v5/charts/hierarchy/legend-hierarchy-series/) . Altering functionality ---------------------- ### Disabling toggling Legend items are togglable by default. To disable toggling, we need to set legend's `clickTarget` setting to `"none"`: let legend = chart.children.push(am5.Legend.new(root, { y: am5.percent(50), centerY: am5.percent(50), clickTarget: "none" })); var legend = chart.children.push(am5.Legend.new(root, { y: am5.percent(50), centerY: am5.percent(50), clickTarget: "none" })); See the Pen amCharts 5: Spectrum chart by amCharts team (@amcharts) on CodePen. ### Disabling hovers To disable just hover effects, like when hovering on legend item triggers hover on a related object, like a slice of a pie chart, we will need to explicitly disable `pointerover` event of all created items. legend.itemContainers.template.setup = function(item) { item.events.disableType("pointerover") }; legend.itemContainers.template.setup = function(item) { item.events.disableType("pointerover") }; See the Pen Disabling hovers in PieChart legend by amCharts team (@amcharts) on CodePen. ### Disabling graying out To disable graying out of legend items when they are toggled off, simply disable propagation of a `disabled` state on item containers: legend.itemContainers.template.set("setStateOnChildren", false); legend.itemContainers.template.set("setStateOnChildren", false); Scrollable legend ----------------- If legend's contents do not fit into its height, we can enable scrolling by setting its `verticalScrollbar` instance of a `Scrollbar`: var legend = chart.children.push(am5.Legend.new(root, { centerY: am5.percent(50), y: am5.percent(50), layout: root.verticalLayout, height: am5.percent(100), verticalScrollbar: am5.Scrollbar.new(root, { orientation: "vertical" }) })); var legend = chart.children.push(am5.Legend.new(root, { centerY: am5.percent(50), y: am5.percent(50), layout: root.verticalLayout, height: am5.percent(100), verticalScrollbar: am5.Scrollbar.new(root, { orientation: "vertical" }) })); NOTE Please note that `height` needs to be set for this to work properly. See the Pen Pie chart legend alignment by amCharts team (@amcharts) on CodePen. External container ------------------ ### Separate Root element Creating a legend in an external container is as easy as creating another root element, then pushing legend into its children: let legendRoot = am5.Root.new("legenddiv"); let legend = legendRoot.container.children.push( am5.Legend.new(legendRoot, { width: am5.percent(100), centerX: am5.percent(50), x: am5.percent(50), layout: legendRoot.grid }) ); legend.data.setAll(series.dataItems); var legendRoot = am5.Root.new("legenddiv"); var legend = legendRoot.container.children.push( am5.Legend.new(legendRoot, { width: am5.percent(100), centerX: am5.percent(50), x: am5.percent(50), layout: legendRoot.grid }) ); legend.data.setAll(series.dataItems); See the Pen Pie chart with scrollable legend by amCharts team (@amcharts) on CodePen. NOTEFor information on how to include external legend when exporting chart to an image, refer to "Exporting to image formats: [Combining multiple images](https://www.amcharts.com/docs/v5/concepts/exporting/exporting-images/#Combining_multiple_images) " tutorial. ### External legend on XY charts NOTEIf you are using external legend on an XY chart, make sure you apply XY [default theme](https://www.amcharts.com/docs/v5/concepts/themes/#default-themes) to the legend's root element as well as use proper `root` element reference for XY series bullets. let legendRoot = am5.Root.new("legenddiv"); legendRoot.setThemes(\[\ am5themes\_Animated.new(legendRoot),\ am5xy.DefaultTheme.new(legendRoot)\ \]); var legendRoot = am5.Root.new("legenddiv"); legendRoot.setThemes(\[\ am5themes\_Animated.new(legendRoot),\ am5xy.DefaultTheme.new(legendRoot)\ \]); ### Sizing external legend container If we'd like our external legend to auto-size according to its actual contents, we could use its `boundschanged` event: legend.events.on("boundschanged", function() { document.getElementById("legenddiv").style.height = legend.height() + "px" }); legend.events.on("boundschanged", function() { document.getElementById("legenddiv").style.height = legend.height() + "px" }); See the Pen Pie chart with external legend by amCharts team (@amcharts) on CodePen. And here's another example which creates a horizontally-scrollable external legend: See the Pen Pie chart with external horizontally-scrollable legend by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Right-to-left legend](https://www.amcharts.com/docs/v5/concepts/locales/right-to-left-support/#legend) * [Adding check marks to legend markers](https://www.amcharts.com/docs/v5/tutorials/adding-check-marks-to-legend-markers/) * [Auto-wrapping legend labels](https://www.amcharts.com/docs/v5/tutorials/auto-wrapping-legend-labels/) * [Individual legend item for each column in series](https://www.amcharts.com/docs/v5/tutorials/individual-legend-item-for-each-column-in-series/) * [Grouping legend items](https://www.amcharts.com/docs/v5/tutorials/grouping-legend-items/) * [Dynamically changing legend position](https://www.amcharts.com/docs/v5/tutorials/dynamically-changing-legend-position/) * [Aligning a legend with plot container](https://www.amcharts.com/docs/v5/tutorials/aligning-a-legend-with-plot-container/) * [Pie chart with right-aligned labels](https://www.amcharts.com/docs/v5/tutorials/pie-chart-with-right-aligned-labels/) * [Toggling all series but one using legend](https://www.amcharts.com/docs/v5/tutorials/toggling-all-series-but-one-using-legend/) * [Toggle multiple pie slices via legend](https://www.amcharts.com/docs/v5/tutorials/toggle-multiple-pie-slices-via-legend/) * [Using series color for legend labels](https://www.amcharts.com/docs/v5/tutorials/using-series-color-for-legend-labels/) * [Applying custom hover/active states on legend markers](https://www.amcharts.com/docs/v5/tutorials/applying-custom-hover-active-states-on-legend-markers/) --- # Heat legend – amCharts 5 Documentation Heat legend is a visual tool that usually compliments a chart with [heat rules](https://www.amcharts.com/docs/v5/concepts/settings/heat-rules/) . Adding ------ We can add a heat legend like a regular legend, by pushing and instance of `[HeatLegend](https://www.amcharts.com/docs/v5/reference/heatlegend/) ` into chart's children. Heat legend also requires at least two settings: `startColor` and `endColor`. Those will define colors for start (lowest value end) and end (highest value end) of the legend. let heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", endColor: am5.color(0x661f00), startColor: am5.color(0xff621f) }) ); var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", endColor: am5.color(0x661f00), startColor: am5.color(0xff621f) }) ); Orientation ----------- Heat legend can either be arranged horizontally or vertically. We can use `orientation` setting for that. It accepts either `"vertical"` or `"horizontal"`. Start/end labels ---------------- Legend will not show any labels by default. If we want some labels shown at legend's ends we can use `startText` and `endText` settings: var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", startColor: am5.color(0xff621f), endColor: am5.color(0x661f00), startText: "Lowest", endText: "Highest" }) ); var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", startColor: am5.color(0xff621f), endColor: am5.color(0x661f00), startText: "Lowest", endText: "Highest" }) ); If we'd like to configure the look of these two labels, we can use `Label` objects available in legend's `startLabel` and `endLabel` properties: heatLegend.startLabel.setAll({ fontSize: 12, fill: heatLegend.get("startColor") }); heatLegend.endLabel.setAll({ fontSize: 12, fill: heatLegend.get("endColor") }); heatLegend.startLabel.setAll({ fontSize: 12, fill: heatLegend.get("startColor") }); heatLegend.endLabel.setAll({ fontSize: 12, fill: heatLegend.get("endColor") }); Gradient or steps ----------------- Heat legend will display a gradient along itself starting at `startColor` and ending with an `endColor`. If we would rather it display incremental steps, we can set legend's `stepCount` setting. It accepts any integer value. var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", startColor: am5.color(0xff621f), endColor: am5.color(0x661f00), startText: "Lowest", endText: "Highest", stepCount: 10 }) ); var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", startColor: am5.color(0xff621f), endColor: am5.color(0x661f00), startText: "Lowest", endText: "Highest", stepCount: 10 }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/heatlegend_stepcount_1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/heatlegend_stepcount_1.png) `stepCount: 1` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/heatlegend_stepcount_5.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/heatlegend_stepcount_5.png) `stepCount: 5` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/heatlegend_stepcount_10.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/heatlegend_stepcount_10.png) `stepCount: 10` Tooltip ------- ### Setting scale In order for legend to be able to show value-sensitive tooltips, we need to assign it an actual value range using its `startValue` and `endValue` settings. var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", startColor: am5.color(0xff621f), endColor: am5.color(0x661f00), startValue: 0, endValue: 1000 }) ); var heatLegend = chart.children.push( am5.HeatLegend.new(root, { orientation: "vertical", startColor: am5.color(0xff621f), endColor: am5.color(0x661f00), startValue: 0, endValue: 1000 }) ); If we don't know extreme values, we can extract that from series, when its data is validated: series.events.on("datavalidated", function () { heatLegend.set("startValue", series.getPrivate("valueHigh")); heatLegend.set("endValue", series.getPrivate("valueLow")); }); series.events.on("datavalidated", function () { heatLegend.set("startValue", series.getPrivate("valueHigh")); heatLegend.set("endValue", series.getPrivate("valueLow")); }); ### Triggering tooltip To trigger the legend to show a tooltip at specific value, we can use its `[showValue()](https://www.amcharts.com/docs/v5/reference/heatlegend/#showValue_method) ` method. heatLegend.showValue(500); heatLegend.showValue(500); We can also specify the optional text and color of tooltip by passing them in as a second and third parameter to `showValue` respectively. heatLegend.showValue(500, "Hot!", am5.color(0xff0000)); heatLegend.showValue(500, "Hot!", am5.color(0xff0000)); We can combine this with `"over"` events on related series items to automatically trigger heat legend tooltip with their value: polygonSeries.mapPolygons.template.events.on("pointerover", function(ev) { heatLegend.showValue(ev.target.dataItem.get("value")); }); polygonSeries.mapPolygons.template.events.on("pointerover", function(ev) { heatLegend.showValue(ev.target.dataItem.get("value")); }); Examples -------- ### Map chart See the Pen Map chart heat map with heat legend by amCharts team (@amcharts) on CodePen. ### Radar chart See the Pen Radar chart with heat legend by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [A custom "heat legend" using a gradient](https://www.amcharts.com/docs/v5/tutorials/a-custom-heat-legend-using-a-gradient/) (demo) * [Heat legend with scale](https://www.amcharts.com/docs/v5/tutorials/heat-legend-with-scale/) (demo) Related class references ------------------------ * [HeatLegend](https://www.amcharts.com/docs/v5/reference/heatlegend) --- # Filters – amCharts 5 Documentation amCharts 5 allows applying various filters to its visual elements. This tutorial will explain how we use them. Compatibility ------------- IMPORTANTFilter functionality is not supported by Safari browsers - both desktop and mobile. This is not a bug, but rather a choice by Apple. Built-in filters ---------------- There's a number of settings that we can use to apply various visual effects to `Sprite` elements: | Setting | Value range | Comment | | --- | --- | --- | | `blur` | `0` to X | Applies blur effect. | | `brightness` | `0` to `1` | Modifies "brightness" of the element. | | `contrast` | `0` to `1` | Modifies contrast. | | `saturate` | `0` to X | Modifies color saturation:
`0` - grayscale, `1` - no changes, `>1` - more saturated. | | `sepia` | `0` to `1` | Applies sepia filter:
`0` (no changes) to `1` (complete sepia). | | `invert` | `0` to `1` | Inverts colors:
Range of values: `0` (no changes) to `1` (completely inverted colors). | | `hue` | `0` to `360` | Rotates HUE circle of colors. | series.slices.template.setAll({ sepia: 1, brightness: 0.5 }); series.slices.template.setAll({ sepia: 1, brightness: 0.5 }); SVG filters ----------- We can also use element's `filter` setting to set any [SVG filter](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter) . series.slices.template.setAll({ filter: "drop-shadow(16px 16px 20px blue) sepia(1)" }); series.slices.template.setAll({ filter: "drop-shadow(16px 16px 20px blue) sepia(1)" }); Example ------- See the Pen Chart with SVG filters by amCharts team (@amcharts) on CodePen. --- # Common elements – amCharts 5 Documentation Select a topic on the sub-menu on the left. --- # Bullets – amCharts 5 Documentation This tutorial will look into all aspects of using bullets on series. Creating a series bullet ------------------------ Each series has a `[bullets](https://www.amcharts.com/docs/v5/reference/series/#bullets_property) ` property, which is a `List` of functions. A function is responsible for returning a `[Bullet](https://www.amcharts.com/docs/v5/reference/bullet/) ` object. Whenever series needs to create a bullet for a specific data item, it will call the function and expect it to return a new bullet, which then be displayed on actual chart. So, creating a bullet involves pushing a custom function into series' `bullets` list: series.bullets.push(function(root) { return am5.Bullet.new(root, {}); }); series.bullets.push(function(root) { return am5.Bullet.new(root, {}); }); NOTEBullet function receives a root object instance as a first parameter. Since bullets can be created in a lot of different places (e.g. external legend), make sure that we use the passed in object to avoid any anomalies. Bullet contents --------------- Naturally, empty bullet is useless because it does not have anything to display, so we need to set its contents. To do that, `Bullet` has a setting `sprite` which can be set to literally any other element: from something as simple as a `Circle` object to another full fledged chart. series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 4, fill: series.get("fill") }) }); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 4, fill: series.get("fill") }) }); }); The above will create a bullet with a circle. Please note that bullets can be complex and will not inherit series colors automatically, hence we need to explicitly set its color to series color. See the Pen Smoothed line series by amCharts team (@amcharts) on CodePen. For an example of how to use images as bullets, refer to "[Images](https://www.amcharts.com/docs/v5/concepts/common-elements/images/#Images_as_bullets) " tutorial. Adding directly to data item ---------------------------- It is possible to create bullets one by one, by adding them directly to the actual series' data items. For that, series does have an `addBullet(dataItem, bullet)` method. It accepts two parameters: * `dataItem` - a series data item to add bullet to. * `bullet` - an instance of `Bullet`. Note that this is not a bullet-creating function, but an actual `Bullet` instance. There are three steps to the process: 1. Waiting for series to process data, i.e. its `datavalidated` event kicks in. 2. Finding series data item to add bullet to. 3. Adding the actual bullet using series method `addBullet()`. ### Waiting for data In order for data items to be available, we need to wait until series finishes processing its data. For that we'll need to watch for its `datavalidated` event kicking in. series.events.once("datavalidated", function() { // Series data ready }); series.events.once("datavalidated", function() { // Series data ready }); ### Finding the data item We will use axis' method `getSeriesItem()` to get the data item from series at specific position in axis. Before that On a `DateAxis` we will use its method `dateToPosition()` to convert specific data/time to an axis position, we can then use in `getSeriesItem()`. series.events.once("datavalidated", function() { let axisPosition = xAxis.dateToPosition(new Date(2023, 5, 12)); let seriesDataItem = xAxis.getSeriesItem(series, axisPosition, 0); // ... }); series.events.once("datavalidated", function() { var axisPosition = xAxis.dateToPosition(new Date(2023, 5, 12)); var seriesDataItem = xAxis.getSeriesItem(series, axisPosition, 0); // ... }); Similarly, on a `CategoryAxis` we will use `categoryToPosition()` to find out what the position specific category is at. series.events.once("datavalidated", function() { let axisPosition = xAxis.categoryToPosition("Research"); let seriesDataItem = xAxis.getSeriesItem(series, axisPosition, 0); // ... }); series.events.once("datavalidated", function() { var axisPosition = xAxis.categoryToPosition("Research"); var seriesDataItem = xAxis.getSeriesItem(series, axisPosition, 0); // ... }); ### Adding data item bullet Now that we know the specific data item, we can use series' `addBullet()` method to add a bullet to it. series.events.once("datavalidated", function() { let axisPosition = xAxis.categoryToPosition("Research"); let seriesDataItem = xAxis.getSeriesItem(series, axisPosition, 0); series.addBullet(seriesDataItem, am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 10, fill: am5.color(0xffffff), stroke: series.get("stroke") }); })); }); series.events.once("datavalidated", function() { var axisPosition = xAxis.categoryToPosition("Research"); var seriesDataItem = xAxis.getSeriesItem(series, axisPosition, 0); series.addBullet(seriesDataItem, am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 10, fill: am5.color(0xffffff), stroke: series.get("stroke") }); })); }); Below example adds several bullets at specific points on chart: See the Pen Adding bullets at specific dates by amCharts team (@amcharts) on CodePen. Positioning ----------- ### By relative location A `Bullet` object has two properties that help position them within the parent element/data item: `[locationX](https://www.amcharts.com/docs/v5/reference/bullet/#locationX_setting) ` and `[locationY](https://www.amcharts.com/docs/v5/reference/bullet/#locationY_setting) `. Those accept numeric values from `0` (zero) to `1` (one) indicating relative position within target element, with zero indicating beginning and one the end. Some series (e.g. line series) do not have any dimension, so location settings will be ignored. However in those series that do have elements with actual shapes (e.g. column series), location settings are super useful as it gives us flexibility over positioning of a bullet. Let's put a `Label` bullet in the middle of a column in a column series: series.bullets.push(function(root) { return am5.Bullet.new(root, { locationX: 0.5, locationY: 0.5, sprite: am5.Label.new(root, { text: "{valueY}", centerX: am5.percent(50), centerY: am5.percent(50), populateText: true }) }); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { locationX: 0.5, locationY: 0.5, sprite: am5.Label.new(root, { text: "{valueY}", centerX: am5.percent(50), centerY: am5.percent(50), populateText: true }) }); }); NOTE Please note the `populateText` use above. This is needed to force `Label` to populate data placeholders with actual data. See the Pen Line series with bullets by amCharts team (@amcharts) on CodePen. Some series are represented by a single line. For example `Chord`, `Sankey`, or `MapLineSeries`. In those cases, only `locationX` or `locationY` is used. I.e. on a horizontal Sankey diagram, `locationX` will be used, and `locationY` will be ignored altogether. ### By data field IMPORTANTPositioning bullets by data fields works only on an `XYChart`. Some XY series can have multiple values - like for instance Candlesticks have open, high, low, close. We can instruct the bullet to attach to that specific value by using bullet's `field` setting. It accepts these values: `"open"`, `"high"`, `"low"`, `"value"` (default). series.bullets.push(function(root, series) { return am5.Bullet.new(root, { field: "open", sprite: am5.Circle.new(root, { radius: 8, stroke: am5.color(0x000000), strokeWidth: 4, fill: am5.color(0xffffff) }) }); }); series.bullets.push(function(root, series) { return am5.Bullet.new(root, { field: "open", sprite: am5.Circle.new(root, { radius: 8, stroke: am5.color(0x000000), strokeWidth: 4, fill: am5.color(0xffffff) }) }); }); NOTESetting `field` makes the bullet completely ignore the `locationX` and `locationY` settings. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_open-1024x768.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_open.png) `field: "open"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_value-1024x768.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_value.png) `field: "value"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_high-1024x767.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_high.png) `field: "high"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_low-1024x768.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2023/11/bullet_dield_low.png) `field: "low"` See the Pen Positioning series bullets by data field by amCharts team (@amcharts) on CodePen. Stacked bullets --------------- Normally, bullets will be displayed at the specific location, regardless if there are any other bullets present in the same position. We can instruct them to stack instead by setting bullet's `stacked` setting. It accepts three values: * `"up"` - will stack bullets upwards. * `"down"` - will stack bullets downards. * `"auto"` - will stack bullets upwards or downwards depending on their relative vertical position in the chart. See the Pen Stacked bullets by amCharts team (@amcharts) on CodePen. Relation to data ---------------- Among other things, series will also pass relevant data item to the bullet. That's why bullets can use [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) to populate text, as well as [heat rules](https://www.amcharts.com/docs/v5/concepts/settings/heat-rules/#Bullets) . ### Data placeholders Bullets that use `Label` as their `sprite` property can have its text populated using curly bracket enclosed data placeholders. series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueY}", populateText: true }) }); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueY}", populateText: true }) }); }); The above label will be replaced by the actual Y value of the related data item. For more information on how data placeholders work, refer to "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorial. ### Heat rules Bullets can also benefit from heat rules. For example circle bullet can have its radius assigned dynamically, according to range of values in the series. For more information and examples, visit "Heat rules: [Bullets](https://www.amcharts.com/docs/v5/concepts/settings/heat-rules/#bullets) ". ### Template fields Template fields are way to override some settings for a series item, such as a bullet, via data. It works by specifying `templateField` setting on an object, which should point to a key in data that holds that element's settings we want to override. For an in-depth explanation how this works, refer to "[Template fields](https://www.amcharts.com/docs/v5/concepts/settings/template-fields/) " tutorial. That said, there are some caveats when using template fields with a bullet. The main one is that bullets are different from any other series object in that they are not created via template, but rather by custom function as a new element. This means that settings supplied during its creations will take precedence over ones that would be inherited via a template field. The below code **will not function correctly**: series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, // ERROR: // "fill" set directly on a new element will take precedence over one pulled in via templateField fill: am5.color(0xff0000), templateField: "bulletSettings" }) }); }); series.data.setAll(\[{\ category: "C1",\ value: 100,\ bulletSettings: {\ fill: am5.color(0x00ff00)\ }\ }, {\ category: "C2",\ value: 200,\ bulletSettings: {\ fill: am5.color(0x0000ff)\ }\ }\]); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, // ERROR: // "fill" set directly on a new element will take precedence over one pulled in via templateField fill: am5.color(0xff0000), templateField: "bulletSettings" }) }); }); series.data.setAll(\[{\ category: "C1",\ value: 100,\ bulletSettings: {\ fill: am5.color(0x00ff00)\ }\ }, {\ category: "C2",\ value: 200,\ bulletSettings: {\ fill: am5.color(0x0000ff)\ }\ }\]); The correct workaround is to use a separate template to set bullet's "default" settings, and pass it in as a third parameter to its `new()` method. The following code **will function correctly**: let bulletTemplate = am5.Template.new({ // This will be default fill for bullets that do not have // it set via templateField fill: am5.color(0xE6E6E6) }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, templateField: "bulletSettings" }, bulletTemplate) }); }); series.data.setAll(\[{\ category: "C1",\ value: 100,\ bulletSettings: {\ fill: am5.color(0x00ff00)\ }\ }, {\ category: "C2",\ value: 200,\ bulletSettings: {\ fill: am5.color(0x0000ff)\ }\ }\]); var bulletTemplate = am5.Template.new({ // This will be default fill for bullets that do not have // it set via templateField fill: am5.color(0xE6E6E6) }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, templateField: "bulletSettings" }, bulletTemplate) }); }); series.data.setAll(\[{\ category: "C1",\ value: 100,\ bulletSettings: {\ fill: am5.color(0x00ff00)\ }\ }, {\ category: "C2",\ value: 200,\ bulletSettings: {\ fill: am5.color(0x0000ff)\ }\ }\]); See the Pen Using templateField with bullets by amCharts team (@amcharts) on CodePen. Selectively displaying bullets ------------------------------ The function that returns a bullet, can also return nothing. If this happens, the bullet is not displayed. This allows us to include our own logic into bullet function to display bullets only in places where we want them. The following code will only show bullets if data for the data item contains `showBullets: true`: series.bullets.push(function(root, series, dataItem) { if (dataItem.dataContext.showBullets == true) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 7, fill: series.get("fill") }) }); } }); series.bullets.push(function(root, series, dataItem) { if (dataItem.dataContext.showBullets == true) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 7, fill: series.get("fill") }) }); } }); The demo below uses this approach to display a dot and a label on the last data item of the line series: See the Pen Using templateField with bullets by amCharts team (@amcharts) on CodePen. Multiple bullets ---------------- Series can contain any number of bullets. Each function pushed into `bullets` will create a separate bullet for each data item. series.bullets.push(function(root) { return am5.Bullet.new(root, { locationX: 0.5, locationY: 0.5, sprite: am5.Circle.new(root, { radius: 15, fill: am5.color(0xffffff) }) }); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { locationX: 0.5, locationY: 0.5, sprite: am5.Label.new(root, { text: "{valueY}", centerX: am5.percent(50), centerY: am5.percent(50), populateText: true }) }); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { locationX: 0.5, locationY: 0.5, sprite: am5.Circle.new(root, { radius: 15, fill: am5.color(0xffffff) }) }); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { locationX: 0.5, locationY: 0.5, sprite: am5.Label.new(root, { text: "{valueY}", centerX: am5.percent(50), centerY: am5.percent(50), populateText: true }) }); }); See the Pen Column series with label bullets by amCharts team (@amcharts) on CodePen. Auto-hiding bullets ------------------- We can set up series to automatically hide its bullets if there are a lot of data points and bullets would just overcrowd the chart. For that purpose, XY chart series has a setting `minBulletDistance`. It's a numeric value which means this: if the distance between data items in series is less than X pixels, hide all bullets. This setting is dynamic, and will react to changing conditions. I.e. when chart is zoomed in and distances between data items increase, hidden bullets may reappear. Bullet masking -------------- Normally, bullets are constrained to the plot area of the chart. If some bullet or part of it goes outside, it's clipped. To disable such clipping, set `maskBullets` to `false` in your series settings: let series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", maskBullets: false })); var series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", maskBullets: false })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/masked_bullets.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/masked_bullets.png) `maskBullets: true` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/unmasked_bullets.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/unmasked_bullets.png) `maskBullets: false` See the Pen Column series with multiple bullets by amCharts team (@amcharts) on CodePen. MORE INFOFor more information on how to work around bullet masking and related issues, refer to "[Handling bullet masking](https://www.amcharts.com/docs/v5/tutorials/handling-bullet-masking/) " tutorial. Event handlers -------------- ### Adding events There is a couple of ways to attach event handlers to bullets: * Creating a standalone template, adding event handlers to it, then using that template to create bullet sprite element. * Attaching events to each sprite element in bullet function. The following snippet adds a `click` event to a bullet using template: let bulletTemplate = am5.Template.new({}); bulletTemplate.events.on("click", function(ev) { console.log("Clicked on a bullet!", ev.target); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill") }, bulletTemplate) }); }); var bulletTemplate = am5.Template.new({}); bulletTemplate.events.on("click", function(ev) { console.log("Clicked on a bullet!", ev.target); }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill") }, bulletTemplate) }); }); And below is the snippet that will achieve the same behavior, albeit by attaching an event to each new bullet being created: series.bullets.push(function(root) { const circle = am5.Circle.new(root, { radius: 5, fill: series.get("fill") }); circle.events.on("click", function(ev) { console.log("Clicked on a bullet!", ev.target); }); return am5.Bullet.new(root, { sprite: circle }); }); series.bullets.push(function(root) { var circle = am5.Circle.new(root, { radius: 5, fill: series.get("fill") }); circle.events.on("click", function(ev) { console.log("Clicked on a bullet!", ev.target); }); return am5.Bullet.new(root, { sprite: circle }); }); See the Pen Line series with bullets by amCharts team (@amcharts) on CodePen. ### Events on series bullets A series bullet event handler will contain all the information about target data item and series: let bulletTemplate = am5.Template.new({}); bulletTemplate.events.on("click", function(ev) { // Bullet id console.log("Clicked on a column", ev.target.uid); // Data item console.log(ev.target.dataItem); // Original data object console.log(ev.target.dataItem.dataContext); // Series console.log(ev.target.dataItem.component) }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill") }, bulletTemplate) }); }); var bulletTemplate = am5.Template.new({}); bulletTemplate.events.on("click", function(ev) { // Bullet id console.log("Clicked on a column", ev.target.uid); // Data item console.log(ev.target.dataItem); // Original data object console.log(ev.target.dataItem.dataContext); // Series console.log(ev.target.dataItem.component) }); series.bullets.push(function(root) { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill") }, bulletTemplate) }); }); Removing series bullets ----------------------- There are two steps to completely remove bullets from series: * Clear series' `bulletsContainer`. * Clear series' `bullets` list. series.bulletsContainer.children.clear(); series.bullets.clear(); series.bulletsContainer.children.clear(); series.bullets.clear(); Related tutorials ----------------- * [Axis range bullets](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/#Bullet) * [Hide or relocate label bullets for small columns](https://www.amcharts.com/docs/v5/tutorials/hide-or-relocate-label-bullets-for-small-columns/) * [Triggering bullet hover with an XY cursor](https://www.amcharts.com/docs/v5/tutorials/triggering-bullet-hover-with-an-xy-cursor/) * [Totals on column stacks](https://www.amcharts.com/docs/v5/tutorials/totals-on-column-stacks/) * [Totals on clustered column stacks](https://www.amcharts.com/docs/v5/tutorials/totals-on-clustered-column-stacks/) * [Handling bullet masking](https://www.amcharts.com/docs/v5/tutorials/handling-bullet-masking/) * [Different bullet styling of grouped data items](https://www.amcharts.com/docs/v5/tutorials/different-bullet-styling-of-grouped-data-items/) * [Solving overlapping bullets](https://www.amcharts.com/docs/v5/tutorials/solving-overlapping-bullets/) * [Complex bullets with hover effect](https://www.amcharts.com/docs/v5/tutorials/complex-bullets-with-hover-effect/) * [Column labels as categories](https://www.amcharts.com/docs/v5/tutorials/column-labels-as-categories/) * [Map with custom markers and data-bound colors](https://www.amcharts.com/docs/v5/tutorials/map-with-custom-markers-and-data-bound-colors/) --- # Colors, gradients, and patterns – amCharts 5 Documentation Colors ------ Colors in amCharts 5 are represented by a `[Color](https://www.amcharts.com/docs/v5/reference/color/) ` object. `Color` class also has a bunch of static [methods](https://www.amcharts.com/docs/v5/reference/color/#Methods) that can be used to convert hex numbers or RGB color identifiers into proper `Color` objects, but the most common method is to use a standalone `am5.color()` function which can convert any number or string into a `Color` object: series.set("fill", am5.color(0xff0000)); // set Series color to red series2.set("fill", am5.color("#00ff00")); // set Series color to green series.set("fill", am5.color(0xff0000)); // set Series color to red series2.set("fill", am5.color("#00ff00")); // set Series color to green Wherever you need to specify a color in amCharts 5 you need to pass in a `Color` object. Typical settings to use colors for is `fill` which indicates area fill color, and `stroke` which indicates line or border (outline) color of the visual elements. Text color is specified via its `fill` setting. Color sets ---------- Colors sets are basically collections of colors with ability to generate new colors according to certain rules as needed. In most scenarios, a chart would grab next color from the color set using its `[next()](https://www.amcharts.com/docs/v5/reference/colorset/#next_method) ` method. Color set has internal counter, so it will produce new color every time. ### Setting own list of colors A color set comes with a pre-defined list of colors, depending on the [theme](https://www.amcharts.com/docs/v5/concepts/themes/) we are using (if any). There is a number of ways to override the list as needed. The most easiest way is to simply set its `colors` setting to an array of `Color` objects: chart.get("colors").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); chart.get("colors").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); Another option is to [modify default theme](https://www.amcharts.com/docs/v5/concepts/themes/#Modifying_default_theme) : root.defaultTheme.rule("ColorSet").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); root.defaultTheme.rule("ColorSet").set("colors", \[\ am5.color(0x095256),\ am5.color(0x087f8c),\ am5.color(0x5aaa95),\ am5.color(0x86a873),\ am5.color(0xbb9f06)\ \]); Obviously, creating own [custom theme](https://www.amcharts.com/docs/v5/concepts/themes/creating-themes/) is also an option. NOTESome chart types (e.g. pie chart) use `colors` setting on its series, rather than chart itself. In those cases you would need to use `series.get("colors")` to modify color list. Interface colors ---------------- Each root element in amCharts 5 has a special version of a color set: `interfaceColors`. Unlike a regular color set, it defines colors for specific purposes, rather than plain list of colors. For example, it defines background, text, grid, and similar colors, that are used throughout chart elements and controls. To get a color for a specific purpose, we use its `get()` method. ### List of purposes | Setting (purpose) | Default | Comment | | --- | --- | --- | | `stroke` | 0xe5e5e5 | Used for all line elements and outlines. | | `fill` | 0xf3f3f3 | Used for element fills. | | `primaryButton` | 0x6794dc | Primary button background color (e.g. zoom out button). | | `primaryButtonHover` | 0x6771dc | Primary button background when hovered. | | `primaryButtonDown` | 0x68dc76 | Primary button background when pressed. | | `primaryButtonActive` | 0x68dc76 | Primary button background when active. | | `primaryButtonText` | 0xffffff | Primary button text color. | | `primaryButtonStroke` | 0xffffff | Primary button border/outline color. | | `secondaryButton` | 0xd9d9d9 | Secondary button background color (e.g. scrollbar grip). | | `secondaryButtonHover` | 0xa3a3a3 | Secondary button background when hovered. | | `secondaryButtonDown` | 0x8d8d8d | Secondary button background when pressed. | | `secondaryButtonActive` | 0xe6e6e6 | Secondary button background when active. | | `secondaryButtonText` | 0x000000 | Secondary button text color. | | `secondaryButtonStroke` | 0xffffff | Secondary button border/outline color. | | `grid` | 0x000000 | Axis grid color. Also used for some other elements like, ticks, hierarchy links, etc. | | `background` | 0xffffff | Background color. | | `alternativeBackground` | 0x000000 | Alternative background. Used for chart cursor's lines, axis fills, clock hands. | | `text` | 0x000000 | Default color text. | | `alternativeText` | 0xffffff | Alternative color text. | | `disabled` | 0xadadad | Fill color for disabled elements. | | `positive` | 0x50b300 | Color to express positive value (e.g. in candlesticks). | | `negative` | 0xb30000 | Color to express negative value (e.g. in candlesticks). | NOTEDefault colors may be overridden by [themes](https://www.amcharts.com/docs/v5/concepts/themes/) . ### Using interface colors To grab a color meant for specific use, we can use `get()` method: xAxis.get("renderer").labels.template.setAll({ fill: root.interfaceColors.get("alternativeText") }); xAxis.setAll({ background: am5.Rectangle.new(root, { fill: root.interfaceColors.get("alternativeBackground"), fillOpacity: 0.7 }) }); xAxis.get("renderer").labels.template.setAll({ fill: root.interfaceColors.get("alternativeText") }); xAxis.setAll({ background: am5.Rectangle.new(root, { fill: root.interfaceColors.get("alternativeBackground"), fillOpacity: 0.7 }) }); The above will use `alternativeText` (default: white) for X axis labels, as well as add `alternativeBackground` (default: black) to the whole axis. Now, if we would also enable "Dark" theme, the labels would become black, and axis fill white, because it flips values of the `alternativeText` and `text` as well as `alternativeBackground` and `background`. ### Changing interface colors We can also modify interface colors, using `set()` method: root.interfaceColors.set("grid", am5.color(0xff0000)); root.interfaceColors.set("grid", am5.color(0xff0000)); The above will make all grid lines (as well as some other elements that use `grid` color) to be red. See the Pen Using interface colors by amCharts team (@amcharts) on CodePen. Dashed lines ------------ To make a line (stroke) dashed, we can use element's `[strokeDasharray](https://www.amcharts.com/docs/v5/reference/graphics/#strokeDasharray_setting) ` setting. It needs to be set to an array of numbers, that define dash pattern. If it's just a single number, it will define a length of the dash and the length of the gap between them. If there are two numbers, the first one will define length of the dash, and the second one length of the gap. There can be multiple numbers to create more intricate patterns. series.strokes.template.setAll({ strokeWidth: 3, strokeDasharray: \[10, 5, 2, 5\] }); series.strokes.template.setAll({ strokeWidth: 3, strokeDasharray: \[10, 5, 2, 5\] }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/strokedasharray_2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/strokedasharray_2.png) `strokeDasharray: [10]` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/strokedasharray_1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/strokedasharray_1.png) `strokeDasharray: [10, 5]` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/strokedasharray_3.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/strokedasharray_3.png) `strokeDasharray: [10, 5, 2, 5]` Gradients --------- For information on how to create gradients for fills and strokes, refer to "[Gradients](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/gradients/) " tutorial. Patterns -------- For information on how to create patterned fills and strokes, refer to "[Patterns](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/patterns/) " tutorial. Shadows ------- For information on how to enable shadows on graphic elements, refer to "[Shadows](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/shadows/) " tutorial. Filters ------- For information on how to apply various filters on graphic elements, refer to "[Filters](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/filters/) " tutorial. --- # Patterns – amCharts 5 Documentation This tutorial looks at how we can create patterns to use for element fills ant outlines. To apply a pattern to an element, we need to do two things: * Create a pattern object. * Assign it to element's `fillPattern` and/or `strokePattern`. Creating a pattern ------------------ Pattern object is created using its `new()` method: am5.LinePattern.new(root, { color: am5.color(0xffffff), rotation: 45, width: 200, height: 200 }); am5.LinePattern.new(root, { color: am5.color(0xffffff), rotation: 45, width: 200, height: 200 }); Basic pattern types ------------------- | Pattern class | Example | | --- | --- | | `[LinePattern](https://www.amcharts.com/docs/v5/reference/linepattern/) ` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern.png) | | `[RectanglePattern](https://www.amcharts.com/docs/v5/reference/rectanglepattern/) ` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern.png) | | `[CirclePattern](https://www.amcharts.com/docs/v5/reference/circlepattern/) ` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/circle_pattern.png) | | `[PathPattern](https://www.amcharts.com/docs/v5/reference/pathpattern/) ` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/11/path_pattern.png) | Patterns can be customized by applying rotation, gap, stroke, and other settings, which we'll explore in a bit. Setting pattern --------------- To set a pattern fill on an element, we need to assign it to element's `fillPattern` setting. Similarly, to assign it to element's stroke (line), we can use `strokePattern`. columnSeries.columns.template.set("fillPattern", am5.LinePattern.new(root, { color: am5.color(0xffffff), rotation: 45, width: 200, height: 200 })); columnSeries.columns.template.set("fillPattern", am5.LinePattern.new(root, { color: am5.color(0xffffff), rotation: 45, width: 200, height: 200 })); Colors ------ ### Primary color To set a color and opacity for pattern shapes, we use its `color` and `colorOpacity` settings. If those are not set, the pattern will inherit `stroke` and `fill` colors from the element it is applied to. columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { color: am5.color(0xffffff), colorOpacity: 0.5 })); columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { color: am5.color(0xffffff), colorOpacity: 0.5 })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_2.png) `color: am5.color(0xffffff)` `colorOpacity: 1` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_1.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_1.png) `color: am5.color(0xffffff)` `colorOpacity: 0.5` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_3.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_3.png) `color: am5.color(0x85ffc7)` `colorOpacity: 1` ### Fill color Pattern will use `color` to color it shapes, but will leave gaps between them transparent. If we'd rather have that area filled, we can use pattern's `fill` and `fillOpacity` settings. We can also "invert" the color pattern, by setting `fill` but omitting the `color` setting. columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { fill: am5.color(0xffffff), fillOpacity: 1 })); columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { fill: am5.color(0xffffff), fillOpacity: 1 })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_2.png) `color: am5.color(0xffffff)` `fill` not set [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_fill.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_fill.png) `color` not set `fill: am5.color(0xffffff)` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_fill_2.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_fill_2.png) `color: am5.color(0x297373)` `fill: am5.color(0xffffff)` ### Color inheritance If `fill` color is not set, pattern will have a transparent background. In such case, any original fill that target object has - either via its own `fill` or `fillGradient` - will be visible through the pattern. Sizing patterns --------------- Normally, patterns are constructed as 50x50 pixel squares. However, in some cases (for example rotated line pattern) they might not tile nicely. In such cases, we might need to increase the size of the pattern using `width` and `height` settings: columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { color: am5.color(0x297373), fill: am5.color(0xffffff), rotation: 45, width: 400, height: 400, })); columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { color: am5.color(0x297373), fill: am5.color(0xffffff), rotation: 45, width: 400, height: 400, })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_50.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_50.png) `width: 50, height: 50` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_400.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_400.png) `width: 400, height: 400` Rotation -------- By setting `rotation` on a pattern, we can create wholly distinctive patterns: columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { fill: am5.color(0xffffff), fillOpacity: 1, rotation: 45 })); columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { fill: am5.color(0xffffff), fillOpacity: 1, rotation: 45 })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_rotation_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_rotation_0.png) `rotation: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_400.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_400.png) `rotation: 45` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_rotation_90.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_rotation_90.png) `rotation: 90` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_patternr_rotation_-45.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_patternr_rotation_-45.png) `rotation: -45` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_rotation_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_rotation_0.png) `rotation: 0` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_rotation_45.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_rotation_45.png) `rotation: 45` NOTE Some rotated patterns will tile well. Some tweaking of `gap`, `width`, `height`, and possibly other settings might be required. Repetition ---------- Normally, pattern repeats the tiles in all directions, until all of the target area is filled. The setting `repetition` can be used to change that. Available values are: `"repeat"` (default), `"repeat-x"`, `"repeat-y"`, and `"no-repeat"`. NOTE Changing `repetition` may cause element not fully filled. Configuration ------------- Each pattern type also has specific configuration settings. For example, `gap` setting is available in all pattern types, and is used to set spacing between elements: lines, rectangles, or other shapes. columnSeries.columns.template.set("fillPattern", am5.LinePattern.new(root, { color: am5.color(0xffffff), rotation: 45, width: 200, height: 200, gap: 10 })); columnSeries.columns.template.set("fillPattern", am5.LinePattern.new(root, { color: am5.color(0xffffff), rotation: 45, width: 200, height: 200, gap: 10 })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_400.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/line_pattern_400.png) `gap: 6` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_gap_3.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_gap_3.png) `gap: 3` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_gap_20.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/pattern_gap_20.png) `gap: 20` There are also type specific settings, e.g. `checkered` (default: `false`) for rectangle and circle patterns: columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { color: am5.color(0xffffff), checkered: true })); columnSeries.columns.template.set("fillPattern", am5.RectanglePattern.new(root, { color: am5.color(0xffffff), checkered: true })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_rotation_0.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_rotation_0.png) `checkered: false` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_checkered.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/rectangle_pattern_checkered.png) `checkered: true` For more configuration options, visit following class references: * [`LinePattern` settings](https://www.amcharts.com/docs/v5/reference/linepattern/#Settings) * [`RectanglePattern` settings](https://www.amcharts.com/docs/v5/reference/linepattern/#Settings) * [`CirclePattern` settings](https://www.amcharts.com/docs/v5/reference/linepattern/#Settings) * [`PathPattern` settings](https://www.amcharts.com/docs/v5/reference/pathpattern/#Settings) Examples -------- The below example uses `CirclePattern` and `LinePattern`: See the Pen Stacked column chart by amCharts team (@amcharts) on CodePen. And this one uses a `PathPattern` to use SVG paths as a fill pattern: See the Pen Patterns by amCharts team (@amcharts) on CodePen. Image patterns -------------- ### Creating an image pattern We can also use any image (external or in-line) as a pattern using `PicturePattern`. It requires its setting `src` to be set either to a URL of the image: columnSeries.columns.template.set("fillPattern", am5.PicturePattern.new(root, { src: "/path/to/pattern.svg" })); columnSeries.columns.template.set("fillPattern", am5.PicturePattern.new(root, { src: "/path/to/pattern.svg" })); Or it can also contain a [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) (in-line) info: columnSeries.columns.template.set("fillPattern", am5.PicturePattern.new(root, { src: "data:image/svg+xml;base64,....." })); columnSeries.columns.template.set("fillPattern", am5.PicturePattern.new(root, { src: "data:image/svg+xml;base64,....." })); ### Sizing and fitting There are a few ways to size the pattern using `fit` setting, which accepts three values: * `"image"` (default) - the pattern will automatically size itself using image's native dimensions. * `"pattern"` - will size image using pattern's `width` and `height` settings. * `"none"` - will size pattern tiles according to `width` and `height` settings, but will let the image use own dimensions. Using this option is risky since it may produce non-fitting tiles if image is larger than the tile. The following code will make pattern use custom dimensions, effectively sizing the image: columnSeries.columns.template.set("fillPattern", am5.PicturePattern.new(root, { src: "/path/to/pattern.svg", fit: "pattern", width: 100, height: 100 })); columnSeries.columns.template.set("fillPattern", am5.PicturePattern.new(root, { src: "/path/to/pattern.svg", fit: "pattern", width: 100, height: 100 })); Here's an example: See the Pen Patterns by amCharts team (@amcharts) on CodePen. Grain patterns -------------- Grain pattern is another special kind of pattern that can complement regular fills with overhead pixel noise to add that additional fuzzy look. It works by applying a random assortment of semi-transparent dots over existing fills. ### Adding grain pattern As with other patterns, we use `fillPattern` to add grain pattern: series.slices.template.setAll({ fillPattern: am5.GrainPattern.new(root, {}) }); series.slices.template.setAll({ fillPattern: am5.GrainPattern.new(root, {}) }); ### Configuring noise pixels There are a few configuration options we can use to tweak appearance of the noise pixels. | Setting | Value range | Default | Comment | | --- | --- | --- | --- | | `size` | `1` to X | `1` | Size of a grain in pixels. | | `density` | `0` to `1` | `1` | Density of pixels. The closer number to `1` the more dense the noise.
`0` means no noise. | | `minOpacity` | `0` to `1` | `0` | Minimum opacity of a noise pixel. | | `maxOpacity` | `0` to `1` | `0.3` | Maximum opacity of a noise pixel. | | `colors` | N/A | | An array of `Color` objects to use for noise pixels. Will use `color` setting or black if `colors` is not set. | | `horizontalGap` | `0` to X | | Horizontal gap between noise pixels measured in `size`. | | `verticalGap` | `0` to X | | Vertical gap between noise pixels measured in `size`. | ### Combining with gradients We can also combine grain pattern with gradient fills as both `fillGradient` and `fillPattern` will be honored: series.slices.template.setAll({ fillGradient: am5.RadialGradient.new(root, { stops: \[\ { offset: 0.5 },\ { brighten: -0.5 }\] }), fillPattern: am5.GrainPattern.new(root, {}) }); series.slices.template.setAll({ fillGradient: am5.RadialGradient.new(root, { stops: \[\ { offset: 0.5 },\ { brighten: -0.5 }\] }), fillPattern: am5.GrainPattern.new(root, {}) }); See the Pen Untitled by amCharts team (@amcharts) on CodePen. Pattern sets ------------ Pattern sets, similar to [color sets](https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/#Color_sets) , are collection patterns that can be used to auto-assign pattern fills to series elements, like slices, series, nodes, etc. Pattern sets are created by instantiating a `PatternSet` class. It will have a predefined list of some distinctive patterns, which, upon need, can be overridden (see later in this section). ### XY chart An `XYChart` can auto-assign `fillPattern` to each series added to it. All we need to do is to set `patterns` setting with a value holding a reference to a `PatternSet` object: let chart = root.container.children.push(am5xy.XYChart.new(root, { patterns: am5.PatternSet.new(root, {}) })); var chart = root.container.children.push(am5xy.XYChart.new(root, { patterns: am5.PatternSet.new(root, {}) })); ### Pie chart In a `PieChart` (or any other Percent chart type), instead of chart, we set `patterns` to its series, because we will need to assign a different pattern to each individual item (slice): let series = chart.series.push(am5percent.PieSeries.new(root, { valueField: "sales", categoryField: "country", patterns: am5.PatternSet.new(root, {}) })); var series = chart.series.push(am5percent.PieSeries.new(root, { valueField: "sales", categoryField: "country", patterns: am5.PatternSet.new(root, {}) })); ### Hierarchy charts Similarly, in Hierarchy charts (Force-directed, Treemap), we set `patterns` directly on series: let series = container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", patterns: am5.PatternSet.new(root, {}) }) ); var series = container.children.push( am5hierarchy.Treemap.new(root, { valueField: "value", categoryField: "name", childDataField: "children", patterns: am5.PatternSet.new(root, {}) }) ); ### Flow charts For a Flow chart (e.g. Sankey, Chord), we assign `patterns` to its [nodes template](https://www.amcharts.com/docs/v5/charts/flow-charts/sankey-diagram/#Configuring_nodes) : series.nodes.set("patterns", am5.PatternSet.new(root, {})); series.nodes.set("patterns", am5.PatternSet.new(root, {})); ### Customizing colors The default patterns from the set will use a light interface stroke color for their elements (lines, squares, etc.) and will have no fill, so that original fill of the target element is visible. If you are using a dark theme, it will use its dark stroke interface color instead. To override the default element color, we can use pattern set's `color` setting: let series = chart.series.push(am5percent.PieSeries.new(root, { valueField: "sales", categoryField: "country", patterns: am5.PatternSet.new(root, { color: am5.color(0x000000) }) })); var series = chart.series.push(am5percent.PieSeries.new(root, { valueField: "sales", categoryField: "country", patterns: am5.PatternSet.new(root, { color: am5.color(0x000000) }) })); ### Custom pattern list We can also override a default list of patterns with our own, by setting set's `patterns` with an array of `Pattern` objects. let series = chart.series.push(am5percent.PieSeries.new(root, { valueField: "sales", categoryField: "country", patterns: am5.PatternSet.new(root, { patterns: \[\ am5.LinePattern.new(root, {\ color: am5.color(0xffffff),\ rotation: 45,\ width: 200,\ height: 200,\ gap: 10\ }),\ am5.RectanglePattern.new(root, {\ color: am5.color(0xffffff),\ checkered: true\ })\ \] }) })); var series = chart.series.push(am5percent.PieSeries.new(root, { valueField: "sales", categoryField: "country", patterns: am5.PatternSet.new(root, { patterns: \[\ am5.LinePattern.new(root, {\ color: am5.color(0xffffff),\ rotation: 45,\ width: 200,\ height: 200,\ gap: 10\ }),\ am5.RectanglePattern.new(root, {\ color: am5.color(0xffffff),\ checkered: true\ })\ \] }) })); Related tutorials ----------------- * [Using custom theme to apply patterns to pie chart slices](https://www.amcharts.com/docs/v5/tutorials/using-custom-theme-to-apply-patterns-to-pie-chart-slices/) --- # Graphics – amCharts 5 Documentation `Graphics` is an element which can be used to draw shapes using vector information. This tutorial will explore how it can be used to draw anything on the chart and its elements. Creating -------- To create a graphics element, we will need to instantiate a `[Graphics](https://www.amcharts.com/docs/v5/reference/graphics/) ` object using its `new()` method. By default, it would not display anything. For it to work, we will need to: 1. Set its `fill` and/or `stroke` settings to provide color. 2. Use drawing functions or an SVG path to define actual shape. am5.Graphics.new(root, { // config }); am5.Picture.new(root, { // config }); Setting colors -------------- Depending whether we will be drawing lines or filled shapes, we can set colors via graphics element's `stroke` and/or `fill` settings. Let's say, we will be drawing a filled shape, which we want to have a red fill, with black outline (stroke): am5.Graphics.new(root, { stroke: am5.color(0x000000), fill: am5.color(0x990000) }); am5.Graphics.new(root, { stroke: am5.color(0x000000), fill: am5.color(0x990000) }); There are more drawing options we can set like opacities, line thickness, or even gradients and patterns. We'll get to those in the [Configuring](#Configuring) section. Drawing shapes -------------- There are two ways to draw shapes in a graphics element: either by providing a ready-made SVG path, or using drawing functions like `lineTo()`, `rectangle()`, etc. Let's look at both now. ### Using SVG paths [SVG path](https://svgwg.org/svg2-draft/paths.html#PathElement) is a standard way to define any shape in a vector format. We can use some sort of editor to produce a path, or just grab one from an existing SVG image. The following is an example of a path that draws a heart shape: M45.418 10c-2.293-2.5-5.625-3.957-8.961-4.168h-.414c-4.168 0-7.918 2.086-10.418 5.418-2.293-4.375-6.668-7.082-11.457-7.082h-.211c-3.539 0-7.082 1.457-9.375 4.164-2.5 2.5-3.75 6.043-3.539 9.586C1.457 24.168 4.582 27.293 7.5 30c3.332 3.332 6.457 6.043 5.418 13.957 0 1.25.625 2.086 1.664 2.086.418 0 .625 0 1.25-.211C37.5 39.168 48.957 30.207 48.957 20.207V20c.211-3.957-1.039-7.293-3.539-10ZM14.582 44.793V43.75Zm0 0 To make graphics element use the path, we need to set it to its `svgPath` setting: am5.Graphics.new(root, { stroke: am5.color(0x000000), fill: am5.color(0x990000), svgPath: "M45.418 10c-2.293-2.5-5.625-3.957-8.961-4.168h-.414c-4.168 0-7.918 2.086-10.418 5.418-2.293-4.375-6.668-7.082-11.457-7.082h-.211c-3.539 0-7.082 1.457-9.375 4.164-2.5 2.5-3.75 6.043-3.539 9.586C1.457 24.168 4.582 27.293 7.5 30c3.332 3.332 6.457 6.043 5.418 13.957 0 1.25.625 2.086 1.664 2.086.418 0 .625 0 1.25-.211C37.5 39.168 48.957 30.207 48.957 20.207V20c.211-3.957-1.039-7.293-3.539-10ZM14.582 44.793V43.75Zm0 0" }); am5.Graphics.new(root, { stroke: am5.color(0x000000), fill: am5.color(0x990000), svgPath: "M45.418 10c-2.293-2.5-5.625-3.957-8.961-4.168h-.414c-4.168 0-7.918 2.086-10.418 5.418-2.293-4.375-6.668-7.082-11.457-7.082h-.211c-3.539 0-7.082 1.457-9.375 4.164-2.5 2.5-3.75 6.043-3.539 9.586C1.457 24.168 4.582 27.293 7.5 30c3.332 3.332 6.457 6.043 5.418 13.957 0 1.25.625 2.086 1.664 2.086.418 0 .625 0 1.25-.211C37.5 39.168 48.957 30.207 48.957 20.207V20c.211-3.957-1.039-7.293-3.539-10ZM14.582 44.793V43.75Zm0 0" }); See the Pen Adding images to container by amCharts team (@amcharts) on CodePen. ### Custom draw functions Another option is using low-level drawing functions, like `moveTo()`, `lineTo()`, `drawRect()`, `drawCircle()`, etc. To use those, we need to assign a custom function to graphics element's [`draw` setting](https://www.amcharts.com/docs/v5/reference/graphics/#draw_setting) . The function will receive a "display object" (`CanvasGraphics`), which will provide the drawing functions we mentioned earlier. Let's draw a triangle: am5.Graphics.new(root, { stroke: am5.color(0x000000), fill: am5.color(0x990000), draw: function(display) { display.moveTo(25, 0); display.lineTo(50, 50); display.lineTo(0, 50); display.lineTo(25, 0); } }); am5.Graphics.new(root, { stroke: am5.color(0x000000), fill: am5.color(0x990000), draw: function(display) { display.moveTo(25, 0); display.lineTo(50, 50); display.lineTo(0, 50); display.lineTo(25, 0); } }); For a full list of drawing methods, refer to `CanvasGraphics` reference. See the Pen Using graphics elements by amCharts team (@amcharts) on CodePen. #### The complete list of drawing functions All number parameters are absolute pixel values. | Method | | --- | | `arc(x, y, radius, startAngle, endAngle [, counterclockwise])` | | `arcTo(x1, y1, x2, y2, radius)` | | `bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)` | | `drawCircle(x, y, radius)` | | `drawEllipse(x, y, radiusX, radiusY)` | | `drawRect(x, y, width, height)` | | `lineTo(x, y)` | | `moveTo(x, y)` | | `quadraticCurveTo(cpX, cpY, toX, toY)` | Configuring ----------- There are more settings to graphics element than just `fill` and `stroke` (that specify fill and line colors respectively). For example `fillOpacity` will control fill transparency. MORE INFOFor a complete list of available settings, check out [`Graphics` reference](https://www.amcharts.com/docs/v5/reference/graphics/#Settings) . Here's another example, that uses `drawRect()` drawing method to draw a rotated semi-transparent rectangle: chart.children.push(am5.Graphics.new(root, { stroke: am5.color(0x000000), strokeWidth: 3, fill: am5.color(0x990000), fillOpacity: 0.5, rotation: 45, draw: function(display) { display.drawRect(0, 0, 50, 50) } })); chart.children.push(am5.Graphics.new(root, { stroke: am5.color(0x000000), strokeWidth: 3, fill: am5.color(0x990000), fillOpacity: 0.5, rotation: 45, draw: function(display) { display.drawRect(0, 0, 50, 50) } })); See the Pen Using graphics elements by amCharts team (@amcharts) on CodePen. --- # Buttons – amCharts 5 Documentation This tutorials takes a brief look at `Button` elements, and ways to configure them. Button element -------------- Buttons are elements of class `[Button](https://www.amcharts.com/docs/v5/reference/button/) ` or one of its derivate classes, such as `ResizeButton`. They are highly configurable. We can change colors, borders, rounding, text, and icons in them. Standalone buttons ------------------ We can create buttons by instantiating `Button` object and pushing it into `children` of the target container. let button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, label: am5.Label.new(root, { text: "Add data" }) })); var button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, label: am5.Label.new(root, { text: "Add data" }) })); And, since we probably want it to do something, we should attach a `click` event to it as well: button.events.on("click", function(ev) { var last = series.data.getIndex(series.data.length - 1); var newDate = new Date(last.date); newDate.setDate(newDate.getDate() + 1); series.data.push({ date: newDate.getTime(), value: last.value + Math.random() \* 5 - 2 }) }); button.events.on("click", function(ev) { var last = series.data.getIndex(series.data.length - 1); var newDate = new Date(last.date); newDate.setDate(newDate.getDate() + 1); series.data.push({ date: newDate.getTime(), value: last.value + Math.random() \* 5 - 2 }) }); The above code will add a button to the corner of chart's plot container, which upon click will add a new data item to the series data. See the Pen Untitled by amCharts team (@amcharts) on CodePen. Built-in buttons ---------------- Some controls in charts come with pre-created buttons. We usually can access them via property and configure just like any other regular button. Below is a list of such pre-created buttons. | Element class | Property | Button class | Comment | | --- | --- | --- | --- | | `XYChart` | `zoomOutButton` | `Button` | A zoom-out button that appears when chart is zoomed in. | | `Scrollbar` | `startGrip` | `Button` | Start grip of a scrollbar. | | `Scrollbar` | `endGrip` | `Button` | End grip of a scrollbar. | | `ZoomControl` | `plusButton` | `Button` | Zoom-in button. | | `ZoomControl` | `minusButton` | `Button` | Zoom-out button. | Customizing buttons ------------------- ### Layer Since buttons are controls that need unobstructive access, we may want to put them in a higher layer than the rest of the chart. Most of the buttons and related interactive controls are put in layer 40. It makes sense to use the same layer for custom buttons as well. To set a layer, we use button's `layer` setting: let button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, layer: 40, label: am5.Label.new(root, { text: "Add data" }) })); var button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, layer: 40, label: am5.Label.new(root, { text: "Add data" }) })); ### Body/background The button body can be configured via its `background` setting which holds an instance of `[RoundedRectangle](https://www.amcharts.com/docs/v5/reference/roundedrectangle/#Settings) `. We can set various settings like colors, corner radius, transparency, etc. button.get("background").setAll({ cornerRadiusTL: 0, cornerRadiusTR: 0, cornerRadiusBR: 0, cornerRadiusBL: 0, fill: am5.color(0x000000), fillOpacity: 0.7 }); button.get("background").setAll({ cornerRadiusTL: 0, cornerRadiusTR: 0, cornerRadiusBR: 0, cornerRadiusBL: 0, fill: am5.color(0x000000), fillOpacity: 0.7 }); In some cases we might want to disable body/background altogether. Perhaps we will use an image as button icon and do not need additional elements. In such case we can use `forceHidden` on button's background to completely hide it. button.get("background").setAll({ forceHidden: true }); button.get("background").setAll({ forceHidden: true }); ### Label Buttons start without any labels, so it's up to us to create a `Label` object and set it to button's `label` setting. That is if we need a textual label on our button. To configure the label, we can use any setting that is available on `[Label](https://www.amcharts.com/docs/v5/reference/label/#Settings) `. let button = chart.plotContainer.children.push(am5.Button.new(root, { layer: 40, label: am5.Label.new(root, { text: "Add data", fontSize: 15, fontWeight: "600", paddingTop: 2, paddingRight: 4, paddingBottom: 2, paddingLeft: 4 }) })); var button = chart.plotContainer.children.push(am5.Button.new(root, { layer: 40, label: am5.Label.new(root, { text: "Add data", fontSize: 15, fontWeight: "600", paddingTop: 2, paddingRight: 4, paddingBottom: 2, paddingLeft: 4 }) })); Note, that all padding on button comes from default label padding. See the Pen amCharts 5: Custom button to add data items by amCharts team (@amcharts) on CodePen. ### Icon Save for some of the built-in ones, buttons do not have an icon by default. If we need some graphical element to be shown instead or next to the label, we will need to create it and pass it in via `icon` setting. #### External image An icon can be any `Graphics` element, including basic built in shapes as `Rectangle` or `Picture` which allows using any external or in-line image to be used in button. let button = chart.plotContainer.children.push(am5.Button.new(root, { layer: 40, icon: am5.Picture.new(root, { interactive: true, src: "https://assets.codepen.io/t-160/icon\_add.png", cursorOverStyle: "pointer" }) })); var button = chart.plotContainer.children.push(am5.Button.new(root, { layer: 40, icon: am5.Picture.new(root, { interactive: true, src: "https://assets.codepen.io/t-160/icon\_add.png", cursorOverStyle: "pointer" }) })); NOTEThe interactive part of the button is its background. If we are disabling it, we will need to explicitly make the icon interactive by setting its `interactive` setting to `true`. #### In-line image We can also use Base64-encoded image data for in-line images. If we use an SVG as an icon, we may want to specify image's `width` and `height` too. let button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, layer: 40, icon: am5.Picture.new(root, { width: 32, height: 32, src: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIyMHB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyMCAyMCIgd2lkdGg9IjIwcHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48dGl0bGUvPjxkZXNjLz48ZGVmcy8+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSI+PGcgZmlsbD0iIzAwMDAwMCIgaWQ9IkNvcmUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTQuMDAwMDAwLCAtMi4wMDAwMDApIj48ZyBpZD0iYWRkLWNpcmNsZS1vdXRsaW5lIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNTQuMDAwMDAwLCAyLjAwMDAwMCkiPjxwYXRoIGQ9Ik0xMSw1IEw5LDUgTDksOSBMNSw5IEw1LDExIEw5LDExIEw5LDE1IEwxMSwxNSBMMTEsMTEgTDE1LDExIEwxNSw5IEwxMSw5IEwxMSw1IEwxMSw1IFogTTEwLDAgQzQuNSwwIDAsNC41IDAsMTAgQzAsMTUuNSA0LjUsMjAgMTAsMjAgQzE1LjUsMjAgMjAsMTUuNSAyMCwxMCBDMjAsNC41IDE1LjUsMCAxMCwwIEwxMCwwIFogTTEwLDE4IEM1LjYsMTggMiwxNC40IDIsMTAgQzIsNS42IDUuNiwyIDEwLDIgQzE0LjQsMiAxOCw1LjYgMTgsMTAgQzE4LDE0LjQgMTQuNCwxOCAxMCwxOCBMMTAsMTggWiIgaWQ9IlNoYXBlIi8+PC9nPjwvZz48L2c+PC9zdmc+", cursorOverStyle: "pointer" }) })); var button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, layer: 40, icon: am5.Picture.new(root, { width: 32, height: 32, src: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaGVpZ2h0PSIyMHB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyMCAyMCIgd2lkdGg9IjIwcHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48dGl0bGUvPjxkZXNjLz48ZGVmcy8+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSI+PGcgZmlsbD0iIzAwMDAwMCIgaWQ9IkNvcmUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yNTQuMDAwMDAwLCAtMi4wMDAwMDApIj48ZyBpZD0iYWRkLWNpcmNsZS1vdXRsaW5lIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNTQuMDAwMDAwLCAyLjAwMDAwMCkiPjxwYXRoIGQ9Ik0xMSw1IEw5LDUgTDksOSBMNSw5IEw1LDExIEw5LDExIEw5LDE1IEwxMSwxNSBMMTEsMTEgTDE1LDExIEwxNSw5IEwxMSw5IEwxMSw1IEwxMSw1IFogTTEwLDAgQzQuNSwwIDAsNC41IDAsMTAgQzAsMTUuNSA0LjUsMjAgMTAsMjAgQzE1LjUsMjAgMjAsMTUuNSAyMCwxMCBDMjAsNC41IDE1LjUsMCAxMCwwIEwxMCwwIFogTTEwLDE4IEM1LjYsMTggMiwxNC40IDIsMTAgQzIsNS42IDUuNiwyIDEwLDIgQzE0LjQsMiAxOCw1LjYgMTgsMTAgQzE4LDE0LjQgMTQuNCwxOCAxMCwxOCBMMTAsMTggWiIgaWQ9IlNoYXBlIi8+PC9nPjwvZz48L2c+PC9zdmc+", cursorOverStyle: "pointer" }) })); See the Pen amCharts 5: Custom button to add data items by amCharts team (@amcharts) on CodePen. #### SVG path We can also use just an [SVG path](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths) as button icon. The advantages of using an SVG path in place of a full image are that we can set colors to it both directly and via states. let button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, layer: 40, icon: am5.Graphics.new(root, { fill: am5.color(0xffffff), svgPath: "M11,5 L9,5 L9,9 L5,9 L5,11 L9,11 L9,15 L11,15 L11,11 L15,11 L15,9 L11,9 L11,5 L11,5 Z M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z" }) })); var button = chart.plotContainer.children.push(am5.Button.new(root, { dx: 10, dy: 10, layer: 40, icon: am5.Graphics.new(root, { fill: am5.color(0xffffff), svgPath: "M11,5 L9,5 L9,9 L5,9 L5,11 L9,11 L9,15 L11,15 L11,11 L15,11 L15,9 L11,9 L11,5 L11,5 Z M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z" }) })); See the Pen amCharts 5: Custom button to add data items by amCharts team (@amcharts) on CodePen. ### States Buttons come with three states that change background appearance on user interactions: * `hover` - applied when button is hovered by a pointer. * `down` - applied when button is being pressed down on by a pointer. * `active` - when button is set as "active". We can modify default states to apply our own colors and other settings: button.get("background").states.create("hover", {}).setAll({ fill: am5.color(0xff0000), fillOpacity: 0.8 }); button.get("background").states.create("down", {}).setAll({ fill: am5.color(0xff0000), fillOpacity: 1 }); button.get("background").states.create("hover", {}).setAll({ fill: am5.color(0xff0000), fillOpacity: 0.8 }); button.get("background").states.create("down", {}).setAll({ fill: am5.color(0xff0000), fillOpacity: 1 }); See the Pen amCharts 5: Custom button to add data items by amCharts team (@amcharts) on CodePen. --- # Labels – amCharts 5 Documentation Creating labels --------------- To create a label, we simply call `new()` method on a `Label` class. The following code creates a title on a chart: chart.children.unshift(am5.Label.new(root, { text: "This is a chart title", fontSize: 25, fontWeight: "500", textAlign: "center", x: am5.percent(50), centerX: am5.percent(50), paddingTop: 0, paddingBottom: 0 })); chart.children.unshift(am5.Label.new(root, { text: "This is a chart title", fontSize: 25, fontWeight: "500", textAlign: "center", x: am5.percent(50), centerX: am5.percent(50), paddingTop: 0, paddingBottom: 0 })); See the Pen Stacked column chart by amCharts team (@amcharts) on CodePen. Refer to [`Label` settings](https://www.amcharts.com/docs/v5/reference/label/#Settings) list for more options. In-line styling --------------- Text within the label can be formatted using in-line style blocks: instructions enclosed in square brackets: label.set("text", "\[#888\]This is gray\[/\]. \[bold\]And this is bold\[/\]!"); label.set("text", "\[#888\]This is gray\[/\]. \[bold\]And this is bold\[/\]!"); For more information, refer to "[Text styling](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) " tutorial. Data placeholders ----------------- Labels that have access to actual data items (e.g. axis labels, series bullets, tooltips), can use data placeholders in curly brackets to refer to actual data. label.set("text", "\[#888\]{categoryX}\[/\]: \[bold\]{valueY}\[/\]"); label.set("text", "\[#888\]{categoryX}\[/\]: \[bold\]{valueY}\[/\]"); For more information, refer to "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorial. In order for data placeholders to work, labels also need to have they `populateText` setting set to `true`. In places where labels are likely use placeholders that would already be set, e.g. in axes, tooltips, node labels, legend, etc. Other places, like labels in bullets, will need their `populateText` set manually. Oversized text -------------- An oversized label is considered one that does not fit into its `maxWidth` setting, if it's set. You can set it manually. Some elements will do it for you, like for example labels on a Treemap will have their `maxWidth` set automatically to the node width they're for. MPORTANTThis setting currently does not work with `RadialLabel`. ### Behavior Normally, oversized labels won't do anything, they'd just go out of bounds. We can control that using label's setting: `[oversizedBehavior](https://www.amcharts.com/docs/v5/reference/label/#oversizedBehavior_setting) `. xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "truncate", maxWidth: 150 }); xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "truncate", maxWidth: 150 }); Available values for `oversizedBehavior`: | Setting value | Comment | | --- | --- | | `"none"` | Text will be shown as is, even if it does not fit into `maxWidth`. | | `"hide"` | Label will be hidden completely if it does not fit. | | `"fit"` | Label will be scaled down to fit into `maxWidth`. | | `"wrap"` | Label text will be auto-wrapped into lines no longer than `maxWidth`. | | `"wrap-no-break"` | Label text will be auto-wrapped into lines to fit within `maxWidth`, but will not break words, which means labels can be longer than `maxWidth`. | | `"truncate"` | Label text will be truncated with an ellipsis to fit into `maxWidth`. | [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_oversized.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_oversized.png) `oversizedBehavior: "none"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_truncate.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_truncate.png) `oversizedBehavior: "truncate"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_wrap.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_wrap.png) `oversizedBehavior: "wrap"` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_fit.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_fit.png) `oversizedBehavior: "fit"` See the Pen Chart with oversized labels by amCharts team (@amcharts) on CodePen. ### Rotated or vertical labels Normally, rotated labels will still use `maxWidth` to apply truncation just like it was horizontal, that is not actual width of a rotated label, but its actual length. The exception is completely vertical labels (`rotation` set to `90` or `-90`). For vertical labels, their `maxHeight` setting will be used instead of `maxWidth`. xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "truncate", maxHeight: 50, rotation: -90 }); xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "truncate", maxHeight: 50, rotation: -90 }); ### Additional options There are some additional options that relate to specific values of `oversizedBehavior`. #### Additional settings for "fit" If `oversizedBehavior` is set to `"fit"`, label will try to scale down itself to fit. To avoid microscopic unreadable labels, there's another setting - `[minScale](https://www.amcharts.com/docs/v5/reference/label/#minScale_setting) `. If set it will not allow labels to shrink beyond certain point. For example, if we set `minScale` to `0.4` label will be allowed to get to 40% of its original size. If it still doesn't fit, it will be hidden. Some series, like force-directed and treemap, have `oversizedBehavior` and `minScale` by default. #### Additional settings for "truncate" When text is truncated, label adds a Unicode ellipsis symbol (`…`) at the end. Since not all fonts support it, we might want to change it using label's `[ellipsis](https://www.amcharts.com/docs/v5/reference/label/#ellipsis_setting) ` setting: xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "truncate", maxWidth: 150, ellipsis: "..." }); xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "truncate", maxWidth: 150, ellipsis: "..." }); Line breaks ----------- If we need a line to break in some place, all we need to do is insert a new line symbol (`"\n"`) into text: chart.children.unshift(am5.Label.new(root, { text: "This is the first line\\nAnd this is the second" })); chart.children.unshift(am5.Label.new(root, { text: "This is the first line\\nAnd this is the second" })); Alignment --------- Multi-line labels, or auto-wrapped labels, will align their lines to the left. We can set labels' `[textAlign](https://www.amcharts.com/docs/v5/reference/label/#textAlign_setting) ` setting to something else, if we can them to be aligned differently: xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "wrap", maxWidth: 150, textAlign: "center" }); xAxis.get("renderer").labels.template.setAll({ oversizedBehavior: "wrap", maxWidth: 150, textAlign: "center" }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_wrap.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/label_wrap.png) `texAlign: "left"` (default) [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/textalign_center.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/08/textalign_center.png) `textAlign: "center"` Background ---------- Labels are containers, so can have a background. We can use its `background` setting for that. For more information and examples, refer to "[Containers: Background](https://www.amcharts.com/docs/v5/concepts/common-elements/containers/#Background) " tutorial. Labels as interactive elements ------------------------------ ### Enabling label interactivity Labels as interactive elements in amCharts 5 are tricky. Basically, it's super hard to determine hover/click over just text because it's impossible to completely eradicate antialising, and the actual colored area is super tiny. Therefore, if we need tooltip to be interactive - have a hover tooltip or handle click events - we need to add a background to it. The background does not necessarily have to be visible: we can just set its `fillOpacity: 0` to make it completely transparent. let label = chart.children.unshift(am5.Label.new(root, { text: "I am clickable!", background: am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 }) })); label.events.on("click", function(ev) { console.log("Clicked!"); }); var label = chart.children.unshift(am5.Label.new(root, { text: "I am clickable!", background: am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 }) })); label.events.on("click", function(ev) { console.log("Clicked!"); }); ### Label templates For labels produces from a template (e.g. axis labels), we may need to add a "[setup function](https://www.amcharts.com/docs/v5/concepts/settings/list-templates/#Setup_handler) " which adds a background to all newly-created labels. yAxis.get("renderer").labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 })); } yAxis.get("renderer").labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 })); } ### Interactive axis labels If we need interactivity on axis labels, we can enable them by setting `interactive: true` or `tooltipText` on a label template as well as setting up a `setup` function for template which adds a background, as per above code. If we would also like to configure tooltip which is displayed, we will need to create a new `Tooltip` object on labels' parent, i.e. `axis.labelsContainer`: xAxis.labelsContainer.set("tooltip", am5.Tooltip.new(root, { pointerOrientation: "down" })); let xRenderer = xAxis.get("renderer"); xRenderer.labels.template.setAll({ tooltipText: "{category}", oversizedBehavior: "truncate", maxWidth: 100 }); xRenderer.labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 })); }; xAxis.labelsContainer.set("tooltip", am5.Tooltip.new(root, { pointerOrientation: "down" })); var xRenderer = xAxis.get("renderer"); xRenderer.labels.template.setAll({ tooltipText: "{category}", oversizedBehavior: "truncate", maxWidth: 100 }); xRenderer.labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 })); }; See the Pen amCharts 5: Tooltips on axis labels by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Clickable circular labels](https://www.amcharts.com/docs/v5/tutorials/clickable-circular-labels/) Related class references ------------------------ * [Label](https://www.amcharts.com/docs/v5/reference/label) --- # Images – amCharts 5 Documentation This tutorial explains how we can use `Picture` class elements to add images to charts. Creating an image ----------------- To create an image, we will need to instantiate a `[Picture](https://www.amcharts.com/docs/v5/reference/picture/) ` object using its `new()` method. For image to work, it needs to at least have its `[src](https://www.amcharts.com/docs/v5/reference/picture/#src_setting) ` setting set. The `src` can be a string with a relative or absolute URL or an encoded data URI. Basically anything that could go into `href` attribute of an HTML `` tag. am5.Picture.new(root, { width: 32, height: 32, src: "/images/icon\_btc.svg" }); am5.Picture.new(root, { width: 32, height: 32, src: "/images/icon\_btc.svg" }); The same icon can also be added as in-line data URI: am5.Picture.new(root, { width: 32, height: 32, src: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0..." }); am5.Picture.new(root, { width: 32, height: 32, src: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0..." }); See the Pen Basic containers by amCharts team (@amcharts) on CodePen. Images as bullets ----------------- Since image is as good as element as any, we can also use it as [bullet in series](https://www.amcharts.com/docs/v5/concepts/common-elements/bullets/) or [axes ranges](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/#Bulltet) : series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Picture.new(root, { width: 32, height: 32, x: am5.percent(30), y: am5.percent(50), centerX: am5.percent(50), centerY: am5.percent(50), src: "/images/icon\_btc.svg" }) }); }); series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Picture.new(root, { width: 32, height: 32, x: am5.percent(30), y: am5.percent(50), centerX: am5.percent(50), centerY: am5.percent(50), src: "/images/icon\_btc.svg" }) }); }); See the Pen Line series with bullets by amCharts team (@amcharts) on CodePen. Known issues ------------ ### Cross-domain issues Images loaded from the same host as the web page displaying the chart, or images loaded via data URIs are considered safe and can be used without any restrictions. Images loaded from another domains (even from another sub-domain) are considered unsafe by the browser. Such unsafe images cannot be used as interactive elements on the chart. They will also be removed when chart snapshot is exported to an image. The above should be taken into consideration when creating charts. ### Dimension-less SVG In Firefox, if the SVG does not have its width and height attributes set, image might not render. It's due to a [bug](https://bugzilla.mozilla.org/show_bug.cgi?id=700533) in Firefox. There's currently no known workarounds, except of manually editing the SVG to give it some dimensions. Using SVG paths --------------- Instead of full images, we can also use SVG paths as images. Using SVG paths adds a number of advantages, like avoiding cross-domain issues, latency loading external files, as well as enabling us to set custom colors and other drawing settings. To draw shapes using SVG paths, instead of `Picture` class, we can use `Graphics`. For more information, please refer to "[Graphics](https://www.amcharts.com/docs/v5/concepts/common-elements/graphics/) " tutorial. --- # Containers – amCharts 5 Documentation A container is an element that can have child elements as well as a background. Most of the elements on a chart are containers. The chart itself is also a container. Root container -------------- When we create a root element it comes with a container of itself. Any top-level element - e.g. chart - will need to go into that root container as a child. Root container is accessible by `root.container`. Children -------- ### Adding To add a child to a container, all we need to do is `push()` it into `children` list. Here's how we'd add a footnote label to a chart: let footnote = chart.children.push(am5.Label.new(root, { text: "Copyright 2021 amCharts" }); var footnote = chart.children.push(am5.Label.new(root, { text: "Copyright 2021 amCharts" }); ### Ordering Using `push()` method will add a child at the end of the child list. If container has a layout set it will be drawn last. To put it in the first position, we can use `unshift()` instead. Or, if we want to be super precise, we can use `insertIndex()` which accepts first parameter an index. Using `insertIndex(0, ...)` is equovalent to `unshift(...)`. Layout ------ ### Setting layout Container's `layout` setting affects how child elements in it are arranged. It can be either vertical, horizontal, grid, or none. A layout is represented by an object, accessible visa root properties. | Layout instance | Comment | | --- | --- | | `root.horizontalLayout` | Child elements are displayed in a row. | | `root.verticalLayout` | Child elements are displayed stacked vertically. | | `root.gridLayout` | Child elements are displayed in a grid of columns, and can form multiple rows. | | Not set | Child elements are placed at whatever `x` and/or `y` setting are set for them, or at upper-left corner if not set. | Setting layout might affect the look of the chart setup, such as where [chart's legend is placed](https://www.amcharts.com/docs/v5/concepts/legend/#Positioning) . let chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalLayout }) ); var chart = root.container.children.push( am5percent.PieChart.new(root, { layout: root.verticalLayout }) ); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chrome_2021-07-29_17-02-22.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/chrome_2021-07-29_17-02-22.png) `layout: root.horizontalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-29_17-02-37.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-29_17-02-37.png) `layout: root.verticalLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-29_17-02-48.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-29_17-02-48.png) `layout: root.gridLayout` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-29_17-02-58.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-29_17-02-58.png) `layout` not set (default) See the Pen Map chart heat map by amCharts team (@amcharts) on CodePen. ### Grid Gird layout is special, because it accepts some configuration options. Those are: * `maxColumns` - maximum number of columns to allow in the grid. * `fixedWidthGrid` - if set to `true` will make all columns equal in width, as opposed to best fit. Since we don't want to modify a global instance of the grid layout (it may be used by other chart elements), we will need to create a unique instance of `GridLayout` specifically for the target container: let legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: am5.GridLayout.new(root, { maxColumns: 3, fixedWidthGrid: true }) })); var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: am5.GridLayout.new(root, { maxColumns: 3, fixedWidthGrid: true }) })); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-09-47.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-09-47.png) (Default) `maxColumns: undefined` `fixedWidthGrid: false` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-10-06.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-10-06.png) `maxColumns: 3` `fixedWidthGrid: false` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-10-16.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-10-16.png) `maxColumns: 3` `fixedWidthGrid: true` [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-12-58.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/07/2021-07-30_09-12-58.png) `maxColumns: 2` `fixedWidthGrid: true` See the Pen Basic containers by amCharts team (@amcharts) on CodePen. Background ---------- ### Standalone elements Containers do not have any background by default. To add one, we will need to container's `background` setting to an instance of a `Rectangle` (or `RoundedRectangle`). let chart = root.container.children.push( am5percent.PieChart.new(root, { background: am5.Rectangle.new(root, { fill: am5.color(0xff5599), fillOpacity: 0.2 }) }) ); var chart = root.container.children.push( am5percent.PieChart.new(root, { background: am5.Rectangle.new(root, { fill: am5.color(0xff5599), fillOpacity: 0.2 }) }) ); ### Templates Objects like backgrounds will not be copied over to new elements from a template, so we will need to set them up using `setup()` method of the template: yAxis.get("renderer").labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0xff0000) })) } yAxis.get("renderer").labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0xff0000) })) } IMPORTANT The `template.setup` needs to be set **before** any data is set on the the series. More info [here](https://www.amcharts.com/docs/v5/concepts/settings/list-templates/#Setup_handler) . Masks ----- Container contents can be constricted to any shape using its `mask` setting. Mask can be any element of type `Graphics`, e.g. a `Circle`, `Rectangle`, or any custom shape. chart.set("mask", am5.Star.new(root, { radius: 200, innerRadius: 150, spikes: 20, fill: am5.color(0x000000), x: am5.percent(50), y: am5.percent(50) })); chart.set("mask", am5.Star.new(root, { radius: 200, innerRadius: 150, spikes: 20, fill: am5.color(0x000000), x: am5.percent(50), y: am5.percent(50) })); The above will display a star-shaped pie chart: See the Pen Pie chart by amCharts team (@amcharts) on CodePen. Scrollbar --------- If container's contents do not fit into its height, we can enable scrolling by setting its `verticalScrollbar` instance of a `Scrollbar`: var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.verticalLayout, height: am5.percent(100), verticalScrollbar: am5.Scrollbar.new(root, { orientation: "vertical" }) })); var legend = chart.children.push(am5.Legend.new(root, { centerX: am5.percent(50), x: am5.percent(50), layout: root.verticalLayout, height: am5.percent(100), verticalScrollbar: am5.Scrollbar.new(root, { orientation: "vertical" }) })); NOTE Please note that `height` needs to be set for this to work properly. See the Pen Pie chart legend alignment by amCharts team (@amcharts) on CodePen. Zoomable container ------------------ There's also a special version of a Container: `ZoomableContainer`. We can use it to make any chart content zoomable. ### Creating a zoomable container `ZoomableContainer` is similar to a regular `Container` with a couple of important restrictions: * It needs to be a top-most child of the Root container. * Zoomable contents must go into its `contents.children` rather than `children`. let zoomableContainer = root.container.children.push( am5.ZoomableContainer.new(root, { width: am5.p100, height: am5.p100 }) ); let series = zoomableContainer.contents.children.push(am5hierarchy.ForceDirected.new(root, { valueField: "value", categoryField: "name", childDataField: "children", idField: "name" })); var zoomableContainer = root.container.children.push( am5.ZoomableContainer.new(root, { width: am5.p100, height: am5.p100 }) ); var series = zoomableContainer.contents.children.push(am5hierarchy.ForceDirected.new(root, { valueField: "value", categoryField: "name", childDataField: "children", idField: "name" })); ### Zoom functionality Zoom in a zoomable container can be can be controlled via mouse wheel, pinch-zoom, API functions, or a zoom tools. Both wheel and pinch-zoom are enabled by default. To disable them, we can use `wheelable` and `pinchZoom` settings respectively: let zoomableContainer = root.container.children.push( am5.ZoomableContainer.new(root, { width: am5.p100, height: am5.p100, wheelable: false, pinchZoom: false }) ); var zoomableContainer = root.container.children.push( am5.ZoomableContainer.new(root, { width: am5.p100, height: am5.p100, wheelable: false, pinchZoom: false }) ); ### Zoom tools To add zoom tools, we can use a bundled `ZoomTools` class: let zoomTools = zoomableContainer.children.push(am5.ZoomTools.new(root, { target: zoomableContainer })); var zoomTools = zoomableContainer.children.push(am5.ZoomTools.new(root, { target: zoomableContainer })); ### Zoom API Finally, zoomable container provides some methods to control zoom level and position: | Method | Comment | | --- | --- | | `zoomToPoint(point, zoomLevel)` | Pans to specific X/Y point and zooms to specific level. | | `zoomIn()` | Zooms in the container. | | `zoomOut()` | Zooms out the container. | | `goHome()` | Resets containers position and zoom level to initial. | ### Example See the Pen Zoomable Force-Directed Tree by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Dynamically adding charts to the same Root](https://www.amcharts.com/docs/v5/tutorials/dynamically-adding-charts-to-the-same-root/) --- # Layers – amCharts 5 Documentation This tutorial will explain how layering functionality works in amCharts 5. What are layers? ---------------- All visual elements in amCharts 5 are drawn in a `` element, which is a high-speed way to display graphics. amCharts 5 supports having multiple `` elements, overlaid over each other. Any element in the chart can go to any of the layers, and developers are free to create as many layers as needed. There is a couple of reasons for moving elements to other layers: 1. To ensure they are displayed over other elements. 2. To increase performance by moving elements that are updated often to a separate layer, so that when they are updated, the whole chart does not need to be re-rendered, but rather those elements in specific layer. Layers are represented by an integer number. Layers with higher number will be displayed on top of ones with lower numbers. In essence, layers work similarly like `zIndex` property works in CSS. Hardcoded layers ---------------- Most of the chart elements are drawn in a "base layer" (or layer `0` - zero). However, some of them are moved to other levels by default. The following table lists a few examples of default layer assignment. | Element | Default layer | | --- | --- | | Legend | `30` | | Zoom button | `30` | | Scrollbar | `30` | | Tooltips | `30` | | Tooltips (if used with [extended bounds](https://www.amcharts.com/docs/v5/getting-started/root-element/#Expanded_tooltip_bounds)
) | `35` | | Cursor on an XY Chart | `30` | | Panel controls of a Stock Chart | `30` | Assigning a layer to elements ----------------------------- To assign a layer to a specific element, we can use its `layer` setting. If there's no such layer created already, it will be created automatically. The following example moves axis tooltip to a lower layer than other tooltips (30 by default), so that it does not overlap them: let xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, { // ... tooltip: am5.Tooltip.new(root, { layer: 10 }) })); var xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, { // ... tooltip: am5.Tooltip.new(root, { layer: 10 }) })); Out-of-bounds layers -------------------- Normally, layers are sized exactly to the width and height of the container of the Root element. This means that all elements that go outside those bounds, will be cut off. It works for most charts in that all of the information is contained withing chart's bounds. However, in some cases, we'd rather have elements bleeding out of the bounds than have them cut off. amCharts 5 provides a way to specify extended bounds for particular layers using `layerMargin` setting. The `layerMargin` accepts an object which specifies extended margins for `top`, `right`, `left`, and `bottom`. axisRenderer.labels.template.setAll({ layer: 20, layerMargin: { left: 50, right: 50, top: 0, bottom: 0 } }); axisRenderer.labels.template.setAll({ layer: 20, layerMargin: { left: 50, right: 50, top: 0, bottom: 0 } }); The above code will add extra 50 pixels to left and right sides of the layer `20`, so any elements contained in it - in this case axis labels - will have a bit of an extra space. [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2024/01/8wyHZYXWzx.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2024/01/8wyHZYXWzx.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2024/01/chrome_ymWBa3qSVW.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2024/01/chrome_ymWBa3qSVW.png) With `layerMargin` Precautions ----------- Important thing to know when using layers is that each new layer will create a full-size `` element. Those elements will take up memory, and in some browsers (e.g. Safari) might hit a hardcoded RAM usage limit, resulting in chart render anomalies. Use layers sparingly! --- # HTML content – amCharts 5 Documentation amCharts 5 using HTML as content for its `Container` elements. This tutorial will show various ways this can be used. Common elements --------------- To make a container (or any other element that extends `Container`) display HTML content, simply use its `html` setting. The below code adds an HTML-enabled title to the chart: chart.children.unshift(am5.Label.new(root, { html: "

Chart title

And a smaller sub-title

", x: am5.percent(50), centerX: am5.percent(50), paddingTop: 0, paddingBottom: 0 })); chart.children.unshift(am5.Label.new(root, { html: "

Chart title

And a smaller sub-title

", x: am5.percent(50), centerX: am5.percent(50), paddingTop: 0, paddingBottom: 0 })); See the Pen Chart with title and sub-title by amCharts team (@amcharts) on CodePen. Tooltips -------- ### Tooltip contents There are couple of ways to set HTML content for tooltips: * Via `tooltipHTML` setting of an element. * Via `labelHTML` setting of a `Tooltip` object. If we'd like some HTML content to be shown in a tooltip when hovered over an element, e.g. a column, we can use its `tooltipHTML` setting: series.columns.template.setAll({ tooltipHTML: "{categoryX}: {valueY}" }); series.columns.template.setAll({ tooltipHTML: "{categoryX}: {valueY}" }); See the Pen HTML tooltips by amCharts team (@amcharts) on CodePen. If we do have a `Tooltip` instance, e.g. on a series, we can use its `labelHTML` setting instead: let series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", sequencedInterpolation: true, categoryXField: "country", tooltip: am5.Tooltip.new(root, { labelHTML: "{categoryX}: {valueY}" }) })); var series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", sequencedInterpolation: true, categoryXField: "country", tooltip: am5.Tooltip.new(root, { labelHTML: "{categoryX}: {valueY}" }) })); See the Pen HTML tooltips by amCharts team (@amcharts) on CodePen. ### Interactive elements If you have interactive elements in tooltip, like buttons or links, you will need to explicitly enable tooltip interactivity by setting `interactive: true` on its label. It's also recommended to use `keepTargetHover: true` on the tooltip, so that tooltip does not go away until the pointer goes outside its area. let series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", sequencedInterpolation: true, categoryXField: "country", tooltip: am5.Tooltip.new(root, { labelHTML: "{categoryX}: {valueY}", keepTargetHover: true }) })); series.get("tooltip").label.set("interactive", true); var series = chart.series.push(am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: "value", sequencedInterpolation: true, categoryXField: "country", tooltip: am5.Tooltip.new(root, { labelHTML: "{categoryX}: {valueY}", keepTargetHover: true }) })); series.get("tooltip").label.set("interactive", true); Axis labels ----------- We will need to use an adapter to dynamically override content for an axis label: xAxis.get("renderer").labels.template.adapters.add("html", function(html, target) { return "
{value.formatDate('d MMM')}
{value.formatDate('EEE')}
"; }); xAxis.get("renderer").labels.template.adapters.add("html", function(html, target) { return "
{value.formatDate('d MMM')}
{value.formatDate('EEE')}
"; }); See the Pen HTML labels on a DateAxis by amCharts team (@amcharts) on CodePen. Limitations ----------- ### Exporting HTML content will not be included when exporting chart snapshot to images or PDF. ### Layer order HTML content does not follow regular "z-index" order in regards to other elements - it will always be in front. ### Tooltips on HTML elements There's currently no way to set rollover tooltip to be displayed on HTML-enabled elements, e.g. via `tooltipText` settings. ### Images All images included in HTML content need to be sized via either `width` and `height` attributes, or CSS. If un-sized images are used, the element will not be sized properly, which will be especially prominent if used in tooltips. // Incorrect! label.set("html", ""); // Correct label.set("html", ""); // Also correct label.set("html", ""); // Incorrect! label.set("html", ""); // Correct label.set("html", ""); // Also correct label.set("html", ""); --- # Tooltips – amCharts 5 Documentation This tutorial will look at various ways how we can enable, configure, and trigger tooltips in amCharts 5. Enabling -------- ### Common elements The easiest way to enable rollover tooltips is to set element's `tooltipText` setting. It can be set directly on an element, or a template. For example, we can set a tooltip to be shown when XY chart's zoom out button is hovered: zoomOutButton.set("tooltipText", "Click to zoom out"); zoomOutButton.set("tooltipText", "Click to zoom out"); The following code will set a rollover tooltip on all columns in a column series using its template: series.columns.template.setAll({ tooltipText: "{name}, {categoryX}: {valueY}" }); series.columns.template.setAll({ tooltipText: "{name}, {categoryX}: {valueY}" }); `tooltipText` supports data placeholders, which means that we can use curly bracket references to related data item and element itself. For more information, please refer to "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorial. ### Shared tooltip When root element is created, it does create a single shared `Tooltip` instance which is reused for most elements. Whenever tooltip needs to be shown, that shared tooltip instance is populated with data and colors of the target element, as well as positioned according to settings. ### Individual tooltip If we would like to configure tooltip for some element (or its children) we will need to set up a dedicated instance of a `Tooltip` for that element. We can do that by assigning a new instance of the `Tooltip` to element's `tooltip` setting. The following will create a dedicated tooltip for a scrollbar, as well as enable rollover tooltips on its grips: let scrollbar = am5.Scrollbar.new(root, { orientation: "horizontal" }); let tooltip = am5.Tooltip.new(root, {}); tooltip.get("background").setAll({ fill: am5.color(0xeeeeee) }); scrollbar.set("tooltip", tooltip); scrollbar.startGrip.set("tooltipText", "Drag to zoom"); scrollbar.endGrip.set("tooltipText", "Drag to zoom"); chart.set("scrollbarX", scrollbar); var scrollbar = am5.Scrollbar.new(root, { orientation: "horizontal" }); var tooltip = am5.Tooltip.new(root, {}); tooltip.get("background").setAll({ fill: am5.color(0xeeeeee) }); scrollbar.set("tooltip", tooltip); scrollbar.startGrip.set("tooltipText", "Drag to zoom"); scrollbar.endGrip.set("tooltipText", "Drag to zoom"); chart.set("scrollbarX", scrollbar); See the Pen Custom tooltip on scrollbar grips by amCharts team (@amcharts) on CodePen. ### Series If we want our chart to be able to show multiple tooltips for multiple series at once, we need to: * Create individual tooltips for each series. * Set up tooltip label to show the information we want it to show. * Enable chart cursor. let series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }) }) ); series.data.setAll(data); var series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }) }) ); series.data.setAll(data); NOTESeries tooltips will only be shown if there's a cursor enabled for the chart. For more information, refer to the "[Cursor](https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/) " tutorial. ### Hoverable tooltips If we want to keep the target element hovered (and tooltip visible) when move pointer (e.g. mouse) position over open tooltip, we need to set tooltip's `keepTargetHover: true`. let series = chart.series.push( am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { keepTargetHover: true }) }) ); series.columns.template.setAll({ tooltipText: "{categoryX}: {valueY}" }); var series = chart.series.push( am5xy.ColumnSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { keepTargetHover: true }) }) ); series.columns.template.setAll({ tooltipText: "{categoryX}: {valueY}" }); Colors ------ ### Default colors Tooltips will automatically inherit its background color from target element's `fill` setting. If such element does not have any `fill` set (or does not support such setting) the tooltip will be transparent. In such case, please refer to the section below on how to set fill color manually. Tooltip will also have a stroke (outline) set to white by default. Finally, tooltip text will be colored either in white or black, whichever contrasts more with tooltip background color. The following sections will examine how we can change those to anything else. ### Background If we need to change background color, we will first need to disable fill inheritance by setting tooltip's `getFillFromSprite` to `false`. Then we can set `fill` on tooltip's `background` element. let tooltip = am5.Tooltip.new(root, { getFillFromSprite: false, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.get("background").setAll({ fill: am5.color(0xffffff), fillOpacity: 0.8 }); series.set("tooltip", tooltip); var tooltip = am5.Tooltip.new(root, { getFillFromSprite: false, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.get("background").setAll({ fill: am5.color(0xffffff), fillOpacity: 0.8 }); series.set("tooltip", tooltip); ### Outline To change color of the outline, all we need to do is to set background's `stroke` setting: let tooltip = am5.Tooltip.new(root, { labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.get("background").setAll({ stroke: am5.color(0x000000), strokeOpacity: 0.8 }); series.set("tooltip", tooltip); var tooltip = am5.Tooltip.new(root, { labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.get("background").setAll({ stroke: am5.color(0x000000), strokeOpacity: 0.8 }); series.set("tooltip", tooltip); We can also make tooltip outline inherit `stroke` from the target element, similarly `fill` is inherited for tooltip's background. For that we will need to set `getStrokeFromSprite` to `true`: let tooltip = am5.Tooltip.new(root, { getStrokeFromSprite: true, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); series.set("tooltip", tooltip); var tooltip = am5.Tooltip.new(root, { getStrokeFromSprite: true, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); series.set("tooltip", tooltip); ### Text color If we need specific color for tooltip text, we will first need to disable default behavior of choosing a contrasting color based on the background. To do that we will need to set `autoTextColor` setting to `false`. Then we can set `fill` setting of the tooltip's label element: let tooltip = am5.Tooltip.new(root, { autoTextColor: false, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.label.setAll({ fill: am5.color(0xff5566) }); series.set("tooltip", tooltip); var tooltip = am5.Tooltip.new(root, { autoTextColor: false, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.label.setAll({ fill: am5.color(0xff5566) }); series.set("tooltip", tooltip); We can also make tooltip label inherit `fill` color from the target element, by using `getLabelFillFromSprite` setting: let tooltip = am5.Tooltip.new(root, { getLabelFillFromSprite: true, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); series.set("tooltip", tooltip); var tooltip = am5.Tooltip.new(root, { getLabelFillFromSprite: true, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); series.set("tooltip", tooltip); ### Full example The following code will make column series' tooltips have white background, but will inherit its stroke and text color from the target column: let tooltip = am5.Tooltip.new(root, { getFillFromSprite: false, getStrokeFromSprite: true, autoTextColor: false, getLabelFillFromSprite: true, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.get("background").setAll({ fill: am5.color(0xffffff), fillOpacity: 0.8 }); series.set("tooltip", tooltip); var tooltip = am5.Tooltip.new(root, { getFillFromSprite: false, getStrokeFromSprite: true, autoTextColor: false, getLabelFillFromSprite: true, labelText: "\[bold\]{name}\[/\]\\n{valueX.formatDate()}: {valueY}" }); tooltip.get("background").setAll({ fill: am5.color(0xffffff), fillOpacity: 0.8 }); series.set("tooltip", tooltip); See the Pen Custom tooltip on scrollbar grips by amCharts team (@amcharts) on CodePen. ### Colors from bullets Normally, tooltips will inherit its colors from target series' `fill` and `stroke` settings. However, we can make it inherit from bullets instead, by setting series' setting `[seriesTooltipTarget](https://www.amcharts.com/docs/v5/reference/ixyseriessettings/#seriesTooltipTarget_property) ` to `"bullet"`. In such case, tooltip will take series first bullet (if available) and use it as a source for its colors. let series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", seriesTooltipTarget: "bullet", tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal" }) }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", seriesTooltipTarget: "bullet", tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal" }) }) ); Orientation ----------- Depending on the situation, tooltip can be shown above, below, to the left, or to the right of the target point. The defaults differ for various elements, but we can control it by explicitly setting tooltip's `pointerOrientation`. let series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal" }) }) ); var series = chart.series.push( am5xy.LineSeries.new(root, { xAxis: xAxis, yAxis: yAxis, valueYField: field, valueXField: "date", tooltip: am5.Tooltip.new(root, { pointerOrientation: "horizontal" }) }) ); | Orientation | Example #1 | Example #2 | | --- | --- | --- | | `"horizontal"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_left1.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_right2.png) | | `"left"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_left1.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_left2.png) | | `"right"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_right1.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_right2.png) | | `"vertical"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_down1.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_down2.png) | | `"down"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_down1.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_down2.png) | | `"up"` | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_up1.png) | ![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2021/09/pointerposition_up2.png) | See the Pen by amCharts team (@amcharts) on CodePen. Position -------- ### Without cursor For elements that have width and height (e.g. columns), it's possible to set the point its tooltip will be anchored to. For that we have `tooltipX` and `tooltipY` settings, which can either be absolute pixel value or percent value relative to target element's width or height, respectively. For example, if we would like to display tooltip anchored to the upper-right corner of a column, we'd do something like this: columnSeries.columns.template.setAll({ tooltipX: am5.percent(100), tooltipY: am5.percent(0), tooltipText: "{categoryX}: {valueY}" }); columnSeries.columns.template.setAll({ tooltipX: am5.percent(100), tooltipY: am5.percent(0), tooltipText: "{categoryX}: {valueY}" }); See the Pen Tooltip orientation by amCharts team (@amcharts) on CodePen. ### With cursor Controlling tooltip position is not possible when used with chart cursor. When enabled, cursor is responsible for arranging multiple tooltips and will usually point to exact place of the data item, regardless of the shape of the related series element. API usage --------- We can trigger showing of a tooltip on an element programmatically, too. Every element has a method `showTooltip()`. All we need to do is to call it: columnSeries.columns.getIndex(1).showTooltip(); columnSeries.columns.getIndex(1).showTooltip(); The above will trigger tooltip for the second column in a column series. Sticky tooltips --------------- Normally, tooltips are shown only when the target element is hovered or touched. We can make them show all the time, without any interactions. For that, we will need: 1. Create a separate instance of a tooltip for the element (because elements share tooltips). 2. Set `showTooltipOn: "always"` setting for the element. chart.zoomOutButton.setAll({ tooltipText: "Click to zoom out", showTooltipOn: "always", tooltip: am5.Tooltip.new(root, {}) }); chart.zoomOutButton.setAll({ tooltipText: "Click to zoom out", showTooltipOn: "always", tooltip: am5.Tooltip.new(root, {}) }); The above will make tooltip appear over XY chart's zoom out button constantly. ### On bullets Creating sticky tooltips for bullets is easy, because we use custom functions that create a bullet: series.bullets.push(function () { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill"), stroke: root.interfaceColors.get("background"), strokeWidth: 2, tooltipText: "{valueY}", showTooltipOn: "always", tooltip: am5.Tooltip.new(root, {}) }) }); }); series.bullets.push(function () { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: series.get("fill"), stroke: root.interfaceColors.get("background"), strokeWidth: 2, tooltipText: "{valueY}", showTooltipOn: "always", tooltip: am5.Tooltip.new(root, {}) }) }); }); See the Pen amCharts 5: Sticky tooltips on bullets by amCharts team (@amcharts) on CodePen. ### On series element templates Adding sticky tooltips to series elements (e.g. columns) via templates is trickier. We will need to use [template's `setup` handler](https://www.amcharts.com/docs/v5/concepts/settings/list-templates/#Setup_handler) for that. series.columns.template.setAll({ tooltipText: "{name}, {categoryX}:{valueY}", width: am5.percent(90), tooltipY: 0, tooltipText: "{categoryX}: {valueY}", showTooltipOn: "always" }); series.columns.template.setup = function(target) { target.set("tooltip", am5.Tooltip.new(root, {})); } series.columns.template.setAll({ tooltipText: "{name}, {categoryX}:{valueY}", width: am5.percent(90), tooltipY: 0, tooltipText: "{categoryX}: {valueY}", showTooltipOn: "always" }); series.columns.template.setup = function(target) { target.set("tooltip", am5.Tooltip.new(root, {})); } See the Pen amCharts 5: Sticky tooltips on columns by amCharts team (@amcharts) on CodePen. Tooltips on labels ------------------ If we need rollover tooltips to be displayed on a label, there is one additional step needed besides setting its `tooltipText`: make label interactive by adding a background to it. If we don't need an actual background, we can make it full transparent. The following snippet will add tooltip to the pie chart's slice labels: series.labels.template.set("tooltipText", "{category}: {value}"); series.labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 })); } series.labels.template.set("tooltipText", "{category}: {value}"); series.labels.template.setup = function(target) { target.set("background", am5.Rectangle.new(root, { fill: am5.color(0x000000), fillOpacity: 0 })); } See the Pen Adding tooltips to pie chart slice labels by amCharts team (@amcharts) on CodePen. MORE INFOFor more information on label interactivity refer to "[Labels as interactive elements](https://www.amcharts.com/docs/v5/concepts/common-elements/labels/#labels-as-interactive-elements) " tutorial. HTML in tooltips ---------------- Please refer to "HTML content: [Tooltips](https://www.amcharts.com/docs/v5/concepts/common-elements/html-content/#Tooltips) " for more information. Tooltips outside chart area --------------------------- Normally, tooltips are constrained to the area of the actual chart. This may not work for small charts that are unable to fit tooltips. 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 } }); [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/2022-09-27_13-32-50-1024x547.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/2022-09-27_13-32-50.png) Default behavior [![](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/chrome_2022-09-27_13-32-25-1024x547.png)](https://www.amcharts.com/docs/v5/wp-content/uploads/sites/7/2022/09/chrome_2022-09-27_13-32-25.png) Using `tooltipContainerBounds` See the Pen Expanded tooltip area by amCharts team (@amcharts) on CodePen. Related tutorials ----------------- * [Combining tooltip values from multiple series](https://www.amcharts.com/docs/v5/tutorials/combining-tooltip-values-from-multiple-series/) * [Constraining tooltip to plot container bounds](https://www.amcharts.com/docs/v5/tutorials/constraining-tooltip-to-plot-container-bounds/) * [Tooltip with a pointer on the side](https://www.amcharts.com/docs/v5/tutorials/tooltip-with-a-pointer-on-the-side/) --- # Formatters – amCharts 5 Documentation Formatters are helper objects that allow setting generic rules for tailoring text output - dates, numbers - with additional functionality of in-line styles. Formatters are represented by their respective objects that are available globally in chart's [root element](https://www.amcharts.com/docs/v5/getting-started/#Root_element) , and can also be set individually on each object. Global formatters ----------------- Each chart's root element comes with pre-created formatters accessible via properties `[numberFormatter](https://www.amcharts.com/docs/v5/reference/root/#numberFormatter_property) `, `[dateFormatter](https://www.amcharts.com/docs/v5/reference/root/#dateFormatter_property) `, and `[durationFormatter](https://www.amcharts.com/docs/v5/reference/root/#durationFormatter_property) `. We can use those instances to set global settings such as number or date formats. root.numberFormatter.set("numberFormat", "#,###.00"); root.numberFormatter.set("numberFormat", "#,###.00"); Local formatters ---------------- In addition to global formatters, each element can have it's own number or date formatter, settable via `[numberFormatter](https://www.amcharts.com/docs/v5/reference/sprite/#numberFormatter_setting) `, `[dateFormatter](https://www.amcharts.com/docs/v5/reference/sprite/#dateFormatter_setting) `, and `[durationFormatter](https://www.amcharts.com/docs/v5/reference/sprite/#durationFormatter_setting) ` settings. This is useful, when we need to use formatting settings different from global ones, for a particular object, e.g. an axis: yAxis.set("numberFormatter", am5.NumberFormatter.new(root, { "numberFormat": "#,###.00" }); yAxis.set("numberFormatter", am5.NumberFormatter.new(root, { "numberFormat": "#,###.00" }); If a formatter is set directly on an element setting, it will use local formatter instead of a global one. Formatter inheritance --------------------- Formatters are **not** inheritable. This means that if an element parent does had local formatter set, its child will still use global formatter. Formatting text --------------- ### Applying number and date formats Whenever needed, charts will turn to a respective formatter to format specific value, e.g. a number or a date. For example, various axes types have their own logic on how to format numbers or dates, so they will use formatters for it. For more information about number and date formats, refer to these tutorials: * [Formatting numbers](https://www.amcharts.com/docs/v5/concepts/formatters/formatting-numbers/) * [Formatting date and time](https://www.amcharts.com/docs/v5/concepts/formatters/formatting-dates/) * [Formatting durations](https://www.amcharts.com/docs/v5/concepts/formatters/formatting-durations/) ### Data placeholders Data placeholders are codes (names in curly brackets) in text that can be replaced with an actual value from data or objects settings. In some cases values, displayed in place of placeholders will need to be formatted. In such cases formatters will also be used. Example of a data placeholder: tooltip.label.set("text", "{name}\\n{valueX}: {valueY}"); tooltip.label.set("text", "{name}\\n{valueX}: {valueY}"); For more information about data placeholders, refer to this tutorial: * [Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) ### Text styling Each text can contain in-line styling instructions, enclosed in square brackets. Example, of an in-line styling being applied: tooltip.label.set("text", "\[bold\]{name}\[/\]\\n{valueX}: {valueY}"); tooltip.label.set("text", "\[bold\]{name}\[/\]\\n{valueX}: {valueY}"); For more information about in-line text styling, refer to this tutorial: * [Text styling](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) --- # Modal popups – amCharts 5 Documentation amCharts 5 has a built-in way to display modal popups over the area of a Root element. Creating -------- To create a modal popup, we just need to instantiate a `Modal` class instance using its `new()` syntax. It takes a single setting: `content`, which holds HTML to display in the modal: let modal = am5.Modal.new(root, { content: "

Hello, I'm modal!

Nice to meet you.

" }); var modal = am5.Modal.new(root, { content: "

Hello, I'm modal!

Nice to meet you.

" }); Opening ------- To open the modal, use its `open()` method: modal.open(); modal.open(); Closing and cancelling ---------------------- Simirally, to close it, use `close()`: modal.close(); modal.close(); A modal can also be "cancelled" by pressing an ESC key, or calling its `cancel()` method. There's no functional difference between the two (modal will close in either case), except closing will generate `"closed"` event, whereas cancelling will trigger `"cancelled"`. Disposing --------- When modal object is no longer needed, make sure you `dispose()` it: modal.dispose(); modal.dispose(); Events ------ Modal has three event types: | Event | Comment | | --- | --- | | `"opened"` | Invoked when a modal opens. | | `"closed"` | Invoked when modal is closed via its `close()` method. | | `"cancelled"` | Invoked when modal is closed via its `cancel()` method or ESC key. | modal.events.on("opened", function(ev) { // A modal has been opened // ... }); modal.events.on("opened", function(ev) { // A modal has been opened // ... }); Modal DOM elements ------------------ Modal consists of several elements representing its main wrapper div, curtain (shaded area covering root element), and content. They are accessible via modal's private settings: | Reference | Comment | | --- | --- | | `modal.getPrivate("wrapper")` | Wrapper `
`. | | `modal.getPrivate("curtain")` | Curtain `
`. | | `modal.getPrivate("content")` | Modal content `
`. | We can use those in any way we want, e.g. styling them, applying classes, or appending other elements. The following code will add two buttons: OK and Cancel, that in respectively invoke `close()` and `cancel()` methods. let modal = modal = am5.Modal.new(root, { content: "

Hello, I'm modal!

Nice to meet you.

" }); let modalSetup = false; function openModal() { if (!modalSetup) { let okButton = document.createElement("input"); okButton.type = "button"; okButton.value = "OK"; okButton.addEventListener("click", function() { modal.close(); }); let cancelButton = document.createElement("input"); cancelButton.type = "button"; cancelButton.value = "Cancel"; cancelButton.addEventListener("click", function() { modal.cancel(); }); modal.getPrivate("content").appendChild(okButton); modal.getPrivate("content").appendChild(cancelButton); modalSetup = true; } modal.open(); } function closeModal() { if (modal) { modal.close(); } } var modal = modal = am5.Modal.new(root, { content: "

Hello, I'm modal!

Nice to meet you.

" }); var modalSetup = false; function openModal() { if (!modalSetup) { var okButton = document.createElement("input"); okButton.type = "button"; okButton.value = "OK"; okButton.addEventListener("click", function() { modal.close(); }); var cancelButton = document.createElement("input"); cancelButton.type = "button"; cancelButton.value = "Cancel"; cancelButton.addEventListener("click", function() { modal.cancel(); }); modal.getPrivate("content").appendChild(okButton); modal.getPrivate("content").appendChild(cancelButton); modalSetup = true; } modal.open(); } function closeModal() { if (modal) { modal.close(); } } Example ------- See the Pen Untitled by amCharts team (@amcharts) on CodePen. --- # Formatting durations – amCharts 5 Documentation This tutorial takes a look at duration formatter - helper object used to format numbers as duration throughout the chart. Formatter object ---------------- Duration formatter object is accessible globally via chart [root element](https://www.amcharts.com/docs/v5/getting-started/#Root_element) 's `durationFormatter` property. We can use it to set `durationFormat`, as well as a few of other related settings, that will be used whenever number needs to be formatted as a duration in the chart. Where is it used? ----------------- Duration formatter is used in a number of places throughout the chart. The most notable user for duration formatter is a duration axis (`DurationAxis`). Also, labels (e.g. in tooltips) with date [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) will turn to duration formatter to format their values where applicable. Data export functionality will also use duration formatter to format its output of duration values. Global duration formats ----------------------- ### Base unit Formatting duration from a numeric value requires knowledge of what the value represents. It can represent millisecond, second, minute, hour, day, etc. We call it a "base unit", and can set it globally using global duration formatter's `baseUnit` setting: root.durationFormatter.set("baseUnit", "hour"); root.durationFormatter.set("baseUnit", "hour"); Available base unit values are: `"millisecond"`, `"second"`, `"minute"`, `"hour"`, `"day"`, `"week"`, `"month"`, and `"year"`. ### Default format There are two ways to set duration formats on a duration formatter: * A universal duration format which will be applied to all values that need to be formatted as a duration. * A list of duration formats tailored for each base unit. A global duration formatter will already have its `durationFormats` pre-set to a default values, that may depend on the [locale](https://www.amcharts.com/docs/v5/concepts/locales/) your chart is using, whereas the universal duration format won't be set. ### Setting default format If we want to set universal duration format throughout the chart, we can set formatter's `durationFormat` setting: root.durationFormatter.set("durationFormat", "mm:ss"); root.durationFormatter.set("durationFormat", "mm:ss"); We can also override formats for specific base units by modifying its `durationFormats` setting: root.durationFormatter.get("durationFormats")\["hour"\] = { hour: "hh'h'", day: "d'd' hh'h'", week: "d'd' hh'h'", month: "M'm' dd'd' hh'h'", year: "y'y' MM'm' dd'd' hh'h'" } root.durationFormatter.get("durationFormats")\["hour"\] = { hour: "hh'h'", day: "d'd' hh'h'", week: "d'd' hh'h'", month: "M'm' dd'd' hh'h'", year: "y'y' MM'm' dd'd' hh'h'" } The multiple entries can be used by a duration axis to use different duration formats for different granularities of grid/labels. For example if we have a duration axis that represents duration values with base unit as seconds. If axis spans just a few seconds or minutes, we might want to display durations formatted as `mm:ss`, however, if the scope is several hours, we might revert to hourly granularity, so `hh:mm` format might be more appropriate. ### Formatting data placeholders The values that will be shown in place of the placeholder will be formatted according to formatting settings as set out in global formatters or in-line functions. We can set names of the data placeholders that hold numbers and need to be formatted as such via global formatter's `durationFields` setting: root.durationFormatter.setAll({ baseUnit: "second", durationFormat: "mm:ss", durationFields: \["valueY"\] }); root.durationFormatter.setAll({ baseUnit: "second", durationFormat: "mm:ss", durationFields: \["valueY"\] }); For more information on how it works, please refer to "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorial. Format codes ------------ The following table outlines codes that can be used in duration formats. IMPORTANTCodes are case-sensitive. | Code | Comment | | --- | --- | | y | Years (a year is 365 days) | | M | Months (a month is 31 days) | | w | Weeks (a week is 7 days) | | d | Days (a day is 24 hours) | | h | Hours (an hour is 60 minutes) | | m | Minutes (a minute is 60 seconds) | | s | Seconds (a second is 1000 milliseconds) | | S | Milliseconds | | a | Special indicator that must always go after other codes. Indicates that absolute value should be used. (no minus sign) | | ' (single quote) | Text enclosed in single quotes will be treated as text and will be displayed as is without parsing it for codes | Styling text ------------ Text formats can also include in-line styling instructions: root.durationFormatter.set("durationFormat", "\[bold\]mm:ss"); root.durationFormatter.set("durationFormat", "\[bold\]mm:ss"); Please refer to the "[Text styling and data binding](https://www.amcharts.com/docs/v5/concepts/formatters/in-line/) " tutorial for more info. Escaping -------- ### Quotes To explicitly make formatter ignore a portion of text, enclose it within single quotes: `"d'days' hh'hours'"` The `"days"` and `"hours"` above will not be parsed when being processed by a date formatter. It will be left as is: `10 days 20 hours` To use a single quote (either within quoted text or outside it) add single quote twice: `"d'day''s'"` Will result in: `5 day's` Duration axis ------------- Chart's duration axes will use global duration formatter and its settings: `baseUnit`, `durationFormat`, and `durationFormats`. The base unit can be overridden for each individual duration axis using its own `baseUnit` setting. For more information, refer to "[Duration axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/duration-axis/) " tutorial. --- # Formatting numbers – amCharts 5 Documentation This tutorial takes a look at number formatter - helper object used to format numbers throughout the chart. Formatter object ---------------- Number formatter object is accessible globally via chart [root element](https://www.amcharts.com/docs/v5/getting-started/#Root_element) 's `numberFormatter` property. We can use it to set `numberFormat`, as well as a few of other related settings, which will be used whenever number needs to be formatted in the chart. Where is it used? ----------------- Number formatter is used in a number of places throughout the chart. Some components like value axis and legend use their own logic to apply number formatting. Labels (e.g. in tooltips) with numeric [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) will turn to number formatter to format their values. Data export functionality will also use number formatter to format its output of numeric values. Global number format -------------------- ### Default format A global number formatter will already have its `numberFormat` set to a default value, which may depend on the [locale](https://www.amcharts.com/docs/v5/concepts/locales/) your chart is using. ### Setting default format Number format is set via formatter's `numberFormat` setting: root.numberFormatter.set("numberFormat", "#,###.00"); root.numberFormatter.set("numberFormat", "#,###.00"); ### Formatting data placeholders The values that will be shown in place of the placeholder will be formatted according to formatting settings as set out in global formatters or in-line functions. We can set names of the data placeholders that hold numbers and need to be formatted as such via global formatter's `numericFields` setting: root.numberFormatter.setAll({ numberFormat: "#,###.00", numericFields: \["valueY"\] }); root.numberFormatter.setAll({ numberFormat: "#,###.00", numericFields: \["valueY"\] }); For more information on how it works, please refer to "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorial. Format codes ------------ Number formatting in amCharts is loosely based on Unicode standard. | Code | Description | | --- | --- | | # | Indicates passive number. Formatter will round to a number of #’s but will not pad with zeros.
Example format: `#.##`
`1.125` > `1.13`
`1.5` > `1.5` | | 0 (zero) | Active number. Formatter will round decimals to a number of zeros. If the length of decimals or integers is less than number of active numbers, the formatter will pad the number with zeros.   Example format: `00.00` `1.125` > `01.13`
`1.5` > `01.50` | | . (dot) | Indicates a decimal place.   Important: if dot is missing, the formatter will not round or format decimals, and will display the number as is. This may result in large numbers. If the number format ends with a dot, the number will be rounded to the nearest integer.

Example format: `#.`
`1.125` > `1`
`1.5` > `2`

Example format: `#`
`1.125` > `1.125`
`1.5` > `1.5` | | , (comma) | Indicates thousand separator place. This is used to determine home many digits to consider a "thousand". Only the rightmost comma will be used.

Example format: `#,###`
`12345` > `1,2345`
`123456789` > `1,2345,6789` | | e | Convert the number into scientific (exponential) format.   Important: Must go at the end of the format.

Example format: `#.##e`
`77.1234` > `7.71e+1`
`123456789` > `1.23e+8`
`0.0000000123` > `1.23e-8` | | a | Recalculates very big and very small numbers by reducing their length according to rules and applying suffix/prefix.   Important: Must go at the end of the format. The suffixes ("K", "M", "G", etc.) are translatable via language files.

Example format: `#.0a`
`1000` > `1.0K`
`5500` > `5.5K`
`5000000` > `5.0M`
`5000000000` > `5.0G`
`0.0015` > `1.5m`
`0.0000015` > `1.5μ`
`0.0000000015` > `1.5n`

Refer to "[Large and small numbers](https://www.amcharts.com/docs/v5/concepts/formatters/formatting-numbers/#Large_and_small_numbers)
" section for more info. | | b | Recalculate to kilobytes, megabytes, etc. and add corresponding suffix.   Important: Must go at the end of the format. The suffixes ("KB", "MB", "GB", etc.) are translatable via language files.

Example format: `#.0b`
`1024` > `1.0KB`
`5000` > `4.9KB`
`500000` > `488.3KB`
`500000000` > `476.8MB`

Refer to "[Byte size modifier](https://www.amcharts.com/docs/v5/concepts/formatters/formatting-numbers/#Byte_size_modifier)
" section for more info. | | s | Display an absolute number. (without the minus sign)   Important: Must go at the end of the format.

Example format: `#.0s`
`1000` > `1.0`
`-1000` > `1.0` | | ‘ (single quote) | Enclose any text you don’t want to be parsed for format options into quotes quotes. It will be included in the formatted output as is. (minus the the quotes)   If you need to display actual single quote, include it twice. This works both within and outside quoted text.

Example format: `'The value is:' #,###.00 '(in million US$)'`
`1000` > `The value is: 1,000.00 (in million US$)` | | % | Multiple the number by 100 and display as percentage. A percent sign will be added either before or after the number, as per locale. | | ‰ | Multiple the number by 1000 and display as per mile | | p | Same as "%" except value is not multiplied by 100. A percent sign will be added either before or after the number, as per locale. | | ! | Works only in conjunction with `a` and `b` modifiers. If present it will "force" application of the minimum/maximum prefixes even if the number does not fit into smallest denomination, e.g. `500` as `"0.5K"`. | ### Examples | Format | Input value | Output | | --- | --- | --- | | `#,###.##` | 1000.125 | 1,000.13 | | `#,###.00` | 1000 | 1,000.00 | | `000.00` | 10 | 010.00 | Positive/negative numbers ------------------------- To apply different formatting to positive, negative and zeros, use | (vertical bar) to separate formats. (in that order). `[positive format] | [negative format] | [zero format]` | Format | Input value | Output | | --- | --- | --- | | `#,###\|(#,###s)\|'-'` | 1000 | 1000 | | `#,###\|(#,###s)\|'-'` | \-1000 | (1000) | | `#,###\|(#,###s)\|'-'` | 0 | \- | Large and small numbers ----------------------- ### Large/small number modifier The grouping of digits is turned on with an `"a"` modifier in the number format. | Format | Input value | Output | | --- | --- | --- | | `#a` | 1000 | 1k | | `# a` | 1000 | 1 k | | `#a` | 1000000 | 1M | | `#a` | 0.001 | 1m | | `# a` | 0.001 | 1 m | | `#a` | 0.000001 | 1μ | The actual suffixes added after formatted number may depend on the [locale](https://www.amcharts.com/docs/v5/concepts/locales/) your chart is using. NOTE A modifier can be preceded with a space character. If it is, the space will be added before the actual suffix as well. ### Custom big/small number grouping We can modify which particular large and small number groups numbers are grouped into using formatters' `bigNumberPrefixes` and `smallNumberPrefixes` settings: root.numberFormatter.setAll({ numberFormat: "#a", // Group only into M (millions), and B (billions) bigNumberPrefixes: \[\ { "number": 1e+6, "suffix": "M" },\ { "number": 1e+9, "suffix": "B" }\ \], // Do not use small number prefixes at all smallNumberPrefixes: \[\] }); root.numberFormatter.setAll({ numberFormat: "#a", // Group only into M (millions), and B (billions) bigNumberPrefixes: \[\ { "number": 1e+6, "suffix": "M" },\ { "number": 1e+9, "suffix": "B" }\ \], // Do not use small number prefixes at all smallNumberPrefixes: \[\] }); ### Small number threshold Normally, any number less than `1` (one) is treated as a small number. We can change it using formatters `smallNumberThreshold` setting: root.numberFormatter.setAll({ numberFormat: "#a", smallNumberThreshold: 0.001 }); root.numberFormatter.setAll({ numberFormat: "#a", smallNumberThreshold: 0.001 }); The above means that regardless of `smallNumberPrefixes`, small number format will not be applied unless number is less than `0.001`. Byte size modifier ------------------ Modifier `"b"` can be used to format byte size number grouping. | Format | Input value | Output | | --- | --- | --- | | `#.0b` | 1024 | 1.0KB | | `#.0b` | 5000 | 4.9KB | | `#.0b` | 500000 | 488.3KB | | `#.0b` | 500000000 | 476.8MB | The actual suffixes added after formatted number may depend on the [locale](https://www.amcharts.com/docs/v5/concepts/locales/) your chart is using. ### Custom byte groups We can modify byte groups using formatters' `bigNumberPrefixes` and `smallNumberPrefixes` settings: root.numberFormatter.setAll({ numberFormat: "#.0b", // Group only into MB (megabytes), and GB (gigabytes) bytePrefixes: \[\ { "number": 1048576, "suffix": "MB" },\ { "number": 1073741824, "suffix": "GB" }\ \] }); root.numberFormatter.setAll({ numberFormat: "#.0b", // Group only into MB (megabytes), and GB (gigabytes) bytePrefixes: \[\ { "number": 1048576, "suffix": "MB" },\ { "number": 1073741824, "suffix": "GB" }\ \] }); Styling text ------------ Text formats can also include in-line styling instructions: root.numberFormatter.set("numberFormat", "\[bold\]#,###.00"); root.numberFormatter.set("numberFormat", "\[bold\]#,###.00"); | Format | Input value | Output | | --- | --- | --- | | `[#0f0]#,###` | 1000 | 1000 | | `[#0f0]#,###\|[#f00](#,###)\|[#ccc]'-'` | 1000 | 1000 | | `[#0f0]#,###\|[#f00](#,###)\|[#ccc]'-'` | \-1000 | (1000) | | `[#0f0]#,###\|[#f00](#,###)\|[#ccc]'-'` | 0 | \- | Please refer to the "[Text styling](https://www.amcharts.com/docs/v5/concepts/formatters/text-styling/) " and "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorials for more info. Escaping -------- ### Quotes To explicitly make formatter  ignore a portion of text, enclose it within single quotes: `'Element # is' #.000` The `"Element # is"` above will not be parsed when being processed by NumberFormatter. It will be left as is: `Element # is 12.000` Any text enclosed in single quotes will be displayed as is, without applying formatting to it. To use a single quote (either within quoted text or outside it) add single quote twice: `'Element ''#'' is' #.000` Will result in: `Element '#' is 12.000` ### Vertical bar As we saw earlier in this article,  a vertical bar "|" in number formats represents different version of the format to be applied for negative, positive and zero values. If you need to explicitly use a vertical bar in your formatted text, just like with quotes, escape it with an additional vertical bar: `Positive || #,###|Negative ||(#,###a)|'-'` ### Square and curly brackets Square and curly brackets have special meaning in formatting text labels as well. Please refer to the "[Text styling and data binding](https://www.amcharts.com/docs/v5/concepts/formatters/in-line/) " tutorial for more info. Using Intl object formats ------------------------- Number formats can be specified using JavaScript's built-in `Intl` object. Please refer to "[Formatting date/time and numbers using “Intl” object](https://www.amcharts.com/docs/v5/tutorials/formatting-date-time-and-numbers-using-intl-object/) " for further information. Formats on a value axis ----------------------- Value axis has two additional settings that can be used to set number format for the axis alone, without affecting the rest of the chart: `numberFormat` and `tooltipNumberFormat`. For more information on how to use them, refer to "Value axis: [Label format](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/#Label_format) " and "Value axis: [Tooltip number format](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/#Tooltip_number_format) ". --- # Data placeholders – amCharts 5 Documentation Data placeholders are special codes in strings, enclosed in curly brackets, that are replaced with actual data or a value of property/setting of a target element or its ancestor. Placeholders in labels ---------------------- Data placeholders are represented by a name enclosed in a curly bracket, e.g. `{valueY}`. They can go into any place of the `text` setting of a `Label`. When encountered a placeholder, a label will look for such name in the following order: 1. Its data item properties (if available). 2. Its data context (if available). 3. Its own settings and properties. 4. Settings and properties of its parent elements. Here's an example of a data placeholder used in the series tooltip: let tooltip = series.set("tooltip", am5.Tooltip.new(root, {})); tooltip.label.set("text", "{name}\\n{valueX}: {valueY}"); var tooltip = series.set("tooltip", am5.Tooltip.new(root, {})); tooltip.label.set("text", "{name}\\n{valueX}: {valueY}"); The above is most likely result in: * `{name}` will be replaced with the parent series' `name` setting. * `{valueX}` will be extracted from elements data item. * `{valueY}` will be extracted from elements data item. Multi-level placeholders ------------------------ Placeholders can access any property of the element's object, at any level, by using dot notation in its name, e.g.: tooltip.label.set("text", "{foo.bar}"); tooltip.label.set("text", "{foo.bar}"); The above will look up `foo` in all of the mentioned places, will check if it's an object, then will look up `bar` among its properties. This is useful, when we have custom objects in data, e.g.: \[{\ category: "A1",\ value: 100,\ foo: {\ bar: "Hello"\ }\ }, {\ category: "A2",\ value: 200,\ foo: {\ bar: "Hola"\ }\ }\] Formatting placeholders ----------------------- Normally, placeholder will be replaced with a raw value, converted to a string, which might not be the best scenario for numbers or date/time which we might need to format in a certain way. ### Setting global formats We can use [global formatters](https://www.amcharts.com/docs/v5/concepts/formatters/#Global_formatters) to automatically apply formats to our placeholders. To make that work, we need to set up formatters for two things: * Format to use. * Fields to apply format to. | Formatter | Format setting | Field setting | | --- | --- | --- | | `root.numberFormatter` | `numberFormat` (string) | `numericFields` (array of strings) | | `root.dateFormatter` | `dateFormat` (string) | `dateFields` (array of strings) | | `root.durationFormatter` | `durationFormat` (string) | `durationFields` (array of strings) | Here's an example: root.numberFormatter.setAll({ numberFormat: "#,###.00", numericFields: \["valueY"\] }); root.dateFormatter.setAll({ dateFormat: "yyyy-MM-dd", dateFields: \["valueX"\] }); root.durationFormatter.setAll({ baseUnit: "second", durationFormat: "mm:ss", durationFields: \["valueY"\] }); root.numberFormatter.setAll({ numberFormat: "#,###.00", numericFields: \["valueY"\] }); root.dateFormatter.setAll({ dateFormat: "yyyy-MM-dd", dateFields: \["valueX"\] }); root.durationFormatter.setAll({ baseUnit: "second", durationFormat: "mm:ss", durationFields: \["valueY"\] }); ### In-line formatting We can use in-line formatting functions `formatNumber()`, `formatDate()`, and `formatDuration()` within the placeholder, too. let tooltip = series.set("tooltip", am5.Tooltip.new(root, {})); tooltip.label.set("text", "{valueX.formatDate()}: {valueY.formatNumber()}"); var tooltip = series.set("tooltip", am5.Tooltip.new(root, {})); tooltip.label.set("text", "{valueX.formatDate()}: {valueY.formatNumber()}"); This negates the need to use `numericFields` or `dateFields` as placeholder now carries specific instruction which formatter to use on its value. Using in-line functions, we can also specify the format: let tooltip = series.set("tooltip", am5.Tooltip.new(root, {})); tooltip.label.set("text", "{valueX.formatDate('yyyy-MM-dd')}: {valueY.formatNumber('#.000')}"); var tooltip = series.set("tooltip", am5.Tooltip.new(root, {})); tooltip.label.set("text", "{valueX.formatDate('yyyy-MM-dd')}: {valueY.formatNumber('#.000')}"); This will make formatter use specific format, regardless of the global setting. --- # Text styling – amCharts 5 Documentation Any text in amCharts 5 can be styled with in-line codes. This tutorial will show how. Style blocks ------------ ### Opening block Style blocks are enclosed in square brackets, and contain style instructions for the text that goes immediately after text until end, or closing block. series.set("tooltipText", "\[#888\]{categoryX}\[/\]: \[bold\]{valueY}\[/\]"); series.set("tooltipText", "\[#888\]{categoryX}\[/\]: \[bold\]{valueY}\[/\]"); ### Closing block The effect of the style block expires if a closing block (`[/]`) is encountered in text. Since style directives can be combined, there's no need to match closing bracket to the opening one. The following is wrong: ~`[bold]...[/bold]`~. The correct usage is `[bold]...[/]`. Closing bracket is also optional. If there's no closing bracket the next opening one the style will be automatically terminated by either next opening style block or end of the string, whichever come first. The following is perfectly valid: `[bold #f00]Value is: [#0f0]{valueY.value}`. ### Available style codes | Code | Example | Comment | | --- | --- | --- | | `bold` | `"I'm a [bold]thick[/] text!"` | Makes enclosed text bold. | | `underline` | `"I'm [underline]underlined[/b]"` | Underlines enclosed text. This feature is experimental. | | Hex color code | `"I'm [#f00]red[/]."` | Applies color to enclosed text. | | `width` | `"[width: 100]Name:[/] Patrick"` | Set minimal width of the block (like tab stop). | | `fontSize` | `"[fontSize: 20px]I'm big![/]"` | Sets [font-size](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size)
for enclosed text. | | `fontVariant` | `"[fontVariant: small-caps]All caps[/]"` | Sets [font-variant](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant)
for enclosed text. | | `fontWeight` | `"[fontWeight: 300]I'm bold(ish).[/]"` | Sets [font-weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight)
for enclosed text. | | `fontStyle` | `"[fontStyle: italic]I'm italic.[/]"` | Sets [font-style](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style)
for enclosed text. | | `fontFamily` | `"[fontFamily: Roboto]I'm a robot![/]"` | Sets [font-family](https://developer.mozilla.org/en-US/docs/Web/CSS/font-family)
for enclosed text. | | `verticalAlign` | `"Copyright[fontSize: 8px; verticalAlign: super;]TM[\]"` | Supports `"super"` and `"sub"` for super- and sub-script. | ### Combining styles Each block can combine several style codes, separated by a space or a semicolon: series.set("tooltipText", "\[#888 fontVariant: small-caps width: 100\]{categoryX}:\[/\] \[bold fontStyle: italic\]{valueY}\[/\]"); series.set("tooltipText", "\[#888 fontVariant: small-caps width: 100\]{categoryX}:\[/\] \[bold fontStyle: italic\]{valueY}\[/\]"); Line breaks ----------- To insert a simple line break use JS-standard `\n` symbol., e.g. `"So it begins...\nand ends on a second line."`. Escaping -------- Let's say we have this text: "Quick \[fox\] jumps over lazy {dog}" That won't work as expected because text in square brackets will be treated as style block, while one in curly brackets - as a data placeholder. Escaping is done by duplicating the bracket: "Quick \[\[fox\]\] jumps over lazy {{dog}}" --- # Events – amCharts 5 Documentation User interactions ----------------- ### Adding a handler To attach an event handler for various user interactions - click, hover, etc. - an an element, we use its event dispatcher, accessible via `events` property. The most common method for the event dispatcher is `on()`: columnSeries.columns.template.events.on("click", function(ev) { console.log("Clicked on a column", ev.target); }); columnSeries.columns.template.events.on("click", function(ev) { console.log("Clicked on a column", ev.target); }); Or, if we want the event to execute only once, we can use `once()` instead: columnSeries.columns.template.events.once("click", function(ev) { console.log("Clicked on a column", ev.target); }); columnSeries.columns.template.events.once("click", function(ev) { console.log("Clicked on a column", ev.target); }); ### Removing a handler To remove a handler, we use `off()` method. Please note that we need to pass in a reference to the function to `off()`, so the anonymous function approach above won't work. fuunction handleColumnClick(ev) { console.log("Clicked on a column", ev.target); } // Add handler columnSeries.columns.template.events.on("click", handleColumnClick); // Remove handler columnSeries.columns.template.events.off("click", handleColumnClick); fuunction handleColumnClick(ev) { console.log("Clicked on a column", ev.target); } // Add handler columnSeries.columns.template.events.on("click", handleColumnClick); // Remove handler columnSeries.columns.template.events.off("click", handleColumnClick); ### Disabling or enabling events To temporarily disable event handlers of certain type, without removing them permanently, use `disableType()`: columnSeries.columns.template.events.disableType("click"); columnSeries.columns.template.events.disableType("click"); To enable event type back, use `enableType()`: columnSeries.columns.template.events.enableType("click"); columnSeries.columns.template.events.enableType("click"); To temporarily disable all event handlers, use `disable()`. To enable all them back on - `enable()`. MORE INFO Please refer to the `[SpriteEventDispatcher](https://www.amcharts.com/docs/v5/reference/spriteeventdispatcher/) ` for a complete list of available methods. Behavioral events ----------------- Some elements might have events that signal some change on it without user's intervention. For example, a Scrollbar might invoke a `rangechanged` event when its selection range changes, whether by dragging its grips or programatically. For a complete list of element's events, see "Events" section in its class reference. Here's a [link](https://www.amcharts.com/docs/v5/reference/scrollbar/#Events) to `Scrollbar` events as an example. Settings value change --------------------- ### Adding Elements settings is a set of key-value pairs that can be set via `set()` property. Most of the configuration in amCharts 5 happens via settings. Read more about it [here](https://www.amcharts.com/docs/v5/concepts/settings/) . We can add a handler whenever a value for a particular setting changes using element's `on()` method: series.on("visible", function(visible, target) { if (visible) { console.log("Series shown", target) } else { console.log("Series hidden", target) } }); series.on("visible", function(visible, target) { if (visible) { console.log("Series shown", target) } else { console.log("Series hidden", target) } }); Similarly, for catching value change of a [private setting](https://www.amcharts.com/docs/v5/concepts/settings/#Private_settings) , we can use the `onPrivate()` method: xAxis.onPrivate("selectionMin", function(value, target) { var start = new Date(value); console.log("Start date changed:", start); }); xAxis.onPrivate("selectionMax", function(value, target) { var end = new Date(value); console.log("End date changed:", end); }); xAxis.onPrivate("selectionMin", function(value, target) { var start = new Date(value); console.log("Start date changed:", start); }); xAxis.onPrivate("selectionMax", function(value, target) { var end = new Date(value); console.log("End date changed:", end); }); ### Removing Turning off value change events are similar to regular events: we can just use `off()` or `offPrivate()` methods. `callback` (second) parameter is optional: if it's specified, only specific key/callback pair will be removed. If callback is not provided, all handlers for the specified settings key will be removed: // Removing specific callback series.off("visible", seriesVisibilityChange); // Removing all handlers for a private setting xAxis.offPrivate("selectionMin"); xAxis.offPrivate("selectionMax"); // Removing specific callback series.off("visible", seriesVisibilityChange); // Removing all handlers for a private setting xAxis.offPrivate("selectionMin"); xAxis.offPrivate("selectionMax"); Related tutorials ----------------- * [Chart ready event](https://www.amcharts.com/docs/v5/getting-started/root-element/#Chart_ready_event) * [Column series events](https://www.amcharts.com/docs/v5/charts/xy-chart/series/column-series/#Events) * [Bullet events](https://www.amcharts.com/docs/v5/concepts/common-elements/bullets/#event-handlers) --- # Formatting dates – amCharts 5 Documentation This tutorial takes a look at date formatter - helper object used to format date/time throughout the chart. Formatter object ---------------- Date formatter object is accessible globally via chart [root element](https://www.amcharts.com/docs/v5/getting-started/#Root_element) 's `dateFormatter` property. We can use it to set `dateFormat`, as well as a few of other related settings, which will be used whenever date needs to be formatted in the chart. Where is it used? ----------------- Date formatter is used in a number of places throughout the chart. Some components like date axis their own logic to apply date formatting. Labels (e.g. in tooltips) with date [data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) will turn to date formatter to format their values. Data export functionality will also use date formatter to format its output of date values. The data processor will also use date formatter to [parse string-based dates](https://www.amcharts.com/docs/v5/concepts/data/#Parsing_dates) . Global date format ------------------ ### Default format A global date formatter will already have its `dateFormat` set to a default value, which may depend on the [locale](https://www.amcharts.com/docs/v5/concepts/locales/) your chart is using. ### Setting default format Date format is set via formatter's `dateFormat` setting: root.dateFormatter.set("dateFormat", "yyyy-MM-dd"); root.dateFormatter.set("dateFormat", "yyyy-MM-dd"); ### Formatting data placeholders The values that will be shown in place of the placeholder will be formatted according to formatting settings as set out in global formatters or in-line functions. We can set names of the data placeholders that hold numbers and need to be formatted as such via global formatter's `dateFields` setting: root.dateFormatter.setAll({ dateFormat: "yyyy-MM-dd", dateFields: \["valueX"\] }); root.dateFormatter.setAll({ dateFormat: "yyyy-MM-dd", dateFields: \["valueX"\] }); For more information on how it works, please refer to "[Data placeholders](https://www.amcharts.com/docs/v5/concepts/formatters/data-placeholders/) " tutorial. Format codes ------------ The following table outlines codes that can be used in date formats. IMPORTANT Codes are case-sensitive. NOTE Pay special attention to year codes. "yyyy" means year. "YYYY" means year of the week. Unless you know otherwise, you should probably always stick with "yyyy" (all lowercase). NOTE The third column ("No.") deserves a little explanation. It indicates the number of times the code symbol can be repeated. For example, if the first row for "M" (month) shows "1..2", it means it can contain either one or two letters of "M". If it contains just one, the numbers will be shown how they are, e.g. 1, 5, 11, if it contains "MM", the resulting number will always be two-digits, e.g. 01, 05, 11. | Period | Code | No. | Example | Comment | | --- | --- | --- | --- | --- | | **era** | G | 1 | AD | Era - Replaced with the Era string for the current date. | | | | | | | | **year** | y | 1..n | 1996 | Calendar year. | | | Y | 1..n | 1997 | Year (of "Week of Year"), used in ISO year-week calendar. May differ from calendar year. | | | u | 1..n | 4601 | Extended year. This is a single number designating the year of this calendar system, encompassing all supra-year fields. For example, for the Julian calendar system, year numbers are positive, with an era of BCE or CE. An extended year value for the Julian calendar system assigns positive values to CE years and negative values to BCE years, with 1 BCE being year 0. | | | | | | | | **quarter** | q | 1 | 3 | Calendar quarter of the year starting from January. | | | | | | | | **month** | M | 1..2 | 09 | Month number. "M" may produce one or two-digit numbers, whereas "MM" will always produce two-digit output, padding with a zero when necessary. | | | | 3 | Sep | Short month abbeviation. | | | | 4 | September | Full month name. | | | | 5 | S | First letter of the month. | | | | | | | | **week** | w | 1..2 | 27 | Week of year. | | | W | 1 | 3 | Week of the month. | | | | | | | | **day** | d | 1..2 | 1 | Day of the month. | | | D | 1..3 | 345 | Day of the year. | | | F | 1 | 2 | Day of Week in Month. The example is for the 2nd Wed in July. | | | g | 1..n | 2451334 | Modified Julian day. This is different from the conventional Julian day number in two regards. First, it demarcates days at local zone midnight, rather than noon GMT. Second, it is a local number; that is, it depends on the local time zone. It can be thought of as a single number that encompasses all the date-related fields. | | | t | 1 | st | Day ordinal: "st", "nd", "rd". | | | | | | | | **weekday** | E | 1..2 | 3 | Day of the week. Using "EE" will prepend day number with a zero. | | | | 3 | Tues | Short weekday name. | | | | 4 | Tuesday | Full weekday name. | | | | 5 | T | First letter of the weekday name. | | | e | 1..2 | 2 | Local day of week. Same as E except numeric value will depend on the local starting day of the week. For this example, Monday is the first day of the week. | | | | 3 | Tues | | | | | 4 | Tuesday | | | | | 5 | T | | | | | | | | | **am/pm** | a | 1 | AM | "AM" or "PM". | | | | 2 | A.M. | "A.M." or "P.M.". | | | | 3 | A | "A" or "P". | | | | | | | | **hour** | h | 1..2 | 11 | Hour \[1-12\]. | | | H | 1..2 | 13 | Hour \[0-23\]. | | | K | 1..2 | 0 | Hour \[0-11\]. | | | k | 1..2 | 24 | Hour \[1-24\]. | | | | | | | | **minute** | m | 1..2 | 59 | Minute. Using "mm" will pad one-digit numbers with a zero. | | | | | | | | **second** | s | 1..2 | 12 | Second. Using "ss" will pad one-digit numbers with a zero. | | | S | 1..n | 3456 | Fractional Second - rounds to the count of letters. (example is for 12.34567) | | | A | 1..n | 69540000 | Milliseconds in day. This field behaves exactly like a composite of all time-related fields, not including the zone fields. As such, it also reflects discontinuities of those fields on DST transition days. On a day of DST onset, it will jump forward. On a day of DST cessation, it will jump backward. This reflects the fact that is must be combined with the offset field to obtain a unique local time value. | | | x | 1 | 1507908460868 | Timestamp (milliseconds since 1970-01-01). | | | n | 1..3 | 029 | Milliseconds. Use one to three for zero padding. This is similar to "S" except number of letters determine padding of numbers instead of rounding. | | | | | | | | **zone** | z | 1 | PT | Time zone. Short wall (generic) time. | | | | 2 | Pacific Time | Time zone. Long wall time. | | | | 3 | PDT | Time zone. Short time zone abbreviation. | | | | 4 | Pacific Daylight Time | Full time zone name. | | | Z | 1 | GMT-08:00 | Time zone in GMT format. | | | | 2 | \-0800 | Time zone in RFC 822 format. | | | | | | | | **other** | i | 1 | 2017-10-14T05:24:17.872Z | Date/time formatted according to [ISO8601 format](http://en.wikipedia.org/wiki/ISO_8601)
. | | | I | 1 | Sat, 14 Oct 2017 05:21:51 GMT | Date/time formatted to a string representation using UTC time zone according to RFC-1123 specification. | ### Examples | Format | Output | | --- | --- | | `yyyy-MM-dd` | 2021-07-17 | | `MMM dt, yyyy` | Jul 17th, 2021 | | `HH:mm` | 14:28 | UTC and time zones ------------------ A number formatter can be made to recalculate all displayed dates into UTC or any other named time zone. For this, we need to set `utc` or `timezone` settings of the root element: root.utc = true; root.utc = true; For more information on setting time zones refer to "Root element: [Time zone](https://www.amcharts.com/docs/v5/getting-started/root-element/#time-zone) ". Styling text ------------ Text formats can also include in-line styling instructions: root.dateFormatter.set("dateFormat", "\[bold\]yyyy-MM-dd"); root.dateFormatter.set("dateFormat", "\[bold\]yyyy-MM-dd"); Please refer to the "[Text styling and data binding](https://www.amcharts.com/docs/v5/concepts/formatters/in-line/) " tutorial for more info. Escaping -------- ### Quotes To explicitly make formatter ignore a portion of text, enclose it within single quotes: `yyyy.MM.dd G 'at' HH:mm:ss zzz` The `"at"` above will not be parsed when being processed by a date formatter. It will be left as is: `2016.09.21 AD at 19:18:01 GMT+3` Any text enclosed in single quotes will be displayed as is, without applying formatting to it. To use a single quote (either within quoted text or outside it) add single quote twice: `HH:mm:ss 'o''clock'` Will result in: `19:18:01 o'clock` Date formatting in charts ------------------------- A date axis has its own special relationship with date formatting. It uses own collection of date formats for various occasions, and will ignore global date settings. Please refer to "[Date axis](https://www.amcharts.com/docs/v5/charts/xy-chart/axes/date-axis/) " tutorial for details. Using Intl object formats ------------------------- Date formats can be specified using JavaScript's built-in `Intl` object. Please refer to "[Formatting date/time and numbers using “Intl” object](https://www.amcharts.com/docs/v5/tutorials/formatting-date-time-and-numbers-using-intl-object/) " for further information. ---