I am reading a jQuery book and trying to do an example. In the example lightning flashes on the screen, and that part works fine. The problem is that when you switch tabs, and then switch back, the lightning starts flashing in rapid succession. The problem is supposed to be fixed using the window.onblur and window.onfocus events, but it's not working. Can anybody see what I am doing wrong?
There are three hidden lightning pictures with different id's, and three different functions that make each one flash. goLightning() sets the interval for each function to go, and stopLightning() should clear that interval. That part is what seems not to be working for all I know. Here is the code:
$(document).ready(function(){
goLightning();
window.onblur = stopLightning;
window.onfocus = goLightning;
var int1; var int2; var int3;
// this function sets the lightning interval
function goLightning() {
int1 = setInterval(function() { lightning_one(); },4000);
int2 = setInterval(function() { lightning_two(); },5000);
int3 = setInterval(function() { lightning_three(); },7000);
}
// this function clears the lightning when the window isn't focused
function stopLightning() {
window.clearInterval(int1);
window.clearInterval(int2);
window.clearInterval(int3);
}
// these three functions make the lightning flash and seem to be working fine
function lightning_one() {
$("#container #lightning1").fadeIn(250).fadeOut(250);
}
function lightning_two() {
$("#container #lightning2").fadeIn(250).fadeOut(250);
}
function lightning_three() {
$("#container #lightning3").fadeIn(250).fadeOut(250);
}
});
I have no idea why this isn't working. It seems like stopLightning() isn't clearing the interval, or window.onblur isn't working. Anyway, any feedback would be helpful. Thanks!
Add stopLightning() to the beginning to goLightning(), before setting the new intervals.
Re-arrange the following lines:
goLightning();
window.onblur = stopLightning;
window.onfocus = goLightning;
var int1; var int2; var int3;
in to this instead:
var int1, int2, int3, w = window;
w.onblur = stopLightning;
w.onfocus = goLightning;
goLightning();
Next, use the variable w instead of window in the stopLightning() function to ensure you use a reference to the proper window. Also, as #Kolink mentioned, it wouldn't hurt to put a call to stopLightning() at the beginning of your goLightning() function to ensure you don't have multiple instances running in the event the focus event gets fired more than once.
EDIT I moved the call to goLightning() after having set up the events - untested but I think it would be better that way?
Related
I have the following code. Pressing the first button sends the user to a different URL after 10 seconds.
However, I am also trying to get the second button to cancel that redirect if pressed before those 10 seconds. This doesn't seem to work and the URL redirect still occurs.
I have looked online for various solutions and I am unable to get anything to work. I have also tried swapping out setTimeout/clearTimeout with setInterval/clearInterval and other variations of the code.
I would be willing to have the code changed completely or use Jquery instead etc. I have been trying to do this for past couple of days so any help would be greatly appreciated.
If the redirect countdown could also start again from 10 seconds if the first button is pressed again after pressing the second button, that would be also great.
Javascript
<script>
var redirectTime = "10000";
var redirectURL = "https://realmbound.com";
function timedRedirect() {
var timeoutHandle = window.setTimeout("location.href = redirectURL;",redirectTime);
}
function stopTimer() {
clearTimeout(timeoutHandle);
}
</script>
HTML
<button onclick="JavaScript:timedRedirect()">Click me for a timed redirect.</button>
<button onclick="JavaScript:stopTimer()">Stop Timer.</button>
Your timeoutHandle is in scope function, you must delcare it to global scope it in your order to access it on stopTimer().
let redirectTime = "1000";
let redirectURL = "https://realmbound.com";
let timeoutHandle;
function timedRedirect() {
timeoutHandle = window.setTimeout("location.href = redirectURL;",redirectTime);
}
function stopTimer() {
clearTimeout(timeoutHandle);
}
<button onclick="JavaScript:timedRedirect()">Click me for a timed redirect.</button>
<button onclick="JavaScript:stopTimer()">Stop Timer.</button>
The rest of the code is fine.
Your solution is correct, only thing that you missed is to scope timeoutHandle variable as global scope so that stopTimer function can access it.
here is the working fixed version of your solution:
https://jsfiddle.net/8uw7f19k/1/
Hope it helps ;-)
I am currently trying to get the width and height of a video by using the following:
var vid = document.getElementById('myVideo');
vid.onloadedmetadata = function () {
var vidHeight = this.videoHeight;
var vidWidth = this.videoWidth;
console.log(vidHeight, vidWidth);
};
I noticed when I tried to use the variables later, it sometimes worked and sometimes didn't. I put a console log in (as above) and refreshed my browser. Sometimes the values show and sometimes they don't, like the onloadedmetadata is not triggering at all. Does anyone know why this is and how to get around it?
I also tried it with another event, onloadstart. This had the same behaviour.
I found the answer (this example is in jQuery, easy enough in plain JS too though):
this.options.$video.on('canplay canplaythrough', cb);
if (this.options.$video[0].readyState > 3) {
cb();
}
function cb() {
var vidWidth = me.options.$video[0].videoWidth;
var vidHeight = me.options.$video[0].videoHeight;
console.log(vidWidth, vidHeight);
}
I have a web site which displays a portfolio using this scrollbar http://manos.malihu.gr/jquery-custom-content-scroller/ .
I want to have an automatic scroll when the page is
fully loaded. When a user pass over the portfolio it stops the scroll and whe, he leaves it starts moving again.
It currently works well but sometimes it's getting slow or sluggish randomly.
Is there something wrong with my js function?
Here's the page having problems : http://www.lecarreau.net/new/spip.php?rubrique5 (I need the change the hosting provider, I know the site is slow).
This is the function:
(function($){
var timerId = 0;
$(window).load(function(){
$("#carousel").show().mCustomScrollbar( {
mouseWheel:false,
mouseWheelPixels:50,
horizontalScroll:true,
setHeight:370,
scrollButtons:{
enable: true,
scrollSpeed:50
},
advanced:{
updateOnContentResize:true
}
});
timerId = setInterval(function(){myTimer()},50);
$('#carousel').mouseenter(function () {
clearInterval(timerId);
});
$('#carousel').mouseleave(function () {
timerId = setInterval(function(){myTimer()},50);
});
});
})(jQuery);
function myTimer()
{
var width = $(".mCSB_container").width();
var left = $(".mCSB_container").position().left;
if (width-left>0) {
var scrollTo = -left+4;
$("#carousel").mCustomScrollbar("scrollTo", scrollTo);
}
}
Is there something obvious I'm missing?
Timing in the browser is never guaranteed. Since all functionality contents for time on a single event loop, continuous repeated tasks sometimes get a little janky.
One thing you could do that might decrease the jank is to cache the jQuery objects you're creating every 50ms:
var mCSBContainerEl = $(".mCSB_container");
var carouselEl = $("#carousel")
function myTimer()
{
var width = mCSBContainerEl.width();
var left = mCSBContainerEl.position().left;
if (width-left>0) {
var scrollTo = -left+4;
carouselEl.mCustomScrollbar("scrollTo", scrollTo);
}
}
Selecting these to elements only needs to happen once. From there they can just reference a variable instead of having to find the element on the page and wrap it in jQuery again and again.
Caching the variable in this case depends on them being in the DOM when the code runs, which isn't guaranteed here. You may have to move the variable assignment and function declaration into the function passed to load.
Also, as John Smith suggested, consider checking out requestAnimationFrame. Here's a shim I use by Paul Irish: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
The problem is this:
In the following example, http://jsfiddle.net/GmgGY/2/
when you click on the orange button it creates a new div. When you click on this div it plays an oscillator. If you push a key on the keyboard (keydown) it plays it as well. It then stops playing it when the keyboard character is lifted (keyup). This is good and what I want.
However, when you click the orange button multiple times and create multiple synths. When you push a key on the keyboard all of them play (which is what I want) but only the last created one seems to respond to the keyup event.I want all of them to respond to the keyup event.Not just the last one.
I am not sure how to fix this.
Each dynamically created div has a unique ID but also a class that is universal to all of them. I thought there might be a way to select the class ( synth.class) and launch a universal oscillator.disconnect() on keyup ???
Another thing I'm thinking is my problem might need some kind of iterating thread that compensates for whatever DOM issue is causing this (assuming it isn't just exclusively the programming thus far). But I am not sure.
The Javascript code is below. I tried to keep it as minimal as possible but I couldn't figure out how to make it any smaller than this and still have it be clear. I omitted the html and css elements but kept them in the JSfiddle example.
$(function(){
var SynthCreationModule = (function(){
context = new webkitAudioContext();
var orangeButton;
var applicationArea = document.getElementById("applicationArea"),
orangeButton = document.getElementById("orangeButton"),
counterSynth = 1;
counterPitchInput = 1;
orangeButton.addEventListener("click",createSynth, false);
function createSynth () {
var synth = document.createElement("div");
synth.className = "synth";
synth.id = "synthid" + (counterSynth++);
applicationArea.appendChild(synth);
var pitchInput = document.createElement('input');
pitchInput.type = "range";
pitchInput.className = "pitchInputClass";
pitchInput.id = "pitchInput" + (counterPitchInput++);
pitchInput.min = "0";
pitchInput.max="2000";
synth.appendChild(pitchInput);
synth.onmousedown= function () {
oscillator = context.createOscillator(),
oscillator.type = 2;
oscillator.frequency.value = pitchInput.value;
oscillator.connect(context.destination);
oscillator.noteOn(0);
};
synth.onmouseup = function () {
oscillator.disconnect();
};
// Keydown & keyup events to launch oscillator. ( These don't work properly if you create two or more synths. Playing a key down works, but keyup only works on the last created synth. The previous created synths will continue to create additional oscillators but the keydown will not work to stop them.
var keydown = false;
$('body').keydown(function() {
if(!keydown){
synth.onmousedown();
keydown = true;
}
});
$('body').keyup(function() {
synth.onmouseup();
keydown = false;
});
$(synth).draggable();
};
}());
});
Your problem is actually that you never explicitly declare and scope "oscillator" - so it's going into globals. Try putting "this." in front of each occurrence of "oscillator", and it will work.
This isn't ideal code, though, because you're attaching a whole extra body event handler for each synth - your code
$('body').keydown(function() {
if(!keydown){
synth.onmousedown();
keydown = true;
}
});
is creating a whole separate function call and calling attachEventHandler on the body under the hood, with "synth" bound to the new version; it might be better to track the list of synths (even getting them back from a body.getElementsBySelector()) and calling noteOn/Off on each one. Up to you, though.
Ok, I tried to create another slider of preloaded images (whatever you wanna call it) with only two directional buttons. Got the animations the way I wanted them and the control idea was from a tutorial.
(Tutorial: How to Make Auto-Advancing Slideshows)
So, I adapted the autoadvance solution to my needs and got everything working OK. But, when I tried to run it in FF (8.0) I got a little problem. After a button click it does everything as it should except the part where the animation continues after the preset 3 seconds time, while IE (8.0) does not have problems (didn't tested in other browsers).
What am I doing wrong?
Here is the necessary code:
Html part:
<div id=imgholder1>
<div id="imgholder2"></div>
</div>
<div id="bwd" class="button"><</div>
<div id="fwd" class="button">></div>
jQuery/JavaScript:
var traker=0;
$(document).ready(function(){
var numOfImages=4;
var timeOut = null;
(function autoAdvance(){
$('#fwd').trigger('click',[true]);
timeOut = setTimeout(autoAdvance,3000);
})();
function preload(imgIndex,numImages){
$("#imgholder1").css('background-image','url("'+imgIndex+'.jpg")');
$("#imgholder2").hide(0);
imgIndex < numImages ? imgIndex++ : imgIndex=1
$("#imgholder2").css('background-image','url("'+imgIndex+'.jpg")');
traker=imgIndex;
}
preload(1,numOfImages);
function animate(imgIndex,numImages){
$("#imgholder2").fadeIn("slow",function(){
preload(imgIndex,numImages);
});
}
$("#fwd").bind("click",function(e,simulated){
animate(traker,numOfImages);
if(!simulated){
clearTimeout(timeOut);
timeOut = setTimeout(autoAdvance,3000);
}
});
$("#bwd").bind("click",function(){
var temp=traker-2;
if(temp == 0){temp=numOfImages;}
if(temp == -1){temp=numOfImages-1;}
$("#imgholder2").css('background-image','url("'+temp+'.jpg")');
animate(temp,numOfImages);
clearTimeout(timeOut);
timeOut = setTimeout(autoAdvance,3000);
});
});
At first glance, it looks like your timeout variable is in the wrong scope - declare it outside of everything so that it is shared between functions:
var traker=0;
var timeOut;
Personally, I also avoid using reserved method keywords that are close like that, so use:
var tmr;
Also, you should use window.setTimeout rather than just setTimeout
The Fix!
This:
(function autoAdvance(){
$('#fwd').trigger('click',[true]);
timeOut = setTimeout(autoAdvance,3000);
})();
should look like this:
function autoAdvance(){
$('#fwd').trigger('click',[true]);
timeOut = setTimeout(autoAdvance,3000);
}
autoAdvance();
FF didn't recognize self calling function autoAdvance otherwise.