You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现小球沿胶囊形父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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:15:03