Tutorial: IIIF > Allmaps Editor > Leaflet Map
How to Georeference a Map in Allmaps and Display it with Leaflet
[Work in progress, last updated 8/17/25.]
A step-by-step tutorial on how to georeference a map from DavidRumsey.com or Searchworks.Stanford.edu using Allmaps Editor and then display it in a webmap made with Leafletjs.com.
Example
This tutorial will guide you through the creation of a webmap similar to the one viewable at this link.
Background Info
-
What is georeferencing? https://blogs.loc.gov/maps/2021/01/georeferencing-moving-analog-maps-into-modern-day-gis/
-
What is a IIIF Manifest? https://iiif.io/guides/using_iiif_resources/#what-is-a-iiif-manifest
-
What is Allmaps? https://allmaps.org/
-
What is Leaflet? https://leafletjs.com/
1. Get Started: Locate and copy a IIIF manifest link for your map
IIIF manifest links can be found on many digital repository and library sites. Unfortunately, there’s not much standardization across sites as to where to put them in a record, so you may have to dig around for them. Below are screenshots of where to find manifest links on David Rumsey’s website and in Stanford’s Searchworks library catalog. As of August 2025 the designs of these websites have changed so screenshots may not match their current state.
You do not need to get a link from both places, just choose one to use, copy it, and move to step 2.
A. Find IIIF Manifest on Davidrumsey.com:
- Click SHARE to reveal dropdown menu
- Click “IIIF Manifests” to reveal text box with link
- Click the “duplicate” icon to right of text box to copy link
B. Find IIIF Manifest on Searchworks.stanford.edu:
- Click the “hamburger menu” at upper left to reveal metadata sidebar
- Scroll all the way to the bottom of the sidebar
- Locate the link below “IIIF manifest”
- Right click to copy the link
2. Georeference your map in Allmaps Editor
- Open Allmaps Editor: https://editor.allmaps.org
- Paste your IIIF manifest link into the text box and click “Load”
Create Mask (optional)
On the next page, click “Mask”
- In this step you are selecting the part of the image with the map and masking out the rest. This step is optional, depending on your map.
- Click to add points outlining the part of the map you wish to use
- Complete the mask by clicking on the initial point to “close the loop”.
Georeference the map
- Click on “Georeference”
- Select a location on the “real world” in the window to the right, then select the corresponding point on the map in the window on the left. You have now created a ground control point or GCP!
- Do this 4-6 times, choosing points at locations spread about the map’s area. (You may need more points, depending on how much the map image must be deformed to match with reality.)
- Click “Results”
- Copy the URL at the end of the page
3. Place Georeferenced Map in a Map Layer using Leaflet
To create a webpage in which the Leaflet map will be displayed, we are using GitHub Pages, the same platform underpinning this tutorial and blog.
Set up your repository and GitHub Page
- Create a new GitHub Repository for your webmap project. Mine is called “leaflet”
- Create and publish a GitHub Page in the repository. Mine is called “leaflet_iiif_allmapsxyz.html”
- Install the transparency slider plugin files in your repository
- I downloaded the whole “lib” directory from the repository below and uploaded it to my “leaflet” repository. I’m sure there’s a better way to do this :)
- Transparency slider code Leaflet Plugin
Start building the html for your page
Here is my html for the page through the end of the head section. Note that the links to Leaflet CSS and JS are absolute links to their server, whie the CSS and JS for the opacity slider are relative links to my local installation of fhe files.
<!DOCTYPE html>
<html>
<head>
<title>Leaflet PLUS ALLMAPS XYZ</title>
<!-- Leaflet CSS and JS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
crossorigin="">
</script>
<!--JS and CSS for ControlOpacity plugin slider and buttons, installed in my Leaflet repository-->
<script src="lib/jquery/jquery-1.9.1.js"></script>
<script src="lib/jquery/jquery-ui-1.10.3.custom.min.js"></script>
<link rel="stylesheet" href="lib/jquery/jquery-ui-1.10.3.custom.min.css" />
<link rel="stylesheet" href="lib/opacity/Control.Opacity.css" />
<script src="lib/opacity/Control.Opacity.js"></script>
<!-- CSS for the map container -->
<style>
html, body {
height: 100%;
margin: 0px;
}
.leaflet-container {
height: 1000px;
width: 1200px;
max-width: 100%;
max-height: 100%;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
Continue building the page
- Add html for your webmap, following this tutorial from “Preparing the Page” through “Setting up the Map” (you can ignore everything after “Markers, circles, and polygons” for now).
- Define a second layer for your Allmaps xyz tile, replacing URL with the link you copied in Step 5 above
- OR just copy my code, in which I defined the map container, an Open Street Map layer, and the Allmaps layer with const declarations and then called both layers into the map (again, replace my Allmaps link with yours, and replace the center point per the comment)
<body>
<div id="map" style="width: 1200px; height: 1000px;"></div>
<script>
// Initialize the map and set its view to a specific center point and zoom level.
// Choose center point coordinates that correspond to the center of the historical map you are using.
// Allmaps tile server currently only supports one zoom level; here we set it to 13.
const map = L.map('map', {
center: [37.757144, -122.443657], // San Francisco
zoom: 13,
});
// Define the OpenStreetMap tile layer
const OpenStreetMap = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom:13,
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
// Define the georeferenced historical map tile layer from Allmaps Editor. We've named this "AllMaps"
const AllMaps = L.tileLayer('https://allmaps.xyz/images/ad87bd6513550e53/{z}/{x}/{y}@2x.png', {
maxZoom:13,
attribution:
'© <a href="https://allmaps.xyz">Allmaps</a> contributors'
});
// Add the OpenStreetMap and AllMaps layers to the map
OpenStreetMap.addTo(map);
AllMaps.addTo(map);
Add code for the opacity controller
If you have called your Allmaps layer something different you will need to change the code to match in the last line below.
// Add the ControlOpacity plugin controls
var higherOpacity = new L.Control.higherOpacity();
map.addControl(higherOpacity);
var lowerOpacity = new L.Control.lowerOpacity();
map.addControl(lowerOpacity);
var opacitySlider = new L.Control.opacitySlider();
map.addControl(opacitySlider);
higherOpacity.setOpacityLayer(AllMaps);
Complete the page
Close the script, body, and html containers
</script>
</body>
</html>
Here’s the full html code of the page
<!DOCTYPE html>
<html>
<head>
<title>Leaflet PLUS ALLMAPS XYZ</title>
<!-- Leaflet CSS and JS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
crossorigin="">
</script>
<!--JS and CSS for ControlOpacity plugin slider and buttons, installed in my Leaflet repository-->
<script src="lib/jquery/jquery-1.9.1.js"></script>
<script src="lib/jquery/jquery-ui-1.10.3.custom.min.js"></script>
<link rel="stylesheet" href="lib/jquery/jquery-ui-1.10.3.custom.min.css" />
<link rel="stylesheet" href="lib/opacity/Control.Opacity.css" />
<script src="lib/opacity/Control.Opacity.js"></script>
<!-- CSS for the map container -->
<style>
html, body {
height: 100%;
margin: 0px;
}
.leaflet-container {
height: 1000px;
width: 1200px;
max-width: 100%;
max-height: 100%;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="map" style="width: 1200px; height: 1000px;"></div>
<script>
// Initialize the map and set its view to a specific center point and zoom level.
// Choose center point coordinates that correspond to the center of the historical map you are using.
// Allmaps tile server currently only supports one zoom level; here we set it to 13.
const map = L.map('map', {
center: [37.757144, -122.443657], // San Francisco
zoom: 13,
});
// Define the OpenStreetMap tile layer
const OpenStreetMap = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom:13,
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
// Define the georeferenced historical map tile layer from Allmaps Editor. We've named this "AllMaps"
const AllMaps = L.tileLayer('https://allmaps.xyz/images/ad87bd6513550e53/{z}/{x}/{y}@2x.png', {
maxZoom:13,
attribution:
'© <a href="https://allmaps.xyz">Allmaps</a> contributors'
});
// Add the OpenStreetMap and AllMaps layers to the map
OpenStreetMap.addTo(map);
AllMaps.addTo(map);
// Add the ControlOpacity plugin controls
var higherOpacity = new L.Control.higherOpacity();
map.addControl(higherOpacity);
var lowerOpacity = new L.Control.lowerOpacity();
map.addControl(lowerOpacity);
var opacitySlider = new L.Control.opacitySlider();
map.addControl(opacitySlider);
higherOpacity.setOpacityLayer(AllMaps);
</script>
</body>
</html>