0

I'm using Highcharts with Map and Drilldown modules. I want to see my contacts for the current visible map.

My problem is that I cannot find documentation or recent examples of how to do this when I'm using TopoJson and its recommended mapview (e.g. topology.objects.default['hc-recommended-mapview']).

I've tried three approaches, as see in this example: https://jsfiddle.net/PolarIce/z9wcp43y/

The test case here is Texas. I have one contact there, and then another which is in Oklahoma near the border with Texas. I don't want to see this Oklahoma contact when I'm drilled down into Texas.

You can change approaches in the example on line 184. I think filter2 is the closest, as it's at least returning data, but it's the wrong data. I can't find an example of how to use chart.mapView.lonLatToProjectedUnits with confidence.

I tried filter2 approach because https://api.highcharts.com/class-reference/Highcharts.Chart#fromLatLonToPoint is deprecated and points to https://api.highcharts.com/class-reference/Highcharts.MapView#lonLatToProjectedUnits

When Texas is drilldown, this returns an array with 3 contacts that are not in view, but not the 1 contact that is in texas.

const filter2 = function(chart) {

  const inrange = [];
  contacts.forEach(contact => {


    const point = chart.mapView.lonLatToProjectedUnits(contact);

    const x = point.x;
    const y = point.y;

    var result = chart.plotLeft <= x && x <= chart.plotLeft + chart.plotWidth &&
      chart.plotTop <= y && y <= chart.plotTop + chart.plotHeight;

    console.log("result", result)

    if (result) {
      inrange.push(contact);

    }


  });
  console.log(inrange);

  return inrange;

}

Source for filter1 example: https://www.highcharts.com/chat/gpt/ no contacts are returned

const filter1 = function(chart) {
    // Get the current map view bounds
    var bounds = chart.plotBox;
    const inrange = [];

   contacts.forEach(contact => {

    if (bounds) {

      // Convert latitude and longitude to projected units
      var point = chart.fromLatLonToPoint(contact.lat, contact.lon);

      // Check if the projected units fall within the visible range
      var isVisible =
        point.x >= bounds.x &&
        point.x <= bounds.x + bounds.width &&
        point.y >= bounds.y &&
        point.y <= bounds.y + bounds.height;

      if (isVisible) {
        inrange.push(contact);

      } else {
        console.log("in range: ", isVisible, contact)
      }

    } else {
      console.log("No bounds available");
    }

    });

    console.log("in range data", inrange);

    return inrange;


    }

Source for filter3 example: https://www.highcharts.com/chat/gpt/ This throws an error at: chart.mapView.getCenter(); ...is not a function

 const filter3 = function(chart) {

  // Get the current center and zoom level of the map
  var center = chart.mapView.getCenter();
  var zoom = chart.mapView.getZoom();

  const inrange = [];
  contacts.forEach(contact => {

    var lat = contact.lat;
    var lon = contact.lon;

    // Calculate the distance between the current center and the point
    var distance = Math.sqrt(Math.pow(center.lat - lat, 2) + Math.pow(center.lon - lon, 2));

    // Calculate the maximum distance allowed for the point to be visible based on the current zoom level
    var maxDistance = Math.pow(2, -zoom) * 180;

    // Check if the distance is within the maximum allowed distance
    var isVisible = distance <= maxDistance;



    if (isVisible) {
      inrange.push(contact);

    }


  });
  console.log(inrange);

  return inrange;


}
Thirdshift
  • 71
  • 4
  • Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. – Community Aug 10 '23 at 22:08

1 Answers1

1

You can map points with a given region for example using the filter() method on an array. It's probably the simplest way.

const addContactSeries = function(chart) {
  const data = contacts.filter(point => chart.series.some(series => series.name === point.subregion));
  chart.addSeries({
    name: "contacts",
    type: 'mappoint',
    data: data,
    dataLabels: {
      enabled: true,
      format: '{point.name}'
    }
  });
}

Demo: https://jsfiddle.net/BlackLabel/Ldgzh2ew/

Michał
  • 773
  • 1
  • 1
  • 12
  • This has worked for me in cases where the points have the subregion. Thanks for that! However, I do have scenarios to handler where the user enters the lat/lon but no other location identifying information. Is there a way (using the topo-json maps) to determine if a given lat/lon is within the current map? – Thirdshift Aug 24 '23 at 20:54