feat(gpui): Add transform group support for pan/zoom camera views #53306
Replies: 3 comments
-
|
I would be delighted to see this proposal implemented. In a recent program I developed using GPUI, I needed to create a complex chart supporting drag and zoom functionality, which I accomplished with Canvas by employing the manual calculation method you described. Separately, I also had a requirement for vertical text layout. To achieve this, I had no alternative but to modify certain internal code within GPUI. In my view, implementing general-purpose component transformation would represent a crucial milestone for GPUI to evolve into a robust UI framework. I believe many developers share similar needs, and I sincerely hope the GPUI team will take this proposal into consideration. |
Beta Was this translation helpful? Give feedback.
-
|
I want to develop an image viewer using |
Beta Was this translation helpful? Give feedback.
-
|
I suggest adding an |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
feat(gpui): Add transform group support for pan/zoom camera views
Pre-flight Checks
status:approvedbefore a PR can be openedProblem Description
Building interactive views that require a pan/zoom camera (e.g., entity-relationship diagrams, node graphs, canvas-based editors, schema visualizers) is not possible in GPUUI without resorting to manual coordinate transformation in
canvas()paint callbacks.Concrete use case: A database schema visualization tool that needs to:
divwith text, icons, column lists)Current workaround and its limitations
The only workaround is to manually transform world coordinates to screen coordinates for each element:
Limitations of this workaround:
paint_quad,paint_path,paint_svg). Standard GPUUI elements likediv,text,h_stack,v_stackcannot be used inside a canvas paint callback.window.layout_bounds()and element hitboxes remain in screen space.What exists but cannot be used
TransformationMatrix(inscene.rs) is a general 2D affine transform struct withtranslate,rotate,scale, andcomposemethods. However, it is only wired into two scene primitives:MonochromeSpriteandSubpixelSprite(both used for SVG rendering). It is not available for:Quad(used bydiv)Path(used by SVG paths, canvas drawing)Shadow,UnderlineAdditionally,
paint_layeronly does clipping (push_layer/pop_layeron the scene's z-stack), not transformation.The
svgelement has awith_transformation()API, but the documentation notes: "won't effect the hitbox or layout of the element, only the rendering".Proposed Solution
Add a
TransformGroupelement that applies aTransformationMatrixto its entire subtree, affecting both rendering and hitboxes.API Proposal
Technical Approach (Option B / C hybrid)
The implementation would build on the existing infrastructure:
scene.rs: Add atransform_stack: Vec<TransformationMatrix>toScenewithpush_transform()/pop_transform()methods.insert_primitive()applies the active transform to primitive bounds before submitting to the platform backend.canvaselement: Accept an optionalTransformationMatrixin itspaint()method. When set,push_transform/pop_transformwraps the user paint callback.divelement (full Option A): Requires changes to theElementtrait'spaint()signature to thread aTransformationMatrixthrough. This is the higher-effort path but enables full composability with existing GPUUI elements.Affected Area
area:gpui— core GPUUI frameworkAlternatives Considered
Doing nothing — external tools like DBFlux work around this with canvas + manual coordinate math, but cannot use standard GPUUI elements in transformed spaces.
CSS-style transform-only visual — Apply
TransformationMatrixonly at paint time (like current SVGwith_transformation). Hitboxes remain in screen space. This solves rendering but breaks hover/click on transformed content.Per-element
.scale()and.translate()methods — Adding individual transform methods to each element is architecturally messier than a group-based approach.Additional Context
What
TransformationMatrixlooks like todayAlready general-purpose, just not exposed beyond SVG sprite rendering.
Pipeline where this would fit
For a TransformGroup element, both
prepaint(hitboxes) andpaint(primitives) would need to apply the active transform.I am willing to implement this. I have a detailed analysis of the required changes across
scene.rs,window.rs,canvas.rs, and theElementtrait, with estimates for both the minimal (canvas-only) and full (TransformGroup) approaches.Beta Was this translation helpful? Give feedback.
All reactions