{"action":"created","comment":{"url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/comments/40603124","id":40603124,"diff_hunk":"@@ -61,10 +63,81 @@ var SGListView = React.createClass({\n         ref='nativeListView'\n         renderScrollComponent={this.renderScrollComponent}\n         renderRow={this.renderRow}\n-        onChangeVisibleRows={this.onChangeVisibleRows} />\n+        onScroll={this.handleScroll}\n+      />\n     );\n   },\n \n+  /**\n+   * Executed on every (throttled) scroll event. I don't like that, but\n+   * some quick timing indicates it handles the interval query in <1ms,\n+   * so it's definitely not a bottleneck and should perform pretty well\n+   * even for a large number of elements.\n+   */\n+  handleScroll: function(evt) {\n+    //  Expand the range that we check so we catch both cells\n+    //  that become visible and cells that become invisible:\n+    //\n+    //  previous interval:  |------------|\n+    //                     y1p          y2p\n+    //\n+    //  current interval:           |------------|\n+    //                             y1           y2\n+    //\n+    //  test interval:      |--------------------|\n+    //                     yt1                  yt2\n+    //\n+    var scrollProperties = this.refs.nativeListView.scrollProperties\n+    var y1 = scrollProperties.offset\n+    var y2 = y1 + scrollProperties.visibleLength\n+\n+    // Expand the interval so that things are rendered before they come on screen:\n+    y1 -= this.props.preemptiveLoadDistance\n+    y2 += this.props.preemptiveLoadDistance\n+\n+    // See above illustration:\n+    var yt1 = Math.min(this.y1p,y1)\n+    var yt2 = Math.max(this.y2p,y2)\n+\n+    // Perform an interval tree query to find all cells that may become\n+    // either hidden or visible:\n+    this.layoutTree.queryInterval( yt1, yt2, (interval) => {","path":"lib/SGListView.js","position":94,"original_position":94,"commit_id":"875d17e0a3f2f35f09d4ee7ebb8d99aad4d6b7e1","original_commit_id":"875d17e0a3f2f35f09d4ee7ebb8d99aad4d6b7e1","user":{"login":"sghiassy","id":792606,"avatar_url":"https://avatars.githubusercontent.com/u/792606?v=3","gravatar_id":"","url":"https://api.github.com/users/sghiassy","html_url":"https://github.com/sghiassy","followers_url":"https://api.github.com/users/sghiassy/followers","following_url":"https://api.github.com/users/sghiassy/following{/other_user}","gists_url":"https://api.github.com/users/sghiassy/gists{/gist_id}","starred_url":"https://api.github.com/users/sghiassy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sghiassy/subscriptions","organizations_url":"https://api.github.com/users/sghiassy/orgs","repos_url":"https://api.github.com/users/sghiassy/repos","events_url":"https://api.github.com/users/sghiassy/events{/privacy}","received_events_url":"https://api.github.com/users/sghiassy/received_events","type":"User","site_admin":false},"body":"Won't this return multiple intervals? Don't we need to loop through them?","created_at":"2015-09-28T20:45:47Z","updated_at":"2015-09-28T20:45:47Z","html_url":"https://github.com/sghiassy/react-native-sglistview/pull/10#discussion_r40603124","pull_request_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10","_links":{"self":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/comments/40603124"},"html":{"href":"https://github.com/sghiassy/react-native-sglistview/pull/10#discussion_r40603124"},"pull_request":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10"}}},"pull_request":{"url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10","id":46108527,"html_url":"https://github.com/sghiassy/react-native-sglistview/pull/10","diff_url":"https://github.com/sghiassy/react-native-sglistview/pull/10.diff","patch_url":"https://github.com/sghiassy/react-native-sglistview/pull/10.patch","issue_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues/10","number":10,"state":"open","locked":false,"title":"Use explicit interval tree query for visibility test","user":{"login":"rreusser","id":572717,"avatar_url":"https://avatars.githubusercontent.com/u/572717?v=3","gravatar_id":"","url":"https://api.github.com/users/rreusser","html_url":"https://github.com/rreusser","followers_url":"https://api.github.com/users/rreusser/followers","following_url":"https://api.github.com/users/rreusser/following{/other_user}","gists_url":"https://api.github.com/users/rreusser/gists{/gist_id}","starred_url":"https://api.github.com/users/rreusser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rreusser/subscriptions","organizations_url":"https://api.github.com/users/rreusser/orgs","repos_url":"https://api.github.com/users/rreusser/repos","events_url":"https://api.github.com/users/rreusser/events{/privacy}","received_events_url":"https://api.github.com/users/rreusser/received_events","type":"User","site_admin":false},"body":"This is a pretty major change so I don't expect a simple merge, but I thought I'd share my approach. I don't know if the swapping approach is the best since it'd be great to handle this on the objective c/gpu/whatnot level, but until then, I was trying to improve the robustness of the visibility check since it's been a challenge to optimize both robustness and performance (i.e. a small preemptiveLoading number results in cells being hidden accidentally; a large number slows it down a bit).\r\n\r\nIt wasn't quite clear to me what the built-in check was doing, so I thought I'd try maintaining an [interval tree](https://github.com/mikolalysenko/interval-tree-1d) explicitly. When a cell is laid out, it registers or updates its bounds in an interval tree. On each scroll event, the union of the previous visible range and current visible range is queried for intersecting cells in order to determine any visibility changes. I didn't like using onScroll, but a quick check indicates the check comes back under 1ms, so it shouldn't be a bottleneck at least.\r\n\r\nIt accepts a `preemptiveLoadDistance` that defines the distance in pixels outside the visible range at which cells become visible.\r\n\r\nFinal question: I had a hard time following the subtleties of the discussion at facebook/react-native#499 . Is there an approach yet that makes all of this obsolete?","created_at":"2015-09-27T20:49:41Z","updated_at":"2015-09-28T20:45:47Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3b26f2bc139d41342855bcf6b779b6b2019e9758","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10/commits","review_comments_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10/comments","review_comment_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/comments{/number}","comments_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues/10/comments","statuses_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/statuses/875d17e0a3f2f35f09d4ee7ebb8d99aad4d6b7e1","head":{"label":"rreusser:interval-tree-query","ref":"interval-tree-query","sha":"875d17e0a3f2f35f09d4ee7ebb8d99aad4d6b7e1","user":{"login":"rreusser","id":572717,"avatar_url":"https://avatars.githubusercontent.com/u/572717?v=3","gravatar_id":"","url":"https://api.github.com/users/rreusser","html_url":"https://github.com/rreusser","followers_url":"https://api.github.com/users/rreusser/followers","following_url":"https://api.github.com/users/rreusser/following{/other_user}","gists_url":"https://api.github.com/users/rreusser/gists{/gist_id}","starred_url":"https://api.github.com/users/rreusser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rreusser/subscriptions","organizations_url":"https://api.github.com/users/rreusser/orgs","repos_url":"https://api.github.com/users/rreusser/repos","events_url":"https://api.github.com/users/rreusser/events{/privacy}","received_events_url":"https://api.github.com/users/rreusser/received_events","type":"User","site_admin":false},"repo":{"id":43262781,"name":"react-native-sglistview","full_name":"rreusser/react-native-sglistview","owner":{"login":"rreusser","id":572717,"avatar_url":"https://avatars.githubusercontent.com/u/572717?v=3","gravatar_id":"","url":"https://api.github.com/users/rreusser","html_url":"https://github.com/rreusser","followers_url":"https://api.github.com/users/rreusser/followers","following_url":"https://api.github.com/users/rreusser/following{/other_user}","gists_url":"https://api.github.com/users/rreusser/gists{/gist_id}","starred_url":"https://api.github.com/users/rreusser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rreusser/subscriptions","organizations_url":"https://api.github.com/users/rreusser/orgs","repos_url":"https://api.github.com/users/rreusser/repos","events_url":"https://api.github.com/users/rreusser/events{/privacy}","received_events_url":"https://api.github.com/users/rreusser/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rreusser/react-native-sglistview","description":"","fork":true,"url":"https://api.github.com/repos/rreusser/react-native-sglistview","forks_url":"https://api.github.com/repos/rreusser/react-native-sglistview/forks","keys_url":"https://api.github.com/repos/rreusser/react-native-sglistview/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rreusser/react-native-sglistview/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rreusser/react-native-sglistview/teams","hooks_url":"https://api.github.com/repos/rreusser/react-native-sglistview/hooks","issue_events_url":"https://api.github.com/repos/rreusser/react-native-sglistview/issues/events{/number}","events_url":"https://api.github.com/repos/rreusser/react-native-sglistview/events","assignees_url":"https://api.github.com/repos/rreusser/react-native-sglistview/assignees{/user}","branches_url":"https://api.github.com/repos/rreusser/react-native-sglistview/branches{/branch}","tags_url":"https://api.github.com/repos/rreusser/react-native-sglistview/tags","blobs_url":"https://api.github.com/repos/rreusser/react-native-sglistview/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rreusser/react-native-sglistview/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rreusser/react-native-sglistview/git/refs{/sha}","trees_url":"https://api.github.com/repos/rreusser/react-native-sglistview/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rreusser/react-native-sglistview/statuses/{sha}","languages_url":"https://api.github.com/repos/rreusser/react-native-sglistview/languages","stargazers_url":"https://api.github.com/repos/rreusser/react-native-sglistview/stargazers","contributors_url":"https://api.github.com/repos/rreusser/react-native-sglistview/contributors","subscribers_url":"https://api.github.com/repos/rreusser/react-native-sglistview/subscribers","subscription_url":"https://api.github.com/repos/rreusser/react-native-sglistview/subscription","commits_url":"https://api.github.com/repos/rreusser/react-native-sglistview/commits{/sha}","git_commits_url":"https://api.github.com/repos/rreusser/react-native-sglistview/git/commits{/sha}","comments_url":"https://api.github.com/repos/rreusser/react-native-sglistview/comments{/number}","issue_comment_url":"https://api.github.com/repos/rreusser/react-native-sglistview/issues/comments{/number}","contents_url":"https://api.github.com/repos/rreusser/react-native-sglistview/contents/{+path}","compare_url":"https://api.github.com/repos/rreusser/react-native-sglistview/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rreusser/react-native-sglistview/merges","archive_url":"https://api.github.com/repos/rreusser/react-native-sglistview/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rreusser/react-native-sglistview/downloads","issues_url":"https://api.github.com/repos/rreusser/react-native-sglistview/issues{/number}","pulls_url":"https://api.github.com/repos/rreusser/react-native-sglistview/pulls{/number}","milestones_url":"https://api.github.com/repos/rreusser/react-native-sglistview/milestones{/number}","notifications_url":"https://api.github.com/repos/rreusser/react-native-sglistview/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rreusser/react-native-sglistview/labels{/name}","releases_url":"https://api.github.com/repos/rreusser/react-native-sglistview/releases{/id}","created_at":"2015-09-27T20:06:26Z","updated_at":"2015-09-27T20:06:26Z","pushed_at":"2015-09-27T21:14:04Z","git_url":"git://github.com/rreusser/react-native-sglistview.git","ssh_url":"git@github.com:rreusser/react-native-sglistview.git","clone_url":"https://github.com/rreusser/react-native-sglistview.git","svn_url":"https://github.com/rreusser/react-native-sglistview","homepage":null,"size":174,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"sghiassy:master","ref":"master","sha":"424cf621baa42f21c010fc618100a794dee259f0","user":{"login":"sghiassy","id":792606,"avatar_url":"https://avatars.githubusercontent.com/u/792606?v=3","gravatar_id":"","url":"https://api.github.com/users/sghiassy","html_url":"https://github.com/sghiassy","followers_url":"https://api.github.com/users/sghiassy/followers","following_url":"https://api.github.com/users/sghiassy/following{/other_user}","gists_url":"https://api.github.com/users/sghiassy/gists{/gist_id}","starred_url":"https://api.github.com/users/sghiassy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sghiassy/subscriptions","organizations_url":"https://api.github.com/users/sghiassy/orgs","repos_url":"https://api.github.com/users/sghiassy/repos","events_url":"https://api.github.com/users/sghiassy/events{/privacy}","received_events_url":"https://api.github.com/users/sghiassy/received_events","type":"User","site_admin":false},"repo":{"id":40141478,"name":"react-native-sglistview","full_name":"sghiassy/react-native-sglistview","owner":{"login":"sghiassy","id":792606,"avatar_url":"https://avatars.githubusercontent.com/u/792606?v=3","gravatar_id":"","url":"https://api.github.com/users/sghiassy","html_url":"https://github.com/sghiassy","followers_url":"https://api.github.com/users/sghiassy/followers","following_url":"https://api.github.com/users/sghiassy/following{/other_user}","gists_url":"https://api.github.com/users/sghiassy/gists{/gist_id}","starred_url":"https://api.github.com/users/sghiassy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sghiassy/subscriptions","organizations_url":"https://api.github.com/users/sghiassy/orgs","repos_url":"https://api.github.com/users/sghiassy/repos","events_url":"https://api.github.com/users/sghiassy/events{/privacy}","received_events_url":"https://api.github.com/users/sghiassy/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sghiassy/react-native-sglistview","description":"","fork":false,"url":"https://api.github.com/repos/sghiassy/react-native-sglistview","forks_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/forks","keys_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/teams","hooks_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/hooks","issue_events_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues/events{/number}","events_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/events","assignees_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/assignees{/user}","branches_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/branches{/branch}","tags_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/tags","blobs_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/git/refs{/sha}","trees_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/statuses/{sha}","languages_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/languages","stargazers_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/stargazers","contributors_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/contributors","subscribers_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/subscribers","subscription_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/subscription","commits_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/commits{/sha}","git_commits_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/git/commits{/sha}","comments_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/comments{/number}","issue_comment_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues/comments{/number}","contents_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/contents/{+path}","compare_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/merges","archive_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/downloads","issues_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues{/number}","pulls_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls{/number}","milestones_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/milestones{/number}","notifications_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/labels{/name}","releases_url":"https://api.github.com/repos/sghiassy/react-native-sglistview/releases{/id}","created_at":"2015-08-03T18:34:09Z","updated_at":"2015-09-27T05:27:48Z","pushed_at":"2015-09-28T20:44:05Z","git_url":"git://github.com/sghiassy/react-native-sglistview.git","ssh_url":"git@github.com:sghiassy/react-native-sglistview.git","clone_url":"https://github.com/sghiassy/react-native-sglistview.git","svn_url":"https://github.com/sghiassy/react-native-sglistview","homepage":null,"size":174,"stargazers_count":85,"watchers_count":85,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9,"mirror_url":null,"open_issues_count":2,"forks":9,"open_issues":2,"watchers":85,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10"},"html":{"href":"https://github.com/sghiassy/react-native-sglistview/pull/10"},"issue":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues/10"},"comments":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/issues/10/comments"},"review_comments":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10/comments"},"review_comment":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/pulls/10/commits"},"statuses":{"href":"https://api.github.com/repos/sghiassy/react-native-sglistview/statuses/875d17e0a3f2f35f09d4ee7ebb8d99aad4d6b7e1"}}}}