1
1
from jinja2 import Template
2
-
3
- from folium .elements import JSCSSMixin
4
- from folium .map import Layer
2
+ from folium .elements import JSCSSMixin , MacroElement
5
3
from folium .utilities import parse_options
6
4
7
-
8
- class OverlappingMarkerSpiderfier (JSCSSMixin , Layer ):
9
- """A plugin that handles overlapping markers by spreading them into a spider-like pattern.
10
-
11
- This plugin uses the OverlappingMarkerSpiderfier-Leaflet library to manage markers
12
- that are close to each other or overlap. When clicked, the overlapping markers
13
- spread out in a spiral pattern, making them easier to select individually.
14
-
5
+ class OverlappingMarkerSpiderfier (JSCSSMixin , MacroElement ):
6
+ """
7
+ A plugin that handles overlapping markers on a map by spreading them out in a spiral or circle pattern when clicked.
8
+
9
+ This plugin is useful when you have multiple markers in close proximity that would otherwise be difficult to interact with.
10
+ When a user clicks on a cluster of overlapping markers, they spread out in a 'spider' pattern, making each marker
11
+ individually accessible.
12
+
13
+ Markers must be added to the map **before** calling `oms.add_to(map)`.
14
+ The plugin identifies and manages all markers already present on the map.
15
+
15
16
Parameters
16
17
----------
17
- markers : list, optional
18
- List of markers to be managed by the spiderfier
19
- name : string, optional
20
- Name of the layer control
21
- overlay : bool, default True
22
- Whether the layer will be included in LayerControl
23
- control : bool, default True
24
- Whether the layer will be included in LayerControl
25
- show : bool, default True
26
- Whether the layer will be shown on opening
27
18
options : dict, optional
28
- Additional options to be passed to the OverlappingMarkerSpiderfier instance
29
- See https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet for available options
30
-
19
+ The options to configure the spiderfier behavior:
20
+ - keepSpiderfied : bool, default True
21
+ If true, markers stay spiderfied after clicking
22
+ - nearbyDistance : int, default 20
23
+ Pixels away from a marker that is considered overlapping
24
+ - legWeight : float, default 1.5
25
+ Weight of the spider legs
26
+ - circleSpiralSwitchover : int, optional
27
+ Number of markers at which to switch from circle to spiral pattern
28
+
31
29
Example
32
30
-------
33
- >>> markers = [marker1, marker2, marker3] # Create some markers
34
- >>> spiderfier = OverlappingMarkerSpiderfier(
35
- ... markers=markers, keepSpiderfied=True, nearbyDistance=20
36
- ... )
37
- >>> spiderfier.add_to(m) # Add to your map
31
+ >>> oms = OverlappingMarkerSpiderfier(options={
32
+ ... "keepSpiderfied": True,
33
+ ... "nearbyDistance": 30,
34
+ ... "legWeight": 2.0
35
+ ... })
36
+ >>> oms.add_to(map)
38
37
"""
39
-
40
38
_template = Template (
41
39
"""
42
40
{% macro script(this, kwargs) %}
43
- var {{ this.get_name() }} = (function () {
44
- var layerGroup = L.layerGroup();
45
-
41
+ (function () {
46
42
try {
47
43
var oms = new OverlappingMarkerSpiderfier(
48
44
{{ this._parent.get_name() }},
49
45
{{ this.options|tojson }}
50
46
);
51
47
52
- var popup = L.popup( {
53
- offset: L.point(0, -30)
48
+ oms.addListener('spiderfy', function() {
49
+ {{ this._parent.get_name() }}.closePopup();
54
50
});
55
51
56
- oms.addListener('click', function(marker) {
57
- var content;
58
- if (marker.options && marker.options.options && marker.options.options.desc) {
59
- content = marker.options.options.desc;
60
- } else if (marker._popup && marker._popup._content) {
61
- content = marker._popup._content;
62
- } else {
63
- content = "";
64
- }
65
-
66
- if (content) {
67
- popup.setContent(content);
68
- popup.setLatLng(marker.getLatLng());
69
- {{ this._parent.get_name() }}.openPopup(popup);
52
+ {{ this._parent.get_name() }}.eachLayer(function(layer) {
53
+ if (
54
+ layer instanceof L.Marker
55
+ ) {
56
+ oms.addMarker(layer);
70
57
}
71
58
});
72
59
73
- oms.addListener('spiderfy', function(markers) {
74
- {{ this._parent.get_name() }}.closePopup();
75
- });
76
-
77
- {% for marker in this.markers %}
78
- var {{ marker.get_name() }} = L.marker(
79
- {{ marker.location|tojson }},
80
- {{ marker.options|tojson }}
81
- );
82
-
83
- {% if marker.popup %}
84
- {{ marker.get_name() }}.bindPopup({{ marker.popup.get_content()|tojson }});
85
- {% endif %}
86
-
87
- oms.addMarker({{ marker.get_name() }});
88
- layerGroup.addLayer({{ marker.get_name() }});
89
- {% endfor %}
90
60
} catch (error) {
91
- console.error('Error in OverlappingMarkerSpiderfier initialization :', error);
61
+ console.error('Error initializing OverlappingMarkerSpiderfier:', error);
92
62
}
93
-
94
- return layerGroup;
95
63
})();
96
64
{% endmacro %}
97
-
98
65
"""
99
66
)
100
67
@@ -105,27 +72,14 @@ class OverlappingMarkerSpiderfier(JSCSSMixin, Layer):
105
72
)
106
73
]
107
74
108
- def __init__ (
109
- self ,
110
- markers = None ,
111
- name = None ,
112
- overlay = True ,
113
- control = True ,
114
- show = True ,
115
- options = None ,
116
- ** kwargs ,
117
- ):
118
- super ().__init__ (name = name , overlay = overlay , control = control , show = show )
75
+ def __init__ (self , options = None , ** kwargs ):
76
+ super ().__init__ ()
119
77
self ._name = "OverlappingMarkerSpiderfier"
120
-
121
- self .markers = markers or []
122
-
123
78
default_options = {
124
79
"keepSpiderfied" : True ,
125
80
"nearbyDistance" : 20 ,
126
81
"legWeight" : 1.5 ,
127
82
}
128
83
if options :
129
84
default_options .update (options )
130
-
131
85
self .options = parse_options (** default_options , ** kwargs )
0 commit comments