首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CSS更改动画持续时间而不跳转

问CSS更改动画持续时间而不跳转
EN

Stack Overflow用户
提问于 2017-12-01 00:39:36
回答 4查看 2.7K关注 0票数 13

我有一个轮子旋转的简单动画。我正在尝试使用滑块(输入范围)来控制旋转轮的速度。我已经设法做到了这一点,但每次我更改动画时,动画都会重新启动(它会跳转)。寻找一种解决方案来创造一个平滑的速度提升。当用户增加滑块的值时,滚轮以更快的速度旋转。

在下面的代码中,#loading是一个旋转的轮子。

​

代码语言:javascript
复制
$(document).on('input', '#slider', function() {
  var speed = $(this).val();
  $('#speed').html(speed);
  $("#loading").css("animation-duration", 50 / speed + "s");
});
代码语言:javascript
复制
#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);
  }
}
代码语言:javascript
复制
<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>

​

EN

回答 4

Stack Overflow用户

发布于 2017-12-01 10:49:18

经典问题

(带跳跃..现在还没有)

使用jQuery的版本

​

代码语言:javascript
复制
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;
});
代码语言:javascript
复制
.anime_object {
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
}

.enable_rotate {
  animation: rotateRight infinite linear;
}

@keyframes rotateRight {
  100% {
    transform: rotate(360deg);
  }
}
代码语言:javascript
复制
<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

  1. SO
  2. css-tricks.com
票数 4
EN

Stack Overflow用户

发布于 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提供了很好的控制,如下面的演示所示。

这就是你的问题,你希望能够改变你的动画的持续时间,然后在动画中寻找正确的位置。

​

代码语言: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);
});
代码语言:javascript
复制
#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);
  }
}
代码语言:javascript
复制
<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>

​

票数 0
EN

Stack Overflow用户

发布于 2017-12-01 04:49:43

TL;DR

不,你不能(根据我的测试)

  • 最重要的是,让我们从你的css中去掉动画声明,把它移到Javascript上,这样动画循环就不会启动(即使你看不到它正在运行)。

您是否注意到,即使当您从初始位置移动滑块时,框也会显示为从随机位置开始?这是因为动画循环实际上一直在运行。

现在,你可以通过你的动画在任何给定的时间获得当前的变换值,使用getComputedStyle(loadingElement).getPropertyValue('transform');,这将返回一个矩阵,这个矩阵不会给你太多,但是我们可以从这个矩阵计算旋转的角度:

(使用一些数学解释here)

代码语言:javascript
复制
Math.round(Math.atan2(b, a) * (180/Math.PI));

现在我们有了这个值,我们必须将它标准化为只有正值的角度,然后我们可以应用这个角度作为transform: rotate(Xdeg)的基准值

到目前为止还不错,你可以在代码片段中看到这一点,然而,即使你这样做了,并增加/减少了速度值,动画循环已经在以设定的时间尺度运行,你不能重置这个循环。

到目前为止,我的答案是,这样其他对动画循环有更深理解的人可以从构建,并可能提出一个有效的代码。

如果你还在读这篇文章,你可能会想,好吧,用loadingElement.style.removeProperty('animation')删除动画,然后再次分配它,尝试它不起作用。如果用setInterval(...,0)重新开始动画,让它在下一个循环中运行,也不会起作用。

​

代码语言:javascript
复制
$(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");
	}

});
代码语言:javascript
复制
#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);
  }
代码语言:javascript
复制
<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>

​

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47578337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档