Everything was going smoothly until now. I want to have this hor() function reverse after 20 seconds. The original hor() function grabs an image offscreen and moves it horizontally from the left to the center of the page. I'd like to create a function that does the opposite after 20 seconds. The "after 20 seconds" part is giving me the most grief. If you could show me what a new function would look like or an 'else' addition to the current function that would be great. Thanks.
<script language="JavaScript" type="text/JavaScript">
var x = -500;
var y = 100;
function hor(val) {
if (x <= 500){
x = x + val;
document.getElementById("pos").style.left = x + "px";
setTimeout("hor(5)", 10);
}
}
</script>
<style type="text/css">
<!--
#pos {
position: absolute;
left: -500px;
top: 100px;
z-index: 0;
}
</style>
<body onLoad="setTimeout('hor(5)',5000)">
<div id="pos">
<img src="image.jpg">
</div>
Perhaps you could try changing the script to this:
// Define variables
var x = -500,
y = 100,
direction = 1;
// Function which moves "pos" element
function hor(val) {
// Move by specified value multiplied by direction
x += val * direction;
if(x > 500){
x = 500;
// Reverse direction
direction = -1;
} else if(x < -500){
x = -500;
// Reverse direction, once again
direction = 1;
}
// Move element
document.getElementById("pos").style.left = x + "px";
// Continue loop
setTimeout("hor("+val+")", 10);
}
This code will continue moving the pos element by the specified value until x greater than 500, at which point it will switch direction, then continue until x reaches -500, and so on.
EDIT:
This code will fix that issue with 20 seconds (I had thought that the 500 pixel thing computed to 20 seconds, lol).
// Define variables
var x = -500,
y = 100,
direction = 1;
firstCall = true;
timeElapsed = 0;
// Function which moves "pos" element
function hor(val) {
// Don't let the first call count!
if(!firstCall)timeElapsed += 10;
else firstCall = false;
if(timeElapsed >= 2000){
// Reverse direction
direction *= -1;
timeElapsed = 0;
}
// Move by specified value multiplied by direction
x += val * direction;
// Move element
document.getElementById("pos").style.left = x + "px";
// Continue loop
setTimeout("hor("+val+")", 10);
}
Try this. Here the img is moved horizontally and after sometime it is reverted back to its original position.
<script>
var x = -500;
var y = 100;
var op;
function hor(val) {
if (x <= 500 && x>=-500) {
x = x + val;
document.getElementById("pos").style.left = x + "px";
setTimeout(function(){hor(val);},10);
}
}
$(document).ready(function(){
setTimeout(function(){hor(5);},1000);
setInterval(function(){
setTimeout(function(){hor(-5);},1000);
},2000);
});
</script>
I have changed the timings for testing purpose only, you can change it back.
Related
I'm working on my Javascript project.
In this project I have to create some animations.
In this specific case, I have to make a ball bounce up and down.
The code below works great just from the top to the bottom, but not viceversa.
var div = document.getElementById('container-ball');
function createBall(event)
{
var x = event.clientX;
var y = event.clientY;
var newBall = document.createElement('div');
newBall.style.position = "absolute"
newBall.style.width = '15px';
newBall.style.height = '15px';
var bx = newBall.style.left = x + 'px';
var by = newBall.style.top = y + 'px';
newBall.style.borderRadius = '10px';
newBall.style.backgroundColor = 'white';
var incrementPos = 0;
var id = setInterval(bounce, 5);
function bounce()
{
incrementPos++;
by = newBall.style.top = incrementPos + y + "px";
if(by == 650 + "px")
{
clearInterval(id)
var id2 = setInterval(function bounceUp()
{
incrementPosYMax -= 650
by = newBall.style.bottom = by + "px" - incrementPosYMax
}, 5)
}`/*Function that make the ball bounce down and up(but when it came at 650 px it stopped )*/ì
} /*End of the set interval */`
div.appendChild(newBall);
}
div.addEventListener("click", createBall);
This down below is the HTML CODE
<html>
<head>
<link rel= "stylesheet" href="style/style.css">
</head>
<body>
<div id ="container-ball">
</div>
<script src="js/main.js"></script>
</body>
Working example (comments see below):
const areaHeight = 150; // it is 650px in the original question
var div = document.getElementById('container-ball');
function createBall(event) {
var x = event.clientX;
var y = event.clientY;
var newBall = document.createElement('div');
newBall.className = 'ball';
var bx = newBall.style.left = x + 'px';
var by = newBall.style.top = y + 'px';
var incrementPos = 0;
var id = setInterval(bounce, 5);
let direction = 1; // 1 = down, -1 = up
function bounce() {
incrementPos += direction;
by = newBall.style.top = incrementPos + y + "px";
if (by == areaHeight + "px" || by == y + 'px') {
direction = -direction;
}
}
div.appendChild(newBall);
}
#container-ball {
width: 300px;
height: 157px;
background: gray;
}
#container-ball .ball {
position: absolute;
width: 15px;
height: 15px;
border-radius: 10px;
background-color: white;
border: 1px solid #333;
box-sizing: border-box;
}
<div id="container-ball" onclick="createBall(event)"></div>
Click on the grey box
Now, the explanation.
I've moved ball's styles to CSS - this is easier to control in the future. So when I have a class for ball, I can write in my code: newBall.className = 'ball';
I removed incrementPosYMax because I do not really understand if you need it
I understand your 'bounce' as bounce, so my ball just fall to the floor and then return to the original position. I do not really understand if you mean that (please, comment if it is wrong).
Your program is quite small, so I do not see the need for another setInterval, so all the animation in my example is inside only one setInterval
I've added new variable direction to control the direction for the ball (1 = down, -1 = up)
I do not like the parts with by == areaHeight + "px", but I keep them for you, because you use it in your code.
This code have some bugs, that you (or me if you ask) can fix. I just need to understand that my approach is correct
How the direction works:
Take a look at this line by = newBall.style.top = incrementPos + y + "px"; here you set new "y" coordinate for the ball as sum of 'original' "y" coordinate (in y) and offset (the distance that ball moved over the time) in incrementPos. So, if you increase incrementPos, then the ball's position will be lower (because "zero" in browser is at the top left corner, bigger "y" means lower the element).
Before my change, in your code you changed the offset with this line: incrementPos++; (means you increase incrementPos by 1 on every bounce step).
To move to another direction, you need to subtract 1 on every bounce step.
To reflect the "direction" of that move, I've added direction variable (so 1 means move down, and -1 means move up)
Now the offset is changed by: incrementPos += direction; (so I add this direction, not always 1)
Sometimes we need to change the "direction" with this code: direction = -direction;
The "levels" where we need to change direction is checked by this code: if (by == areaHeight + "px" || by == y + 'px') - here we check bottom (areaHeight) and top (y - it is where user clicks the mouse)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Hi there
so i'm trying to create a bouncing ball using javascript and i need some help finishing it without using any complicated code
this is the code that i have done:
https://codepen.io/messili-islem/pen/XWrjOja
i appreciate your help guys
Thanks
var ball = document.getElementById('ball')
var ballObj = { x: 0, y: 0, dx: 1, dy: 1, size: 100 }
var x = 0
var y = 0
function movement () {
var id = setInterval(moveball, 1)
function moveball () {
function downleft () {
x++
y++
ball.style.top = x + 'px'
ball.style.left = y + 'px'
}
function upright () {
x--
y--
ball.style.top = x + 'px'
ball.style.left = y + 'px'
}
function downright () {
x++
y--
ball.style.top = x + 'px'
ball.style.left = y + 'px'
}
function upleft () {
x--
y++
ball.style.top = x + 'px'
ball.style.left = y + 'px'
}
downleft()
if (x == 400) {
clearInterval(id)
var id2 = setInterval(upleft, 1)
}
}
}
That's a starter code
I use requestAnimationFrame instead of setInterval for time based calculations
I use transform style instead of top and left for better performance
I encapsulated all the code into an anonymous function to prevent global namespace pollution
I used EventListener instead of onclick on button
"use strict";
// This is a self-invoking anonymous function
// It's used to encapsulate the inner variables
// and functions in order for the global namespace
// to not be polluted and to avoid naming conflicts
// See: https://stackoverflow.com/questions/592396/what-is-the-purpose-of-a-self-executing-function-in-javascript
// See: https://idiallo.com/javascript/self-invoking-anonymous-function
(function() {
var ball = document.getElementById("ball");
var container = document.getElementById("container");
var btn = document.getElementById("btn");
// some factor to scale the speed of the ball
var factor = 1 / 5;
var timeOld, timeElapsed;
// the current x position of the ball
var x = 0;
var y = 0;
var step = 1;
// the direction in the x dimension (1 or -1)
var dx = step;
var dy = step;
var width = ball.offsetWidth;
var height = ball.offsetHeight;
var cH = container.offsetHeight;
var cW = container.offsetWidth;
function movement() {
// use requestAnimationFrame in favor of setInterval/setTimeout
// See: https://css-tricks.com/using-requestanimationframe/
requestAnimationFrame(moveball);
// check the balls position and set the direction if out of bounds
function checkBall() {
if (x + width >= cW) dx = -step;
if (x <= 0) dx = step;
if (y + height >= cH) dy = -step;
if (y <= 0) dy = step;
}
// move the ball by (dx,dy)
function moveball(timestamp) {
// measure the time elapsed since
// last call to moveball function
if (!timeOld) timeOld = timestamp;
timeElapsed = timestamp - timeOld;
timeOld = timestamp;
// calculate ball's position based on
// movement's direction and time elapsed
x += dx * timeElapsed * factor;
y += dy * timeElapsed * factor;
// use CSS transform instead of top and left
// for performance reasons
// See: https://www.keycdn.com/blog/animation-performance#there-are-three-main-types-of-css-properties
ball.style.transform = "translate(" + x + "px, " + y + "px)";
checkBall();
// call requestAnimationFrame again
// like you would do with
// setTimeout
requestAnimationFrame(moveball);
}
}
btn.addEventListener('click', movement)
})();
#container {
width: 450px;
height: 300px;
position: relative;
border: 1px solid black;
margin: auto;
}
#ball {
border-radius: 100px;
width: 100px;
height: 100px;
position: absolute;
background-image: radial-gradient(farthest-side at 30px 30px, red, black 125%);
}
<p><button id="btn" >movement()</button></p>
<div id="container">
<div id="ball"></div>
</div>
I adapted this code to create a large div which scrolls horizontally inside a smaller div, depending on the position of the mouse.
You can see my example here.. http://thetally.efinancialnews.com/tallyassets/20years/index.html
What I am trying to achieve is for the inner (yellow) div to stop at a maximum of left:0px, in other words the far left of the yellow div will become stuck to the far left of the outer div if you go that far.
I tried to implement this with an 'if else' statement, however as this piece of code gets run every 30th of a second it creates a strange result, which I can't find a solution for. I'm sure its very simple but its stumped me
You can see my code here...
var x=0,
rate=0,
maxspeed=10;
var backdrop = $('.container');
var years = $('.events');
$('.direction', backdrop).mousemove(function(e){
var $this = $(this);
var left = $this.is('.left');
if (left){
var w = $this.width();
rate = (w - e.pageX - $(this).offset().left + 1)/w;
} else {
var w = $this.width();
rate = -(e.pageX - $(this).offset().left + 1)/w;
}
});
backdrop.hover(function(){
var scroller = setInterval( moveBackdrop, 30 );
$(this).data('scroller', scroller);
},
function(){
var scroller = $(this).data('scroller');
clearInterval( scroller );
});
function moveBackdrop(){
if ( parseInt(years.css("left"), 10) <= 0 ) {
x += maxspeed * rate;
var newpos = x+'px';
years.css('left',newpos);
} else {
years.css('left','0');
}
}
The code in question is right here at the end^
Is this what you were trying to do?
function moveBackdrop(){
if ( parseInt(years.css("left"), 10) <= 0 && rate < 0 ) {
// Means that the element is already at left: 0 or less,
// and we are trying to move it even more left with rate being negative.
// So keep the element at left: 0
years.css('left','0');
} else {
x += maxspeed * rate;
var newpos = x+'px';
years.css('left',newpos);
}
}
Extra note for future: parseInt uses base 10 by default :) so parseInt("20px") will equal 20
Final Edit: Ah there is an even better way to do it.
function moveBackdrop(){
x += maxspeed * rate;
if( x < 0 ) x = 0; // If left less than 0, fix it at 0
var newpos = x+'px';
years.css('left',newpos);
}
I have written a function that when invoked, will scroll the page downwards in a smooth fashion.
The problem is that the amount scrolled is not precise. It can be off by one pixel or so depending on the distance scrolled and the duration of the scroll.
Is there a better way to do this such that the scroll can move the exact number of desired pixels?
const EASING = BezierEasing(0, .1, .1, 1); // Example values.
const DURATION = 1000; // ms.
document.addEventListener('DOMContentLoaded',
() => {
document.querySelector('#foo')
.addEventListener('click', onClick, false);
});
function onClick(e) {
scroll(400); // px.
e.preventDefault();
return false;
}
function scroll(distance) {
var start, travelled, html;
start = performance.now();
travelled = 0;
html = document.querySelector('html');
(function move(now) {
var fractionDone, dy, toMove;
fractionDone = (now-start) / DURATION;
if((1 - fractionDone) <= 0) {
return; // Done!
}
if(window.scrollY + window.innerHeight
=== html.offsetHeight) {
return; // At bottom of page.
}
dy = ((EASING.get(fractionDone)) * distance);
toMove = Math.floor((dy - travelled)); // `scrollBy` only accepts integers.
if(toMove > 0) {
window.scrollBy(0, toMove);
travelled += toMove;
}
requestAnimationFrame(move);
}(start));
}
<!DOCTYPE html>
<html>
<head>
<script src="https://rawgit.com/gre/bezier-easing/master/build.js"></script>
</head>
<body>
<a href id="foo">Click Me!</a>
<script>
/* print some numbers to
the DOM to help visualize
the scrolling */
var body = document.querySelector('body');
for(var x = 0; x < 50; x++) {
var div = document.createElement("div");
var text = document.createTextNode(x);
div.appendChild(text);
body.appendChild(div);
}
</script>
</body>
</html>
could you do something like this to account for the last iteration?
basically if toMove gets rounded down to 0, but distance hasnt been travelled yet, force it to do scroll one more?
if(toMove > 0 || (toMove == 0 && travelled != distance) {
window.scrollBy(0, (toMove ? toMove : 1));
travelled += toMove;
}
I decided to modify the done logic to move any remaining distance:
// ...
if((1 - fractionDone) <= 0) {
window.scrollBy(0, (distance - travelled)); // Scroll any remaining distance.
return; // Done!
}
// ...
Which, I think, solves the issue.
I have moved the image left to right successfully. But when I tried to move image from right to left then also image moves towards right.actually the value of x in not decreasing.x=x-step doesn't decreases value of x. Help will be appreciated.
<script>
function disp(){
var step=1; // Change this step value
var y=document.getElementById('i1').offsetTop;
var x=document.getElementById('i1').offsetLeft;
if(x <= 550 && y<=500 && y>=0 && x>=0)
{
x=x-step;
document.getElementById('i1').style.left= x + "px"; // horizontal movment
}
}
function timer(){
disp();
var y=document.getElementById('i1').offsetTop;
var x=document.getElementById('i1').offsetLeft;
my_time=setTimeout('timer()',100);
}
</script>
<img src=image2.jpg id='i1' style="height:20px;width:20px;position:relative;left:300px;top:300px;">
Change your step to 10 and you will see it move left by 2px, set the step to 6 and you will see it move right by 2px. this is becuase there is a difference between the offsetleft and left by 8px, causing the funny behavior
You can subtract the diff like so: var x=document.getElementById('i1').offsetLeft - 8; (or calculate the difference), flip the x=x-step; to x=x+step; and it will move the opposite direction
<html>
<meta charset="utf-8" />
<img src='image2.jpg' id='i1' style="height:20px;width:20px;position:relative;left:300px;top:300px;" />
<script>
function disp(){
var step=1; // Change this step value
var y=document.getElementById('i1').offsetTop;
var x=x=document.getElementById('i1').offsetLeft - 8;
if(x <= 550 && y <=500 && y>=0 && x>=0)
{
x=x-step;
document.getElementById('i1').style.left = x + "px";
}
}
function timer(){
disp();
var y=document.getElementById('i1').offsetTop;
var x=document.getElementById('i1').offsetLeft;
my_time=setTimeout('timer()',100);
}
timer();
</script>
</html>
Check out this fiddle please
function disp(){
var step;
var y=document.getElementById('i1').offsetTop;
var x=document.getElementById('i1').offsetLeft;
if (x>1000){
clearTimeout(my_time);
}
if (x>=400){
dir = "left";
} else if (x<0){
dir = "right";
}
if(dir == "left")
{
step = -10;
} else {
step = 10;
}
x = x + step;
document.getElementById('i1').style.left= x + "px"; // horizontal movment
}
function tmr(){
disp();
my_time=setTimeout(function(){ tmr(); } ,100);
}
var my_time;
var dir = "right";
tmr();