Hide map images until zoomed in

Showing a lot of markers on the map may render it cluttered beyond usability. This tutorial will show how you can easily specify custom zoom levels for each individual image to be shown at.

The problem

Say we have a map with a lot of images in a MapImageSeries:

See the Pen amCharts 4: Show map images only at specific zoom level by amCharts team (@amcharts) on CodePen.0

While not exactly "unusable", still a bit cluttery.

Let's see what we can do about it.

The solution

Specifying zoom threshold

We decided to assign zoom level on a city-level. Let's add the zoom level threshold to our data, so it looks something like this:

[ {
"minZoomLevel": 2,
"svgPath": targetSVG,
"title": "Vienna",
"latitude": 48.2092,
"longitude": 16.3728
}, {
"minZoomLevel": 2,
"svgPath": targetSVG,
"title": "Minsk",
"latitude": 53.9678,
"longitude": 27.5766
}, {
"minZoomLevel": 2,
"svgPath": targetSVG,
"title": "Brussels",
"latitude": 50.8371,
"longitude": 4.3676
}, {
// ...
} ]

NOTE The minZoomLevel is not a built-in keyword. It's something we've just made up. It can be mickeyHasBigEars just as well.

The custom entry in the data will mean the zoom level at which the image starts to appear. The image stays hidden when the map is above that level of zoom.

As you are probably suspecting, adding this in data is not enough. We'll need to set up a function that actually uses that info to toggle images on and off based on current zoom level.

Toggling images based on zoom

Now, let's create a function that will toggle images on and off based on the current zoom level.

function updateImageVisibility(ev) {
let chart = ev.target.baseSprite;
let series = chart.map.getKey("markers");
series.mapImages.each(function(image) {
if (image.dataItem.dataContext.minZoomLevel) {
if (image.dataItem.dataContext.minZoomLevel >= chart.zoomLevel) {
image.hide();
}
else {
image.show();
}
}
});
}
function updateImageVisibility(ev) {
var chart = ev.target.baseSprite;
var series = chart.map.getKey("markers");
series.mapImages.each(function(image) {
if (image.dataItem.dataContext.minZoomLevel) {
if (image.dataItem.dataContext.minZoomLevel >= chart.zoomLevel) {
image.hide();
}
else {
image.show();
}
}
});
}

Let's explore what's going on in the function above.

We're going to be using this function as a handler for various events happening on the chart, hence the ev parameter. It will hold the event object.

We're also be going to be using event object to extract target of the event and namely its baseSprite property which will point to a chart/map instance, so that we don't need to rely on global variables.

In our code we've tagged our image series with an id = "markers" so that we can extract it easily using chart's map dictionary.

After that it's easy: we just iterate through all map images in the series and compare minZoomLevel (or that alternative field involving Disney character's ears) to the current zoom (zoomLevel). Then just either hide or show the image based on it.

Now, let's drive it home by attaching our function to actual events.

Setting up events

We'll need our custom handler kick in on two occasions:

  • When map first loads, so that we can pre-hide images that are not supposed to be shown on full zoom out.
  • When map zoom level changes.

For the first one, we are going to be using datavalidated event on image series itself. Why? Because we definitely need to be sure that our image series has its data parsed and ready, but did not had a chance to draw itself yet. Perfect time to hide some images so they don't end up flashing briefly on the screen.

The second is best handled by chart's zoomlevelchanged.

imageSeries.events.on("datavalidated", updateImageVisibility);
chart.events.on("zoomlevelchanged", updateImageVisibility);
imageSeries.events.on("datavalidated", updateImageVisibility);
chart.events.on("zoomlevelchanged", updateImageVisibility);
{
// ...
"series": [{
// ...
}, {
// ...
"events": {
"datavalidated": updateImageVisibility
}
}],
"events": {
"zoomlevelchanged": updateImageVisibility
}
}

That's it. We're all set.

Working example

See the Pen amCharts 4: Show map images only at specific zoom level by amCharts team (@amcharts) on CodePen.0

Alternative approach

So far we have been micro-managing which markers to show in at which zoom level.

The following demo implements another approach: reveal markers only when there is X or less of them in the current viewport.

Using this approach heavily populated areas might require deeper zoom in, whereas areas with sparsely placed markers would not need as much.

See the Pen amCharts 4: Show map images only at specific zoom level by amCharts team (@amcharts) on CodePen.24419