我有一个轮子旋转的简单动画。我正在尝试使用滑块(输入范围)来控制旋转轮的速度。我已经设法做到了这一点,但每次我更改动画时,动画都会重新启动(它会跳转)。寻找一种解决方案来创造一个平滑的速度提升。当用户增加滑块的值时,滚轮以更快的速度旋转。
在下面的代码中,#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>
发布于 2017-12-01 10:49:18
经典问题
(带跳跃..现在还没有)
使用jQuery的版本
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>
工作草案
保存当前动画的变量
http://www.w3.org/TR/css-animations-1/#interface-animationevent-attributes
发布于 2017-12-01 01:15:54
如果没有一种不使用CSS动画的不同方法,我不能完全确定这是否可能。问题是,无论何时更改速度,动画都不会规格化。它始终是从0%动画到100%动画的动画。每次调整animation-duration时,都会使用动画中的当前位置重新插值。
换句话说,如果您在t=12从animation-duration: 25更改为50,那么动画已经完成了一半(180度);现在只完成了四分之一(90度)。你不能控制t,这是浏览器的。如果你可以,你可以设置t保持它在插值中的位置,在这个例子中是t=25,这样你就可以保持动画完成的百分比,但是你会拉伸剩余的时间。
我稍微修改了您的脚本,以便更好地显示我所描述的内容。它会在速度0到5之间以每秒0.25的速度递增。你可以看到问题是浏览器控制的t是怎么回事。
你可以重写这个代码,以便用JavaScript自己控制t,但我认为你必须放弃CSS动画。
要更深入地讨论这个浏览器控制的t变量,请看这篇关于CSS- 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);
});#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" step=".25" class="slider" id="slider" value="0">
<p>Speed: <span id="speed"></span></p>
发布于 2017-12-01 04:49:43
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");
}
});#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);
}<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>
https://stackoverflow.com/questions/47578337
复制相似问题