I am trying to rotate div elements (class card) when clicking on it. The div elements are dynamically positioned by setting translateX using jQuery. I would like to rotate the elements out-of-plane when clicking on them (rotateY(90deg)) using the jQuery Keyframes plugin. The expected behaviour would be a rotation in place (the "hinge" would be in the center of the div element, keeping the element at exactly the same position during and after rotation). However, the observed behaviour is a movement of the elements to the right during rotation so that they end up further right than they should. How do I keep them in place? I am using the following code:
$(document).ready(function(){
sortCards();
$(window).on('resize', function(){
sortCards();
});
$('.card').on("click", animate_card);
});
function sortCards() {
var cards = $(".card");
let cardwidth = cards[0].clientWidth;
let content_width = 0.78 * $(window).width();
let no_cards = 4;
let offset = ((no_cards * cardwidth) - content_width)/(no_cards - 1);
for (var i = 1; i < cards.length; i++) {
cards[i].style.transform = "translateX(-" + offset * 1 * i + "px)";
}
}
function animate_card(){
if ($.keyframe.isSupported()){
console.log("supported");
let translation = getTranslation($(this));
if (translation != null){
var str1 = 'rotateY(0deg)';
var str2 = 'rotateY(90deg)';
} else {
var str1 = 'rotateY(0deg)';
var str2 = 'rotateY(90deg)';
}
$.keyframe.define([{
name: 'rotateCard',
'0%': {'transform': str1},
'100%': {'transform': str2}
}]);
$(this).playKeyframe({
name: 'rotateCard',
duration: '5s',
timingFunction: 'linear',
iterationCount: 1,
complete: function(){
}
})
}
}
function getTranslation(selector){
var obj = $(selector);
var transformMatrix = obj.css("-webkit-transform") ||
obj.css("-moz-transform") ||
obj.css("-ms-transform") ||
obj.css("-o-transform") ||
obj.css("transform");
var matrix = transformMatrix.replace(/[^0-9\-.,]/g, '').split(',');
var x = matrix[12] || matrix[4];//translate x
console.log(x);
return x;
}
:root{
--content_width: 80vw;
--content_height: 60vh;
--card_scale: 1;
}
#card-grid{
display: flex;
width: var(--content_width);
margin-top: 20px;
}
.card{
display: grid;
grid-template-columns: 10% 10% 10% 40% 10% 10% 10%;
grid-template-rows: calc(0.75*20%) 1fr calc(0.75*20%);
height: calc(var(--card_scale)*var(--content_height));
width: calc(var(--card_scale)*0.75*var(--content_height));
border-radius: 5px;
border-color: black;
border-style: solid;
border-width: 1%;
background-color: white;
justify-self: left;
transform-origin: 50%, 50%;
/*position: relative;
z-index: inherit;*/
}
#card-grid > .card{
flex: 0 0 calc(var(--card_scale)*0.75*var(--content_height));
box-shadow: 10px 10px 0px 0px;
}
<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- jQuery keyframes library, don't know how to embed it otherwise -->
<script>!function o(a,u,s){function l(t,e){if(!u[t]){if(!a[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(c)return c(t,!0);var r=new Error("Cannot find module '"+t+"'");throw r.code="MODULE_NOT_FOUND",r}var i=u[t]={exports:{}};a[t][0].call(i.exports,function(e){return l(a[t][1][e]||e)},i,i.exports,o,a,u,s)}return u[t].exports}for(var c="function"==typeof require&&require,e=0;e<s.length;e++)l(s[e]);return l}({1:[function(e,t,n){"use strict";var r,i,o=(r=e("@keyframes/core"))&&r.__esModule?r:{default:r};function a(e,n){e.each(function(e,t){t.Keyframes||(t.Keyframes=new o.default(t)),n(t.Keyframes)})}(i=jQuery).keyframe={isSupported:o.default.isSupported,generate:o.default.generate,generateCSS:o.default.generateCSS,define:o.default.define},i.fn.resetKeyframe=function(t){a(this,function(e){return e.reset().then(t)})},i.fn.pauseKeyframe=function(){a(this,function(e){return e.pause()})},i.fn.resumeKeyframe=function(){a(this,function(e){return e.resume()})},i.fn.playKeyframe=function(t,e){var n=e;t.complete&&(e=t.complete),"function"==typeof e&&(n={onIteration:e,onEnd:e}),a(this,function(e){return e.play(t,n)})}},{"@keyframes/core":2}],2:[function(e,t,n){"use strict";var o=function(){return(o=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)},d=function(e,a,u,s){return new(u=u||Promise)(function(t,n){function r(e){try{o(s.next(e))}catch(e){n(e)}}function i(e){try{o(s.throw(e))}catch(e){n(e)}}function o(e){e.done?t(e.value):function(t){return t instanceof u?t:new u(function(e){e(t)})}(e.value).then(r,i)}o((s=s.apply(e,a||[])).next())})},p=function(n,r){var i,o,a,e,u={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]};return e={next:t(0),throw:t(1),return:t(2)},"function"==typeof Symbol&&(e[Symbol.iterator]=function(){return this}),e;function t(t){return function(e){return function(t){if(i)throw new TypeError("Generator is already executing.");for(;u;)try{if(i=1,o&&(a=2&t[0]?o.return:t[0]?o.throw||((a=o.return)&&a.call(o),0):o.next)&&!(a=a.call(o,t[1])).done)return a;switch(o=0,a&&(t=[2&t[0],a.value]),t[0]){case 0:case 1:a=t;break;case 4:return u.label++,{value:t[1],done:!1};case 5:u.label++,o=t[1],t=[0];continue;case 7:t=u.ops.pop(),u.trys.pop();continue;default:if(!(a=0<(a=u.trys).length&&a[a.length-1])&&(6===t[0]||2===t[0])){u=0;continue}if(3===t[0]&&(!a||t[1]>a[0]&&t[1]<a[3])){u.label=t[1];break}if(6===t[0]&&u.label<a[1]){u.label=a[1],a=t;break}if(a&&u.label<a[2]){u.label=a[2],u.ops.push(t);break}a[2]&&u.ops.pop(),u.trys.pop();continue}t=r.call(n,u)}catch(e){t=[6,e],o=0}finally{i=a=0}if(5&t[0])throw t[1];return{value:t[0]?t[1]:void 0,done:!0}}([t,e])}}},r=function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(n,"__esModule",{value:!0});function i(){return new Promise(function(e){requestAnimationFrame(function(){e()})})}var a,u=r(e("add-px-to-style")),s=r(e("hyphenate-style-name")),l="undefined"!=typeof window;if(l){var c=document.createElement("style");c.setAttribute("id","keyframesjs-stylesheet"),document.head.appendChild(c),a=c.sheet}function f(){}function h(e){if(!Object.keys(e).length)return"";var t="";for(var n in e)t+=s.default(n)+":"+u.default(n,e[n])+";";return t}var m=(y.isSupported=function(){return void 0!==document.body.style.animationName},y.prototype.reset=function(){return d(this,void 0,void 0,function(){return p(this,function(e){switch(e.label){case 0:return this.removeEvents(),this.mountedElement.style.animationPlayState="running",this.mountedElement.style.animation="none",[4,i()];case 1:return e.sent(),[2,this]}})})},y.prototype.pause=function(){return this.mountedElement.style.animationPlayState="paused",this},y.prototype.resume=function(){return this.mountedElement.style.animationPlayState="running",this},y.prototype.play=function(t,n){var r=this;if(this.mountedElement.style.animationName===this.getAnimationName(t))return requestAnimationFrame(function(){return d(r,void 0,void 0,function(){return p(this,function(e){switch(e.label){case 0:return[4,this.reset()];case 1:return e.sent(),this.play(t,n),[2]}})})}),this;function e(e,t){var n=e+"Listener";r.mountedElement.removeEventListener(e,r[n]),r[n]=t,r.mountedElement.addEventListener(e,r[n])}var i=n||{},o=i.onBeforeStart,a=void 0===o?null:o,u=i.onStart,s=void 0===u?null:u,l=i.onIteration,c=void 0===l?null:l,f=i.onEnd,h=void 0===f?null:f,m=y.playCSS(t);return a&&a(),this.mountedElement.style.animationPlayState="running",this.mountedElement.style.animation=m,c&&e("animationiteration",c),h&&e("animationend",h),s&&requestAnimationFrame(s),this},y.prototype.removeEvents=function(){return this.mountedElement.removeEventListener("animationiteration",this.animationiterationListener),this.mountedElement.removeEventListener("animationend",this.animationendListener),this},y.prototype.playNext=function(){var e=this,t=this.queueStore.pop();t?this.play(t,{onEnd:function(){return e.playNext()},onIteration:this.callbacks.onIteration}):this.callbacks.onEnd&&this.callbacks.onEnd()},y.prototype.updateCallbacks=function(e){e&&(this.callbacks=o(o({},this.callbacks),e))},y.prototype.queue=function(e,t){var n=this.queueStore.length;return this.updateCallbacks(t),e.constructor===Array?this.queueStore=e.reverse().concat(this.queueStore):this.queueStore.unshift(e),n||(this.callbacks.onBeforeStart&&this.callbacks.onBeforeStart(),this.playNext(),this.callbacks.onStart&&requestAnimationFrame(this.callbacks.onStart)),this},y.prototype.resetQueue=function(){return d(this,void 0,void 0,function(){return p(this,function(e){switch(e.label){case 0:return[4,i()];case 1:return e.sent(),this.removeEvents(),this.queueStore=[],[4,this.reset()];case 2:return e.sent(),[2,this]}})})},y.prototype.chain=function(t,n){return d(this,void 0,void 0,function(){return p(this,function(e){switch(e.label){case 0:return[4,this.resetQueue()];case 1:return e.sent(),this.queue(t,n),[2,this]}})})},y.prototype.getAnimationName=function(e){switch(e.constructor){case Array:return e.map(this.getAnimationName).join(", ");case String:return e.split(" ")[0];default:return e.name}},y.playCSS=function(e){function t(e){var t=o({duration:"0s",timingFunction:"ease",delay:"0s",iterationCount:1,direction:"normal",fillMode:"forwards"},e);return[t.name,t.duration,t.timingFunction,t.delay,t.iterationCount,t.direction,t.fillMode].join(" ")}if(e.constructor!==Array)return e.constructor===String?e:t(e);for(var n=e,r=[],i=0;i<n.length;i+=1)r.push(n[i].constructor===String?n[i]:t(n[i]));return r.join(", ")},y.generateCSS=function(e){var t="@keyframes "+e.name+" {";for(var n in e)"name"!==n&&"media"!==n&&"complete"!==n&&(t+=n+" {"+h(e[n])+"}");return t+="}",e.media&&(t="@media "+e.media+"{"+t+"}"),t},y.generate=function(e){var t=this.generateCSS(e),n=y.rules.indexOf(e.name);-1<n&&(y.sheet.deleteRule(n),y.rules.splice(n,1));var r=(y.sheet.cssRules||y.sheet.rules).length;y.sheet.insertRule(t,r),y.rules[r]=e.name},y.define=function(e){if(e.length)for(var t=0;t<e.length;t+=1)this.generate(e[t]);else this.generate(e)},y.defineCSS=function(e){if(e.length){for(var t="",n=0;n<e.length;n+=1)t+=this.generateCSS(e[n]);return t}return this.generateCSS(e)},y.plugin=function(e){if(e.constructor===Array)for(var t=0;t<e.length;t+=1)e[t](this);else e(this)},y.sheet=a,y.rules=[],y);function y(e){this.queueStore=[],this.callbacks={onStart:f,onBeforeStart:f,onIteration:f,onEnd:f},this.animationendListener=f,this.animationiterationListener=f,this.mountedElement=e}l&&(window.Keyframes=m),n.default=m},{"add-px-to-style":3,"hyphenate-style-name":4}],3:[function(e,t,n){"use strict";var r={animationIterationCount:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridColumn:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,stopOpacity:!0,strokeDashoffset:!0,strokeOpacity:!0,strokeWidth:!0};t.exports=function(e,t){return"number"!=typeof t||r[e]?t:t+"px"}},{}],4:[function(e,t,n){"use strict";var r=/[A-Z]/g,i=/^ms-/,o={};function a(e){return"-"+e.toLowerCase()}t.exports=function(e){if(o.hasOwnProperty(e))return o[e];var t=e.replace(r,a);return o[e]=i.test(t)?"-"+t:t}},{}]},{},[1]);</script>
<body>
<div id="card-grid">
<div class="card" id="create-card">
</div>
<div class="card" id="join-card">
</div>
<div class="card" id="sign_in-card">
</div>
<div class="card" id="about-card">
</div>
</div>
</body>
</html>