This question already has answers here:
Javascript style.left is empty string
(4 answers)
Closed 2 years ago.
I'm attempting to learn the absolute basics of game-making, and I'm wondering why I can move an img but not a div element.
JS:
var element;
function moveSelection(evt) {
element = document.getElementById("char");
switch (evt.keyCode) {
case 37:
element.style.left = parseInt(element.style.left) - 10;
break;
case 39:
element.style.left = parseInt(element.style.left) + 10;
break;
case 38:
element.style.top = parseInt(element.style.top) - 10;
break;
case 40:
element.style.top = parseInt(element.style.top) + 10;
break;
}
}
window.addEventListener('keydown', moveSelection);
Now, if I have an img tag with the id of char, I can move it with my arrow keys.
<img src="" id="char">
But if I remove that image and replace it with a div,
<div id="char"></div>
it doesn't let me move it.
There are multiple issues with the code and I'm not sure how it could work with images.
For this to work, a few things need to be done:
Ensure the target element's CSS has the position: absolute property set. You can also use relative, fixed or sticky depending on need.
Use getComputedStyle instead of accessing style directly. The style property will only contain values set by a property or attribute.
Append a measurement unit like "px" to the parsed number.
Here's a minimal, complete example:
const element = document.getElementById("char");
const charStyle = getComputedStyle(element);
function moveSelection(evt) {
evt.preventDefault();
switch (evt.keyCode) {
case 37:
element.style.left = parseInt(charStyle.left) - 10 + "px";
break;
case 39:
element.style.left = parseInt(charStyle.left) + 10 + "px";
break;
case 38:
element.style.top = parseInt(charStyle.top) - 10 + "px";
break;
case 40:
element.style.top = parseInt(charStyle.top) + 10 + "px";
break;
}
}
document.addEventListener("keydown", moveSelection);
#char {
width: 50px;
height: 50px;
background: red;
position: absolute;
}
<div id="char"></div>
Having said that, this sort of design should strike you as an antipattern because it serializes and de-serializes attributes from DOM elements. This is a poor substitute for creating a good old fashioned data structure like:
const character = {x: 0, y: 0, stepSize: 10 /*... more properties ...*/};
Also, having the keyboard directly triggering the character's movement causes awkward retriggering and generally unreliable UX. It's best to use an animation loop like requestAnimationFrame for such cases. The keyboard handler will flip on and off flags for each key but won't actually update anything directly. The animation loop will handle the repositioning smoothly. Your JS script will keep game/animation state and only dump it to the DOM as a decoupled view when it's time to render a frame. This way, data flows in one direction and your app will be easier to write and maintain.
Related
The buttons should move a few arrows to the right and left I choose in the check box which arrow I want and then it should move each time + or - 20 degrees so that the breasts rotate.
The buttons work but they get stuck and the arrows do not move smoothly.
curretnAngle is a new angle that I compare to each arrow and its angles and then in the second function I change it to 20 degrees each time
const handleChange=(e)=>{
let curretnAngle;
if (props.selectedButton=='turret') {
console.log(props.selectedButton);
curretnAngle = props.angleTurret
console.log(props.angleTurret, curretnAngle);
}
else if (props.selectedButton=='lazer') {
curretnAngle= props.angleLazer
}
else{
curretnAngle = props.radanglee
}
switch (e.target.name){
case 'minus':
console.log(curretnAngle,props.selectedButton);
props.handlerotat(curretnAngle-20)
console.log('minus')
break;
case 'plus':
console.log(curretnAngle,props.selectedButton);
props.handlerotate(curretnAngle+20)
console.log('plus')
break;
}
const handlerotate=(newAngle)=>{
switch (selectedButton) {
case 'turret':
setAngleTurret(newAngle)
break;
case 'lazer':
setAngleLazer(newAngle)
break;
case 'lezerr':
setAnglerad(newAngle)
break;
}
}
So I am a bit new to javascript and I am looking to create a switch statement for keyboard functions relating to my animation. So if I were to click backspace it stops the animation, and when I click enter it resumes etc. That works but im also trying to get it to advance to the next frame or the previous frame when i click the left or right key, and it isn't entirely working. Sorry this is my first post but any suggestions or help would be great!
var roote = this;
addEventListener("keydown", controlBox);
function controlBox(evt){
switch(evt.keyCode){
case 8:
roote.box.stop();
break;
case 13:
roote.box.play();
break;
//previous frame
case 37:
roote.box.prevFrame();
break;
//next frame
case 39:
roote.box.nextFrame();
break;
}
}
var theFrame = document.getElementsByTagName("frame")[0];
var frameNumb = parseInt(theFrame, 10);
function prevFrame(){
roote.gotoAndStop((frameNumb) -1);
}
function nextFrame(){
roote.gotoAndStop((frameNumb) +1);
}
var myFrame = roote.currentFrame();
case 37:
roote.gotoAndStop(myFrame + 1); //go to next frame
break;
case 39:
roote.gotoAndStop(myFrame - 1); //go to previous frame
break;
answered my own question, was overthinking it.
I am trying to code a menu bar for my site in JS - the problem I'm having is that I am using a variable as a 'which category is unfolded' switch, and it does not seem to register. Firebug seems to tell me it's not defined, and or stays zero.
var navOpen = 0;
$(function() {
///////////bunch of other functions here
//When designWork is clicked
$(".designwork").click(function(){
switch(navOpen)
{
case 0:
$(".navsub:hidden",this).slideDown("slow");
navOpen = 1; break;
case 1:
break;
case 2:
$("div.artProjects .navsub").slideUp("fast");
$(".navsub:hidden",this).slideDown("slow");
navOpen = 1; break;
default:
break;
}
});
//When artProjects is clicked
$(".artprojects").click(function(){
switch(navOpen)
{
case 0:
$(".navsub:hidden",this).slideDown("slow");
navOpen = 2; break;
case 1:
$("div.designWork .navsub").slideUp("fast");
$(".navsub:hidden",this).slideDown("slow");
navOpen = 2; break;
case 2:
break;
default:
break;
}
});
});
For a reason that is probably obvious, but I'm not seeing it, both menus open when clicked in the manner they should, but they do not close the other menu... help me out here, what am I missing?
$("div.designWork .navsub") should be $("div.designwork .navsub")
and
$("div.artProjects .navsub") should be $("div.artProjects .navsub")
capitals ...
Well, I think it has to do with the fact that in both cases you refer to ".navsub:hidden" without specifying precisely which navsub you really mean. You probably want to add either div.designWork or div.artProjects in front of it to specify which menu should slidedown.
I am new to javascript and I am trying to start a very simple project which is to display a controllable div that can be moved around using a,w,s,d keys on keyboard. I am currently having problem on how to move around the div because I do not know what attribute to change.
divBar = null;
function detectKey() {
//97 = a
//115 = s
//100 = d
//119 = w
if (event.charCode == 97) {
//a
alert(divBar.position);
}
if (event.charCode == 115) {
//s
}
if (event.charCode == 100) {
//d
}
if (event.charCode == 119) {
//w
}
}
function createDiv() {
divBar = document.createElement("div");
divBar.id = "divBar";
divBar.style.border = "solid 1px #AAAAAA";
divBar.style.backgroundColor = "black";
divBar.style.top = 400;
divBar.style.height = "10px";
divBar.style.width = "100px";
divBar.style.position = "absolute";
document.body.appendChild(divBar);
document.addEventListener("keypress", detectKey, false);
}
I am not sure to put in that condition statement. so that the div will move to the left, right, up and down.
If it's absolutely positioned (which it appears to be), then you change divbar.style.top and divbar.style.left to move it around.
Here's a working example: http://jsfiddle.net/jfriend00/rRbZz/.
Since it's absolutely positioned, you are most likely going to want to change it's top/left style attributes. It will involve reading the current top/left attributes, and then adding/subtracting from them after a a,w,s,d key is pressed, and then adding that value back. So for each key/direction, you are going to have to figure out what impact that will have on the element. will it move it up/down (affect the top attribute) or left/right (affect the left attribute). Read what's there, make the appropriate calculations, and the update the attribute. The trickiest part IMO is reading the initial style.top/style.left attributes, but since you are setting them with Javascript, then you shouldn't have a problem.
i have table with 3X4 cells i navigate among cells using arrow keys(right,left,up, down) but problem is initially i need to press tab key to get focus to first cell and only after that i will be able to use arrow key to navigate. now my question is how can i set focus to first cell of table so that i can directly use arrow keys to navigate instead use tab first and they arrow keys.
here is my code:
function myNav(e,down,left,up,right)
{
if (!e) e=window.event;
var selectArrowKey;
switch(e.keyCode)
{
case 37:
selectArrowKey = left;
break;
case 38:
selectArrowKey = down;
break;
case 39:
selectArrowKey = right;
break;
case 40:
selectArrowKey = up;
break;
}
if (!selectArrowKey) return;
var controls = document.getElementsByName(selectArrowKey);
if (!controls) return;
if (controls.length != 1) return;
controls[0].focus();
}
kindly help.
On page load, retrieve a reference to that cell and call focus on it. You haven't shown your markup, so it's hard to give you a concrete example, but for instance if your table has an id of "foo":
var node = findFirstChild(document.getElementById('foo'), 'TD');
if (node) {
// get the control within the cell
node.focus();
}
function findFirstChild(parent, tag) {
var node, child;
for (node = parent.firstChild; node; node = node.nextSibling) {
if (node.nodeType == 1) { // Element
if (node.tagName === tag) {
return node;
}
child = findFirstChild(node, tag);
if (child) {
return child;
}
}
}
return undefined;
}
In terms of "page load", you can either hook the window.onload event (but that happens very late), or just put a script element at the bottom of the body tag (or anywhere after the table) that does the above. Once the table tag is closed, you can access it from script (ref1, ref2).
Off-topic: If you use a library like jQuery, Prototype, YUI, Closure, or any of several others, the code can get a lot simpler. For instance, with jQuery, the above changes to:
$("#foo td:first").focus();
Update: Responding to your comment below, your jsFiddle code was:
<html>
<head>
<script type="text/javascript" src="jquery-1.4.4.js"></script>
<script type="text/javascript">
$("#mycell td:first").focus();
function myTest(e,down,left,up,right)
{
if (!e) e=window.event;
var selectArrowKey;
switch(e.keyCode)
{
case 37:
// Key links.
selectArrowKey = left;
break;
case 38:
// Key oben.
selectArrowKey = down;
break;
case 39:
// Key rechts.
selectArrowKey = right;
break;
case 40:
// Key unten.
selectArrowKey = up;
break;
}
if (!selectArrowKey) return;
var controls = document.getElementsByName(selectArrowKey);
if (!controls) return;
if (controls.length != 1) return;
controls[0].focus();
}
var node = findFirstChild(document.getElementById('mycell'), 'TD');
if (node) {
// get the control within the cell
node.focus();
}
function findFirstChild(parent, tag) {
var node, child;
for (node = parent.firstChild; node; node = node.nextSibling) {
if (node.nodeType == 1) { // Element
if (node.tagName === tag) {
return node;
}
child = findFirstChild(node, tag);
if (child) {
return child;
}
}
}
return undefined;
}
</script>
</head>
<body>
<table id="mycell" border="1" cellpadding="0" cellspacing="0">
<tr>
<td><button name="obenLinks" onkeydown="myTest(event,undefined,undefined,'mitteLinks','obenMitte')"><img src="C:\Documents and Settings\ing12732\Desktop\html_files\tv-dev\image2.png" ></button></td>
<td><button name="obenMitte" onkeydown="myTest(event,undefined,'obenLinks','mitteMitte','obenRechts')"><img src="C:\Documents and Settings\ing12732\Desktop\html_files\tv-dev\image2.png" ></td>
<td><button name="obenRechts" onkeydown="myTest(event,undefined,'obenMitte','mitteRechts',undefined)"><img src="C:\Documents and Settings\ing12732\Desktop\html_files\tv-dev\image2.png" ></td>
</tr>
</table>
</body>
</html>
Three issues prevented that fiddle from working:
You weren't successfully including jquery. On your system, the path jquery-1.4.4.js may give you jQuery, but jsFiddle is obviously not on your system.
You're trying to access an element before it's been created. Your first line of script code happens right away, but since the script is above the table in the file, it fails because the element isn't there.
Your selector is selecting the table cell; I'm guessing you actually want the button.
Separately:
The second and third button tags weren't closed. The browser probably quietly closes them for you, but one of the first steps in debugging this sort of thign is to make sure your markup is correct and valid. Valid markup make a difference.
The paths "C:\Documents and Settings\ing12732\Desktop\html_files\tv-dev\image2.png" and the like in the images inside the button tags indicate to me that you're trying to do web development without using a web server. Strongly recommend using a web server and proper paths, browsers do various things differently when dealing with local files rather than resources loaded via HTTP.
Strongly recommend using a DOCTYPE. Any DOCTYPE, although my preferred one is HTML5's <!DOCTYPE html> (more).
Here's a corrected fiddle. Hope this helps.