Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transition.style("transform", …) ignores inherited styles. #72

Open
edcoumont opened this issue Jul 26, 2017 · 1 comment
Open

transition.style("transform", …) ignores inherited styles. #72

edcoumont opened this issue Jul 26, 2017 · 1 comment

Comments

@edcoumont
Copy link

I'm trying to perform a transition to a transform:translate style with values specified as em.

This jsfiddle is reproducing the problem : https://jsfiddle.net/59ushyut/

Note the body font-size:2px so that 1em should be considered as 2px in the document.

When I start at transform: translate(100em) :

  • doing element.style("transform", "translate(200em)") is ok.
  • but doing element.transition().duration(1000).style("transform", "translate(200em)"); is sending my element way too far. The final style becomes transform: translate(3200px, 0px);, as if d3 was considering that 1em = 16px.

D3 version is 4.10.0
Issue reproduced on last versions of Chrome and Firefox.

@mbostock
Copy link
Member

The problem is that transition.style on the transform style uses d3.interpolateTransformCss, which computes the normalized form of the transform style property using an off-screen DIV element; see parse.js. Thus the interpolator ignores the inherited style from the body, and transitions from matrix(1, 0, 0, 1, 1600, 0) to matrix(1, 0, 0, 1, 3200, 0).

(Prior to d3-transition@1.1.0/d3@4.9.0, the computed style property value on the transitioning element was used as the starting value for the transition, so the starting value was correct: matrix(1, 0, 0, 1, 200, 0). However, the ending value would still be interpreted incorrectly as matrix(1, 0, 0, 1, 3200, 0).)

You can workaround this issue by not depending on inherited styles, by using px units, or by using transition.attr (which only allows pixel units). You could also compute the normalized values yourself on each transitioning element, and pass them to d3.interpolateTransformCss using transition.styleTween.

Fixing this is possible, but it doesn’t look easy, since it requires computing the normalized transform on the transitioning element for both the starting and ending value. And there’s no easy way to pass along the transitioning element to d3.interpolateTransformCss (without either further special-casing of transitions on the transform style, or always passing the transitioning element as the third argument to the interpolator factory, which seems like overkill and could also cause surprising behavior if interpolator factories are not expecting that additional argument).

This might require a completely different code path in transition.style for the transform attribute, so that the computed value is always used as the starting and ending value, rather than the normal behavior where the inline value takes priority.

Alternatively, we could use the computed value for both the starting and ending values, as discussed in #47 (comment). However, this behavior was recently changed in 1.1.0 as mentioned above, and I think in general using the inline values (as specified by the caller) leads to more predictable behavior; transforms are special because they are normalized rather than interpolated as-specified using d3.interpolateString. So I think it’d be better to change the special case in transition.style as described in the previous paragraph.

@mbostock mbostock changed the title Transition to transform:translate(123em) is not working right transition.style("transform", …) ignores inherited styles. Jul 31, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants