A map of the 27 countries of the European Union, grouped by when they joined. Hover a country and its whole group lights up; the legend switches groups off and on.
Coloring areas by a few categories answers which ones belong together: members and non-members, sales regions, voting blocs. Lighting up the whole group on hover makes the grouping hard to miss. It works best with a handful of groups; past six or seven, the colors are hard to tell apart.
Built with amCharts 5, a JavaScript library. The JavaScript includes your theme and renderer (canvas or SVG); the JSON also follows the changes you make with the controls.
npm install @amcharts/amcharts5 and @amcharts/amcharts5-geodata. See Getting started.
The same chart as a JSON config. Chart Maker reads and writes this format, the library's JSON parser turns it into a chart, and the <am5-chart> element puts it on a page with no code."type" is the class to create and "settings" what you would pass to its new() in code; "properties" fill in its parts, lists such as series and axes or templates such as columns.template; "refs" holds objects used in more than one place ("#series-0" stands for the one named series-0); a string starting with "@" takes a value from another object, such as "@series.get('fill')".
A complete page. Save it as an .html file and open it in a browser.
Paste this into an AI coding assistant to build the chart from scratch. More in amCharts & AI.
// Data: the 27 members of the European Union, grouped by when they joined
var groupData = [
{
"name": "Joined before 2004",
"data": [
{ "id": "AT", "joined": "1995"},
{ "id": "IE", "joined": "1973"},
{ "id": "DK", "joined": "1973"},
{ "id": "FI", "joined": "1995"},
{ "id": "SE", "joined": "1995"},
{ "id": "IT", "joined": "1957"},
{ "id": "FR", "joined": "1957"},
{ "id": "ES", "joined": "1986"},
{ "id": "GR", "joined": "1981"},
{ "id": "DE", "joined": "1957"},
{ "id": "BE", "joined": "1957"},
{ "id": "LU", "joined": "1957"},
{ "id": "NL", "joined": "1957"},
{ "id": "PT", "joined": "1986"}
]
}, {
"name": "Joined in 2004",
"data": [
{ "id": "LT", "joined": "2004" },
{ "id": "LV", "joined": "2004" },
{ "id": "CZ", "joined": "2004" },
{ "id": "SK", "joined": "2004" },
{ "id": "SI", "joined": "2004" },
{ "id": "EE", "joined": "2004" },
{ "id": "HU", "joined": "2004" },
{ "id": "CY", "joined": "2004" },
{ "id": "MT", "joined": "2004" },
{ "id": "PL", "joined": "2004" }
]
}, {
"name": "Joined in 2007",
"data": [
{ "id": "RO", "joined": "2007" },
{ "id": "BG", "joined": "2007" }
]
}, {
"name": "Joined in 2013",
"data": [
{ "id": "HR", "joined": "2013" }
]
}
];
// Create root and chart
var root = am5.Root.new("chartdiv");
// Set themes
root.setThemes([
am5themes_Animated.new(root),
am5themes_Responsive.new(root)
]);
// Create chart
var chart = root.container.children.push(am5map.MapChart.new(root, {
minZoomLevel: 0.5, // zoom out to half the fitted size at most
// go to the home view once the map is fitted
autoHome: true,
homeZoomLevel: 3.5, // the home view is zoomed in on Europe...
homeGeoPoint: { longitude: 10, latitude: 52 } // ...centered on this point
}));
// Create series for the water: a faint fill behind the countries
// https://www.amcharts.com/docs/v5/charts/map-chart/map-polygon-series/#Background_polygon
var waterSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
// the map fits the countries, not this rectangle around the whole world
affectsBounds: false
}));
waterSeries.mapPolygons.template.setAll({
fill: root.interfaceColors.get("alternativeBackground"), // dark on a light background, light on a dark one
fillOpacity: 0.05, // barely there
strokeOpacity: 0 // no outline
});
waterSeries.data.push({
geometry: am5map.getGeoRectangle(90, 180, -90, -180) // north, east, south and west edges: the whole world
});
// Create graticule series: grid lines every 10 degrees
// https://www.amcharts.com/docs/v5/charts/map-chart/graticule-series/
var graticuleSeries = chart.series.push(am5map.GraticuleSeries.new(root, {
step: 10
}));
graticuleSeries.mapLines.template.setAll({
stroke: root.interfaceColors.get("alternativeBackground"), // dark on a light background, light on a dark one
strokeOpacity: 0.08 // very faint
});
// Create world polygon series
var worldSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_worldLow,
exclude: ["AQ"] // no Antarctica
}));
// the other countries in a neutral gray that suits light and dark backgrounds: a solid color 30% of the way from
// the background color to the contrasting one, so a color picked for them shows as it is
worldSeries.mapPolygons.template.setAll({
fill: am5.Color.interpolate(0.3, root.interfaceColors.get("background"), root.interfaceColors.get("alternativeBackground"))
});
// Add legend
var legend = chart.children.push(am5.Legend.new(root, {
// plain square markers instead of markers that copy the look of the series
useDefaultMarker: true,
centerX: am5.p50, // the legend's middle...
x: am5.p50, // ...at the middle of the chart
centerY: am5.p100, // its bottom edge...
y: am5.p100, // ...at the chart's bottom...
dy: -20, // ...20px up from it
background: am5.RoundedRectangle.new(root, {
fill: root.interfaceColors.get("background"), // a box in the background color...
fillOpacity: 0.7 // ...slightly see-through
})
}));
legend.valueLabels.template.set("forceHidden", true) // no value labels in the legend
// Create series for each group
var colors = am5.ColorSet.new(root, {
step: 2 // every other palette color...
});
colors.next(); // ...skipping the first one
am5.array.each(groupData, function(group) {
var countries = [];
var color = colors.next();
am5.array.each(group.data, function(country) {
countries.push(country.id)
});
var polygonSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_worldLow,
// only this group's countries, drawn over the gray world map
include: countries,
name: group.name,
fill: color // in the group's color
}));
polygonSeries.mapPolygons.template.setAll({
tooltipText: "[bold]{name}[/]\nMember since {joined}", // the name in bold, then the year it joined
interactive: true, // reacts to hover
fill: color,
strokeWidth: 1 // 1px borders
});
polygonSeries.mapPolygons.template.states.create("hover", {
fill: am5.Color.brighten(color, -0.3) // a darker shade of the group's color
});
// hovering one country highlights every country in its group
polygonSeries.mapPolygons.template.events.on("pointerover", function(ev) {
ev.target.series.mapPolygons.each(function(polygon) {
polygon.states.applyAnimate("hover");
});
});
polygonSeries.mapPolygons.template.events.on("pointerout", function(ev) {
ev.target.series.mapPolygons.each(function(polygon) {
polygon.states.applyAnimate("default");
});
});
polygonSeries.data.setAll(group.data);
legend.data.push(polygonSeries); // one legend item per group
});
{
"type": "MapChart",
"settings": {
"minZoomLevel": 0.5,
"autoHome": true,
"homeZoomLevel": 3.5,
"homeGeoPoint": {
"longitude": 10,
"latitude": 52
}
},
"properties": {
"series": [
"#series-0",
"#series-1",
"#series-2",
"#series-3",
"#series-4",
"#series-5",
"#series-6"
]
},
"children": [
{
"type": "Legend",
"settings": {
"useDefaultMarker": true,
"centerX": {
"type": "Percent",
"value": 50
},
"x": {
"type": "Percent",
"value": 50
},
"centerY": {
"type": "Percent",
"value": 100
},
"y": {
"type": "Percent",
"value": 100
},
"dy": -20,
"background": {
"type": "RoundedRectangle",
"settings": {
"fill": "@root.interfaceColors.get('background')",
"fillOpacity": 0.7
}
}
},
"properties": {
"data": [
"#series-3",
"#series-4",
"#series-5",
"#series-6"
],
"valueLabels": {
"properties": {
"template": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
],
"refs": [
{
"data-0": [
{
"geometry": {
"type": "GeoRectangle",
"north": 90,
"east": 180,
"south": -90,
"west": -180
},
"__parse": true
}
]
},
{
"data-1": []
},
{
"data-2": []
},
{
"data-3": [
{
"id": "AT",
"joined": "1995",
"__parse": true
},
{
"id": "IE",
"joined": "1973",
"__parse": true
},
{
"id": "DK",
"joined": "1973",
"__parse": true
},
{
"id": "FI",
"joined": "1995",
"__parse": true
},
{
"id": "SE",
"joined": "1995",
"__parse": true
},
{
"id": "IT",
"joined": "1957",
"__parse": true
},
{
"id": "FR",
"joined": "1957",
"__parse": true
},
{
"id": "ES",
"joined": "1986",
"__parse": true
},
{
"id": "GR",
"joined": "1981",
"__parse": true
},
{
"id": "DE",
"joined": "1957",
"__parse": true
},
{
"id": "BE",
"joined": "1957",
"__parse": true
},
{
"id": "LU",
"joined": "1957",
"__parse": true
},
{
"id": "NL",
"joined": "1957",
"__parse": true
},
{
"id": "PT",
"joined": "1986",
"__parse": true
}
]
},
{
"data-4": [
{
"id": "LT",
"joined": "2004",
"__parse": true
},
{
"id": "LV",
"joined": "2004",
"__parse": true
},
{
"id": "CZ",
"joined": "2004",
"__parse": true
},
{
"id": "SK",
"joined": "2004",
"__parse": true
},
{
"id": "SI",
"joined": "2004",
"__parse": true
},
{
"id": "EE",
"joined": "2004",
"__parse": true
},
{
"id": "HU",
"joined": "2004",
"__parse": true
},
{
"id": "CY",
"joined": "2004",
"__parse": true
},
{
"id": "MT",
"joined": "2004",
"__parse": true
},
{
"id": "PL",
"joined": "2004",
"__parse": true
}
]
},
{
"data-5": [
{
"id": "RO",
"joined": "2007",
"__parse": true
},
{
"id": "BG",
"joined": "2007",
"__parse": true
}
]
},
{
"data-6": [
{
"id": "HR",
"joined": "2013",
"__parse": true
}
]
},
{
"series-0": {
"type": "MapPolygonSeries",
"settings": {
"affectsBounds": false
},
"properties": {
"data": "#data-0",
"mapPolygons": {
"properties": {
"template": {
"settings": {
"fill": "@root.interfaceColors.get('alternativeBackground')",
"fillOpacity": 0.05,
"strokeOpacity": 0
}
}
}
}
}
}
},
{
"series-1": {
"type": "GraticuleSeries",
"settings": {
"step": 10
},
"properties": {
"mapLines": {
"properties": {
"template": {
"settings": {
"stroke": "@root.interfaceColors.get('alternativeBackground')",
"strokeOpacity": 0.08
}
}
}
}
}
}
},
{
"series-2": {
"type": "MapPolygonSeries",
"settings": {
"geoJSON": "am5geodata_worldLow",
"exclude": [
"AQ"
]
},
"properties": {
"mapPolygons": {
"properties": {
"template": {
"settings": {
"fill": {
"type": "Color",
"value": "#b2b2b2"
}
}
}
}
}
}
}
},
{
"series-3": {
"type": "MapPolygonSeries",
"settings": {
"geoJSON": "am5geodata_worldLow",
"include": [
"AT",
"IE",
"DK",
"FI",
"SE",
"IT",
"FR",
"ES",
"GR",
"DE",
"BE",
"LU",
"NL",
"PT"
],
"name": "Joined before 2004",
"fill": {
"type": "Color",
"value": "#6771dc"
}
},
"properties": {
"data": "#data-3",
"mapPolygons": {
"properties": {
"template": {
"settings": {
"tooltipText": "[bold]{name}[/]\nMember since {joined}",
"interactive": true,
"fill": {
"type": "Color",
"value": "#6771dc"
},
"strokeWidth": 1
},
"states": [
{
"key": "hover",
"settings": {
"fill": {
"type": "Color",
"value": "#252f9a"
}
}
}
]
}
}
}
}
}
},
{
"series-4": {
"type": "MapPolygonSeries",
"settings": {
"geoJSON": "am5geodata_worldLow",
"include": [
"LT",
"LV",
"CZ",
"SK",
"SI",
"EE",
"HU",
"CY",
"MT",
"PL"
],
"name": "Joined in 2004",
"fill": {
"type": "Color",
"value": "#a367dc"
}
},
"properties": {
"data": "#data-4",
"mapPolygons": {
"properties": {
"template": {
"settings": {
"tooltipText": "[bold]{name}[/]\nMember since {joined}",
"interactive": true,
"fill": {
"type": "Color",
"value": "#a367dc"
},
"strokeWidth": 1
},
"states": [
{
"key": "hover",
"settings": {
"fill": {
"type": "Color",
"value": "#61259a"
}
}
}
]
}
}
}
}
}
},
{
"series-5": {
"type": "MapPolygonSeries",
"settings": {
"geoJSON": "am5geodata_worldLow",
"include": [
"RO",
"BG"
],
"name": "Joined in 2007",
"fill": {
"type": "Color",
"value": "#dc67ce"
}
},
"properties": {
"data": "#data-5",
"mapPolygons": {
"properties": {
"template": {
"settings": {
"tooltipText": "[bold]{name}[/]\nMember since {joined}",
"interactive": true,
"fill": {
"type": "Color",
"value": "#dc67ce"
},
"strokeWidth": 1
},
"states": [
{
"key": "hover",
"settings": {
"fill": {
"type": "Color",
"value": "#9a258c"
}
}
}
]
}
}
}
}
}
},
{
"series-6": {
"type": "MapPolygonSeries",
"settings": {
"geoJSON": "am5geodata_worldLow",
"include": [
"HR"
],
"name": "Joined in 2013",
"fill": {
"type": "Color",
"value": "#dc6788"
}
},
"properties": {
"data": "#data-6",
"mapPolygons": {
"properties": {
"template": {
"settings": {
"tooltipText": "[bold]{name}[/]\nMember since {joined}",
"interactive": true,
"fill": {
"type": "Color",
"value": "#dc6788"
},
"strokeWidth": 1
},
"states": [
{
"key": "hover",
"settings": {
"fill": {
"type": "Color",
"value": "#9a2546"
}
}
}
]
}
}
}
}
}
}
]
}
