Source code for sepal_ui.mapping.layer_state_control
"""A specific statebar dedicated to the the counting of loading tiles in the map."""
from typing import Optional
import traitlets as t
from ipyleaflet import Map, WidgetControl
from traitlets import observe
from sepal_ui import sepalwidgets as sw
from sepal_ui.message import ms
[docs]
class LayerStateControl(WidgetControl):
m: Optional[Map] = None
"the map connected to the control"
w_state: Optional[sw.StateBar] = None
"sw.StateBar: the stateBar displaying the number of layer loading on the map"
nb_layer: t.Int = t.Int(0).tag(sync=True)
"the number of layers in the map"
nb_loading_layer: t.Int = t.Int(0).tag(sync=True)
"the number of loading layer in the map"
[docs]
def __init__(self, m: Map, **kwargs) -> None:
"""A specific statebar dedicated to the the counting of loading tiles in the map.
every time a map is added to the map the counter will be raised by one. same behaviour with removed.
Args:
m: The map the component is listening to
"""
# save the map as a member of the widget
self.m = m
# create a statebar
msg = ms.layer_state.complete.format(self.nb_layer)
self.w_state = sw.StateBar(loading=False, msg=msg)
# overwrite the widget set in the kwargs (if any)
kwargs["widget"] = self.w_state
kwargs.setdefault("position", "topleft")
kwargs["transparent_bg"] = True
# create the widget
super().__init__(**kwargs)
# add js behaviour
self.m.observe(self.update_nb_layer, "layers")
[docs]
def update_nb_layer(self, change: dict) -> None:
"""Update the number of layer monitored by the statebar."""
# exit if nothing changed
# for example we change a layer parameters and it trigger this one
if len(change["new"]) == len(change["old"]):
return
self.nb_layer = len([lyr for lyr in change["new"] if not lyr.base])
# identify the modified layer
modified_layer = list(set(change["new"]) ^ set(change["old"]))[0]
if modified_layer.base is True:
return
# add a layer
if len(change["new"]) > len(change["old"]):
modified_layer.observe(self.update_loading, "loading")
# remove a layer
elif len(change["new"]) < len(change["old"]):
# the test is split as not all the layers have a loading trait
if hasattr(modified_layer, "loading") is True:
if modified_layer.loading is True:
self.nb_loading_layer += -1
return
[docs]
def update_loading(self, change: dict) -> None:
"""Update the nb_loading_layer value according to the number of tile loading on the map."""
increment = [-1, 1]
self.nb_loading_layer += increment[change["new"]]
return
@observe("nb_loading_layer", "nb_layer")
def _update_state(self, *args) -> None:
# check if anything is loading
self.loading = bool(self.nb_loading_layer)
# update the message
if self.loading is True:
msg = ms.layer_state.loading.format(self.nb_loading_layer, self.nb_layer)
else:
msg = ms.layer_state.complete.format(self.nb_layer)
self.w_state.msg = msg
return