I am currently using jQuery's resize function, but because of what I adjust on resize, there's simply too much going on to make it look smooth, as it fires at every adjustment.
$(window).resize(function() {
myFunction();
});
Is there a way to fire a function off after the resize has stopped? Like $(window).afterResize() or something?
Any solutions welcome.
Set a timeout and do the action 100ms later, perhaps.
var timer;
$(window).resize(function() {
clearTimeout(timer);
timer = setTimeout(myFunction, 100);
});
I am not sure if there is a 'clean' native way to do it (hopefully there is and someone will shed light)
but you "hack" it like this http://jsfiddle.net/tuuN3/
var myInterval = false; // this variable will hold the interval and work as a flag
var $win = $(window); //jquery win object
var dimensions = [ $win.width(), $win.height() ]; //initial dimensions
$(window).resize(function() { //on window resize...
if( !myInterval ) //if the interval is not set,
{
myInterval = setInterval( function() { //initialize it
//and check to see if the dimenions have changed or remained the same
if( dimensions[ 0 ] === $win.width() && dimensions[ 1 ] === $win.height() )
{ //if they are the same, then we are no longer resizing the window
clearInterval( myInterval ); //deactivate the interval
myInterval = false; //use it as a flag
doStuff(); //call your callback function
}
else
{
dimensions[ 0 ] = $win.width(); //else keep the new dimensions
dimensions[ 1 ] = $win.height();
}
}, 64 ); //and perform a check every 64ms
}
});
You should research "debounce" or "throttle" as it relates to javascript. Depending on your needs - you may need to use one or the other. Here is a debounce/throttle library I've used as well as great descriptions of their applications. There is no need to re-invent the wheel - plus it is always great to know the terminology and identify useful coding patterns (for future maintainers of your code).
Related
this is my javascript code only work on click event and i want to make this auto slideshow. please help me i have no knowledge how to do it..
var wflSliders = ({});
var wflSlider = new Class({
Implements:[Options,Events],
initialize:function(options){
this.setOptions(options);
if(this.options.ribbon_behavior == 'scroll'){
this.wrapper = $('rand_products_wfl_'+this.options.id);
if(this.wrapper){
this.ribbon = this.wrapper.getElement('.jspw_ribbon');
this.scroll_r = this.wrapper.getElement('.jspw_scroll');
this.lt = this.wrapper.getElement('.jspw_ribon_button_lt');
this.rb = this.wrapper.getElement('.jspw_ribon_button_rb');
this.blocks = this.wrapper.getElements('.jspw_prod');
var blockSize = this.blocks[0].getComputedSize();
var dim = (this.options.orientation == 'hor')?'x':'y';
if(this.options.effect_block == 'single'){
this.offset=(dim=='x')?blockSize.totalWidth:blockSize.totalHeight;
}
One way to approach is that you can use a built-in function called setInterval in Javascript and after wrapping your code in a function call it in the interval you desire to have your slideshow speed.
Like the following:
setInterval(function(){
slideShow(); // Every second the function is called
},1000);
Check the documentation here for more understanding: MDN Documentation for setInterval function
UPDATE: Givi just proved to me (in the comments of my answer) that my answer was not right. It has high risk that you use my suggested approach and better to use setTimeout recursively like this:
function slideShow() {
setTimeout(function() {
slideShow();
}, 1000);
}
you can us slide show plugin. Good luck
What is the equivalent of the following jQuery animate in pure JavaScript?
function animate(element, position, speed) {
$(element).animate({
"top": position
}, speed);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You can acheive complex animations with pure javascript by using setTimeout and setInterval methods.
Please check here.
Here is the key part of moving an element:
function move(elem) {
var left = 0
function frame() {
left++ // update parameters
elem.style.left = left + 'px' // show frame
if (left == 100) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 10) // draw every 10ms
}
This version uses vanilla javascript .animate() function, which is better or more performant
than requestAnimation frame. & it is also the proper alternative to JQuerys .animate().
you can play around with the iterations, timing functions & fill method aswell as daisy chain it with other animations
document.getElementById("Elem");
Elem.style.position = "absolute";
Elem.animate({
top: ['8px', '280px']
},{ duration: 1760, // number in ms [this would be equiv of your speed].
easing: 'ease-in-out',
iterations: 1, // infinity or a number.
// fill: ''
});
I believe the setTimeout & setInterval functions both use the unsafe eval() function under the hood, but not 100% sure about that, just remember reading an article about it...
Don't Quote me on that! just research it,
but the code I wrote out has been tested to be working..
hope this helps someone...
The setInterval() method is too heavy for the browser, so it's better to use requestAnimationFrame() for animations. The following code is an example of using this method.
let _btns = document.querySelectorAll('.btn'),
_start = null;
let _loop = function (timestamp, duration, position, wrap) {
if (!_start) _start = timestamp;
let progress = (timestamp - _start) / duration;
wrap.style.left = progress * position + 'px'
if ( progress < 1 ) {
window.requestAnimationFrame( function (timestamp){
_loop(timestamp,duration,position,wrap);
} );
} else {
_start = null;
}
},
_animation = function () {
const wrap = document.querySelector('.logo-2'),
position = 300, // 300 pixels
duration = 500; // 500 milliseconds
_loop(0,duration,position,wrap);
},
_addEvents = function () {
[].forEach.call(_btns,function(el){
el.addEventListener('click', function (e) {
_animation();
})
});
},
_init = function() {
_addEvents();
};
_init();
Element.animate() function seems to be very simple and useful. But there are for now a lot of compatibility issues. You can read about it:
https://developer.mozilla.org/en-US/docs/Web/API/Element/animate
I would recommend to get used to requestAnmationFrame. It's compatible with all browsers and it is very powerful:
https://javascript.info/js-animation
I'm creating a simple game with a character that can jump, move right, and move left.
I'm having trouble with the jump function, which uses a setInterval.
Here is the function:
jumpUp: function (speed) {
setInterval(function () {
this.yPos += 10;
this.playerElement.css("top", '-=' + 10);
alert("dude, im not moving....so stop trying"); //for some reson, this line works and other dont.
}, 100);
}
I should add that the code works without the setInterval. I really don't have any idea why it's not working when I add the setInterval.
My questions:
What is stopping this code from running?
Is setInterval a good way to make a character look like it jumping and landing? Or should i use different method?
EDIT 1:
fiddle
The problem is your use of this. When the function you pass to setInterval is called, this will be the global object (window in browsers). You need to preserve the this value from when you call setInterval. One way of doing this is to store the value of this into a variable, which will then be closed over by the anonymous function (which is a closure):
jumpUp: function (speed) {
var self = this;
setInterval(function () {
self.yPos += 10;
self.playerElement.css("top", '-=' + 10);
}, 100);
}
EDIT:
To answer your second question, a better approach to animating a sprite (like your character) is to store the character's velocity, and then have a single game loop that will calculate the next position of the sprite based on that information. A very simple example would look like:
// Somewhere else in the code:
function tick() {
// move player by player.velocity.x and player.velocity.y
// code to decelerate player gradually, stop player when they hit a wall/floor, etc...
// A very simple example:
if (player.velocity.y > 0) {
player.velocity.y -= 1
}
// call next tick() (setTimeout, or preferably requestAnimationFrame)
}
// In the player code:
velocity: {x: 0, y: 0},
jumpUp: function () {
this.velocity.y -= 10;
},
moveRight: function () {
this.velocity.x += 10;
}
As darma and danronmoon pointed out, you have a scoping problem with this.
Try the following code:
jumpUp: function (speed) {
var that = this;
setInterval(function () {
that.yPos += 10;
that.playerElement.css("top", '-=' + 10);
}, 100);
}
I added a variable, that, to maintain the reference to whatever this is supposed to be.
In addition to your closure problem, this is probably going to cause choppy jumping.
Here's another pattern that watches the clock to see how much time has elapsed between each call to the function (setInterval is not consistent):
jumpUp: function (speed) // speed in pixels per second
{
var last = +new Date();
var c = this;
var jumptick = function ()
{
var interval = +new Date() - last;
c.yPos += speed * interval;
c.playerElement.css("top", c.yPos);
if (/* condition for reaching maximum height */) speed = -speed;
if (! /* condition for reaching ground */) setTimeout(jumptick);
// could add an interval but this will lead to fastest frame rate
};
jumptick();
}
Setinterval is not a good way to achieve this because it will use a lot a ressources.
You also need to consider the framerate when you are moving your character, otherwise he will move fast on a fast machine/browser and slow on a slow machine.
A good method is using the requestAnimationFrame method. You can find a javascript file on google that will make it crossbrowser compatible.
Then, everytime your function is called, you will need to check the time elapsed between to frame and move your sprites accordingly. It's more work but that way, your game will run at the same pace on any machine.
I am trying to fiddle around and create a little fadeOut function in JavaScript,
This is what I came up with:
function fadeOut(id, time){
var elem = document.getElementById(id);
elem.style.opacity = 1;
var opc = 1;
while(opc >= (1/time)){
opc -= (1/time);
console.log(opc);
elem.style.opacity = opc;
}
elem.style.opacity = 0;
}
But this will not show the div's opacity in "real-time" but rather the end result, which is opacity = 0;
I've tested it out here:
fadeOut("hello",10000);
document.getElementById("hello").style.opacity = 1;
fadeOut("hello",10000);
document.getElementById("hello").style.opacity = 1;
fadeOut("hello",10000);
document.getElementById("hello").style.opacity = 1;
It would take it a long time to calculate and only when it finishes it will dump the result,
not showing it seamlessly, while calculating,
How can I resolve this?
You need to set timers, as, until your function is done and the event handler can run, the UI won't be updated.
It is because you are not 'yielding` the thread so as to allow the browser to apply the changes.
Use setTimeout(..) instead like this:
function fadeOut(id, time){
var elem = document.getElementById(id);
if(opc >= (1/time)){
opc -= (1/time);
console.log(opc);
elem.style.opacity = opc;
setTimeout(function(){fadeOut(id,time);}, 100);
}
else
elem.style.opacity = 0;
}
Not really a great code but it gives you the idea.
May be you could use jQuery library. In that case, you will use fadeOut
one potential causing this problem can be bubbling of event.try to use event.stopPropagation() to prevent the event (in case that you are using the FadeOut function in response to an event) from bubbling up.
the code is
function StopBubble(e)
{
if (!e)
e = window.event;
e.cancelBubble = true; /* Microsoft */
if (e.stopPropagation)
e.stopPropagation(); /* W3C */
}
You have to specify a delay between every modification you make to the DOM in order to see the effect. There is no option in javascript to add a pause feature, so you have to rely on timers. There are two ways to achieve this. Most commonly used approach is setInterval(fn,sec). But setInterval is bad, because it executes the callback every interval of time specified regardless the previous execution is complete or not.
I personally suggest using a library rather than re-inventing the wheel. But its always good to have a basic understanding what the libraries do behind the scene.
Below is a sample snippet to achieve this without setInterval.
Note: This is just for demonstration. Not cross browser compatible. Extend it for reusability and cross broswer compatibility.
<div id="mydiv"></div>
function fadeOut() {
var _timeOut,
_proceed = true,
_elm = document.getElementById( "mydiv" ),
_opacity;
function addOpacity() {
// _elm.style.opacity will return empty string
// see https://developer.mozilla.org/en-US/docs/DOM/window.getComputedStyle
// getComputedStyle() not cross broswer
_opacity = +window.getComputedStyle( _elm, null ).getPropertyValue( "opacity" );
if( _opacity > 0.1 ) {
// a simple algorithm for basic animation
_elm.style.opacity = _opacity / 2;
} else {
_elm.style.opacity = 0;
_proceed = false;
}
}
(function animate() {
if( !_proceed ) {
clearTimeout( _timeOut );
return;
}
addOpacity();
// unlike setInterval(), this approach waits for addOpacity() to complete before its executed again
_timeOut = setTimeout( animate, 1000 );
}());
}
Why not to use a JavaScript library like jQuery? Because some JavaScript code is not compatible with different sorts of browsers.
In jQuery you can use this:
$(".id").css("background","blue").fadeOut("slow");
I'm just trying some JS animations, and I have animated a box that moves within borders, but I would like the animation to stop when the box hits one of the borders. This is one of the functions I use:
function AnimMoveRight() {
var interval = setInterval("moveRight(10)", 40);
if (hitRight == true) {
clearInterval(interval);
}
}
The moveRight(10) changes the box'position for 10 pixels to the right. hitRight is set true when the box hits the right border. Well, obviously, this code doesn't work, it just keeps on looping the moveRight() function. Now, my question is, how do I cancel the interval from within the AnimMoveRight() function?
function AnimMoveRight() {
var interval;
function fnc(){
if (hitRight == true) {
window.clearInterval(interval);
}
else{
moveRight(10);
}
}
interval = setInterval(fnc, 40);
}
One option would be to get rid of setInterval altogether and just call setTimeout every iteration that doesn't result in a border hit:
function AnimMoveRight() {
// Do stuff here
if (!hitRight) {
var nextCall = setTimeout("moveRight(10)", 40);
}
}
Use setTimeout instead of setInterval for greater control.
Use functions instead of strings when setting timers.
The common convention is to start function names with a lower case letter.
Directly check truthy/falsy expressions instead of comparing them to Booleans.
function animMoveRight() {
moveRight(10);
if (!hitRight) {
setTimeout(animMoveRight, 40);
}
}
I'd say, just move clearInterval(); out of the AnimMoveRight(); and do a global check for hitRight. And, if it's true, then clear the interval.
Or, define the interval variable in global scape, and on AnimMoveRight(); set it. Then you could clear it within AnimMoveRight(); too. Haven't tested neither, but I think both options would work.
If you check to see if it has hit the right before moving it will only call the animate function if it has yet to hit the right side, I chaged the function to setTimeout, I think this fits the task better.
function AnimMoveRight() {
if (hitRight !== true) {
moveRight(10);
setTimeout(AnimMoveRight,40);
}
}
Save the interval handle as a global, and check, within moveRight, if it needs to be canceled and if so cancel it there.
Better yet, use a closure so that the moveRight function can get to the interval handle without having to make it a global.
var interval = setInterval(function(){moveRight(10, interval);}, 40);
Use this:
function AnimMoveRight() {
var interval;
function animate() {
var hitRight = moveRight(10);
if (hitRight)
clearInterval(interval);
}
interval = setInterval(animate, 40);
}
Note that your moveRight shall return true|false.
You'll need to cancel the interval from within moveRight()*. The trick is letting moveRight() know what the intervalId is. Do you need to expose moveRight() as public? If not, you could put it inside AnimMoveRight:
function AnimMoveRight() {
function moveRight(n) {
// do stuff
if (hitRight) {
clearInterval(interval);
}
}
var interval = setInterval(function() { moveRight(10); }, 40);
}
Other options including passing interval as a parameter to moveRight:
var interval = setInterval(function() { moveRight(10, interval); }, 40);
Or do it right after the moveRight() call:
var interval = setInterval(function() {
moveRight(10);
if (hitRight) {
clearInterval(interval);
}
}, 40);
* This last one actually does cancel the interval from within AnimMoveRight(), as you requested.