I am trying to update the coordinates of a folium map rendered by a Dash App on a callback (which is running inside a Flask App). The callback selectively renders different layers on a map - the issue is that the zoom and center coordinates are not persisted when the map is updated. The map is rendered as html and injected as in iframe into the app.
Addendum: Not a professional programmer, have only been trying my hand at this for the past six months.
I have tried three approaches:
- JS API call client-side to flask route. I ended up realizing this had too much overhead (plus couldn’t identify user to update the proper coordinates).
- Encoding the coordinates and zoom in the URL. The URL changes as expected from this js snippet:
map_layer.on("mouseup zoomend", function(){
var coordinates = map_layer.getCenter();
var lat = coordinates.lat
var lon = coordinates.lng
var zoom = map_layer.getZoom();
parent.history.replaceState({}, '', `/app/layer?&lat=${lat}&lon=${lon}&zoom=${zoom}`);
// const ON_CHANGE = '_dashprivate_historychange';
// window.dispatchEvent(new CustomEvent(ON_CHANGE));
// parent.window.dispatchEvent(new CustomEvent(ON_CHANGE));
console.log("success");
The commented-out code also tries to dispatch a CustomEvent to dash to try and update it’s history - not really clear what’s happening there - just tried to emulate this approach.
The right URL is not passed on to the callback however. So despite the url changing on the browser, it’s not being sent back with the updated query variables. If I refresh the page and actively send the URL, than the right URL is passed on, but that’s not the kind of behavior I’m looking for - I would like for it to change with no active reloading of the page:
@layer.callback(
Output("map", "srcDoc"),
-- other inputs --,
Input('url', 'href') #tried State as well
)
def update_output_src(href):
print(href)
-- other code --
return map.get_root().render()
- Using a hidden DIV to store the coordinates . The div content changes as expected from this js snippet:
map_layer.on("mouseup zoomend", function(){
var coordinates = map_layer.getCenter();
var lat = coordinates.lat
var lon = coordinates.lng
var zoom = map_layer.getZoom();
var latstore = parent.document.getElementById('latstore');
latstore.textContent = lat; #trying different approaches in what's changed to see if dash callback captures it.
var lonstore = parent.document.getElementById('lonstore');
lonstore.innerText = lon;
var zoomstore = parent.document.getElementById('zoomstore');
zoomstore.innerHTML = zoom;
console.log("success");
But again I am not able to capture the stored coordinates when the input is triggered.
@layer.callback(
Output("map", "srcDoc"),
-- other inputs --,
State('latstore', 'children'),
State('lonstore', 'children'),
State('zoomstore', 'children'),
)
def update_output_src(latstore, lonstore, zoomstore):
print(latstore, lonstore, zoomstor)
-- other code --
return map.get_root().render()
Any help or pointer in the right direction for approaches 2 or 3 would be super useful. I have been struggling with this for 3-4 days now and I’m out of ideas.