0
votes

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>
1
If you use translateX property the element moves on the x-axis - Sfili_81
@Sfili_81 sorry, the translate option was still in my code because I was trying to fix the movement by a counter-movement, to no avail. I removed the translate code from the javascript. - Iridium
Could you check your snippet - at the moment it's giving an uncaught typeerror trying to read propert isSupported of undefined. Thanks. - A Haworth

1 Answers

0
votes
<div class="frame">
  <div class="element"></div>
</div>

I've faced similar problem while making a analog clock in js. You can rotate the frame and keep the element in place, ie rotate the element in place.