Search code examples
angulartypescriptecmascript-6amchartsamcharts4

Stacking single column in amcharts 4 on hover


Please check this stackblitz link

Here on hover you can see a tooltip with different counts, I wanted to show a stacked column on hover, something like this this I have tried creating a second series on 'over' event of first series (same can be seen in the code), but it is not working.

Is there a way to achieve this in amcharts?


Solution

  • First of all you should create a "normal" stacked column chart with multiple series for each data value:

    var series = chart.series.push(new am4charts.ColumnSeries());
    series.dataFields.valueY = "error"; // "pass", ...
    series.dataFields.dateX = "date";
    series.name = "Research";
    series.stacked = true;
    

    If that works you can set the fill and stroke color of all series to the same value:

    series.fill = am4core.color('#ececec');
    series.stroke = am4core.color('#ececec');
    

    And add an hover state, which is applied when you hover a column:

    let hoverState = series.columns.template.states.create("hover");
    hoverState.properties.stroke = am4core.color("red"); // change the color for each series
    hoverState.properties.fill = am4core.color("red"); // change the color for each series
    

    Here is the complete example:

    am4core.useTheme(am4themes_animated);
    
    var chart = am4core.create("chartdiv", am4charts.XYChart);
    
    chart.data = [{
      'date': new Date(2019, 4, 1),
      'itrCount': 100,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 2),
      'itrCount': 75,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 3),
      'itrCount': 80,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 4),
      'itrCount': 250,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 5),
      'itrCount': 150,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 6),
      'itrCount': 180,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 7),
      'itrCount': 95,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 8),
      'itrCount': 100,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 9),
      'itrCount': 20,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 10),
      'itrCount': 20,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 11),
      'itrCount': 20,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 12),
      'itrCount': 47,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 13),
      'itrCount': 100,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 14),
      'itrCount': 75,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 15),
      'itrCount': 80,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 16),
      'itrCount': 250,
      'pass': 35,
      'error': 10
    }, {
      'date': new Date(2019, 4, 17),
      'itrCount': 150,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 18),
      'itrCount': 180,
      'pass': 50,
      'error': 10
    }, {
      'date': new Date(2019, 4, 19),
      'itrCount': 95,
      'pass': 30,
      'error': 10
    }, {
      'date': new Date(2019, 4, 20),
      'itrCount': 100,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 21),
      'itrCount': 20,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 22),
      'itrCount': 20,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 23),
      'itrCount': 20,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 24),
      'itrCount': 47,
      'pass': 25,
      'error': 10
    }, {
      'date': new Date(2019, 4, 25),
      'itrCount': 100,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 26),
      'itrCount': 75,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 27),
      'itrCount': 80,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 28),
      'itrCount': 250,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 29),
      'itrCount': 150,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 30),
      'itrCount': 180,
      'pass': 10,
      'error': 10
    }, {
      'date': new Date(2019, 4, 31),
      'itrCount': 95,
      'pass': 10,
      'error': 10
    }];
    
    const dateAxis = chart.xAxes.push(new am4charts.DateAxis());
    dateAxis.renderer.grid.template.disabled = true;
    dateAxis.renderer.minGridDistance = 0;
    dateAxis.renderer.grid.template.location = 0.5;
    dateAxis.startLocation = 0;
    dateAxis.endLocation = 1;
    dateAxis.dateFormats.setKey('day', 'dd');
    dateAxis.cursorTooltipEnabled = false;
    
    const valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
    valueAxis.renderer.grid.template.disabled = true;
    valueAxis.renderer.labels.template.disabled = true;
    valueAxis.cursorTooltipEnabled = false;
    
    var series = chart.series.push(new am4charts.ColumnSeries());
    series.dataFields.valueY = "error";
    series.dataFields.dateX = "date";
    series.name = "Research";
    series.stacked = true;
    series.fill = am4core.color('#ececec');
    series.stroke = am4core.color('#ececec');
    
    let hoverState = series.columns.template.states.create("hover");
    hoverState.properties.stroke = am4core.color("red");
    hoverState.properties.fill = am4core.color("red");
    
    var series2 = chart.series.push(new am4charts.ColumnSeries());
    series2.dataFields.valueY = "pass";
    series2.dataFields.dateX = "date";
    series2.name = "Marketing";
    series2.stacked = true;
    series2.fill = am4core.color('#ececec');
    series2.stroke = am4core.color('#ececec');
    
    let hoverState2 = series2.columns.template.states.create("hover");
    hoverState2.properties.stroke = am4core.color("green");
    hoverState2.properties.fill = am4core.color("green");
    
    var series3 = chart.series.push(new am4charts.ColumnSeries());
    series3.dataFields.valueY = "itrCount";
    series3.dataFields.dateX = "date";
    series3.name = "Sales";
    series3.stacked = true;
    series3.fill = am4core.color('#ececec');
    series3.stroke = am4core.color('#ececec');
    
    let hoverState3 = series3.columns.template.states.create("hover");
    hoverState3.properties.stroke = am4core.color("blue");
    hoverState3.properties.fill = am4core.color("blue");
    
    series3.tooltip.getFillFromObject = false;
    series3.tooltip.background.fill = am4core.color('#fff');
    series3.tooltip.label.fill = am4core.color('#000');
    series3.columns.template.tooltipY = 0;
    series3.columns.template.tooltipText = 'Series: {name}\nDate: {date}\nCount: {itrCount}\nPass: {pass}\nFail: {error}';
    
    chart.cursor = new am4charts.XYCursor();
    chart.cursor.lineX.disabled = true;
    chart.cursor.lineY.disabled = true;
    #chartdiv {
      width: 100%;
      height: 500px;
    }
    <script src="//www.amcharts.com/lib/4/core.js"></script>
    <script src="//www.amcharts.com/lib/4/charts.js"></script>
    <script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
    <div id="chartdiv"></div>

    You can also fork and edit this code pen. Here is a screenshot of the result:

    enter image description here

    You might want to consider some more things:

    • To add a Shadow to the hover state you can create a filter and add a DropShadowFilter
    • To improve your tooltip you cat take a look at chart.tooltipHTML or follow this tutorial
    • I would not recommend using series2.columns.template.width = am4core.percent(100); because that can result in some overlapping SVG bugs:

    enter image description here