Skip to content

Commit

Permalink
Add amp-fx="fade-in" - scroll triggered timed animation. (#14351)
Browse files Browse the repository at this point in the history
* WIP

* Refactor parallax code to make it easier to add new presets

* Force Travis checks

* Travis fixes

* Private -> protected

* Add support for amp-fx='fade-in'. Write example and validator tests accordingly as well

* Demos post UX review

* Add 'real world' example that uses amp-fx='fade-in'

* Commit worthy test

* Add support for easing keywords

* Only access private members through accessors

* Only access private members through accessors

* Remove demo files

* Add accessor for resources.

* Fix linter errors

* Formatting FUNS

* Fix markdown

* Moar demos

* Gate amp-fx='fade-in' experiment

* Edits before push

* markdown changes

* Bring back demos

* remove US demos

* Respond to alanorozco@'s comments

* Fix build failures

* Fix missing support check

* Travis fixes

* Cleanups

* Remove references to fade-in

* Don't use private members outside class

* OOPS
  • Loading branch information
nainar authored and cvializ committed Apr 5, 2018
1 parent dbbdd78 commit e554769
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 17 deletions.
112 changes: 112 additions & 0 deletions examples/article-fade-in.amp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<!doctype html>
<html >
<head>
<meta charset="utf-8">
<title>AMP Article with fade-in animations</title>
<link rel="canonical" href="amps.html">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-fx-collection" src="https://cdn.ampproject.org/v0/amp-fx-collection-0.1.js"></script>
<style amp-custom>
.spacer {
margin-top: 10px;
height: 70vh;
width: 100%;
background-image: -webkit-linear-gradient(#EEE 50%, white 50%);
background-image: linear-gradient(#EEE 50%, white 50%);
background-size: 100% 3em;
}

header {
position: relative;
}

h1 {
margin: 0px 10px;
}

header h1 {
position: absolute;
top: 20vh;
padding: 5px;
z-index: 1;
}

header h1 span, .title {
background-color: black;
color: white;
line-height: 1.2em;
}

amp-img img {
object-fit: cover;
}

.overlay-top {
position: absolute;
top: 0;
}

.overlay-container {
position: relative;
overflow: hidden;
}

main {
font-family: Helvetica, sans-serif;
padding: 10px;
max-width: 412px;
margin: auto;
}

a, a:visited, a:active {
color: #2196F3;
text-decoration: none;
display: block;
padding: 5px;
}

.overflow-window {
overflow: hidden;
}

.overflow-window amp-img {
margin-bottom: -80%;
}
</style>
</head>
<body>
<main>
<header>
<h1>
<span class="title">Lorem Ipsum Dolor Sit Lorem Ipsum<span>
</h1>
<amp-img height="50vh" layout="fixed-height" src="https://picsum.photos/1600/900?image=1069"></amp-img>
</header>

<article>
<div class="spacer"></div>
<div class="overlay-container">
<amp-img layout=responsive width=1600 height=900 src="https://picsum.photos/1600/900?image=981"></amp-img>
<h1 class="overlay-top" amp-fx="fade-in">
<span class="title">Default easing, margin and duration<span>
</h1>
</div>
<div class="spacer"></div>
<div class="overflow-window">
<amp-img amp-fx="fade-in" data-duration="200ms" layout=responsive width=900 height=1600 src="https://picsum.photos/900/1600?image=736"></amp-img>
</div>
<div class="spacer"></div>
<div class="overflow-window">
<amp-img amp-fx="fade-in" data-margin="0.5" layout=responsive width=900 height=1600 src="https://picsum.photos/900/1600?image=736"></amp-img>
</div>
<div class="spacer"></div>
<div class="overflow-window">
<amp-img amp-fx="fade-in" data-easing="ease-out" layout=responsive width=900 height=1600 src="https://picsum.photos/900/1600?image=736"></amp-img>
</div>
</article>
</main>
</body>

</html>
3 changes: 3 additions & 0 deletions extensions/amp-fx-collection/0.1/amp-fx-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import {AmpEvents} from '../../../src/amp-events';
import {FxProvider} from './providers/fx-provider';
import {Presets} from './providers/amp-fx-presets';
import {Services} from '../../../src/services';
import {dev, rethrowAsync, user} from '../../../src/log';
import {iterateCursor} from '../../../src/dom';
Expand All @@ -30,6 +31,7 @@ const TAG = 'amp-fx-collection';
*/
const FxType = {
PARALLAX: 'parallax',
FADE_IN: 'fade-in',
};

/**
Expand Down Expand Up @@ -126,6 +128,7 @@ class AmpFxCollection {

// Validate that we support the requested fx types.
fxTypes.forEach(fxType => {
Presets[fxType].isFxTypeSupported(this.ampdoc_.win);
user().assertEnumValue(FxType, fxType, 'amp-fx');
});

Expand Down
47 changes: 47 additions & 0 deletions extensions/amp-fx-collection/0.1/providers/amp-fx-presets-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright 2018 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @fileoverview Common animations utility functions used in the amp-fx
* presets.
*/

import {startsWith} from '../../../../src/string';
import {user} from '../../../../src/log';

/**
* Converts the data-fade-ineasing input into the corresponding `cubic-bezier()`
* notation.
* @param {string} keyword to be converted.
* @return {string} cubic-bezier() notation.
*/
export function convertEasingKeyword(keyword) {
switch (keyword) {
case 'linear':
return 'cubic-bezier(0.00, 0.00, 1.00, 1.00)';
case 'ease-in-out':
return 'cubic-bezier(0.80, 0.00, 0.20, 1.00)';
case 'ease-in':
return 'cubic-bezier(0.80, 0.00, 0.60, 1.00)';
case 'ease-out':
return 'cubic-bezier(0.40, 0.00, 0.40, 1.00)';
default:
user().assert(startsWith(keyword, 'cubic-bezier'),
'All custom bezier curves should be specified by following the ' +
'`cubic-bezier()` function notation.');
return keyword;
}
}
68 changes: 58 additions & 10 deletions extensions/amp-fx-collection/0.1/providers/amp-fx-presets.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
*/

import {dev, user} from '../../../../src/log';
import {isExperimentOn} from '../../../../src/experiments';
import {setStyles} from '../../../../src/style';

export const Presets = {
'parallax': {
isFxTypeSupported(unusedWin) {
return true;
},
userAsserts(element) {
const factorValue = user().assert(
element.getAttribute('data-parallax-factor'),
Expand Down Expand Up @@ -47,17 +51,61 @@ export const Presets = {
const offset = (fxElement.adjustedViewportHeight_ - top) * adjustedFactor;
fxElement.setOffset(offset);

if (!fxElement.isMutateScheduled()) {
fxElement.setIsMutateScheduled(true);
fxElement.getResources().mutateElement(fxElement.getElement(),
function() {
fxElement.setIsMutateScheduled(false);
// Translate the element offset pixels.
setStyles(fxElement.getElement(),
{transform:
`translateY(${fxElement.getOffset().toFixed(0)}px)`});
});
if (fxElement.isMutateScheduled()) {
return;
}

// If above the threshold of trigger-position
fxElement.setIsMutateScheduled(true);
fxElement.getResources().mutateElement(fxElement.getElement(),
function() {
fxElement.setIsMutateScheduled(false);
// Translate the element offset pixels.
setStyles(fxElement.getElement(),
{transform:
`translateY(${fxElement.getOffset().toFixed(0)}px)`});
});
},
},
'fade-in': {
isFxTypeSupported(win) {
user().assert(isExperimentOn(win, 'amp-fx-fade-in'),
'amp-fx-fade-in experiment is not turned on.');
},
userAsserts(element) {
if (!element.hasAttribute('data-margin')) {
return;
}
const margin = element.getAttribute('data-margin');
user().assert(parseFloat(margin) >= 0 && parseFloat(margin) < 1,
'data-margin must be a number and be between 0 and 1 for: %s',
element);
},
update(entry) {
const fxElement = this;
dev().assert(fxElement.adjustedViewportHeight_);
// Outside viewport
if (!entry.positionRect ||
entry.positionRect.top >
(1 - fxElement.getMargin()) * fxElement.adjustedViewportHeight_) {
return;
}

if (fxElement.isMutateScheduled()) {
return;
}

// If above the threshold of trigger-position
fxElement.setIsMutateScheduled(true);
fxElement.resources_.mutateElement(fxElement.getElement(), function() {
fxElement.setIsMutateScheduled(false);
// Translate the element offset pixels.
setStyles(fxElement.getElement(), {
'transition-duration': fxElement.getDuration(),
'transition-timing-function': fxElement.getEasing(),
'opacity': 1,
});
});
},
},
};
49 changes: 45 additions & 4 deletions extensions/amp-fx-collection/0.1/providers/fx-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@ import {
} from '../../../../src/service/position-observer/position-observer-worker';
import {Presets} from './amp-fx-presets';
import {Services} from '../../../../src/services';
import {convertEasingKeyword} from './amp-fx-presets-utils';
import {getServiceForDoc} from '../../../../src/service';
import {
installPositionObserverServiceForDoc,
} from '../../../../src/service/position-observer/position-observer-impl';
import {setStyle} from '../../../../src/style';
import {setStyles} from '../../../../src/style';

const propertyAnimated = {
'parallax': 'transform',
const installStyles = {
'parallax': {
'will-change': 'transform',
},
'fade-in': {
'will-change': 'opacity',
'opacity': 0,

},
};

/**
Expand Down Expand Up @@ -62,7 +70,7 @@ export class FxProvider {
* @param {!Element} element
*/
installOn(element) {
setStyle(element, 'will-change', propertyAnimated[this.fxType_]);
setStyles(element, installStyles[this.fxType_]);
const parallaxElement = new FxElement(
element, this.positionObserver_, this.viewport_, this.resources_,
this.fxType_);
Expand Down Expand Up @@ -110,6 +118,18 @@ export class FxElement {

/** @private {number} */
this.factor_ = parseFloat(element.getAttribute('data-parallax-factor'));

/** @private {number} */
this.margin_ = element.hasAttribute('data-margin') ?
parseFloat(element.getAttribute('data-margin')) : 0.05;

/** @private {string} */
this.easing_ = convertEasingKeyword(element.hasAttribute('data-easing') ?
element.getAttribute('data-easing') : 'ease-in');

/** @private {string} */
this.duration_ = element.hasAttribute('data-duration') ?
element.getAttribute('data-duration') : '1000ms';
}

/**
Expand Down Expand Up @@ -172,6 +192,27 @@ export class FxElement {
return this.factor_;
}

/**
* @returns {string}
*/
getDuration() {
return this.duration_;
}

/**
* @returns {number}
*/
getMargin() {
return this.margin_;
}

/**
* @returns {string}
*/
getEasing() {
return this.easing_;
}

/**
* @returns {Element}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,10 @@
<div>
<h1 amp-fx="parallax"></h1>
</div>
<div amp-fx="fade-in"></div>
<amp-img amp-fx="fade-in" width="20" height="20" layout="responsive" src="https://example.com"></amp-img>
<div>
<h1 amp-fx="fade-in"></h1>
</div>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,10 @@ PASS
| <div>
| <h1 amp-fx="parallax"></h1>
| </div>
| <div amp-fx="fade-in"></div>
| <amp-img amp-fx="fade-in" width="20" height="20" layout="responsive" src="https://example.com"></amp-img>
| <div>
| <h1 amp-fx="fade-in"></h1>
| </div>
| </body>
| </html>
Loading

0 comments on commit e554769

Please sign in to comment.