Skip to content

Commit

Permalink
WIP: Make + and - zoom in and out, respectively
Browse files Browse the repository at this point in the history
This adds a zoom function to the PCanvas and implements for the two
current backends. For vispy, the zoom happens under the cursor, like how
the mouse wheel behaves. But for pygfx, I did not yet figure out how to
do that. Do we need to translate the focused point to the origin, then
change zoom, then translate it back?
  • Loading branch information
ctrueden committed Oct 9, 2024
1 parent 10abe13 commit 2b598ea
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/ndv/viewer/_backends/_protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ def set_range(
z: tuple[float, float] | None = None,
margin: float = ...,
) -> None: ...
def zoom(
self,
factor: Union[float, tuple],
center: tuple = None,
) -> None: ...
def refresh(self) -> None: ...
def qwidget(self) -> QWidget: ...
def add_image(
Expand Down
17 changes: 17 additions & 0 deletions src/ndv/viewer/_backends/_pygfx.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,23 @@ def set_range(
cam.zoom = 1 - margin
self.refresh()

def zoom(self, factor: Union[float, tuple], center: tuple = None):
"""
Zoom in (or out) at the given center.
Parameters
----------
factor : float or tuple
Fraction by which the scene should be zoomed (e.g. a factor of 2
causes the scene to appear twice as large).
center : tuple of 2-4 elements
The center of the view. If not given or None, use the
current center.
"""
cam = self._camera
cam.zoom *= factor
self.refresh()

def refresh(self) -> None:
self._canvas.update()
self._canvas.request_draw(self._animate)
Expand Down
17 changes: 16 additions & 1 deletion src/ndv/viewer/_backends/_vispy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import warnings
from contextlib import suppress
from typing import TYPE_CHECKING, Any, Literal, cast
from typing import TYPE_CHECKING, Any, Literal, Union, cast
from weakref import WeakKeyDictionary

import cmap
Expand Down Expand Up @@ -580,6 +580,21 @@ def set_range(
max_size = max(x[1], y[1], z[1])
self._camera.scale_factor = max_size + 6

def zoom(self, factor: Union[float, tuple], center: tuple = None):
"""
Zoom in (or out) at the given center.
Parameters
----------
factor : float or tuple
Fraction by which the scene should be zoomed (e.g. a factor of 2
causes the scene to appear twice as large).
center : tuple of 2-4 elements
The center of the view. If not given or None, use the
current center.
"""
return self._camera.zoom(factor=factor, center=center)

def canvas_to_world(
self, pos_xy: tuple[float, float]
) -> tuple[float, float, float]:
Expand Down
8 changes: 8 additions & 0 deletions src/ndv/viewer/_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ def __init__(
# ROI
self._roi: PRoiHandle | None = None

# closest data point under the mouse
self._data_coords: tuple[int, int] = (0, 0)

# WIDGETS ----------------------------------------------------

# the button that controls the display mode of the channels
Expand Down Expand Up @@ -731,6 +734,7 @@ def _update_hover_info(self, event: QMouseEvent) -> bool:

x = int(x)
y = int(y)
self._data_coords = (x, y)
text = f"[{y}, {x}]"
# TODO: Can we use self._canvas.elements_at?
for n, handles in enumerate(self._img_handles.values()):
Expand Down Expand Up @@ -765,6 +769,10 @@ def keyPressEvent(self, a0: QKeyEvent | None) -> None:
if a0.key() == Qt.Key.Key_Delete and self._selection is not None:
self._selection.remove()
self._selection = None
elif a0.key() in [Qt.Key.Key_Plus, Qt.Key.Key_Equal]:
self._canvas.zoom(factor=0.667, center=self._data_coords)
elif a0.key() in [Qt.Key.Key_Minus, Qt.Key.Key_Underscore]:
self._canvas.zoom(factor=1.5, center=self._data_coords)

def _update_roi_button(self, event: QMouseEvent) -> bool:
if self._add_roi_btn.isChecked():
Expand Down

0 comments on commit 2b598ea

Please sign in to comment.