Using states on LineSeries

This tutorial will show how we can use states to manipulate appearance of the LineSeries in a variety of situations.

SIDE READING This tutorial relies on amCharts 4 concept of states, which is a way to dynamically apply collection of values to multiple properties of an element. For more information about states, read this article.

Adding hover state

If you know states, you know that there's a hardcoded state name "hover" which, if available, will be applied to the element when it is hovered (via mouse cursor or touch).

Say, we want to highlight a LineSeries when it is hovered, by increasing its line thickness.

For that, we'll need to create a state object for its "hover" state.

Please note, that actual elements, LineSeries consists of are called segments, accessible via its segments property. We'll need to create the hover state on its template.

Furthermore, segments are completely removed from interactions processing. If we want these to "react" to hovers, we'll need to re-enable them.

// Enable interactions on series segments
let segment = series.segments.template;
segment.interactionsEnabled = true;

// Create hover state
let hs = segment.states.create("hover");
hs.properties.strokeWidth = 10;
// Enable interactions on series segments
var segment = series.segments.template;
segment.interactionsEnabled = true;

// Create hover state
var hs = segment.states.create("hover");
hs.properties.strokeWidth = 10;
{
  // ...
  "series": [{
    "type": "LineSeries",
    // ...
    "segments": {
      "interactionsEnabled": true,
      "states": {
        "hover": {
          "properties": {
            "strokeWidth": 10
          }
        }
      }
    }
  }]
}

Now, when we hover over the line of the series, it will become thicker.

Go ahead, try it on a below example:

See the Pen amCharts 4: applying hover state on line series by amCharts team (@amcharts) on CodePen.

Triggering hover via API

You can also trigger "hover" programatically. To do so, you simply need to set target object's isHover to true.

In this case target objects are particular series' actual segments, so we'll need to set isHover on each of them.

series1.segments.each(function(segment) {
  segment.isHover = true;
});
series1.segments.each(function(segment) {
  segment.isHover = true;
});

Here's a working example:

See the Pen amCharts 4: applying hover state on line series by amCharts team (@amcharts) on CodePen.

Trigering hover via legend

Now that we know how to trigger series hover via API, we can use it in a more useful scenario: highlight series when its legend item is hovered.

All we need to do is to put over and out events on legend's items (legend.itemContainers.template). The event target will be legend item, but we can deduct its related series by accessing its dataItem.dataContext property:

chart.legend.itemContainers.template.events.on("over", function(ev) {
  toggleSeries(ev.target.dataItem.dataContext, true);
});

chart.legend.itemContainers.template.events.on("out", function(ev) {
  toggleSeries(ev.target.dataItem.dataContext, false);
});

function toggleSeries(series, over) {
  series.segments.each(function(segment) {
    segment.isHover = over;
  });
}
chart.legend.itemContainers.template.events.on("over", function(ev) {
  toggleSeries(ev.target.dataItem.dataContext, true);
});

chart.legend.itemContainers.template.events.on("out", function(ev) {
  toggleSeries(ev.target.dataItem.dataContext, false);
});

function toggleSeries(series, over) {
  series.segments.each(function(segment) {
    segment.isHover = over;
  });
}
{
  // ...
  "legend": {
    // ...
    "itemContainer": {
      "events": {
        "over": function(ev) {
          var series = ev.target.dataItem.dataContext;
          series.segments.each(function(segment) {
            segment.isHover = true;
          });
        },
        "out": function(ev) {
          var series = ev.target.dataItem.dataContext;
          series.segments.each(function(segment) {
            segment.isHover = false;
          });
        }
      }
    }
  }
}

See the Pen amCharts 4: applying hover state on line series from legend by amCharts team (@amcharts) on CodePen.

Triggering via cursor

Let's improve it even further: let's introduce a chart cursor to our char and set it up to display a tooltip on the closest series.

We'll also set up our chart in such way, that whenever a tooltip for closest series is shown, we trigger hover effect on that series.

This is accomplished easily, by tapping into "shown" and "hidden" events for each series' own Tooltip object:

series.tooltipText = "{dateX}: {valueY}";
series.tooltip.events.on("shown", function(ev) {
  toggleSeries(ev.target.targetSprite, true);
});
series.tooltip.events.on("hidden", function(ev) {
  if (ev.target.targetSprite) {
    toggleSeries(ev.target.targetSprite, false);
  }
  else {
    chart.series.each(function(series) {
      toggleSeries(series, false);
    });
  }
});
series.tooltipText = "{dateX}: {valueY}";
series.tooltip.events.on("shown", function(ev) {
  toggleSeries(ev.target.targetSprite, true);
});
series.tooltip.events.on("hidden", function(ev) {
  if (ev.target.targetSprite) {
    toggleSeries(ev.target.targetSprite, false);
  }
  else {
    chart.series.each(function(series) {
      toggleSeries(series, false);
    });
  }
});
{
  // ...
  "series": [{
    "type": "LineSeries",
    // ...
    "tooltip": {
      "events": {
        "shown": function(ev) {
          toggleSeries(ev.target.targetSprite, true);
        },
        "shown": function(ev) {
          var chart = ev.target.baseSprite;
          if (ev.target.targetSprite) {
            toggleSeries(ev.target.targetSprite, false);
          }
          else {
            chart.series.each(function(series) {
              toggleSeries(series, false);
            });
          }
        }
      }
    }
  }]
}

Here, try it out:

See the Pen amCharts 4: applying hover state on line series via cursor tooltip proximity by amCharts team (@amcharts) on CodePen.

Affecting non-hovered series

There are multiple ways to highlight some series. We already showed how we can highlight series by increasing its line thickness.

Now, let's try something else: let's dim all other non-hovered series, so they're less prominent than the one we are currently hovering.

To make that happen, we'll need a few ingredients:

  1. Enabling segment interactions, just like in above examples.
  2. Creating a custom "dimmed" state for segments on all series.
  3. Adding "over" and "out" events with handlers that would apply our custom "dimmed" state to series that are no currently hovered.

For full working code check the example below.

See the Pen amCharts 4: Dimming other series on series hover by amCharts team (@amcharts) on CodePen.