Skip to content

🐛Tweaks "ken burns" animations to check for image sizes#14334

Merged
newmuis merged 19 commits intoampproject:masterfrom
Enriqe:ken-burns-tweaks
Apr 12, 2018
Merged

🐛Tweaks "ken burns" animations to check for image sizes#14334
newmuis merged 19 commits intoampproject:masterfrom
Enriqe:ken-burns-tweaks

Conversation

@Enriqe
Copy link
Copy Markdown
Contributor

@Enriqe Enriqe commented Mar 30, 2018

"Pan" animations will not look as intended with screen sizes bigger than the image.

This PR addresses this issue by checking if the images are smaller than the screen size and scaling it accordingly.

It also checks if the image is a direct child of a grid layer using a "fill" template, and overwrites the styles so that the calculations of the animation won't be affected.

@Enriqe
Copy link
Copy Markdown
Contributor Author

Enriqe commented Mar 30, 2018

/cc @newmuis

dimensions.pageWidth / dimensions.targetWidth : 1;
const heightFactor = dimensions.pageHeight > dimensions.targetHeight ?
dimensions.pageHeight / dimensions.targetHeight : 1;
return Math.max(widthFactor, heightFactor) + 0.25;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of adding 0.25, we should multiply by 1.25? If you need to increase something by 6000x for it to fit the viewport, increasing it by 6000.25 won't give you much space to pan.

Also, nit: whatever approach we take, that magic number should be a constant

const WHITELISTED_RPOPS = {
'opacity': true,
'transform': true,
'transform-origin': true,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @aghassemi, question: if I would like to whitelist this property, do I have to do something on the validator side as well?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for validator changes. It is all runtime validation

@@ -83,8 +83,8 @@ export function whooshIn(startX, startY, endX, endY) {
* @param {StoryAnimationDimsDef} dimensions Dimensions of page and target.
*/
export function pageIsLargerThanTarget(dimensions) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the change to the implementation, should this be renamed? pageIsLargerThanOrEqualToTarget(...)?
targetFitsWithinPage(...)?

@@ -83,8 +83,8 @@ export function whooshIn(startX, startY, endX, endY) {
* @param {StoryAnimationDimsDef} dimensions Dimensions of page and target.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing @return

@Enriqe
Copy link
Copy Markdown
Contributor Author

Enriqe commented Apr 6, 2018

As discussed offline, I will look into adding the logic of overwriting the styles for the image on the animation itself, rather than in the grid-layer logic.

@Enriqe Enriqe force-pushed the ken-burns-tweaks branch from 48ddcce to 9042051 Compare April 9, 2018 19:40
@Enriqe
Copy link
Copy Markdown
Contributor Author

Enriqe commented Apr 9, 2018

const fillTemplate = 'fill';

// For panning and zooming animations.
if (PANNING_ANIMATION_NAMES.includes(presetName)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we can use includes; can you use PANNING_ANIMATION_NAMES.indexOf(presetName) >= 0?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Out of curiosity, why wouldn't we want to use includes?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be okay? I'm not 100% sure. I thought I remembered that some things that are added with es6 are not transpiled, but I never know which ones.

* @private @const {!Object<string, string>}
*/
const ANIMATION_CSS_CLASS_NAMES = {
'pan': 'i-amphtml-story-grid-template-with-pan-animation',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this problem only occur with pan? i.e. Do zoom animations ever show whitespace?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to apply this styling to zoom for a couple of reasons:

  1. It's fair to assume that all the use cases for panning will have to do with images that outgrow the size of the viewport (from the name of the animation), but I'm not so sure for zooming. e.g. Users may want to zoom in on an object that just takes a fraction of the screen.
  2. If the fill layout resizes the image to be the same size of the viewport, that wouldn't break the animation, since zoom doesn't depend on the image dimensions. It's just a simple scale.

WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it more, we might want to also include zoom animations. It will make it more straight forward for when users want to combine both the pan and the zoom. This way they won't have to wrap everything inside a div. I'll do a quick prototype and see if it works.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM; I think especially if it's a child of a template="fill" layer, we might want this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prototyped it with the zooming and it works well. I think we should also include it since it eliminates the need to wrap images inside a div when using multiple images for the animation.

* @private @const {!Array<string>}
*/
const PANNING_ANIMATION_NAMES = [
const FULL_SCREEN_ANIMATION_NAMES = [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: slightly prefer "full bleed" over "full screen" here, since technically it's not fullscreen as long as we have the browser bars (and, at some point, we might have an actual "full screen" implementation that is different from this)

@Enriqe
Copy link
Copy Markdown
Contributor Author

Enriqe commented Apr 11, 2018

/cc @gmajoulet @alanorozco

.i-amphtml-story-grid-template-with-full-bleed-animation {
position: absolute !important;
display: block !important;
padding: 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should either be !important or in amp-story-user-overridable.css.

duration: 1000,
easing: 'linear',
keyframes(dimensions) {
let resized = false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this whole keyframes def can be extracted into a function that just accepts frames as a parameter? As is, this repeats a lot of the same code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure with what you meant. I made some changes to how these presets are calculated though, does your suggestion still stand after those?

const offsetX = -dimensions.targetWidth / 2;
const offsetY = dimensions.pageHeight - dimensions.targetHeight;

const expectedKeyframes = [{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: Maybe put the { on the next line and indent both objects +2

}

it('should tell if target fits within page', () => {
let dimensions = setDimensions(380 , 580, 360, 580);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are three different cases, we should break them into three different it(...) declarations. Especially true for the one that's expected to be false

});
});

it('should not add additional css class to non-full-bleed animation target ' +
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: this name and the two above are a bit hard to parse. I tried to come up with something clearer, but I now see that these are just super specific cases with a lot to say 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rephrased it a bit in hopes of making it easier to read 😅

const fillTemplate = 'fill';

// For full bleed animations.
if (FULL_BLEED_ANIMATION_NAMES.indexOf(presetName) >= 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this can just be === or a switch statement instead of indexOf, right? Sorry for the churn, commented too quickly last time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure what you mean. Do you want to check for every preset and see if it equals the current preset, then apply the corresponding styles?

* @param {string} presetName
*/
export function setStyleForPreset(el, presetName) {
const fullBleed = 'full-bleed';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract this to a top-level constant and change the name to SNAKE_CASE. Then, you can also use the constant as the key for ANIMATION_CSS_CLASS_NAMES too:

const ANIMATION_CSS_CLASS_NAMES = {
  [FULL_BLEED_CATEGORY]: 'i-amphtml-story-grid-template-with-full-bleed-animation',
};

* @param {number} scalingFactor Scaling factor at which target will be scaled.
* @return {KeyframesDef}
*/
export function enlargeKeyFrames(keyframes, scalingFactor) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just make this scaleAndTranslate(startX, startY, endX, endY, scalingFactor) to follow the pattern. Then, if scalingFactor === 1, you don't have to emit the scale(scalingFactor), so that in animation-presets.js, you can just use scaleAndTranslate instead of translate2d with a conditional.

}

/**
* Checks if the target's dimensions are smaller than or equal to those of the page.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This is ||, so it should be "Checks if either of the target's dimensions are smaller than or equal to those of the page."

Copy link
Copy Markdown
Contributor

@newmuis newmuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! Last few tweaks 😄

* @param {number} scalingFactor Scaling factor at which target will be scaled.
* @return {KeyframesDef}
*/
export function enlargeKeyFrames(keyframes, scalingFactor) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this no longer needs to be exported.

* @param {string} presetName
*/
export function setStyleForPreset(el, presetName) {
const fillTemplate = 'fill';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can be top-level too

@@ -0,0 +1,206 @@
import {AmpStory} from '../amp-story';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright goes before imports

@newmuis newmuis merged commit 759f257 into ampproject:master Apr 12, 2018
@Enriqe Enriqe deleted the ken-burns-tweaks branch April 20, 2018 19:29
glevitzky pushed a commit that referenced this pull request Apr 27, 2018
* Tweaks ken burns effect animations to check for image sizes that are smaller than screen and scale them accordingly.

* Adds constant for scaling factor, linter stuff.

* Linter.:

* also take into consideration images that are same size as page.

* import

* change method name.

* Replace CSS class for elements animated with a panning animation inside a grid layer fill template.

* Move style specific logic to animation-presets.js and add examples.

* Changes includes for indexOf.

* Includes zoom animations in the tweak.

* Renames from full screen to full bleed.

* format html

* Comment.

* adds test.

* Adds more tests.

* lint

* Reviews.

* nit changes

* add visible for testing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants