Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Rotate, Translate, and Scale rectangle from a keyframe using popmotion pure?

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)
})
like image 951
Armeen Harwood Avatar asked Dec 22 '22 18:12

Armeen Harwood


2 Answers

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

like image 179
KCE Avatar answered Jan 19 '23 00:01

KCE


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' },
  ],
like image 28
Joundill Avatar answered Jan 18 '23 22:01

Joundill