requestAnimationFrame with multiple independent objects

I am attempting to animate two different objects, a div formatted to look like a square and another formatted to look like a circle. I have a button for each object to start the animation which consists of just moving the object from left to right. I have included the code below. The issue I am having is that if I click on the Move Square button and then click on the Move Circle button, the square moves back to the left. What I am attempting to do is to move the objects independently of one another.

I am sure there is an object oriented solution for this but I have searched and have not found anything that makes sense to me. Any suggestions?

$(document).ready(function() {
  var moveSquare = $('#moveSquare');
  var moveCircle = $('#moveCircle');

  var square = $('#square');
  var squareText = $('#squareText');

  square.css({
    top: '100px',
    left: '0px',
    color: 'white',
    position: 'fixed',
    'text-align': 'center'
  });
  var pos_square = square.position();
  squareText.html(pos_square.top + 'px' + '<br/>' + pos_square.left + 'px');

  var circle = $('#circle');
  var circleText = $('#circleText');

  circle.css({
    top: '300px',
    left: '0px',
    color: 'white',
    position: 'fixed',
    'text-align': 'center'
  });
  var pos_circle = circle.position();
  circleText.html(pos_circle.top + 'px' + '<br/>' + pos_circle.left + 'px');

  moveSquare.on('click', function() {
    console.log('movesuqare here');

    requestAnimationFrame(function(timestamp) {
      starttime = timestamp;
      move(timestamp, square, squareText, 800, 5000);
    });

  });

  moveCircle.on('click', function() {
    console.log('movecircle here');

    requestAnimationFrame(function(timestamp) {
      starttime = timestamp;
      move(timestamp, circle, circleText, 800, 1000);
    });

  });


  function move(timestamp, element, elementText, distance, duration) {
    var runtime = timestamp - starttime;
    var progress = runtime / duration;
    progress = Math.min(progress, 1);

    var leftPos = (distance * progress).toFixed(0) + 'px';
    element.css({
      left: leftPos,
      position: 'absolute'
    });
    element.css({
      'text-align': 'center'
    });

    var topPos = element.css('top') + '<br/>';
    elementText.html(topPos + leftPos);

    console.log(element.prop('id') + leftPos);
    if (runtime < duration) {
      requestAnimationFrame(function(timestamp) {
        move(timestamp, element, elementText, distance, duration);
      });
    }
  }


});
html {
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
}

body {
  font-family: 'Courier New';
  color: black;
  font-size: 15px;
  width: auto;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
}

.container {
  width: 100px;
  height: 100px;
}

.square_css {
  width: 100px;
  height: 100px;
  background-color: blue;
}

.circle_css {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color: green;
}

.shapeText {
  padding-top: 30%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<html lang="en">

<head>
  <link rel="stylesheet" type="text/css" href="<?php echo URL; ?>views/index/css/index_Main.css" />
</head>

<body>

  <div>
    <input type="button" id="moveSquare" value="Move Square" />
  </div>

  <div>
    <input type="button" id="moveCircle" value="Move Circle" />
  </div>

  <div id="square" class="square_css">
    <div id="squareText" class="shapeText"></div>
  </div>

  <div id="circle" class="circle_css">
    <div id="circleText" class="shapeText"></div>
  </div>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script type="text/javascript" src="<?php echo URL; ?>views/index/js/index_main.js"></script>
</body>

</html>

1 answer

  • answered 2017-11-13 01:19 Roamer-1888

    The problems is caused by the two animations sharing a common variable starttime.

    To fix, you need some way of each animation having its own starttime.

    There's a number of ways you could do that, the simplest of which is to pass a start time to move() along with the other parameters, from the click handlers. And because move() calls itself, starttime needs to be passed on to the next call.

    $(document).ready(function() {
    	var square = $('#square').css({
    		'top': '100px',
    		'left': '0px',
    		'color': 'white',
    		'position': 'fixed',
    		'text-align': 'center'
    	});
    	var circle = $('#circle').css({
    		'top': '300px',
    		'left': '0px',
    		'color': 'white',
    		'position': 'fixed',
    		'text-align': 'center'
    	});
    
    	var squareText = $('#squareText');
    	var circleText = $('#circleText');
    
    	var pos_square = square.position();
    	var pos_circle = circle.position();
    
    	squareText.html(pos_square.top + 'px' + '<br/>' + pos_square.left + 'px');
    	circleText.html(pos_circle.top + 'px' + '<br/>' + pos_circle.left + 'px');
    
    	$('#moveSquare').on('click', function() { // button
    		console.log('movesuqare here');
    		requestAnimationFrame(function(timestamp) {
    			move(timestamp, timestamp, square, squareText, 800, 5000);
    		});
    	});
    
    	$('#moveCircle').on('click', function() { // button
    		console.log('movecircle here');
    		requestAnimationFrame(function(timestamp) {
    			move(timestamp, timestamp, circle, circleText, 800, 1000);
    		});
    	});
    
    	function move(starttime, timestamp, element, elementText, distance, duration) {
    		var runtime = timestamp - starttime;
    		var progress = runtime / duration;
    		progress = Math.min(progress, 1);
    		var leftPos = (distance * progress).toFixed(0) + 'px';
    		element.css({
    			left: leftPos,
    			position: 'absolute'
    		});
    		element.css({
    			'text-align': 'center'
    		});
    		var topPos = element.css('top') + '<br/>';
    		elementText.html(topPos + leftPos);
    		console.log(element.prop('id') + leftPos);
    		if (runtime < duration) {
    			requestAnimationFrame(function(timestamp) {
    				move(starttime, timestamp, element, elementText, distance, duration);
    			});
    		}
    	}
    });
    html {
      position: fixed;
      top: 0;
      bottom: 0;
      right: 0;
      left: 0;
    }
    
    body {
      font-family: 'Courier New';
      color: black;
      font-size: 15px;
      width: auto;
      top: 0;
      bottom: 0;
      right: 0;
      left: 0;
    }
    
    .container {
      width: 100px;
      height: 100px;
    }
    
    .square_css {
      width: 100px;
      height: 100px;
      background-color: blue;
    }
    
    .circle_css {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background-color: green;
    }
    
    .shapeText {
      padding-top: 30%;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
    <html lang="en">
    
    <head>
      <link rel="stylesheet" type="text/css" href="<?php echo URL; ?>views/index/css/index_Main.css" />
    </head>
    
    <body>
    
      <div>
        <input type="button" id="moveSquare" value="Move Square" />
      </div>
    
      <div>
        <input type="button" id="moveCircle" value="Move Circle" />
      </div>
    
      <div id="square" class="square_css">
        <div id="squareText" class="shapeText"></div>
      </div>
    
      <div id="circle" class="circle_css">
        <div id="circleText" class="shapeText"></div>
      </div>
    
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
      <script type="text/javascript" src="<?php echo URL; ?>views/index/js/index_main.js"></script>
    </body>
    
    </html>