Using Responsive Features

We can't imagine today's web without responsive features. amCharts 4 has a powerful responsive capabilities built into its core.

This tutorial will explain how you can enable, customize and use amCharts 4 responsive features.

How it works

The problem

Imagine your everyday regularly-boring normal chart like this:

Looks good at full size - 900 pixels wide.

Now, let's imagine we'll need to cram it into less space, like 600 pixels:

Columns are kinda crammed together, but the chart is still passable.

Let's go deeper: 400px.

The chart is now bordering of hardly comprehensible. Suddenly we are aware of wasted white space around the chart, and the legend that takes up whopping third of the available area.

Deeper? Alright: 200px.

OK, this is getting ridiculous, but let's try to go even deeper: 100px.

Congratulations! We now have a completely useless chart on our hands.

You may argue, that nobody in their right mind would make chart container that small, and you might be right.

However, we're living in a multi-platform world, where the designer of a website is not in complete control anymore. The web page that looks perfectly fine on desktop, might crumble down like in the above examples when viewed on a phone, that uses much lesser resolution.

Responsive solution

Responsive features in amCharts 4 allow overriding and dynamically changing certain settings or features of the chart based on the actual available space.

For example, we could have made our chart look better if we got rid of padding and legend when space is scarce. Axis labels could go inside plot area, further saving us space.

This dynamic transformation is controlled using Responsive Rules. We're just going to call them "Rules" from now on.

A Rule is basically an object that does two things:

  1. Checks if current chart parameters matches certain conditions, i.e. "chart's actual width is less than 400 pixels";
  2. Generates a "State" object which has to be applied if the Rule is relevant.

This allows us to create chart once, and make it automatically adapt to various conditions.

Enabling

Responsive settings in amCharts 4 are set via responsive property of the chart, which is an object of the type Responsive.

Since those are disabled by default, all we need to do in order to enable them is to set enabled = true:

chart.responsive.enabled = true;
chart.responsive.enabled = true;
{
// ...
"responsive": {
"enabled": true
}
}

That's it. Our chart is now responsive-aware. Let's see how we can use that.

Using default rules

Simply enabling responsive features will make an amCharts-curated set of default rules kick in.

Below table lists generic rules along the size break points when they kick in.

NOTE The effect of the multiple rules are cumulative, meaning that all "relevant" rules will be applied. E.g. for a chart that is 80px wide, both width <= 200 and width < 100 rules apply.

List of default rules

Element Breakpoint Comment
Chart itself width <= 200 / height <= 200 Horizontal / vertical padding reduced to 10px.
Scrollbars are disabled.
width <= 100 / height <= 100 Horizontal / vertical padding set to 0.
Axes width <= 200 / height <= 200 Horizontal / vertical axis labels are placed inside plot area.
Grid is disabled.
width <= 100 / height <= 100 Horizontal / vertical axis labels are disabled.
XY Series width <= 200 and height <= 200 Bullets are disabled.
Percent Series (Pie, Funnel, Pyramid) width <= 200 or height <= 200 Labels and ticks are disabled.
Legend width <= 200 Move legend to right.
height <= 200 Move legend to bottom.
width <= 200 and height <= 200 Disable legend.

Disabling default rules

If you don't want default any rules applied, simply set useDefault = false.

Adding custom rules

What is a Rule

chart.responsive object has a property rules which is a list of Rules. A Rule is an object that corresponds to the IResponsiveRule interface, which means it has to have at least two methods:

  • relevant(target) - it is called so the rule can do its own calculations to determine whether it is relevant for the current situation;
  • state(target, stateId) - it is called when Responsive asks the Rule to generate a State that needs to be applied to the object if the Rule is currently relevant. (as determined by relevant() call)

REQUIRED READING Responsive works by applying states to various objects of the chart. States is a concept of temporarily applying set of property values to an object. For more information, please read our "Sates" article.

Creating Rules

To create a new Rule, we create a new object, with two methods: relevant and state, then push() it into chart.responsive.rules:

chart.responsive.rules.push({
relevant: function(target) {
// Code that determines if rule is currently relevant
// and returns true or false
return false;
},
state: function(target, stateId) {
// Code that creates a new SpriteState object to be
// applied to target if Rule is "relevant"
return;
}
});
chart.responsive.rules.push({
relevant: function(target) {
// Code that determines if rule is currently relevant
// and returns true or false
return false;
},
state: function(target, stateId) {
// Code that creates a new SpriteState object to be
// applied to target if Rule is "relevant"
return;
}
});
{
// ...
"responsive": {
"enabled": true,
"rules": [{
relevant: function(target) {
// Code that determines if rule is currently relevant
// and returns true or false
return false;
},
state: function(target, stateId) {
// Code that creates a new SpriteState object to be
// applied to target if Rule is "relevant"
return;
}
}]
}
}

Right now, the Rule above, does nothing. Let's try tackling issues with our chart above, one by one.

Base chart

Let's start with a base chart at 400 by 400 px:

See the Pen amCharts 4: Responsive (1) by amCharts (@amcharts) on CodePen.24419

Technically, it's still usable, however the space is not used efficiently.

Adding Rule relevancy check

First, we need to add code which checks whether the Rule is relevant under current chart conditions.

As we explained earlier, Rule's relevant method is responsible for just that.

Let's add a check whether chart is 400 pixel wide or less:

relevant: function(target) {
if (target.pixelWidth <= 400) {
return true;
}
return false;
}
relevant: function(target) {
if (target.pixelWidth <= 400) {
return true;
}
return false;
}

A relevant() method will receive a reference to object our responsive object is attached to - the chart.

We are using chart's pixelWidth property (which returns current chart in pixels) to check whether it is 400px wide or less.

Using pre-defined named breakpoints

Instead of specifying pixel values and defining functions, you can use built-in pre-defined breakpoints, accessible via am4core.ResponsiveBreakpoints static class.

You can use its static pixel values:

Accessible via Value
am4core.ResponsibleDefaults.XXS 100
am4core.ResponsibleDefaults.XS 200
am4core.ResponsibleDefaults.S 300
am4core.ResponsibleDefaults.M 400
am4core.ResponsibleDefaults.L 600
am4core.ResponsibleDefaults.XL 800
am4core.ResponsibleDefaults.XXL 1000

Or via "relevant"-compatible functions:

Accessible via Check
am4core.ResponsibleDefaults.widthXXS width <= 100
am4core.ResponsibleDefaults.widthXS width <= 200
am4core.ResponsibleDefaults.widthS width <= 300
am4core.ResponsibleDefaults.widthM width <= 400
am4core.ResponsibleDefaults.widthL width <= 600
am4core.ResponsibleDefaults.widthXL width <= 800
am4core.ResponsibleDefaults.widthXXL width <= 1000
am4core.ResponsibleDefaults.heightXXS height <= 100
am4core.ResponsibleDefaults.heightXS height <= 200
am4core.ResponsibleDefaults.heightS height <= 300
am4core.ResponsibleDefaults.heightM height <= 400
am4core.ResponsibleDefaults.heightL height <= 600
am4core.ResponsibleDefaults.heightXL height <= 800
am4core.ResponsibleDefaults.heightXXL height <= 1000
am4core.ResponsibleDefaults.maybeXXS width <= 100 || height <= 100
am4core.ResponsibleDefaults.maybeXS width <= 200 || height <= 200
am4core.ResponsibleDefaults.maybeS width <= 300 || height <= 300
am4core.ResponsibleDefaults.maybeM width <= 400 || height <= 400
am4core.ResponsibleDefaults.maybeL width <= 600 || height <= 600
am4core.ResponsibleDefaults.maybeXL width <= 800 || height <= 800
am4core.ResponsibleDefaults.maybeXXL width <= 1000 || height <= 1000
am4core.ResponsibleDefaults.isXXS width <= 100 && height <= 100
am4core.ResponsibleDefaults.isXS width <= 200 && height <= 200
am4core.ResponsibleDefaults.isS width <= 300 && height <= 300
am4core.ResponsibleDefaults.isM width <= 400 && height <= 400
am4core.ResponsibleDefaults.isL width <= 600 && height <= 600
am4core.ResponsibleDefaults.isXL width <= 800 && height <= 800
am4core.ResponsibleDefaults.isXXL width <= 1000 && height <= 1000

The "relevant" function we had before can be simplified using breakpoints:

relevant: am4core.ResponsiveBreakpoints.widthS
relevant: am4core.ResponsiveBreakpoints.widthS

Defining a state to apply when the Rule is "relevant"

Since our chart IS 400px or less, responsive will try to call Rule's state() method expecting to receive a SpriteState object which it can then apply to chart.

For starters, let's try to shave off margins, that are way to generous at this size:

state: function(target, stateId) {
if (target instanceof am4charts.Chart) {
let state = target.states.create(stateId);
state.properties.paddingTop = 0;
state.properties.paddingRight = 15;
state.properties.paddingBottom = 5;
state.properties.paddingLeft = 15;
return state;
}
return null;
}
state: function(target, stateId) {
if (target instanceof am4charts.Chart) {
var state = target.states.create(stateId);
state.properties.paddingTop = 0;
state.properties.paddingRight = 15;
state.properties.paddingBottom = 5;
state.properties.paddingLeft = 15;
return state;
}
return null;
}

IMPORTANT At this point we need to explain something. Responsive Rule will be applied not just directly to the chart object, but also on its children, and other descendants. This is why we need to check what kind of object is this, so that properties are not being applied to all elements.

Let's see how our chart looks now:

See the Pen amCharts 4: Responsive (2) by amCharts (@amcharts) on CodePen.24419

Better already. But let's not stop there. Let's also make the following space-saving adjustments:

  • Tweak the legend to fit into a single line;
  • Put value axis labels inside plot area so they don't take up so much space on the left;
  • Remove spacing between Scrollbar and plot area.

Using multiple rules

You can have more than one rule. The chart will check each rule if it's relevant() and will apply it as it is, in the same order as you have rules set.

Let's say we have three rules set:

  1. The first rule checks whether chart width is 400 pixels or less;
  2. The second rule checks whether the chart width is 300 pixels or less;
  3. The third rule checks if the width is 200 pixels or less.

And, we have a chart that is currently 300 pixels wide. What will happen is this:

  1. The first rule will be applied;
  2. The second rule will be applied;
  3. The third rule will not be applied.

This allows for very powerful combinations and setups to be created with rules overriding all or some of the settings set by other rules, and so on.

See the Pen amCharts 4: Responsive (3) by amCharts (@amcharts) on CodePen.24419