|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +from branca.element import Figure, JavascriptLink |
| 4 | + |
| 5 | +from folium.map import Marker |
| 6 | +from folium.utilities import parse_options |
| 7 | + |
| 8 | +from jinja2 import Template |
| 9 | + |
| 10 | +from folium.vector_layers import path_options |
| 11 | + |
| 12 | +_default_js = [ |
| 13 | + ('semicirclejs', |
| 14 | + 'https://cdn.jsdelivr.net/npm/leaflet-semicircle@2.0.4/Semicircle.min.js') |
| 15 | +] |
| 16 | + |
| 17 | + |
| 18 | +class SemiCircle(Marker): |
| 19 | + """Add a marker in the shape of a semicircle, similar to the Circle class. |
| 20 | +
|
| 21 | + Use (direction and arc) or (start_angle and stop_angle), not both. |
| 22 | +
|
| 23 | + Parameters |
| 24 | + ---------- |
| 25 | + location: tuple[float, float] |
| 26 | + Latitude and Longitude pair (Northing, Easting) |
| 27 | + radius: float |
| 28 | + Radius of the circle, in meters. |
| 29 | + direction: int, default None |
| 30 | + Direction angle in degrees |
| 31 | + arc: int, default None |
| 32 | + Arc angle in degrees. |
| 33 | + start_angle: int, default None |
| 34 | + Start angle in degrees |
| 35 | + stop_angle: int, default None |
| 36 | + Stop angle in degrees. |
| 37 | + popup: str or folium.Popup, optional |
| 38 | + Input text or visualization for object displayed when clicking. |
| 39 | + tooltip: str or folium.Tooltip, optional |
| 40 | + Display a text when hovering over the object. |
| 41 | + **kwargs |
| 42 | + For additional arguments see :func:`folium.vector_layers.path_options` |
| 43 | +
|
| 44 | + Uses Leaflet plugin https://github.com/jieter/Leaflet-semicircle |
| 45 | +
|
| 46 | + """ |
| 47 | + _template = Template(u""" |
| 48 | + {% macro script(this, kwargs) %} |
| 49 | + var {{ this.get_name() }} = L.semiCircle( |
| 50 | + {{ this.location|tojson }}, |
| 51 | + {{ this.options|tojson }} |
| 52 | + ) |
| 53 | + {%- if this.direction %} |
| 54 | + .setDirection({{ this.direction[0] }}, {{ this.direction[1] }}) |
| 55 | + {%- endif %} |
| 56 | + .addTo({{ this._parent.get_name() }}); |
| 57 | + {% endmacro %} |
| 58 | + """) |
| 59 | + |
| 60 | + def __init__(self, location, radius, |
| 61 | + direction=None, arc=None, |
| 62 | + start_angle=None, stop_angle=None, |
| 63 | + popup=None, tooltip=None, **kwargs): |
| 64 | + super(SemiCircle, self).__init__(location, popup=popup, tooltip=tooltip) |
| 65 | + self._name = 'SemiCircle' |
| 66 | + self.direction = (direction, arc) if direction is not None and arc is not None else None |
| 67 | + self.options = path_options(line=False, radius=radius, **kwargs) |
| 68 | + self.options.update(parse_options( |
| 69 | + start_angle=start_angle, |
| 70 | + stop_angle=stop_angle, |
| 71 | + )) |
| 72 | + |
| 73 | + if not ((direction is None and arc is None) and (start_angle is not None and stop_angle is not None) |
| 74 | + or (direction is not None and arc is not None) and (start_angle is None and stop_angle is None)): |
| 75 | + raise ValueError("Invalid arguments. Either provide direction and arc OR start_angle and stop_angle") |
| 76 | + |
| 77 | + def render(self, **kwargs): |
| 78 | + super(SemiCircle, self).render(**kwargs) |
| 79 | + |
| 80 | + figure = self.get_root() |
| 81 | + assert isinstance(figure, Figure), ('You cannot render this Element ' |
| 82 | + 'if it is not in a Figure.') |
| 83 | + |
| 84 | + for name, url in _default_js: |
| 85 | + figure.header.add_child(JavascriptLink(url), name=name) |
0 commit comments