如何流畅实现SVG中animateTransform旋转速度的动态调整?
实现SVG图形平滑减速旋转
直接修改SVG动画的dur属性会导致动画跳帧,因为动画会重置状态重新计算,所以没法实现平滑过渡。要达成「初始快速旋转,4秒内逐渐停止」的效果,给你两种靠谱方案:
方案一:纯SVG关键帧动画
利用animateTransform的values和keyTimes属性,定义不同阶段的旋转节奏,前1秒快速转,后3秒逐步减慢直到停止,总时长刚好4秒。
<svg viewBox='0 0 200 200' style='width:400px;'> <g transform="translate(100,100)" stroke="#000" stroke-width="2"> <path d="M0 0-70 70A99 99 0 0 1-70-70Z" fill="#f00"/> <path d="M0 0-70-70A99 99 0 0 1 70-70Z" fill="#080"/> <path d="M0 0 70-70A99 99 0 0 1 70 70Z" fill="#dd0"/> <path d="M0 0 70 70A99 99 0 0 1-70 70Z" fill="#04e"/> </g> <animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 0 0; 360 0 0; 720 0 0; 900 0 0; 990 0 0; 1080 0 0" keyTimes="0; 0.25; 0.5; 0.7; 0.85; 1" dur="4s" fill="freeze" id='rad_rotate' /> </svg>
细节说明:
values里的数值是旋转角度关键节点:前0.25秒(1秒)转1圈,之后每段旋转量逐步减少,最终总共转3圈后停下keyTimes对应每个关键帧的时间占比,0是动画开始,1是4秒结束fill="freeze"让动画结束后保持最后静止状态
方案二:JavaScript实时控制(更灵活)
用requestAnimationFrame逐帧计算旋转角度,通过减速公式实现平滑减速,完全避开修改SVG动画属性导致的跳变问题。
<svg viewBox='0 0 200 200' style='width:400px;'> <g id="rotating-group" transform="translate(100,100) rotate(0)" stroke="#000" stroke-width="2"> <path d="M0 0-70 70A99 99 0 0 1-70-70Z" fill="#f00"/> <path d="M0 0-70-70A99 99 0 0 1 70-70Z" fill="#080"/> <path d="M0 0 70-70A99 99 0 0 1 70 70Z" fill="#dd0"/> <path d="M0 0 70 70A99 99 0 0 1-70 70Z" fill="#04e"/> </g> </svg> <script> const rotatingGroup = document.getElementById('rotating-group'); let currentAngle = 0; // 初始角速度:每秒转1圈(360度) let angularSpeed = 360; // 4秒减速到0,计算每帧减速幅度 const deceleration = angularSpeed / 4 / 60; let startTime = null; function animate(timestamp) { if (!startTime) startTime = timestamp; const elapsed = (timestamp - startTime) / 1000; // 角速度减到0就不再变化 if (angularSpeed > 0) { angularSpeed = Math.max(0, angularSpeed - deceleration); } // 更新当前旋转角度 currentAngle += angularSpeed / 60; rotatingGroup.setAttribute('transform', `translate(100,100) rotate(${currentAngle})`); // 角速度不为0就继续动画 if (angularSpeed > 0) { requestAnimationFrame(animate); } } // 启动动画 requestAnimationFrame(animate); </script>
细节说明:
- 直接操作旋转组的
transform属性,逐帧更新角度,完全避免SVG动画的状态重置问题 - 这里用的是线性减速,如果你想要更自然的「先快后慢」效果,可以把减速逻辑改成指数形式,比如每帧让角速度乘以0.98:
angularSpeed *= 0.98
内容的提问来源于stack exchange,提问作者user2051376
相关产品推荐
相关产品推荐

