javascript animation sometimes works - javascript

I'm trying to make pacman move without using jquery.animation because I want more control. so I'm using setInterval, but it only works sometimes. if you refresh enough, it will eventually "click on" and work fine, but if you refresh again, it won't work, it's here http://pacman.townsendwebdd.com if you want to look at it, thank you
//earlier in the code
this.moveInterval = setInterval(_this.move, 40, _this);
move: function(_this)
{
if(_this.pause)//set to true for now
return false;
var horz = 0;
var vert = 0;
var dir = _this.dir;
//set horizontal and vertical directions
if(dir % 2 == 0)
horz = dir - 1;
else
vert = dir - 2;
_this.top += vert;
_this.left += horz;
$('#pacman').css('top', _this.top);
$('#pacman').css('left', _this.left);
},

I'm not sure if this will fix the problem, but I would recommend using request animation frame instead of setInterval.
The other thing I think would be the problem (and I've been stung by this too) is that you're possibly trying to start the animation before the page has fully loaded. Try putting your code into a function and calling it with the onload attribute of the body tag.
Good luck!
Griffork.

Related

Seamless HTML5 Video Loop

I have searched extensively to find a solution to this but have not succeeded.
I have created a 4 second video clip that loops seamlessly in an editor.
However when the clip runs in a page via Safari, Chrome or Firefox there is a small but noticeable pause in the playback from end back to beginning.
I have tried using the loop and preload attributes both together and independently.
I have also tried the following javascript:
loopVid.play();
loopVid.addEventListener("timeupdate", function() {
if (loopVid.currentTime >= 4) {
loopVid.currentTime = 0;
loopVid.play();
}
}
But in all cases the momentary pause remains and spoils the effect.
I'm open to any ideas?
Since this question is a top search result in Google, but doesn't "technically" have an answer yet, I'd like to contribute my solution, which works, but has a drawback. Also, fair warning: my answer uses jQuery.
It seems the slight pause in the video loop is because it takes time for html5 video to seek from one position to another. So it won't help anything to try to tell the video to jump to the beginning when it ends, because the seek will still happen. So here's my idea:
Use javascript to clone the tag, and have the clone sit hidden, paused, and at the beginning. Something like this:
var $video = $("video");
var $clone = $video.clone();
$video.after($clone);
var video = $video[0];
var clone = $clone[0];
clone.hidden = true;
clone.pause();
clone.currentTime = 0;
Yes, I used clone.hidden = true instead of $clone.hide(). Sorry.
Anyway, after this the idea is to detect when the original video ends, and then switch to the clone and play it. That way there is only a change in the DOM as to which video is being shown, but there is actually no seeking that has to happen until after the clone starts playing. So after you hide the original video and play the clone, you seek the original back to the beginning and pause it. And then you add the same functionality to the clone so that it switches to the original video when it's done, etc. Just flip flopping back and forth.
Example:
video.ontimeupdate = function() {
if (video.currentTime >= video.duration - .5) {
clone.play();
video.hidden = true;
clone.hidden = false;
video.pause();
video.currentTime = 0;
}
}
clone.ontimeupdate = function() {
if (clone.currentTime >= clone.duration - .5) {
video.play();
clone.hidden = true;
video.hidden = false;
clone.pause();
clone.currentTime = 0;
}
}
The reason I add the - .5 is because in my experience, currentTime never actually reaches the same value as duration for a video object. It gets pretty close, but never quite there. In my case I can afford to chop half a second off the end, but in your case you might want to tailor that .5 value to be as small as possible while still working.
So here's my entire code that I have on my page:
!function($){
$(document).ready(function() {
$("video").each(function($index) {
var $video = $(this);
var $clone = $video.clone();
$video.after($clone);
var video = $video[0];
var clone = $clone[0];
clone.hidden = true;
clone.pause();
clone.currentTime = 0;
video.ontimeupdate = function() {
if (video.currentTime >= video.duration - .5) {
clone.play();
video.hidden = true;
clone.hidden = false;
video.pause();
video.currentTime = 0;
}
}
clone.ontimeupdate = function() {
if (clone.currentTime >= clone.duration - .5) {
video.play();
clone.hidden = true;
video.hidden = false;
clone.pause();
clone.currentTime = 0;
}
}
});
});
}(jQuery);
I hope this will be useful for somebody. It works really well for my application. The drawback is that .5, so if someone comes up with a better way to detect exactly when the video ends, please comment and I will edit this answer.
I've found that Firefox will stutter while looping if I'm using mp4 or ogv files. I changed the code in my page to try using a webm file first instead, and suddenly the stutter was gone and the video looped seamlessly, or at least close enough that I didn't see an issue. If you haven't given that a shot, it could be worth it to try converting the file to a webm format and loading that instead.

setInterval, animating multiple images, stopping setInterval

I need to create some animation using DHTML/Javascript and I am struggling to get anything I do to work. My parameters are it must use the setInterval function, a user defined function and 8 jpg files. There must also be a way of stopping the animation.
If someone could get me pointed in the right direction I would be very happy. I have not been able to find suitable information on how to do this so far and I am still fairly new to Javascript. Thanks.
Sorry for not posting code earlier. It was such a mess I didn't want to embarrass myself. Here's what I have. It's not working.
var slideShow = ['images/pic0.jpg','images/pic1.jpg','images/pic2.jpg','images/pic3.jpg','images/pic4.jpg','images/pic5.jpg','images/pic6.jpg','images/pic7.jpg'];
picO = new Array();
for(i=0; i < slideShow.length; i++) {
picO[i] = new Image();
picO[i].src = slideShow[i];
}
var curPic = -1;
function changeImage(){
curPic = (++curPic > slideShow.length-1)? 0 : curPic;
imgO.src = picO[curPic].src;
setInterval(changeImage,100);
}
window.onload=function(){
imgO = document.getElementById("imgAnim");
changeImage();
}
var t=setTimeout(function(){alert("Welcome to my animated page")},3000)
The other thing it needs to do is pop up an alert box 3 seconds after the animation starts. It's doing that but it's popping up EVERY 3 seconds, which is not what I want.
Thanks for your help so far. I've done pretty well with my Javascript work lately but this one is just something I'm not that familiar with.
To the using of setInterval and stopping the animation
var animation = setInterval(yourAnimation,500); // run yourAnimation every 500ms
clearInterval(animation); // stop animation
To the animation
var slideShow = ["img1.jpg","img2.jpg", ... ,"img8.jpg"];
var counter = 0;
function yourAnimation() {someImage.src = slideShow[++counter%slideShow.length];}

Strange behaviour in Javascript; not showing div while calculating

I'm doing some pretty processor heavy processing on a few audio files. Before I go in to this function called startProcessing I want to show a div which overlays the entire page and says calculating...Problem is the div is only shown after the function has terminated. When I click the button which activates tis code the button freezes and only when the process function has terminated does it unfreeze and show the loader. Anyone seen similar behaviour and was able to solve it?
document.getElementById('loader').innerHTML = "<p>Calculating...</p><p>Please Wait</p><img src='../img/loader.gif' />";
document.getElementById('loader').style.visibility = "visible";
document.getElementById('notification').style.visibility = "visible";
var speed = document.getElementById("playbackSpeed").value/100;
console.log("Changing speed");
if (speed > 1.5){
startProcessing(1.5);
backend.playbackSpeed = 1.5;
} else if (speed < 0.75){
startProcessing(0.75);
backend.playbackSpeed = 0.75;
} else {
startProcessing(speed);
backend.playbackSpeed = speed;
}
You could throw the heavy processing into a Web Worker. That would free up your UI.
Note: Its not IE friendly... only IE10 (I think)
Try to run heavy calculations with some delay:
setTimeout(function(){
var speed = document.getElementById("playbackSpeed").value/100;
console.log("Changing speed");
speed = Math.min(Math.max(speed, 0.75), 1.5);
startProcessing(speed);
backend.playbackSpeed = speed;
}, 13);
One approach could be to use setTimeout or setInterval for your div showing the progress bar. Another way to get around it is doing some (pseudo) multithreading.

Earliest event to get an image's width

I've got some JavaScript to center images and <object>s on a page if they're over a threshold width. It also checks that certain classes haven't already been manually applied.
$('img,object').bind('load', function() {
w = $(this).width();
if (w > 400 && !( $(this).hasClass('inlineimage') | $(this).parent().hasClass('inlineimage') ))
$(this).css('margin', '10px ' + (parseInt((800-w)/2)-30) +'px');
});
It's horrific but the meaning behind this was all originally quite sane. The CMS doesn't make it easy to specify alignment and developing it to allow this would have taken significant time away from other jobs. A client-side hack works.
The only problem with it is that the JS waits until the whole image has loaded. Obviously this means that on slower networks, the page loads, the images start loading and some time later the images snap into position. Ugly.
But the browser seems to know the width of an image as soon as it starts to download it. I would really love to hook into this event and splat this visual bug.
Of course, if there's a CSS way of approaching this, I'm open to that too.
In browsers that support it, you can poll for natural dimensions:
var interval = setInterval( function() {
if( img.naturalWidth ) {
clearInterval(interval);
console.log( "Natural available: "+ (new Date - now );
console.log( img.naturalWidth, img.naturalHeight );
}
}, 0 );
In the demo here on uncached image I get:
Natural available: 782
62 71
Loaded: 827
So the real dimensions were available 50 milliseconds before load event. Unfortunately in IE, the readystate "loading" doesn't guarantee real dimensions.
Change the query string for the image before each test to ensure uncached.
Here's whatwg link on natural dimensions: http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#dom-img-naturalwidth
var span = document.getElementById('span'); // The parent span
var check = function (){
if(span.offsetWidth > 0){
console.log('Width while loading', span.offsetWidth);
}
else{
setTimeout(check, 100);
}
};
check();
​
Demo. This should show the width in the console while it's loading first, and then the width after it's loaded. That is as long as the image isn't cached. (If the demo doesn't work for someone, try changing the hoo part of the image URL to anything else)
In the interest of this still working on more than the latest browsers, I've cobbled together a best effort brute force. It waits 500ms between attempts and checks images to see if the current run through is the same width as the last time it tried.
As soon as the width for an image is the same in two consecutive passes, we run the centring code.
This uses arrays to keep track of things so we're not constantly raping the DOM nor are we querying items that aren't applicable (because they've already been dealt with or ruled out).
attempts = 0;
arr = [];
$.each($('img,object').not('inlineimage'), function(){
arr.push([this, -2, $(this).width()]);
});
checkImgs = function() {
attempts++;
newarr = []
$.each(arr, function(){
if ($(this[0]).parent().hasClass('inlineimage'))
return;
w = $(this[0]).width();
this[1] = this[2];
this[2] = w;
if (this[1] != this[2])
return newarr.push(this);
// We know this image is loaded enough now - we can do things!
if (w >= 400)
$(this[0]).css('margin', '10px ' + (parseInt((800-w)/2)-30) +'px');
});
arr = newarr;
if (arr.length && attempts < 6)
setTimeout(checkImgs, 500);
}
setTimeout(checkImgs, 500);
It's not beautiful but it seems to work both efficiently (CPU was getting hammered by some of my earlier attempts) and quickly (cached images spring into place within 500ms).

Why do these HTML5 images render (or not!) depending on how fast I refresh?

Use Firefox 10.0.2 to open Framework.html from this project: http://code.google.com/p/unitspeeds-vhh/ (EDIT: I'm now preloading the icons. Use this revision if you'd like to try to debug the original problem.)
Hit F5 to refresh.
Hit F5 a few more times very quickly.
Expected: The unit icons (unitIconObj in the code) should always render.Actual: They never render on the first page load. First F5 usually shows all icons. Some very fast repetitions of F5 cause most most -- but not all -- icons to show.
The basic problem I'm trying to solve is icons not rendering properly the first time, and I assume this means I need to be preloading the images. I've been trying a few different methods to do this, but the behavior is not strictly reproducible, and I think I just don't know enough about refreshes and caching to figure this out myself. The icons themselves are very small image files, so I'm surprised to see that this is an issue at all.
Very sorry for the messy code and question -- I'm a noob! Any advice would be welcome.
Edit: Here's the part where I load the image file and render it:
for (var x = 0; x < sortedOutput.length; x++)
{
// Draw the unit icon
var unitIconObj = new Image();
if (sortedOutput[x].Filename == "--") // I don't have real icons for a few units
{
unitIconObj.src = "Icons/Creep.jpg";
} else
{
unitIconObj.src = "Icons/" + sortedOutput[x].Filename + ".jpg";
}
speedContext.drawImage(unitIconObj, ChartBuffer+textBlock+2+4*iconSpace, 50+(x*iconSpace), BarHeight, BarHeight);
}
Have you tried changing this so it waits to call drawImage function until the onload event on the image fires. This will ensure that the image is loaded before any of the other magic happens.
for (var x = 0; x < sortedOutput.length; x++)
{
var unitIconObj= new Image();
unitIconObj.onload = function(){
speedContext.drawImage(unitIconObj, ChartBuffer+textBlock+2+4*iconSpace, 50+(x*iconSpace), BarHeight, BarHeight);
};
if (sortedOutput[x].Filename == "--") // I don't have real icons for a few units
{
unitIconObj.src = "Icons/Creep.jpg";
} else
{
unitIconObj.src = "Icons/" + sortedOutput[x].Filename + ".jpg";
}
}
found this here: https://developer.mozilla.org/en/Canvas_tutorial/Using_images

Categories

Resources