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/
CodePudding user response:
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;
}