Search code examples
javascriptjqueryjquery-uiamcharts4

Apply zoom to multiple Amcharts 4 charts with jquery slider


I have a container with two or more XYCharts with dateAxis and I want to change the zoom for all my charts in the container at the same time, using a jQuery slider. I have tried to make the function below run, but it doesn't work.

$("#slider-range").slider({
    animate: "fast",
    range: true,
    min: 0,
    max: 1,
    step: 0.01,
    values: [0, 1],
    slide: function (event, ui) {
        for (var i = 0; i < container.children.length; i++) {
            container.children[i].dateAxis[0].start = ui.values[0];
            container.children[i].dateAxis[0].end = ui.values[1];
        }
    }
});

I always get the error message 'Cannot read property 'dateAxis' of undefined'

This is my code:

am4core.ready(function () {
    am4core.useTheme(am4themes_animated);

    container = am4core.create("container", am4core.Container);
    container.width = am4core.percent(100);
    container.height = am4core.percent(100);
    container.layout = "vertical";
});

function createSimpleLineChart() {
    var chart = container.createChild(am4charts.XYChart);

    ...
    var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
    dateAxis.baseInterval = { "timeUnit": "second", "count": 1 };
    ...
    return chart;
}

Solution

  • There are a couple of issues with your slide method:

    1) You're going through your container's children incorrectly. The children property is not an array that you can directly index; it is a List object that has specific methods you can use to access each element. In this case, using the each method to loop through the children is the way to go.

    2) There is no dateAxis property in the chart object. Each chart's axis objects are stored in the corresponding yAxes and xAxes properties, which are also List objects. Assuming each chart only has one date axis, you can access it directly by using getIndex. Also note that you might find calling the zoom method cleaner than modifying start and end directly.

    Putting it all together:

        slide: function (event, ui) {
          container.children.each(function(chart) {
            chart.xAxes.getIndex(0).zoom({start: ui.values[0], end: ui.values[1]}, false, true);
            //chart.xAxes.getIndex(0).start = ui.values[0];
            //chart.xAxes.getIndex(0).end = ui.values[1];
          });
        }
    

    Demo below:

    am4core.useTheme(am4themes_animated);
    var container = am4core.create("container", am4core.Container);
    container.width = am4core.percent(100);
    container.height = am4core.percent(100);
    container.layout = "vertical";
    
    $("#slider-range").slider({
      animate: "fast",
      range: true,
      min: 0,
      max: 1,
      step: 0.01,
      values: [0, 1],
      slide: function(event, ui) {
        container.children.each(function(chart) {
          chart.xAxes
            .getIndex(0)
            .zoom({ start: ui.values[0], end: ui.values[1] }, false, true);
          //chart.xAxes.getIndex(0).start =ui.values[0];
          //chart.xAxes.getIndex(0).end =ui.values[1];
        });
      }
    });
    
    createCharts();
    
    function createCharts() {
      var chart = container.createChild(am4charts.XYChart);
      var data = generateData();
      chart.data = data;
    
      var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
    
      var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
    
      var series = chart.series.push(new am4charts.LineSeries());
      series.dataFields.dateX = "date";
      series.dataFields.valueY = "price";
      series.tooltipText = "{valueY.value}";
      series.name = "Series 1";
    
      chart.zoomOutButton.disabled = true;
    
      chart2 = container.createChild(am4charts.XYChart);
      chart2.data = data;
      var dateAxis2 = chart2.xAxes.push(new am4charts.DateAxis());
      var valueAxis2 = chart2.yAxes.push(new am4charts.ValueAxis());
    
      var series2 = chart2.series.push(new am4charts.ColumnSeries());
      series2.columns.template.width = am4core.percent(50);
      series2.dataFields.dateX = "date";
      series2.dataFields.valueY = "quantity";
      series2.yAxis = valueAxis2;
      series2.tooltipText = "{valueY.value}";
      series2.name = "Series 2";
      chart2.zoomOutButton.disabled = true;
    }
    
    function generateData() {
      var data = [];
      var price = 100;
      var quantity = 1000;
      for (var i = 0; i < 300; i++) {
        price += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 100);
        quantity += Math.round(
          (Math.random() < 0.5 ? 1 : -1) * Math.random() * 1000
        );
        data.push({ date: new Date(2000, 1, i), price: price, quantity: quantity });
      }
    
      return data;
    }
    #container {
      width: 95%;
      height: 400px;
    }
    #slider-range {
      width: 95%;
      height: 10px;
      border: 1px solid #000;
    }
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> 
    <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>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <div id="container"></div>
    <div id="slider-range"></div>