Skip to content

Commit

Permalink
Merge pull request jupyter-widgets#737 from davidbrochart/fit_bounds
Browse files Browse the repository at this point in the history
Add Map.fit_bounds(bounds)
  • Loading branch information
davidbrochart authored Oct 19, 2020
2 parents f40a3a0 + 2414c6e commit 14131d6
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 3 deletions.
5 changes: 3 additions & 2 deletions docs/source/api_reference/map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ clear_layers Remove all layers f
add_control Control instance Add a new control to the map
remove_control Control instance Remove a control from the map
clear_controls Remove all controls from the map
on_interaction callable object Add a callback on interaction
save output file Save the map to an HTML file
on_interaction Callable object Add a callback on interaction
save Output file Save the map to an HTML file
fit_bounds Bounds Set the map so that it contains the given bounds with the maximum zoom level.
================ ===================================== ===
54 changes: 53 additions & 1 deletion ipyleaflet/leaflet.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#

import copy

import asyncio
import json

from ipywidgets import (
Expand Down Expand Up @@ -69,6 +69,17 @@ def basemap_to_tiles(basemap, day='yesterday', **kwargs):
)


def wait_for_change(widget, value):
future = asyncio.Future()

def get_value(change):
future.set_result(change.new)
widget.unobserve(get_value, value)

widget.observe(get_value, value)
return future


class LayerException(TraitError):
"""Custom LayerException class."""
pass
Expand Down Expand Up @@ -2177,3 +2188,44 @@ def _handle_leaflet_event(self, _, content, buffers):

def on_interaction(self, callback, remove=False):
self._interaction_callbacks.register_callback(callback, remove=remove)

def fit_bounds(self, bounds):
"""Sets a map view that contains the given geographical bounds
with the maximum zoom level possible.
Parameters
----------
bounds: list of lists
The lat/lon bounds in the form [[south, east], [north, west]].
"""
asyncio.ensure_future(self._fit_bounds(bounds))

async def _fit_bounds(self, bounds):
(b_south, b_west), (b_north, b_east) = bounds
center = b_south + (b_north - b_south) / 2, b_west + (b_east - b_west) / 2
if center != self.center:
self.center = center
await wait_for_change(self, 'bounds')
zoomed_out = False
# zoom out
while True:
if self.zoom <= 1:
break
(south, west), (north, east) = self.bounds
if south > b_south or north < b_north or west > b_west or east < b_east:
self.zoom -= 1
await wait_for_change(self, 'bounds')
zoomed_out = True
else:
break
if not zoomed_out:
# zoom in
while True:
(south, west), (north, east) = self.bounds
if south < b_south and north > b_north and west < b_west and east > b_east:
self.zoom += 1
await wait_for_change(self, 'bounds')
else:
self.zoom -= 1
await wait_for_change(self, 'bounds')
break

0 comments on commit 14131d6

Please sign in to comment.