Skip to content

Resize and title support for Pyodide canvases#196

Merged
almarklein merged 5 commits intomainfrom
more-js
Mar 25, 2026
Merged

Resize and title support for Pyodide canvases#196
almarklein merged 5 commits intomainfrom
more-js

Conversation

@almarklein
Copy link
Member

@almarklein almarklein commented Mar 13, 2026

Instead of connecting the pyodide canvas to a <canvas>, it can now also be connected to a <div class='renderview-wrapper'>. When this is done, the a canvas will be created inside it, plus additional elements to support manual resizing, and a titlebar.

image

You can grab the bottom-right corner and drag it.

An additional benefit is that content placed inside the wrapper will be deleted when the canvas loads; so its very easy to show a loading notification.

Side note: I started out with just replacing the <canvas> with a wrapper element, but that will cause all sorts of problems if users style their canvas, e.g. to position it. We'd have to transfer styles onto the wrapper and that will just become a mess. So I made it explicit.

If a <canvas> is provided (the old approach), the JS code will not change its style at all (except width and height), providing a magic-less option for use-cases that need full control over the canvas.

The Pyodide canvas got a few new methods (the anywidget backend will have these too):

  • set_css_width() and set_css_height()
  • set_resizable()
  • show_titlebar()

@almarklein almarklein requested a review from Korijn March 13, 2026 09:34
@almarklein
Copy link
Member Author

cc @Vipitis

Also, in the future we could add stuff to the titlebar to minimize the widget, or maximize it (like a youtube video).

@almarklein
Copy link
Member Author

almarklein commented Mar 13, 2026

Some technical details on the DOM and CSS, for those interested:

<div class='renderview-wrapper'>
  <canvas />  <!-- or <img>  -->
  <div class='rendervier-top'> 
    <span>The title </span
  </div>
  <div class='renderview-resizer'></div>
</div>

The wrapper represents the viewport of the canvas. You can size the wrapper, and the canvas will follow (it has width and height set to 100%).

The resize element is an invisible 14x14 square absolutely positioned in the bottom-right corner of the wrapper (on top of the canvas). Good to mention that a canvas cannot have child elements.

The titlebar is a bit more tricky; it's absolutely positioned at the top of the wrapper, with a negative offset, so it extends beyond the wrapper. The wrapper sets a margin-top to avoid the titlebar from overlapping with other content.

@Vipitis
Copy link
Contributor

Vipitis commented Mar 13, 2026

I will have to have a look at all the improvements over the weekend.
Have you thought about closing, repositioning and maybe spawning canvases from the UI or python side? There is a few multi canvas examples where this might come in handy. The sorta technical difficulty with groups will be running them in webworkers(like pyscript does) - so it doesn't block interactivity with the rest of the tab. Also could there be a very slight hint if the wrapper/canvas is focussed to take key and pointer events?

It's good to have the vanilla canvas still work (or perhaps it should be just it's context?) so other web frameworks can make use of it. One simple example could be how to setup a fullscreen canvas.

@almarklein
Copy link
Member Author

almarklein commented Mar 13, 2026

Have you thought about closing,

Yes, closing works. (manually closing could be an option for later).

repositioning and maybe spawning canvases from the UI or python side?

I thought about that. Would not be very hard; instead of providing the canvas/wrapper, provide a container element. This is actually more similar to how AnyWidget works (it gives you a container to put the widget in). For now I stuck to the existing API, I created #197 to track this and other ideas.

Also could there be a very slight hint if the wrapper/canvas is focussed to take key and pointer events?

Good idea! Added to #197.

@almarklein almarklein merged commit 8f67af2 into main Mar 25, 2026
21 checks passed
@almarklein almarklein deleted the more-js branch March 25, 2026 11:41
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