Using html and javascript, i create variables in js to corrospond to the buttons i made in html, they are to make an image move left, right, up, and down.
the image move left and right just fine but i can't seem to get it to move up or down. i thought it should work similary to moving it left and right but it doesnt seem to work.
here is the code i have
leftButton.addEventListener("click", moveLeft);
rightButton.addEventListener("click", moveRight);
downButton.addEventListener("click", moveDown);
rocketPicture.style.position = "relative";
rocketPicture.style.left = '0px';
function moveLeft(){
rocketPicture.style.left = parseInt(rocketPicture.style.left ) - 10 + 'px';
}
function moveRight(){
rocketPicture.style.left = parseInt(rocketPicture.style.left ) + 10 + 'px';
}
function moveDown(){
rocketPicture.style.top = parseInt(rocketPicture.style.top) + 10 + 'px';
You have assigned an initial value - 0 - for style.left, but not for style.top, hence checking its value gives undefined.
Now, parseInt(undefined) returns NaN, and doing anything mathematical with NaN just puts more NaN in this world.
Solution: assign an initial value for style.top in the same way you did for style.left.
As a sidenote, it might be worthwhile to unify all those move functions in the same step func, like this:
function move(dir, delta) {
const prev = parseInt( rocketPicture.style[dir] );
// assert !Number.isNaN(prev)
rocketPicture.style[dir] = prev + delta + 'px';
}
function moveUp() { move('top', -10) }
function moveDown() { move('top', 10) }
function moveLeft() { move('left', -10) }
function moveRight() { move('left', 10) }
Why not use Element#getBoundingClientRect ? It provides information regarding your element including its top and left position without having to convert the values with parseInt.
It looks something like this:
{
"x": 50,
"y": 100,
"width": 124,
"height": 119.19999694824219,
"top": 100,
"right": 174,
"bottom": 219.1999969482422,
"left": 50
}
Working solution:
const box = document.getElementById("item");
function vertical(value){
const {top} = box.getBoundingClientRect();
box.style.top = `${top + value}px`;
}
function horizontal(value){
const {left} = box.getBoundingClientRect();
box.style.left = `${left + value}px`;
}
#item {
padding: 50px;
position: absolute;
background-color: purple;
color: white;
left: 50px;
top: 100px;
}
<div id="item">
box
</div>
<button onclick="vertical(-10)">Up</button>
<button onclick="vertical(10)">Down</button>
<button onclick="horizontal(-10)">Left</button>
<button onclick="horizontal(10)">Right</button>
Related
var circle = document.getElementById("circle");
function moveUp() {
var top = circle.offsetTop;
newTop = top - 10;
circle.style.top = newTop + "px";
console.log("moveUP Called")
}
function moveDown() {
var top = circle.offsetTop;
newTop = top + 10;
circle.style.top = newTop + "px";
console.log("moveDown Called")
}
function moveLeft() {
var left = circle.offsetLeft;
newLeft = left - 10;
circle.style.left = newLeft + "px";
console.log("moveLeft Called")
}
function moveRight() {
var left = circle.offsetLeft;
newLeft = left + 10;
circle.style.left = newLeft + "px";
console.log("moveRight Called")
}
window.addEventListener("keypress", (event) => {
if (event.key == 'w') {
moveUp();
} else if (event.key == 's') {
moveDown();
} else if (event.key == 'a') {
moveLeft();
} else if (event.key == 'd') {
moveRight();
}
})
body {
margin: 2px;
background-color: aquamarine;
}
#circle {
height: 100px;
width: 100px;
background-color: blue;
border-radius: 50%;
position: absolute;
}
In the above code where on key press circle moves, for example on 'w' it moves up, for 's' it moves down and so on.
But the problem is that the circle even moves out of the window, how do I fix it and what is the problem??
var circle = document.getElementById("circle");
console.log(window.innerWidth, window.innerHeight)
function moveUp() {
var top = circle.offsetTop;
console.log(top)
newTop = top - 10;
if(newTop < 0) {
newTop = 0;
}
circle.style.top = newTop + "px";
}
function moveDown() {
var top = circle.offsetTop;
var height = circle.offsetHeight + top;
if((height + 10) >= window.innerHeight) {
return;
}
newTop = top + 10;
circle.style.top = newTop + "px";
/* console.log("moveDown Called") */
}
function moveLeft() {
var left = circle.offsetLeft;
newLeft = left - 10;
if(newLeft<0) {
newLeft = 0;
}
circle.style.left = newLeft + "px";
}
function moveRight() {
var left = circle.offsetLeft;
newLeft = left + 10;
if(newLeft > window.innerWidth - 100 ) {
newLeft = window.innerWidth - 100 ;
}
circle.style.left = newLeft + "px";
}
window.addEventListener("keypress", (event) => {
if (event.key == 'w') {
moveUp();
} else if (event.key == 's') {
moveDown();
} else if (event.key == 'a') {
moveLeft();
} else if (event.key == 'd') {
moveRight();
}
})
body{
margin:2px;
background-color: aquamarine;
}
#circle{
height: 100px;
width: 100px;
background-color: blue;
border-radius: 50%;
position: absolute;
overflow: hidden;
}
<div id="circle">
</div>
Explaination
for moveup() if the position is a negative number that means the div is going out of the viewport. So with the if condition new position will be always set to 0 preventing the div to go negative position.
for moveDown() first you get the offsetTop which means how far is the box from top position along with the offsetHeight which represents the height of the box. So add these two to get the total height. Now simply check if this height is going over the innerHeight + the distance(10) you are going with each move. If it is more than the innerHeight simply return. otherwise move the box.
moveLeft() is same as moveUp().
moveRight() is also same as moveDown() but here we're calculating the innerWidth. Subtract it with the box width so it doesn't go outside the viewport. Now simple condition check and set the new right position.
hope it helped
What is the problem?
There is no problem. CSS does exactly what you told it to do.
For example, you can click on 'w' couple of times, which will set left property for your absolutely positioned circle to, let's say, -160px. This will instruct the browser to move your element to the left, away from the viewport, i.e. to position it -160px of the left edge of the initial containing block or nearest positioned ancestor. More about left property: https://developer.mozilla.org/en-US/docs/Web/CSS/left
I would not say that it is a problem, because it is exactly what left is used for - move elements to whatever position you like. Sometimes you can hide elements by setting their position: absolute; left: -10000px;
How do I fix it?
If you don't want your circle to move away from the viewport, you need to check if your circle is 'touching' the viewport. I will use example with the left, but the same logic can be applied to top, right and bottom.
So for the left, this will consist of two parts:
Check what is the initial distance from your circle to the left edge of the viewport.
Check if absolute value of your new left value is not greater than this distance.
For example, for the left method:
var elDistanceToLeft = window.pageXOffset + circle.getBoundingClientRect().left;
function moveLeft() {
let left = circle.offsetLeft;
newLeft = Math.abs(left - 10) <= elDistanceToLeft ? left - 10 : -elDistanceToLeft;
circle.style.left = newLeft + "px";
}
In this case your circle will move all way to the left (on pressing 'a') until it 'touches' the viewport (screen). Then it will stop.
Here is a code snippet
var elDistanceToLeft = window.pageXOffset + circle.getBoundingClientRect().left
function moveLeft() {
let left = circle.offsetLeft;
newLeft = Math.abs(left - 10) <= elDistanceToLeft ? left - 10 : -elDistanceToLeft;
circle.style.left = newLeft + "px";
}
window.addEventListener("keypress", (ev) => { if (ev.key == 'a') { moveLeft();} })
#circle {
height: 100px;
width: 100px;
background-color: blue;
border-radius: 50%;
position: absolute;
}
#parent {
position: relative;
padding: 200px;
}
<div id="parent">
<div id="circle"></div>
</div>
I'm a beginner JavaScript user. I am making a board game using mostly JavaScript. I am having a hard time making my pawn go down after passing left: 400px. My pawn will automatically
goes to left: 0px then move down; even after I set it to left: 400px.
dicedir = "diceimage/"
let x_pos = 100;
let y_pos = 100;
sum = 0;
// My roll() will starts when the button is clicked on
document.getElementById("rollButton").addEventListener("click", roll)
function roll() {
//dice portion of the function
randomNumber = Math.ceil(Math.random() * 6)
console.log(randomNumber)
rollthedice = dicedir + "dice" + randomNumber + ".png"
console.log(rollthedice)
document.getElementById("dice").src = rollthedice
//end of the dice portion of the function
// pawn postioning
blackpawn = document.getElementById("pawn")
//pawn moving right
moveright = [5, 10, 15, 20, 25, 30]
x_pos += moveright[randomNumber - 1]
leftrightpos = x_pos + "px"
console.log(leftrightpos)
blackpawn.style = "left: " + leftrightpos
//pawn moving down when its cross left: 400px
if (leftrightpos > 400 + "px") {
blackpawn.style.position = "relative"
blackpawn.style.left = "400px";
y_pos += moveright[0]
upBottompos = y_pos + "px"
console.log(upBottompos)
blackpawn.style = "top: " + upBottompos
}
}
These lines:
blackpawn.style = "left: " + leftrightpos
blackpawn.style = "top: " + upBottompos
Replace all existing styles with the style you specify. In other words, the first one doesn't say "add a left style" ... it says "remove all other styled, then add a left style".
I suspect this is related to your problem. You should instead use the style (no pun intended) for setting style that you used elsewhere, eg.
blackpawn.style.left = "400px";
Or, in other words, those two lines should become:
blackpawn.style.left = leftrightpos
blackpawn.style.top = upBottompos
I have a task to make animation with JavaScript.
Basically I have two squares (red and yellow) and a two buttons (button 1 and button 2).
When I click on button1 the red square goes from the (top-left corner) to the (bottom-right corner).
I need to make another button (button2) such that when I click on it I need the red square to go back to the beginning.
I need it to do the opposite move (moving from the bottom-right corner to the top-left corner).
What changes should I do in the second function?
here is the code
function myMove1() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myMove2() {
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
I'm going to assume the teacher is trying to teach basic javascript, and tell you how I'd solve this with the parts you've provided.
That said, your commenters are correct, requestAnimationFrame is the right tool here. Also, the 5 ms delay on your interval is really short (125fps). If you made this number, I'd suggest changing it to 16, which is roughly 60fps.
// We want each function to be able to see these vars.
var pos = 0;
// Either -1, 0, or 1, depending on if were moving forward, backwards or
// stopped.
var direction = 0;
// This var now serves dual purpose, either its a number which is the
// interval id or its falsy, which we can use to understand the animation
// has stopped.
var id = null;
// Doing this here, will save the browser from having to redo this step on
// each frame.
var elem = document.getElementById("animate");
// Render the elem to the correct starting location.
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
// A single animation function.
function frame() {
// Assume we are heading for 350.
var goal = 350
if (direction < 0) {
// unless the goal is -1, when the goal is zero.
goal = 0
}
if (pos != goal) {
pos += direction;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
} else {
// Reset all the shared vars.
direction = 0;
clearInterval(id);
id = null;
}
}
function myMove1() {
if (id) {
clearInterval(id)
}
direction = 1;
id = setInterval(frame, 5);
}
function myMove2() {
if (id) {
clearInterval(id)
}
direction = -1;
id = setInterval(frame, 5);
}
#animate {
position: absolute;
width: 10px;
height: 10px;
background-color: red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
</body>
</html>
What you're asking is straightforward: take the function you already wrote and change the increment direction on pos. The only difference is you'll need to keep track of x and y coordinates separately since they move in opposite directions. I used this object initialized to the start position of the box:
pos = {x: 350, y: 0};
function myMove1() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myMove2() {
var elem = document.getElementById("animate");
var pos = {x: 350, y: 0};
var id = setInterval(frame, 5);
function frame() {
if (pos.y >= 350 || pos.x <= 0) {
clearInterval(id);
} else {
pos.x--;
pos.y++;
elem.style.top = pos.y + 'px';
elem.style.left = pos.x + 'px';
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
However, these functions aren't reusable without parameters; this code is WET (wrote everything twice). The animation is brittle because each click creates a new timeout (you can spam the buttons and watch it crumble). Entities in the animation have no state. If you want to change the position or add another box, you have to we-write and duplicate all of your code again.
With that in mind, here's a sketch to illustrate a somewhat improved version as food for thought. The functions and objects are more general and don't need to be re-written for new movements you decide to add. The Box class keeps track of entity state over time. requestAnimationFrame() is used to update and draw all entities on the screen at once, avoiding the many problems with setTimeout.
const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1;
const dist = (a, b) => ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5;
class Box {
constructor(elem, pos, size, color, speed) {
this.elem = elem;
this.speed = speed;
this.from = this.to = this.pos = pos;
this.t = 0;
this.elem.style.position = "absolute";
this.elem.style.background = color;
this.elem.style.height = `${size}px`;
this.elem.style.width = `${size}px`;
this.elem.style.top = `${this.pos.y}px`;
this.elem.style.left = `${this.pos.x}px`;
}
move(to) {
this.from = {x: this.pos.x, y: this.pos.y};
this.to = {x: to.x, y: to.y};
this.t = 0;
}
update() {
if (dist(this.pos, this.to) > 1) {
this.pos.x = lerp(this.from.x, this.to.x, this.t);
this.pos.y = lerp(this.from.y, this.to.y, this.t);
this.elem.style.top = `${this.pos.y}px`;
this.elem.style.left = `${this.pos.x}px`;
this.t += this.speed;
}
}
}
const data = [
{color: "red", pos: {x: 0, y: 0}, size: 10},
{color: "yellow", pos: {x: 350, y: 0}, size: 10},
];
const elems = document.getElementsByClassName("box");
const boxes = [];
for (let i = 0; i < elems.length; i++) {
boxes.push(new Box(elems[i], data[i].pos, data[i].size, data[i].color, 0.01));
}
function myMove1() {
boxes[0].move({x: 350, y: 350});
boxes[1].move({x: 0, y: 350});
}
function myMove2() {
boxes[0].move({x: 0, y: 0});
boxes[1].move({x: 350, y: 0});
}
(function render() {
boxes.forEach(e => e.update());
requestAnimationFrame(render);
})();
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div class="box"></div>
<div class="box"></div>
</div>
Lastly, consider using CSS animations, JS canvas or an animation framework to do this sort of task; these tools will abstract away a lot of the math and state representation that animations involve.
A previous QUESTION I had has led me to construct the code below. What Im trying to do is increment the element up/down/left/right based on keyboard arrow selection
"<div id="test"></div>"
by 20 pixels (or however many I chose) at a time. I have the "left" and "right" direction working for the most part but something interesting keeps happening when I try and change directions. First off whichever direction I initially chose to go first does not work on the first key press, I have to hit the arrow key of either left or right twice to start transitioning. Then once the transitions do start working; if im traveling left and then want to change direction to the right; it goes left even though im hitting the right key at least once before it goes the correct direction corresponding to the key I chose. This is a bit difficult to explain by text so here is the code pen so you can see what I mean. CODEPEN (hit the left and right arrow keys a couple times so clearly see the issue)
Also the functions moveDown() and moveUp() dont even move the box positioning at all. To try and trouble shoot the problem I added console.log('moveUp') and console.log('moveDown') in order to see whether the console was recognizing the key code when I struck it, and it clearly does. It even recognizes when I strike the left or right key but still runs the incorrect direction at-least once before it starts going the correct direction on the left and right keys.
I have a feeling it make have to do with transitions not being cleared or maybe using an IF statement might not be the base way to read the key code?
Also thought about using switch case for JavaScript key code recognition but I am pretty sure the issue would still be the same and im not skilled enough to pull off switchcase yet.
ALL I WANT is the box to go the direction I tell it to go using the arrows on my keypad, I am close but as you can see I am missing some key concepts
document.addEventListener("keydown", keyBoardInput);
var left = 0;
var top = 0;
function moveUp() {
console.log('moveUp');
document.getElementById("test").style.top = top + "px";
top -= 20;
document.getElementById("test").style.transition = "all 1s";
};
function moveDown() {
console.log('moveDown');
document.getElementById("test").style.top = top + "px";
top += 20;
document.getElementById("test").style.transition = "all 1s";
};
function moveLeft() {
console.log('moveLeft');
document.getElementById("test").style.left = left + "px";
left -= 20;
document.getElementById("test").style.transition = "all 1s";
};
function moveRight() {
console.log('moveRight');
document.getElementById("test").style.left = left + "px";
left += 20;
document.getElementById("test").style.transition = "all 1s";
};
function keyBoardInput() {
var i = event.keyCode;
if (i == 38) {
moveUp()
};
if (i == 40) {
moveDown()
};
if (i == 37) {
moveLeft()
};
if (i == 39) {
moveRight()
};
};
#test {
position: relative;
width: 30px;
border: 1px solid blue;
height: 10px;
top: 0px;
left: 0px;
}
<div id="test"></div>
2 issues: You updated your globals too late, just do it before you use it on the element. And the variable name "top" is reserved, just use another one (see this blog post). Here the code:
document.addEventListener("keydown", keyBoardInput);
var left = 0;
var topx = 0;
function moveUp() {
console.log('moveUp');
topx -= 20;
document.getElementById("test").style.top = topx + "px";
document.getElementById("test").style.transition = "all 1s";
};
function moveDown() {
console.log('moveDown');
topx += 20;
document.getElementById("test").style.top = topx + "px";
document.getElementById("test").style.transition = "all 1s";
};
function moveLeft() {
console.log('moveLeft');
left -= 20;
document.getElementById("test").style.left = left + "px";
document.getElementById("test").style.transition = "all 1s";
};
function moveRight() {
console.log('moveRight');
left += 20;
document.getElementById("test").style.left = left + "px";
document.getElementById("test").style.transition = "all 1s";
};
function keyBoardInput() {
var i = event.keyCode;
if (i == 38) {
moveUp()
};
if (i == 40) {
moveDown()
};
if (i == 37) {
moveLeft()
};
if (i == 39) {
moveRight()
};
};
#test {
position: relative;
width: 30px;
border: 1px solid blue;
height: 10px;
top: 0px;
left: 0px;
}
<div id="test"></div>
You need to do the arithmetic for top and left before setting it in the CSS :)
function moveUp() {
console.log('moveUp');
top -= 20;
document.getElementById("test").style.top = top + "px";
document.getElementById("test").style.transition = "all 1s";
};
function moveDown() {
console.log('moveDown');
top += 20;
document.getElementById("test").style.top = top + "px";
document.getElementById("test").style.transition = "all 1s";
};
function moveLeft() {
console.log('moveLeft');
left -= 20;
document.getElementById("test").style.left = left + "px";
document.getElementById("test").style.transition = "all 1s";
};
function moveRight() {
console.log('moveRight');
left += 20;
document.getElementById("test").style.left = left + "px";
document.getElementById("test").style.transition = "all 1s";
};
Here's a working fiddle: https://jsfiddle.net/x2yxexs9/
I have a code which causes the waterlevel in a bottle to go up or down by clicking a button. however, it can't stop without clicking on stop. I need it to basically reset when it empties, and that the div of the waterlevel doesn't go below a certain point (or above a certain point). If you're interested in what I'm making; I'm making an alcohol simulator. So you'll basically see the waterlevel of an alcohol drink going down (i.e. 100 px), and 100 px down means that you can see the waterlevel(alcogol level) in the stomach with i.e. 50 px, and that equals 20 px in the blood circulation and 10 px in the brains. (just to get an idea.)
But if I click on the button of going down, the div will just leave the bottle and will have an endless journey. (js please, not jquery)
here's my JS code:
function move_img(str) {
var step=2 ; // change this to different step value
switch(str){
case "down":
var x=document.getElementById('i1').offsetTop;
x= x + step;
document.getElementById('i1').style.top= x - 1 + "px";
break;
case "up":
var x=document.getElementById('i1').offsetTop;
x= x -step;
document.getElementById('i1').style.top= x + "px";
break;
case "left":
var y=document.getElementById('i1').offsetLeft;
y= y - step;
document.getElementById('i1').style.left= y + "px";
break;
case "right":
var y=document.getElementById('i1').offsetLeft;
y= y + step;
document.getElementById('i1').style.left= y + "px";
break;
}
}
function auto(str) {
myVar = setInterval(function(){ move_img(str); }, 2) ;
}
setTimeout(function( ) { clearInterval( myVar ); }, 1);
function nana(){
}
Your fiddle doesn't work. You'll need to specify the height as well as the top attribute, and I believe top has to be above bottom. I've made an example here. The changes to your examples are:
//javascript
if (str == 'up' || str == 'down') {
var top = el.offsetTop;
var height = el.offsetHeight; //get height to modify
console.log(height);
if (str == 'up') {
top -= step;
height += step; //adjust height
} else {
top += step;
height -=step; //adjust height
}
if (top_max >= top && top >= 0) { //make sure #i1 is inside #i
document.getElementById('i1').style.top = top + "px";
document.getElementById('i1').style.height = height + "px"; //modify height
} else {
clearInterval(myVar)
}
//css
#i1 {
width: 100px;
display: inline-block;
background:red;
position: absolute;
top: 150px; //initial top
bottom: 250px; //as as bottom of #i
height:100px; //initial height
}