4

How do I make the last keyframe rotate my rectangle to a 35deg angle using popmotion pure?

enter image description here https://codepen.io/matthewharwood/pen/XWmRPaK?editors=1111

HTML:

<div class="flex h-screen w-screen justify-center items-center">
  <div class="portal-b">
    <h1 class="left"></h1>
  </div>
</div>
<button class="trigger fixed z-10 left-0 top-0">
  B replace A
</button>

CSS:

.portal-b {
  background: blue;
  width: 1px;
  height: 100px;
}

JS

const { easing, keyframes, styler } = window.popmotion;
const trigger = document.querySelector('.trigger');
const [_, portalB] = [document.querySelector('.portal-a'), document.querySelector('.portal-b')];
trigger.addEventListener('click', () => {
  const portalS = styler(portalB);
  keyframes({
  values: [
    { translateX: 0, scaleX: 0, rotateZ: 0, transformOrigin: 'left center' },
    { translateX: 200, scaleX: 400, rotateZ: 0, transformOrigin: 'left center' },
    { translateX: 200, scaleX: 400,  rotateZ: 90,  transformOrigin: 'left center' },
  ],
  duration: 3000,
  easings: easing.easeInOut,
}).start(portalS.set)
})
Armeen Moon
  • 18,061
  • 35
  • 120
  • 233

2 Answers2

7

For this kind of problem I recommend stepping through the values in plain CSS in your browser. I found that the following CSS rule provided the final state you wanted

.portal-b {
  background: blue;
  width: 1px;
  height: 100px;
  transform: translateX(200px) rotate(-35deg) scaleX(400);
}

Then all you need is for your keyframes to step their way there, stating explicitly the values they expect like so

  values: [
    { transform: "translateX(0px) rotate(0deg) scaleX(1)" },
    { transform: "translateX(200px) rotate(0deg) scaleX(400)" },
    { transform: "translateX(200px) rotate(-35deg) scaleX(400)"},
  ],

Here's your pen with my changes: https://codepen.io/kcerb/pen/wvKyWLv?editors=1111

KCE
  • 1,159
  • 8
  • 25
  • @Matthew Harwood added a copy of your codepen with the values above pasted in. I believe this gives the behavior you're looking for. – KCE May 06 '20 at 13:15
3

Here's a solution using Popmotion Pure, using the built-in transform options rather than a transform string: https://jsfiddle.net/rqjahwLt/

You're correct that the trouble is math-based. You need to set the dimensions of your rectangle in your CSS to be what you want at the end of the animation.

The trouble is Popmotion Pure will apply rotateZ, before it applies scaleX.

The solution:

The CSS uses width to set the dimensions desired at the end of the animation, and transform to set the dimensions desired at the beginning. If you set width: 1px, then your rotateZ is applied before scaleX, which leaves you with a rhombus (i.e. skewed rectangle) instead of a rotated rectangle as desired.

.portal-b {
  background: blue; 
  width: 300px; /* set the width to what you want at the end */
  height: 100px;
  transform: scaleX(0.001); /* transform the width to what you want at the start */
}

The Javascript then only has to un-set our transform: scaleX(0.001) from above. The second keyframe will animate the rectangle from being width = 0.3px to width = 300px. Then the final keyframe rotates this to -35deg around the Z axis.

  values: [
  { translateX: 0, scaleX: 0.001, rotateZ: 0, transformOrigin: 'left center' },
    { translateX: 200, scaleX: 1, rotateZ: 0, transformOrigin: 'left center' },
    { translateX: 200, rotateZ: -35,  transformOrigin: 'center' },
  ],
Community
  • 1
  • 1
Joundill
  • 6,828
  • 12
  • 36
  • 50