Custom Loading Indicator

This tutorial will show how you can create your own custom loading indicator over chart.

The task

Supposedly we have a complex chart, with loads of data, which needs to be loaded from server, parsed, digested and visualized.

We don't want the empty space of a chart just sit there, so we'd like to display some kind of loading indicator there.

So it happens we're extremely picky, so we want to have granular control over what goes into indicator.

Let's do just that.

Disabling default preloader

Before we go on creating a custom indicator, let's get rid of the default one, and make sure it does not pop in.

It's accessible via chart's preloader property. All we have to do is to set its disabled to true.

chart.preloader.disabled = true;
chart.preloader.disabled = true;
{
  // ...
  "preloader": {
    "disabled": true
  }
}

Creating curtain - container

First of all, we will create a Container which we will use as a semi-transparent curtain over chart area as well as a place to put our indicator elements into.

We will create as a child to chart's tooltipContainer. Why? Because it's the ideal candidate for a number of reasons:

  1. It's always on the very top;
  2. It spans all the way to the edges of the chart area, ignoring even padding;
  3. It doesn't have any strict layout type set, so we can plop into and position anything the way we want.

MORE INFO If you don't know what's the deal with all the "container" stuff we're talking here, we suggest you take a peek at "Working with Containers" article.

OK, let's try that.

let indicator;
function showIndicator() {
  indicator = chart.tooltipContainer.createChild(am4core.Container);
  indicator.background.fill = am4core.color("#fff");
  indicator.background.fillOpacity = 0.8;
  indicator.width = am4core.percent(100);
  indicator.height = am4core.percent(100);
}

showIndicator();
var indicator;
function showIndicator() {
  indicator = chart.tooltipContainer.createChild(am4core.Container);
  indicator.background.fill = am4core.color("#fff");
  indicator.background.fillOpacity = 0.8;
  indicator.width = am4core.percent(100);
  indicator.height = am4core.percent(100);
}

showIndicator();

As you can see, all we do is create a new Container child in tooltipContainer, set it's background to be semi-transparent white, and instruct it to take maximum space.

Let's see how it turned out on a real chart.

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

OK, so we have a washed out chart, which means our curtain is working.

Let's move on to something more meaningful, and add a label.

Adding a label

Since our indicator is a Container, we can add anything into it.

Let's create a child of type Label:

let indicator;
function showIndicator() {
  // ...

  let indicatorLabel = indicator.createChild(am4core.Label);
  indicatorLabel.text = "Loading stuff...";
  indicatorLabel.align = "center";
  indicatorLabel.valign = "middle";
  indicatorLabel.fontSize = 20;
}

showIndicator();
var indicator;
function showIndicator() {
  // ...

  var indicatorLabel = indicator.createChild(am4core.Label);
  indicatorLabel.text = "Loading stuff...";
  indicatorLabel.align = "center";
  indicatorLabel.valign = "middle";
  indicatorLabel.fontSize = 20;
}

showIndicator();

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

Now our indicator started indicating something: apparently we're "loading stuff".

While we're on a roll, let's add another element - an image.

Adding an image

We're going to go ahead and add another child to our indicator container. This time its an Image.

Let's set image's href to an SVG hourglass icon we got off iconfinder.com.

let indicator;
function showIndicator() {
  // ...

  let hourglass = indicator.createChild(am4core.Image);
  hourglass.href = "path/to/hourglass.svg";
  hourglass.align = "center";
  hourglass.valign = "middle";
  hourglass.horizontalCenter = "middle";
  hourglass.verticalCenter = "middle";
  hourglass.scale = 0.7;
}

showIndicator();
var indicator;
function showIndicator() {
  // ...

  var hourglass = indicator.createChild(am4core.Image);
  hourglass.href = "path/to/hourglass.svg";
  hourglass.align = "center";
  hourglass.valign = "middle";
  hourglass.horizontalCenter = "middle";
  hourglass.verticalCenter = "middle";
  hourglass.scale = 0.7;
}

showIndicator();

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

Our indicator is getting cooler. But let's not stop there. Let's add an animation.

Adding animation

Let's make our little hourglass rotate.

amCharts 4 comes with a powerful animation framework. All we need to do is to use any element's animate() method to smoothly transition any number of properties from one value to another.

To make the animation repeat, we can create an interval that repeats animation every few seconds.

let indicator;
function showIndicator() {
  // ...

  setInterval(function() {
    hourglass.animate([{
      from: 0,
      to: 360,
      property: "rotation"
    }], 2000);
  }, 3000);
}

showIndicator();
var indicator;
function showIndicator() {
  // ...

  setInterval(function() {
    hourglass.animate([{
      from: 0,
      to: 360,
      property: "rotation"
    }], 2000);
  }, 3000);
}

showIndicator();

See the Pen amCharts 4: Custom loading indicator (4) by amCharts (@amcharts) on CodePen.24419

Nice huh?

Let's wrap it all up.

Putting it all together

Let's augment our function with some checks. Create a complimentary indicator close function.

let indicator;
let indicatorInterval;

function showIndicator() {
  
  if (!indicator) {
    let indicator = chart.tooltipContainer.createChild(am4core.Container);
    indicator.background.fill = am4core.color("#fff");
    indicator.background.fillOpacity = 0.8;
    indicator.width = am4core.percent(100);
    indicator.height = am4core.percent(100);

    let indicatorLabel = indicator.createChild(am4core.Label);
    indicatorLabel.text = "Loading stuff...";
    indicatorLabel.align = "center";
    indicatorLabel.valign = "middle";
    indicatorLabel.fontSize = 20;
    indicatorLabel.dy = 50;
    
    let hourglass = indicator.createChild(am4core.Image);
    hourglass.href = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-160/hourglass.svg";
    hourglass.align = "center";
    hourglass.valign = "middle";
    hourglass.horizontalCenter = "middle";
    hourglass.verticalCenter = "middle";
    hourglass.scale = 0.7;
  }
  
  indicator.hide(0);
  indicator.show();
  
  clearInterval(indicatorInterval);
  indicatorInterval = setInterval(function() {
    hourglass.animate([{
      from: 0,
      to: 360,
      property: "rotation"
    }], 2000);
  }, 3000);
}

function hideIndicator() {
  indicator.hide();
  clearInterval(indicatorInterval);
}

showIndicator();
var indicator;
var indicatorInterval;

function showIndicator() {
  
  if (!indicator) {
    var indicator = chart.tooltipContainer.createChild(am4core.Container);
    indicator.background.fill = am4core.color("#fff");
    indicator.background.fillOpacity = 0.8;
    indicator.width = am4core.percent(100);
    indicator.height = am4core.percent(100);

    var indicatorLabel = indicator.createChild(am4core.Label);
    indicatorLabel.text = "Loading stuff...";
    indicatorLabel.align = "center";
    indicatorLabel.valign = "middle";
    indicatorLabel.fontSize = 20;
    indicatorLabel.dy = 50;
    
    var hourglass = indicator.createChild(am4core.Image);
    hourglass.href = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-160/hourglass.svg";
    hourglass.align = "center";
    hourglass.valign = "middle";
    hourglass.horizontalCenter = "middle";
    hourglass.verticalCenter = "middle";
    hourglass.scale = 0.7;
  }
  
  indicator.hide(0);
  indicator.show();
  
  clearInterval(indicatorInterval);
  indicatorInterval = setInterval(function() {
    hourglass.animate([{
      from: 0,
      to: 360,
      property: "rotation"
    }], 2000);
  }, 3000);
}

function hideIndicator() {
  indicator.hide();
  clearInterval(indicatorInterval);
}

showIndicator();

See the Pen amCharts 4: Custom loading indicator (5) by amCharts (@amcharts) on CodePen.24419