Skip to content

Commit

Permalink
Merge pull request #136 from PolymerElements/amortized-fp
Browse files Browse the repository at this point in the history
Amortize first paint
  • Loading branch information
blasten committed Nov 14, 2015
2 parents bbfe2a3 + f0a131e commit 836d03d
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 74 deletions.
13 changes: 11 additions & 2 deletions demo/collapse.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<link rel="import" href="../iron-list.html">

</head>
<body unresolved>
<body class="fullbleed" unresolved>

<dom-module id="x-collapse">
<template>
Expand All @@ -40,6 +40,7 @@
@apply(--layout-fit);
@apply(--layout-vertical);
@apply(--paper-font-common-base);
background-color: var(--paper-grey-200, #eee);
}

paper-toolbar {
Expand All @@ -54,9 +55,11 @@
}

iron-list {
background-color: var(--paper-grey-200, #eee);
padding-top: 1px;
padding-bottom: 16px;
-webkit-flex: 1 1;
flex: 1 1;

--iron-list-items-container: {
max-width: 800px;
margin: auto;
Expand Down Expand Up @@ -125,6 +128,12 @@
.item.expanded:hover .longText::after {
content: ' [–]';
}

@media (max-width: 460px) {
paper-toolbar .bottom.title {
font-size: 14px;
}
}
</style>
<iron-ajax url="data/contacts.json" last-response="{{items}}" auto></iron-ajax>
<paper-toolbar>
Expand Down
6 changes: 3 additions & 3 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,23 @@
@apply(--layout-fit);
@apply(--layout-vertical);
@apply(--paper-font-common-base);
background-color: var(--paper-grey-200, #eee);
}

paper-toolbar.tall .title {
font-size: 40px;
margin-left: 60px;
overflow: visible;

-webkit-transform-origin: left center;
transform-origin: left center;
overflow: visible;
}

paper-toolbar paper-icon-button {
--paper-icon-button-ink-color: white;
}

iron-list {
background-color: var(--paper-grey-200, #eee);
padding-bottom: 16px;
}

Expand Down Expand Up @@ -101,7 +101,7 @@
</style>

</head>
<body unresolved>
<body class="fullbleed" unresolved>

<template is="dom-bind">
<iron-ajax url="data/contacts.json" last-response="{{data}}" auto></iron-ajax>
Expand Down
15 changes: 10 additions & 5 deletions demo/selection.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<html>
<head>

<title>Selection</title>
<title>Select contacts</title>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
Expand Down Expand Up @@ -50,6 +50,7 @@
background: var(--paper-pink-500);
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
font-weight: bold;
z-index: 1;
}

.toolbar paper-icon-button {
Expand All @@ -68,17 +69,21 @@
border-bottom: 1px solid #DDD;
}

.item:hover {
background-color: var(--google-grey-100);
}

.item:focus,
.item.selected:focus {
outline: 0;
background-color: #ddd;
/* background-color: #ddd;*/
}

.item.selected .star {
color: var(--paper-blue-600);
}

.item.selected:not(:focus) {
.item.selected {
background-color: var(--google-grey-100);
}

Expand Down Expand Up @@ -170,7 +175,7 @@
<iron-ajax url="data/contacts.json" last-response="{{data}}" auto></iron-ajax>

<paper-toolbar class="toolbar">
<div class="flex">Inbox</div>
<div class="flex">Selection using iron-list</div>
<div style="position: relative;">
<paper-icon-button icon="icons:star" alt="Starred" on-tap="_toggleStarredView"></paper-icon-button>
<paper-badge label$="[[selectedItems.length]]"></paper-badge>
Expand Down Expand Up @@ -267,7 +272,7 @@
</script>

</head>
<body unresolved>
<body class="fullbleed" unresolved>

<x-app></x-app>

Expand Down
92 changes: 49 additions & 43 deletions iron-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@

var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
var DEFAULT_PHYSICAL_COUNT = 20;
var DEFAULT_PHYSICAL_COUNT = 3;
var MAX_PHYSICAL_COUNT = 500;

Polymer({
Expand Down Expand Up @@ -347,7 +347,7 @@
_scrollHeight: 0,

/**
* The size of the viewport
* The height of the list. This is referred as the viewport in the context of list.
*/
_viewportSize: 0,

Expand Down Expand Up @@ -382,6 +382,16 @@
*/
_itemsRendered: false,

/**
* The page that is currently rendered.
*/
_lastPage: null,

/**
* The max number of pages to render. One page is equivalent to the height of the list.
*/
_maxPages: 3,

/**
* The bottom of the physical content.
*/
Expand Down Expand Up @@ -454,7 +464,7 @@
* to a viewport of physical items above and below the user's viewport.
*/
get _optPhysicalSize() {
return this._viewportSize * 3;
return this._viewportSize * this._maxPages;
},

/**
Expand Down Expand Up @@ -555,7 +565,7 @@
// IE 10|11 scrollTop may go above `_maxScrollTop`
// iOS `scrollTop` may go below 0 and above `_maxScrollTop`
var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scroller.scrollTop));
var tileHeight, tileTop, kth, recycledTileSet, scrollBottom;
var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
var ratio = this._ratio;
var delta = scrollTop - this._scrollPosition;
var recycledTiles = 0;
Expand All @@ -570,6 +580,7 @@
this._firstVisibleIndexVal = null;

scrollBottom = this._scrollBottom;
physicalBottom = this._physicalBottom;

// random access
if (Math.abs(delta) > this._physicalSize) {
Expand All @@ -580,7 +591,6 @@
else if (delta < 0) {
var topSpace = scrollTop - this._physicalTop;
var virtualStart = this._virtualStart;
var physicalBottom = this._physicalBottom;

recycledTileSet = [];

Expand Down Expand Up @@ -612,7 +622,7 @@
}
// scroll down
else if (delta > 0) {
var bottomSpace = this._physicalBottom - scrollBottom;
var bottomSpace = physicalBottom - scrollBottom;
var virtualEnd = this._virtualEnd;
var lastVirtualItemIndex = this._virtualCount-1;

Expand Down Expand Up @@ -647,9 +657,8 @@
// If the list ever reach this case, the physical average is not significant enough
// to create all the items needed to cover the entire viewport.
// e.g. A few items have a height that differs from the average by serveral order of magnitude.
if (this._increasePoolIfNeeded()) {
// yield and set models to the new items
this.async(this._update);
if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
this.async(this._increasePool.bind(this, 1));
}
} else {
this._virtualStart = this._virtualStart + recycledTiles;
Expand Down Expand Up @@ -681,11 +690,8 @@
// set the scroller size
this._updateScrollerSize();

// increase the pool of physical items if needed
if (this._increasePoolIfNeeded()) {
// yield set models to the new items
this.async(this._update);
}
// increase the pool of physical items
this._increasePoolIfNeeded();
},

/**
Expand All @@ -698,7 +704,6 @@

for (var i = 0; i < size; i++) {
var inst = this.stamp(null);

// First element child is item; Safari doesn't support children[0]
// on a doc fragment
physicalItems[i] = inst.root.querySelector('*');
Expand All @@ -711,20 +716,25 @@
/**
* Increases the pool of physical items only if needed.
* This function will allocate additional physical items
* (limited by `MAX_PHYSICAL_COUNT`) if the content size is shorter than
* `_optPhysicalSize`
*
* @return boolean
* if the physical size is shorter than `_optPhysicalSize`
*/
_increasePoolIfNeeded: function() {
if (this._physicalAverage === 0) {
return false;
}
if (this._physicalBottom < this._scrollBottom || this._physicalTop > this._scrollPosition) {
return this._increasePool(1);
}
if (this._physicalSize < this._optPhysicalSize) {
return this._increasePool(Math.round((this._optPhysicalSize - this._physicalSize) * 1.2 / this._physicalAverage));
if (this._viewportSize !== 0 && this._physicalSize < this._optPhysicalSize) {
// 0 <= `currentPage` <= `_maxPages`
var currentPage = Math.floor(this._physicalSize / this._viewportSize);

if (currentPage === 0) {
// fill the first page
this.async(this._increasePool.bind(this, Math.round(this._physicalCount * 0.5)));
} else if (this._lastPage !== currentPage) {
// once a page is filled up, paint it and defer the next increase
requestAnimationFrame(this._increasePool.bind(this, 1));
} else {
// fill the rest of the pages
this.async(this._increasePool.bind(this, 1));
}
this._lastPage = currentPage;
return true;
}
return false;
},
Expand All @@ -739,20 +749,17 @@
this._virtualCount,
MAX_PHYSICAL_COUNT
);

var prevPhysicalCount = this._physicalCount;
var delta = nextPhysicalCount - prevPhysicalCount;

if (delta <= 0) {
return false;
}

[].push.apply(this._physicalItems, this._createPool(delta));
[].push.apply(this._physicalSizes, new Array(delta));

this._physicalCount = prevPhysicalCount + delta;
if (delta > 0) {
[].push.apply(this._physicalItems, this._createPool(delta));
[].push.apply(this._physicalSizes, new Array(delta));

return true;
this._physicalCount = prevPhysicalCount + delta;
// tail call
return this._update();
}
},

/**
Expand All @@ -762,7 +769,8 @@
_render: function() {
var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0;

if (this.isAttached && !this._itemsRendered && this._isVisible && requiresUpdate) {
if (this.isAttached && !this._itemsRendered && this._isVisible && requiresUpdate) {
this._lastPage = 0;
this._update();
this._itemsRendered = true;
}
Expand Down Expand Up @@ -1126,7 +1134,7 @@
var hiddenContentSize = this._hiddenContentSize;

// scroll to the item as much as we can
while (currentVirtualItem !== idx && targetOffsetTop < hiddenContentSize) {
while (currentVirtualItem < idx && targetOffsetTop < hiddenContentSize) {
targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem];
currentTopItem = (currentTopItem + 1) % this._physicalCount;
currentVirtualItem++;
Expand All @@ -1142,10 +1150,8 @@
this._resetScrollPosition(this._physicalTop + targetOffsetTop + 1);

// increase the pool of physical items if needed
if (this._increasePoolIfNeeded()) {
// yield set models to the new items
this.async(this._update);
}
this._increasePoolIfNeeded();

// clear cached visible index
this._firstVisibleIndexVal = null;
},
Expand Down
Loading

0 comments on commit 836d03d

Please sign in to comment.