Skip to content

Commit

Permalink
Add helper Polymer.AppLayout.scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
blasten committed Mar 2, 2016
1 parent 0b89e52 commit df49a09
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 28 deletions.
10 changes: 9 additions & 1 deletion app-header/app-header.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,15 @@
:host([disabled])::after,
:host([disabled]) #backgroundFrontLayer,
:host([disabled]) #backgroundRearLayer,
:host([disabled]) ::content > app-toolbar:first-of-type {
:host([disabled]) ::content > app-toolbar:first-of-type,
:host([disabled]) ::content > [primary],
/* Silent scrolling should not run CSS transitions */
:host-context(.app-layout-silent-scroll),
:host-context(.app-layout-silent-scroll)::after,
:host-context(.app-layout-silent-scroll) #backgroundFrontLayer,
:host-context(.app-layout-silent-scroll) #backgroundRearLayer,
:host-context(.app-layout-silent-scroll) ::content > app-toolbar:first-of-type,
:host-context(.app-layout-silent-scroll) ::content > [primary] {
transition: none !important;
}

Expand Down
2 changes: 1 addition & 1 deletion app-header/test/app-header.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
tearDown: sinon.spy(),
run: sinon.spy()
};
Polymer.AppScrollEffects = {
Polymer.AppLayout.scrollEffects = {
'test-effect': testEffect
};
});
Expand Down
1 change: 1 addition & 0 deletions app-layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<link rel="import" href="helpers/helpers.html">
<link rel="import" href="app-drawer-layout/app-drawer-layout.html">
<link rel="import" href="app-drawer/app-drawer.html">
<link rel="import" href="app-header/app-header.html">
Expand Down
2 changes: 1 addition & 1 deletion app-scroll-effects/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Polymer.AppScrollEffectsBehavior

`Polymer.AppScrollEffectsBehavior` provides an interface that allows to consume scrolls events.
Effects are installed in the `Polymer.AppScrollEffects` namescape.
Effects are installed in the `Polymer.AppLayout.scrollEffects` namescape.

A few effects are defined in `app-scroll-effects.html`, but, by default, no effect is imported.
Thus, users need to explicitly import the dependency.
Expand Down
19 changes: 6 additions & 13 deletions app-scroll-effects/app-scroll-effects-behavior.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@

<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../app-scroll-behaviors/app-custom-scroller-behavior.html">
<link rel="import" href="../helpers/helpers.html">

<script>
/**
* `Polymer.AppScrollEffectsBehavior` provides an interface that allows to consume scrolls events.
* Effects are installed in the `Polymer.AppScrollEffects` namescape.
* Effects are installed in the `Polymer.AppLayout.scrollEffects` namescape.
*
* A few effects are defined in `app-scroll-effects.html`, but, by default, no effect is imported.
* Thus, users need to explicitly import the dependency.
Expand Down Expand Up @@ -149,7 +150,7 @@
* effects programmatically.
*
* @method createEffect
* @param {string} effectName The name of an effect defined in `Polymer.AppScrollEffects`
* @param {string} effectName The name of an effect defined in `Polymer.AppLayout.scrollEffects`
* @param {Object=} effectConfig The effect config object if the effect accepts config
* values. (Optional)
* @return {Object} The effect object. This object has the following interface:
Expand All @@ -167,13 +168,9 @@
* ```
*/
createEffect: function(effectName, effectConfig) {
if (!Polymer.AppScrollEffects) {
throw new ReferenceError('undefined Polymer.AppScrollEffects');
return;
}
var effectDef = Polymer.AppScrollEffects[effectName];
var effectDef = Polymer.AppLayout.scrollEffects[effectName];
if (!effectDef) {
throw new ReferenceError('undefined effect `' + effectName + '`');
throw new ReferenceError('Scroll effect `' + effectName + '` is undefined');
return;
}
var prop = this._boundEffect(effectDef, effectConfig || {});
Expand All @@ -193,7 +190,7 @@
effects.split(' ').forEach(function(effectName) {
var effectDef;
if (effectName !== '') {
if ((effectDef = Polymer.AppScrollEffects[effectName])) {
if ((effectDef = Polymer.AppLayout.scrollEffects[effectName])) {
this._effects.push(this._boundEffect(effectDef, effectsConfig[effectName]));
} else {
this._warn(this._logf('_effectsChanged', 'undefined effect `', effectName, '`'));
Expand Down Expand Up @@ -284,8 +281,4 @@
}
}];

/**
* Defines the namespace for the effects
*/
Polymer.AppScrollEffects = Polymer.AppScrollEffects || {};
</script>
23 changes: 12 additions & 11 deletions app-scroll-effects/app-scroll-effects.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<link rel="import" href="app-scroll-effects-behavior.html">

<script>

(function() {
(function(scrollEffects) {
function interpolate(progress, points, fn, ctx) {
fn.apply(ctx, points.map(function(point) {
return point[0] + (point[1] - point[0]) * progress;
}));
}

Polymer.AppScrollEffects = {};

/**
* While scrolling down, fade in the rear background layer and fade out the front background
* layer (opacity interpolated based on scroll position).
*/
Polymer.AppScrollEffects['blend-background'] = {
scrollEffects['blend-background'] = {
setUp: function setUp() {
this.$.backgroundFrontLayer.style.willChange = 'opacity';
this.$.backgroundFrontLayer.style.webkitTransform = 'translateZ(0)';
Expand All @@ -40,7 +41,7 @@
* Upon scrolling past a threshold, fade in the rear background layer and fade out the front
* background layer (opacity CSS transitioned over time).
*/
Polymer.AppScrollEffects['fade-background'] = {
scrollEffects['fade-background'] = {
setUp: function setUp(config) {
var duration = config.duration || '0.5s';
this.$.backgroundFrontLayer.style.willChange = 'opacity';
Expand All @@ -66,7 +67,7 @@
/**
* Vertically translate the background based on a factor of the scroll position.
*/
Polymer.AppScrollEffects['parallax-background'] = {
scrollEffects['parallax-background'] = {
setUp: function setUp(config) {
var scalar = parseFloat(config.scalar);
this._deltaBg = this.$.backgroundFrontLayer.offsetHeight - this.$.background.offsetHeight;
Expand Down Expand Up @@ -97,7 +98,7 @@
* Transform the font size of a designated title element between two values based on the scroll
* position.
*/
Polymer.AppScrollEffects['resize-title'] = {
scrollEffects['resize-title'] = {
setUp: function setUp() {
var title = Polymer.dom(this).querySelector('[title]');
var condensedTitle = Polymer.dom(this).querySelector('[condensed-title]');
Expand Down Expand Up @@ -162,7 +163,7 @@
* Upon scrolling past a threshold, CSS transition the font size of a designated title element
* between two values.
*/
Polymer.AppScrollEffects['resize-snapped-title'] = {
scrollEffects['resize-snapped-title'] = {
setUp: function setUp(config) {
var title = Polymer.dom(this).querySelector('[title]');
var condensedTitle = Polymer.dom(this).querySelector('[condensed-title]');
Expand Down Expand Up @@ -209,7 +210,7 @@
* Toggles the shadow property in app-header when content is scrolled to create a sense of depth
* between the element and the content underneath.
*/
Polymer.AppScrollEffects['waterfall'] = {
scrollEffects.waterfall = {
run: function run(p, y) {
this.shadow = this.isOnScreen() && this.isContentBelow();
}
Expand All @@ -218,13 +219,13 @@
/**
* Shorthand for the waterfall, resize-title, blend-background, and parallax-background effects.
*/
Polymer.AppScrollEffects['material'] = {
scrollEffects.material = {
setUp: function() {
this.effects = 'waterfall resize-title blend-background parallax-background';
return false;
}
};

})();
})(Polymer.AppLayout.scrollEffects);

</script>
115 changes: 115 additions & 0 deletions helpers/helpers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<!--
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<link rel="import" href="../../polymer/polymer.html">

<script>
Polymer.AppLayout = Polymer.AppLayout || {};

Polymer.AppLayout.scrollEffects = Polymer.AppLayout.scrollEffects || {};

Polymer.AppLayout.scrollTimingFunction = function easeOutQuad(t, b, c, d) {
t /= d;
return -c * t*(t-2) + b;
};

/**
* Helper function that scrolls to a particular set of coordinates in a scroll target.
* If the scroll target is not defined, then it would use the main document as the target.
*
* To scroll in a smooth fashion, you can set the option `behavior: 'smooth'`. e.g.
*
* ```js
* Polymer.AppLayout.scroll({top: 0, behavior: 'smooth'});
* ```
*
* To scroll in a silent mode, without notifying scroll changes to any app-layout elements,
* you can set the option `behavior: 'silent'`. This is particularly useful we you are using
* `app-header` and you desire to scroll to the top of a scrolling region without running
* scroll effects. e.g.
*
* ```js
* Polymer.AppLayout.scroll({top: 0, behavior: 'silent'});
* ```
*
* @param {Object} options {top: Number, left: Number, behavior: String(smooth | silent)}
*/
Polymer.AppLayout.scroll = function scroll(options) {
options = options || {};

var docEl = document.documentElement;
var target = options.target || docEl;
var hasNativeScrollBehavior = 'scrollBehavior' in target.style && target.scroll;
var scrollClassName = 'app-layout-silent-scroll';
var scrollTop = options.top || 0;
var scrollLeft = options.left || 0;
var scrollTo = target === docEl ? window.scrollTo :
function scrollTo(scrollLeft, scrollTop) {
target.scrollLeft = scrollLeft;
target.scrollTop = scrollTop;
};

if (options.behavior === 'smooth') {

if (hasNativeScrollBehavior) {

target.scroll(options);

} else {

var timingFn = Polymer.AppLayout.scrollTimingFunction;
var startTime = Date.now();
var currentScrollTop = target === docEl ? window.pageYOffset : target.scrollTop;
var currentScrollLeft = target === docEl ? window.pageXOffset : target.scrollLeft;
var deltaScrollTop = scrollTop - currentScrollTop;
var deltaScrollLeft = scrollLeft - currentScrollLeft;
var duration = 300;

(function updateFrame() {
var now = Date.now();
var elapsedTime = now - startTime;

if (elapsedTime < duration) {
scrollTo(
timingFn(elapsedTime, currentScrollLeft, deltaScrollLeft, duration),
timingFn(elapsedTime, currentScrollTop, deltaScrollTop, duration)
);
requestAnimationFrame(updateFrame.bind(this));
}
}).call(this);
}

} else if (options.behavior === 'silent') {

docEl.classList.add(scrollClassName);

// Browsers keep the scroll momentum even if the bottom of the scrolling content
// was reached. This means that calling scroll({top: 0, behavior: 'silent'}) when
// the momentum is still going will result in more scroll events and thus scroll effects.
// This seems to only apply when using document scrolling.
// Therefore, when should we remove the class from the document element?

clearInterval(this._scrollTimer);

this._scrollTimer = setTimeout(function() {
docEl.classList.remove(scrollClassName);
this._scrollTimer = null;
}, 100);

scrollTo(scrollLeft, scrollTop);

} else {

scrollTo(scrollLeft, scrollTop);

}
};

</script>
Loading

0 comments on commit df49a09

Please sign in to comment.