- Published on
Using amCharts 5 Map with Nextjs for data visualization.
amCharts 5 is a powerful programming library designed for data visualization. It offers various chart types, including maps, and is free to use as long as the amCharts logo is displayed. This blog will guide you through the steps to integrate amCharts 5 Map with a Next.js project, helping you create interactive maps for your next web application.
Create NextJS project
To get started, you'll first need to create a new Next.js project. You can do this by running the following command in your terminal:
npx create-next-app@latest your-project-name
cd your-project-name
Now, you're ready to start working with amCharts.
Install am5charts 5
Next, you'll need to install the necessary amCharts 5 packages. Run the following commands in your terminal:
npm install @amcharts/amcharts5
npm install @amcharts/amcharts5-geodata
npm install @amcharts/amcharts5-fonts
These packages include the core amCharts library, geographical data for maps, and additional fonts to enhance the appearance of your charts.
Imports
Now, let's import the necessary modules into your component. Here's how to do it:
import * as am5 from "@amcharts/amcharts5";
import * as am5map from "@amcharts/amcharts5/map";
import am5geodata_worldLow from "@amcharts/amcharts5-geodata/worldLow";
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import { useEffect } from "react";
These imports bring in the core amCharts functionality, map chart capabilities, geographical data for the world map, and an animated theme to make your map visually appealing.
Basic Component Setup
Let's create a basic component to render the map. This component will include a div element where the map will be displayed:
export default function MapWithClusteredPoints() {
return (
<main>
{/* amCharts5 div */}
<div
id="chartdiv"
className="mt-[28px] md:mt-[110px]"
style={{ width: "100%", height: "500px" }}
></div>
</main>
);
}
Adding Map Functionality with useEffect
To bring the map to life, you'll need to add some JavaScript code that initializes the map and handles its behavior. This code should be placed inside the useEffect hook to ensure it runs when the component is mounted:
useEffect(() => {
/* Chart code */
// Create root element
let root = am5.Root.new("chartdiv");
// Set themes
root.setThemes([am5themes_Animated.new(root)]);
// Create the map chart
let chart = root.container.children.push(
am5map.MapChart.new(root, {
panX: "rotateX",
panY: "translateY",
projection: am5map.geoMercator(),
})
);
let zoomControl = chart.set(
"zoomControl",
am5map.ZoomControl.new(root, {})
);
zoomControl.homeButton.set("visible", true);
// Create main polygon series for countries
// https://www.amcharts.com/docs/v5/charts/map-chart/map-polygon-series/
let polygonSeries = chart.series.push(
am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_worldLow,
exclude: ["AQ"],
})
);
polygonSeries.mapPolygons.template.setAll({
fill: am5.color(0xdadada),
});
// Create point series for markers
// https://www.amcharts.com/docs/v5/charts/map-chart/map-point-series/
let pointSeries = chart.series.push(
am5map.ClusteredPointSeries.new(root, {})
);
// Set clustered bullet
// https://www.amcharts.com/docs/v5/charts/map-chart/clustered-point-series/#Group_bullet
pointSeries.set("clusteredBullet", function (root) {
let container = am5.Container.new(root, {
cursorOverStyle: "pointer",
});
let circle1 = container.children.push(
am5.Circle.new(root, {
radius: 8,
tooltipY: 0,
fill: am5.color(0xff8c00),
})
);
let circle2 = container.children.push(
am5.Circle.new(root, {
radius: 12,
fillOpacity: 0.3,
tooltipY: 0,
fill: am5.color(0xff8c00),
})
);
let circle3 = container.children.push(
am5.Circle.new(root, {
radius: 16,
fillOpacity: 0.3,
tooltipY: 0,
fill: am5.color(0xff8c00),
})
);
let label = container.children.push(
am5.Label.new(root, {
centerX: am5.p50,
centerY: am5.p50,
fill: am5.color(0xffffff),
populateText: true,
fontSize: "8",
text: "{value}",
})
);
container.events.on("click", function (e) {
pointSeries.zoomToCluster(e.target.dataItem);
});
return am5.Bullet.new(root, {
sprite: container,
});
});
// Create regular bullets
pointSeries.bullets.push(function () {
let circle = am5.Circle.new(root, {
radius: 6,
tooltipY: 0,
fill: am5.color(0xff8c00),
tooltipText: "{title}",
});
return am5.Bullet.new(root, {
sprite: circle,
});
});
// Set data
var cities = [
{ title: "Malibu, California", latitude: 36.7783, longitude: -119.4179 },
{ title: "Brooklyn, NY", latitude: 40.7128, longitude: -74.006 },
{ title: "Detroit, MI", latitude: 44.3148, longitude: -85.6024 },
{ title: "Tokyo, Japan", latitude: 35.6824, longitude: 139.759 },
{ title: "Istanbul, Turkey", latitude: 41.0082, longitude: 28.9784 },
{ title: "Mumbai, India", latitude: 19.076, longitude: 72.8777 },
{ title: "Shanghai, China", latitude: 31.2304, longitude: 121.4737 },
];
for (var i = 0; i < cities.length; i++) {
let city = cities[i];
addCity(city.longitude, city.latitude, city.title);
}
function addCity(longitude: number, latitude: number, title: string) {
pointSeries.data.push({
geometry: { type: "Point", coordinates: [longitude, latitude] },
title: title,
});
}
// Make stuff animate on load
chart.appear(1000, 100);
This block of code sets up the map, adds a zoom control, and creates two series: a polygon series for countries and a point series for markers. It also handles clustering of points and adds interactivity with click events.
Cleaning Up
It's important to clean up the map when the component is unmounted to prevent memory leaks. This is done by returning a cleanup function inside the useEffect hook:
// cleaning
return () => {
root.dispose();
};
Result
Conclusion
Using amCharts 5 with Next.js is a straightforward process that allows you to create interactive and visually appealing maps. By following the steps outlined in this blog, you can quickly integrate amCharts 5 into your Next.js project and enhance your web applications with dynamic data visualizations.
Feel free to customize the map further to suit your project's specific needs, and explore the amCharts documentation for more advanced features and customization options.