Commits (2)
$(document).ready(function () {
$(document).on('click', "#download", function () {
var element = document.getElementById("graph-collection"); // global variable
if (element == null) {
element = document.getElementById("map");
}
getCanvas(element);
});
});
function getCanvas(element) {
html2canvas(element, {
scrollX: 0,
scrollY: 0,
allowTaint: true,
useCORS: true,
async: true,
windowWidth: element.offsetWidth + 90,
windowHeight: element.offsetHeight,
logging: true,
imageTimeout: 0,
ignoreElements: function( element ) {
console.log(element.classList);
if( element.classList.contains('leaflet-control-zoom')) {
return true;
}
}
}).then(function (canvas) {
// Get zoom and coordinates
zoom = document.getElementById("current-zoom").innerHTML.split(': ')[1];
lat = document.getElementById("current-lat").innerHTML.split(': ')[1];
lon = document.getElementById("current-lon").innerHTML.split(': ')[1];
saveAs(canvas.toDataURL(), 'map_' + lat + '_' + lon + '_' + zoom + '.png');
});
}
function saveAs(uri, filename) {
var link = document.createElement('a');
if (typeof link.download === 'string') {
link.href = uri;
link.download = filename;
// Firefox requires the link to be in the body
document.body.appendChild(link);
// Simulate click
link.click();
// Remove the link when done
document.body.removeChild(link);
} else {
window.open(uri);
}
}
import dash
from dash import html
from dash import dcc
import dash_leaflet as dl
from dash.dependencies import Output
from dash.dependencies import Input
from dash.dependencies import State
from dash.exceptions import PreventUpdate
import dash_bootstrap_components as dbc
leaflet = "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css"
html2canvas = "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"
jQuery = 'https://code.jquery.com/jquery-3.6.0.slim.min.js'
app = dash.Dash(__name__,
external_scripts=[jQuery, html2canvas],
external_stylesheets=[leaflet,
dbc.themes.BOOTSTRAP,
dbc.themes.GRID])
app.index_string = '''
<!DOCTYPE html>
<html>
<head>
<script>
L_PREFER_CANVAS=true;
L_SCROLL_WHEEL_ZOOM=false;
</script>
{%metas%}
<title>{%title%}</title>
{%favicon%}
{%css%}
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
{%renderer%}
</footer>
</body>
</html>
'''
zoom_properties = {
"zoomSnap": 0.1,
"wheelPxPerZoomLevel": 120,
"wheelDebounceTime": 80,
"minZoom": 2,
"attributionControl": False
}
map_layers = {"carto-positron-no-labels": {"name": "Light without labels",
"url": "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
"attribution": ""
}
}
@dash.callback(
[
Output('map-div', 'children'),
Output('current-lat', 'children'),
Output('current-lon', 'children'),
Output('current-zoom', 'children')
],
[
Input('view-dropdown', 'value'),
Input('lat', 'value'),
Input('lon', 'value'),
Input('zoom', 'value'),
Input('map', 'center'),
Input('map', 'zoom'),
],
prevent_initial_call=True,
)
def update_figure(tile_layer, lat, lon, zoom, map_center, map_zoom):
if lat is None or lon is None or zoom is None or tile_layer is None:
raise PreventUpdate
ctx = dash.callback_context
if ctx.triggered:
trigger_id = ctx.triggered_id
curr_lat = 'Selected latitude: '
curr_lon = 'Selected longitude: '
curr_zoom = 'Selected zoom: '
# Update zoom and lat/lon when scrolling
if trigger_id not in ['lat', 'lon', 'zoom']:
zoom = round(map_zoom, 2)
[lat, lon] = [round(coord, 2) for coord in map_center]
curr_lat += str(lat)
curr_lon += str(lon)
curr_zoom += str(zoom)
fig = dl.Map(dl.TileLayer(
url=map_layers[tile_layer]['url'],
attribution=map_layers[tile_layer]['attribution']),
id="map",
zoom=zoom,
center=[lat, lon],
style={'width': '100%', 'height': '750px'},
**zoom_properties)
return fig, curr_lat, curr_lon, curr_zoom
app.layout = html.Div([
dbc.Row(
[
dbc.Col(html.Div("Tile layer", style={'margin': '5px'}), width=2),
dbc.Col(html.Div("Center latitude", style={'margin': '5px'}), width=2),
dbc.Col(html.Div("Center longitude", style={'margin': '5px'}), width=2),
dbc.Col(html.Div("Zoom", style={'margin': '5px'}), width=2),
dbc.Col(html.Div("Export", style={'margin': '5px'}), width=2),
]),
dbc.Row(
[
dbc.Col(dcc.Dropdown(
id='view-dropdown',
options=[
{'label': map_layers[style]['name'],
'value': style}
for style in map_layers],
value='carto-positron-no-labels',
style={'margin': '5px'}
),
width=2),
dbc.Col(dcc.Input(
id='lat',
type='number',
placeholder="Input center latitude",
# value=40,
style={'margin': '5px', 'height': '35px'}
),
width=2),
dbc.Col(dcc.Input(
id='lon',
type='number',
# value=-3.7,
placeholder="Input center longitude",
style={'margin': '5px', 'height': '35px'}
),
width=2),
dbc.Col(dcc.Input(
id='zoom',
type='number',
step=0.1,
placeholder="Input zoom level",
# value=6.2,
style={'margin': '5px', 'height': '35px'}
),
width=2),
dbc.Col(dbc.Button(
"Download image",
id="download",
className="me-2",
n_clicks=0
),
width=2)
]
),
dbc.Row([
dbc.Col(width=2),
dbc.Col(html.Div('Selected latitude: ',
id='current-lat',
style={'margin-left': '5px', 'height': '35px', 'font-size': '13px'}),
width=2),
dbc.Col(html.Div('Selected longitude: ',
id='current-lon',
style={'margin-left': '5px', 'height': '35px', 'font-size': '13px'}),
width=2),
dbc.Col(html.Div('Selected zoom: ',
id='current-zoom',
style={'margin-left': '5px', 'height': '35px', 'font-size': '13px'}),
width=2),
dbc.Col(width=2),
]),
html.Div(id='map-div',
children=[dl.Map(dl.TileLayer(
url=map_layers["carto-positron-no-labels"]['url'],
attribution=map_layers["carto-positron-no-labels"]['attribution']),
id="map",
zoom=6.2,
center=[40, -3.7],
style={'width': '100%', 'height': '750px'},
**zoom_properties)]),
])
if __name__ == '__main__':
app.run_server(debug=True, port=7779)
dash==2.10.2
dash-leaflet==0.1.28
dash_bootstrap_components==1.5.0
\ No newline at end of file