Skip to content

Conversation

@axelboc
Copy link
Contributor

@axelboc axelboc commented Jan 8, 2026

Fix #1572

Contrary to what I initially suggested in the issue above, I went with a solution that's fully transparent for users. There's no "pin" button; everything is automatic. The solution relies on the axis domains to decide whether to restore the camera scale and position:

  • The position and scale of the R3F camera are saved in a zustand store every time the user zooms or pans (with some debouncing), along with a visContextKey string computed from the axis domain(s).
  • When switching dataset, if the current key and the key saved in the store match, the camera position and scale are restored.

The store can keep the camera states of multiple visualizations at once (cf. visKey prop of KeepZoom).

Screencast.from.2026-01-14.10-25-19.webm

For the Line visualization, the zoom gets saved as long the user zooms only on the x axis (cf xOnly prop):

Screencast.from.2026-01-14.13-32-56.webm

@axelboc axelboc force-pushed the maintain-camera-zoom branch from 9bc2c19 to 83ce18d Compare January 8, 2026 16:09
@axelboc axelboc requested a review from loichuder January 8, 2026 16:10
Copy link
Member

@loichuder loichuder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading back ##1572, it may be useful to also add the feature to Line as well.

I am also wondering about something. Consider the following sequence:

  1. I view Image1 with Heatmap. I zoom in.
  2. I view Image2 with Heatmap`. It has the same dimensions so the zoom is conserved.
  3. I view another unrelated dataset (say a line). The zoom is not conserved since the key is different.
  4. I view Image2 again. Is the zoom reset or because the entry is still in the store, I get a zoomed-in display?

@axelboc
Copy link
Contributor Author

axelboc commented Jan 12, 2026

useFrame always triggers at least once after mount, so at step 3 in the sequence you describe, the store receives the new key. This means that at step 4, the zoom is not restored on the heatmap.

I'm realising however, that this only applies when both visualizations have KeepZoom; otherwise, at step 3, the store doesn't receive a new key and at step 4, the zoom is in fact restored on the heatmap. This inconsistency is not ideal.


Regarding adding KeepZoom to the line visualization, the problem is that the restore key is computed from both axis domains. As a result:

  • if the user changes the ordinates domain with the slider and zooms in, this zoom level will be restored for any dataset with the same abscissas domain — this seems okay;
  • but if autoscaling is enabled, then the zoom will rarely be restored since the ordinates domain will likely change across datasets — if the user had only zoomed in along the x axis, this feels like a missed opportunity.

Perhaps KeepZoom should be a bit cleverer in this case?

@loichuder
Copy link
Member

Regarding adding KeepZoom to the line visualization [...]

I see your point. Perhaps let's not add anything to Line for now and wait for user feedback with perhaps some relevant data.

@axelboc axelboc force-pushed the maintain-camera-zoom branch 2 times, most recently from bf4c4f4 to 3219a44 Compare January 14, 2026 12:43
@axelboc
Copy link
Contributor Author

axelboc commented Jan 14, 2026

Alright, I think I've got it:

  • The keep-zoom store can now hold multiple independent vis camera states. Each state is stored against a visKey. Inside each state, there's a separate visContextKey to hold the stringified axis domains.
  • On the line vis, I pass an xOnly prop to KeepZoom, which adapts the behaviour as follows:
    • The visContextKey is computed from the abscissas domain only.
    • The camera state is saved only if the users zooms on the x axis only; if they start zooming on the y axis, any previously saved state is unset from the store.

I've updated the PR description accordingly; let me know what you think. I think the proposed behaviour for the line vis fits with what was requested in #1572 and compensates nicely for the lack of an x-axis domain widget.

@axelboc axelboc force-pushed the maintain-camera-zoom branch from 3219a44 to 3186d39 Compare January 14, 2026 12:53
@axelboc axelboc requested a review from loichuder January 14, 2026 12:55
@axelboc axelboc changed the title Maintain camera zoom if applicable on heatmap and RGB visualizations Maintain camera zoom when applicable Jan 14, 2026
@axelboc axelboc merged commit 7d6c227 into main Jan 14, 2026
13 checks passed
@axelboc axelboc deleted the maintain-camera-zoom branch January 14, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keep zoom level and axis positions fixed between files

3 participants