Amcharts 4, xychart, limiting the number of tooltips and combining infos in one tooltip

I am using amcharts 4 to display temperature lines. At times there are many stations so I would like to have just one tooltip and just for the value the cursor is at instead of one tooltip for every line (because then they overlap and some are unreadable).

multiple tooltips

And there might be several stations with the same temperature so I would have to list all of them in the tooltip.

Anyone knows how to achieve that?

In amcharts 3 I used a balloonFunction attached to the graphs to create my own tooltip. But yet I couldn't find how to do it with the series in amcharts 4.

Thanks for a hint!

728x90

2 Answers Amcharts 4, xychart, limiting the number of tooltips and combining infos in one tooltip

If your series' data points have different x values, it's impossible to combine all the information into one tooltip.

But if they do have same x values, you can just turn on the tooltip for just one of the series:

...,
series: [{
    type: "LineSeries",
    tooltipHTML: `xxx`,
    ...
}, {
    type: "LineSeries",
    ...
}, {
    type: "LineSeries",
    ...
}],
...

And within the tooltip HTML, you have access to the data:

...,
tooltipHTML: `
    <strong>Year: </strong>{year}<br />
    <strong>Cars: </strong>{cars}<br />
    <strong>Motorcycles: </strong>{motorcycles}<br />
    <strong>Bicycles: </strong>{bicycles}
`,
...

enter image description here

demo: http://jsfiddle.net/davidliang2008/aq9Laaew/286519/

3 months ago

So as David Liang mentioned, since all the data items converge along their x axis value (a datetime in this case), you can limit tooltips down to one by only setting one series' tooltipText, and it will have access to the rest of the data fields via data placeholders. E.g. even though series1's value field is E852_t4m, it can use series30's value by just putting "{median_tBel}".

But if you want to have a tooltip based on which line you're hovering over, how to do that depends whether or not you require the Chart Cursor.

If you don't need it, simply set the tooltipText on the line's bullets, e.g.

series1.bullets.getIndex(0).tooltipText = "{name} {valueY}°C";

Here's a demo of your fiddle with that:

https://codepen.io/team/amcharts/pen/803515896cf9df42310ecb7d8d7a2fb7

But if you require Chart Cursor, unfortunately there isn't a supported option at the moment. There's a kind of workaround but it's not the best experience. You start with doing the above. The Chart Cursor will trigger hover effects on all lines and their bullets, including triggering their tooltips. A bullet's tooltip is actually its series' (series1.bulletsContainer.children.getIndex(0).tooltip === series1.tooltip). If we remove the reference to the bullet's tooltip, e.g. series1.bullets.getIndex(0).tooltip = undefined;, the chart will check up the chain and refer to series' anyway. If we do the same to the series' tooltip, it'll go up the chain to chart.tooltip, if we do this to all series, we basically turn chart.tooltip into a singleton behavior of sorts. But it's not as responsive to mouseovers.

You'll see what I mean with this demo:

https://codepen.io/team/amcharts/pen/244ced223fe647ad6df889836da695a8

Oh, also in the above, you'll have to adjust the chart's tooltip to appear on the left/right of bullets with this:

chart.tooltip.pointerOrientation = "horizontal";

Edit:

Since the first method sufficed, I've updated it with an adapter that checks for other fields in range. In the adapter, the target will be the CircleBullet, target.dataItem.valueY is the currently hovered value, and target.dataItem.dataContext are the other fields at the same date.

This is how I modified tooltipText to show other series within +/-0.5C range of the currently-hovered bullet:

// Provide a range of values for determining what you'll consider to be an "overlap"
// (instead of checking neighboring x/y coords.)
function inRange(valueA, rangeA, rangeB) {
  return valueA >= rangeA && valueA <= rangeB;
}

// Provide adapters for tooltipText so we can modify them on the fly
chart.series.each(function(series) {
  series.bullets
    .getIndex(0)
    .adapter.add("tooltipText", function(tooltipText, target) {
      // the other data fields will already match on the date/x axis, so skip
      // the date and this bullet's data fields.
      // (target.dataItem.component is the target's series.)
      var skipFields = ["date", target.dataItem.component.dataFields.valueY];
      // this bullet's value
      var hoveredValue = target.dataItem.valueY;
      // all the other data fields at this date
      var data = target.dataItem.dataContext;
      // flag for adding additional text before listing other nearby bullet values
      var otherPoints = false;
      Object.keys(target.dataItem.dataContext).forEach(function(field) {
        // if the field is neither date, nor bullet's
        if (!~skipFields.indexOf(field)) {
          if (inRange(data[field], hoveredValue - 0.5, hoveredValue + 0.5)) {
            if (!otherPoints) {
              tooltipText += "\n\nOthers:";
              otherPoints = true;
            }
            // Keep {data placeholder} notation to retain chart formatting features
            tooltipText += "\n" + field + ": {" + field + "}°C";
          }
        }
      });
      return tooltipText;
    });
});

3 months ago