Skip to content

Commit

Permalink
Version 0.9.0 - Multiple map support (#47)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
JaWeilBaum authored Dec 4, 2022
1 parent 49d74af commit bf73968
Show file tree
Hide file tree
Showing 17 changed files with 121 additions and 81 deletions.
2 changes: 1 addition & 1 deletion pyqtlet2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

__author__ = 'Leon Friedmann <[email protected]>'
__version__ = '0.8.3'
__version__ = '0.9.0'

from .mapwidget import MapWidget
from .leaflet import L
51 changes: 34 additions & 17 deletions pyqtlet2/leaflet/core/evented.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
import time

from ... import mapwidget

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

def __init__(self, mapWidget=None):
def __init__(self, mapWidget=None, mapWidgetIndex=None):
'''
Base class for all pyqtlet2 objects
Handles initiation, as well as python-Js communication
Expand All @@ -28,22 +27,31 @@ def __init__(self, mapWidget=None):
super().__init__()
self._logger = logging.getLogger(__name__)
self.response = None
if Evented.mapWidget:

if isinstance(mapWidgetIndex, type(None)):
return

if mapWidget is None:
raise RuntimeError('L.map must be initialised before other pyqtlet2 objects')
if not issubclass(type(mapWidget), mapwidget.MapWidget):
raise TypeError(('Expected mapWidget of type pyqtlet2.MapWidget, '
'received {type_}'.format(type_=type(mapWidget))))
Evented.mapWidget = mapWidget
self.mapWidgets.append(mapWidget)
js = ('var channelObjects = null;'
'new QWebChannel(qt.webChannelTransport, function(channel) {'
' channelObjects = channel.objects;'
'});')
self.runJavaScript(js)
self.mapWidget.page.titleChanged.connect(lambda: print('title changed'))
self.runJavaScript(js, mapWidgetIndex)
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
mapWidget.page.titleChanged.connect(lambda: print('title changed'))

def getMapWidgetAtIndex(self, mapWidgetIndex):
if len(self.mapWidgets) > mapWidgetIndex:
return self.mapWidgets[mapWidgetIndex]
self._logger.error("No")
return None

def getJsResponse(self, js, callback):
def getJsResponse(self, js, mapWidgetIndex, callback):
'''
Runs javascript code in the mapWidget and triggers callback.
Expand All @@ -63,9 +71,12 @@ def getJsResponse(self, js, callback):
'''
self._logger.debug('Running JS with callback: {js}=>{callback}'.format(
js=js, callback=callback.__name__))
self.mapWidget.page.runJavaScript(js, callback)
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
mapWidget.page.runJavaScript(js, callback)
else:
self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")

def runJavaScript(self, js):
def runJavaScript(self, js, mapWidgetIndex: int):
'''
Runs javascript code in the mapWidget.
Expand All @@ -75,9 +86,12 @@ def runJavaScript(self, js):
:param str js: The javascript code
'''
self._logger.debug('Running JS: {js}'.format(js=js))
self.mapWidget.page.runJavaScript(js)
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
mapWidget.page.runJavaScript(js)
else:
self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")

def _createJsObject(self, leafletJsObject):
def _createJsObject(self, leafletJsObject, mapWidgetIndex):
'''
Function to create variables/objects in leaflet in the
javascript "engine", and registers the object so that it can
Expand All @@ -89,20 +103,23 @@ def _createJsObject(self, leafletJsObject):
# Creates the js object on the mapWidget page
js = 'var {name} = {jsObject}'.format(name=self.jsName,
jsObject=leafletJsObject)
self.runJavaScript(js)
self.runJavaScript(js, mapWidgetIndex)
# register the object in the channel
self.mapWidget.channel.registerObject(
'{name}Object'.format(name=self.jsName), self)
if mapWidget := self.getMapWidgetAtIndex(mapWidgetIndex):
mapWidget.channel.registerObject(
'{name}Object'.format(name=self.jsName), self)
else:
self._logger.error(f"Can't find mapWidget at index: {mapWidgetIndex}")

def _connectEventToSignal(self, event, signalEmitter):
def _connectEventToSignal(self, event, signalEmitter, mapWidgetIndex):
# We need to delete some keys as they are causing circular structures
js = '{name}.on("{event}", function(e) {{\
delete e.target;\
delete e.sourceTarget;\
e = copyWithoutCircularReferences([e], e);\
channelObjects.{name}Object.{signalEmitter}(e)}})'.format(
name=self.jsName, event=event, signalEmitter=signalEmitter)
self.runJavaScript(js)
self.runJavaScript(js, mapWidgetIndex)

def _stringifyForJs(self, object_):
# When passing options to JS, sometimes we need to pass in objects
Expand Down
2 changes: 1 addition & 1 deletion pyqtlet2/leaflet/layer/featuregroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class FeatureGroup(LayerGroup):

def _initJs(self):
leafletJsObject = 'new L.featureGroup()'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

def createAndAddDrawnLayer(self, drawnLayer, options=None):
layerType = drawnLayer['layerType']
Expand Down
5 changes: 3 additions & 2 deletions pyqtlet2/leaflet/layer/icon/icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ def __init__(self, iconUrl: str, options=None):
self.icon_found = False
self.options = options
self._check_icon_url()
self._initJs()
if self._map:
self._initJs()

def _check_icon_url(self):
if "http" in self.iconUrl:
Expand All @@ -26,4 +27,4 @@ def _check_icon_url(self):
def _initJs(self):
leafletJsObject = 'L.icon({options});'.format(options=Parser.dict_for_js({"iconUrl": self.iconUrl,
**self.options}))
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
5 changes: 3 additions & 2 deletions pyqtlet2/leaflet/layer/imageoverlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ def __init__(self, imageURL, bounds, options=None):
self.imageURL = imageURL
self.bounds = bounds
self.options = options
self._initJs()
if self._map:
self._initJs()

def _initJs(self):
leafletJsObject = 'L.imageOverlay("{imageURL}",{bounds}'.format(imageURL=self.imageURL,bounds=self.bounds)
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

16 changes: 12 additions & 4 deletions pyqtlet2/leaflet/layer/layer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ..core import Evented
import logging
from abc import abstractmethod

class Layer(Evented):

Expand Down Expand Up @@ -27,6 +28,13 @@ def map(self):
def map(self, map_):
self._map = map_

@abstractmethod
def _initJs(self):
raise NotImplemented

def runJavaScriptForMapIndex(self, js):
self.runJavaScript(js, self._map.mapWidgetIndex)

def __init__(self):
super().__init__()
self._map = None
Expand All @@ -52,12 +60,12 @@ def bindPopup(self, content, options=None):
if options:
js += ', {options}'.format(options=self._stringifyForJs(options))
js += ')'
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def unbindPopup(self):
js = '{layerName}.unbindPopup()'.format(layerName=self._layerName)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def bindTooltip(self, content, options=None):
Expand All @@ -66,12 +74,12 @@ def bindTooltip(self, content, options=None):
if options:
js += ', {options}'.format(options=self._stringifyForJs(options))
js += ')'
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def unbindTooltip(self):
js = '{layerName}.unbindTooltip()'.format(layerName=self._layerName)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self


11 changes: 6 additions & 5 deletions pyqtlet2/leaflet/layer/layergroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ def layers(self):
def __init__(self):
super().__init__()
self._layers = []
self._initJs()
if self._map:
self._initJs()

def _initJs(self):
leafletJsObject = 'new L.layerGroup()'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

def addLayer(self, layer):
self._layers.append(layer)
js = '{layerGroup}.addLayer({layerName})'.format(layerGroup=self._layerName,
layerName=layer._layerName)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)

def removeLayer(self, layer):
if not layer in self._layers:
Expand All @@ -31,11 +32,11 @@ def removeLayer(self, layer):
self._layers.remove(layer)
js = '{layerGroup}.removeLayer({layerName})'.format(layerGroup=self._layerName,
layerName=layer._layerName)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)

def clearLayers(self):
js = '{layerGroup}.clearLayers()'.format(layerGroup=self._layerName)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)

def toGeoJSON(self, callback):
self.getJsResponse('{layer}.toGeoJSON()'.format(layer=self.jsName), callback)
Expand Down
23 changes: 12 additions & 11 deletions pyqtlet2/leaflet/layer/marker/marker.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ def __init__(self, latLng: List[float], options=None):
self.options = options
self.opacity = options.get('opacity', 1)
self.draggable = options.get('draggable', False)
self._initJs()
self._connectEventToSignal('move', '_onMove')
self._connectEventToSignal('moveend', '_onMoveend')
self._connectEventToSignal('click', '_click')
if self._map:
self._initJs()

@Slot(QJsonValue)
def _onMove(self, event):
Expand Down Expand Up @@ -51,40 +49,43 @@ def _initJs(self):
if self.options:
leafletJsObject += ', {options}'.format(options=Parser.dict_for_js(self.options))
leafletJsObject += ')'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
self._connectEventToSignal('move', '_onMove', self._map.mapWidgetIndex)
self._connectEventToSignal('moveend', '_onMoveend', self._map.mapWidgetIndex)
self._connectEventToSignal('click', '_click', self._map.mapWidgetIndex)

def setLatLng(self, latLng):
self.latLng = latLng
js = '{layerName}.setLatLng({latLng})'.format(
layerName=self._layerName, latLng=latLng)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def setOpacity(self, opacity):
self.opacity = opacity
js = '{layerName}.setOpacity({opacity})'.format(
layerName=self._layerName, opacity=self.opacity)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def setDragging(self, draggable):
self.draggable = draggable
option = 'enable' if self.draggable else 'disable'
js = '{layerName}.dragging.{option}();'.format(layerName=self._layerName, option=option)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def setIcon(self, icon: Icon):
js = '{layerName}.setIcon({markerIcon});'.format(layerName=self._layerName, markerIcon=icon._layerName)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def setRotationAngle(self, angle_deg: float):
js = '{layerName}.setRotationAngle({angle_deg});'.format(layerName=self._layerName, angle_deg=angle_deg)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self

def setRotationOrigin(self, origin: str):
js = '{layerName}.setRotationOrigin({origin});'.format(layerName=self._layerName, origin=origin)
self.runJavaScript(js)
self.runJavaScriptForMapIndex(js)
return self
6 changes: 3 additions & 3 deletions pyqtlet2/leaflet/layer/tile/tilelayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ def __init__(self, urlTemplate, options=None):
super().__init__()
self.urlTemplate = urlTemplate
self.options = options
self._initJs()
if self._map:
self._initJs()

def _initJs(self):
leafletJsObject = 'L.tileLayer("{urlTemplate}"'.format(urlTemplate=self.urlTemplate)
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)

self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)
3 changes: 1 addition & 2 deletions pyqtlet2/leaflet/layer/vector/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ def _initJs(self):
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)

self._createJsObject(leafletJsObject, self)
5 changes: 3 additions & 2 deletions pyqtlet2/leaflet/layer/vector/circlemarker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ def __init__(self, latLng, options=None):
super().__init__()
self.latLng = latLng
self.options = options
self._initJs()
if self._map:
self._initJs()

def _initJs(self):
leafletJsObject = 'L.circleMarker({latLng}'.format(latLng=self.latLng)
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

2 changes: 1 addition & 1 deletion pyqtlet2/leaflet/layer/vector/polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ def _initJs(self):
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

5 changes: 3 additions & 2 deletions pyqtlet2/leaflet/layer/vector/polyline.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ def __init__(self, latLngs, options=None):
super().__init__()
self.latLngs = latLngs
self.options = options
self._initJs()
if self._map:
self._initJs()

def _initJs(self):
leafletJsObject = 'L.polyline({latLngs}'.format(latLngs=self.latLngs)
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

2 changes: 1 addition & 1 deletion pyqtlet2/leaflet/layer/vector/rectangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ def _initJs(self):
if self.options:
leafletJsObject += ', {options}'.format(options=self.options)
leafletJsObject += ')'
self._createJsObject(leafletJsObject)
self._createJsObject(leafletJsObject, self._map.mapWidgetIndex)

Loading

0 comments on commit bf73968

Please sign in to comment.