如何实现小球沿胶囊形父div边框运动?三角函数/圆方程实现方案求教
胶囊轨道小球运动实现方案
核心逻辑说明
- 轨道分为三段:中间直边段(x∈[100,300])、左侧半圆段(x∈[0,100])、右侧半圆段(x∈[300,400])
- 直边段top固定:下半段为
185px,上半段为-15px - 半圆段通过圆方程计算y值,需要额外标记小球当前处于上半轨道还是下半轨道
修正后完整代码
HTML(无需改动)
<html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> </head> <body> <button id="start_stop">Orbit</button> <div id="oval"> <div id="ball0" class="ball"></div> <div id="ball1" class="ball"></div> <div id="ball2" class="ball"></div> <div id="ball3" class="ball"></div> </div> <script src="orbit.js"></script> </body> </html>
CSS(仅修正border-radius保证两端为标准半圆)
#oval { position: absolute; margin-top: 200px; height: 200px; width: 400px; border: 3px solid black; border-radius: 100px; /* 高度200,半径100刚好两端为半圆 */ right: 50%; transform: translate(50%, -50%); } .ball { height: 30px; width: 30px; border-radius: 50%; position: absolute; } #ball0 { left:270px; top:185px; background-color: blue; } #ball1 { left:100px; top: 185px; background-color: green; } #ball2 { top:-15px; left: 270px; background-color: yellow; } #ball3 { top:-15px; left: 100px; background-color: red; }
JS(补全计算逻辑)
var oval = document.getElementById('oval'); var balls = document.getElementsByClassName('ball'); var run_animation = false; var req; document.getElementById("start_stop").addEventListener("click", toggle); function toggle() { run_animation = !run_animation if(run_animation) { req = window.requestAnimationFrame(orbit); } } var max_x = 400; var min_x = 0; // 新增isUp字段标记当前处于上半轨道还是下半轨道 var map = { "ball0": {"top": 185, "left": 270, forward: true, isUp: false}, "ball1": {"top": 185, "left": 100, forward: true, isUp: false}, "ball2": {"top": -15, "left": 270, forward: false, isUp: true}, "ball3": {"top": -15, "left": 100, forward: false, isUp: true} } // 计算半圆段的top值 function get_top(left, isUp, isLeftCircle) { const r = 100; const centerY = 100; let offsetX; if(isLeftCircle) { // 左半圆圆心x坐标为100,小球中心x为left+15 offsetX = (left + 15) - 100; } else { // 右半圆圆心x坐标为300 offsetX = (left + 15) - 300; } // 圆方程求y方向偏移 const offsetY = Math.sqrt(r*r - offsetX*offsetX); let centerYVal; if(isUp) { centerYVal = centerY - offsetY; } else { centerYVal = centerY + offsetY; } // 小球top = 中心y - 小球半高15 return centerYVal - 15; } function orbit() { if (run_animation){ for(var i=0; i<balls.length; i++){ const ball = map["ball"+i]; let curr_left = ball.left; // 走到端点时翻转方向和上下轨道标记 if (curr_left >= max_x) { ball.forward = false; ball.isUp = false; ball.top = 185; } if (curr_left <= min_x ) { ball.forward = true; ball.isUp = true; ball.top = -15; } // 移动x坐标 ball.left += ball.forward ? 3 : -3; // 左侧半圆计算top if(ball.left <= 100 && ball.left >= 0) { ball.top = get_top(ball.left, ball.isUp, true); } // 右侧半圆计算top if(ball.left >= 300 && ball.left <= 400) { ball.top = get_top(ball.left, ball.isUp, false); } // 赋值样式 balls[i].style.left = ball.left + 'px'; balls[i].style.top = ball.top + 'px'; } req = window.requestAnimationFrame(orbit); } else { window.cancelAnimationFrame(req); } } req = window.requestAnimationFrame(orbit);
内容的提问来源于stack exchange,提问作者Scragglez
相关产品推荐
相关产品推荐

