Creating a Leaflet Map with Custom GeoTIFF Files

Dara
3 min readAug 11, 2024

--

A few weeks ago, I was working on a project to create a Leaflet map with a custom GeoTIFF file. I did some research on how to integrate GeoTIFF into Leaflet, but it was challenging to find resources on this topic. After several days of searching, I finally discovered a solution. I decided to write this blog post to help others who want to use GeoTIFF files with Leaflet.

What is a GeoTIFF file?

Let’s start with an explanation of what a GeoTIFF file is. A GeoTIFF is a type of raster image file that contains geospatial information embedded within the file. It is a standard image file, but with added geolocation information, allowing it to be accurately placed on a map.

We can display GeoTIFF file information using Python libraries. I installed GDAL using Conda on Ubuntu 22.04 with the following command:

conda install -c conda-forge gdal

To verify the installation, run:

gdal --version

I downloaded an GeoTIFF file on geotiff samples.

When I run gdalinfo cea.tif command on terminal, you should see following output:

Driver: GTiff/GeoTIFF
Files: cea.tif
Size is 514, 515
Coordinate System is:
PROJCRS["unnamed",
BASEGEOGCRS["NAD27",
DATUM["North American Datum 1927",
ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4267]],
CONVERSION["Lambert Cylindrical Equal Area",
METHOD["Lambert Cylindrical Equal Area",
ID["EPSG",9835]],
PARAMETER["Latitude of 1st standard parallel",33.75,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8823]],
PARAMETER["Longitude of natural origin",-117.333333333333,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8802]],
PARAMETER["False easting",0,
LENGTHUNIT["metre",1],
ID["EPSG",8806]],
PARAMETER["False northing",0,
LENGTHUNIT["metre",1],
ID["EPSG",8807]]],
CS[Cartesian,2],
AXIS["easting",east,
ORDER[1],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]],
AXIS["northing",north,
ORDER[2],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]]]
Data axis to CRS axis mapping: 1,2
Origin = (-28493.166784412522247,4255884.543802191503346)
Pixel Size = (60.022136983193739,-60.022136983193739)
Metadata:
AREA_OR_POINT=Area
Image Structure Metadata:
INTERLEAVE=BAND
Corner Coordinates:
Upper Left ( -28493.167, 4255884.544) (117d38'27.05"W, 33d56'37.74"N)
Lower Left ( -28493.167, 4224973.143) (117d38'27.05"W, 33d39'53.81"N)
Upper Right ( 2358.212, 4255884.544) (117d18'28.38"W, 33d56'37.74"N)
Lower Right ( 2358.212, 4224973.143) (117d18'28.38"W, 33d39'53.81"N)
Center ( -13067.478, 4240428.844) (117d28'27.71"W, 33d48'15.38"N)
Band 1 Block=514x15 Type=Byte, ColorInterp=Gray

As you can see, there are lots of useful information.

Converting GeoTIFF to Map Tiles

Tiles are small, square images that represent a portion of a larger map. These tiles are typically organized in a grid pattern and are used to display maps at various zoom levels.

GeoTIFF files, especially large ones, can be very heavy and slow to load on the web. By converting a GeoTIFF to map tiles, the data is broken down into smaller, manageable pieces. This results in faster loading times and a more responsive map experience.

We can use a gdal2tiles.py Python script to convert our GeoTIFF to map tiles. The script is part of the GDAL library.

gdal2tiles.py -z 0-22 -w leaflet cea.tif ./tiles/

-z 0-22: It will create for zoom levels 0 through 22. Zoom level 0 is the entire world in a single tile, and higher zoom levels provide more detailed, smaller-area tiles. Zoom level 22 is very detailed, typically used for street-level maps.

-w leaflet: This option specifies the type of web viewer for which the tiles are being generated.

cea.tif: This is the input file.

./tiles/: This is the output directory where the generated tiles will be stored.

Overlaying custom tiles onto Leaflet Map

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Adding Tiles Layer on Leaflet</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// Initialize the map
var map = L.map('map', {
center: [33.80427100088687, -117.4753998353766],
zoom: 10,
minZoom: 0,
maxZoom: 15,
});

// Add a tile layer to the map (OpenStreetMap)
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);

// Overlay custom tiles (TMS)
var lyr = L.tileLayer("./tiles/{z}/{x}/{y}.png", {
tms: 1,
opacity: 0.7,
attribution: "",
minZoom: 0,
maxZoom: 15,
}).addTo(map);
</script>
</body>
</html>

This code sets up a basic Leaflet map that uses OpenStreetMap as a base layer and overlays custom tiles generated from cea.tif file. The custom tiles are semi-transparent, allowing the user to see both the base map and the overlay. ./tiles/{z}/{x}/{y}.png points to the directory where the tiles are stored, with {z}, {x}, and {y} representing the zoom level, and x and y coordinates of the tiles.

Here is the result:

Conclusion

It’s amazing how something that seems difficult at first can become easy with a little learning, isn’t it :)? I hope this post helps you overcome a small hurdle on your way to creating amazing maps.

Thank you for reading!

--

--

Dara
Dara

No responses yet