Amchart 4: How to highlight bar/column on click of bar/column in bar plots

Viewed 874

I am trying to highlight the bar/column on click of bar/column in Amchart 4. Using the below code, I am getting the value of current clicked bar/column but using the column.isActive property, the bar/column is not getting highlighted.

I found this Amchart official Documentation link, but it is about on click of axis label. I am trying to implement the same but on click of bar/column, not axis label.

This is the code implementation:

am4core.ready(function() {

// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end

// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);

// Add data
chart.data = [{
  "country": "USA",
  "visits": 2025
}, {
  "country": "China",
  "visits": 1882
}, {
  "country": "Japan",
  "visits": 1809
}, {
  "country": "Germany",
  "visits": 1322
}, {
  "country": "UK",
  "visits": 1122
}];

// Create axes

var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "country";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 30;

categoryAxis.renderer.labels.template.adapter.add("dy", function(dy, target) {
  if (target.dataItem && target.dataItem.index & 2 == 2) {
    return dy + 25;
  }
  return dy;
});

var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());

// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "visits";
series.dataFields.categoryX = "country";
series.name = "Visits";
series.columns.template.tooltipText = "{categoryX}: [bold]{valueY}[/]";
series.columns.template.fillOpacity = .8;

var columnTemplate = series.columns.template;
columnTemplate.strokeWidth = 2;
columnTemplate.strokeOpacity = 1;

// Make a panning cursor
chart.cursor = new am4charts.XYCursor();
chart.cursor.behavior = "panXY";
chart.cursor.snapToSeries = series;

chart.events.on("hit", function(ev){
 chart.series.each(function(series) {
     if (series instanceof am4charts.ColumnSeries) {
       series.columns.each(function(column) {
         if (column.dataItem.categories.categoryX == series.tooltipDataItem.dataContext.country) {           
           console.log(column.dataItem.categories.categoryX, series.tooltipDataItem.dataContext.country);
           column.isActive = true;
         } else {
           column.isActive = false;
         }
       })
     }
   })
})
}); // end am4core.ready()

Now, I also found this stackoverflow post link, but that was related to the Amchart version 3 libraray and I am using Amchart 4.

Kindly check this jfiddle implementation.

2 Answers

You do not require the hit listener for this per definition, only if you want to deactivate other columns while activating the clicked one. You merely have to make the columns togglable and define the actual properties in active state.

You have to make the columns togglable.

series.columns.template.togglable = true;

This will toggle the active state from false to true. togglable

Properties while state is active

var tActiveState = series.columns.template.states.create("active");
tActiveState.properties.strokeWidth = 0;
tActiveState.properties.fill = "crimson";

You have to set the properties of the active state. states

Deactivate other columns on hit

series.columns.template.events.on("hit", function(event){
  series.columns.each(function(column){
    if(column !== event.target){
      column.setState("default");
      column.isActive = false
    }
  })
});

For this we are to use the hit listener again. Event Listeners

Example based on your code

am4core.ready(function() {
  // Themes begin
  am4core.useTheme(am4themes_animated);
  // Themes end

  // Create chart instance
  var chart = am4core.create("chartdiv", am4charts.XYChart);

  // Add data
  chart.data = [{
    "country": "USA",
    "visits": 2025
  }, {
    "country": "China",
    "visits": 1882
  }, {
    "country": "Japan",
    "visits": 1809
  }, {
    "country": "Germany",
    "visits": 1322
  }, {
    "country": "UK",
    "visits": 1122
  }];

  // Create axes

  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "country";
  categoryAxis.renderer.grid.template.location = 0;
  categoryAxis.renderer.minGridDistance = 30;

  categoryAxis.renderer.labels.template.adapter.add("dy", function(dy, target) {
    if (target.dataItem && target.dataItem.index & 2 == 2) {
      return dy + 25;
    }
    return dy;
  });

  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());

  // Create series
  var series = chart.series.push(new am4charts.ColumnSeries());
  series.dataFields.valueY = "visits";
  series.dataFields.categoryX = "country";
  series.name = "Visits";
  series.columns.template.tooltipText = "{categoryX}: [bold]{valueY}[/]";
  series.columns.template.fillOpacity = .8;

  //REM: Making the columns togglable.
  series.columns.template.togglable = true;

  //REM: Setting the properties of the "hover" state
  var tHoverState = series.columns.template.states.create("hover");
  tHoverState.properties.strokeWidth = 1;
  tHoverState.properties.fill = "yellow";

  //REM: Setting the properties of the active state "isActive=true"
  var tActiveState = series.columns.template.states.create("active");
  tActiveState.properties.strokeWidth = 0;
  tActiveState.properties.fill = "crimson";

  var columnTemplate = series.columns.template;
  columnTemplate.strokeWidth = 2;
  columnTemplate.strokeOpacity = 1;

  // Make a panning cursor
  chart.cursor = new am4charts.XYCursor();
  chart.cursor.behavior = "panXY";
  chart.cursor.snapToSeries = series;

  //REM: To deactivate other columns on click
  series.columns.template.events.on("hit", function(event){
    series.columns.each(function(column){
      if(column !== event.target){
        column.setState("default");
        column.isActive = false
      }
    })
  });

}); // end am4core.ready()
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>

<div id = 'chartdiv'></div>

Alternatively you can skip togglable and only use hit

series.columns.template.events.on("hit", function(event){
  series.columns.each(function(column){
    //REM: Deactivate all non clicked columns
    if(column !== event.target){
      column.setState("default");
      column.isActive = false
    }
    //REM: Toggle the clicked column
    else{
      column.isActive = !column.isActive
    }
  })
});

I'm not sure if amchart has api for it or not, but because it's based on svg, we can easily set style for selected column like this

column.element.node.parentNode.setAttribute('fill', highLightColor);           
column.element.node.parentNode.setAttribute('stroke', highLightStrokeColor);
Related