Fizer Khan
Fizer Khan

Reputation: 92745

Synchronize multiple chart's x-axis

In Angular Highcharts, I wanted to do synchronized X-axis in multiple charts in the dashboard. I found a solution for x-axis synchronize for two chart(pasted below). But I stuck with multi chart synchronize. I have 8 charts in my dashboard. I want to synchronize all of them.

Existing code for two charts in highcharts-ng

$scope.chart1 = {
    options: {
        chart: {
            events: {
                selection: function(event) {
                    self.onZoomHandler(event, 'chart2');
                }
            }
        }
    }
}

self.onZoomHandler = function(event, chartToUpdate) {
    var chart = $scope[chartToUpdate].getHighcharts();
    if (event.xAxis) {
        chart.xAxis[0].setExtremes(event.xAxis[0].min, event.xAxis[0].max);
        if (!chart.resetZoomButton) {
            chart.showResetZoom();
        }
    } else {
        chart.xAxis[0].setExtremes(null, null);
        if (chart.resetZoomButton) {
            chart.resetZoomButton = chart.resetZoomButton.destroy();
        }
    }
};

How could we do this in multiple charts?

Upvotes: 1

Views: 3831

Answers (2)

K Scandrett
K Scandrett

Reputation: 16540

You can synchronise tooltips and zoom for any number of charts inside a containing element that has id="container":

<div id="container">
  <div class="row">
    <highchart id="chart1" config="chartConfig" class="span10"></highchart>
  </div>
  <div class="row">
    <highchart id="chart2" config="chartConfig2" class="span10"></highchart>
  </div>
  <div class="row">
    <highchart id="chart3" config="chartConfig3" class="span10"></highchart>
  </div>
</div>

with the following JS functions:

/**
 * In order to synchronize tooltips and crosshairs, override the
 * built-in events with handlers defined on the parent element.
 */
$('#container').bind('mousemove touchmove touchstart', function(e) {
  var chart,
    point,
    i,
    event;

  for (i = 0; i < Highcharts.charts.length; i = i + 1) {
    chart = Highcharts.charts[i];
    event = chart.pointer.normalize(e.originalEvent); // Find coordinates within the chart
    point = chart.series[0].searchPoint(event, true); // Get the hovered point

    if (point) {
      point.highlight(e);
    }
  }
});

/**
 * Override the reset function, we don't need to hide the tooltips and crosshairs.
 */
Highcharts.Pointer.prototype.reset = function() {
  return undefined;
};

/**
 * Highlight a point by showing tooltip, setting hover state and draw crosshair
 */
Highcharts.Point.prototype.highlight = function(event) {
  this.onMouseOver(); // Show the hover marker
  this.series.chart.tooltip.refresh(this); // Show the tooltip
  this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
/**
 * Synchronize zooming through the setExtremes event handler.
 */
function syncExtremes(e) {
  var thisChart = this.chart;

  if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
    Highcharts.each(Highcharts.charts, function(chart) {
      if (chart !== thisChart) {
        if (chart.xAxis[0].setExtremes) { // It is null while updating
          chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
            trigger: 'syncExtremes'
          });
        }
      }
    });
  }
}

(sourced from http://www.highcharts.com/demo/synchronized-charts)

Then just set the syncExtremes function in the setExtremes callback.

$scope.chartConfig = {
  ...
  xAxis: {
    events: {
      setExtremes: syncExtremes
    },
  ...
}

Here's a jsfiddle example with 3 charts: http://jsfiddle.net/nLguvp7m/4/

Upvotes: 1

morganfree
morganfree

Reputation: 12472

Modify your function a little bit so it can handle an array of chart configs and loop through it invoking setExtremes(). onZoomHandler should be set in all charts - so all charts can trigger zooming in the other charts.

$scope.chartConfig = {
  chart: {
    zoomType: 'x',
    events: {
     selection: function (e) {
      e.preventDefault();
      self.onZoomHandler(e, ['chartConfig', 'chartConfig2', 'chartConfig3'])
    }
  }
},

self.onZoomHandler = function (event, chartsToUpdate) {
  chartsToUpdate.forEach(config => {
    zoomHandler($scope[config].getChartObj());
  });

  function zoomHandler(chart) {     
    if (event.xAxis) {
      chart.xAxis[0].setExtremes(event.xAxis[0].min, event.xAxis[0].max);
      if (!chart.resetZoomButton) {
        chart.showResetZoom();
      }
    } else {
      chart.xAxis[0].setExtremes(null, null);
      if (chart.resetZoomButton) {
        chart.resetZoomButton = chart.resetZoomButton.destroy();
      }
    }
  }
}

Upvotes: 0

Related Questions