Move an element with arrow keys - javascript

function docReady()
{
image = document.getElementById("someImage");
window.addEventListener("keydown", moveImage);
}
function moveImage(e)
{
if (e.keyCode == 37)
image.style.left = parseInt(image.style.left) - 5 + 'px';
if (e.keyCode == 38)
image.style.top = parseInt(image.style.top) - 5 + 'px';
if (e.keyCode == 39)
image.style.left = parseInt(image.style.left) + 5 + 'px';
if (e.keyCode == 40)
image.style.top = parseInt(image.style.top) + 5 + 'px';
console.log(image.style.left + ', ' + image.style.top);
}
So the code above is supposed to move an image around. However, it doesn't. The console returns blanks for image.style.left and image.style.top. Could you help me with fixing it?
P.S. If you would be so kind, can you also make it so that if the image is on the screen borders it will stop moving? Thank you so much!

You are missing some steps indeed.
To be precise, you should:
create the variable image outside the function (i.e., declare it global)
set the initial values of top, left
set the position of your element to absolute. Default is static and it doesn't support moving/styling with top/left/right/bottom.
call the whole thing on page load
And here's what you get once you follow the above steps:
window.onload = docReady;
var image;
function docReady() {
image = document.getElementById("someImage");
window.addEventListener("keydown", moveImage);
image.style.left = 0;
image.style.top = 0;
}
function moveImage(e) {
if (e.keyCode == 37)
image.style.left = parseInt(image.style.left) - 5 + 'px';
if (e.keyCode == 38)
image.style.top = parseInt(image.style.top) - 5 + 'px';
if (e.keyCode == 39)
image.style.left = parseInt(image.style.left) + 5 + 'px';
if (e.keyCode == 40)
image.style.top = parseInt(image.style.top) + 5 + 'px';
console.log(image.style.left + ', ' + image.style.top);
}
#someImage{
position:absolute;
}
<div id = "someImage"> not an image but a test </div>
(For the simplicity I'm using a plain text element instead of image, but that doesn't matter)

Related

Using CSS transforms to translate/rotate sprite using arrow key inputs. Problem updating position

I am trying to control a Sprite using the arrow keys (UP/DOWN for Translation & LEFT/RIGHT for Rotation).
I need the sprite to translate in the direction it has been rotated in.
The issue is that when the sprite is rotated after the sprite has been translated, the position of the sprite resets to where it was originally. I have tried using one div for rotation and one div for translation to no success.
The problem I am facing is a little different to the usual "moving div around screen" issue because I need to move the div at angles and continue to move at that angle.
I feel I am overlooking a simple solution, I would really appreciate if someone could point me in the right direction! Is there an easier alternative to what I am attempting to do that someone could make me aware of?
I have created a JSFiddle to demonstrate what is going on:
CSS transform sprite fiddle
var r = document.getElementById("image2");
document.addEventListener("keyup", checkKeyUp);
document.addEventListener("keydown", checkKey);
var trany = 0;
var rotate = 0;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {
// up arrow
trany = trany-1;
r.style.transform = 'rotate('+rotate+'deg)translateY('+trany+'vmin)';
}
else if (e.keyCode == '40') {
// down arrow
trany = trany+1;
r.style.transform = 'rotate('+rotate+'deg)translateY('+trany+'vmin)';
}
else if (e.keyCode == '37') {
// left arrow
rotate = rotate-.8;
r.style.transform = 'translateY('+trany+'vmin)rotate('+rotate+'deg)';
}
else if (e.keyCode == '39') {
// right arrow
rotate = rotate+.8;
r.style.transform = 'translateY('+trany+'vmin)rotate('+rotate+'deg)';
}
}
function checkKeyUp(e) {
e = e || window.event;
if (e.keyCode == '38') {
// up arrow
}
else if (e.keyCode == '40') {
// down arrow
}
else if (e.keyCode == '37') {
// left arrow
r.style.transform = 'translateY('+trany+'vmin)rotate('+rotate+'deg)';
}
else if (e.keyCode == '39') {
// right arrow
r.style.transform = 'translateY('+trany+'vmin)rotate('+rotate+'deg)';
}
}
#myAnimation {
top:250px;
left:250px;
position: absolute;
}
#image2 {
width:40%
}
img {
width: 30%;
}
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<body>
<div id ="myContainer">
<div id="image1" style="height:300px;width:500px; background-
color:red;"></div>
</div>
<div id ="myAnimation">
<image id="image2" src="https://banner2.kisspng.com/20180415/pge/kisspng-arrow-desktop-wallpaper-symbol-clip-art-up-arrow-5ad37ddc82f384.4572004515238097565364.jpg" style="bottom:0px;width:10%"></image>
</div>
</body>
</html>
what you want to achieve is to move your element independently from its previous state and this cannot be achieved using only transform since transform always consider the initial state in order to move your element.
An idea is to consider using bottom/left to move the element and use only transform to rotate the element. The angle of rotation will define how you will adjust the bottom and left properties:
var r = document.getElementById("image2");
document.addEventListener("keydown", checkKey);
var rotate = 0;
var left=0;
var bottom= 0;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {
// up arrow
r.style.left = left + Math.sin(rotate*Math.PI/180) + 'px';
r.style.bottom = bottom + Math.cos(rotate*Math.PI/180) + 'px';
} else if (e.keyCode == '40') {
// down arrow
r.style.left = left - Math.sin(rotate*Math.PI/180) + 'px';
r.style.bottom = bottom - Math.cos(rotate*Math.PI/180) + 'px';
} else if (e.keyCode == '37') {
// left arrow
rotate = rotate - .8;
r.style.transform = 'rotate(' + rotate + 'deg)';
} else if (e.keyCode == '39') {
// right arrow
rotate = rotate + .8;
r.style.transform = 'rotate(' + rotate + 'deg)';
}
left = parseFloat(r.style.left);
bottom = parseFloat(r.style.bottom);
}
#image2 {
width: 40px;
position: absolute;
}
<img id="image2" src="https://banner2.kisspng.com/20180415/pge/kisspng-arrow-desktop-wallpaper-symbol-clip-art-up-arrow-5ad37ddc82f384.4572004515238097565364.jpg" style="left:0;bottom:0;">
To fix this problem we need to understand how transform works. It does each step one by one. If we want, for example to move diagonally, first we need to rotate, then translate. If we want to make the next move, our previous steps need to be saved. If we don't remember them, the arrow will be animated from the beginning.
So, on each animation end (key up) we need to save all the previous steps.
The next step is all the previous steps + translate/rotate.
Here is your code that I think is working correctly:
var r = document.getElementById("image2");
document.addEventListener("keyup", checkKeyUp);
document.addEventListener("keydown", checkKey);
var saved_moves = '';
var trany = 0;
var rotate = 0;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {
// up arrow
trany = trany-1;
r.style.transform = saved_moves + 'translateY('+trany+'vmin)';
}
else if (e.keyCode == '40') {
// down arrow
trany = trany+1;
r.style.transform = saved_moves + 'translateY('+trany+'vmin)';
}
else if (e.keyCode == '37') {
// left arrow
rotate = rotate-2;
r.style.transform = saved_moves + 'rotate('+rotate+'deg)';
}
else if (e.keyCode == '39') {
// right arrow
rotate = rotate+2;
r.style.transform = saved_moves + 'rotate('+rotate+'deg)';
}
}
function checkKeyUp(e) {
e = e || window.event;
if (e.keyCode == '37' || e.keyCode == '38' || e.keyCode == '39' || e.keyCode == '40') {
// every arrow
saved_moves = r.style.transform;
// reset trany and rotate values
trany = 0;
rotate = 0;
}
}
You can check this jsfiddle https://jsfiddle.net/cyv0j1du/49/
EDIT
Becouse the solution above would create a very long transform, I've came up with different solution. When you release the key, app is reading the matrix value, and then it changes the arrow top and left value. Now only rotate value is remembered.
// Based on the absolute position you've chosen
var left = 250;
var top = 250;
function checkKeyUp(e) {
e = e || window.event;
if (e.keyCode == '37' || e.keyCode == '38' || e.keyCode == '39' || e.keyCode == '40') {
var matrix = window.getComputedStyle(r).getPropertyValue('transform');
matrix = matrix.slice(0, -1);
var values = matrix.split(',');
var x = values[4];
var y = values[5];
top += parseInt(y);
left += parseInt(x);
r.style.top = top + 'px';
r.style.left = left + 'px';
r.style.transform = 'rotateZ('+rotate+'deg)';
trany = 0;
}
}
I've also deleted #myAnimation
#image2 {
width: 20%;
position: absolute;
top: 250px;
left: 250px;
}
so I've deleted the div
<image id="image2" src="https://banner2.kisspng.com/20180415/pge/kisspng-arrow-desktop-wallpaper-symbol-clip-art-up-arrow-5ad37ddc82f384.4572004515238097565364.jpg" style="bottom:0px;width:10%"></image>
You can check how it works here:
https://jsfiddle.net/w1ox240m/57/

Why is my JS only working if I put it after the HTML, even though I have a window.onload?

I just started a CS class at school, so please excuse my total lack of basic knowledge. This JS only works if I put it after the HTML code, not if I put it in the headtag. Shouldn't the window.onload take care of that? Can someone please explain what's wrong? Thanks in advance!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#field {
width: 600;
height: 600;
background-color: black;
position: relative;
}
#player {
width: 50;
height: 50;
background-color: red;
position: absolute;
left: 0px;
top: 0px;
}
</style>
<script>
var player = document.getElementById("player");
var playerLeft = 0;
var PlayerTop = 0;
function move(e) {
if (e.keyCode == 68) {
playerLeft += 10
player.style.left = playerLeft + "px";
}
if (e.keyCode == 65) {
playerLeft -= 10
player.style.left = playerLeft + "px";
}
if (e.keyCode == 87) {
PlayerTop -= 10
player.style.top = PlayerTop + "px";
}
if (e.keyCode == 83) {
PlayerTop += 10
player.style.top = PlayerTop + "px";
}
}
function loadEvents() {
document.onkeydown = move;
}
window.onload = loadEvents;
</script>
</head>
<body>
<div id="field">
<div id="player">
</div>
</div>
The problem is that your want to get an element which doesn't exist yet
var player = document.getElementById("player");
Put this line in the loadEvents() function which is called when the window is loaded.
Note: Avoid errors (if #player element doesn't exist) adding if (player) { ... }
<script>
var player = null;
var playerLeft = 0;
var playerTop = 0;
function move(e) {
if (e.keyCode == 68) {
playerLeft += 10
player.style.left = playerLeft + "px";
}
if (e.keyCode == 65) {
playerLeft -= 10
player.style.left = playerLeft + "px";
}
if (e.keyCode == 87) {
playerTop -= 10
player.style.top = playerTop + "px";
}
if (e.keyCode == 83) {
playerTop += 10
player.style.top = playerTop + "px";
}
}
function loadEvents() {
player = document.getElementById("player");
if (player) {
document.onkeydown = move;
}
}
window.onload = loadEvents;
</script>
Edit
For #tmslnz
var player = null is somewhat redundant, since getElementById returns null if no element is found.
From the ECMAScript2015 spec
4.3.10 undefined value
primitive value used when a variable has not been assigned a value
4.3.12 null value
primitive value that represents the intentional absence of any object value
See this thread and this answer
This runs before the document is loaded.
AKA before the browser has any clue of your markup.
var player = document.getElementById("player");
…
Any time you are querying the DOM (think of it as the HTML you wrote as seen by the browser), you need to wait for it be ready.
Your script would probably be OK if you placed it at the very end of your document, before the closing </body> tag, because by then the browser would have had a chance to spot #player.
What you need to do is find a way to structure your scripts so that they don't try to access the DOM before it's ready.
The easy way is to put everything inside onload in inside $(function(){ … }) if you are using jQuery.
Alternatively if you prefer a bit more control, you can use something like an init function, which you use to "start the engine after the tank is filled" (to use a crappy metaphor…)
For example:
var player;
var playerLeft = 0;
var playerTop = 0;
function init () {
player = document.getElementById("player");
loadEvents();
}
function move(e) {
if (e.keyCode == 68) {
playerLeft += 10
player.style.left = playerLeft + "px";
}
if (e.keyCode == 65) {
playerLeft -= 10
player.style.left = playerLeft + "px";
}
if (e.keyCode == 87) {
playerTop -= 10
player.style.top = playerTop + "px";
}
if (e.keyCode == 83) {
playerTop += 10
player.style.top = playerTop + "px";
}
}
function loadEvents() {
document.onkeydown = move;
}
window.onload = init;

How to make a border?

I have element
<div id="square"></div>
He has a property to move on document
var square = document.getElementById("square");
document.body.onkeydown = function(e) {
if (e.keyCode == 37) {left()}
if (e.keyCode == 38) {up()}
if (e.keyCode == 39) {right()}
if (e.keyCode == 40) {down()}
}
How I make a function, which not allowed movement, if square element is closest to document border?
JSFiddle: https://jsfiddle.net/zutxyLsq/
You need to check if left is outside of boundaries like this:
function left() {
console.log('Left');
var left = parseInt(square.style.left || getComputedStyle(square)['left'], 10);
if (left >= 50) {
square.style.left = (left - 50) + 'px';
}
}
function right() {
console.log('Right');
var left = parseInt(square.style.left || getComputedStyle(square)['left'], 10);
if (left+50+square.offsetWidth < window.innerWidth) {
square.style.left = (left + 50) + 'px';
}
}
https://jsfiddle.net/zutxyLsq/3/
and the same for up and down.

keycodes not working in javascript

this does not move the box when pressing the right and left arrow.
please post in the comments if you can help.
window.addEventListener("keydown", testkey , false );
var el = document.getElementById("player");
//changes the x position by a value
function changex(num) {
el.style.left = ((num + el.style.left) + "px");
}
//changes the y position by a value
function changey(num2) {
el.style.top = ((num2 + el.style.top) + "px");
}
//sets x and y position of box
function setpos(x, y) {
el.style.left = (x + "px");
el.style.top = (y + "px");
}
//this returns the key that is pressed
function testkey(e) {
if (e.keyCode == "37") {
//left key
changex(-10);
}
else if (e.keyCode == "39") {
//right key
changex(10);
}
}
setpos(0,0);
I see two issues:
First
You are adding numeric values to strings, which results in concatination. For example:
((num + el.style.left) + "px") is equivalent to 10 + 0px + px, which results in a string like 100pxpx. This is not a valid CSS value.
I suggest using parseInt to convert existing style values from strings to numbers:
el.style.left = parseInt(el.style.left) + num + "px";
For further reference, see Get a number for a style value WITHOUT the “px;” suffix.
Second
You'll need to position the element before you can use left,right,top, or bottom CSS definitions. The MDN notes that left (for example) only applies to "positioned elements".
Below, I've used position:absolute, but any valid position value will work.
For further reference, see css “left” not working.
Working Example
window.addEventListener("keydown", testkey, false);
var el = document.getElementById("player");
function changex(num) {
el.style.left = parseInt(el.style.left) + num + "px";
}
function changey(num) {
el.style.top = parseInt(el.style.top) + num + "px";
}
function setpos(x, y) {
el.style.left = (x + "px");
el.style.top = (y + "px");
}
function testkey(e) {
switch (e.keyCode) {
case 37: changex(-10); break;
case 38: changey(-10); break;
case 39: changex(10); break;
case 40: changey(10); break;
default:
}
}
setpos(0, 0);
#player {
position: absolute;
}
<div id="player">test</div>
in your changex() and changey() functions, you're trying to do calculations between a number and a string. num comes in as a number but el.style.left is the string '0px'. put parseInt() around el.style.left like this and it works:
el.style.left = ((num + parseInt(el.style.left)) + "px");
Also make sure your player element has position:absolute applied via CSS.

why isn't dynamically changing css style.left and style.top working

I am trying to move an image when the keys w, a, s, and d are pressed, but nothing is happening, and nothing is showing up in the console. Any help or suggestions would be greatly appreciated.
var moveBy = 10;
function moveObj(name, xPix, yPix)
{
var obj = document.getElementById(name);
var xp = parseInt(obj.style.left) + xPix;
var yp = parseInt(obj.style.top) + yPix;
obj.style.left = xp;
obj.style.top = yp;
}
$(document).ready(function()
{
$('body').keydown(function(e)
{
if(e.keyCode == 68)
{
moveObj('player', moveBy, 0);
}
else if(e.keyCode == 65)
{
moveObj('player', -moveBy, 0);
}
else if(e.keyCode == 87)
{
moveObj('player', 0, -moveBy);
}
else if(e.keyCode == 83)
{
moveObj('player', 0, moveBy);
}
});
});
Did you set position: relative on your player object?
That will be needed to move the player. If you have it set to static, it'll not move.
put this in moveObj to see if it's actually being called: console.log(arguments);. Set the new value with the units, i.e. obj.style.left = xp + 'px';. Also make sure the element you're changing the position of has a position property, you're probably looking for position: absolute;. Adding the HTML to your post would help.

Categories