Responsive

Responsive features in amCharts 5 are activated via Responsive theme.

Loading

Responsive is loaded just like any other theme:

import am5themes_Responsive from "@amcharts/amcharts5/themes/Responsive";
<script src="//cdn.amcharts.com/lib/5/themes/Responsive.js"></script>

Applying

If we do not wish to modify anything in the responsive rules, we can just instantiate the Responsive theme using its static new() method, passing in the root element.

root.setThemes([
  am5themes_Responsive.new(root)
]);
root.setThemes([
  am5themes_Responsive.new(root)
]);

This will instantiate the responsive theme with all default rules available.

However, if we are going to be adding our own rules, we may want to start off without default rules. In such case we'd use newEmpty() method instead:

root.setThemes([
  am5themes_Responsive.newEmpty(root)
]);
root.setThemes([
  am5themes_Responsive.newEmpty(root)
]);

Adding custom rules

Basically responsive works like this:

  • If condition is met (e.g. chart width is smaller than X), apply certain setting value.
  • If condition is no longer applicable (e.g. chart grows larger), reset setting to original value (or no value at all of it wasn't set before).

A responsive rule defines all those elements: condition and setting values to override.

To create a rule, we use responsive theme's addRule() method. Since we need to call the method on theme object, we will need to pre-create the object:

const responsive = am5themes_Responsive.new(root);

responsive.addRule({
  name: "AxisRendererY",
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    inside: true
  }
});

root.setThemes([
  AnimatedTheme.new(root),
  responsive
]);
const responsive = am5themes_Responsive.new(root);

responsive.addRule({
  name: "AxisRendererY",
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    inside: true
  }
});

root.setThemes([
  AnimatedTheme.new(root),
  responsive
]);

Let's examine what's going on in the above snippet.

Rule target

Target element class name

name parameter indicates what elements to target by this rule. Each element has at least one class name, but possibly more.

The class name of the element is represented by its class' className and classNames properties.

Take a look at class reference of the AxisRendererY from the example above:

We can target elements by any of the class names. E.g. using AxisRenderer would target all axis renderers, not just ones for the Y axis.

Theme tags

It's possible to refine targeting by using theme tags of the element:

responsive.addRule({
  name: "AxisRendererY",
  tags: ["opposite"],
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    inside: true
  }
});
responsive.addRule({
  name: "AxisRendererY",
  tags: ["opposite"],
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    inside: true
  }
});

The above will target vertical axis renderer, but only if it's placed on the right-side of the chart (opposite: true).

For more information about targeting elements using class names, theme tags and a list of hard-coded tags, refer to "Creating themes: Targeting elements" tutorial.

Rule condition

Condition is represented by rule's relevant property, which must be a function that takes two parameters: width and height of the chart, and returns true if rule condition is met or false if it's not.

Bundled conditions and breakpoints

Responsive theme comes with some helpful condition functions as well as breakpoints we can use to avoid replicating the code.

Breakpoints

Accessible viaValue
am5themes_Responsive.XXS100
am5themes_Responsive.XS200
am5themes_Responsive.S300
am5themes_Responsive.M400
am5themes_Responsive.L600
am5themes_Responsive.XL800
am5themes_Responsive.XXL1000

Using breakpoints we can rewrite our example above:

responsive.addRule({
  name: "AxisRendererY",
  relevant: function(width, height) {
    return width < am5themes_Responsive.XXL;
  },
  settings: {
    inside: true
  }
});
responsive.addRule({
  name: "AxisRendererY",
  relevant: function(width, height) {
    return width < am5themes_Responsive.XXL;
  },
  settings: {
    inside: true
  }
});

Conditional functions

Accessible viaCheck
am5themes_Responsive.widthXXSwidth <= 100
am5themes_Responsive.widthXSwidth <= 200
am5themes_Responsive.widthSwidth <= 300
am5themes_Responsive.widthMwidth <= 400
am5themes_Responsive.widthLwidth <= 600
am5themes_Responsive.widthXLwidth <= 800
am5themes_Responsive.widthXXLwidth <= 1000
 
am5themes_Responsive.heightXXSheight <= 100
am5themes_Responsive.heightXSheight <= 200
am5themes_Responsive.heightSheight <= 300
am5themes_Responsive.heightMheight <= 400
am5themes_Responsive.heightLheight <= 600
am5themes_Responsive.heightXLheight <= 800
am5themes_Responsive.heightXXLheight <= 1000
 
am5themes_Responsive.maybeXXSwidth <= 100 || height <= 100
am5themes_Responsive.maybeXSwidth <= 200 || height <= 200
am5themes_Responsive.maybeSwidth <= 300 || height <= 300
am5themes_Responsive.maybeMwidth <= 400 || height <= 400
am5themes_Responsive.maybeLwidth <= 600 || height <= 600
am5themes_Responsive.maybeXLwidth <= 800 || height <= 800
am5themes_Responsive.maybeXXLwidth <= 1000 || height <= 1000
 
am5themes_Responsive.isXXSwidth <= 100 && height <= 100
am5themes_Responsive.isXSwidth <= 200 && height <= 200
am5themes_Responsive.isSwidth <= 300 && height <= 300
am5themes_Responsive.isMwidth <= 400 && height <= 400
am5themes_Responsive.isLwidth <= 600 && height <= 600
am5themes_Responsive.isXLwidth <= 800 && height <= 800
am5themes_Responsive.isXXLwidth <= 1000 && height <= 1000

Let's simplify our example even further:

responsive.addRule({
  name: "AxisRendererY",
  relevant: am5themes_Responsive.widthXXL,
  settings: {
    inside: true
  }
});
responsive.addRule({
  name: "AxisRendererY",
  relevant: am5themes_Responsive.widthXXL,
  settings: {
    inside: true
  }
});

Setting overrides

Final property of the rule is settings which supplies key - value pairs to override for the element if the condition is met.

NOTE Settings are not regular properties of the element, which cannot be set by the responsive rule. For more complex overrides, please refer to the "Custom apply/remove functions" section of this tutorial. Also, read about "Settings".

Note about user-set settings

IMPORTANTSettings set in a responsive rule will not override settings, that are set directly on an element.

As an example, let's take an XYChart which has layout set directly on it:

let chart = root.container.children.push(am5xy.XYChart.new(root, {
  layout: root.verticalLayout
}));
var chart = root.container.children.push(am5xy.XYChart.new(root, {
  layout: root.verticalLayout
}));

Let's say we want to change layout to vertical, if chart is less than 1000px width.

The assumption would be that the following responsive rule should do it:

// THIS WILL NOT WORK AS EXPECTED!
responsive.addRule({
  name: "XYChart",
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    layout: root.horizontalLayout
  }
});
// THIS WILL NOT WORK AS EXPECTED!
responsive.addRule({
  name: "XYChart",
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    layout: root.horizontalLayout
  }
});

However, this will not work, because layout set directly on chart's object will take precedence over the rule's template.

The solution is to remove layout setting from the XYChart and create two responsive rules instead to handle situations when the chart is below and above 1000px in width:

responsive.addRule({
  name: "XYChart",
  relevant: function(width, height) {
    return width >= 1000;
  },
  settings: {
    layout: root.verticalLayout
  }
});

responsive.addRule({
  name: "XYChart",
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    layout: root.horizontalLayout
  }
});

// ...

let chart = root.container.children.push(am5xy.XYChart.new(root, {
  //layout: root.verticalLayout
}));
responsive.addRule({
  name: "XYChart",
  relevant: function(width, height) {
    return width >= 1000;
  },
  settings: {
    layout: root.verticalLayout
  }
});

responsive.addRule({
  name: "XYChart",
  relevant: function(width, height) {
    return width < 1000;
  },
  settings: {
    layout: root.horizontalLayout
  }
});

// ...

var chart = root.container.children.push(am5xy.XYChart.new(root, {
  //layout: root.verticalLayout
}));

Custom apply/remove functions

If we need to do some more complex chart setup changes than changing a value for a setting, we can use custom functions that are called when rule is applied and removed.

They are supplied via rule's applying and removing properties, respectively.

As an example, let's move the chart's legend to bottom of the chart when its width gets smaller than 400 pixels.

responsive.addRule({
  relevant: am5themes_Responsive.widthM,
  applying: function() {
    chart.set("layout", root.verticalLayout);
    legend.setAll({
      y: null,
      centerY: null,
      x: am5.p0,
      centerX: am5.p0
    });
  },
  removing: function() {
    chart.set("layout", root.horizontalLayout);
    legend.setAll({
      y: am5.p50,
      centerY: am5.p50,
      x: null,
      centerX: null
    });
  }
});
responsive.addRule({
  relevant: am5themes_Responsive.widthM,
  applying: function() {
    chart.set("layout", root.verticalLayout);
    legend.setAll({
      y: null,
      centerY: null,
      x: am5.p0,
      centerX: am5.p0
    });
  },
  removing: function() {
    chart.set("layout", root.horizontalLayout);
    legend.setAll({
      y: am5.p50,
      centerY: am5.p50,
      x: null,
      centerX: null
    });
  }
});

See the Pen Testing responsive by amCharts team (@amcharts) on CodePen.

Related tutorials