I am trying to make a webpage where when you click a link, the link moves diagonally every 100 milliseconds.
So I have my Javascript, but right now when I click the link nothing happens
Also, does anyone know of a Javascript IDE I can use to make sure I have no errors in my code?
PS: Does anyone know why my elements dont stretch to fit the whole 200px by 200px of the div element? The links are only small when they should be the same width as their parent div element.
Edited with new advice, although still wont move.
<script LANGUAGE="JavaScript" type = "text/javascript">
<!--
var block = null;
var clockStep = null;
var index = 0;
var maxIndex = 6;
var x = 0;
var y = 0;
var timerInterval = 100; // milliseconds
var xPos = null;
var yPos = null;
function moveBlock()
{
if ( index < 0 || index >= maxIndex || block == null || clockStep == null )
{
clearInterval( clockStep );
return;
}
block.style.left = xPos[index] + "px";
block.style.top = yPos[index] + "px";
index++;
}
function onBlockClick( blockID )
{
if ( clockStep != null )
{
return;
}
block = document.getElementById( blockID );
index = 0;
x = parseInt( block.style.left, 10 );
y = parseInt( block.style.top, 10 );
xPos = new Array( x+10, x+20, x+30, x+40, x+50, x+60 );
yPos = new Array( y-10, y-20, y-30, y-40, y-50, y-60 );
clockStep = self.SetInterval( moveBlock(), timerInterval );
}
-->
</script>
<style type="text/css" media="all">
<!--
#import url("styles.css");
#blockMenu { z-index: 0; width: 650px; height: 600px; background-color: blue; padding: 0; }
#block1 { z-index: 30; position: relative; top: 10px; left: 10px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block2 { z-index: 30; position: relative; top: 50px; left: 220px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block3 { z-index: 30; position: relative; top: 50px; left: 440px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block4 { z-index: 30; position: relative; top: 0px; left: 600px; background-color: red; width: 200px; height: 200px;
margin: 0; padding: 0; /* background-image: url("images/block1.png"); */ }
#block1 a { display: block; width: 100%; height: 100%; }
#block2 a { display: block; width: 100%; height: 100%; }
#block3 a { display: block; width: 100%; height: 100%; }
#block4 a { display: block; width: 100%; height: 100%; }
#block1 a:hover { background-color: green; }
#block2 a:hover { background-color: green; }
#block3 a:hover { background-color: green; }
#block4 a:hover { background-color: green; }
#block1 a:active { background-color: yellow; }
#block2 a:active { background-color: yellow; }
#block3 a:active { background-color: yellow; }
#block4 a:active { background-color: yellow; }
-->
</style>
Errors needed to fix
To fill the width of the div elements, the a elements need to be display: block; not their default display: inline;.
Knowing runtime errors is more important in my opinion, and IDEs don't catch DOM errors or anything more complex than syntax; use the error logging in your browser (Firefox's is called Error Console). That'll also catch in-development errors like syntax errors.
This is the most important point to stress: block.style.left and block.style.top are not just numbers with implicit pixel values in them. Setting it to a number without a unit suffix will do absolutely nothing. You need to add % or px or whatever unit when setting left and top.
When getting the current value, as in var x = ... and var y = ..., you need to Number() manually to get the numeric portion of the string.
Also, I believe you meant || block == null, not =, which would set block to null.
Tips
You can use moveBlock instead of "moveBlock();" as an argument to setTimeout. This avoids parsing the string into code, and avoids scope problems (though not in this example as moveBlock is global).
I know that you have an array of values, where both x and y move 10 each time. I assume you want to move at a 45 degree angle. If so, this won't work as you expect even after fixing all the errors as x is percentage and y is in pixels.
You should declare your x and y above like your other variables. It may work but its confusing.
in your setTimeout, use moveBlock, not "moveBlock()" - it will save the step of evaluating your string into code.
block.style.left will return a string that includes "px" - it won't be a number. You can do:
x = Number(x);
//or
x = parseInt(x, 10);
When you set the position, remember to add the "px":
block.style.left = xPos[index] + "px";
EDIT:
Ok, the key problem is 'style.left' is not reading because it was set with CSS and not the style object. I use my library to get the style which runs through a few scenarios and catches that automatically. So change these lines to (this may not be exactly correct but will get things moving):
x = parseInt( node.style.left, 10 ) || 0;
y = parseInt( node.style.top, 10 ) || 0;
Also, this is wrong (you never declared 'self', and you don't need it here anyway; JS is case sensitive, SetInterval is not capped; pass the function, not the function result):
clockStep = self.SetInterval( moveBlock(), timerInterval ); // <-- result of moveBlock
// change to:
clockStep = setInterval( moveBlock, timerInterval ); // <-- the function moveBlock
During dev, you should remove the if() statements that could have been blocking the code and just put a simple count--; in there. It's really hard to debug code when you have literally 20 things wrong. Write a line, test. Write a line, test.
You have HTML comments in the script and style blocks. This is from 1998. While they don't hurt anything intact, in the past I've accidentally edited my code and removed one of them, and this will throw everything out of whack - your IDE, the browser - because they won't know what's wrong and you won't get a good error message.
LANGUAGE="JavaScript" is no longer used and is a waste of bytes.
To help speed development add this line:
window.onloadfunction(){
onBlockClick('block1')
}
That will execute your code right away for testing and you don't have to click every time.
Finally, I highly recommend you use Firefox and Firebug. Developing without it is like trying to build a ship in a bottle with boxing gloves. Using console.log(block.style.left) would have shown you it was not set. The error messages would have told you SetInterval and moveBlock() was incorrect. You do need to remember to remove the console.logs before production though. or... (shameless plug)... use my JavaScript Console Fix library which will do that for you: http://clubajax.org/javascript-console-fix-v2-now-with-ios/
Related
I have a simple animation function that simulates a button being pushed, by varying the width:
function bPress(b) {
var w = (parseFloat(b.style.width)*0.96);
if (b.style.width.substr(-1)=="%") {
var s ="%";
}
else {
var s = "em";
}
b.style.width = w +s;
b.onmouseup = function () {
w = (parseFloat(b.style.width)/0.96);
b.style.width = w+s;
// etc.
}
This was working well until I started cleaning up my code and changed inline CSS style declarations to classes. I previously had, for example:
<div style= 'height: 1.5em; width: 100%; margin: 0 auto; margin-top: 0.2em; font: inherit; font-weight:bold' onclick='checkSave("continue")' onmousedown='bPress(this)'>Continue</div>
I moved the CSS parts to a new class:
.response_button {
height: 1.5em;
width: 100%;
margin: 0 auto;
margin-top: 0.2em;
font: inherit;
font-weight:bold
}
... avoiding repetition and of course simplifying the div tags.
But the animations stopped working. After some experimenting, I eventually came up with a temporary solution by moving the width back into an inline style declaration. But this seems wrong.
So 2 questions:
Why does this.style.width not work if the width is declared inside a class?
Is there a way to get and set a div's properties if they are declared inside a class?
Edit: For completeness, using nick zoum's answer, here is the modified bPress function:
function bPress(b) {
var w_px = window.getComputedStyle(b).width;
var w_int = (parseInt(w_px));
b.style.width = Math.round(w_int * 0.96) + "px";
b.onmouseup = function () {
b.style.width = w_px;
}
}
You can use getComputedStyle to get all of the calculated style properties of an element.
var dom = document.querySelector("#foo");
console.log(getComputedStyle(dom).backgroundColor);
#foo {
background-color: red;
width: 10px;
height: 10px;
}
<div id="foo"></div>
I have two elements, and one is moving towards the other. I am trying to get the new distance as it moves closer. Consider the code below:
<html>
<center>
<body onload = 'start()'>
<div class='field'>
<div id='bull'></div>
<div id='mount'></div>
</div>
<button id='one'>DO</button>
</body>
</center>
<style>
.field{
width: 440px;
height: 260px;
background: rgba(0, 0, 0, .2);
margin-top: 30px;
border: 1px solid #222;
border-radius: 10px;
}
#bull{
width: 15px;
height: 10px;
background: #000;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
position: absolute;
}
#mount{
width: 60px;
height: 30px;
background: rgba(20, 10, 45);
color: #fff;
border-radius: 4px;
margin-top: 210px;
}
</style>
<script type='text/javascript'>
function start() {
var ball = document.getElementById('bull');
var button = document.getElementById('one');
var mount = document.getElementById('mount');
button.addEventListener('click', go);
var x_pos = 0;
var y_pos = 0;
var bounce_point = 200;
var ball_dim = ball.getBoundingClientRect();
var ball_h_half = ball_dim.width / 2;
var ball_w_half = ball_dim.height / 2;
var mount_dim = mount.getBoundingClientRect();
var mount_h_half = mount_dim.width / 2;
var mount_w_half = mount_dim.height / 2;
function go() {
for(x_pos = 0; bounce_point > x_pos; x_pos++) {
ball.style.margin = x_pos + "px";
ball.style.transition = x_pos/2 + "s";
var dist = ((ball_h_half - mount_h_half)*(ball_w_half - mount_w_half)) + ((mount_h_half - ball_h_half)*(mount_w_half - ball_w_half));
console.log(dist);
if(dist < 3) {
console.log('One');
}
}
}
}
</script>
When bull reaches comes within 3px of mount, nothing happens... I've pretty much explained the issue as best as I can.
**
When bull reaches comes within 3px of mount, nothing happens... I've pretty much explained the issue as best as I can.**
Well i tried a little bit more, and your logic doens't seem to fit to what you want to do. First of all, you probably noticed your value in the log doesn't change.
It could have been because the values are retreived outside the loop, but not only (they actually have to be in the loop to be updated). You have 2 other problems: first, you are measuring the elements width and height, which don't take account of margin or other positioning. Your elements don't change size, so the value also won't. The other problem is actually the transition itself on the movement. Because of the delay, all your loop iterations are most probably done, and the margin already set to its final value when your "bull" effectively starts to move. It means that in the loop, you can't detect the position change, the element having not started to move yet. Using the value that was just set (margin) instead of detecting the real position of the element should show a progression for the value, but it makes harder to detect the collision because your 2 elements don't have the same positioning rules and you can't just compare the margins.
Here is a quick example that gets updated values (because the transition has been disabled, if you enable back, the problem comes again). You'll notice your calculation for the collision is wrong too. You can't just compare a distance between 2 corners for that, for a rectangle it's rather "has gone beyond left vertical edge AND has gone beyond top horizontal edge" (this of course takes only in account the top left corner, to be complete, it should also be added that it must not have reached the right or bottom edge yet).
Well, I can't propose you an all ready solution, but this addresses your code main issues:
<html>
<center>
<body onload = 'start()'>
<div class='field'>
<div id='bull'></div>
<div id='mount'></div>
</div>
<button id='one'>DO</button>
</body>
</center>
<style>
.field{
width: 440px;
height: 260px;
background: rgba(0, 0, 0, .2);
margin-top: 30px;
border: 1px solid #222;
border-radius: 10px;
}
#bull{
width: 15px;
height: 10px;
background: #000;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
position: absolute;
}
#mount{
width: 60px;
height: 30px;
background: rgba(20, 10, 45);
color: #fff;
border-radius: 4px;
margin-top: 210px;
}
</style>
<script type='text/javascript'>
function start() {
var ball = document.getElementById('bull');
var button = document.getElementById('one');
var mount = document.getElementById('mount');
button.addEventListener('click', go);
var x_pos = 0;
var y_pos = 0;
var bounce_point = 200;
var ball_dim, ball_x, ball_y, mount_dim, mount_x, mount_y, diff_x, diff_y;
var stayInLoop = true;
//ball.style.transition = "0.4s"; //i don't know why you updated the transition time based on position, changed to a fixed value outside the loop because it's quicker for the example
function go() {
for(x_pos = 0; bounce_point > x_pos && stayInLoop; x_pos++) {
ball_dim = ball.getBoundingClientRect();
ball_y = ball_dim.top + 10; // +10 because we're considering the bottom edge of bull
ball_x = ball_dim.left + 15; // +15 because we're considering the right edge of bull
mount_dim = mount.getBoundingClientRect();
mount_y = mount_dim.top;
mount_x = mount_dim.left;
diff_x = mount_x - ball_x;
diff_y = mount_y - ball_y;
console.log(diff_x, diff_y);
ball.style.margin = x_pos + "px";
if(diff_x < 3 && diff_y < 3) {
console.log('One');
stayInLoop = false;
}
}
}
}
</script>
EDIT/SUGGESTION: i suggest looking at window.requestAnimationFrame() MDN doc here for a better control on animations
I've tried to setup a very "vanilla" approach to this but cannot get the result.
I'm trying to reach into the DOM and the associated div styles using JS and effectively change the "display" property of the CSS.
The JS is error free but the CSS doesn't change.
(function() {
var singleCard = document.getElementById('card-container');
var manyCard = document.getElementById('card-container-many');
var allCard = document.getElementById('card-container') && document.getElementById('card-container-many');
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
var allCardCss = document.querySelector('#card-container') && document.querySelector('#card-container-many');
if (singleCardCss.display && manyCardCss.display === 'none') {
allCardCss.display = 'block';
} else {
allCardCss.display = 'none';
}
}());
#card-container {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
#card-container-many {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
<div class="container-fluid text-center">
<div id="card-container"></div>
</div>
<div class="container-fluid text-center">
<div id="card-container-many"></div>
</div>
The .style property is missing. For example:
allCardCss.style.display = 'block';
Also, the use of the AND operator is wrong I believe. It should be used in the if condition like so:
if (singleCardCss.style.display === "none" && manyCardCss.style.display === 'none') {...
Each side of the operand must be complete in a conditional even when it's a comparison between 2 objects (singleCardCSS and manyCardCSS) vs. the same condition ("none").
I took a third look and saw that allCardCSS is wrong as well, it should be:
var allCardCSS = document.querySelectorAll('div > div');
The result will be a NodeList of all divs that are a child of another div (singleCardCSS and manyCardCSS). This NodeList is an array-like object which you can do simple iterations upon in order to access the objects within. Notice how the for loop goes through the NodeList allCardCss.
Finally on the last statement has been eliminated because the else isn't needed since they are already .style.display="none". The first statements have been eliminated as well because .getElementById('ID') is identical to querySelector('#ID');
One last thing, I almost forgot about the parenthesis business:
Either of the following two patterns can be used to immediately invoke
a function expression, utilizing the function's execution context to
create "privacy."
(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well
-Ben Alman
So you are ok. The point is that if you have a set of extra parenthesis at the end then that'll be interpreted by the browser as an Expression Function which causes an Immediate Invocation*. The mention of privacy is referring to the IIFE with a closure which doesn't apply in your circumstance unless you make the latter part of the code into a function in which case you have a closure. In your case it's not needed since you aren't passing any variables from the outside of your function.
To those more knowledgeable. If there's anything I've said that to the contrary or omitted, please leave a comment with your downvote.
*it's IIFE a little mixed up in order in sentence but you get the picture 😉
Demo
(function() {
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
var allCardCss = document.querySelectorAll('div > div');
if (singleCardCss.style.display === "none" && manyCardCss.style.display === 'none') {
for (let i = 0; i < allCardCSS.length; i++) {
allCardCss[i].style.display = 'block';
}
}
}());
#card-container {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
#card-container-many {
position: relative;
display: none;
width: 280px;
height: 310px;
background-size: 640px 360px;
background-repeat: no-repeat;
border: 1px solid #222;
border-radius: 10px;
margin: 10px;
cursor: pointer;
}
<div class="container-fluid text-center">
<div id="card-container"></div>
</div>
<div class="container-fluid text-center">
<div id="card-container-many"></div>
</div>
Your error is very common. You have to remove the last ) after your function. You close your IIFE after calling it. You can try but your function will be never call! You also can try to delete your variable allCardCss and allCard. I do not understand why do you initialize them with &&.
Replace:
(function() {
var singleCard = document.getElementById('card-container');
var manyCard = document.getElementById('card-container-many');
var allCard = document.getElementById('card-container') && document.getElementById('card-container-many');
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
var allCardCss = document.querySelector('#card-container') && document.querySelector('#card-container-many');
if (singleCardCss.display && manyCardCss.display === 'none') {
singleCardCss.display = 'block';
} else {
allCardCss.display = 'none';
}
}());
By:
(function() {
var singleCard = document.getElementById('card-container');
var manyCard = document.getElementById('card-container-many');
var singleCardCss = document.querySelector('#card-container');
var manyCardCss = document.querySelector('#card-container-many');
if (singleCardCss.display && manyCardCss.display === 'none') {
singleCardCss.display = 'block';
manyCardCss.display = 'block';
} else {
singleCardCss.display = 'none';
manyCardCss.display = 'none';
}
})();
There is a circle and some object around it.the objects number may vary from 1 to n (dynamic).
How can i place all this objects around the circle automatically ??
Tnx in advance.
Here is a way of doing it. I've added comments in the code to explain the steps. I've taken the liberty to use just colored divs instead of images, but the effect is the same.
// Editor to change the number of persons dynamically
var nr = document.getElementById('nr');
nr.addEventListener('keyup', function(){updatePersons();});
// The globe
var globe = document.getElementById('globe');
// A function to reinitialize the persons
function updatePersons() {
var personCount = parseInt(nr.value);
globe.innerHTML = ''; // A bit dirty way to remove all previous peeps
// Just add them in a loop, and apply a transformation.
for (var i = 0; i < personCount; i++) {
var person = document.createElement('div');
person.className = 'mens';
var rotation = i * (360 / personCount);
console.log(rotation);
person.style.transform = 'translate(125px, -100px) rotate(' + rotation + 'deg)';
globe.appendChild(person);
}
}
// Initial positioning of persons.
updatePersons();
#nr {
position: relative;
z-index: 1;
}
.corea {
background-color: blue;
border-radius: 50%;
width: 300px;
height: 300px;
position: relative;
}
.mens {
position: absolute; /* Needed, otherwise they influence each other */
width: 50px;
height: 100px;
background-color: red;
transform-origin: 25px 250px;
/* Transform is set in Javascript */
x-transform: translate(125px, -100px) rotate(180deg);
}
<input id="nr" value="5">
<div id="globe" class="corea">
</div>
I'm trying to write a facebook like chatbox, but i've encountered a small problem.
I'm using the following code (it's only test code, so it's not really clean):
css code:
#messenger {
position: fixed;
bottom: 0px;
right: 10px;
width: 200px;
height: 300px;
z-index: 4;
background-color: #ECECEC;
border: 1px solid #000;
}
#messenger.p {
text-align: right;
}
#contacts {
margin: 5px 5px 5px 5px;
}
#chatspace {
position: fixed;
bottom: 0px;
right: 240px;
height: 20px;
left: 20px;
background-color: #ECECEC;
border: 1px solid #000;
z-index: 4;
}
.chatbox {
position: absolute;
bottom: 0px;
width: 200px;
height: 200px;
z-index: 4;
background-color: #ECECEC;
border: 1px solid #000;
}
html/javascript code:
<script type="text/javascript">
var i = 0;
function oc_chatbox() {
if (i == 0) {
document.getElementById('contacts').style.visibility = 'hidden';
document.getElementById('messenger').style.height = '20px';
i = 1;
}
else {
document.getElementById('contacts').style.visibility = 'visible';
document.getElementById('messenger').style.height = '300px';
i = 0;
}
}
function new_chat(userid) {
var new_right;
new_right = document.getElementById('messenger').style.right;
//alert('old value: '+ new_right);
new_right += 20;
//alert('New value of right: '+ new_right);
document.getElementById('chatspace').innerHTML = '<div id="'+userid+'" class="chatbox" style="right: '+new_right+'px;"></div>';
//document.write('<div id="'+userid+'" class="chatbox" style="right: '+new_right+'px;"></div>');
}
</script>
<div id="chatspace"></div>
<div id="messenger">
<p>Collapse</p>
<div id="contacts">
<ul>
<li>contact A</li>
</ul>
</div>
</div>
the problem is, that when I try to add new chats to the chatbar, i can't seem the place them next to each other.
anyone who can help ?
EDIT:
so i changed to javascript code to:
var last = null;
function new_chat(userid) {
if(userid==null)
userid = "user666";
var new_right;
var margin = 10;
var messenger = window.last==null?document.getElementById('messenger'):window.last; //Take the messenger or the last added chat
new_right = document.body.clientWidth-messenger.offsetLeft; //Compute the window size
console.log(new_right); //Log the number
new_right += margin; //keep spaces between divs
var newChat = document.createElement("div"); //DOM create DIV
newChat.id = userid;
newChat.className = "chatbox shadow";
newChat.style.right = new_right+"px";
newChat.innerHTML = '<p>'+userid+'</p><p><textarea></textarea></p>';
window.last = newChat; //Remember whichever is last
document.body.appendChild(newChat);
}
and now it works, thanks !
You cannot get an element right offset using its style, unlest the style is set and valid. Instead you must get element.offsetLeft and size of window area and do this:
new_right = windowSize()[0]-messenger.offsetLeft;
Where window size is this function.
Here is my, working, version of your function:
var last = null;
function new_chat(userid) {
if(userid==null)
userid = "user666";
var new_right;
var margin = 20;
var messenger = window.last==null?document.getElementById('messenger'):window.last; //Take the messenger or the last added chat
new_right = windowSize()[0]-messenger.offsetLeft; //Compute the window size
console.log(new_right); //Log the number
new_right += margin; //keep spaces between divs
var newChat = document.createElement("div"); //DOM create DIV
newChat.id = userid;
newChat.className = "chatbox";
newChat.style.right = new_right+"px";
window.last = newChat; //Remember whichever is last
document.body.appendChild(newChat);
}
You may get errors if console is not defined in your brouwser. But in such case you should take a better browser. Normally, the if(console!=null) is put in code.
And here is the link.
You should try adding a float style.
.chatbox {
float: right;
}
Add that to your chatbox styles. You may need to mess around a bit to make sure the float doesn't mess with your other elements. You may need a better container for them.
If you want to get really fun, you can add .draggable() from jQuery, and you can have them snap to your chat bar. You can then change the order of your chats.