Search code examples
amcharts

amCharts: Map Recentering after JSON DataSource Despite Previous chart.homeGeoPoint


I'm mapping a series of points with amChart; after loading the data from an external JSON source, the map re-centers instead of staying at the point I'd set earlier with chart.homeGeoPoint.

I believe I need to use an event listener and set the homeGeoPoint after the map renders the points... but I'm at a bit of a loss; the only events I've found are from dataSource.events, and those appear to be related to fetching/parsing the JSON, as opposed to rendering the map.

// Create map instance
var chart = am4core.create("chartdiv", am4maps.MapChart);

// Set map definition
chart.geodata = am4geodata_region_world_northAmericaLow;

// Set projection
chart.projection = new am4maps.projections.Miller();

// Initial Position / Zoom
chart.homeZoomLevel = 2.6;
chart.homeGeoPoint = {
    latitude: 39,
    longitude: -96.2456
};

// Series for World map
var worldSeries = chart.series.push(new am4maps.MapPolygonSeries());
worldSeries.useGeodata = true;

// Markers

// Create image series
var imageSeries = chart.series.push(new am4maps.MapImageSeries());

// Create a circle image in image series template so it gets replicated to all new images

var imageSeriesTemplate = imageSeries.mapImages.template;
var circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 5;
circle.fill = am4core.color("#116ad6");
circle.stroke = am4core.color("#FFFFFF");
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = "{title}";

// Set property fields
imageSeriesTemplate.propertyFields.latitude = "latitude";
imageSeriesTemplate.propertyFields.longitude = "longitude";
imageSeriesTemplate.propertyFields.url = "url";

// Load data        
imageSeries.dataSource.url = "/foo/map-points.php";
imageSeries.dataSource.parser = new am4core.JSONParser();
imageSeries.dataSource.parser.options.emptyAs = 0;

// Center after render
imageSeries.dataSource.events.on("done", function(ev) {
    // This doesn't work - perhaps it is firing too early?
    chart.homeGeoPoint = {
        latitude: 39,
        longitude: -96.2456
    };
});

By request, here is a foo.json file for expirmenting with.

[{"title":"ISP","url":"\/airport\/kisp\/","latitude":40.7952,"longitude":-73.1002},{"title":"AEX","url":"\/airport\/kaex\/","latitude":31.3274,"longitude":-92.5486}]

What do I need to do to make sure the map stays centered on my desired location after the JSON data are loaded and rendered?


Solution

  • I've created an issue on GitHub in regards to why the map re-positions on the MapImageSeries' dataSource load and how to better work with that. (If you've a GitHub account, please subscribe to the issue.)

    In the meantime, presuming the first time your dataSource gets its data that the user hasn't moved the map and we want to maintain homeGeoPoint as the current center, we can chain events to achieve that.

    When the dataSource is "done" with its data, that doesn't necessarily imply anything has been done on the actual map level. The data still needs to propagate to the MapImageSeries, that still needs to create MapImages per data item, have the data validated/parsed there, and for whatever reason the map position shifts around. So the first time that happens (using events.once instead of events.on), we then listen for the MapImageSeries' "datavalidated" event also only one time (because "datavalidated" will have run before this, e.g. as soon as you create the MapImageSeries, if no data is supplied or it's taking some time, it will still run the event and the "inited" event, i.e. I guess you can say the series itself will successfully render nothing).

    And to center the map we use chart.goHome(0);, this method will zoom to your homeGeoPoint and homeZoomLevel, the 0 is for how long the animation duration should run, i.e. just do the work, don't animate.

    So all that together will look something like this:

    // Center after render
    imageSeries.dataSource.events.once("done", function(ev) {    
        imageSeries.events.once("datavalidated", function() {
          chart.goHome(0);
        });
    });
    

    Here's a demo:

    https://codepen.io/team/amcharts/pen/239bfdc8689c65468df32d71b29759b8

    Even though the map does re-position once the MapImageSeries loads, then it re-centers with the above code, I haven't actually seen the map shift at all anymore. So it looks to me the above code is doing the job of maintaining the homeGeoPoint. Let me know if that is still the case once implemented in your application.