Source code for panel.layout.swipe

"""
The Swipe layout enables you to quickly compare two panels
"""
from __future__ import annotations

from typing import ClassVar, List

import param

from ..io.resources import CDN_DIST
from ..reactive import ReactiveHTML
from .base import ListLike


[docs]class Swipe(ListLike, ReactiveHTML): """ The Swipe layout enables you to quickly compare two panels laid out on top of each other with a part of the *before* panel shown on one side of a slider and a part of the *after* panel shown on the other side. """ objects = param.List(default=[], bounds=(0, 2), doc=""" The list of child objects that make up the layout.""", precedence=-1) slider_width = param.Integer(default=5, bounds=(0, 25), doc=""" The width of the slider in pixels""") slider_color = param.Color(default="black", doc=""" The color of the slider""") value = param.Integer(default=50, bounds=(0, 100), doc=""" The percentage of the *after* panel to show.""") _before = param.Parameter() _after = param.Parameter() _direction: ClassVar[str | None] = 'vertical' _template = """ <div id="container" class="swipe-container"> <div id="before" class="outer"> <div id="before-inner" class="inner">${_before}</div> </div> <div id="after" class="outer" style="overflow: hidden;"> <div id="after-inner" class="inner">${_after}</div> </div> <div id="slider" class="slider" onmousedown="${script('drag')}" style="background: ${slider_color}; width: ${slider_width}px;"> </div> </div> """ _scripts = { 'render': """ self.adjustSlider() """, 'after_layout': """ self.value() """, 'drag': """ function endDrag() { document.removeEventListener('mouseup', endDrag); document.removeEventListener('mousemove', handleDrag); } function handleDrag(e) { e = e || window.event; e.preventDefault(); current = e.clientX start = view.el.getBoundingClientRect().left value = parseInt(((current-start)/ container.clientWidth)*100) data.value = Math.max(0, Math.min(value, 100)) } let e = event || window.event; e.preventDefault(); document.addEventListener('mouseup', endDrag); document.addEventListener('mousemove', handleDrag); """, 'value': """ before.style.clipPath = `polygon(0% 0%, calc(${data.value}% + 5px) 0%, calc(${data.value}% + 5px) 100%, 0% 100%)` after.style.clipPath = `polygon(calc(${data.value}% + 5px) 0%, 100% 0%, 100% 100%, calc(${data.value}% + 5px) 100%)` self.adjustSlider() """, 'slider_width': "self.adjustSlider()", 'adjustSlider': """ halfWidth = parseInt(data.slider_width/2) slider.style.marginLeft = `calc(${data.value}% + 5px - ${halfWidth}px)` """ } _stylesheets: ClassVar[List[str]] = [ f'{CDN_DIST}css/swipe.css' ] def __init__(self, *objects, **params): if 'objects' in params and objects: raise ValueError( "Either supply objects as an positional argument or " "as a keyword argument, not both." ) from ..pane.base import panel objects = params.pop('objects', objects) if not objects: objects = [None, None] super().__init__(objects=[panel(obj) for obj in objects], **params) @param.depends('objects', watch=True, on_init=True) def _update_layout(self): self._before = self.before self._after = self.after @property def before(self): return self[0] if len(self) else None @before.setter def before(self, before): self[0] = before @property def after(self): return self[1] if len(self) > 1 else None @after.setter def after(self, after): self[1] = after
[docs] def select(self, selector=None): """ Iterates over the Viewable and any potential children in the applying the Selector. Arguments --------- selector: type or callable or None The selector allows selecting a subset of Viewables by declaring a type or callable function to filter by. Returns ------- viewables: list(Viewable) """ objects = super().select(selector) for obj in self: objects += obj.select(selector) return objects