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.
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.
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: '© <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 !