{"action":"created","issue":{"url":"https://api.github.com/repos/aurelia/ui-virtualization/issues/27","labels_url":"https://api.github.com/repos/aurelia/ui-virtualization/issues/27/labels{/name}","comments_url":"https://api.github.com/repos/aurelia/ui-virtualization/issues/27/comments","events_url":"https://api.github.com/repos/aurelia/ui-virtualization/issues/27/events","html_url":"https://github.com/aurelia/ui-virtualization/pull/27","id":127025421,"number":27,"title":"Native scrolling","user":{"login":"martingust","id":5166897,"avatar_url":"https://avatars.githubusercontent.com/u/5166897?v=3","gravatar_id":"","url":"https://api.github.com/users/martingust","html_url":"https://github.com/martingust","followers_url":"https://api.github.com/users/martingust/followers","following_url":"https://api.github.com/users/martingust/following{/other_user}","gists_url":"https://api.github.com/users/martingust/gists{/gist_id}","starred_url":"https://api.github.com/users/martingust/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/martingust/subscriptions","organizations_url":"https://api.github.com/users/martingust/orgs","repos_url":"https://api.github.com/users/martingust/repos","events_url":"https://api.github.com/users/martingust/events{/privacy}","received_events_url":"https://api.github.com/users/martingust/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-01-16T13:36:54Z","updated_at":"2016-01-18T22:08:57Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/aurelia/ui-virtualization/pulls/27","html_url":"https://github.com/aurelia/ui-virtualization/pull/27","diff_url":"https://github.com/aurelia/ui-virtualization/pull/27.diff","patch_url":"https://github.com/aurelia/ui-virtualization/pull/27.patch"},"body":"This is an experimental branch on leveraging the browsers native scroll and scroll bar. This pull request should only act as a place to collaborate on the implementation and should not be merged to master. \r\n\r\n#### Approach\r\nThe idea for this approach comes from @AStoker\r\n``` css\r\n.scroll-container {\r\n   overflow: scroll;\r\n}\r\n```\r\n``` html\r\n<div class=\"scroll-container\">\r\n   <ul class=\"scrolling-list\">\r\n      <li class=\"scroll-top-buffer\"></li>\r\n      <li virtual-repeat.for=\"item of items\">\r\n        <template replaceable part=\"item-template\"></template>\r\n      </li>\r\n      <li class=\"scroll-bottom-buffer\"></li>\r\n   </ul>\r\n</div>\r\n```\r\nYou could then as you scroll through the list of items, determine the height of the element you're popping off and add that height to the `<li class=\"scroll-top-buffer\"></li>`. Likewise for the scroll buffer on the bottom.\r\n\r\n#### Implementation\r\nThe plugin sets up a `requestAnimationFrame` recursion to check current scroll position. Current scroll position is checked be [looking at `scrollTop`](https://github.com/aurelia/ui-virtualization/blob/native-scrolling/src/virtual-repeat.js#L179) of the container. If the top element is scrolled outside of the view port it gets [moved to the bottom and re-bound](https://github.com/aurelia/ui-virtualization/blob/native-scrolling/src/virtual-repeat.js#L393) to whatever the bindingContext is for that position at the bottom, likewise when scrolling up the elements get scrolled outside of the view port at the bottom, the elements get [moved and re-bound](https://github.com/aurelia/ui-virtualization/blob/native-scrolling/src/virtual-repeat.js#L410) to the top of the list. \r\n\r\nThe speed the users scroll will vary a lot, between different devices and scroll inputs. When a user is scrolling faster than what the `requestAnimationFrame` loop can keep up with, list items start being skipped. This is guarded by looking if any elements are skipped and if so, slow down the move/rebind by only taking the [next element in the order](https://github.com/aurelia/ui-virtualization/blob/native-scrolling/src/virtual-repeat.js#L190).  This makes sure that no matter how fast the user scrolls no items will be skipped. However move/rebind-phase only one element has obviously a limit on how many elements can be moved and rebound per time unit. Lets say the list has 1000 items, the user quickly drags the scrollbar to the bottom, the list has to go through move and re-bind almost 1000 items, although only a few items at the bottom will be viewed by the user. To speed up this the lists checks how many items are being skipped, if above a certain threshold ([currently 2 times the number of elements rendered in the DOM](https://github.com/aurelia/ui-virtualization/blob/native-scrolling/src/virtual-repeat.js#L191)) the list skipping move and rebind a certain number of elements ([currently half of the number items being skipped](https://github.com/aurelia/ui-virtualization/blob/native-scrolling/src/virtual-repeat.js#L192)), this gives the list a chance to faster keep up with the scroll position the give the user desired element without have the render unnecessary elements. These numbers can of course be tinkered with. \r\n\r\nIn addition to give the list some room to keep up with scrolling a certain number of elements can be buffered above and below. This number should probably be a setting for the user to set depending on requirements.\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/aurelia/ui-virtualization/issues/comments/172667438","html_url":"https://github.com/aurelia/ui-virtualization/pull/27#issuecomment-172667438","issue_url":"https://api.github.com/repos/aurelia/ui-virtualization/issues/27","id":172667438,"user":{"login":"martingust","id":5166897,"avatar_url":"https://avatars.githubusercontent.com/u/5166897?v=3","gravatar_id":"","url":"https://api.github.com/users/martingust","html_url":"https://github.com/martingust","followers_url":"https://api.github.com/users/martingust/followers","following_url":"https://api.github.com/users/martingust/following{/other_user}","gists_url":"https://api.github.com/users/martingust/gists{/gist_id}","starred_url":"https://api.github.com/users/martingust/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/martingust/subscriptions","organizations_url":"https://api.github.com/users/martingust/orgs","repos_url":"https://api.github.com/users/martingust/repos","events_url":"https://api.github.com/users/martingust/events{/privacy}","received_events_url":"https://api.github.com/users/martingust/received_events","type":"User","site_admin":false},"created_at":"2016-01-18T22:08:57Z","updated_at":"2016-01-18T22:08:57Z","body":"@vamp Cool, I like how they split up the list in clusters, that works pretty good. One problem using `Clusterize.js` for is that it will destroy the view comments Aurelia creates to determine the view boundaries. We could use `Clusterize.js` own handling of list changes, however it only support append and prepend also we would loose animation capabilities and the view lifecycle when iterating bahaviors. Perhaps we could look into how they handle the clusters and get some ideas from there. \r\n\r\n@AStoker thoughts?"}}