简体   繁体   中英

Move elements around semicircle - orbit div around parent

I'm attempting to make these balls move along the border of this parent div. The parent div is a pill/discorectangle. I'm sure there must be a way to do this using some trig or equation of a circle. So the straight sides are 200px long and the radius of each semi circle is 100px. So from 0-100px and 300-400px the top style needs to be calculated for each ball. Has anyone done anything similar or have any advice?

HTML:

<html>
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="style.css">
</head>
<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>

 </html>

CSS:

#oval {
  position: absolute;
  margin-top: 200px;
  height: 200px;
  width: 400px;
  border: 3px solid black;
  border-radius: 400px/400px;
  right: 50%;
  transform: translate(50%, -50%);
}


.ball {
  height: 30px;
  width: 30px;
  border-radius: 30px;
  position: absolute;
}

#ball0 {

  left:270px;
  top:185px;

  /*right: 100px;
    bottom: -15;*/

  background-color: blue;
}

#ball1 {
  left:100px;
  /* bottom:-15px; */
  top: 185px;
  background-color: green;
}

#ball2 {
  top:-15px;
  /* right: 100px; */
  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);
  }
}

console.log(balls.length);

var max_x = oval.clientWidth; // - 100;
var min_x = 0;
var step = 0;

var map = {
  "ball0": {"top": 185, "left": 270, forward: true},
  "ball1": {"top": 185, "left": 100, forward: true},
  "ball2": {"top": -15, "left": 270, forward: false},
  "ball3": {"top": -15, "left": 100, forward: false}
}

function get_y(x){
  //some math here?
  // return 100 * Math.sin(x);
  // return Math.sqrt(100**2 + x**2);
}

function orbit() {
  if (run_animation){

    for(var i=0; i<balls.length; i++){
      var curr_left = map["ball"+i].left;
      if (curr_left >= max_x) map["ball"+i].forward = false;
      if (curr_left <= min_x ) map["ball"+i].forward = true;

      if(map["ball"+i].forward){
        map["ball"+i].left += 3;
      }
      else {
        forward = false
        map["ball"+i].left -= 3;
      }

      //left edge - curve around semicircle
      if(map["ball"+i].left <= 100) {
        // map["ball"+i].top = -1 * get_y(map["ball"+i].left);
      }
      //right edge - curve around semicircle
      if(map["ball"+i].left >= 300) {
        // map["ball"+i].top = -1 * get_y(map["ball"+i].left);
      }

      balls[i].style.left = map["ball"+i].left + 'px';
      balls[i].style.top  = map["ball"+i].top + 'px';
    }
    req = window.requestAnimationFrame(orbit);
  }
  else {
    console.log("cancel");
    window.cancelAnimationFrame(req);
  }

}

/* orbit(); */

req = window.requestAnimationFrame(orbit);

https://jsfiddle.net/gzjfxtbu/2/

Well I did it. Not sure if this is the best way to do this or not. I'd still like to figure out any other methods to accomplish this. Eventually I was going to turn the balls into actual divs containing info and images. So I'm not sure if the SVG route is the best?

Hopefully this can help someone.

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);
  }
}

console.log(balls.length);

var max_x = oval.clientWidth;
var min_x = 0;
var step = 0;

var map = {
  "ball0": {"top": 185, "left": 270, forward: false},
  "ball1": {"top": 185, "left": 100, forward: false},
  "ball2": {"top": -15, "left": 270, forward: true},
  "ball3": {"top": -15, "left": 100, forward: true}
}

function get_y(x){
  //some math here?
  // return 100 * Math.sin(x);
  return 1 * (Math.sqrt(100**2 - (100-x)**2));
}

function get_y2(x) {
  return 1 * (Math.sqrt(100**2 - (300-x)**2));
}

function orbit() {
  if (run_animation){

    for(var i=0; i<balls.length; i++){
      var curr_left = map["ball"+i].left;
      if (curr_left >= max_x) map["ball"+i].forward = false;
      if (curr_left <= min_x ) map["ball"+i].forward = true;

      if(map["ball"+i].forward){
        map["ball"+i].left += 3;
      }
      else {
        map["ball"+i].left -= 3;
      }

      //left edge - curve around semicircle
      if(map["ball"+i].left <= 85 && !map["ball"+i].forward ) {
        map["ball"+i].top = 1*get_y(map["ball"+i].left) + 85;
      }
      else if(map["ball"+i].left <= 85 && map["ball"+i].forward ) {
        map["ball"+i].top =  -1*get_y(map["ball"+i].left) + 85;
      }
      //right edge - curve around semicircle
      if(map["ball"+i].left >= 315 && map["ball"+i].forward) {
        map["ball"+i].top = -1*get_y2(map["ball"+i].left) + 85;
      }
      else if(map["ball"+i].left >= 315 && !map["ball"+i].forward) {
        map["ball"+i].top = get_y2(map["ball"+i].left) + 85;
      }

      balls[i].style.left = map["ball"+i].left + 'px';
      balls[i].style.top  = map["ball"+i].top + 'px';
    }
    req = window.requestAnimationFrame(orbit);
  }
  else {
    console.log("cancel");
    window.cancelAnimationFrame(req);
  }

}

/* orbit(); */

req = window.requestAnimationFrame(orbit);


HTML:

<html>
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="style.css">
</head>
<button id="start_stop">Orbit</button>
 <div id="oval">
        <div id="ball0" class="ball">0</div>
      <div id="ball1" class="ball">1</div>
      <div id="ball2" class="ball">2</div>
      <div id="ball3" class="ball">3</div>
 </div>

 <script src="orbit.js"></script>

 </html>


CSS:

#oval {
  position: absolute;
  margin-top: 100px;
  height: 200px;
  width: 400px;
  border: 3px solid black;
  border-radius: 400px/400px;
  right: 50%;
  transform: translate(50%, -50%);
}


.ball {
  height: 30px;
  width: 30px;
  border-radius: 30px;
  position: absolute;
}

#ball0 {

  left:270px;
  top:185px;

  /*right: 100px;
    bottom: -15;*/

  background-color: blue;
}

#ball1 {
  left:100px;
  /* bottom:-15px; */
  top: 185px;
  background-color: green;
}

#ball2 {
  top:-15px;
  /* right: 100px; */
  left: 270px;
  background-color: yellow;
}

#ball3 {
  top:-15px;
  left: 100px;

  background-color: red;
}


https://jsfiddle.net/nwm3r4he/3/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM