Search code examples
reactjsleafletopenstreetmapreact-leaflet

Use a local tile layer with leaflet


I'm creating a project with React and Leaflet.

This project will run offline on a computer connected to nothing, so I need to have the tile layer stored on the same computer (no tile server).

Since I need a very simple map with a fixed zoom of just a few countries, I guess it won't be too heavy.

  • Will it be possible to store the whole tile layer on the client?
  • Where can I download or how can I create such a map for offline use (has to be free)? I will only be doing it once so I prefer to use tools with low learning curve.
<MapContainer center={[lat,lng]} zoom={z}>
    <TileLayer
      attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" <-- this needs to be stored locally
    />
</MapContainer>

Solution

  • This is already a known problem, but I find that answer a bit more complicated than you may need. Here's my pseudo-answer / advice:

    I recommend you read this article about slippymap tilenames before getting started with this. It will help...a lot.

    Considering you have a fixed zoom, and what sounds like a limited map extent (bounds), it shouldn't be too hard to get your tiles. I would open up a browser with a leaflet map set up to that zoom and bounds, and look in your network tab. You will see network requests for all the tiles you need, and you'll see the urls for those tiles. You can then download those tiles directly.

    You can also use leaflet-offline for this. Its a great quick tool to get all your tile urls, and will lay out the tile urls you need beautifully. leaflet-offline may also have a way to auto-download all these tiles in the directory strcuture you need, but I find their docs hard to follow.

    Create a directory somewhere on your machine and name it something useful, like "my-offline-tiles". In that directory, create a subdirectory and name it the zoom level that you expect your map to be (lets say its 10). So you'll have something like this:

    /my-offlline-tiles
      /10
    

    As you download one tile at a time, keep in mind that once you download them, they'll be named something like "32.png", or something of the sort, basically "someNumber.png". That number (as explained in the article I linked), is the y position of the tile, for a given zoom and x column. So you have to pay attention to what the z and x values are in those urls, and download the tiles to the appropriate subdirectory in your "my-offline-tiles" directory. For example, any tiles that end in 10/245/something.png will go in this directory:

    /my-offlline-tiles
      /10
        /245
          something.png
    

    You'll likely end up with a handful of directories under your /10 dir, and a handful of png files in each. As you hopefully read in that article, this is how tile servers structure their tile files for easy access. You need to duplicate that structure, and offer just enough tiles to cover your bounds for you desired zoom level.

    Now in your map, you simply need to make the url of that L.tileLayer the location of your tiles. Lets say /my-offlline-tiles is in the public directory of your project (with your index.html)

    <TileLayer url="/my-offline-tiles/{z}/{x}/{y}.png" />
    

    This might need to be adjusted a bit based on your project structure, build process, or dir structure of the machine this is running on. Basically, you need to make sure your react app knows where to find these files on your machine. But as long as it does, leaflet will find the tiles and render them in your map as expected.

    Hopefully that's enough to get you started.