I'm trying to make an infinitely rotating imagereel with jQuery. This imagereel shifts between images with an interval of 5000 milliseconds, then fading out the 'old' image and fading in the 'new' image. The image to be displayed has a style-attribute for "display:inline".
The code can be found below:
function switchImage(){
var selector = $('#fotoreel img[style="display: inline; "]');
var nextOne = $(selector).next();
if($(nextOne).length == 0)
{
var nextOne = $('#fotoreel img:first');
}
$(selector).fadeOut('normal',function(){
$(nextOne).fadeIn('normal');
});
var t = setTimeout("switchImage()",5000);
}
$(document).ready(function(){
setTimeout("switchImage()",5000);
});
The problem is that it works fine in Chrome, but in Firefox and in Opera it only shifts image one time. In IE it's worse; there it doesn't work at all.
Do you guys know a better way of infinitely looping with javascript? Now I use setTimeout() to call the function again, but that doesn't seem to work.
EDIT
Okay, thank you everyone! Such fast responds, awesome!
The solution that I used was the one of adding a class and searching for that instead of for the style. The display:inline didn't appear to be a problem, as it worked out, but all the browsers appeared to implement the jQuery fadeIn() function differently.
I namely wanted to filter EXACTLY on "display: inline ;", because the spaces were added in Chrome, but not in IE, FF or Opera. So that means the style attribute wasn't accurately at all to filter with. Stupid me! :)
I made sure that a class was added to the image that is showed currently, and find the next one by filtering on that class. Now it works like a charm.
Thank you all for your answers, I love this place! :D
This is most likely because you are checking the style attribute, which is very inconsistent in browsers. I.E. doesn't work at all or works with various amounts of white-space. Just simplify your selector to use a class or ":visible"
It's probably going to work better if you explicitly mark images with a class:
function switchImage(){
var selector = $('#fotoreel img.current');
var nextOne = $(selector).length ? $(selector).next();
if($(nextOne).length == 0)
{
var nextOne = $('#fotoreel img:first');
}
$(selector).fadeOut('normal',function() {
$(selector).removeClass('current');
$(nextOne).addClass('current').fadeIn('normal');
});
setTimeout(switchImage, 5000);
}
$(document).ready(function(){
$('#fortoreel img:last-child').addClass('current');
setTimeout(switchImage,5000);
});
Note also that in my calls to "setTimeout()" I pass a direct reference to the function instead of a string version of the code to call it.
This wasn't working because the browsers you mentioned did not like the display: inline selector you used.
I got it working using the following:
function switchImage() {
var selector = $('#fotoreel img:visible');
var nextOne = selector.next();
if (nextOne.length == 0) {
var nextOne = $('#fotoreel img:first');
}
selector.fadeOut('normal', function () {
nextOne.fadeIn('normal');
});
var t = setTimeout(switchImage, 5000);
}
$(document).ready(function () {
setTimeout(switchImage, 5000);
});
Related
I'm working on a HTML5 friendly drag and drop system and I've encountered another mystery that seems to make no sense...
The system is working in Edge - it's when I'm emulating IE8 that I encounter this latest problem.
I have a set of '.draggable' divs that get the following listener attached:
$(document).ready(function() {
$('#reset-button').click(resetDraggables);
if (!dragAndDropSupported()) {
var $draggables = $('.draggable');
$draggables.each( function (index) {
$(this).mousedown( jQueryStartDrag );
});
}
}
The draggables can be sent back to their original locations by hitting a 'reset' button. That all works fine.
The problem is - any divs that get sent back to their origins are no longer draggable. Even if I re-attach the listener in the reset function, it does not fire. Once again, this issue is only happening when I'm emulating IE8 and I don't remove the listener anywhere in my code.
function resetDraggables() {
if ( !$('#reset-button').hasClass('inactive') ) {
var $dropTargets = $('.drop-target');
$dropTargets.each(function (index) {
var draggableId = $(this).attr('data-contains');
var $originDraggable = $('#' + draggableId);
if ($originDraggable.attr('id')!=undefined) {
var $droppedDraggable = $(this).find('.draggable');
$droppedDraggable.remove();
$originDraggable.removeClass('inactive').addClass('draggable').attr('draggable', 'true').css('filter', 'alpha(opacity=100)').hide().fadeIn('fast');
$('#' + draggableId).mousedown( jQueryStartDrag );
$(this).removeClass('occupied').attr('data-contains', '');
$('#reset-button').addClass('inactive');
}
});
}
}
I've realised it's the $droppedDraggable.remove() line that's causing the problem. I'm not sure why a line to remove ONE object would remove the listener from another. The $droppedDraggable object was cloned from the other; Is that causing the issue?
Any ideas what might be going on?
OK, so I replaced the jQuery remove() lines with...
var droppedDraggable = document.getElementById('dropped-' + draggableId);
droppedDraggable.outerHTML = "";
...and that has done the trick. I'm guessing there must have been some hidden association made between the objects when one was cloned from the other and remove()ing one removed the mousedown listener from the other.
If anyone has a better theory, feel free to let me know, but this seems to have solved the problem.
Edit
I've just realised the above fixed the problem in IE8, but not in 9. Great! If anyone has any pointers on how NOT to include a bunch of browser-specific work arounds in my code, I'd be very keen to hear them. Thanks.
I have a menu composed of three options.
Clicking on one causes a container div to "FadeInDown".
Then, its contents "FadeIn".
Clicking on another menu item or anywhere else on the page causes the
contents to "FadeOut" then container div to "FadeOutUp".
Here is the fiddle that I have been testing jsfiddle
$(document).ready(function() {
$('.container').each(function() {
animationHover(this,'.fadeInDown');
});
});
I'm not very familiar with jQuery and have been trying to use animate-css to get me along. Thanks for any help and tips in advance and welcome coding criticism :)
My answer is mainly based on JQuery and its animate function (http://api.jquery.com/animate/) . Here is the fiddle :
http://jsfiddle.net/awmat/7/
I use JavaScript objects like fadeInDown to animate the container.
var fadeInDown = {
opacity:1,
top: "50px"
};
And i use the complete callback function of animate to make the content appear after the container.
To manage several div (one for each menu item), I use id as selectors, but since the "click and display" function remains the same, I used a "builder" : (this uses a closure, so if you're not familiar with JavaScript, you may have to read several times to understand what is going on)
var menuClickCallbackBuilder = function(menuItem){
var container = $('#container' + menuItem);
var content = container.find('.content');
var showContent = function(){
content.animate({opacity:1},{duration:1000});
};
return function() {
var activeContainer = $('.active');
var hideContainer = function(){
activeContainer.animate(fadeOutUp,1000);
};
activeContainer.find('.content').animate({opacity:0},{duration: 1000, complete : hideContainer});
activeContainer.removeClass("active");
if(activeContainer[0] != container[0])
{
var timeout = activeContainer[0] ? 2000 : 0 ;
setTimeout(function(){
container.animate(fadeInDown,{duration : 1000, complete :showContent});
},timeout);
container.addClass("active");
}
}
};
This way, when you add the add the click callbacks, you can just do :
$(document).ready(function(){
// note that menuClickCallbackBuilder(1) returns a function
// again if you're not familiar with JS, you may have to re-read menuClickCallbackBuilder
$('#menuLink1').on('click', menuClickCallbackBuilder(1));
$('#menuLink2').on('click', menuClickCallbackBuilder(2));
$('#menuLink3').on('click', menuClickCallbackBuilder(3));
});
Some improvements you can bring to this :
Factor the durations into a variable (e.g animationDurationInSeconds) so that if you want to change the speed of the animation, you only have 1 thing to change. (#Huangism: and right after you did that, make animation faster so that it gets more dynamic)
(From #Huangism) : stop it from going crazy when people cicks on the menu 10 times really fast
Actually, I think you don't need 3 different containers, you could do it with just one container (though I don't know if it would be considered an improvement)
There is probably a way to use CSS classes instead of fadeInDown and fadeOutUp JS objects. That would be cleaner, I think you should keep styles in CSS as much as you can.
There is no need for different IDs for menu items, you could do the exact same thing with a loop.
Whatever your imagination wants to add
I am attempting to make a slideshow out of text, wherein one piece of text fades out, and another fades in, and so on. I have it working for the most part, but there is a small issue.
When the page is first loaded, all of the pieces of text are displayed at once. Each one fades in turn, and once they have all faded once they function as I want. I have used:
(function langFade() {
var lang = $('.lang, .first');
var langIndex = -1;
function showNextLang() {
++langIndex;
lang.eq(langIndex % lang.length)
.fadeIn(1500)
.delay(2000)
.fadeOut(1500, showNextLang);
}
showNextLang();
})();
as described here, but this is causing the problem described above. I've attempted using CSS to hide all but the first piece of text when the site is loaded, but this isn't doing the trick. My suspicion is that the issue is with the HTML - it is rather different to the demo. I have created a fiddle to demonstrate what I mean.
Is there any way of fixing this, either through modifying the JavaScript, or the HTML?
Try to hide the others at first with .not(':eq(0)').hide()
(function langFade() {
var lang = $('.lang, .first'),
langIndex = -1;
lang.not(':eq(0)').hide();
function showNextLang() {
++langIndex;
lang.eq(langIndex % lang.length)
.fadeIn(1500)
.delay(2000)
.fadeOut(1500, showNextLang);
}
showNextLang();
})();
Can also use .not(':first').hide() which may be a little easier to read.
Just hide them initially. And this can be done in pure CSS. Add following class:
h2.first, h2.lang {
display: none
}
Demo: http://jsfiddle.net/XbWJS/2/
I have a rare issue. May be is a bug of jQuery, I dont know how can I solve it.
While I am using below method to hover a element, meanwhile I was monitering the length of element.
The problem is the length of added element 'el' will return 0 while using hide() + slide
hover(
function() {
if (!trigger.next('#id').length) // if #id not exsist, add html
el = trigger.after(html).next('#id') // el = new added html
else
el = trigger.next('#id')
el.stop(true, true).show('slide', { direction, 'left' })
},
function() {
el.hide('slide', { direction, 'left' })
});
If I switch to another method, hide()<-just hide, animate(), fadeOut(), all will return 1.
The added html is existing. However, length will not return while hide() + slide,
but after finish hide() + slide, will return 1;
Please help to solve this issue.
Issue is el.length will return 0 while hide() + slide even-though the el is existing
Thank you very much for your advice.
I have created a example, please check.
http://jsfiddle.net/fantill/DFd7e/6/
Is there a reason why you're using jQuery beta 2.0 ? It would have been worth mentioning.
You're also using jQuery UI which I doubt is compatible with jQuery 2.0.0b1.
I just changed jQuery to v1.9 and it seems to be working, I also added brackets and commas.
This is tidier :
if( !$('#B').length )
{
el = $(this).after('<div id="B" style="display:none; width:50px; height:50px; background-color:#09F; ">YYYYYYYYY</div>').next('#B');
}
else
{
el = $('#B');
}
Here's the fiddle updated :
http://jsfiddle.net/DFd7e/9/
EDIT: I enabled jQuery UI, and replaced this $(this).next('#B').first().length
with this : $('#B').length.
next() doesn't work in your case because jQuery UI is adding a wrapper around the div that you're animating, you can see it if you open your dev tool.
Updated fiddle : http://jsfiddle.net/DFd7e/11/
The best way to understand this is to look at this fiddle.
Notice how mouse wheel over the fixed content in the red box does nothing. I would like the scrollable div to scroll.
In case the fiddle dies - basically I have a scrollable div with a fixed element over it. Typically when you mouse wheel over a scrollable div it will of course scroll. But if you are over the fixed element instead then no scroll happens. Depending on your site layout this could be counter intuitive to a user.
jQuery solutions are okay.
A much, MUCH simpler, but much less widely supported, answer is the following:
#fixed{ pointer-events:none; }
jsFiddle
Doesn't work in IE at all though unfortunately! But you could use modernizr or somesuch to detect whether it was supported and use the jQuery as a stop-gap where it isn't.
Courtesy of Mr. Dominic Stubbs
I had this problem and this works for me (using jquery):
$(document).ready( function (){
$('#fixed').on('mousewheel',function(event) {
var scroll = $('#container').scrollTop();
$('#container').scrollTop(scroll - event.originalEvent.wheelDeltaY);
return true;
});
});
Works on Safari and Chrome: http://jsfiddle.net/5bwWe/36/
I think this does what you're asking for!
$('#fixed').bind('mousewheel', function(e){
var scrollTo= (e.wheelDelta*-1) + $('#container').scrollTop();
$("#container").scrollTop(scrollTo);
});
EDIT: Updated the jsFiddle link to one that actually works
DOUBLE EDIT: Best to dispense with the .animate() on further testing...
jsFiddle Example
TRIPLE EDIT:
Much less pretty (and will probably be horribly slow with a lot of elements on the page), but this works and I owe a lot to this stackoverflow answer.
$('#fixed').bind('mousewheel', function(e) {
var potentialScrollElements = findIntersectors($('#fixed'), $('*:not(#fixed,body,html)'));
$.each(potentialScrollElements, function(index, Element) {
var hasVerticalScrollbar = $(Element)[0].scrollHeight > $(Element)[0].clientHeight;
if (hasVerticalScrollbar) {
var scrollTo = (e.wheelDelta * -1) + $(Element).scrollTop();
$(Element).scrollTop(scrollTo);
}
});
});
function findIntersectors(targetSelector, intersectorsSelector) {
var intersectors = [];
var $target = $(targetSelector);
var tAxis = $target.offset();
var t_x = [tAxis.left, tAxis.left + $target.outerWidth()];
var t_y = [tAxis.top, tAxis.top + $target.outerHeight()];
$(intersectorsSelector).each(function() {
var $this = $(this);
var thisPos = $this.offset();
var i_x = [thisPos.left, thisPos.left + $this.outerWidth()]
var i_y = [thisPos.top, thisPos.top + $this.outerHeight()];
if (t_x[0] < i_x[1] && t_x[1] > i_x[0] && t_y[0] < i_y[1] && t_y[1] > i_y[0]) {
intersectors.push($this);
}
});
return intersectors;
}
UPDATE (August 2016): It seems the browser implementations have changed and it's no longer possible to re-dispatch a WheelEvent on a different target. See the discussion here.
For an alternative solution that should work across platforms, try this:
var target = $('#container').get(0);
$('#fixed').on('wheel', function (e) {
var o = e.originalEvent;
target.scrollTop += o.deltaY;
target.scrollLeft += o.deltaX;
});
Working example: https://gist.run/?id=6a8830cb3b0564e7b16a4f31a9405386
Original answer below:
Actually, the best way to do it is to copy the original event. I've tried #Tuokakouan's code but scrolling behaves strangely (too fast) when we use a multitouch touchpad that has inertia.
Here's my code:
var target = $('#container').get(0);
$('#fixed').on('wheel', function(e){
var newEvent = new WheelEvent(e.originalEvent.type, e.originalEvent);
target.dispatchEvent(newEvent);
});
You can try it here: http://jsfiddle.net/NIXin/t2expL6u/1/
What I'm trying to do now is also to pass the touch events, without much success. Since mobile phones and touch screens are now more popular, some people might want to scroll using their fingers instead - neither of the answers offered solves that.
Well,all solutions with js are kind of delayed when scrolling on it. if the fixed element you use is just for display, then I have a good css tricks to achieve that.
make the fixed element z-index:-1 and the container element background-color:transparent
here is the jsfiddle you can see: https://jsfiddle.net/LeeConan/4xz0vcgf/1/