Fix the SVG transform-origin during initial mount#3154
Fix the SVG transform-origin during initial mount#3154mattgperry merged 16 commits intomotiondivision:mainfrom
Conversation
…2949) Dimension is measured on the client side. Therefore, the origin cannot be measured on the first mount, resulting in a jump. Before the dimension is measured, set "transformBox" to "Fill Box" and center the origin to leave the initial origin to the browser. This behavior is only valid when manually calculating the last value of "transformOrigin".
|
I'm a little concerned about the extra bundle size here, but I have to ask, if this works, is it possible for us to just ditch measuring the SVG elements entirely and use this |
|
Unfortunately, I don't know exactly what context "calcSVGTransformOrigin" was added in, so it's hard to give you a definite answer. "fill-box" is widely used, but I think I can keep "calcSVGTransformOrigin" if it requires a manual accurate calculation. As a temporary measure, I took the form of leaving the server to the browser. I need to make sure most browsers guarantee the same behavior of the "fill-box" and "transform-origin: 50% 50%" combination. What I've checked are firefox and chrome browsers. For now, I think it's possible. However, I think someone might want to use "view-box". I think we might consider whether to give this option to the user or not. |
|
Ah ok - well currently as it stands the intended behaviour of all this measurement is to force transforms to apply to SVG elements the same way they do HTML elements. There's no option to have the default behaviour. So by setting |
|
Maybe, I think it's possible. |
|
Having a quick play, this is what we're trying to do with all the measurements. This would be a big win for performance and filesize. Is this something you'd be interested in taking a look at or would you prefer me to give it a go? |
|
I'll try it. |
|
Hi, I have a question. The origin doesn't apply to HTML elements (not SVG). Wouldn't it be better if origin could apply to HTML elements as well?...or is it not necessary? example// HTML element origin
<motion.div style={{ originX : 0.1 }} />
|
|
@Taeyeon-Lim It should be the case that |
|
oh..., I understand. Thank you. |
Change the existing origin calculation from manual to automatic. To do this, switch the transform-box style from the default value to 'fill-box'.
| const staticMarkup = renderToStaticMarkup(<Component />) | ||
| const string = renderToString(<Component />) | ||
|
|
||
| const expectedMarkup = `<article><main draggable="false" style="z-index:unset;transform:none;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:pan-x"></main></article>` |
There was a problem hiding this comment.
This should only be the case if originX etc or transformOrigin have been explicitly set.
| ) | ||
|
|
||
| expect(div).toBe( | ||
| '<div style="transform:translateX(100px) translateY(200px)"></div>' |
There was a problem hiding this comment.
Likewise we definitely don't want to set this if it wasn't explicitly set by the user - unless this is an SVG with a transform
| ) | ||
|
|
||
| expect(rect).toBe( | ||
| '<rect mask="" class="test" style="background:#fff"></rect>' |
There was a problem hiding this comment.
How come this one doesn't have transform-box:fill-box?
| * undefined origins. | ||
| */ | ||
| if (hasTransformOrigin) { | ||
| if (hasTransformOrigin || style.transform) { |
There was a problem hiding this comment.
If you move this logic to the svg/utils/build-styles file this will remove the style from HTML elements
| useVisualState: makeUseVisualState({ | ||
| scrapeMotionValuesFromProps: scrapeSVGProps, | ||
| createRenderState: createSvgRenderState, | ||
| onUpdate: ({ |
|
I left some comments, but this looks amazing. I think if we can get |
|
I'm sorry for the late response and thank you for the comment. Well, I got the default behavior wrong. What you said meant it only changed when you were given |
|
No rush! Yes good to default to 50% for SVG with transforms but to ensure
HTML only gets an origin if one is defined
…On Thu, 17 Apr 2025 at 16:31, ltys ***@***.***> wrote:
I'm sorry for the late response and thank you for the comment. Well, I got
the default behavior wrong. What you said meant it only changed when you
were given transform-origin or transform by the user...
I will remove the style.transform of html/utils/build-styles and change
the transform-origin of SVG to operate when there is only transform-origin
from html. If I do this, unlike HTML, if there is only transform,
transform-origin will act like 0, 0 instead of 50% 50%, right? Or, should
I include this case as well?
—
Reply to this email directly, view it on GitHub
<#3154 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB34WKW2TQRL2JAQYNRQHN32Z63MPAVCNFSM6AAAAAB3FUSXB2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQMJTGEZTKNJVGI>
.
You are receiving this because you commented.Message ID:
***@***.***>
*Taeyeon-Lim* left a comment (motiondivision/motion#3154)
<#3154 (comment)>
I'm sorry for the late response and thank you for the comment. Well, I got
the default behavior wrong. What you said meant it only changed when you
were given transform-origin or transform by the user...
I will remove the style.transform of html/utils/build-styles and change
the transform-origin of SVG to operate when there is only transform-origin
from html. If I do this, unlike HTML, if there is only transform,
transform-origin will act like 0, 0 instead of 50% 50%, right? Or, should
I include this case as well?
—
Reply to this email directly, view it on GitHub
<#3154 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB34WKW2TQRL2JAQYNRQHN32Z63MPAVCNFSM6AAAAAB3FUSXB2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDQMJTGEZTKNJVGI>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
|
I've understood your intentions clearly, and I'll take my time to ensure it's done well. don't worry |
Modify the behavior of "transform-origin, -box" in SVG to apply user-provided values correctly. Changes include: - Default "transform" value set to "50% 50%" when "transform-origin" is not provided. - "transform-origin" applies the input value as is. - "transform" or "transform-origin" triggers the application of "transform-box: fill-box".
This type is no longer in use.
|
Thanks for your work on this @Taeyeon-Lim! There's just the conflicts to resolve and we can publish this - I'd do it myself but I'm getting a message that they're too complex to resolve in the web editor. |
bc2897c to
09c94a6
Compare
|
I see, I'll try to solve it. |
09c94a6 to
b5586d0
Compare
|
The conflict is resolved, but the content has gotten a little messy. Is it better to do a new PR? |
|
@Taeyeon-Lim No it's perfect, thanks for all your work on this! |
The bug (SVG transform-origin jumping on initial mount) was fixed in PR #3154, which ensured transformBox: "fill-box" and transformOrigin: "50% 50%" are set before dimensions are measured. The fix was preserved during the motion-dom refactoring. This commit adds targeted E2E tests to prevent regression and closes the issue. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dimension is measured on the client side. Therefore, the origin cannot be measured on the first mount, resulting in a jump. Before the dimension is measured, set transformBox to "fill-box" and center the origin to leave the initial origin to the browser.
This is only valid when manually calculating the last value of transformOrigin.
ref: #2949