All,
A total newbie here but could someone please review this code and let me know where I am going wrong?
What effect I am trying to achieve: I have about 9 divs on the webpage, consisting of images and text, the text comes into focus when the user hovers over the image inside the div. I want these divs to 'appear' to be floating around the page.
So what I did: I absolutely positioned the divs using CSS on the webpage. Now I am using JS to move the divs from their position to set positions on the page (will do this for each div) and try to give the effect of random movement to the divs. Here is the code:
<script language="javascript">
var x = document.getElementById("cr001").style.left;
var y = document.getElementById("cr001").style.top;
var d_x = 75;
var d_y = 100;
var interval = 2; //move by only 2px...
function moveImage() {
if(x < d_x) x = x + interval;
if(y < d_y) y = y + interval - 1; //move y by only 1px
document.getElementById("cr001").style.left = x+'px';
document.getElementById("cr001").style.top = y+'px';
if ((x + interval < d_x) && (y + interval < d_y)) {
window.setTimeout('moveImage()',100);
}
}
</script>
</head>
<body onload="moveImage()">
<div id="blackhole"><img src="img/bimg.png" alt="blackhole" /></div>
<div id="container">
<div id="cr001" class="twinkles">
<a href="#">
<img src="img/cr.png" alt="Co is about your freedom" />
<span>Co is about your freedom</span></a>
</div>
</body>
Could someone please explain where I am going wrong?
Cheers,
Based on the refined post, I now see that you are trying to access body content in the head with var x = document.getElementById("cr001").style.left;
This won't work because when the head is loaded, the body is not ready. You should make an init() function that looks like:
function init(){
window.x = document.getElementById("cr001").style.left;
window.y = document.getElementById("cr001").style.top;
moveImage();
}
and then attach that to the body onload.
EDIT: ok, here is some modified code that does what you want. You can stick this in a file named index.html and launch it in Firefox. I broke it down for you:
<html>
<head>
<script language="javascript">
var d_x = 75;
var d_y = 100;
var interval = 2;
//init is used for getting things up and running once the page is loaded
function init(){
//optimization: only get the element once
var el = document.getElementById("cr001")
x = parseInt(el.style.left);
if(isNaN(x)){
//parseInt("") == NaN
x = 0;
}
y = parseInt(el.style.top);
if(isNaN(y)){
//ditto
y = 0;
}
//call the nuts of this script
moveImage();
}
//this is mostly unchanged
function moveImage() {
if(x < d_x){
x = x + interval;
}else{
//lets keep looping just for fun!
x = 0;
}
if(y < d_y){
y = y + interval - 1; //move y by only 1px
}else{
y = 0;
}
//optimization: only get the element once
var el = document.getElementById("cr001")
el.style.left = x + 'px'; //dont forget to add 'px' back in
el.style.top = y + 'px';
//loop, don't use strings in setTimeout since this is basically eval...eval is evil
setTimeout(moveImage, 100);
}
</script>
</head>
<body onload="init()">
<div id="container">
<!-- IMPORTANT: POSITION IS ABSOLUTE -->
<div id="cr001" style="position:absolute; width:10px; height:10px; background-color:black"></div>
</div>
</body>
The problem is here:
document.getElementById("cr001").style.left
This actually returns the css value, which is a string for example '100px' or '10%' etc. Yet, later on your code, you use this value as if it was an integer.
You have an unclosed div. You open <div id="container"> and <div id="cr001" class="twinkles"> but only close one of them
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)
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.
Now I have working on window load code, but can't make it work with window resize (height values will increase if I repeat the same function for resize event). Array is to show initial values after onload completed.
var arr = [];
window.onload = function() {
var newsBlocks = document.getElementsByClassName('news');
for (var i = 0; i < newsBlocks.length; i++) {
var newsBlock = newsBlocks[i];
var left = newsBlock.getElementsByTagName('article')[0];
var right = newsBlock.getElementsByTagName('article')[1];
var height = Math.max(left.offsetHeight, right.offsetHeight);
left.style.height = right.style.height = height.toString() + 'px';
arr.push(left.style.height);
console.log(arr);
}
};
Here is html:
<div class="main">
<section class="news">
<article>
<img src="images/t.png">
<h2>Heading</h2>
test text
</article>
<article>
<img src="images/t.png">
<h2>Heading</h2>
a lot of test text here
</article>
</div>
Pure JavaScript solution is appreciated. Thanks in advance for a help!
You should re-organize your code to be able to repaint the whole screen any time, and hook on the resize event, see: JavaScript window resize event
Resize event is called also on mobile devices, when they change orientation.
<div id=div1></div>
<script>
div1.style.height = (your preffered height)
</script>
same you can do with width.
it works for me ...
try the following code. It is working for me.
var buffer = 20; //scroll bar buffer
var divId = document.getElementById('yourDivID');
function pageY(elem) {
return elem.offsetParent ? (elem.offsetTop + pageY(elem.offsetParent)) : elem.offsetTop;
}
function resizeDiv() {
var height = document.documentElement.clientHeight;
height -= pageY(divId) + buffer;
height = (height < 0) ? 0 : height;
divId.style.height = height + 'px';
}
window.onresize = resizeDiv;
I'm making a scrolling comment section, it works by having several elements echoed by php have their top property animated with javascript. Everything seems to be working fine except when I set their position to absolute and use javascript simultaneously, this results in text-align:center only working whenever there is more than one line in the text. Here is my code:
HTML (Roughly goes like this, is echoed through PHP, also apologies for the inline styling)
<div id="element0" style="position:absolute;text-align:center;">Hello world!</div>
<div id="element1" style="position:absolute;text-align:center;">Hello world!</div>
<div id="element2" style="position:absolute;text-align:center;">Hello world!</div>
<div id="element3" style="position:absolute;text-align:center;">Hello world!</div>
Javascript
var offset = 0;
var i = 0;
for(i = 0; i < 3; i++) {
obj = document.getElementById("element" + i);
obj.style.top = offset + "px";
offset += obj.clientHeight;
}
function moveComments() {
var i1 = 0;
for(i1 = 0; i1 < 3; i1++) {
obj = document.getElementById("element" + i1);
obj.style.top = parseInt(obj.style.top) - 1 + 'px';
if(parseInt(obj.style.top) <= -offset)
obj.style.top = offset + 100 + "px";
}
}
setInterval(moveComments, 10);
position: absolute causes the element's width to automatically shrink to fit its content.
text-align: center centers text within the bounds of the block element.
If the block element is not wider than the text, it won't do anything.
You need to give it a larger width.
I'm trying to create a div 'floater' which acts similar to a fixed div (stuck in a specific position regardless of scrolling), but when it hits the boundaries of the div it is within, it stops being fixed.
When the scrollbar is at the top, it should have the div placed at 0 within the containing div (positioned say 100 pixels from the top) and when the scrollbar reaches the bottom, it should prevent the floater from going outside the container. The height of the floater would be static, but the container height would be dynamic.
I've seen this type of this all over the place, but can't figure out how to find a good example for it.
I'd like to avoid jQuery if possible, as I imagine it should only require some simple JavaScript to determine the current position relative to the div it is within.
Thank you.
Okay folks, here is a complete solution. I've only tested this in Firefox and IE, but it should work across the board (I think). This is straight JavaScript and jQuery is not used. The first JS function makes sure the height returned works in various browsers.
Edit - I improved on this, see below.
<html>
<head>
<style type="text/css">
* {margin:0;padding:0;}
#header {height:300px;width:100%;background:#888;}
#main {height:800px;width:70%;background:#eee;float:left;}
#side {width:30%;height:auto;background:#ddd;float:left;position:relative;}
#floater {height:400px;width:90%;background:#dcd;top:0px;position:absolute;}
#footer {height:300px;width:100%;background:#888;clear:both;}
</style>
<script>
function getPageY() {
var height = 0;
if(typeof(window.pageYOffset) == 'number') {
height = window.pageYOffset;
}
else if(document.body && document.body.scrollTop) {
height = document.body.scrollTop;
}
else if(document.documentElement && document.documentElement.scrollTop) {
height = document.documentElement.scrollTop;
}
return height;
}
onload=function() {
window.onscroll = scroll;
function scroll() {
ybox.value = "this: "+getPageY();
var f = document.getElementById("floater");
var y = getPageY()-300; // minus header height
var divh = document.getElementById("main").offsetHeight;
if (divh > 400) { // greater than floater height
divh -= 400; // minus floater height
if (y < 0) y = 0;
else if (y > divh) y = divh;
f.style.top = y+"px";
}
}
}
</script>
</head>
<body>
<div id="header"></div>
<div id="main"></div>
<div id="side"><div id="floater">Float Content<br />
<input name="ybox" id="ybox"></div></div>
<div id="footer"></div>
</body>
</html>
This works, but with images it is extremely jumpy. I modified it to use a fixed position when it should be stuck in a position. Replace the three matching lines with this for a smoother result:
if (y < 0) {y = 0;f.style.position = "absolute";}
else if (y > divh) {y = divh;f.style.position = "absolute";f.style.top = divh+"px";}
else {f.style.position = "fixed";f.style.top = 0;}
I've implemented this and its pretty good. http://net.tutsplus.com/tutorials/html-css-techniques/creating-a-floating-html-menu-using-jquery-and-css/. But this is done using jquery only. Ill let you know if icome across any links with just plain javascript.