DEV Community

Bouchaala Reda
Bouchaala Reda

Posted on

Using OpenStreetMap For Your Web Projects

Note: This is an old article I published in my personal blog onAugust 2019.I now publish articles on dev.to so I stopped my blog and moved this article here.


What's wrong with Google Maps?

Nothing. But... let's consider this scenario:
You're working on a web project, say an e-commerce platform for a real-estate company based in Algeria (where I currently live). One of the project's requirements is to show a map of the product's location, on its details page.

You could go with Google Maps, but since they changed to a pay-as-you-go pricing model, you should probably think twice before just jumping in.

Using Google Maps could be the perfect solution in your case but for me it wasn't. I had to look for an alternative.

OpenStreetMap to the rescue

First of all, what is OpenStreetMap?
OpenStreetMap is a collaborative project, that aims to providefree, continuously updated geographic dataof the world.

So can we use their maps? and how? Let's have a look.

OpenStreetMap usage requirements

OpenStreetMap data is licensedOpen Data Commons Open Database License (ODbL),
and the map itself is licensed underCC BY-SA 2.0.That means...

To be able to use OpenStreetMap in your websites, you need adhere by two perfectly reasonable requirements

  1. You mustdisplay a proper attribution text in/around your map. Since we're using the map and the data, we'll add© OpenStreetMap contributorstext inside the map (more on that later), and link it to thecopyright page.
  2. When expecting high traffic (in our case we are),you mustavoid flooding OpenStreetMap servers. You can read more about the tile server usage policyhere.

Show me the code

Enough talk, we will now setup a map, with respect to the requirements mentioned above.

I'm going to use NodeJS to setup a map tile server proxy, I found thislibrarythat can help us with that.

Let's install everything we'll be needing

npminstall--savetilestrata tilestrata-proxy tilestrata-disk tilestrata-headers
Enter fullscreen mode Exit fullscreen mode

Let's review what we installed:

  • Tilestrata is the main server code.
  • TileStrata Proxy will help us proxy requests to OpenStreetMap servers.
  • TileStrata Disk, will help us cache the map tiles, to avoid flooding the proxied servers.
  • TileStrata Headers to help us with client-side caching of map tiles.

Let's first setup a config file

module.exports={
// Host:Port to listen on
host:'127.0.0.1',
port:12345,

cache:{
lifetime:3600*24*7*4,// Cache for a month
refresh:3600*24*14,// 14 days refresh

// The map-server script needs to be lunched from the project root
dir:'./map_tiles_cache',
},
};
Enter fullscreen mode Exit fullscreen mode

and now the server code:

vartilestrata=require('tilestrata');
varheaders=require('tilestrata-headers');
varproxy=require('tilestrata-proxy');
vardisk=require('tilestrata-disk');
varconfig=require('./config');
varutil=require('util');

varstrata=tilestrata();
strata.layer('osm')// highlight-line
.route('*.png')
.use(disk.cache({
dir:config.cache.dir,
refreshage:config.cache.refresh,
maxage:config.cache.lifetime,
}))
.use(proxy({
uri:'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',// highlight-line
subdomains:['a','b','c'],
}))
.use(headers({// highlight-line
'Cache-Control':'public, max-age='+config.cache.lifetime,// highlight-line
'Expires':config.cache.lifetime,// highlight-line
}));

process.stdout.write(util.format(
"Map server listening on http://%s:%s\nPress Ctrl-C to quit.\n",
config.host,config.port
));
strata.listen(config.port,config.host);
Enter fullscreen mode Exit fullscreen mode

Let's review the highlighted lines

  1. We called our map layerosm,you can call this whatever you want.
  2. We proxy the request to OpenStreetMap tile servers, the variables are
    • smeans sub-domain, and it's picked at random from the arrow bellow the highlighted line. Note that this is a required behavior.
    • zis the zoom level,xandyand numbers indicating the column and row the map. You don't have to worry about all this parameters, they will be passed automatically by our client map library. We'll still be using latitudes and longitudes like we're used to.
  3. Then we setup client side caching, using theCache-ControlandExpiresheader.

Now that our map server code is done, let's start it and use our map!

mkdirmap_tiles_cache# for caching files
node mapserver.js
Enter fullscreen mode Exit fullscreen mode

Let's create a simple page that displays our map. We'll be usingLeaflet JSfor that.

<html>
<head>
<title>OpenStreenMap Example</title>
<metacharset="utf-8">
<linkrel="stylesheet"type="text/css"href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css">
<scriptsrc='https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.js'></script>
</head>

<body>
<divid="map"style="height: 700px; width: 100%;"></div>

<script>
varmap=L.map('map',{
center:[36.7597907,3.0665139],// The capital of Algeria
zoom:9,// default zoom level
});

L.tileLayer('http://127.0.0.1:12345/osm/{z}/{x}/{y}.png',{
attribution:'&copy; <a href= "https://www.openstreetmap.org/copyright" >OpenStreetMap contributors</a>'
}).addTo(map);
</script>
</body>
Enter fullscreen mode Exit fullscreen mode

And we're done! We have ourselves a free, flexible map to use in our website.
Checkout theLeaflet websitefor more documentation on how to ineract with your new map.

One more thing...

Depending on the use case, the cache disk space can grow very large.

As an example, The north side of Algeria, viewed from from zoom level 6 all the way up to zoom level 18 (which is the maximum zoom level supported by OpenStreetMap) will be around30GB(You can calculate your own area with thiscalculator toolfromGeofabrik).

You have two options to fix that

  1. Delete the cache folder periodically.
  2. Setup map boundaries for the map.

The first option is self-explanatory, so let's look at the second one.

From thedocs,LeafletJS has map boundaries,
which restricts the view to the given geographical bounds,
bouncing the user back if they try to pan outside the view.

Let's set that up. I got the bounds for Algeriahere(you can get bounds for any country).

// The bounds object
// representing a fixed rectangular area
varbounds=L.bounds(
L.point(-8.704895,18.92874),
L.point(12.03598,37.77284)
);

// Set the max bounds
map.setMaxBounds(bounds);
Enter fullscreen mode Exit fullscreen mode

And we're done!

Of course everything has its pros and cons, and you should decide what's better suited for you own needs.

But as you can see, it was pretty easy to setup a map server based on OpenStreetMap and get started with it, so it's good to have it in your arsenal.

And that's about it! I hope this post was of help to you.
Make sure to drop a comment if you have any question or feedback. Thanks!

Top comments(0)