A weather map of Europe: an animated icon and the temperature for seven capitals, picked from the data through template fields. The weather is made up.
Pictures read faster than numbers: a sun or a storm cloud tells the weather before anyone reads the temperature. Here each city’s icon and label come from its data, so a new forecast only means new data. Keep the icons few and far apart, or they cover the map.
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. Map 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.
// Create root element
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
var root = am5.Root.new("chartdiv");
// Set themes
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root),
am5themes_Responsive.new(root)
]);
// Create the map chart
// https://www.amcharts.com/docs/v5/charts/map-chart/
var chart = root.container.children.push(am5map.MapChart.new(root, {
// near-black space behind the satellite picture, shown only with it
background: am5.Rectangle.new(root, {
fill: am5.color(0x101318),
fillOpacity: 0 // invisible until the satellite view turns it on
}),
minZoomLevel: 0.5, // the map can zoom out to half its fitted size
// go to the home view once the map is fitted
autoHome: true,
panX: "translateX", // drag the map to move it sideways...
panY: "translateY", // ...and up and down
projection: am5map.geoMercator(), // the Mercator projection, as on most web maps
// the home view: central Europe, zoomed in 6 times
homeGeoPoint: { longitude: 10, latitude: 51 },
homeZoomLevel: 6
}));
// 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"), // the theme's contrast color...
fillOpacity: 0.05, // ...at 5%, a faint tint
strokeOpacity: 0 // no outline
});
waterSeries.data.push({
geometry: am5map.getGeoRectangle(90, 180, -90, -180) // north, east, south and west edges: the whole world
});
// Satellite view: NASA's picture of the Earth by day, under the grid lines and the countries. Hidden at first
// (visible: false): make it visible for the satellite view
// https://www.amcharts.com/docs/v5/charts/map-chart/map-raster-series/
var satelliteSeries = chart.series.push(am5map.MapRasterSeries.new(root, {
visible: false,
// the map fits the countries, not the whole picture
affectsBounds: false
}));
// 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"), // the theme's contrast color...
strokeOpacity: 0.08 // ...very faint
});
// Create main polygon series for countries
// https://www.amcharts.com/docs/v5/charts/map-chart/map-polygon-series/
var polygonSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_worldLow, // the world's countries, in low detail...
exclude: ["AQ"] // ...without Antarctica
}));
// gray land in light and dark themes, so the weather icons stand out
polygonSeries.mapPolygons.template.setAll({
fill: root.interfaceColors.get("alternativeBackground"),
fillOpacity: 0.15
});
// Add zoom control
// https://www.amcharts.com/docs/v5/charts/map-chart/map-pan-zoom/#Zoom_control
var zoomControl = chart.set("zoomControl", am5map.ZoomControl.new(root, {}));
zoomControl.homeButton.set("visible", true); // a button that goes back to the home view
// Set clicking on "water" to zoom out
chart.chartContainer.get("background").events.on("click", function() {
chart.goHome();
})
// Create point series for the cities
// https://www.amcharts.com/docs/v5/charts/map-chart/map-point-series/
var pointSeries = chart.series.push(am5map.MapPointSeries.new(root, {}));
// All icons share one template and all labels another, so each can be changed at once.
// The icon and the text come from the data, through template fields.
var iconTemplate = am5.Template.new({
width: 50, // 50px icons...
height: 50,
centerX: am5.p50, // ...centered on the city
centerY: am5.p50
});
var labelTemplate = am5.Template.new({
centerX: am5.p50, // the city's name centered...
dy: 10 // ...and 10px lower than the city's point
});
pointSeries.bullets.push(function() {
return am5.Bullet.new(root, {
sprite: am5.Picture.new(root, {
templateField: "pictureSettings"
}, iconTemplate)
});
});
pointSeries.bullets.push(function() {
return am5.Bullet.new(root, {
sprite: am5.Label.new(root, {
templateField: "labelSettings"
}, labelTemplate)
});
});
// Made-up weather in seven cities
pointSeries.data.setAll([{
geometry: { type: "Point", coordinates: [-3.703790, 40.416775] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/rainy-1.svg"
},
labelSettings: {
text: "Madrid: +22°C"
}
},
{
geometry: { type: "Point", coordinates: [2.352222, 48.856614] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/thunder.svg"
},
labelSettings: {
text: "Paris: +18°C"
}
},
{
geometry: { type: "Point", coordinates: [13.404954, 52.520007] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/cloudy-day-1.svg"
},
labelSettings: {
text: "Berlin: +13°C"
}
},
{
geometry: { type: "Point", coordinates: [21.012229, 52.229676] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/day.svg"
},
labelSettings: {
text: "Warsaw: +22°C"
}
},
{
geometry: { type: "Point", coordinates: [12.480180, 41.872389] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/day.svg"
},
labelSettings: {
text: "Rome: +29°C"
}
},
{
geometry: { type: "Point", coordinates: [-0.127758, 51.507351] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/rainy-7.svg"
},
labelSettings: {
text: "London: +10°C"
}
},
{
geometry: { type: "Point", coordinates: [18.068581, 59.329323] },
pictureSettings: {
src: "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/rainy-1.svg"
},
labelSettings: {
text: "Stockholm: +8°C"
}
}
])
// The image credit
var credit = chart.children.push(am5.Label.new(root, {
text: "Imagery: NASA Earth Observatory",
fontSize: 12, // in pixels
fill: am5.color(0xffffff), // white, over the dark satellite picture
fillOpacity: 0.6, // slightly faded
x: am5.p100, // at the right edge...
centerX: am5.p100,
dx: -10, // ...10px in from it
y: 10, // 10px from the top
visible: false // shown only with the satellite view
}));
// The countries' own look, to go back to
var landTemplate = polygonSeries.mapPolygons.template;
var landLook = {
fillOpacity: landTemplate.get("fillOpacity", 1),
stroke: landTemplate.get("stroke", root.interfaceColors.get("background")),
strokeOpacity: landTemplate.get("strokeOpacity", 1)
};
// The picture loads the first time it shows. Then the countries turn to white outlines over it, the grid lines and
// the city labels turn white, the credit shows and the map sits in near-black space
satelliteSeries.on("visible", function(visible) {
if (visible) {
satelliteSeries.set("src", "https://cdn.amcharts.com/lib/5/geodata/images/earthDay2048.jpg");
}
credit.set("visible", visible);
chart.get("background").set("fillOpacity", visible ? 1 : 0);
landTemplate.setAll(visible ? { fillOpacity: 0, stroke: am5.color(0xffffff), strokeOpacity: 0.6 } : landLook);
graticuleSeries.mapLines.template.set("stroke", visible ? am5.color(0xffffff) : root.interfaceColors.get("alternativeBackground"));
labelTemplate.set("fill", visible ? am5.color(0xffffff) : root.interfaceColors.get("text"));
});
// Make stuff animate on load
chart.appear(1000, 100);
{
"type": "MapChart",
"settings": {
"background": {
"type": "Rectangle",
"settings": {
"fill": {
"type": "Color",
"value": "#101318"
},
"fillOpacity": 0
}
},
"minZoomLevel": 0.5,
"autoHome": true,
"panX": "translateX",
"panY": "translateY",
"homeGeoPoint": {
"longitude": 10,
"latitude": 51
},
"homeZoomLevel": 6,
"zoomControl": {
"type": "ZoomControl",
"properties": {
"homeButton": {
"settings": {
"visible": true
}
}
}
},
"projectionName": "geoMercator"
},
"properties": {
"series": [
"#series-0",
"#series-1",
"#series-2",
"#series-3",
"#series-4"
]
},
"children": [
{
"type": "Label",
"settings": {
"text": "Imagery: NASA Earth Observatory",
"fontSize": 12,
"fill": {
"type": "Color",
"value": "#ffffff"
},
"fillOpacity": 0.6,
"x": {
"type": "Percent",
"value": 100
},
"centerX": {
"type": "Percent",
"value": 100
},
"dx": -10,
"y": 10,
"visible": false
},
"index": 2
}
],
"refs": [
{
"data-0": [
{
"geometry": {
"type": "GeoRectangle",
"north": 90,
"east": 180,
"south": -90,
"west": -180
},
"__parse": true
}
]
},
{
"data-1": []
},
{
"data-2": []
},
{
"data-3": [
{
"geometry": {
"type": "Point",
"coordinates": [
-3.70379,
40.416775
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/rainy-1.svg"
},
"labelSettings": {
"text": "Madrid: +22°C"
},
"__parse": true
},
{
"geometry": {
"type": "Point",
"coordinates": [
2.352222,
48.856614
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/thunder.svg"
},
"labelSettings": {
"text": "Paris: +18°C"
},
"__parse": true
},
{
"geometry": {
"type": "Point",
"coordinates": [
13.404954,
52.520007
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/cloudy-day-1.svg"
},
"labelSettings": {
"text": "Berlin: +13°C"
},
"__parse": true
},
{
"geometry": {
"type": "Point",
"coordinates": [
21.012229,
52.229676
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/day.svg"
},
"labelSettings": {
"text": "Warsaw: +22°C"
},
"__parse": true
},
{
"geometry": {
"type": "Point",
"coordinates": [
12.48018,
41.872389
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/day.svg"
},
"labelSettings": {
"text": "Rome: +29°C"
},
"__parse": true
},
{
"geometry": {
"type": "Point",
"coordinates": [
-0.127758,
51.507351
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/rainy-7.svg"
},
"labelSettings": {
"text": "London: +10°C"
},
"__parse": true
},
{
"geometry": {
"type": "Point",
"coordinates": [
18.068581,
59.329323
],
"__parse": true
},
"pictureSettings": {
"src": "https://www.amcharts.com/wp-content/uploads/assets/weather/animated/rainy-1.svg"
},
"labelSettings": {
"text": "Stockholm: +8°C"
},
"__parse": true
}
]
},
{
"template-0": {
"type": "Template",
"settings": {
"width": 50,
"height": 50,
"centerX": {
"type": "Percent",
"value": 50
},
"centerY": {
"type": "Percent",
"value": 50
}
}
}
},
{
"template-1": {
"type": "Template",
"settings": {
"centerX": {
"type": "Percent",
"value": 50
},
"dy": 10
}
}
},
{
"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": "MapRasterSeries",
"settings": {
"visible": false,
"affectsBounds": false
}
}
},
{
"series-2": {
"type": "GraticuleSeries",
"settings": {
"step": 10
},
"properties": {
"mapLines": {
"properties": {
"template": {
"settings": {
"stroke": "@root.interfaceColors.get('alternativeBackground')",
"strokeOpacity": 0.08
}
}
}
}
}
}
},
{
"series-3": {
"type": "MapPolygonSeries",
"settings": {
"geoJSON": "am5geodata_worldLow",
"exclude": [
"AQ"
]
},
"properties": {
"mapPolygons": {
"properties": {
"template": {
"settings": {
"fill": "@root.interfaceColors.get('alternativeBackground')",
"fillOpacity": 0.15
}
}
}
}
}
}
},
{
"series-4": {
"type": "MapPointSeries",
"properties": {
"data": "#data-3",
"bullets": [
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Picture",
"settings": {
"templateField": "pictureSettings"
},
"properties": {
"template": "#template-0"
}
}
}
},
{
"type": "Bullet",
"settings": {
"sprite": {
"type": "Label",
"settings": {
"templateField": "labelSettings"
},
"properties": {
"template": "#template-1"
}
}
}
}
]
}
}
}
]
}
