Skip to content

Conversation

@flimsyhat
Copy link
Contributor

@flimsyhat flimsyhat commented Jun 4, 2025

This PR adds the ability to continuously zoom in and out on the PlotDevice canvas with a trackpad or mouse. It also improves rendering performance by replacing the bitmap-based approach with directly rendering to the graphic context.


Continuous zoom

  • Added pinch-to-zoom gesture support
  • Added Command+scroll for zooming
zoom_demo.mov

Direct render approach

Previously, the GraphicsView would pre-render the entire canvas to a bitmap (NSImage) at the current zoom level, convert it to a CALayer's contents, and display that layer. This has been replaced by directly drawing to the view's graphics context, with viewport clipping to only draw the visible portion of the canvas.

This avoids potentially expensive pre-rendering and caching, which can be significantly faster for large scenes or high zoom levels:
render_comparison

This is particularly helpful when working with animations, since each frame draws faster:

animation_test.mp4

Note: The old bitmap approach was smoother when scrolling at high zoom (just moving a cached bitmap around instead of redrawing), but overall I think the benefits of direct drawing outweigh this.

flimsyhat added 5 commits June 4, 2025 12:17
Variable is unused, left over from previous version?
use min() instead of the index/loop approach
- added pinch-to-zoom gesture support for trackpads
- added Cmd + scroll wheel support for mouse
both zoom methods are centered on mouse position
Previously we'd pre-render the entire canvas to a bitmap at the current zoom level, convert it to a CALayer's contents, and display that layer. This is replaced by directly drawing to the view's graphics context.

Changes:
- removed layer-based rendering approach (CALayer and bitmap caching)
- added drawRect_ method to draw canvas contents directly to view's graphics context, with viewport clipping
- updated placeholder image handling to use direct drawing
- removed unused backing scale factor (_dpr) and related bitmap rendering code
- canvas contents are now scaled using NSAffineTransform instead of pre-scaling bitmaps
@samizdatco
Copy link
Member

That's a huge improvement in the animated case; nice work!

I'm a little worried about the static case though. Have you tried scrolling around while zoomed in on moderately complex graphics (e.g., the Drawing›Spider example)? That's the scenario that prompted the existing bitmap + CALayer approach. I wonder if there's a hybrid option available to us, where it uses direct drawing while animating then switches to the cached-bitmap approach when the animation terminates (or when a single image is being generated)?

@flimsyhat
Copy link
Contributor Author

Thanks for taking a look! I agree that the static case is a concern (scroll performance with Drawing›Spider is poor) and I think your suggestion of a hybrid approach is the right balance. I'll take a crack at that and build on this PR.

With Drawing›Spider, the trackpad/mouse zoom isn't great either, and honestly this direct-drawing implementation is redrawing much too often on zoom in any case. For the static case, what I can try is displaying a cached bitmap that gets scaled when zoom starts, and when zoom ends (or we hit some gate condition during the zoom) asynchronously render a new cached bitmap that gets swapped in when ready. That way we have smooth zoom and scroll no matter what.

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.

2 participants