JSFiddle - React, Tailwind, and code Playground
HTML
<div id="test1">
<div id="rect-1">
Rect 1 (easy one)
</div>
<div id="goal-x1">
It works if box lands here!
</div>
</div>
<div id="test2">
<div id="rect-2">
Rect 2 (crazy transform!)
</div>
<div id="goal-x2">
It works if box lands here!
</div>
</div>
<div id="test3">
<div id="rect-3">
Rect 3 (crazier transform!)
</div>
<div id="goal-x3">
It works if box lands here!
</div>
</div>
CSS
#rect-1 {
width: 200px;
height: 200px;
border: 1px solid;
transform: translateZ(100px);
}
#rect-2 {
width: 200px;
height: 200px;
border: 1px solid;
transform: rotate(20deg);
}
#rect-3 {
width: 200px;
height: 200px;
border: 1px solid;
transform: matrix(2, 1, 0, 1, 1, 0);
transform-origin: bottom left;
}
#goal-x1,
#goal-x2,
#goal-x3 {
width: 200px;
height: 200px;
border: 1px solid;
transform: translateX(200px);
position: relative;
top: -202px;
}
JavaScript
function animate(elm, milliseconds, distance) {
console.warn(
'Running an "animate" method that should be named "moveRightOnly"'
);
return new Promise((resolve, reject) => {
// Allow animation to be chained
if (distance < 0 || milliseconds < 0) {
reject(
new Error(
"Feeling negative? Really? This method only moves things to the right. Sorry!"
)
);
}
// I think the Matrix API is neat, but the only reason I'm doing it this long-drawn out way is:
// 1. MDN warns of the API being non-standard, not production-ready
// 2. ES features make it easy enough to do without it
let computedStyle = getComputedStyle(elm).getPropertyValue("transform");
let newStyle
if (computedStyle === "none") {
elm.style.transform = "translate(0px, 0px)";
computedStyle = getComputedStyle(elm).getPropertyValue("transform");
}
const params = computedStyle
.match(/\((.+)\)/)[1]
.split(/,\s*/)
.map(s => parseFloat(s));
if (computedStyle.includes('matrix3d')) {
params[12] += distance
newStyle = `matrix3d(${params.join(', ')})`
} else {
params[4] += distance
newStyle = `matrix(${params.join(', ')})`
}
elm.animate(
[
{
transform: computedStyle
},
{
transform: newStyle
}
],
{
duration: milliseconds,
fill: "forwards"
}
).onfinish = resolve;
});
}
const elms = ["rect-1", "rect-2", "rect-3"];
elms.forEach(elmId => {
const elm = document.getElementById(elmId);
elm.addEventListener("click", () => {
animate(elm, 1000, 200);
});
});