This onscreen plugin is meant to add classnames only to elements when they are within the viewport, however it seems to be adding the classnames as soon as the page is loaded which isn't what's meant to happen.
$(function() {
setInterval(function() {
$("#star").filter(":onScreen").addClass('animated bounceInRight');
}, 0)
})
I'm using it within this plugin which, is a book effect plugin and I think it conflicts with onscreen in some way: http://pastebin.com/UmyJ6zBW This plugin requires different sections on one page for it to work. Onscreen works when used within the first section but breaks when in others that aren't actually on view. How do I fix this?
You can do one of three things.
Don't bother. In general you don't need to worry about the style of elements that are not in view.
Use setInterval() but reduce the interval to the minimum acceptable value but no less than about 20 ms.
[preferred] Establish an event handler that fires in response to whatever causes your #star element to be moved on/off screen.
For the third approach :
jQuery animations provide for a step callback which fires as each animation step is executed.
As scrolling the document will also cause elements to come in/out of view, you probably also want to a scroll handler.
With care, you should be able to write a single function and use it for both purposes.
Related
I am implementing a functionality where I can add, drag, and delete "sticky notes" on a webpage. The app is built in Vue js but it also renders content in an iframe. All the notes that are added to the page have to be on top of the iframe (which is almost 80% of the main .vue page), therefore positioning here is important and I also have to preserve the positions because I must render the notes on the same position on next page reload. The problem is that there's a lot of lag in dragging the "note" element.
The "sticky note" itself is a very lite weight separate component.
I have noticed that this because of the iframe that's present on the vue page because when I inspect the DOM in the browser and delete the iframe and then try dragging the "note" component then it works smoothly.
Things I have tried:
Use throttling: I tried to use loadsh.throttle but that does not make any difference.
Inject "sticky note" code inside the iframe: I tried to inject a sticky note element into the iframe and append it to iframe's body. It actually makes the dragging very smooth. But I don't want to go ahead with this solution because then I will have to write a lot of extra code to maintain the state of multiple notes (which can be done easily with Vue js).
In this solution, instead of using the document of the main page to attach events for dragging, I attached all the events to iframe.contentDocument.
So the question here is how do I make the drag smooth while using vue.js
Sandbox Link: https://codesandbox.io/s/affectionate-jang-3c1hw?file=/src/components/HelloWorld.vue
In this gif, the background is actually the iframe, I have reduced its opacity to hide it.
I could not actually include the iframe in sandbox code because of cross-origin problems but I have included a lot of extra content in that sandbox to make it heavy.
UPDATE:
Using the chrome task manager, I found that the page is only taking max 200MB memory and the GPU process is taking another 200MB. I am running this on a system with 16GB RAM. So I don't think it's a memory issue. But there is a sudden spike in the CPU consumption when I start dragging the element (up to 40%).
UPDATE:
I have found the fix for this problem. The actual problem wasn't lag but it was mouse trailing i.e. the draggable element wasn't able to catch up with the fast moving mouse cursor. And the slowness was due to e.preventDefault in the dragMouseDown method inside Note.vue. Just removing the e.preventDefault fixed all the problems. Also just adding a return false at the end of dragMouseDown method seems to cause the same amount of lag.
function dragMouseDown(e) {
e = e || window.event;
// e.preventDefault(); --> this line causes the mouse trailing issue
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
// return false; --> adding this line also causes mouse trailing problem.
}
So for now I have just removed the preventDefault from this function. But I tried searching and could not find any explanation of this behavior. Also I am not sure if not cancelling the event can cause any other issue.
The problem is that you're working with mousemove without using requestAnimationFrame to debounce. Here's a working example using debounce (CodeSandbox link)
Generally, anytime you're trying to animate with javascript, you want to use requestAnimationFrame. Another thing you could try is using transform to change the position of the element instead of absolute positions.
Here's the MDN reference on requestAnimationFrame.
Here's an article by Paul Irish about using transform instead of absolute positioning to speed up a drag/drop.
As your extra description in the comments,
It starts to lag when these a lot of other content on screen. There's
a v-for in the sandbox. make it do more iterations and it will start
to laggy
The problem you met is the Dom elements were too many on your page then caused high memory usage. (Actually I tried <div v-for="i in 10000" :key="i">", then it took around 3GBs of memory), finally, everything works slowly and laggy
If your page has tons of Dom elements, you may have to consider dynamically add only visible items into the Dom tree when scrolling.
Even there are some packages that already implements this feature.
Below is one demo which uses RecycleScroller of vue-virtual-scroller:
100K items in the Codepen
You will see even the number of the items are 100,000, it still works smoothly.
PS: you may notice the below statement in the user guide of the above package=vue-virtual-scroller
The browsers have a size limitation on DOM elements, it means that
currently the virtual scroller can't display more than ~500k items
depending on the browser.
I have a number of images in my HTML document.
The user triggers some changes (AJAX calls) when clicking on an image or by pressing a key.
To keep track of the latest image (client-side), I use javascript and onmouseover, assigning the image ID to a javascript-variable which in turn is used to fill the AJAX calls.
Everything works well (even it there might be better ways to do it), but sometimes it takes some time to refresh the image. For a moment, it ceases to exist, causing the image next to it to jump left.
This, of course, moves that image underneath the pointer, triggering the mouseover event.
How(?) is it possible to distinguish between a mouseover event caused by mouse-movement from one fired by a layout change?
The short answer is you can't really tell what caused a mouseover event, other than the cursor moved over a new DOM element (or some other things, like a tap on a touch device). A layout change is just something that happens independent of this event.
One possible solution to your actual problem is to avoid the problem altogether by preventing the layout jump. For example, you could use a placeholder element to fill the space while the next image loads.
Alternately, your logic could almost-certainly be made more-robust so as not to depend on something as fragile as this.
I have a box that takes an input, then uses the scrollable's seekTo method on keyup to go to a particular slide. The problem is that if someone types quickly the scrollable gets a large queue and it takes a while for the animation to stop.
What I would like is on keyup the previous animation stops (unless the input is empty) and the new animation starts. I've tried putting .stop() in various places, but nothing seems to work.
Here is a fiddle of something similar to what I'm doing: http://jsfiddle.net/QaMZH/
Putting a number in the box (ex:1) then changing it to another number (ex: 2) will animate the scrollable to that slide number, but changing the numbers quickly queues a bunch of animations that can take a while to finish.
I had the same problem, and after searching for more detailed documentation and fail, I just dug into the code.
It turns out that all you need to do is call this before .seekTo():
api.getItemWrap().stop(true, false);
api.seekTo($(this).val(), 1000);
where getItemWrap() returns the target jQuery element where the animation takes place.
See http://jsfiddle.net/QaMZH/4/ how the modified version works.
This works because .seekTo() method calls the jQuery .animation() method on the elements, and you can cancel jQuery animations any time with .stop().
I've two (but maybe more) DIVs, animated through jQuery; so now they are running all over my screen, following pseudo random paths.
I want to fire an event every time part of a DIVoverlaps part of another one. Any ideas?
You could use something like this http://sourceforge.net/projects/jquerycollision/ and check for collisions after each animation step.
Okay, so, I have a bit of a strange situation which I have encountered multiple times. I'm looking for a simple/the best solution, NOT the overcomplicated solution I used before (and have since forgotten).
You see, I have a slideshow. I also have a couple of buttons that float on top of the slide show (visible here: http://marsxplr.com/view-13378)
Now, I have these buttons appear when the user's mouse goes over the slideshow. However, the minute the user's mouse goes over the buttons, mouseleave is called (even though the mouse is still technically over the slideshow!). This causes the buttons to disappear whenever the mouse goes over them, which is obviously not something I would like to happen.
I solved this by then making each button re-show its self whenever it receives a mouseover.
But now, we have a problem...
The button is on the very edge of the slideshow. That means that when mouseleave is called, one of two things happened:
A:The mouse went off of the button but not off of the slideshow, and mouseEnter got called on the slideshow meaning that no action should be taken because slideshow will eventually take care of hiding the button in its mouseleave.
B: The mouse simply left the slideshow and button altogether meaning that we should HIDE the button!
So my question is, how do I tell the difference between these two possibilities? Yes, yes, one solution would be to just always make the button hide its self -- and rely on the slideshow re-showing the button... But I am worried that the slideshow onmouseenter will be called BEFORE the button onmouseleave on certain browsers! This could cause issues as you can probably tell. In fact, thinking about this, I am already susceptible to this. For instance, if the mouse goes from the slideshow to the button, and the onmouseleave for my slideshow is called AFTER the onmousleave causing the button to still dissapear...
So, long story short, I need to know one of these two things:
Is there a guaranteed order in which these events are called?
Or is there a way to tell where the mouse actually WENT when mouseleave is called?
As you can see in my example above, I am using mootools, so a mootools solution is fine. It would, however, be interesting to see a vanilla-js solution as well.
EDIT:
My buttons are floated and on a separate z-index, so the standard operation for a parent-child DOM relationship does not occur
No such problem with standard DOM events.
As for the order, it bubbles from the deepest elements up to the document root.
There's also an optional (see the false param in the code below) capture phase, when the order is reversed. From the root to each inner element under the cursor (for mouse events).
To check on which inner element of the original element the event actually occurred, you can inspect the target property of the event object:
el.addEventListener('mouseout', function (e) {
var target = e.target;
if (target.classList.contains('whatever')) {
// Do something
}
}, false);
As per Georges Oates Larsen's comment, there's also relatedTarget, designed specifically for events involving several elements.