I'm building an hybrid app using ionic and AngularJS (AngularJS-material). This app also has an integrated chat built with Node.js and socket.io.
I have the problem now that with only 200 messages the app gets very slow to load all the messages (200ms in Browser -> 4sec in app, even with CrossWalk, and with track by message.id) and also typing in the the textarea to insert the message is slowed down.
I have two solutions to resolve this:
Virtual Repeat (md-virtual-repeat)
Infinite Scroll (ion-infinite-scroll)
1) I think that virtual repeat would be the best solution (I have already implemented it on another page and it scrolls 1500 items like a charm) but the problem is that the messages can have different heights based on their lenghts and md-virtual-repeat requirements are that all the elements must have the same height to work.
2) So maybe we can pivot to the Infinite Scroll method but the problem now is that doing it with the ion-infinite-scroll directive gets a bit tricky since a chat needs to trigger the loadMore() when reaching the top and not the bottom.
So my question is: Does anybody have a workaround to have a smooth/fast ng-repeat inside a chat using or a virtual-repeat directive that can handle different heights or an infinite scroll that works at the top ?
Efficient scroll lists like md-virtual-repeat or collection-repeat need to know the height of each item in order to work. That’s because they need to know the scroll position, e.g. to show a scrollbar or to be able to skip frames for quick swipe-down motions. The scroll position itself can only be found if you know both how much has been scrolled (we need the height of elements above) and how much there is left to scroll (we need the height of elements below).
What you can do is use a factory to compute the height of each element before injecting them into the loop. This can be done by creating a container with the same properties as the target container (e.g. CSS classes), appending the newly-loaded elements, compute their height (using element.offsetHeight), and removing the container after.
Be aware that this is quite heavy and will likely cause a small lag spike.
Couple of things you could try to speed it up.
One would be to use something like quick-ng-repeat: https://github.com/allaud/quick-ng-repeat instead of built in angular js ng-repeat
Another would be to use one time binding where ever possible to prevent angular from constantly looking for changes during every digest cycle: https://docs.angularjs.org/guide/expression#one-time-binding
And of course, if it's possible, try using chrome's developer tool profile option to find out which of the functions are slowing the application down ; )
PS: Might be worth checking out this thread to see how reverse infinite scrolling could be implemented: Implementing a reverse infinite scroll using ngInfiniteScroll directive in AngularJS
Have you taken a look at React.js as a solution? It uses a virtual DOM which makes updating long lists more efficient.
There is an open-source repo on GitHub that mixes Angular and React, called ngReact.
overview:
http://ngreact.github.io/ngReact/
docs:
http://ngreact.github.io/ngReact/docs/ngReact.html
repo:
https://github.com/ngReact/ngReact
Hope this helps.
Using separate binders like rivets could be a good solution,its easy to integrate and its having rv-each to loop
I think the ionic directive collection-repeat might be what you're looking for.
collection-repeat allows an app to show huge lists of items much more
performantly than ng-repeat. It renders into the DOM only as many
items as are currently visible. This means that on a phone screen that
can fit eight items, only the eight items matching the current scroll
position will be rendered.
Look at angular-vs-repeat angular-vs-repeat
Demo: demo
I use line length for calculation height of items.
It's very approximate method. In our app we know, that one English character with font-size 15px will have width about 6.7px (that's fine, if you use monospace font, but it's not our case). Also we always know width of each segments and height of one text line.
itemHeight = commulativeTextLenght / lineWidth + paddingsOfItem;
Also line break stile can affect your calculation. In general we had a not bad method to calculate heights of about 8000 text paragraphs.
Related
I'm using a library called ParticlesJS for part of the background of my website - this library dynamically generates a canvas element sized according to its parent, and fills it with animated particle effects, creating a neat effect. With that said, I have run into some practical issues when trying to use it as the background:
If the canvas element is the same size as the content, the visuals become pixelated and distorted if the height changes, such as with the addition of new content. Reloading the library is not a solution to this as it creates a visually distracting effect.
If the canvas element is an arbitrary extreme height and not sized according to the content (with the overflow simply hidden), the performance of the website suffers, as the library consumes excessive CPU power.
If the canvas element is simply given a fixed position in CSS, performance is good and it sticks, but it looks out of place as everything behind it moves during scrolling.
After some consideration, it seems like the best way to make it work is to give it a modest size (like 200% page height), and then make it repeat infinitely during scrolling - performance would be acceptable, and there wouldn't be any distortion. However, I can't find any way to do this - I'm aware that there's a background-repeat property in CSS, but that seems to only work for images.
Is there any way to do what I'm trying to accomplish? Both CSS and JS based answers are welcome.
After some trial and error, it looks like the only means of accomplishing what I'm trying to do is as follows:
Create 3 or so background divs, each the size of the view port, and stack them vertically
Record user scrolling activity, and set a trigger for when a user has scrolled a height equal to the height of the view port
when the trigger is hit, place the div that just left the view port at the end of the list, and insert an empty spacer div where it used to be
If done correctly, this creates an effect where the user is apparently scrolling through an infinite background, when it's really just the same 3 or so divs being shuffled over and over. Going in reverse is the same principle.
Not sure how to make this work with in a system that also has scroll position restoration, but it could probably be done by waiting for page loads and then dynamically inserting enough spacers to move the background divs to the appropriate position in the view port.
The downside to using animated effects that rely on viewport dimensions is that the user may resize the browser and wreck your animation so you have no choice but to catch any viewport resizing in which case you may have to reload everything or recalculate!
You can't have the cake and the cherry on top unfortunately, so you'll either have to abandon the idea of "impressive effects" because they are impractical or take action...
document.body.onresize=function(){Adjustments();};
function Adjustments(){
var W=Container.offsetWidth, H=Container.offsetHeight;
// You've now got the new resolution so go for your life!
}
I´m trying to code blog and i want to synchronise positions of timeline events and it´s posts. I coded it as two different columns and I´m trying to get height of post with jQuery and then count the size of blank space in timeline event. Everything seems to be set OK, console gives me equivalent numbers and so the programmer tools in chrome. You can see the height of the post here and these are heights of elements next to it: element1, element2, element3. Together, it 740px but the main element-post is also 740px.
So, I would like to know, how is this possible? Thank you.
As you can see in the pictures, the margin is not included in the size. So, for instance, while that "G+" icon may be 32x32, with margins, it taking up what looks to be closer to maybe 48x48. And the height of the article is only referring to up to the green line (the padding).
There are probably multiple ways of solving this, but using what you're doing now, if you wrap those margin-spaced elements in divs, then those wrapping divs will have the correct sizing themselves.
I want to implement infinite scroll using virtual ng-repeat.
But there is one caveat - I have dynamic row height.
Imagine simple chat. Length (content / height) of messages may vary.
I wonder how it's implemented in most messengers and G+, for example. They all had the same issue.
In G+ the feed has blocks with different height. Do they use Virtual Repeat?
md-virtual-repeat and collection-repeat don't work for me because they want constant height for all rows (messages)
Even if I use them, there some scroll positioning issues.
They take dimensions from first element if none is specified explicitly.
ngInfiniteScroll has nothing common with word virtual. It spawns enormous amount of watchers.
Any ideas?
Thanks!
I am a developer for a web application. In this application there is a certain scenario where there are multiple position:fixed elements, and canvases and a overflow:scroll element. In this scenario, scrolling is super slow on firefox when smooth scrolling is enabled.
From the user's perspective the solution is simply to disable smooth scrolling. However, as a developer I can't ensure that the user has done this.
Is there anywhere that I can tell firefox to not to use smooth scrolling for my website from javascript (or html)? Or is there any other known workaround for this?
I do understand that your question basically is how to disable smooth scrolling. however I will answer you a little differently to get this working.
Why different?
Even if you can detect smooth scrolling of users, you cannot force the user to disable it. In other words, you are trying to cover the problem instead of solving it. so lets solve it!
Intro: pixels-to-screen pipeline
On each frame the browser does the following steps to render the page on screen.
JavaScript. Typically JavaScript is used to handle work that will result in visual changes, whether it’s jQuery’s animate function, sorting a data set, or adding DOM elements to the page. It doesn’t have to be JavaScript that triggers a visual change, though: CSS Animations, Transitions, and the Web Animations API are also commonly used.
Style calculations. This is the process of figuring out which CSS rules apply to which elements based on matching selectors, e.g. .headline or .nav > .nav__item. From there, once rules are known, they are applied and the final styles for each element are calculated.
Layout. Once the browser knows which rules apply to an element it can begin to calculate how much space it takes up and where it is on screen. The web’s layout model means that one element can affect others, e.g. the width of the element typically affects its children’s widths and so on all the way up and down the tree, so the process can be quite involved for the browser.
Paint. Painting is the process of filling in pixels. It involves drawing out text, colors, images, borders, and shadows, essentially every visual part of the elements. The drawing is typically done onto multiple surfaces, often called layers.
Compositing. Since the parts of the page were drawn into potentially multiple layers they need to be drawn to the screen in the correct order so that the page renders correctly. This is especially important for elements that overlap another, since a mistake could result in one element appearing over the top of another incorrectly.
details and source: https://developers.google.com/web/fundamentals/performance/rendering/?hl=en
Step 1:
First step is to remove render costly css properties. You might not be able to remove alot, however you can replace rgba(255,255,255,1); with #fff which removes the alpha layer.
check this for more details: https://csstriggers.com/
some properties do not need to do a layout or a paint and there are less heavy than others.
Step 2:
Check for forced synchronous layout triggers. These happen when you force the browser to do a layout while its in the javascript step, then return to javascript, instead of walking smoothly along the pipeline on each frame. to do this, avoid getting layout attributes and setting them directly afterwards in a loop for example.
here is a list of what causes sync layout: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
read more: https://developers.google.com/web/tools/chrome-devtools/profile/rendering-tools/forced-synchronous-layouts?hl=en
Step 3:
Move components on the page that need to be repainted regularly into new layers.
The browser needs to repaint every time you scroll or an animation is playing. to avoid a full page repaint and only repaint the part that is changing, move that part (ex parallax, navigation, animation) to a new layer on the browser (think about it like photoshop layers)
to do so use the will-change css property to tell the browser to move it to a new layer, and use transform: translateZ(0); if you want to force the broswer to move it.
Have you tried adding
backface-visibility: hidden;
to you fixed position elements?
I would rather fix the source of the problem. Often there is one small detail that creates a giant bottleneck and that is easy to fix with the change of one line of code or something. Note that you most probably won't need to reduce the "good looks" of the app at all; it's just a matter of avoiding the small but devastating-for-performance details of the browser's layout engine.
I'll make a guess and say that something on you web app is causing very large repaints and/or frequent reflows. Check for things like usage of offsetTop and position: fixed. Also using requestAnimationFrame instead of updating for every scroll event is something worth looking at. Here's a good guide on both finding and fixing scrolling performance problems.
Use inspect element to try and get a handle on the specific cause.
Also, if you've not installed FireBug, install it and use it instead of the default inspect element. This will give you more code details and allow you to step through the script to find the problem.
There also plugins for FireBug for various frameworks, which can aid the diagnostics if your using one of those frameworks.
We can make assumptions about the cause or come up with shotgun solutions; but, only you can diagnose your code to find the specifics.
I have a grid of div boxes that I will be animating. They will be moving across the screen after a user drags one of the boxes (to re-align into a grid).
Currently I am using JQuery to change the css left and top positions of all of the divs and running this on an interval.
It is laggy if there are more than 50 boxes. How do I make this less laggy? Is there an animation library that is better for this, or do I just need to limit it to 50 boxes?
Image of layout:
You have a few options to optimize the performance.
Newer browsers have requestAnimationFrame that lets the browser take care of the animation timing in order to optimize Javascript animations. Rather than using times to perform the animation, which is what jQuery framework uses, you repeatedly a callback to requestAnimationFrame. The browser will call your function with a progress variable for the animation, and you render the current stage of your animation based on the progress variable. requestAnimationFrame for smarting animating talks about this in depth. Google Closure is the only framework I am aware of that uses requestAnimationFrame however, and it's rather heavyweight.
CSS animations. jQuery offers CSS animation, so do many other frameworks. CSS animations give you hardware acceleration, so the animation is much faster. Unfortunately, CSS animations are relatively new and not yet well supported, so you'll probably end up falling back to Javascript animation on older browsers, depending on the library you use.
Optimize your Javascript. Instead of animation each and every box in the grid, encapsulate each row in a div and animate the entire div instead. That should speed the animation up by a bit. I'm sure there are other ways you can optimize based on your current implementation.
Honestly, I don't know of any library that will make this work more efficiently for you, though there are many libraries out there that are faster than jQuery. The issue isn't just the jQuery, its the fact that you have 50 elements that are all moving/draggable, thus requiring a lot of the browser's resources.
If you can post your code there may be a few things that we could suggest to speed it up slightly.
The two biggest things problems that I can think of are if you added those boxes programmatically and added the handler for each as you added the element to the page, and if you don't store your selectors in variables. Aside from that I would have to see the code.
Have a look at:
jQuery isotope
It has options to allow you to use css3 animations if available or use jQuery / JS animations.
Handy for grid like animation and arrangements.
Some brave soul has managed to add drag and drop to isotope too. http://tyler-designs.com/masonry-ui/ (a bit clunky but works)
There are several ways of increasing the performance. One would be to reduce the amount of DOM elements required for each box. Another is to not animate (and render) boxes outside of the current viewport. Give all boxes that are outside of the viewable area "display: none;" and exclude them before starting a new animation. If you want to go even further you can start to recycle boxes instead of showing and hiding them when the user is scrolling through the page.
This way you will always get the same performance no matter how many boxes you have (above the amount that you can fit in the viewport).
This technique is called UI virtualization. There are several projects that use it like: http://github.com/mleibman/SlickGrid/wiki. It's really useful when you need to render a lot of elements (hundreds, thousands, millions). But it takes quite some work to get it right. And I don't know about any generic working components that are easy to plug in. I tried to find an article that explains it. This is the only thing I could come up with for now, it's for Silverlight though: http://www.silverlightshow.net/items/Virtualization-in-Silverlight-4-RC.aspx
Also try this this plugin for jQuery. Use the regular 'animate' method and it will try to use (hardware accelerated) CSS animations where possible: http://playground.benbarnett.net/jquery-animate-enhanced/