我有一个简单的车轮旋转动画。我试图使用滑块(输入范围)控制旋转轮的速度。我已设法做到这一点,但每次我更改动画时动画重新启动(它跳转)。寻找一种解决方案,以创造一个平稳的速度增长。当用户增加滑块的值时,轮子以增加的速度旋转。
在下面的代码中,#loading是旋转轮。
$(document).on('input', '#slider', function() {
var speed = $(this).val();
$('#speed').html(speed);
$("#loading").css("animation-duration", 50 / speed + "s");
});

#loading {
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 50% 50%;
animation: rotateRight infinite linear;
animation-duration: 0;
}
@keyframes rotateRight {
100% {
transform: rotate(360deg);
}
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<img id="loading" src="//placehold.it/100">
<input type="range" min="0" max="100" value="0" class="slider" id="slider">
<p>Speed: <span id="speed"></span></p>
&#13;
答案 0 :(得分:2)
经典问题
(跳跃......现在还没有)
var lasttime = 0, lastduration = 0, angle = 0;
$(document).on('input', '#slider', function(event) {
var speed = $(this).val();
$('#speed').html(speed);
var el = $("#loading");
var duration = (speed > 0) ? 50 / speed : 0;
var currenttime = event.originalEvent.timeStamp / 1000;
var difftime = currenttime - lasttime;
el.removeClass("enable_rotate").show();
if (!lastduration && duration)
el.css("transform", "");
else
angle += (difftime % lastduration) / lastduration;
if (duration){
el.css("animation-duration", duration + "s")
.css("animation-delay", -duration * angle + "s")
.addClass("enable_rotate");
}
else
el.css("transform", "rotate(" + 360 * angle + "deg)");
angle -= angle | 0; //use fractional part only
lasttime = currenttime;
lastduration = duration;
});
.anime_object {
position: absolute;
left: 0;
right: 0;
margin: auto;
}
.enable_rotate {
animation: rotateRight infinite linear;
}
@keyframes rotateRight {
100% {
transform: rotate(360deg);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<img id="loading" class="anime_object" src="//placehold.it/100">
<input type="range" min="0" max="100" value="0" id="slider">
<p>Speed: <span id="speed"></span></p>
保存currentanimation的变量
http://www.w3.org/TR/css-animations-1/#interface-animationevent-attributes
答案 1 :(得分:0)
如果没有不使用CSS动画的不同方法,我不能完全确定这是可行的。问题是,无论何时更改速度,动画都不会正常化。它总是动画从动画的0%到动画的100%。每次调整animation-duration
时,您都会使用动画中的当前位置重新插值。
换句话说,如果您在animation-duration: 25
处从50
更改为t=12
,那么动画 中途完成(180度);现在它只完成了四分之一(90度)。但是,您无法控制t
,这是浏览器的标识。如果可以,您可能希望将t
设置为插值中的位置,在此示例中为t=25
,以便您保持与动画完全相同的百分比,但是你延长剩余的时间。
我稍稍修改了你的脚本,试着展示我所描述的更好一点。它会在速度0到5之间每秒将速度提高0.25
。您可以看到问题是浏览器控制t
是问题所在。
你可以重写这个以便用JavaScript控制t
,但我认为你必须放弃CSS动画。
再谈谈这个浏览器控制的t
变量,请看看有关CSS-Tricks的这篇文章:Myth Busting: CSS Animations vs. JavaScript
某些浏览器允许您暂停/恢复CSS关键帧动画,但是 那是关于它的。你不能寻找一个特定的地方 动画,你也不能顺利地逆转或改变 时间刻度或在某些位置添加回调或将它们绑定到富人 一组播放事件。 JavaScript提供了很好的控制,如图所示 下面的演示。
这是您的问题,您希望能够更改动画的持续时间,但也可以在动画中寻找正确的位置。
$(function() {
var speed = parseInt($("#slider").val(), 10);
$("#speed").html(speed);
$("#loading").css("animation-duration", 50 / speed + "s");
var forward = true;
setInterval(function() {
speed += (forward ? 0.25 : -0.25);
if (speed >= 5) {
forward = false;
} else if (speed <= 0) {
forward = true;
}
$("#loading").css("animation-duration", 50 / speed + "s");
$("#slider").val(speed);
$("#speed").html(speed);
}, 1000);
});
&#13;
#loading {
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 50% 50%;
animation: rotateRight infinite linear;
animation-duration: 0;
}
@keyframes rotateRight {
100% {
transform: rotate(360deg);
}
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<img id="loading" src="//placehold.it/100">
<input type="range" min="0" max="100" value="0" step=".25" class="slider" id="slider" value="0">
<p>Speed: <span id="speed"></span></p>
&#13;
答案 2 :(得分:0)
TL; DR
您是否注意到即使您从最初位置移动滑块,该框似乎从随机位置开始?这是因为动画循环实际上已经在运行。
getComputedStyle(loadingElement).getPropertyValue('transform');
这将返回一个矩阵,它不会给你很多,但我们可以从该矩阵计算旋转角度:(使用一些数学解释here)
Math.round(Math.atan2(b, a) * (180/Math.PI));
现在我们有了这个值,我们必须将它标准化为只有角度的正值,然后我们可以将此角度应用为transform: rotate(Xdeg)
到目前为止一切顺利,您可以看到这在代码片段中工作,但是即使您这样做,并递增/递减速度值,动画循环已经在运行设定时间刻度,您无法重置此循环。
到目前为止,我的回答是其他对动画循环有更深入了解的人可以从构建,也许会想出一个可行的代码。
如果您还在阅读本文,您可能会想到,只需使用loadingElement.style.removeProperty('animation')
删除动画并再次分配,尝试它不起作用。然后用setInterval(...,0)再次启动动画,以便它在下一个循环中运行,也不会工作。
$(document).on('input', '#slider', function() {
var speed = $(this).val();
var loadingElement = document.querySelector("#loading")
$('#speed').html(speed);
//get the current status of the animation applied to the element (this is a matrix)
var currentCss = getComputedStyle(loadingElement).getPropertyValue('transform');
if (currentCss !== 'none'){
//parse each value we need from the matrix (there is a total of 6)
var values = currentCss.split('(')[1];
values = values.split(')')[0];
values = values.split(',');
var a = values[0];
var b = values[1];
var c = values[2];
var d = values[3];
//here we make the actual calculation
var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
//normalize to positive values
angle = angle < 0 ? angle + 360 : angle;
loadingElement.style.removeProperty('animation'); //remove the property for testing purposes
$("#loading").css('transform', 'rotate(' + angle + 'deg)');
}
else{ //else for testing purposes, this will change the speed of the animation only on the first slider input change
$("#loading").css('animation', 'rotateRight infinite linear'); //see how the animation now actually starts from the initial location
$("#loading").css("animation-duration", 50 / speed + "s");
}
});
&#13;
#loading {
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 50% 50%;
/*I removed the initialization of the animation here*/
}
@keyframes rotateRight {
100% {
transform: rotate(360deg);
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="loading" src="https://placehold.it/100">
<input type="range" min="0" max="100" value="0" class="slider" id="slider">
<p>Speed: <span id="speed"></span></p>
&#13;
答案 3 :(得分:0)
以下是我们采取的方法:
transform
值,该值以matrix()
matrix()
转换为rotate
度数我们需要克服的主要问题是根据当前旋转值创建新的动画关键帧 - 我们需要创建一个新动画,其起始值等于当前旋转值,并且结束值等于当前旋转值价值+ 360。
换句话说,如果我们的元素被轮换90deg
并且速度发生了变化,我们需要创建一个新的@keyframes
:
@keyframes updatedKeyframes {
0% {
transform: rotate(90deg);
},
100% {
transform: rotate(450deg); // 90 + 360
}
}
要创建动态动画,请使用jQuery.keyframes插件创建动态@keyframes
。
虽然这个解决方案有效,但我根据jQuery.keyframes
插件的工作方式,我不相信它的超级性能。对于每个新动画关键帧,插件都会附加内联<style>
。这导致可能定义了数十,数百甚至数千keyframes
个speed
。在下面的示例中,我使用@keyframe
变量创建@keyframes
名称,因此最多可创建100个唯一$(document).on('input', '#slider', function() {
var speed = $(this).val();
$('#speed').html(speed);
var transform = $("#loading").css('transform');
var angle = getRotationDegrees(transform);
$("#loading").css({
"animation": "none"
});
$.keyframe.define([{
name: `rotateRight_${speed}`,
"0%": {
"transform": "rotate(" + angle + "deg)"
},
"100%": {
'transform': "rotate(" + (angle + 360) + "deg)"
}
}]);
if (speed === "0") {
$("#loading").css("transform", "rotate(" + angle + "deg)");
} else {
$("#loading").playKeyframe({
name: `rotateRight_${speed}`,
duration: 50 / speed + "s",
timingFunction: "linear",
iterationCount: "infinite"
});
}
});
function getRotationDegrees(matrix) {
if (matrix !== 'none') {
var values = matrix.split('(')[1].split(')')[0].split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
} else {
var angle = 0;
}
return angle;
}
个样式。我们可以在这里进行一些优化,但这不属于此解决方案的范围。
以下是工作示例:
#loading {
position: absolute;
left: 0;
right: 0;
margin: auto;
transform-origin: 50% 50%;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://rawgit.com/jQueryKeyframes/jQuery.Keyframes/master/jquery.keyframes.js"></script>
<img id="loading" src="http://via.placeholder.com/100x100">
<input type="range" min="0" max="100" value="0" class="slider" id="slider">
<p>Speed: <span id="speed"></span></p>
&#13;
{{1}}&#13;