从关键帧中间动画转换回来

时间:2017-12-19 14:17:54

标签: css3 css-transitions

我正在寻找一种从rotate转换中关键帧转换回来的方法。我有一个长期运行的关键帧,可以从0deg重复转换为360deg

当该动画停止时(通过删除类),我希望元素从当前位置返回0deg。目前,我正在使用第二个关键帧来动画回0deg,但是这个关键帧总是将完整的360deg转回0deg,这不是我想要的。

我做了一个JSFiddle来演示这个问题:https://jsfiddle.net/egdct6qz/2/

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

您可以使用以下CSS和JavaScript组合来实现这一点,该组合使用getComputedStyle ()

const circle = document.querySelector (".circle");

circle.onclick = () => {
    if (circle.classList.contains ("circle--spinning")) {
    	// Get rotation and start animating back
        let currentRotation = getRotationDegrees (circle);
        animateRotationBack (currentRotation);
    }
    
    // Toggle the spinning itself
    circle.classList.toggle ("circle--spinning");
} 

function animateRotationBack (angle) {
	const keyframe = `
    	@keyframes spin-back {
        	from { transform: rotate(${angle}deg); }
            to { transform: rotate(0deg); }
        }
    `;

    // Get inserted style-tag or create a new one
    const style = document.getElementById ("spin-back-kf") || document.createElement ("style");
    style.textContent = keyframe;
    style.id = "spin-back-kf";
    
    // Remove previously inserted style tag if existant
    style.parentNode && style.parentNode.removeChild (style);
    
    // Append style tag and set animation
    document.body.appendChild (style);
}

function getRotationDegrees (element) {
    // get the computed style object for the element
    const style = window.getComputedStyle (element);
     
    // this string will be in the form 'matrix(a, b, c, d, tx, ty)'
    let transformString = style["-webkit-transform"]
                       || style["-moz-transform"]
                       || style["transform"];
                       
    if (!transformString || transformString === "none")
        return 0;
        
    // Remove matrix notation
    transformString = transformString
    	.substr (0, transformString.length - 2)
        .substr (7);
    
    // Split and parse to floats
    const parts = transformString
    	.split (",")
        .map (num => parseFloat (num));
        
    // Destructure in a and b
    let [a, b] = parts;
    
    // Doing atan2 on (b, a) will give you the angle in radians
    // Convert it to degrees and normalize it from (-180...180) to (0...360)
    const degrees = ((180 * Math.atan2 (b, a) / Math.PI) + 360) % 360;
    
    return degrees;
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.wrapper {
    margin: 5% auto;
    text-align: center;
}

.circle {
    padding: 3em;
    border-radius: 3em;
    position: relative;
    background-color: #EE5622;
    display: inline-block;
    cursor: pointer;
    
    animation: .5s spin-back forwards;
}

.circle--spinning {
    animation: 2s spin infinite linear;
}

.square {
    padding: 1em;
    background-color: #F1F7ED;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: inline-block;
}

@keyframes spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}
<div class="wrapper">
    <span class="circle circle--spinning">
        <span class="square"></span>
    </span>
</div>