I'm waist deep in my own React virtualization implementation and one of the minor issues that has been annoying me is that if I middle click on an item in my list and start scrolling, once that element is removed from the DOM the scrolling halts. My first theory was that the element was gaining focus and that preventing that would solve the issue, but what I've tried hasn't been working and I'm not even sure that's the issue.
How can I prevent this from happening?
See this fiddle for a basic demonstration:
https://jsfiddle.net/v169xkym/2/
And the relevant bit of code that handles virtualization:
$('#container').scroll(function(e) {
$('#container').children().each(function(i) {
if ($('.item:eq(' + i + ')').length > 0) {
if ($('.item:eq(' + i + ')').offset().top < 0) {
$('.item:eq(' + i + ')').remove();
$('#topPadding').height($('#topPadding').height() + 45);
}
}
});
});
Basically, I'm using the standard method of removing the element and upping the padding. In my React implementation this is handled different but here you get a basic functional representation.
you can get around this by not having the disappearing element register mouse events.
this can be done with CSS3 :
div.item {
pointer-events : none;
}
(Not entirely sure why, but my guess is that once the element disappears, the origin of the event is missing, so browsers simply stop doing what they were doing.)
Jsfiddle here
Maybe a bit late to the party. A workaround I am using on a virtual scroller is to detect when there is a scroll event, and when there has been no new events for a time, I consider the scroll is complete.
let scrollTimer = null;
let isScrolling = false;
window.addEventListener('scroll', function() {
clearTimeout(scrollTimer);
isScrolling = true;
scrollTimer = setTimeout(()=>{
isScrolling = false;
},500);
}, false);
I then grab a reference to the element that is hovered at the time isScrolling becomes true (using mouseOver) and prevent this element being unloaded until isScrolling is false. It is a bit of a juggle, but works. I am hoping I can find something simpler as it only seems to be a Chrome problem.
Update: It seems to be a known bug, about to be fixed related to pointer-events: none on something that overlays a virtual scroller (reproduction by someone https://codepen.io/flachware/pen/WNMzKav). I have no idea why my work around above works, but nice to know it wont be needed come Chrome 103. https://bugs.chromium.org/p/chromium/issues/detail?id=1330045&q=chrome%20scroll&can=2&sort=-opened
Images can explain better than words sometimes.
So I've a very weird problem with my self-written jquery tooltip (I actually want to avoid to use some lib, since my use-case is actually pretty simple and I don't need some bloated lib here).
When I move my mouse from right to left or from top to down everything is fine. When I move my mouse from left to right or bottom to top my tooltip gets stuttering - see the gif.
My tooltips are referenced by data attributes
HOVER ME
<div id="myTooltip">Tooltip Content Foo Bar</div>
To avoid problems positioning my element I'll move it later wit jQuery to the body.
Well, now I've now idea whats going on with my tooltip. Any ideas why it is stuttering?
BTW: This is happening in all modern browsers for me.
$(function () {
$('[data-tooltip]').each(function () {
$($(this).data('tooltip')).appendTo('body');
// this mouseenter listener could be safely removed, probably
// (don't forget to move the display:block part to mousemove tho)
$(this).on('mouseenter', function (e) {
$($(this).data('tooltip')).css({
display: 'block',
left: e.pageX,
top: e.pageY
});
});
$(this).on('mousemove', function (e) {
$($(this).data('tooltip')).css({
left: e.pageX,
top: e.pageY
});
});
$(this).on('mouseleave', function () {
$($(this).data('tooltip')).hide();
});
});
});
I think I found a solution for you. Might not really what you wanted but I think it will work for what you want to use it for.
Here is the JSfiddle: http://jsfiddle.net/nj1hxq47/3/
Ok so the key is to make sure the mouse never goes over the element you are dragging. So making sure you have at least 1 xp between the element you are dragging and the element you are hovering over will make sure it does not trigger the onleavemouse event.
var yPos = e.pageY + 5;
I am sure there is a better way to do this... but I hope this helps.
EDIT: The main problem is the mouse is going over the element you are moving to the mouse's position and thus triggering the onmouseleave event resulting in the element being hidden and shown in milliseconds of each other. Because the mouse leave event triggers before the move.
I have created a sliding image gallery and when the button is pushed it slides the picture across and updates the image attribute for the relevant sections.
However this works perfectly like 50% of the time. The other times there is a second glitch and the images then go in place as expected.
I have attached the javascript methods for the animate method and the array change method. I have looked elsewhere and cannot see anyone else with a similar issue or where I am going wrong, especially when it doesn't happen often.
imageGallery.leftSelect.onclick = function () {
window.setTimeout(imageGallery.rightClick, 250);
imageGallery.animateImages('.image1', '.imageRight');
imageGallery.animateImages('.imageRight', '.imageNoneRight');
imageGallery.animateImages('.imageLeft', '.image1');
imageGallery.animateImages('.imageNoneLeft', '.imageLeft');
};
animateImages: function (classFrom, classTo) {
var classMoving = $(classFrom);
var classGoingTo = $(classTo);
classMoving.animate({
top: classGoingTo.css('top'),
left: classGoingTo.css('left'),
width: classGoingTo.css('width'),
opacity: classGoingTo.css('opacity'),
}, 258, function () {
console.log('Animated');
classMoving.css({"width":'', "opacity":'', "top":'', "left":'', });
});
},
rightClick: function () {
imageGallery.imagesDisplay.push(imageGallery.imagesDisplay.shift());
imageGallery.imageNoneLeft.setAttribute('src', imageGallery.imagesDisplay[2]);
imageGallery.imageLeft.setAttribute('src', imageGallery.imagesDisplay[1]);
imageGallery.imageMain.setAttribute('src', imageGallery.imagesDisplay[0]);
imageGallery.imageRight.setAttribute('src', imageGallery.imagesDisplay[10]);
imageGallery.imageNoneRight.setAttribute('src', imageGallery.imagesDisplay[9]);
},
Can someone assist, I really need this to work?
If there is anything not clear or you need more code let me know.
Thanks,
First things first, the culprit was the setAttribute of all images i.e. whatever you were doing inside the rightClick and leftClick functions were the reasons why you were seeing a glitch. Changing src of an img tag produces the glitch.
But then we cannot simply remove it because your approach relies heavily on this swapping of images.
I had to breakdown and really understand your approach first. The way it worked was that you would animate, for example, image1 (the centered one) to move to the position of imageLeft upon click on the rightCarousel button. On that same click, you had a setTimeout of almost the duration of the animation to call rightClick function. This rightClick function then swaps the images so that image1 can always remain at the center and only images can come and go after animation. This was the problem.
What I had to change was that all image tags i.e. imageNoneLeft, imageLeft, image1, imageRight & imageNoneRight would change each others classes such that their position remains changed after animations.
Also, I had to add another animateImages line inside your leftSelect and rightSelect callbacks to animate the furthest images i.e. imageNoneLeft & imageNoneRight to animate to each other's positions with respect to the click of the buttons.
Take a look at this jsFiddle. It will help you understand a lot better. And let me know if you have any questions.
JavaScript:
var imageGallery={
prefix:'https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/',
imagesDisplay:['JS.jpg','PIXI.jpg','GSAP.jpg','JS.jpg','PIXI.jpg','GSAP.jpg','JS.jpg','PIXI.jpg','GSAP.jpg','JS.jpg','PIXI.jpg'],
rightSelect:document.querySelector('.rightCarousel'),
leftSelect:document.querySelector('.leftCarousel'),
imageMain:document.querySelector('.image1'),
imageLeft:document.querySelector('.imageLeft'),
imageRight:document.querySelector('.imageRight'),
imageNoneLeft:document.querySelector('.imageNoneLeft'),
imageNoneRight:document.querySelector('.imageNoneRight'),
init:function(){
imageGallery.imagesDisplay.push(imageGallery.imagesDisplay.shift());
imageGallery.imageNoneLeft.setAttribute('src',imageGallery.prefix+imageGallery.imagesDisplay[2]);
imageGallery.imageLeft.setAttribute('src',imageGallery.prefix+imageGallery.imagesDisplay[1]);
imageGallery.imageMain.setAttribute('src',imageGallery.prefix+imageGallery.imagesDisplay[0]);
imageGallery.imageRight.setAttribute('src',imageGallery.prefix+imageGallery.imagesDisplay[10]);
imageGallery.imageNoneRight.setAttribute('src',imageGallery.prefix+imageGallery.imagesDisplay[9]);
},
animateImages:function(classFrom,classTo){
var classMoving=$(classFrom);
var classGoingTo=$(classTo);
classMoving.animate({
top:classGoingTo.css('top'),
left:classGoingTo.css('left'),
width:classGoingTo.css('width'),
opacity:classGoingTo.css('opacity')
},258,function(){
$(this).removeClass(classFrom.substr(1));
$(this).addClass(classTo.substr(1));
$(this).removeAttr('style');
});
}
};
imageGallery.init();
imageGallery.leftSelect.onclick=function(){
imageGallery.animateImages('.imageNoneRight','.imageNoneLeft');
imageGallery.animateImages('.imageRight','.imageNoneRight');
imageGallery.animateImages('.image1','.imageRight');
imageGallery.animateImages('.imageLeft','.image1');
imageGallery.animateImages('.imageNoneLeft','.imageLeft');
};
imageGallery.rightSelect.onclick=function(){
imageGallery.animateImages('.imageNoneLeft','.imageNoneRight');
imageGallery.animateImages('.imageLeft','.imageNoneLeft');
imageGallery.animateImages('.image1','.imageLeft');
imageGallery.animateImages('.imageRight','.image1');
imageGallery.animateImages('.imageNoneRight','.imageRight');
};
I have this div called 'header'. which is draggable and has a scroll bar. to prevent the div dragging when clicking the srollbar I have this code below, however it is not effective if the thumb is at the absolute top and someone clicks the the top arrow or scrolls up with the thumb. it will then start to drag. same thing for the bottom. How can I prevent this from happening. Thanks.
$("#header").draggable({
start: function() {
if ($(this).data("scrolled")) {
$(this).data("scrolled", false).trigger("mouseup");
return false;
}
}
}).find("*").andSelf().scroll(function() {
$(this).parents(".ui-draggable").data("scrolled", true);
});
If you use 'cancel' option, you can solved it easily.
Please check their official doc
http://api.jqueryui.com/draggable/#option-cancel
I have some menu items on the right hand side of my website that are: -
Basket Summary
Best Sellers
Quick Links
etc
I want the basket summary to follow down the page as the page is scrolled, I know how to this using position: fixed, but I need it to also move the other elements out of the way otherwise it will just overlap them.
I was looking at this: jsfiddle which would do the job and works but obviously thats only on button click, I would need to adapt this to scroll via jQuery.
I have read many tutorials for floated fixed divs but they are all for one div and don't have any other divs to interact with.
Any ideas if possible and/or how to do it?
Code from js fiddle as follows: -
$(function() {
$('.upButton').click(function(e){
var $parent = $('.highlight').closest('.box');
$parent.insertBefore($parent.prev());
});
$('.downButton').click(function(e){
var $parent = $('.highlight').closest('.box');
$parent.insertAfter($parent.next());
});
});
Is this what you're looking for?: http://jsfiddle.net/cmontgomery/YVh4q/
essentially, whenever the window scrolls check to see if your section is in the visible area and if not, adjust accordingly:
$(window).scroll(function () {
var mover = $("#sidebar .quick-links");
if($(window).scrollTop() === 0) {
//console.log("to top");
mover.prependTo("#sidebar");
} else if(!isFullyInViewableArea(mover)) {
var parent = mover.closest('.section');
if(isBelowViewableArea(mover)) {
//console.log("moving up");
parent.insertBefore(parent.prev());
} else {
//console.log("moving down");
parent.insertAfter(parent.next());
}
}
});
I must admit, this solution is not the best user experience, i.e. it jumps instead of scrolling smoothly. If it were me I would put the movable section as the last item in the right column and move that down the page with absolute positioning so it follows the top of the view-able area exactly.
Use this
Drag & Drop is best.
Greetings.