def is_animating(component, include_children=False) -> bool: """Determines whether a component is currently animating""" el = _dom_node(component) return any( a.playState == "running" for a in el.getAnimations({"subtree": include_children}) )
def wait_for(animation_or_component, include_children=False): """If given an animation equivalent to animateion.wait(). If given a component, will wait for all running animations on the component to finish""" if hasattr(animation_or_component, "finished"): _await_promise(animation_or_component.finished) return el = _dom_node(animation_or_component) animations = el.getAnimations({"subtree": include_children}) _window.Promise.all(list(map(lambda a: a.finished, animations)))
def _animate(component, keyframes, options, use_ghost=False): if isinstance(keyframes, Transition): keyframes = keyframes._compute() el = _dom_node(component) if use_ghost: _animate_ghost(el, keyframes, options) return Animation(_a=el.animate(keyframes, options))
def __new__(cls, component=None, effect=None, *, _a=None): # we just return the animation object # the only job of this class is to provide autocompletions if _a is not None: # we're already an animation return _a elif component is None or effect is None: raise TypeError( "An Animation can only be created with a Component (or DOM node) and an Effect" ) el = _dom_node(component) keyframes = effect.getKeyframes() timings = effect.getTimings() return _window.Animation(_a=_window.KeyframeEffect(el, keyframes, timings))
def correct_canvas_resolution(canvas): """call this function in the reset event for a canvas element. It will reduce blurryness of canvas elements on retina screens""" assert isinstance(canvas, _Canvas), "expected a Canvas object as the first argument" dpr = max(_window.devicePixelRatio, 2) dom_c = _dom_node(canvas) rect = dom_c.getBoundingClientRect() new_width = int(rect.width * dpr) if dom_c.width == new_width: # we've done this scaling already return dom_c.width = new_width dom_c.height = int(rect.height * dpr) ctx = dom_c.getContext("2d") # scale all drawing options by the dpr # so we don't worry about the difference ctx.scale(dpr, dpr)
def _animate_from_to(component, c1, c2, t, options): el = _dom_node(component) pos = el.getBoundingClientRect() pos1, pos2 = get_bounding_rect(c1), get_bounding_rect(c2) t_fromto = Transition( translateX=[f"{pos1.x - pos.x}px", f"{pos2.x - pos.x}px"], translateY=[f"{pos1.y - pos.y}px", f"{pos2.y - pos.y}px"], ) if pos1.width != pos2.width: t_fromto["width"] = [pos1.width, pos2.width] if pos1.height != pos2.height: t_fromto["height"] = [pos1.height, pos2.height] t = (t or {}) | t_fromto # we create a ghost node return Animation(_a=_animate(component, t, options, use_ghost=True))
def get_bounding_rect(component) -> DOMRect: """returns an object with attributes relating to the position of the component on the page: x, y, width, height""" if component.__class__ == _window.DOMRect: return component el = _dom_node(component) return DOMRect(obj=el.getBoundingClientRect())