interactive_image.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. from __future__ import annotations
  2. from typing import Callable, Dict, List, Optional
  3. from ..events import MouseEventArguments, handle_event
  4. from ..vue import register_component
  5. from .mixins.content_element import ContentElement
  6. from .mixins.source_element import SourceElement
  7. register_component('interactive_image', __file__, 'interactive_image.js')
  8. class InteractiveImage(SourceElement, ContentElement):
  9. def __init__(self, source: str = '', *,
  10. on_mouse: Optional[Callable] = None, events: List[str] = ['click'], cross: bool = False) -> None:
  11. """Interactive Image
  12. Create an image with an SVG overlay that handles mouse events and yields image coordinates.
  13. :param source: the source of the image; can be an URL or a base64 string
  14. :param on_mouse: callback for mouse events (yields `type`, `image_x` and `image_y`)
  15. :param events: list of JavaScript events to subscribe to (default: `['click']`)
  16. :param cross: whether to show crosshairs (default: `False`)
  17. """
  18. super().__init__(tag='interactive_image', source=source, content='')
  19. self._props['events'] = events
  20. self._props['cross'] = cross
  21. def handle_connect(_) -> None:
  22. self.run_method('set_source', self.source)
  23. self.run_method('set_content', self.content)
  24. self.on('connect', handle_connect)
  25. def handle_mouse(msg: Dict) -> None:
  26. if on_mouse is None:
  27. return
  28. arguments = MouseEventArguments(
  29. sender=self,
  30. client=self.client,
  31. type=msg['args'].get('mouse_event_type'),
  32. image_x=msg['args'].get('image_x'),
  33. image_y=msg['args'].get('image_y'),
  34. )
  35. return handle_event(on_mouse, arguments)
  36. self.on('mouse', handle_mouse, ['*'])
  37. def on_source_change(self, source: str) -> None:
  38. self.run_method('set_source', source)
  39. def on_content_change(self, content: str) -> None:
  40. self.run_method('set_content', content)