{"action":"closed","number":3660,"pull_request":{"url":"https://api.github.com/repos/openlayers/ol3/pulls/3660","id":34704837,"html_url":"https://github.com/openlayers/ol3/pull/3660","diff_url":"https://github.com/openlayers/ol3/pull/3660.diff","patch_url":"https://github.com/openlayers/ol3/pull/3660.patch","issue_url":"https://api.github.com/repos/openlayers/ol3/issues/3660","number":3660,"state":"closed","locked":false,"title":"Smooth rendering of parameter changes","user":{"login":"thomasmoelhave","id":179143,"avatar_url":"https://avatars.githubusercontent.com/u/179143?v=3","gravatar_id":"","url":"https://api.github.com/users/thomasmoelhave","html_url":"https://github.com/thomasmoelhave","followers_url":"https://api.github.com/users/thomasmoelhave/followers","following_url":"https://api.github.com/users/thomasmoelhave/following{/other_user}","gists_url":"https://api.github.com/users/thomasmoelhave/gists{/gist_id}","starred_url":"https://api.github.com/users/thomasmoelhave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomasmoelhave/subscriptions","organizations_url":"https://api.github.com/users/thomasmoelhave/orgs","repos_url":"https://api.github.com/users/thomasmoelhave/repos","events_url":"https://api.github.com/users/thomasmoelhave/events{/privacy}","received_events_url":"https://api.github.com/users/thomasmoelhave/received_events","type":"User","site_admin":false},"body":"Rationale:\r\n---------------\r\n\r\nThere are many use-cases where one or more frequently changing parameter/dimension for a WMTS source are used. One such example is issue #2827 and in our SCALGO Live products we also have several different  types of WMTS layers where a continuous dimension made available in the UI through a slider. An example of this is the [sea-level flooding] (http://scalgo.com/live/global?center=-10546029.2%2C3387094.1&zoom=5&tool=zoom&lrs=basic%2Cglobal%2Fhydrosheds%3Adem%2Cglobal%2Fhydrosheds%3Asea-levels&flooding=10) layer, and there is a similar interaction for [flow accumulation](http://scalgo.com/live/global?center=1717825.6%2C5738245.9&zoom=5&tool=zoom&lrs=basic%2Cglobal%2Fhydrosheds%3Adem%2Cglobal%2Fhydrosheds%3Aedgeflow&edge_flow=3509720000). In the former, the sea-level rise is set via a dimension/parameter to the GetTile request, and when the user drags the slider around, the sea level changes (the WMTS server delivers tiles with the appropriate sea level). In stock openlayers, this is not well supported as no tiles are rendered until the new tiles are ready, resulting in heavy flickering. \r\n\r\nThis non-trivial patch changes the image tile renderer to keep rendering old tiles while the new tiles are being loaded, this significantly improves the use cases where such rapid changes in a dimension are being performed. We have created an [example](http://scalgo.com/stuff/ol3/build/examples/smooth-params.html), supplementing the one in issue #2827, that clearly illustrates the use case. You can see the regular WMTS mode on the left, and the new on the right. Use the sea-level slider to change the sea level and notice how the regular WMTS layer flickers significantly, especially when you slowly drag the slider (which is a very common use case). This patch does not change the semantics of existing WMTS layers, the smooth mode has to be explicitly requested by designating which dimensions  should be treated this way.  We have already been running this patch in production for several months (and it's used in the links above) with no issues for both regular WMTS layers and WMTS layers with a smooth dimension.\r\n\r\nDetails:\r\n---------------\r\nFirst, the patch tells WTMS sources to ignore certain dimensions when building tile cache keys. That way, when these parameters change, the existing tiles are not immediately discarded (or ignored) from the cache. Instead, the old tiles are still rendered. Without any other changes to the code, just this change would cause the ignored dimensions to have no effect on rendering at all.\r\n\r\nWhen the ignored dimensions do change, we added a new method that, when called, explicitly reloads all the currently-visible tiles, and purges all the not visible tiles.\r\n\r\nTile reloading for this method uses a mechanism we called \"out-of-band\" in the code. Essentially, we turned each tile in the cache into a linked list of tiles. The head of the list is the current tile, and the second node (if any) is a tile waiting to be loaded. If there's a third node in the linked list (which is less common), that means the second node tile is in a loading state, but yet another tile has been requested. If a linked list gets flooded with load requests (which often happens for e.g. slider inputs), the linked list builder drops tile nodes that it knows will never be rendered. This load shedding generally keeps the length of the linked list to at most three.\r\n\r\nThis tile loading mechanism uses the ol3 tile load queue, so it still takes advantage of all the nice work scheduling for image loading that the ol3 engine uses.\r\n\r\nWe also made a small change to the image tile renderer to check the state of the linked list for each tile to decide which one to render for that frame.\r\n\r\nThe patch passes the Travis CI test and is rebased on top of current ol3 master. We have split the patch into one commit for the base functionality (I am not sure it's necessary to further subdivide that commit) and a separate commit for the example. I have filled out the corporate contributor license agreement and can send that in when it becomes relevant.\r\n\r\nWe appreciate your comments.\r\n","created_at":"2015-05-05T08:40:07Z","updated_at":"2015-11-16T13:03:22Z","closed_at":"2015-11-16T13:03:22Z","merged_at":null,"merge_commit_sha":"c7e69e5e06ee736e5137de9a1d7fb8ec08cf453e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openlayers/ol3/pulls/3660/commits","review_comments_url":"https://api.github.com/repos/openlayers/ol3/pulls/3660/comments","review_comment_url":"https://api.github.com/repos/openlayers/ol3/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openlayers/ol3/issues/3660/comments","statuses_url":"https://api.github.com/repos/openlayers/ol3/statuses/f8de2bf4171c45a88ecb116dc8ff1bc09afc4598","head":{"label":"thomasmoelhave:smoothparams_clean","ref":"smoothparams_clean","sha":"f8de2bf4171c45a88ecb116dc8ff1bc09afc4598","user":{"login":"thomasmoelhave","id":179143,"avatar_url":"https://avatars.githubusercontent.com/u/179143?v=3","gravatar_id":"","url":"https://api.github.com/users/thomasmoelhave","html_url":"https://github.com/thomasmoelhave","followers_url":"https://api.github.com/users/thomasmoelhave/followers","following_url":"https://api.github.com/users/thomasmoelhave/following{/other_user}","gists_url":"https://api.github.com/users/thomasmoelhave/gists{/gist_id}","starred_url":"https://api.github.com/users/thomasmoelhave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomasmoelhave/subscriptions","organizations_url":"https://api.github.com/users/thomasmoelhave/orgs","repos_url":"https://api.github.com/users/thomasmoelhave/repos","events_url":"https://api.github.com/users/thomasmoelhave/events{/privacy}","received_events_url":"https://api.github.com/users/thomasmoelhave/received_events","type":"User","site_admin":false},"repo":{"id":34791212,"name":"ol3","full_name":"thomasmoelhave/ol3","owner":{"login":"thomasmoelhave","id":179143,"avatar_url":"https://avatars.githubusercontent.com/u/179143?v=3","gravatar_id":"","url":"https://api.github.com/users/thomasmoelhave","html_url":"https://github.com/thomasmoelhave","followers_url":"https://api.github.com/users/thomasmoelhave/followers","following_url":"https://api.github.com/users/thomasmoelhave/following{/other_user}","gists_url":"https://api.github.com/users/thomasmoelhave/gists{/gist_id}","starred_url":"https://api.github.com/users/thomasmoelhave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomasmoelhave/subscriptions","organizations_url":"https://api.github.com/users/thomasmoelhave/orgs","repos_url":"https://api.github.com/users/thomasmoelhave/repos","events_url":"https://api.github.com/users/thomasmoelhave/events{/privacy}","received_events_url":"https://api.github.com/users/thomasmoelhave/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/thomasmoelhave/ol3","description":"OpenLayers 3","fork":true,"url":"https://api.github.com/repos/thomasmoelhave/ol3","forks_url":"https://api.github.com/repos/thomasmoelhave/ol3/forks","keys_url":"https://api.github.com/repos/thomasmoelhave/ol3/keys{/key_id}","collaborators_url":"https://api.github.com/repos/thomasmoelhave/ol3/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/thomasmoelhave/ol3/teams","hooks_url":"https://api.github.com/repos/thomasmoelhave/ol3/hooks","issue_events_url":"https://api.github.com/repos/thomasmoelhave/ol3/issues/events{/number}","events_url":"https://api.github.com/repos/thomasmoelhave/ol3/events","assignees_url":"https://api.github.com/repos/thomasmoelhave/ol3/assignees{/user}","branches_url":"https://api.github.com/repos/thomasmoelhave/ol3/branches{/branch}","tags_url":"https://api.github.com/repos/thomasmoelhave/ol3/tags","blobs_url":"https://api.github.com/repos/thomasmoelhave/ol3/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/thomasmoelhave/ol3/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/thomasmoelhave/ol3/git/refs{/sha}","trees_url":"https://api.github.com/repos/thomasmoelhave/ol3/git/trees{/sha}","statuses_url":"https://api.github.com/repos/thomasmoelhave/ol3/statuses/{sha}","languages_url":"https://api.github.com/repos/thomasmoelhave/ol3/languages","stargazers_url":"https://api.github.com/repos/thomasmoelhave/ol3/stargazers","contributors_url":"https://api.github.com/repos/thomasmoelhave/ol3/contributors","subscribers_url":"https://api.github.com/repos/thomasmoelhave/ol3/subscribers","subscription_url":"https://api.github.com/repos/thomasmoelhave/ol3/subscription","commits_url":"https://api.github.com/repos/thomasmoelhave/ol3/commits{/sha}","git_commits_url":"https://api.github.com/repos/thomasmoelhave/ol3/git/commits{/sha}","comments_url":"https://api.github.com/repos/thomasmoelhave/ol3/comments{/number}","issue_comment_url":"https://api.github.com/repos/thomasmoelhave/ol3/issues/comments{/number}","contents_url":"https://api.github.com/repos/thomasmoelhave/ol3/contents/{+path}","compare_url":"https://api.github.com/repos/thomasmoelhave/ol3/compare/{base}...{head}","merges_url":"https://api.github.com/repos/thomasmoelhave/ol3/merges","archive_url":"https://api.github.com/repos/thomasmoelhave/ol3/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/thomasmoelhave/ol3/downloads","issues_url":"https://api.github.com/repos/thomasmoelhave/ol3/issues{/number}","pulls_url":"https://api.github.com/repos/thomasmoelhave/ol3/pulls{/number}","milestones_url":"https://api.github.com/repos/thomasmoelhave/ol3/milestones{/number}","notifications_url":"https://api.github.com/repos/thomasmoelhave/ol3/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/thomasmoelhave/ol3/labels{/name}","releases_url":"https://api.github.com/repos/thomasmoelhave/ol3/releases{/id}","created_at":"2015-04-29T11:56:51Z","updated_at":"2015-05-04T09:59:39Z","pushed_at":"2015-06-25T08:24:15Z","git_url":"git://github.com/thomasmoelhave/ol3.git","ssh_url":"git@github.com:thomasmoelhave/ol3.git","clone_url":"https://github.com/thomasmoelhave/ol3.git","svn_url":"https://github.com/thomasmoelhave/ol3","homepage":"http://openlayers.org","size":31000,"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":"openlayers:master","ref":"master","sha":"4cf1ee769e556be4542c243e3b35a357f3120871","user":{"login":"openlayers","id":240579,"avatar_url":"https://avatars.githubusercontent.com/u/240579?v=3","gravatar_id":"","url":"https://api.github.com/users/openlayers","html_url":"https://github.com/openlayers","followers_url":"https://api.github.com/users/openlayers/followers","following_url":"https://api.github.com/users/openlayers/following{/other_user}","gists_url":"https://api.github.com/users/openlayers/gists{/gist_id}","starred_url":"https://api.github.com/users/openlayers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openlayers/subscriptions","organizations_url":"https://api.github.com/users/openlayers/orgs","repos_url":"https://api.github.com/users/openlayers/repos","events_url":"https://api.github.com/users/openlayers/events{/privacy}","received_events_url":"https://api.github.com/users/openlayers/received_events","type":"Organization","site_admin":false},"repo":{"id":4723248,"name":"ol3","full_name":"openlayers/ol3","owner":{"login":"openlayers","id":240579,"avatar_url":"https://avatars.githubusercontent.com/u/240579?v=3","gravatar_id":"","url":"https://api.github.com/users/openlayers","html_url":"https://github.com/openlayers","followers_url":"https://api.github.com/users/openlayers/followers","following_url":"https://api.github.com/users/openlayers/following{/other_user}","gists_url":"https://api.github.com/users/openlayers/gists{/gist_id}","starred_url":"https://api.github.com/users/openlayers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openlayers/subscriptions","organizations_url":"https://api.github.com/users/openlayers/orgs","repos_url":"https://api.github.com/users/openlayers/repos","events_url":"https://api.github.com/users/openlayers/events{/privacy}","received_events_url":"https://api.github.com/users/openlayers/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openlayers/ol3","description":"OpenLayers 3","fork":false,"url":"https://api.github.com/repos/openlayers/ol3","forks_url":"https://api.github.com/repos/openlayers/ol3/forks","keys_url":"https://api.github.com/repos/openlayers/ol3/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openlayers/ol3/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openlayers/ol3/teams","hooks_url":"https://api.github.com/repos/openlayers/ol3/hooks","issue_events_url":"https://api.github.com/repos/openlayers/ol3/issues/events{/number}","events_url":"https://api.github.com/repos/openlayers/ol3/events","assignees_url":"https://api.github.com/repos/openlayers/ol3/assignees{/user}","branches_url":"https://api.github.com/repos/openlayers/ol3/branches{/branch}","tags_url":"https://api.github.com/repos/openlayers/ol3/tags","blobs_url":"https://api.github.com/repos/openlayers/ol3/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openlayers/ol3/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openlayers/ol3/git/refs{/sha}","trees_url":"https://api.github.com/repos/openlayers/ol3/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openlayers/ol3/statuses/{sha}","languages_url":"https://api.github.com/repos/openlayers/ol3/languages","stargazers_url":"https://api.github.com/repos/openlayers/ol3/stargazers","contributors_url":"https://api.github.com/repos/openlayers/ol3/contributors","subscribers_url":"https://api.github.com/repos/openlayers/ol3/subscribers","subscription_url":"https://api.github.com/repos/openlayers/ol3/subscription","commits_url":"https://api.github.com/repos/openlayers/ol3/commits{/sha}","git_commits_url":"https://api.github.com/repos/openlayers/ol3/git/commits{/sha}","comments_url":"https://api.github.com/repos/openlayers/ol3/comments{/number}","issue_comment_url":"https://api.github.com/repos/openlayers/ol3/issues/comments{/number}","contents_url":"https://api.github.com/repos/openlayers/ol3/contents/{+path}","compare_url":"https://api.github.com/repos/openlayers/ol3/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openlayers/ol3/merges","archive_url":"https://api.github.com/repos/openlayers/ol3/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openlayers/ol3/downloads","issues_url":"https://api.github.com/repos/openlayers/ol3/issues{/number}","pulls_url":"https://api.github.com/repos/openlayers/ol3/pulls{/number}","milestones_url":"https://api.github.com/repos/openlayers/ol3/milestones{/number}","notifications_url":"https://api.github.com/repos/openlayers/ol3/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openlayers/ol3/labels{/name}","releases_url":"https://api.github.com/repos/openlayers/ol3/releases{/id}","created_at":"2012-06-20T06:53:59Z","updated_at":"2015-11-16T10:29:54Z","pushed_at":"2015-11-16T10:55:23Z","git_url":"git://github.com/openlayers/ol3.git","ssh_url":"git@github.com:openlayers/ol3.git","clone_url":"https://github.com/openlayers/ol3.git","svn_url":"https://github.com/openlayers/ol3","homepage":"http://openlayers.org","size":103338,"stargazers_count":1495,"watchers_count":1495,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":843,"mirror_url":null,"open_issues_count":367,"forks":843,"open_issues":367,"watchers":1495,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openlayers/ol3/pulls/3660"},"html":{"href":"https://github.com/openlayers/ol3/pull/3660"},"issue":{"href":"https://api.github.com/repos/openlayers/ol3/issues/3660"},"comments":{"href":"https://api.github.com/repos/openlayers/ol3/issues/3660/comments"},"review_comments":{"href":"https://api.github.com/repos/openlayers/ol3/pulls/3660/comments"},"review_comment":{"href":"https://api.github.com/repos/openlayers/ol3/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openlayers/ol3/pulls/3660/commits"},"statuses":{"href":"https://api.github.com/repos/openlayers/ol3/statuses/f8de2bf4171c45a88ecb116dc8ff1bc09afc4598"}},"merged":false,"mergeable":false,"mergeable_state":"dirty","merged_by":null,"comments":21,"review_comments":9,"commits":2,"additions":502,"deletions":2,"changed_files":9}}