2

I am trying to create a Leaflet map with custom tiles on top of OSM base layer (from Leaflet.js), using Flask.
I generated a set of tiles from geo-referenced GeoTIFF images, and I first visualized them using standard CSS / HTML / JS to quickly check the result,

// maps.js
L.tileLayer('data/tiles/{z}/{x}/{y}.png', {tms: true, opacity: 0.7, attribution: ""});

and everything was working.

custom tiles displayed with only HTML / CSS / JS

However, when I switched to flask, I got a GET http://127.0.0.1:5000/data/tiles/7/61/83.png 404 (NOT FOUND) error.

custom tiles are not rendering with Flask

I am new to Flask, and I suspect that the error comes from a routing connection.

What I tried

I tried to add a new route from my app.py file, so Flask could find the images:

# app.py
@app.route('/data/tiles/<path:img>', methods=['GET'])
def tile(img):
    return f'data/tiles/{img}'

This solved the errors GET [...] 404 (NOT FOUND) problem, but the tiles were still not loaded / displayed.

Project structure:

/ my_app /
| - -   app.py
|
| - -   templates
|       | - -   maps.html
|
| - -   static
|       | - -   css
|       |       | - -   maps.css
|       |
|       | - -   js
|       |       | - -   maps.js
|
| - -   data
|       | - -   tiles
|       |       | - - sub-folders containing pyramid images,
|       |       |     in 'z/x/y.png' format

The code:

app.py

from flask import Flask, render_template, url_for

app = Flask(__name__)


@app.route("/maps")
def maps():
    return render_template('maps.html')


if __name__ == '__main__':
    app.run(debug=True)

maps.html

<!-- Basic import (Leaflet) -->
<!-- ... and layout style -->

<script type='text/javascript' src="{{ url_for('static', filename='js/maps.js') }}"></script>

maps.js

// Base layers
var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'});

// Overlay layer
var lyr = L.tileLayer('data/tiles/{z}/{x}/{y}.png', {tms: true, opacity: 0.7, attribution: ""});

// Map
var map = L.map('map', {
    center: [47.81260945134799, -6.375234248965416],
    zoom: 10,
    minZoom: 4,
    maxZoom: 10,
    layers: [osm]
});

var basemaps = {"OpenStreetMap": osm}
var overlaymaps = {"Layer": lyr}

// Add base layers
L.control.layers(basemaps, overlaymaps, {collapsed: true}).addTo(map);

Thanks !

Edit:

I finally got it working thanks to @IvanSanchez comment.

From the post, I added a new route in app.py:

# app.py
@app.route('/data/tiles/<path:img>')
def get_image(img):
    filename = f'data/tiles/{img}'
    return send_file(filename, mimetype='image/png')

This added my custom tiles to my Leaflet map. However, I got another error because my tiles didn't covered fully the world.
I fixed it by adding a bounding box to my Leaflet layer:

// maps.js

// Overlay layer
var lyr = L.tileLayer('data/tiles/{z}/{x}/{y}.png',
    {bounds: [[50, -16.24],[43, -0.2]], tms: true, opacity: 0.7, attribution: ""});

Thanks again for all your help !

jegertor
  • 73
  • 2
  • 8

0 Answers0