Map point series
Map point series can be used to add points (markers) at specific coordinates on the map.
Adding series
Section titled “Adding series”To create a map line series we need to call its new() method and push the new object into chart’s series list:
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... }));var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... }));Markers
Section titled “Markers”Marker template
Section titled “Marker template”Markers (or points) on a map point series are bullets. We create them like on any other series: by pushing a function that returns Bullet object into bullets list of the series.
It can be any visual element, from as simple as a Circle or a Label, to a full-fledged chart.
pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) });});pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) });});Whenever a point/marker will need to be created (as per data explained below), series will call the bullet function to create an actual element.
Auto-scaling markers
Section titled “Auto-scaling markers”Markers (bullets) will stay the same size when map is panned or zoomed.
If we’d rather they grew when zoomed in (and shrank when zoomed out), we can set series’ autoScale property to true.
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... autoScale: true }));var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... autoScale: true }));Surface bullets
Section titled “Surface bullets”Normally, markers face the viewer, whatever the projection. With surfaceBullets: true, they are laid onto the map instead, as if painted on it: each one turns, squashes, and stretches with the map at its location.
On a globe, such markers flatten towards its edge. On a Mercator map, they grow towards the poles, just like the countries do.
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... surfaceBullets: true }));var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { // ... surfaceBullets: true }));There is a number of ways to add data to series. Let’s explore them.
GeoJSON
Section titled “GeoJSON”Point series accepts data in GeoJSON format. It will pick out features of type Point and MultiPoint.
Here’s an example of a simple GeoJSON data, depicting three points: New York City, London, and Beijing.
{ "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": { "name": "New York City" }, "geometry": { "type": "Point", "coordinates": [-73.778137, 40.641312] } }, { "type": "Feature", "properties": { "name": "London" }, "geometry": { "type": "Point", "coordinates": [-0.454296, 51.470020] } }, { "type": "Feature", "properties": { "name": "Beijing" }, "geometry": { "type": "Point", "coordinates": [116.597504, 40.072498] } }]}We can set such data directly to series geoJSON property:
let cities = { "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": { "name": "New York City" }, "geometry": { "type": "Point", "coordinates": [-73.778137, 40.641312] } }, { "type": "Feature", "properties": { "name": "London" }, "geometry": { "type": "Point", "coordinates": [-0.454296, 51.470020] } }, { "type": "Feature", "properties": { "name": "Beijing" }, "geometry": { "type": "Point", "coordinates": [116.597504, 40.072498] } }]};
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { geoJSON: cities }));var cities = { "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": { "name": "New York City" }, "geometry": { "type": "Point", "coordinates": [-73.778137, 40.641312] } }, { "type": "Feature", "properties": { "name": "London" }, "geometry": { "type": "Point", "coordinates": [-0.454296, 51.470020] } }, { "type": "Feature", "properties": { "name": "Beijing" }, "geometry": { "type": "Point", "coordinates": [116.597504, 40.072498] } }]};
var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { geoJSON: cities }));Plain data
Section titled “Plain data”Another way to set data is via series data interface.
There are two ways to do that:
- Arrays containing objects with GeoJSON-like geometry syntax.
- Arrays of objects containing proprietary keys bound to series via its
latitudeFieldandlongitudeFieldsettings.
Using GeoJSON-like geometry
Section titled “Using GeoJSON-like geometry”With this approach, each item in data needs to have at least geometry key in it, that identifies points. Basically, it’s a subset of a GeoJSON format:
pointSeries.data.setAll([{ geometry: { type: "Point", coordinates: [-73.778137, 40.641312] }}, { geometry: { type: "Point", coordinates: [-0.454296, 51.470020] }}, { geometry: { type: "Point", coordinates: [116.597504, 40.072498] }}]);pointSeries.data.setAll([{ geometry: { type: "Point", coordinates: [-73.778137, 40.641312] }}, { geometry: { type: "Point", coordinates: [-0.454296, 51.470020] }}, { geometry: { type: "Point", coordinates: [116.597504, 40.072498] }}]);Using custom data fields
Section titled “Using custom data fields”This approach requires setting series’ latitudeField and longitudeField to indicate which keys in data hold latitude and longitude values.
While it requires additional configuration, it allows data to be considerably simpler:
var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "long"}));
pointSeries.data.setAll([{ long: -73.778137, lat: 40.641312}, { long: -0.454296, lat: 51.470020}, { long: 116.597504, lat: 40.072498}]);var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "long"}));
pointSeries.data.setAll([{ long: -73.778137, lat: 40.641312}, { long: -0.454296, lat: 51.470020}, { long: 116.597504, lat: 40.072498}]);Individual data items
Section titled “Individual data items”We can also use series pushDataItem() method to add data points one-by-one.
The parameter is an object that adheres to IMapPointSeriesDataItem interface.
let nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 });let london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 });let beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 });var nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 });var london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 });var beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 });Relation to polygon series
Section titled “Relation to polygon series”Point series can use a map polygon series to position its markers.
Via ID data field
Section titled “Via ID data field”If we are using series data to points, we can include an ID of the related polygon in it, then set polygonIdField setting to let series know we are providing polygon ids.
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { polygonIdField: "country" }));
pointSeries.data.setAll([{ country: "CA", name: "Canada"}, { country: "US", name: "United States"},{ country: "MX", name: "Mexico"}]);var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { polygonIdField: "country" }));
pointSeries.data.setAll([{ country: "CA", name: "Canada"}, { country: "US", name: "United States"},{ country: "MX", name: "Mexico"}]);Via data items
Section titled “Via data items”We can do that with custom-created point data items, too:
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}));
pointSeries.pushDataItem({ polygonId: "CA", name: "Canada" });pointSeries.pushDataItem({ polygonId: "US", name: "United States" });pointSeries.pushDataItem({ polygonId: "MX", name: "Mexico" });var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}));
pointSeries.pushDataItem({ polygonId: "CA", name: "Canada" });pointSeries.pushDataItem({ polygonId: "US", name: "United States" });pointSeries.pushDataItem({ polygonId: "MX", name: "Mexico" });Automatic labels
Section titled “Automatic labels”We can also automate the above process, by utilizing polygon series’ datavalidated event, to automatically build data for our point series:
polygonSeries.events.on("datavalidated", function(ev) { let series = ev.target; let labelData = []; series.mapPolygons.each(function(polygon) { labelData.push({ polygonId: polygon.dataItem.get("id"), name: polygon.dataItem.get("name") }) }) pointSeries.data.setAll(labelData);});polygonSeries.events.on("datavalidated", function(ev) { var series = ev.target; var labelData = []; series.mapPolygons.each(function(polygon) { var id = polygon.dataItem.get("id"); labelData.push({ polygonId: polygon.dataItem.get("id"), name: polygon.dataItem.get("name") }); }) pointSeries.data.setAll(labelData);});Relation to line series
Section titled “Relation to line series”Connecting line series points
Section titled “Connecting line series points”We can use actual data items from a map line series as points for the line from a map line series.
This eliminates the need to define geometry for our lines, as we can use pointsToConnect setting instead, which is an array of map line series’ data items:
// Create point serieslet pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}));
let nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 });let london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 });let beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 });
// Create line serieslet lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}));
lineSeries.pushDataItem({ pointsToConnect: [nyc, london, beijing]});// Create point seriesvar pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}));
var nyc = pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137 });var london = pointSeries.pushDataItem({ latitude: 51.470020, longitude: -0.454296 });var beijing = pointSeries.pushDataItem({ latitude: 40.072498, longitude: 116.597504 });
// Create line seriesvar lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}));
lineSeries.pushDataItem({ pointsToConnect: [nyc, london, beijing]});Points on a line
Section titled “Points on a line”This can also work the other way around: we can make a data item form map line series “stick” to any point on a line.
All we have to do is to set lineDataItem to a data item of the specific line, as well as positionOnLine to indicate relative position, when creating a point series data item:
// Create line serieslet lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}));
let route = lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: [ [ -73.778137, 40.641312 ], [ -0.454296, 51.470020 ], [ 116.597504, 40.072498 ] ] }});
// Create point serieslet pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}));
pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) });});
let plane = pointSeries.pushDataItem({ lineDataItem: route, positionOnLine: 0.7, autoRotate: true});// Create line seriesvar lineSeries = chart.series.push( am5map.MapLineSeries.new(root, {}));
var route = lineSeries.pushDataItem({ geometry: { type: "LineString", coordinates: [ [ -73.778137, 40.641312 ], [ -0.454296, 51.470020 ], [ 116.597504, 40.072498 ] ] }});
// Create point seriesvar pointSeries = chart.series.push( am5map.MapPointSeries.new(root, {}));
pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000) }) });});
var plane = pointSeries.pushDataItem({ lineDataItem: route, positionOnLine: 0.7, autoRotate: true});Let’s examine the code above.
The pointSeries.pushDataItem() creates a new point in point (item) series. Normally it would contain a latitude/longitude information, but since we’re sticking it to a line, we use different settings:
| Setting key | Comment |
|---|---|
lineDataItem |
A data item from map line series. Created with pushDataItem() on a line series, or extracted from series dataItems. |
positionOnLine |
Relative position on the line. 0 (zero) means the beginning, and 1 (one) the end. Any intermediate number will indicate relative position along the whole line.In case the line is multi-segmented, the position is calculated from the beginning of the first segment to the end of the last one. |
autoRotate |
If set to true, point bullet will be automatically rotated to the angle of the exact point in line. |
autoRotateAngle |
If set, this will be added to the angle calculated by autoRotate. Can be used to reverse the direction. |
The below example uses above code, albeit with the slightly more sophisticated image as a point bullet:
Via data
Section titled “Via data”Points can be put on lines via series data, too. Give the line an id, and refer to it in the point’s lineId:
lineSeries.data.setAll([{ id: "route", geometry: { type: "LineString", coordinates: [ [ -73.778137, 40.641312 ], [ -0.454296, 51.470020 ], [ 116.597504, 40.072498 ] ] }}]);
pointSeries.data.setAll([{ lineId: "route", positionOnLine: 0.7, autoRotate: true}]);lineSeries.data.setAll([{ id: "route", geometry: { type: "LineString", coordinates: [ [ -73.778137, 40.641312 ], [ -0.454296, 51.470020 ], [ 116.597504, 40.072498 ] ] }}]);
pointSeries.data.setAll([{ lineId: "route", positionOnLine: 0.7, autoRotate: true}]);If the data uses other names for these keys, set them with series’ lineIdField, positionOnLineField, autoRotateField, and autoRotateAngleField settings.
Points follow their line when it changes, e.g. when it is moved or given a new altitude.
Altitude
Section titled “Altitude”Points can float above the ground, e.g. satellites or aircraft. The height is in metres: 400000 is about the height of the International Space Station.
To read heights from data, set series’ altitudeField:
let pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "long", altitudeField: "altitude" }));
pointSeries.data.setAll([{ name: "ISS", long: -73.778137, lat: 40.641312, altitude: 400000}]);var pointSeries = chart.series.push( am5map.MapPointSeries.new(root, { latitudeField: "lat", longitudeField: "long", altitudeField: "altitude" }));
pointSeries.data.setAll([{ name: "ISS", long: -73.778137, lat: 40.641312, altitude: 400000}]);altitudeField is not set by default, so data that happens to have an “altitude” key (e.g. elevation above sea level, or a value in feet) is not used as height by accident.
When adding points one by one, set altitude on the data item:
pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137, altitude: 400000 });pointSeries.pushDataItem({ latitude: 40.641312, longitude: -73.778137, altitude: 400000 });On a globe, raised points rise away from its surface. On flat maps they rise up the screen.
A point on a line takes the line’s altitude instead. For lines that arc above the ground, see “Map line series”.
Hover behavior
Section titled “Hover behavior”Adding tooltips
Section titled “Adding tooltips”To add a tooltip to the points/markers, we can use tooltipText on a related bullet.
The value may contain data placeholders as well as in-line text styles.
pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }) });});pointSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" }) });});Hover states
Section titled “Hover states”We can set values to apply to point bullets when it is hovered by creating a “hover” state for them.
pointSeries.bullets.push(function() { let circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" });
circle.states.create("hover", { fill: am5.color(0x00ff00) });
return am5.Bullet.new(root, { sprite: circle });});pointSeries.bullets.push(function() { var circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" });
circle.states.create("hover", { fill: am5.color(0x00ff00) });
return am5.Bullet.new(root, { sprite: circle });});Events
Section titled “Events”To attach events like click and hover on map point series we will need to add them on its bullets when they are created.
pointSeries.bullets.push(function() { let circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" });
circle.events.on("click", function(ev) { console.log(ev.target.dataItem); });
return am5.Bullet.new(root, { sprite: circle });});pointSeries.bullets.push(function() { var circle = am5.Circle.new(root, { radius: 5, fill: am5.color(0xff0000), tooltipText: "{name}" });
circle.events.on("click", function(ev) { console.log(ev.target.dataItem); });
return am5.Bullet.new(root, { sprite: circle });});