Drill-Down Congressional Map
A map of the United States that drills down to congressional districts: click a state to zoom in and load the map of its districts.
About this map
When to load maps on demand
Detailed maps are big files, so this one starts with the states and loads a state’s district map only when someone clicks it. The first view loads quickly, and the detail is a click away. The same approach works for countries and their regions, or any two levels of geography.
Good for
- Districts, counties or zip codes within states
- Two levels of geography with large files
- Exploring one area at a time
Think twice when
- Comparing districts across states: show them all at once
- Offline use: the maps load from the CDN
- Readers who won’t click: lead with the key area
For developers
Get the code.
Built with amCharts 5, a JavaScript library. The code includes your theme and renderer (canvas or SVG), but not the changes you make with the controls.
For projects that use npm:
How it reads:
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.How it reads:
"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://docs.amcharts.com/v5/getting-started/#root-element
var root = am5.Root.new("chartdiv");
// Set themes
// https://docs.amcharts.com/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root),
am5themes_Responsive.new(root)
]);
// Hover colors come from the theme's palette
var colors = am5.ColorSet.new(root, {});
// Create the map chart
// https://docs.amcharts.com/v5/charts/map-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,
panX: "translateX", // dragging moves the map sideways (Albers USA can't rotate)
panY: "translateY", // ...and up and down
projection: am5map.geoAlbersUsa(), // a US projection, with Alaska and Hawaii in insets at the lower left
// room for the title above the map
paddingTop: 40
}));
// Zoom control
// https://docs.amcharts.com/v5/charts/map-chart/map-pan-zoom/#zoom-control
var zoomControl = chart.set("zoomControl", am5map.ZoomControl.new(root, {}));
// the home button is hidden by default
zoomControl.homeButton.set("visible", true);
// Create polygon series for the states
// https://docs.amcharts.com/v5/charts/map-chart/map-polygon-series/
var usaSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_usaLow
}));
usaSeries.mapPolygons.template.setAll({
tooltipText: "{name}", // the state's name on hover
interactive: true, // reacts to hover and clicks
templateField: "polygonSettings" // styles from a polygonSettings field in the data, if a state has one
});
// a state turns a palette color under the pointer
usaSeries.mapPolygons.template.states.create("hover", {
fill: colors.getIndex(9)
});
// a click zooms in on the state and loads its congressional districts
usaSeries.mapPolygons.template.events.on("click", (ev) => {
var dataItem = ev.target.dataItem;
// "US-CA" becomes "ca", the state's part of the district map's file name
var id = dataItem.get("id").toLowerCase().split("-").pop();
var name = dataItem.dataContext.name;
var zoomAnimation = usaSeries.zoomToDataItem(dataItem); // zoom in to fit the clicked state
// once the zoom has ended and the districts have loaded, swap the states for the districts
Promise.all([
zoomAnimation.waitForStop(),
am5.net.load("https://cdn.amcharts.com/lib/5/geodata/json/region/usa/congressional120/" + id + "Low.json", chart)
]).then(function(results) {
var geodata = am5.JSONParser.parse(results[1].response);
stateSeries.setAll({
geoJSON: geodata
});
stateSeries.show();
usaSeries.hide(100); // hide the states in 0.1 seconds
backContainer.show();
title.set("text", name);
});
});
// Create polygon series for the districts of the clicked state
// https://docs.amcharts.com/v5/charts/map-chart/map-polygon-series/
var stateSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
visible: false // hidden until a state is clicked
}));
stateSeries.mapPolygons.template.setAll({
tooltipText: "{name}", // the district's name on hover
interactive: true // reacts to hover
});
stateSeries.mapPolygons.template.states.create("hover", {
fill: colors.getIndex(9)
});
// Add button to go back to the whole country
var backContainer = chart.children.push(am5.Container.new(root, {
x: am5.p100, // at the chart's right edge...
centerX: am5.p100, // ...aligned by its own right edge
dx: -10, // 10px in from the edge
paddingTop: 5, // space around the label and the arrow
paddingRight: 10,
paddingBottom: 5,
y: 30, // a little below the top
// the whole box takes the click, not the label and icon inside it
interactiveChildren: false,
layout: root.horizontalLayout, // the label and the arrow side by side
cursorOverStyle: "pointer", // a hand pointer over the button
background: am5.RoundedRectangle.new(root, {
fill: root.interfaceColors.get("background"), // a box in the chart's background color...
fillOpacity: 0.7 // ...slightly see-through
}),
visible: false // hidden until a state is clicked
}));
var backLabel = backContainer.children.push(am5.Label.new(root, {
text: "Back",
centerY: am5.p50 // the label and the arrow line up on their middles
}));
var backButton = backContainer.children.push(am5.Graphics.new(root, {
width: 32, // a 32px icon
height: 32,
centerY: am5.p50,
fill: root.interfaceColors.get("text"), // in the text color, so it shows on light and dark backgrounds
// a back arrow, as SVG path data
svgPath: "M12 9.059V6.5a1.001 1.001 0 0 0-1.707-.708L4 12l6.293 6.207a.997.997 0 0 0 1.414 0A.999.999 0 0 0 12 17.5v-2.489c2.75.068 5.755.566 8 3.989v-1c0-4.633-3.5-8.443-8-8.941z"
}));
// back to the whole country: zoom out and swap the districts for the states
function goBack() {
chart.goHome();
usaSeries.show();
stateSeries.hide();
backContainer.hide();
title.set("text", "United States");
}
backContainer.events.on("click", goBack);
// the zoom control's home button goes back to the whole country too
zoomControl.homeButton.events.on("click", goBack);
// the title sits in the room above the map ("absolute" places it from the chart's top edge, not inside the padding)
var title = chart.children.push(am5.Label.new(root, {
text: "United States",
position: "absolute",
x: am5.p50, // centered across the chart...
centerX: am5.p50, // ...by its own middle
y: 5, // 5px from the top
fontSize: 20, // 20px text
textAlign: "center"
}));
More map tools.

SVG Map Generator
Any region, any projection
Pick a map and projection, simplify it and paint regions, then export SVG or PNG.
Pixel Map Generator
Dotted and pixel-art maps
Turn any map into dots, squares, hexagons or diamonds for posters and slides.

SVG Maps
427 maps, free to download
World, continents, countries and regions, with every region as its own named path.



