|
10 | 10 |
|
11 | 11 | from .utilities import (color_brewer, _parse_size, legend_scaler, |
12 | 12 | _locations_mirror, _locations_tolist, image_to_url, |
13 | | - text_type, binary_type) |
| 13 | + text_type, binary_type, |
| 14 | + none_min, none_max, iter_points, |
| 15 | + ) |
14 | 16 |
|
15 | 17 | from .element import Element, Figure, JavascriptLink, CssLink, MacroElement |
16 | 18 | from .map import Layer, Icon, Marker, Popup |
@@ -280,7 +282,30 @@ def _get_self_bounds(self): |
280 | 282 | """Computes the bounds of the object itself (not including it's children) |
281 | 283 | in the form [[lat_min, lon_min], [lat_max, lon_max]] |
282 | 284 | """ |
283 | | - raise NotImplementedError |
| 285 | + if not self.embed: |
| 286 | + raise ValueError('Cannot compute bounds of non-embedded GeoJSON.') |
| 287 | + |
| 288 | + if 'features' not in self.data.keys(): |
| 289 | + # Catch case when GeoJSON is just a single Feature or a geometry. |
| 290 | + if not (isinstance(self.data, dict) and 'geometry' in self.data.keys()): |
| 291 | + # Catch case when GeoJSON is just a geometry. |
| 292 | + self.data = {'type' : 'Feature', 'geometry' : self.data} |
| 293 | + self.data = {'type' : 'FeatureCollection', 'features' : [self.data]} |
| 294 | + |
| 295 | + bounds = [[None,None],[None,None]] |
| 296 | + for feature in self.data['features']: |
| 297 | + for point in iter_points(feature.get('geometry',{}).get('coordinates',{})): |
| 298 | + bounds = [ |
| 299 | + [ |
| 300 | + none_min(bounds[0][0], point[1]), |
| 301 | + none_min(bounds[0][1], point[0]), |
| 302 | + ], |
| 303 | + [ |
| 304 | + none_max(bounds[1][0], point[1]), |
| 305 | + none_max(bounds[1][1], point[0]), |
| 306 | + ], |
| 307 | + ] |
| 308 | + return bounds |
284 | 309 |
|
285 | 310 | class TopoJson(MacroElement): |
286 | 311 | def __init__(self, data, object_path): |
@@ -584,7 +609,19 @@ def _get_self_bounds(self): |
584 | 609 | """Computes the bounds of the object itself (not including it's children) |
585 | 610 | in the form [[lat_min, lon_min], [lat_max, lon_max]] |
586 | 611 | """ |
587 | | - raise NotImplementedError |
| 612 | + bounds = [[None,None],[None,None]] |
| 613 | + for point in iter_points(self.data): |
| 614 | + bounds = [ |
| 615 | + [ |
| 616 | + none_min(bounds[0][0], point[0]), |
| 617 | + none_min(bounds[0][1], point[1]), |
| 618 | + ], |
| 619 | + [ |
| 620 | + none_max(bounds[1][0], point[0]), |
| 621 | + none_max(bounds[1][1], point[1]), |
| 622 | + ], |
| 623 | + ] |
| 624 | + return bounds |
588 | 625 |
|
589 | 626 | class MultiPolyLine(MacroElement): |
590 | 627 | def __init__(self, locations, color=None, weight=None, |
@@ -636,7 +673,19 @@ def _get_self_bounds(self): |
636 | 673 | """Computes the bounds of the object itself (not including it's children) |
637 | 674 | in the form [[lat_min, lon_min], [lat_max, lon_max]] |
638 | 675 | """ |
639 | | - raise NotImplementedError |
| 676 | + bounds = [[None,None],[None,None]] |
| 677 | + for point in iter_points(self.data): |
| 678 | + bounds = [ |
| 679 | + [ |
| 680 | + none_min(bounds[0][0], point[0]), |
| 681 | + none_min(bounds[0][1], point[1]), |
| 682 | + ], |
| 683 | + [ |
| 684 | + none_max(bounds[1][0], point[0]), |
| 685 | + none_max(bounds[1][1], point[1]), |
| 686 | + ], |
| 687 | + ] |
| 688 | + return bounds |
640 | 689 |
|
641 | 690 | class CustomIcon(Icon): |
642 | 691 | def __init__(self, icon_image, icon_size=None, icon_anchor=None, |
|
0 commit comments