Preload all sound and images before starting animation - javascript

I'm building a simple animation web app that involves sound and images. I want it so that when a user enters the site they see a "now loading" page, and when all the images and audio files are done loading it calls a function that starts the animation. So far the code I have is roughly this:
var img1, img2;
var sound1, sound2;
function loadImages() {
img1=new Image();
img1.src="...";
img2=new Image();
img2.src="...";
img1.onload=img2.onload=handleImageLoad;
}
function loadSound() {
createjs.Sound.registerSound({id:"sound1", src:"sound1.wav"});
createjs.Sound.registerSound({id:"sound2", src:"sound2.wav"});
createjs.Sound.addEventListener("fileload", handleSoundLoad);
}
function handleImageLoad(e) {
//Do something when an image loads
}
function handleSoundLoad(e) {
//Do something when a sound loads
if(e.id=="sound1") sound1 = createjs.Sound.createInstance("sound1");
else if(e.id=="sound2") sound2 = createjs.Sound.createInstance("sound2");
}
$(document).ready(function() {
//overlay a "now loading" .gif on my canvas
...
...
loadSound();
loadImages();
}
// call this when everything loads
function start() {
//remove "now loading..." overlay .gif
...
...
//start animating
}
handleImageLoad() and handleSoundLoad() are invoked independently of each other so I can't rely on them on calling start(). How can I figure out when everything is loaded? What callback function(s) can I use to achieve this?

Using the built-in SoundJS registerSound method is not bad, but PreloadJS will handle both Sounds and images (and other types) in a single queue. Check out the examples in the PreloadJS GitHub.
http://preloadjs.com and
http://github.com/CreateJS/PreloadJS/

This is probably not the best solution, but I did something similar this way:
var lSnd = false;
var lImg = false;
$(document).ready(function(){
setInterval(checkLoadComplete,1000);
});
function loadSound(){
//loadingSound
//on load complete call= soundLoadingComplite();
}
function soundLoadingComplite(){
//do some stuff
lSnd = true;
}
function loadImages(){
//loadingImages
//on load complete call= imageLoadingComplite();
}
function imageLoadingComplite(){
//do some stuff
lSnd = true;
}
function checkLoadComplete(){
if(lSnd&&lImg){
startAnimation();
//clear interval
}
}
Hope this helps.

I'd be doing it this way:
function loadSound(){
songOK = false;
song = new Audio()
song.src = uri;
song.addEventListener('canplaythrough', function(){ songOK = true; }, false)
return songOK;
}
function loadImage(){
pictOK = false;
pict = new Image();
pict.src = uri;
pict.onload = function (){
pictOK = true;
}
return pictOK;
}
function loadMedia(){
startNowLoading();
if( loadSound() && loadImage())
stopNowLoading();
else
kaboom(); //something went wrong!
}
$(document).ready(function(){
loadMedia();
}
This should allow you to execute the functions in sequence.

Related

Stop JavaScript function after 3 seconds

Heyo,
I want to call a function that disables the scrollwheel while the Preloader is shown. But after the Preloader is gone, the scrollwhell should be usable again.
I got the function which disables the scrollwheel allready. Now I need a simple code which makes it run only the first 3 seconds.
My anitscrollwheel function looks like so: window.onwheel = function(){ return false; }
Try this:
<script type="text/javascript">
var wheelEnabled = false;
window.onwheel = function() { return wheelEnabled; }
setTimeout(function() {
wheelEnabled = true;
}, 3000);
</script>
You can do something like that
var enable_scroll = false;
//When preloader ends, set enable_scroll = true;
window.onwheel = function(){
if(enable_scroll == false) {
return false;
}
}

A JavaScript function is repeated many times

I have two function print and callPrint bellow. I click call function print the first time is right.
But when click call function print the second or third then function callPrint will be call 2 times or 3 times.
I have debug on attack file.
function print(url) {
console.log('print');
var _this = this, iframeId = 'iframeprint', $iframe = $('iframe#iframeprint');
if ($iframe.attr('src') != url) {
$.when(
$iframe.attr('src', 'about:blank'),
$iframe.load(function () {
console.log($iframe.prop('contentWindow').document.readyState);
})
).done(function () {
$iframe.attr('src', url);
$iframe.load(function () {
console.log('new');
_this.callPrint(iframeId);
});
});
} else {
console.log('old');
_this.callPrint(iframeId);
}
}
// initiates print once content has been loaded into iframe
function callPrint(iframeId) {
console.log('callPrint');
$('div.wait').hide();
var PDF = document.getElementById(iframeId);
PDF.focus();
PDF.contentWindow.print();
return false;
}
A JavaScript function is repeated many times
The problem is because you're attaching two new load() event handlers to the iframe every time print() is called. To fix this, add a single load() event handler and call your function from in there. This will be triggered whenever you update the src attribute on the element. Try this:
var $iframe = $('#iframeprint').load(function() {
// You'll need to make sure the function is in scope of the handler
// There's not enough information in the OP for me to show you how
callPrint('iframeprint');
});
function print(url) {
var _this = this;
if ($iframe.attr('src') != url) {
$iframe.attr('src', url);
} else {
_this.callPrint(iframeId);
}
}
Thanks "Rory McCrossan". I add setTimeout function when callPrint so dialog print will open. But I can't vote for you at the moment.
var $iframe = $('iframe#iframeprint').load(function () {
// You'll need to make sure the function is in scope of the handler
// There's not enough information in the OP for me to show you how
setTimeout(function () {
callPrint('iframeprint');
}, 100);
});
function print(url) {
if ($iframe.attr('src') != url) {
$iframe.attr('src', url);
} else {
console.log('old');
callPrint('iframeprint');
}
}
// initiates print once content has been loaded into iframe
function callPrint(iframeId) {
$('div.wait').hide();
var PDF = document.getElementById(iframeId);
PDF.focus();
PDF.contentWindow.print();
}

How to have multiple instances of a jQuery plugin

I am trying to create a SoundCloud music player. It can play any track from SoundCloud, but this plugin is only working if there is only one instance of it in the page. So it wont work if two of the same plugin are in the page.
Here is an example of having two players in the page: JSFiddle
var trackURL = $(".player").text();
$(".player").empty();
$(".player").append("<div class='playBTN'>Play</div>");
$(".player").append("<div class='title'></div>");
var trackId;
SC.get('/resolve', { url: trackURL }, function (track) {
var trackId = track.id;
//var trackTitle = track.title;
$(".title").text(track.title);
$(".playBTN").on('click tap', function () {
//trackId = $(".DSPlayer").attr('id');
stream(trackId);
});
// first do async action
SC.stream("/tracks/" + trackId, {
useHTML5Audio: true,
preferFlash: false
}, function (goz) {
soundToPlay = goz;
sound = soundToPlay;
scTrack = sound;
//updater = setInterval( updatePosition, 100);
});
});
var is_playing = false,
sound;
function stream(trackId) {
scTrack = sound;
if (sound) {
if (is_playing) {
sound.pause();
is_playing = false;
$(".playBTN").text("Play");
} else {
sound.play();
is_playing = true;
$(".playBTN").text("Pause");
}
} else {
is_playing = true;
}
}
If you remove any of these div elements that hold the .player class, the other element will work. So it only doesn't work because there are two instances of the same plugin.
How can I fix it? to have multiple instances of the player in one page?
I have identified the problem. It has to do with the fact that you are trying to load multiple tracks at the same time, but have not separated the code to do so.
As #Greener mentioned you need to iterate over the .player instances separately and execute a SC.get() for each one of them.
Here is what I see happening that is causing the problem:
var trackURL = $(".player").text();
^The code above returns a string that contains both of the URLs you want to use back-to-back without spaces. This creates a problem down the road because of this code:
SC.get('/resolve', { url: trackURL }, function (track) {...
That is a function that is trying to load the relevant song from SoundCloud. You are passing it a variable "trackURL" for it to try and load a specific URL. The function gets a string that looks like "URLURL" what it needs is just "URL".
What you can do is iterate over all the different ".player" elements that exist and then call the sounds that way. I modified your script a little to make it work using a for loop. I had to move the "empty()" functions into the for loop to make it work correctly. You have to use .eq(index) when referring to JQuery array of elements.
Like this:
var trackURL
var trackId;
for(index = 0; index < $(".player").length; index++){
trackURL = $(".player").eq(index).text();
//alert(trackURL);
$(".player").eq(index).empty();
$(".player").eq(index).append("<div class='playBTN'>Play</div>");
$(".player").eq(index).append("<div class='title'></div>");
SC.get('/resolve', { url: trackURL }, function (track) {
var trackId = track.id;
alert(track.id);
//var trackTitle = track.title;
$(".title").eq(index).text(track.title);
$(".playBTN").eq(index).on('click tap', function () {
//trackId = $(".DSPlayer").attr('id');
stream(trackId);
});
// first do async action
SC.stream("/tracks/" + trackId, {
useHTML5Audio: true,
preferFlash: false
}, function (goz) {
soundToPlay = goz;
sound = soundToPlay;
scTrack = sound;
//updater = setInterval( updatePosition, 100);
});
});
}
This is not a completely finished code here, but it will initiate two separate songs "ready" for streaming. I checked using the commented out alert what IDs SoundCloud was giving us (which shows that its loaded now). You are doing some interesting stuff with your streaming function and with the play and pause. This should give you a good idea on what was happening and you can implement your custom code that way.

Load Image and Fade In, but in sequential way

I'm trying to load my images and fade in. Its working. But lets suppose that I have 4 images. Right now, my script its working by loading the last image, not the first. How can I make my js load the first image, and just start loading the second after the first has been loaded?
Here's my code:
$(function(){
$("a").click(function(){
$("#load").load('load.html', function() {
$('#load img').hide();
alert($("#load img").length);
$('#load img').each( function(){
$(this).on('load', function () {
$(this).fadeIn();
});
});
});
return false;
});
});
See http://jsfiddle.net/5uNGR/15/
Try something where you are not trying to perform a fadeIn on each image as they load, but test the ok-ness of the next image in your animation queue each time ANY load event happens, then on the animation callback, see if the next one is ready. Here is a script that should work.
BTW, see http://www.sajithmr.me/javascript-check-an-image-is-loaded-or-not for more on image readiness testing.
$(function () {
// util fn to test if image loaded properly
var isImgLoadOk = function (img) {
if (!img.complete) { return false; }
if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) {
return false;
}
return true;
};
$("a").on('click', function () {
$("#load").load('load.html', function () {
var imgs = $('#load img').hide(), //create image array and hide (chaining)
animIndex = 0, //position in the animation queue
isFading = false; //track state of whether an animation is in prog
// this is a load handler AND is called in the fadeIn callback if
// not at last image in the collection
var fadeNextImg = function () {
// make sure a load event didn't happen in the middle of an animation
if (isFading) return;
// last image in animation queue?
var isLast = animIndex == imgs.length - 1;
// get the raw image out of the collection and test if it is loaded happily
var targetImage = imgs[animIndex];
if (isImgLoadOk(targetImage)) {
// jQuery-up the htmlImage
targetImage = $(targetImage);
// increment the queue
animIndex++;
// set animation state - this will ignore load events
isFading = true;
// fade in the img
targetImage.fadeIn('slow', function () {
isFading = false;
// test to see if next image is ready to load by
// recursively calling the parent fn
if (!isLast) fadeNextImg();
});
}
};
imgs.on('load', fadeNextImg);
});
return false;
});
});
Ron's solution is a little over-engineered IMO. If your intention is indeed to load all of the images before the animation starts, then you could do something similar to the following:
$(function(){
$("a").click(function(){
$("#load").load('load.html', function() {
$('#load img').hide(); // I would recommend using css to hide the image instead
alert($("#load img").length);
$("#load img").each(function(i, image) {
setTimeout(function() { // For each image, set increasingly large timeout before fadeIn
$(this).fadeIn();
}, 2000 * i);
});
});
return false;
});
});

JavaScript audio not playing outside of jQuery function

I know the question title doesn't make much sense, but I can't think of a better way to put it. I am a newbie to jQuery and I'm using this code to fade in a <div> and play a sound:
$(document).ready(function(){
$('#speech').fadeIn('medium', function() {
play('msg_appear');
var sptx = $('<p class="stext">').text('There is nothing here.');
$('#speech').append(sptx);
$('.stext').typeOut({marker: '', delay: 22});
});
});
This code runs fine however the sound plays after the fade-in is complete. I wanted it to play while it was fading in, so I tried placing the play() call outside of the fade-in function like this:
$(document).ready(function(){
play('msg_appear');
$('#speech').fadeIn('medium', function() {
However, now it's not playing at all. There's no errors on the JavaScript console so I'm unsure if it's a syntax error, and probably something obvious, but I don't know what.
play() is a function I found to play audio, here it is if it matters at all. I placed it in the same file the above code is; right above the $(document).ready().
function play(sound) {
if (window.HTMLAudioElement) {
var snd = new Audio('');
if(snd.canPlayType('audio/ogg')) {
snd = new Audio(sound + '.ogg');
}
else if(snd.canPlayType('audio/mp3')) {
snd = new Audio(sound + '.mp3');
}
snd.play();
}
else {
alert('HTML5 Audio is not supported by your browser!');
}
}
Based on the comments, I'd recommend modifying the play() function you found:
function play(sound, callback) {
if (window.HTMLAudioElement) {
var snd = new Audio('');
if(snd.canPlayType('audio/ogg')) {
snd = new Audio(sound + '.ogg');
}
else if(snd.canPlayType('audio/mp3')) {
snd = new Audio(sound + '.mp3');
}
if(typeof(callback)=="function"){
snd.addEventListener("canplay", function(){
snd.play();
callback();
});
} else {
snd.addEventListener("canplay", function(){
snd.play();
});
}
snd.load();
}
else {
alert('HTML5 Audio is not supported by your browser!');
}
}
Then call it like:
play('msg_appear', function(){
$('#speech').fadeIn('medium', function() {
var sptx = $('<p class="stext">').text('There is nothing here.');
$('#speech').append(sptx);
$('.stext').typeOut({marker: '', delay: 22});
});
});
That way the audio's play(); won't fire until after the audio can start playing, and the fadeIn() will be started at the same time as the audio.
And of course, the callback isn't necessary; it just makes for more robust timing in varying network conditions.
I can only think that $(document).ready is too early to allow play to happen (in whichever browser is exhibiting this problem), when not delayed by the fadeIn.
Try :
$(window).on('load', function(){
play('msg_appear');
$('#speech').fadeIn('medium', function() {
var sptx = $('<p class="stext">').text('There is nothing here.');
$('#speech').append(sptx);
$('.stext').typeOut({marker: '', delay: 22});
});
});
EDIT:
If necessary, you can introduce further delay as follows:
$(window).on('load', function(){
setTimeout(function() {
play('msg_appear');
$('#speech').fadeIn('medium', function() {
var sptx = $('<p class="stext">').text('There is nothing here.');
$('#speech').append(sptx);
$('.stext').typeOut({marker: '', delay: 22});
});
}, 1000);//adjust up/down to the minimum reliable value
});
First of all, see: HTML5 Audio onLoad
There are some ways to handle loading state. The accepted answer looks weird though.
I recommend code like this:
function makePlayer(sound){
if (window.HTMLAudioElement) {
var snd = new Audio('');
if(snd.canPlayType('audio/ogg')) {
snd = new Audio(sound + '.ogg');
}
else if(snd.canPlayType('audio/mp3')) {
snd = new Audio(sound + '.mp3');
}
return function(){
snd.play();
};
}
};
var play = makePlayer('msg_appear');
$(document).ready(function(){
$('#speech').fadeIn('medium', function() {
play();
var sptx = $('<p class="stext">').text('There is nothing here.');
$('#speech').append(sptx);
$('.stext').typeOut({marker: '', delay: 22});
});
});

Categories