Customizing chart scrollbar

Chart scrollbars come pre-configured with certain looks, in part influenced by used themes. This tutorial show how we can customize the looks of scrollbars.

Test subject

During the course of this tutorial we will be torturing a scrollbar of this chart:

See the Pen amCharts 4: Custmizing XYChartScrollbar by amCharts team (@amcharts) on CodePen.24419

Customizing grips

Let's start by customizing the grips.

Accessing grip objects

Both of them are objects of type ResizeButton and are accessible via scrollbar's startGrip and endGrip properties.

In this section we will be accessing objects in those two properties a lot.

Since there are two of the grips, and we don't want to repeat code twice, we'll start off by creating a function that we can use to apply customizations to both buttons.

function customizeGrip(grip) {
  // This is empty for now
}

customizeGrip(chart.scrollbarX.startGrip);
customizeGrip(chart.scrollbarX.endGrip); 
function customizeGrip(grip) {
  // This is empty for now
}

customizeGrip(chart.scrollbarX.startGrip);
customizeGrip(chart.scrollbarX.endGrip); 
{
  // ...
  "scrollbarX": {
    // ...
    "startGrip": {
      // JSON config will have to have options repeated to avoid using functions
    },
    "endGrip": {
      // JSON config will have to have options repeated to avoid using functions
    } 
  }
}

Removing default icon

We already decided we don't want a default icon that shows two parallel lines.

That icon is in the grip object's icon property. All we have to do to get rid of it is to disable it:

grip.icon.disabled = true;
grip.icon.disabled = true;
{
  // ...
  "scrollbarX": {
    // ...
    "startGrip": {
      "icon": {
        "disabled": true
      }
    },
    "endGrip": {
      "icon": {
        "disabled": true
      }
    } 
  }
}
Grip button without icon

Since grip is a Button which is sized to fit it's contents, once we disable the icon, shrinks to a tiny cute dot.

Configuring grip background

Similarly to icon we already got rid of, grip's background has own property too. It's named very predictably background.

If we would like to change its fill color and/or opacity we could do just that:

grip.background.fill = am4core.color("#c00");
grip.background.fillOpacity = 0.5;
grip.background.fill = am4core.color("#c00");
grip.background.fillOpacity = 0.5;
{
  // ...
  "scrollbarX": {
    // ...
    "startGrip": {
      // ...
      "background": {
        "fill": "#c00",
        "fillOpacity": 0.5
      }
    },
    "endGrip": {
      // ...
      "background": {
        "fill": "#c00",
        "fillOpacity": 0.5
      } 
    } 
  }
}

However, since we want to completely get rid of the background, we'll do the same thing we did with the icon: disable it.

grip.background.disabled = true;
grip.background.disabled = true;
{
  // ...
  "scrollbarX": {
    // ...
    "startGrip": {
      // ...
      "background": {
        "disabled": true
      }
    },
    "endGrip": {
      // ...
      "background": {
        "disabled": true
      } 
    } 
  }
}

Grip with both icon and background disabled

Adding elements to grip

OK, so we now have an invisible, or more like empty, grip, which is a perfect place to start building our own design from the ground up.

We want to have a double-arrow with a straight line running through it. Since there is none of such shape in amCharts 4 arsenal readily available, we'll need to build one out of basic shapes.

In fact, one shape: a rectangle.

One rectangle, rotated at 45 degrees will serve as bi-directional arrow. Another one, stretched thin, as a dividing line.

We'll also need to do some positioning of the two so they are right in the middle of our for now invisible grip button.

let img = grip.createChild(am4core.Rectangle);
img.width = 15;
img.height = 15;
img.fill = am4core.color("#999");
img.rotation = 45;
img.align = "center";
img.valign = "middle";

// Add vertical bar
let line = grip.createChild(am4core.Rectangle);
line.height = 60;
line.width = 3;
line.fill = am4core.color("#999");
line.align = "center";
line.valign = "middle";
var img = grip.createChild(am4core.Rectangle);
img.width = 15;
img.height = 15;
img.fill = am4core.color("#999");
img.rotation = 45;
img.align = "center";
img.valign = "middle";

// Add vertical bar
var line = grip.createChild(am4core.Rectangle);
line.height = 60;
line.width = 3;
line.fill = am4core.color("#999");
line.align = "center";
line.valign = "middle";
{
  // ...
  "scrollbarX": {
    // ...
    "startGrip": {
      // ...
      "children": [{
        "type": "Rectangle",
        "width": 15,
        "height": 15,
        "fill": "#999",
        "rotation": 45,
        "align": "center",
        "valign": "middle"
      },  {
        "type": "Rectangle",
        "width": 60,
        "height": 3,
        "fill": "#999",
        "align": "center",
        "valign": "middle"
      } ]
    },
    "endGrip": {
      // ...
      "children": [{
        "type": "Rectangle",
        "width": 15,
        "height": 15,
        "fill": "#999",
        "rotation": 45,
        "align": "center",
        "valign": "middle"
      },  {
        "type": "Rectangle",
        "width": 60,
        "height": 3,
        "fill": "#999",
        "align": "center",
        "valign": "middle"
      } ] 
    } 
  }
}

And, voilĂ .

Completely custom grip

And here's a complete working example:

See the Pen amCharts 4: Custmizing XYChartScrollbar by amCharts team (@amcharts) on CodePen.24419

Customizing fills

Now, let's customize scrollbar's fills.

Scrollbar's background

Like with backgrounds of most elements in amCharts 4, they are configured via Rectangle object in their background property.

Thus, if we want to change background color and opacity of the scrollbar, we change fill and fillOpacity properties of its background.

chart.scrollbarX.background.fill = am4core.color("#dc67ab");
chart.scrollbarX.background.fillOpacity = 0.2;
chart.scrollbarX.background.fill = am4core.color("#dc67ab");
chart.scrollbarX.background.fillOpacity = 0.2;
{
  // ...
  "scrollbarX": {
    // ...
    "background": {
      "fill": "#dc67ab",
      "fillOpacity": 0.2
    }
  }
}

See the Pen amCharts 4: Custmizing XYChartScrollbar by amCharts team (@amcharts) on CodePen.24419

Thumb element

A "thumb" element is what we call an area between two grips. It's called thumb because it's all draggable.

In regular Scrollbar it's gray by default. In an XYChartScrollbar is completely invisible.

We can access its object (which is another element of type Button) by scrollbar's thumb property.

Similarly to scrollbar's fill, we can also set fill/opacity of the thumb's background element.

chart.scrollbarX.thumb.background.fill = am4core.color("#67dcab");
chart.scrollbarX.thumb.background.fillOpacity = 0.2;
chart.scrollbarX.thumb.background.fill = am4core.color("#67dcab");
chart.scrollbarX.thumb.background.fillOpacity = 0.2;
{
  // ...
  "scrollbarX": {
    // ...
    "thumb": {
      "background": {
        "fill": "#dc67ab",
        "fillOpacity": 0.2
      }
    }
  }
}

See the Pen amCharts 4: Custmizing XYChartScrollbar by amCharts team (@amcharts) on CodePen.24419

Unselected area

This section is relevant to XYChartScrollbar only. Regular Scrollbar does not have any content in it so there's nothing to configure in the unselected area.

VERSION INFO The public property described in this chapter is available from version 4.6.1. If it does not work as expected, it probably means you have an earlier version.

XYChartScrollbar has a property unselectedOverlay which holds an object that acts a semi-transparent "curtain" producing dimming effect on everything in an unselected area - an area outside of the grips.

To control which color and what opacity the dimming occurs, use overlay's fill (default is theme's background color) and fillOpacity (default 0.8) properties:

chart.scrollbarX.unselectedOverlay.fill = am4core.color("#fff");
chart.scrollbarX.unselectedOverlay.fillOpacity = 0.9;
chart.scrollbarX.unselectedOverlay.fill = am4core.color("#fff");
chart.scrollbarX.unselectedOverlay.fillOpacity = 0.9;
{
  // ...
  "scrollbarX": {
    // ...
    "unselectedOverlay": {
      "fill": "#fff",
      "fillOpacity": 0.9
    }
  }
}

Customizing series

We now come to the last part comprising the scrollbar - series.

This section is not relevant for regular Scrollbar since, well, it does not display any series.

When you add a series to an XYChartScrollbar by pushing it into its series list, scrollbar makes an exact copy and places it into series list of its child element: scrollbarChart, which is a separate copy of XYChart.

We'll use those "clone series" to change how they look in the scrollbar.

Re-enabling colors

Besides making it an exact copy of the "original" series, scrollbar also applies a "Desaturare" filter to the clone, so it is stripped of all color and appear in a shade of gray.

If we want to bring back the color, we just need to remove the filters from the series.

let scrollSeries1 = chart.scrollbarX.scrollbarChart.series.getIndex(0);
scrollSeries1.filters.clear();
var scrollSeries1 = chart.scrollbarX.scrollbarChart.series.getIndex(0);
scrollSeries1.filters.clear();
{
  // ...
  "scrollbarX": {
    // ...
    // Well, this is somewhat awkwardly looking in JSON, but... oh well 
    "callback": function() {
      var scrollSeries1 = this.scrollbarChart.series.getIndex(0);
      scrollSeries1.filters.clear();
    }
  }
}

Configuring series

The series object we retrieve from scrollbar's scrollbarChart is a full-fledged series (just like scrollbarChart is a fill-fledged chart).

This means we can apply any properties we want to configure it's appearance.

Say, we want to lose the fill, and also make the line dotted.

let scrollSeries1 = chart.scrollbarX.scrollbarChart.series.getIndex(0);
scrollSeries1.filters.clear();
scrollSeries1.fillOpacity = 0;
scrollSeries1.strokeDasharray = "2,2";
var scrollSeries1 = chart.scrollbarX.scrollbarChart.series.getIndex(0);
scrollSeries1.filters.clear();
scrollSeries1.fillOpacity = 0;
scrollSeries1.strokeDasharray = "2,2";
{
  // ...
  "scrollbarX": {
    // ...
    // Well, this is somewhat awkwardly looking in JSON, but... oh well 
    "callback": function() {
      var scrollSeries1 = this.scrollbarChart.series.getIndex(0);
      scrollSeries1.filters.clear();
      scrollSeries1.fillOpacity = 0;
      scrollSeries1.strokeDasharray = "2,2"; 
    }
  }
}

See the Pen amCharts 4: Custmizing XYChartScrollbar by amCharts team (@amcharts) on CodePen.24419

Disabling system tooltips

A scrollbar has also some selection information in its hidden attributes, which display as a system tooltip when hovered:

Various elements of scrollbar - thumb, grips, and scrollbar itself - all display some kind of system tooltip information.

Should we want to disable them, we can use showSystemTooltip property of respective elements:

chart.scrollbarX.showSystemTooltip = false;
chart.scrollbarX.thumb.showSystemTooltip = false;
chart.scrollbarX.startGrip.showSystemTooltip = false;
chart.scrollbarX.endGrip.showSystemTooltip = false;
chart.scrollbarX.showSystemTooltip = false;
chart.scrollbarX.thumb.showSystemTooltip = false;
chart.scrollbarX.startGrip.showSystemTooltip = false;
chart.scrollbarX.endGrip.showSystemTooltip = false;
{
  // ...
  "scrollbarX": {
    // ...
    "showSystemTooltip": false,
    "thumb": {
      // ...
      "showSystemTooltip": false
    },
    "startGrip": {
      // ...
      "showSystemTooltip": false
    },
    "endGrip": {
      // ...
      "showSystemTooltip": false
    } 
  }
}