Using actual images in MapImageSeries

In our main Map Chart article we have touched the topic of creating an image series, feeding them data, and positioning them. However, we were operating using plain, same shapes. This tutorial will show how we can use actual images as markers on the map.

Using same image

Explaining MapImageSeries in our Map Chart article, we've used simple Circle shape. E.g.:

let imageSeriesTemplate = imageSeries.mapImages.template;
let circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 4;
circle.fill = am4core.color("#B27799");
circle.stroke = am4core.color("#FFFFFF");
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = "{title}";
var imageSeriesTemplate = imageSeries.mapImages.template;
var circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 4;
circle.fill = am4core.color("#B27799");
circle.stroke = am4core.color("#FFFFFF");
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = "{title}";
{
// ...
"series": [{
"type": "MapPolygonSeries",
// ...
}, {
"type": "MapImageSeries",
"mapImages": {
"children": [{
"type": "Circle",
"radius": 4,
"stroke" : "#B27799",
"strokeWidth": 2,
"nonScaling": true,
"tooltipText": "{title}"
}]
}
}]
}

Using real image is not that different: we just replace Circle with an Image, as well as set its appropriate properties, like href.

let imageSeriesTemplate = imageSeries.mapImages.template;
let marker = imageSeriesTemplate.createChild(am4core.Image);
marker.href = "path/to/marker.svg";
marker.width = 20;
marker.height = 20;
marker.nonScaling = true;
marker.tooltipText = "{title}";
marker.horizontalCenter = "middle";
marker.verticalCenter = "bottom";
var imageSeriesTemplate = imageSeries.mapImages.template;
var marker = imageSeriesTemplate.createChild(am4core.Image);
marker.href = "path/to/marker.svg";
marker.width = 20;
marker.height = 20;
marker.nonScaling = true;
marker.tooltipText = "{title}";
marker.horizontalCenter = "middle";
marker.verticalCenter = "bottom";
{
// ...
"series": [{
"type": "MapPolygonSeries",
// ...
}, {
"type": "MapImageSeries",
"mapImages": {
"children": [{
"type": "Image",
"href": "path/to/marker.svg",
"width": 20,
"height": 20,
"nonScaling": true,
"tooltipText": "{title}",
"horizontalCenter": "middle",
"verticalCenter": "bottom"
}]
}
}]
}

NOTE Take note about horizontalCenter and verticalCenter settings. They are important, as they will determine which part of the image is placed at the latitude/longitude coordinates. Since we are using a map pin image, we need it to be centered to bottom/middle.

See the Pen amCharts 4: Map image series with actual images by amCharts team (@amcharts) on CodePen.0

Using different images

Previous section was "stamping out" the same image for all items in our image series.

Now, let's see how we can use different image for each individual item.

Since we are going to be feeding images via data, let's add update our data:

[{
"latitude": 48.856614,
"longitude": 2.352222,
"title": "Paris",
"flag": "path/to/pin_france.png"
}, {
"latitude": 40.712775,
"longitude": -74.005973,
"title": "New York",
"flag": "path/to/pin_usa.png"
}, {
"latitude": 49.282729,
"longitude": -123.120738,
"title": "Vancouver",
"flag": "path/to/pin_canada.png"
}]

Now, all we need to do is to bind our image's href property to flag field in data, instead of hard-coding it.

For that, we are going to be using "property fields". It's a way to bind any property of any object to a field in data.

So, instead of setting marker.href we are going to be doing this:

marker.propertyFields.href = "flag";
marker.propertyFields.href = "flag";
{
// ...
"series": [{
"type": "MapPolygonSeries",
// ...
}, {
"type": "MapImageSeries",
"mapImages": {
"children": [{
// ...
"propertyFields": {
"href": "flag"
}
}]
}
}]
}

That's it!

See the Pen amCharts 4: Map image series with actual images by amCharts team (@amcharts) on CodePen.0

Using SVG paths

Up until now we have been using actual external image files.

We can use an SVG path as well. An SVG path is a list of special geometrical instructions, that define a vector shape.

When comparing it to conventional images - vector (SVG) and bitmap (PNG, JPEG) alike - it has two distinctive advantages:

  1. They are completely in-line. No reliance on external files. Now potential CORS issues.
  2. They can styled using properties like fill, stroke, and even filters. This means that you can either set colors directly, or even via data and/or heat rules.

Below is an SVG path of a star shape:

M9 9l-5 1v1l4 3a2286 2286 0 0 0-1 6l5-3a14908 14908 0 0 0 5 2l-1-5 4-3v-1l-5-1-3-5-3 5z

To use it as a map image, we need to do make following modifications to our map image definition:

  1. Use regular Sprite (instead of Image).
  2. Use its path attribute to set SVG path (instead of href).
let marker = imageSeriesTemplate.createChild(am4core.Sprite);
marker.path = "M9 9l-5 1v1l4 3a2286 2286 0 0 0-1 6l5-3a14908 14908 0 0 0 5 2l-1-5 4-3v-1l-5-1-3-5-3 5z";
marker.fill = am4core.color("#f55");
var marker = imageSeriesTemplate.createChild(am4core.Sprite);
marker.path = "M9 9l-5 1v1l4 3a2286 2286 0 0 0-1 6l5-3a14908 14908 0 0 0 5 2l-1-5 4-3v-1l-5-1-3-5-3 5z";
marker.fill = am4core.color("#f55");
{
// ...
"series": [{
"type": "MapPolygonSeries",
// ...
}, {
"type": "MapImageSeries",
"mapImages": {
"children": [{
"type": "Sprite",
"path": "M9 9l-5 1v1l4 3a2286 2286 0 0 0-1 6l5-3a14908 14908 0 0 0 5 2l-1-5 4-3v-1l-5-1-3-5-3 5z",
"fill": "#f55"
// ...
}]
}
}]
}

NOTE The above example sets path directly to the image template, however it would work just as well with propertyFields.path if you would rather add different shapes for different images.

See the Pen amCharts 4: Map image series with actual images by amCharts team (@amcharts) on CodePen.0