Skip to content

Commit bf73968

Browse files
authored
Version 0.9.0 - Multiple map support (#47)
* Added initial version of multiple MapWidget Support * Addjusted js execution functions * Fixed bugs where the callback was not taking the respected mapWidget * Bumped version to 0.9.0
1 parent 49d74af commit bf73968

File tree

17 files changed

+121
-81
lines changed

17 files changed

+121
-81
lines changed

pyqtlet2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55
__author__ = 'Leon Friedmann <leon.friedmann@tum.de>'
6-
__version__ = '0.8.3'
6+
__version__ = '0.9.0'
77

88
from .mapwidget import MapWidget
99
from .leaflet import L

pyqtlet2/leaflet/core/evented.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import time
32

43
from ... import mapwidget
54

@@ -11,9 +10,9 @@ class Evented(QObject):
1110
Base class for all pyqtlet2 objects.
1211
Handles initiation, as well as all python<->js communication
1312
'''
14-
mapWidget = None
13+
mapWidgets = []
1514

16-
def __init__(self, mapWidget=None):
15+
def __init__(self, mapWidget=None, mapWidgetIndex=None):
1716
'''
1817
Base class for all pyqtlet2 objects
1918
Handles initiation, as well as python-Js communication
@@ -28,22 +27,31 @@ def __init__(self, mapWidget=None):
2827
super().__init__()
2928
self._logger = logging.getLogger(__name__)
3029
self.response = None
31-
if Evented.mapWidget:
30+
31+
if isinstance(mapWidgetIndex, type(None)):
3232
return
33+
3334
if mapWidget is None:
3435
raise RuntimeError('L.map must be initialised before other pyqtlet2 objects')
3536
if not issubclass(type(mapWidget), mapwidget.MapWidget):
3637
raise TypeError(('Expected mapWidget of type pyqtlet2.MapWidget, '
3738
'received {type_}'.format(type_=type(mapWidget))))
38-
Evented.mapWidget = mapWidget
39+
self.mapWidgets.append(mapWidget)
3940
js = ('var channelObjects = null;'
4041
'new QWebChannel(qt.webChannelTransport, function(channel) {'
4142
' channelObjects = channel.objects;'
4243
'});')
43-
self.runJavaScript(js)
44-
self.mapWidget.page.titleChanged.connect(lambda: print('title changed'))
44+
self.runJavaScript(js, mapWidgetIndex)
45+
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
46+
mapWidget.page.titleChanged.connect(lambda: print('title changed'))
47+
48+
def getMapWidgetAtIndex(self, mapWidgetIndex):
49+
if len(self.mapWidgets) > mapWidgetIndex:
50+
return self.mapWidgets[mapWidgetIndex]
51+
self._logger.error("No")
52+
return None
4553

46-
def getJsResponse(self, js, callback):
54+
def getJsResponse(self, js, mapWidgetIndex, callback):
4755
'''
4856
Runs javascript code in the mapWidget and triggers callback.
4957
@@ -63,9 +71,12 @@ def getJsResponse(self, js, callback):
6371
'''
6472
self._logger.debug('Running JS with callback: {js}=>{callback}'.format(
6573
js=js, callback=callback.__name__))
66-
self.mapWidget.page.runJavaScript(js, callback)
74+
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
75+
mapWidget.page.runJavaScript(js, callback)
76+
else:
77+
self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")
6778

68-
def runJavaScript(self, js):
79+
def runJavaScript(self, js, mapWidgetIndex: int):
6980
'''
7081
Runs javascript code in the mapWidget.
7182
@@ -75,9 +86,12 @@ def runJavaScript(self, js):
7586
:param str js: The javascript code
7687
'''
7788
self._logger.debug('Running JS: {js}'.format(js=js))
78-
self.mapWidget.page.runJavaScript(js)
89+
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
90+
mapWidget.page.runJavaScript(js)
91+
else:
92+
self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")
7993

80-
def _createJsObject(self, leafletJsObject):
94+
def _createJsObject(self, leafletJsObject, mapWidgetIndex):
8195
'''
8296
Function to create variables/objects in leaflet in the
8397
javascript "engine", and registers the object so that it can
@@ -89,20 +103,23 @@ def _createJsObject(self, leafletJsObject):
89103
# Creates the js object on the mapWidget page
90104
js = 'var {name} = {jsObject}'.format(name=self.jsName,
91105
jsObject=leafletJsObject)
92-
self.runJavaScript(js)
106+
self.runJavaScript(js, mapWidgetIndex)
93107
# register the object in the channel
94-
self.mapWidget.channel.registerObject(
95-
'{name}Object'.format(name=self.jsName), self)
108+
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
109+
mapWidget.channel.registerObject(
110+
'{name}Object'.format(name=self.jsName), self)
111+
else:
112+
self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")
96113

97-
def _connectEventToSignal(self, event, signalEmitter):
114+
def _connectEventToSignal(self, event, signalEmitter, mapWidgetIndex):
98115
# We need to delete some keys as they are causing circular structures
99116
js = '{name}.on("{event}", function(e) {{\
100117
delete e.target;\
101118
delete e.sourceTarget;\
102119
e = copyWithoutCircularReferences([e], e);\
103120
channelObjects.{name}Object.{signalEmitter}(e)}})'.format(
104121
name=self.jsName, event=event, signalEmitter=signalEmitter)
105-
self.runJavaScript(js)
122+
self.runJavaScript(js, mapWidgetIndex)
106123

107124
def _stringifyForJs(self, object_):
108125
# When passing options to JS, sometimes we need to pass in objects

pyqtlet2/leaflet/layer/featuregroup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class FeatureGroup(LayerGroup):
88

99
def _initJs(self):
1010
leafletJsObject = 'new L.featureGroup()'
11-
self._createJsObject(leafletJsObject)
11+
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
1212

1313
def createAndAddDrawnLayer(self, drawnLayer, options=None):
1414
layerType = drawnLayer['layerType']

pyqtlet2/leaflet/layer/icon/icon.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ def __init__(self, iconUrl: str, options=None):
1212
self.icon_found = False
1313
self.options = options
1414
self._check_icon_url()
15-
self._initJs()
15+
if self._map:
16+
self._initJs()
1617

1718
def _check_icon_url(self):
1819
if "http" in self.iconUrl:
@@ -26,4 +27,4 @@ def _check_icon_url(self):
2627
def _initJs(self):
2728
leafletJsObject = 'L.icon({options});'.format(options=Parser.dict_for_js({"iconUrl": self.iconUrl,
2829
**self.options}))
29-
self._createJsObject(leafletJsObject)
30+
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

pyqtlet2/leaflet/layer/imageoverlay.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ def __init__(self, imageURL, bounds, options=None):
66
self.imageURL = imageURL
77
self.bounds = bounds
88
self.options = options
9-
self._initJs()
9+
if self._map:
10+
self._initJs()
1011

1112
def _initJs(self):
1213
leafletJsObject = 'L.imageOverlay("{imageURL}",{bounds}'.format(imageURL=self.imageURL,bounds=self.bounds)
1314
if self.options:
1415
leafletJsObject += ', {options}'.format(options=self.options)
1516
leafletJsObject += ')'
16-
self._createJsObject(leafletJsObject)
17+
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
1718

pyqtlet2/leaflet/layer/layer.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from ..core import Evented
22
import logging
3+
from abc import abstractmethod
34

45
class Layer(Evented):
56

@@ -27,6 +28,13 @@ def map(self):
2728
def map(self, map_):
2829
self._map = map_
2930

31+
@abstractmethod
32+
def _initJs(self):
33+
raise NotImplemented
34+
35+
def runJavaScriptForMapIndex(self, js):
36+
self.runJavaScript(js, self._map.mapWidgetIndex)
37+
3038
def __init__(self):
3139
super().__init__()
3240
self._map = None
@@ -52,12 +60,12 @@ def bindPopup(self, content, options=None):
5260
if options:
5361
js += ', {options}'.format(options=self._stringifyForJs(options))
5462
js += ')'
55-
self.runJavaScript(js)
63+
self.runJavaScriptForMapIndex(js)
5664
return self
5765

5866
def unbindPopup(self):
5967
js = '{layerName}.unbindPopup()'.format(layerName=self._layerName)
60-
self.runJavaScript(js)
68+
self.runJavaScriptForMapIndex(js)
6169
return self
6270

6371
def bindTooltip(self, content, options=None):
@@ -66,12 +74,12 @@ def bindTooltip(self, content, options=None):
6674
if options:
6775
js += ', {options}'.format(options=self._stringifyForJs(options))
6876
js += ')'
69-
self.runJavaScript(js)
77+
self.runJavaScriptForMapIndex(js)
7078
return self
7179

7280
def unbindTooltip(self):
7381
js = '{layerName}.unbindTooltip()'.format(layerName=self._layerName)
74-
self.runJavaScript(js)
82+
self.runJavaScriptForMapIndex(js)
7583
return self
7684

7785

pyqtlet2/leaflet/layer/layergroup.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@ def layers(self):
1212
def __init__(self):
1313
super().__init__()
1414
self._layers = []
15-
self._initJs()
15+
if self._map:
16+
self._initJs()
1617

1718
def _initJs(self):
1819
leafletJsObject = 'new L.layerGroup()'
19-
self._createJsObject(leafletJsObject)
20+
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
2021

2122
def addLayer(self, layer):
2223
self._layers.append(layer)
2324
js = '{layerGroup}.addLayer({layerName})'.format(layerGroup=self._layerName,
2425
layerName=layer._layerName)
25-
self.runJavaScript(js)
26+
self.runJavaScriptForMapIndex(js)
2627

2728
def removeLayer(self, layer):
2829
if not layer in self._layers:
@@ -31,11 +32,11 @@ def removeLayer(self, layer):
3132
self._layers.remove(layer)
3233
js = '{layerGroup}.removeLayer({layerName})'.format(layerGroup=self._layerName,
3334
layerName=layer._layerName)
34-
self.runJavaScript(js)
35+
self.runJavaScriptForMapIndex(js)
3536

3637
def clearLayers(self):
3738
js = '{layerGroup}.clearLayers()'.format(layerGroup=self._layerName)
38-
self.runJavaScript(js)
39+
self.runJavaScriptForMapIndex(js)
3940

4041
def toGeoJSON(self, callback):
4142
self.getJsResponse('{layer}.toGeoJSON()'.format(layer=self.jsName), callback)

pyqtlet2/leaflet/layer/marker/marker.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ def __init__(self, latLng: List[float], options=None):
2020
self.options = options
2121
self.opacity = options.get('opacity', 1)
2222
self.draggable = options.get('draggable', False)
23-
self._initJs()
24-
self._connectEventToSignal('move', '_onMove')
25-
self._connectEventToSignal('moveend', '_onMoveend')
26-
self._connectEventToSignal('click', '_click')
23+
if self._map:
24+
self._initJs()
2725

2826
@Slot(QJsonValue)
2927
def _onMove(self, event):
@@ -51,40 +49,43 @@ def _initJs(self):
5149
if self.options:
5250
leafletJsObject += ', {options}'.format(options=Parser.dict_for_js(self.options))
5351
leafletJsObject += ')'
54-
self._createJsObject(leafletJsObject)
52+
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
53+
self._connectEventToSignal('move', '_onMove', self._map.mapWidgetIndex)
54+
self._connectEventToSignal('moveend', '_onMoveend', self._map.mapWidgetIndex)
55+
self._connectEventToSignal('click', '_click', self._map.mapWidgetIndex)
5556

5657
def setLatLng(self, latLng):
5758
self.latLng = latLng
5859
js = '{layerName}.setLatLng({latLng})'.format(
5960
layerName=self._layerName, latLng=latLng)
60-
self.runJavaScript(js)
61+
self.runJavaScriptForMapIndex(js)
6162
return self
6263

6364
def setOpacity(self, opacity):
6465
self.opacity = opacity
6566
js = '{layerName}.setOpacity({opacity})'.format(
6667
layerName=self._layerName, opacity=self.opacity)
67-
self.runJavaScript(js)
68+
self.runJavaScriptForMapIndex(js)
6869
return self
6970

7071
def setDragging(self, draggable):
7172
self.draggable = draggable
7273
option = 'enable' if self.draggable else 'disable'
7374
js = '{layerName}.dragging.{option}();'.format(layerName=self._layerName, option=option)
74-
self.runJavaScript(js)
75+
self.runJavaScriptForMapIndex(js)
7576
return self
7677

7778
def setIcon(self, icon: Icon):
7879
js = '{layerName}.setIcon({markerIcon});'.format(layerName=self._layerName, markerIcon=icon._layerName)
79-
self.runJavaScript(js)
80+
self.runJavaScriptForMapIndex(js)
8081
return self
8182

8283
def setRotationAngle(self, angle_deg: float):
8384
js = '{layerName}.setRotationAngle({angle_deg});'.format(layerName=self._layerName, angle_deg=angle_deg)
84-
self.runJavaScript(js)
85+
self.runJavaScriptForMapIndex(js)
8586
return self
8687

8788
def setRotationOrigin(self, origin: str):
8889
js = '{layerName}.setRotationOrigin({origin});'.format(layerName=self._layerName, origin=origin)
89-
self.runJavaScript(js)
90+
self.runJavaScriptForMapIndex(js)
9091
return self

pyqtlet2/leaflet/layer/tile/tilelayer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ def __init__(self, urlTemplate, options=None):
55
super().__init__()
66
self.urlTemplate = urlTemplate
77
self.options = options
8-
self._initJs()
8+
if self._map:
9+
self._initJs()
910

1011
def _initJs(self):
1112
leafletJsObject = 'L.tileLayer("{urlTemplate}"'.format(urlTemplate=self.urlTemplate)
1213
if self.options:
1314
leafletJsObject += ', {options}'.format(options=self.options)
1415
leafletJsObject += ')'
15-
self._createJsObject(leafletJsObject)
16-
16+
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

pyqtlet2/leaflet/layer/vector/circle.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@ def _initJs(self):
1212
if self.options:
1313
leafletJsObject += ', {options}'.format(options=self.options)
1414
leafletJsObject += ')'
15-
self._createJsObject(leafletJsObject)
16-
15+
self._createJsObject(leafletJsObject, self)

0 commit comments

Comments
 (0)