/ Basemap

Terranigma 16-bit style world web map

TL;DR
Get me to the map


There is a diverse assortment of JavaScript libraries for displaying geographic information in a browser on the web. They all have their pros and cons. Today, I'd like to take a look at the capabilities of LeafletJS for using a special custom basemap. The basemap is basically the background on top of which other spatial data (markers, points, lines, polygons) can be displayed. Google Maps for example offers different basemap based on satellite imagery and topographic data. For this example, I'll be using a special map of the world, represented by the overworld of the 1997 Super Nintendo action RPG Terranigma.

1. Prepare your basemap

The map itself exists in a relatively small resolution of 4098 x 4098 pixel, at least for our purposes. If we want to display a lot of the nice pixel art details we need to increase the resolution of our image. Artificially making an image bigger might sound counter intuitive at first, but it will make sense in the end.

To increase the resolution we'll use GDAL, the geographic data abstraction library. This is a set of tools to manipulate spatial data. One specific tool of GDAL, called gdal_translate, is used to convert raster data, which our image basically is a type of. Usually, if you want to use for example a satellite image which represents a specific place on earth you would define the coordinates of the upper left and lower right corner of the image. The Terranigma basemap has no specific geographic reference, so we will be using display coordinates instead. Use the following command to create a virtual raster, an XML file with raster size and reference points.

$ gdal_translate -of vrt -expand rgba Terranigma-World.png Terra.vrt

2. Creating tiles

Tiles are used to reduce traffic and display maps in a faster way. Instead of downloading the whole image, only excerpts of the image that are currently displayed are downloaded.

Map tiles

To create these tiles we use the following command.

gdal2tiles.py -p raster Terra.vrt [output folder]

The process takes a couple of seconds, depending on the size of the raster. The gdal2tiles.py also creates a simple html file for displaying the tiles using OpenLayers. But the interesting part are the folders containing the small tiles of our big image. We can use LeafletJS to access these tiles as a Tiles Map Service (TMS).

3. A simple map

index.html

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="lib/leaflet-0.6.4/leaflet.css" />
	<link rel="stylesheet" href="lib/leaflet-0.6.4/leaflet.ie.css" />
	<link rel="stylesheet" href="styles.css" />
	
</head>
<body>
    <div id="map" style="width: 1024px; height: 100%; margin: auto"></div>
    
	<script type="text/javascript" src="lib/leaflet-0.6.4/leaflet.js"></script>
	<script type="text/javascript" src="lib/leaflet-0.6.4/leaflet-src.js"></script>
	<script type="text/javascript" src="lib/jquery-1.11.2.min.js"></script>
	<script type="text/javascript" src="map.js"></script>
		
	<script type="text/javascript">
        $(document).ready(function() {
            setTimeout('init()',500);
        });
    </script>
</body>
</html>

style.css

body {
    padding: 0;
    margin: 0;
}
html, body{
    height: 100%;
}

map.js

function init() {
        initMap();
}

function initMap() {

		var overworldBasemap = L.tileLayer('tiles/{z}/{x}/{y}.png', {
	        tms: true,
            attribution: 'Imagery and data: <a href="http://www.nintendo.com">NINTENDO</a>'
});

        var map = L.map('map', {
			maxZoom: 6,
			minZoom: 2,
			layers: [overworldBasemap],
			crs: L.CRS.Simple
		}).setView([0, 0], 2);
        var southWest = map.unproject([0,16384], map.getMaxZoom());
		var northEast = map.unproject([16384,0], map.getMaxZoom());
        map.setMaxBounds(new L.LatLngBounds(southWest, northEast));

        var overlay = {
			'Oberwelt': new L.layerGroup().addTo(map)
		};

		L.control.layers(overlay, null, {
			collapsed: false
        }).addTo(map);

You can find an expanded example on GitHub:

DeEgge/16-Bit-Maps