ashenshugar
ashenshugar

Reputation: 91

Need help in simplifying the code to synchronise tooltips and crosshairs for Highcharts,

I have created a series of synchronised charts, the code to link the crosshair and tooltip is rather complicated:

    function syncronizeCrossHairs(chart) {

  ['mousemove', 'touchmove', 'touchstart'].forEach(function(eventType) {
    var container = $(chart.container),
      offset = container.offset(),
      x;
    container[0].addEventListener(eventType,
      (function(evt) {
        x = evt.clientX - chart.plotLeft - offset.left;
        //remove old plot line and draw new plot line (crosshair) for this chart
        var xAxis1 = chart1.xAxis[0],
          points = [],
          points1 = [],
          points2 = [],
          points3 = [],
          e = chart1.pointer.normalize(evt); // Find coordinates within the chart   

        chart1.series.forEach(s => {
          var point = s.searchPoint(e, true)
          if (point) {
            point.setState();
            points.push(point)
          }
        })

        if (points) {
          var number = 0;
          Highcharts.each(points, function(p, i) {
            if (!p.series.visible) {
              points.splice(i - number, 1);
              number++;
            }
          })
          if (points.length) {
            chart1.tooltip.refresh(points); // Show the tooltip
          }
        }

        xAxis1.drawCrosshair(x, points[0])


        /*----- second chart ------*/
        var xAxis2 = chart2.xAxis[0];

        chart2.series.forEach(s => {
          var point = s.searchPoint(e, true)
          if (point) {
            point.setState();
            points1.push(point)
          }
        })

        if (points1[0]) {
          var number = 0;
          Highcharts.each(points1, function(p, i) {
            if (!p.series.visible) {
              points1.splice(i - number, 1);
              number++;
            }
          })
          if (points1.length) {
            chart2.tooltip.refresh(points1); // Show the tooltip
          }
        }
        xAxis2.drawCrosshair(x, points1[0])


        /*----- third chart ------*/
        var xAxis3 = chart3.xAxis[0];

        chart3.series.forEach(s => {
          var point = s.searchPoint(e, true)
          if (point) {
            point.setState();
            points2.push(point)
          }
          console.log(points2)
        })

        if (points2[0]) {
          var number = 0;
          Highcharts.each(points1, function(p, i) {
            if (!p.series.visible) {
              points2.splice(i - number, 1);
              number++;
            }
          })
          if (points2.length) {
            chart3.tooltip.refresh(points2); // Show the tooltip
          }
        }

        xAxis3.drawCrosshair(x, points2[0])

        /*     ----- fourth chart ------ */
        var xAxis4 = chart4.xAxis[0];

        chart4.series.forEach(s => {
          var point = s.searchPoint(e, true)
          if (point) {
            point.setState();
            points3.push(point)
          }
        })

        if (points3[0]) {
          var number = 0;
          Highcharts.each(points3, function(p, i) {
            if (!p.series.visible) {
              points3.splice(i - number, 1);
              number++;
            }
          })
          if (points3.length) {
            chart4.tooltip.refresh(points3); // Show the tooltip
          }
        }
        xAxis4.drawCrosshair(x, points3[0])
      }))
  })

}

How ever I have found a better example here: http://jsfiddle.net/mushigh/a3kjrz6u/

    $('#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.onMouseOver(); // Show the hover marker
        chart.tooltip.refresh(point); // Show the tooltip
        chart.xAxis[0].drawCrosshair(event, point); // Show the crosshair
      }
    }
  });
  /**
   * Override the reset function, we don't need to hide the tooltips and crosshairs.
   */
  Highcharts.Pointer.prototype.reset = function() {
    return undefined;
  };

How do I adapt my code here: https://jsfiddle.net/ashenshugar/716jx4n9/

To use the simplified code in my example

Upvotes: 0

Views: 98

Answers (1)

Sebastian Wędzel
Sebastian Wędzel

Reputation: 11633

I don't think that the demo which you have found is a good approach to your requirements.

  1. The demo needs to the specific data structure, like: https://github.com/highcharts/highcharts/blob/master/samples/data/activity.json

  2. The demo is an example to show tooltip for only one series per chart, meanwhile, you have got a few and a shared tooltip, so finally, you will need to do the same calculations to get the array of points for shared tooltip.

Except that, I think that a better approach is to clean up your code.

Notice that the functionalities to calculate points for each chart are similar and can be paste into the loop:

function syncronizeCrossHairs(chart) {

  ['mousemove', 'touchmove', 'touchstart'].forEach(function(eventType) {
    var container = $(chart.container),
      offset = container.offset(),
      x;

    container[0].addEventListener(eventType,
      (function(evt) {
        x = evt.clientX - chart.plotLeft - offset.left;
        Highcharts.charts.forEach(ch => {
          var e = ch.pointer.normalize(evt), // Find coordinates within the chart   
            points = [];
          ch.series.forEach(s => {
            var point = s.searchPoint(e, true);
            if (point) {
              point.setState();
              points.push(point)
            }
          })

          if (points) {
            var number = 0;
            Highcharts.each(points, function(p, i) {
              if (!p.series.visible) {
                points.splice(i - number, 1);
                number++;
              }
            })
            if (points.length) {
              ch.tooltip.refresh(points); // Show the tooltip
            }
          }
          ch.xAxis[0].drawCrosshair(x, points[0])
        })
      }))
  })

}

And notice that also your afterSetextreme callback can be change to trigger this function:

function setExtremes(chart, min, max) {
  Highcharts.charts.forEach(ch => {
    if (ch !== chart) {
      ch.xAxis[0].setExtremes(min, max)
    }
  })
}

Also, you can define options which are common for each chart, like it is done here: https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/gauge-solid/

Finally demo: https://jsfiddle.net/BlackLabel/hv7azdgm/

Upvotes: 1

Related Questions