Jump to content

[SOLVED] Animation issues


KevinM1

Recommended Posts

I'm currently trying my hand at simple JavaScript animation since I don't know Flash.  Unfortunately, I cannot get a simple test script to work properly.  The JavaScript is:

 

var W3CDOM = (document.createElement && document.getElementsByTagName);

function init(){
   if (!W3CDOM) return;
   var scrollImage = document.getElementById('scrollImage');
   scrollImage.style.left = '2px'; //reset position on every page view, just in case
   animate(scrollImage);
}

function animate(scrollImage){
   scrollImage.style.left = parseInt(scrollImage.style.left) + 10 + 'px';
   setTimeout(animate, 2000);
}

window.onload = init;

 

With this code, I keep getting a "scrollImage.style has no properties" error in Firefox, and something similar in IE.  This isn't the case, though, as I have some simple CSS defined for it:

 

#scrollImage {
   position: absolute;
   left: 2px;
}

 

Here's the thing: I can get it to work in IE if I don't pass the image to the function.  This results in scrollImage being undefined in Firefox, leading me to believe my main problem is one of scope.  Unfortunately, I'm not sure how to work around it (I thought that passing the image to the function would fix it, but instead it broke the script in both browsers).  Any ideas?

 

Thanks! :)

Link to comment
Share on other sites

Well, I'm getting closer.  I was able to get it working by doing the following:

 

var W3CDOM = (document.createElement && document.getElementsByTagName);

function init(){
   if (!W3CDOM) return;
   var scrollImage = document.getElementById('scrollImage');
   scrollImage.style.left = '2px'; //reset position on every page view, just in case
   animate(scrollImage);
}

function animate(scrollImage){
   scrollImage.style.left = parseInt(scrollImage.style.left) + 10 + 'px';
   setTimeout(animate(scrollImage), 2000);
}

window.onload = init;

 

Now I'm having problems making a looping animation.  Here's what I'm trying to do: slide an image 500 px to the right, then, once it gets there, start over.  I tried the following code:

 

var W3CDOM = (document.createElement && document.getElementsByTagName);

function init(){
   if (!W3CDOM) return;
   var scrollImage = document.getElementById('scrollImage');
   var count = 500;
   animate(scrollImage, count);
}

function animate(scrollImage, count){
   if(count != 0){
      scrollImage.style.left = parseInt(scrollImage.style.left) + 1 + 'px';
      --count;
      setTimeout(animate(scrollImage, count), 200);
   } else{
      count = 501;
      scrollImage.style.left = '2px';
      setTimeout(animate(scrollImage, count), 200);
   }
}

window.onload = init;

 

But Firebug is saying I have too much recursion going on.  What I'd ultimately like to do is this:

 

Have the image move 500px to the right.  Once it's there, wait several seconds before restarting the loop.  So, I'm thinking that using one function with a timeout, with a nested interval function which would return after the count reaches zero is the way to go, but I'm not 100% sure how to code it up.  Any ideas?

Link to comment
Share on other sites

Well, here's what I have so far:

 

var W3CDOM = (document.createElement && document.getElementsByTagName);

function init(){
   if (!W3CDOM) return;
   var scrollImage = document.getElementById('scrollImage');
   animationController(scrollImage);
}

function animationController(scrollImage){
   var count = 500;
   var intervalId = setInterval("animate(scrollImage, count)", 200);
   setTimeout("animationController(scrollImage)", 3000);
}

function animate(scrollImage, count){
   if(count != 0){
      scrollImage.style.left = parseInt(scrollImage.style.left) + 1 + 'px';
      count--;
   } else{
      scrollImage.style.left = '2px';
      return;
   }
}

window.onload = init;

 

Unfortunately, it's not working.  Specifically, Firebug keeps informing me that scrollImage is undefined in the animate function.  I'm at a bit of a loss, so any help would be appreciated.

Link to comment
Share on other sites

I think I'm another step closer.  My current code (with a couple alerts for debugging):

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function init(){
   if (!W3CDOM) return;
   animationController();
}

function animationController(scrollImage){
   var intervalId = setInterval(animate, 200);
   setTimeout(animationController, 3000);
}

function animate(){
   var scrollImage = document.getElementById('scrollImage');

   alert("Do I have the image: " + scrollImage);
   alert("Left value: " + scrollImage.style.left);

   if(count != 0){
      scrollImage.style.left = parseInt(scrollImage.style.left) + 1 + 'px';

      alert("Left value: " + scrollImage.style.left);

      count--;
   } else{
      scrollImage.style.left = '2px';
      count = 500;
      return;
   }
}

window.onload = init;

 

I hate the idea of using a global variable (count), but, so far, that's the only way I can come up with a possible solution to the counting issue.  I can't seem to pass values to the functions in the setTimeout/setInterval functions, so this is the workaround I've come up with at the moment.

 

My problem now is that, for some reason, the script can't parse the image's style property.  For reference, my CSS is:

#scrollImage {
   position: absolute;
   left: 2px;
}

 

Yet, my script can't seem to get a handle on that property.  I AM getting a hold of the image itself, though, as the first alert box comes back okay.  Again, any help would be appreciated.

Link to comment
Share on other sites

 

can you post your entire code (with html and javascript); that way I can get a better concept of your problem, by viewing your demo?

 

Well, like I said, this is just a test script, so virtually all of the code has already been shown....

 

HTML (test.html):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>scroll test</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
<script type="text/javascript" src="scroll.js"></script>
</head>

<body>
<img src="../Bergeron_Patrice.jpg" alt="" id="scrollImage" />
</body>

</html>

 

CSS (styles.css):

#scrollImage {
   position: absolute;
   left: 2px;
}

 

JavaScript (scroll.js):

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function init(){
   if (!W3CDOM) return;
   animationController();
}

function animationController(scrollImage){
   var intervalId = setInterval(animate, 200);
   setTimeout(animationController, 3000);
}

function animate(){
   var scrollImage = document.getElementById('scrollImage');

   alert("Do I have the image: " + scrollImage);
   alert("Left value: " + scrollImage.style.left);

   if(count != 0){
      scrollImage.style.left = parseInt(scrollImage.style.left) + 1 + 'px';

      alert("Left value: " + scrollImage.style.left);

      count--;
   } else{
      scrollImage.style.left = '2px';
      count = 500;
      return;
   }
}

window.onload = init;

Link to comment
Share on other sites

 

your going to have to add your css style inline or with javascript for your "scrollImage" image's style. that is how javascript recognizes the style of the element. here is the your code below; I changed it around a little bit; so that it would not throw errors.

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>scroll test</title>

<script>
var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function init(){
   if (!W3CDOM) return;
   animationController();
}

function animationController(scrollImage){
   var intervalId = setInterval("animate()", 200);
   setTimeout("animationController()", 3000);
}

function animate(){
   var scrollImage = document.getElementById('scrollimage');
   var amount = document.getElementById('scrollimage').style.left;

   alert("Do I have the image: " + scrollImage.id);
   alert("Left value: " + amount);

   if(count != 0){
      amount = parseInt(amount) + 1 + 'px';

      alert("Left value: " + amount);

      count--;
   } else{
      scrollImage.style.left = '2px';
      count = 500;
      return;
   }
}

window.onload = init;
</script>
</head>

<body>
<img id="scrollimage" src="Bergeron_Patrice.jpg" alt="" style="position:absolute;left:2px" />
</body>

</html>

Link to comment
Share on other sites

Just want to point out that for cases like this where you are going to be dynamically changing absolute position values, DIVs are the best way to go.

 

<img id="scrollimage" src="Bergeron_Patrice.jpg" alt="" style="position:absolute;left:2px" />

 

So instead of that, try this:

 

<div id="scrollimage">
<img id="scrollimage_holder">
</div>

<script type='text/javascript'>
document.getElementById("scrollimage").style.position = 'absolute';
document.getElementById("scrollimage").style.left = '2px';
document.getElementById('scrollimage_holder").src = 'Bergeron_Patrice.jpg';
</script>

 

I can guarantee that this will work much better (since absolute positioning was made for divs and not for images :-o) I remember getting this error in FF way back then, and I believe it's because of its "standards" for CSS. For example, a textarea could have a width and height, but FireFox will show errors when JavaScript tries to manipulate these (although it renders normally inline) while IE will not recognize width and height for textareas.

 

You can also control initial values for this div with simple javascript, if you want to keep the html simple, otherwise, just use inline attributes like previously mentioned.

Link to comment
Share on other sites

The good news is that my parse errors are gone.  The bad news is that I have a logic error, so no animation is happening.  My code is below:

 

HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>scroll test</title>
<script type="text/javascript" src="scroll.js"></script>
</head>

<body>
<div id="container">
   <div id="scroll" style="position: absolute; left: 2px; width: 97px;">
      <img src="../Bergeron_Patrice.jpg" alt="" />
   </div>
</div>
</body>

</html>

 

JavaScript:

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function init(){
   if (!W3CDOM) return;
   var timeoutId = setTimeout("animationController()", 3000);
}

function animationController(){
   var intervalId = setInterval("animate()", 200);
}

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   alert("Do I have the div: " + scroll);
   alert("Do I have the left-side: " + left);

   if(count != 0){
      left = parseInt(left) + 1 + 'px';
      count--;
   } else{
      left = '2px';
      count = 500;
      return;
   }
}

window.onload = init;

 

The strange thing is that both alerts are returning the right values -- I have access to the div, and it correctly reports that the left attribute is 2px.  However, it seems that the extra pixel is not being added to the left side, as each loop reports that the left is set at 2px, when it should be incrementing.  Is this just a case of me needing to set the value in the script itself and work with it that way, or is it possible for me to keep it as an inline style in the markup?

Link to comment
Share on other sites

Was going to edit my last post, but I guess I took too long.  New JavaScript code, same result as my last post:

 

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function init(){
   if (!W3CDOM) return;
   var mainIntervalId = setInterval("animationController()", 3000);
}

function animationController(){
   var animateIntervalId = setInterval("animate()", 200);
}

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   alert("Do I have the div: " + scroll);
   alert("Do I have the left-side: " + left);

   if(count != 0){
      left = parseInt(left) + 1 + 'px';
      count--;
   } else{
      left = '2px';
      count = 500;
      clearInterval(animateIntervalId);
   }
}

window.onload = init;

Link to comment
Share on other sites

That's easy to figure out why. This is probably one of the most common mistakes anyone can make (even an expert) and I've made it a lot myself, I admit.

 

You have scroll set to reference the div. You have left set to a value that's found for the div's left position. However, just setting "left" to a new value doesn't mean you're setting the div's LEFT position to a new value. All you need to do is add this line somewhere after you run through the script

 

scroll.style.left = left;

 

And it should update it correctly. Fixed function:

 

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   alert("Do I have the div: " + scroll);
   alert("Do I have the left-side: " + left);

   if(count != 0){
      left = parseInt(left) + 1 + 'px';
      count--;
   } else{
      left = '2px';
      count = 500;
      clearInterval(animateIntervalId);
   }
scroll.style.left = left;
}

Link to comment
Share on other sites

That's easy to figure out why. This is probably one of the most common mistakes anyone can make (even an expert) and I've made it a lot myself, I admit.

 

You have scroll set to reference the div. You have left set to a value that's found for the div's left position. However, just setting "left" to a new value doesn't mean you're setting the div's LEFT position to a new value. All you need to do is add this line somewhere after you run through the script

 

scroll.style.left = left;

 

And it should update it correctly. Fixed function:

 

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   alert("Do I have the div: " + scroll);
   alert("Do I have the left-side: " + left);

   if(count != 0){
      left = parseInt(left) + 1 + 'px';
      count--;
   } else{
      left = '2px';
      count = 500;
      clearInterval(animateIntervalId);
   }
scroll.style.left = left;
}

 

Ah, duh...I must've stared at the code for an hour, and that didn't jump out at me.  D'oh!

 

So, now I have the image moving, and the animation correctly loops.  There's only one more problem.  I want each loop to have a several second delay (in this case, 3 seconds).  Right now, the first loop is waiting 3 seconds before it begins (which I don't really want, but I can live with it), but each subsequent loop remains at the same speed, with no delay in between.  I know what the problem is...when I return, I'm only going up one level of scope instead of the necessary two to pulse another animationController() interval.  Updated code is below:

 

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function init(){
   if (!W3CDOM) return;
   var mainIntervalId = setInterval("animationController()", 3000);
}

function animationController(){
   var animateIntervalId = setInterval("animate()", 200);
}

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   if(count != 0){
      scroll.style.left = parseInt(left) + 1 + 'px'; //see below
      count--;
   } else{
      scroll.style.left = '2px'; //direct assigment in order to reset the loop
      count = 500;
      return;  //clearInterval did nothing...this only returns me to animationController().  I need to get to init()
   }
}

window.onload = init;

 

Any idea on how I can move back to init() from the else-block in animate()?

Link to comment
Share on other sites

First things first, if it was me, I'd get rid of the first two functions COMPLETELY. I see no purpose for them other then to keep making more intervals (quite ridiculous honestly).

 

Here's how I would do it, use the W3CDOM conditional as a means of adding a new "event" listener to your javascript:

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 500;

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   if(count != 0){
      scroll.style.left = parseInt(left) + 1 + 'px'; //see below
      count--;
   } else {
      scroll.style.left = '2px'; //direct assigment in order to reset the loop
      count = 500;
      clearInterval(mainIntervalId);
   }
}

if(W3CDOM && window.onload){var mainIntervalId = setInterval("animate()", 3000);animate();}//this piece of coding checks the conditional and makes sure the page has loaded, this SHOULD work

 

Now, it sets an interval that will repeat every 3 seconds (3000 milliseconds) and after 500 times, it will stop (it won't run anymore).

Link to comment
Share on other sites

Thanks for the reply.  I actually had a similar epiphany last night.  I've almost got it 100% where I want it, but now there's some overlapping div issues.

 

My ultimate goal was to create something of a window/mask that the image would move through.  So, the image(s...I plan on expanding this once I get 1 image to work correctly) wouldn't be visible until it moved into that 'open' area.  Now, I know how to do something like that using an element's background property, but trying to animate that seems a bit difficult to me at first blush, which is why I went the embedded div route.  This will probably make more sense after seeing my code:

 

HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>scroll test</title>
<script type="text/javascript" src="scroll.js"></script>
</head>

<body>
<div id="container" style="width: 500px; height: 125px; border: 1px solid black;">
   <div id="scroll" style="position: absolute; left: -97px; width: 97px;">
      <img src="../Bergeron_Patrice.jpg" alt="" />
   </div>
</div>
</body>

</html>

 

JavaScript:

var W3CDOM = (document.createElement && document.getElementsByTagName);

var count = 694;

function init(){
   if (!W3CDOM) return;
   var intervalId = setInterval("animate()", 200);
}

function animate(){
   var scroll = document.getElementById('scroll');
   var left = scroll.style.left;

   if(count != 0){
      scroll.style.left = parseInt(left) + 1 + 'px';
      count--;
   } else{
      scroll.style.left = '-97px';
      count = 694;
   }
}

window.onload = init;

 

If you use this code, you'll see that my image starts off the screen on the left, moves through the container div, then out the other side before resetting.  What I want it to do is not be visible until it starts moving through the container div.  I tried messing with the elements' z-indicies, but that won't work as there's no way I can think of to essentially make the container div a window/mask that allows the other layers to show through.

 

Other than that, it's working just as I had hoped.

Link to comment
Share on other sites

That's an interesting idea, huh... Never really realized that we cannot do anything like that.. without some hard work, sweat, and blood (well not really blood, but you get my point).

 

I have two ideas, the former being the harder one to implement.

 

Idea One: Use a table, 3 X 3 with the inner-most center cell being that "container" in which the image is revealed. This idea uses a literal interpretation of the "mask" or a hole in a box scheme.

 

Idea Two: Take two divs, place them on the left and right edges of the screen (wide enough to fit the image behind it comfortably). Use z-indexes to control visibility, so as the image moves from under one div, it is shown, then hides under the next one. This idea uses a figurative interpretation, it may appear to be a box, but it really isn't.

 

**Note, if you want to do multiple images, you DO NOT need multiple divs. Just use a javascript:

document.getElementById("someImage").src = 'some_new_src.jpg';

 

and have that run for the loops (just go right through an array of those images, etc...)

Link to comment
Share on other sites

I'm trying to get idea 2 to work, but it appears as though the z-indicies aren't working:

 

HTML (JavaScript is the same as last time):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>scroll test</title>
<script type="text/javascript" src="scroll.js"></script>
</head>

<body>
<div id="container" style="width: 500px; height: 125px; position: absolute; padding: 0; margin: 0; top: 2px; left: 2px; z-index: 1; border: 1px solid black;">
   <div id="scroll" style="position: absolute; left: -97px; width: 97px; z-index: 2;">
      <img src="../Bergeron_Patrice.jpg" alt="" />
   </div>
</div>
<div id="mask" style="width: 500px; height: 125px; position: absolute; padding: 0; margin: 0; top: 2px; left: 504px; z-index: 99; border: 1px solid blue;">
    
</div>
</body>

</html>

 

As the image scrolls, I want it to hide behind the 'mask' div, but it's not disappearing.  I'm not sure what I'm doing wrong, as I made all the divs absolutely positioned, which, according to what I've read, is the only way to get z-indicies to work.  And, to add to my frustration, it fails in both IE and Firefox.

Link to comment
Share on other sites

I only see one mask?

 

How are your masks working?

 

Left-Right side masks, Top-Bottom masks?

 

The z-indexes work they way they're supposed to, you may not have the image anywhere in the vicinity of the div. Add borders to both elements so you can physically see the overlap.

Link to comment
Share on other sites

I only see one mask?

 

How are your masks working?

 

Left-Right side masks, Top-Bottom masks?

 

The z-indexes work they way they're supposed to, you may not have the image anywhere in the vicinity of the div. Add borders to both elements so you can physically see the overlap.

 

Yeah, I only made one mask div to see if I could get the simplest case to work.  I've already put in borders, but they didn't shed any light on the situation.  You should probably take a look at my test page: http://www.nightslyr.com/scroll/test.html.  The black-bordered div is the 'window' area.  The blue-bordered div is the part that the scrolling image is supposed to hide behind.  Right now, it's acting as though all elements have the same z-index.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.