🐛Tweaks "ken burns" animations to check for image sizes#14334
🐛Tweaks "ken burns" animations to check for image sizes#14334newmuis merged 19 commits intoampproject:masterfrom
Conversation
|
/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; |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
hey @aghassemi, question: if I would like to whitelist this property, do I have to do something on the validator side as well?
There was a problem hiding this comment.
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) { | |||
There was a problem hiding this comment.
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. | |||
…smaller than screen and scale them accordingly.
…de a grid layer fill template.
|
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. |
| const fillTemplate = 'fill'; | ||
|
|
||
| // For panning and zooming animations. | ||
| if (PANNING_ANIMATION_NAMES.includes(presetName)) { |
There was a problem hiding this comment.
I'm not sure we can use includes; can you use PANNING_ANIMATION_NAMES.indexOf(presetName) >= 0?
There was a problem hiding this comment.
Sure. Out of curiosity, why wouldn't we want to use includes?
There was a problem hiding this comment.
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', |
There was a problem hiding this comment.
Does this problem only occur with pan? i.e. Do zoom animations ever show whitespace?
There was a problem hiding this comment.
I don't think we want to apply this styling to zoom for a couple of reasons:
- 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.
- 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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
SGTM; I think especially if it's a child of a template="fill" layer, we might want this.
There was a problem hiding this comment.
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 = [ |
There was a problem hiding this comment.
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)
| .i-amphtml-story-grid-template-with-full-bleed-animation { | ||
| position: absolute !important; | ||
| display: block !important; | ||
| padding: 0; |
There was a problem hiding this comment.
This should either be !important or in amp-story-user-overridable.css.
| duration: 1000, | ||
| easing: 'linear', | ||
| keyframes(dimensions) { | ||
| let resized = false; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 = [{ |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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 ' + |
There was a problem hiding this comment.
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 😄
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
Actually, this can just be === or a switch statement instead of indexOf, right? Sorry for the churn, commented too quickly last time.
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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."
newmuis
left a comment
There was a problem hiding this comment.
Looking good! Last few tweaks 😄
| * @param {number} scalingFactor Scaling factor at which target will be scaled. | ||
| * @return {KeyframesDef} | ||
| */ | ||
| export function enlargeKeyFrames(keyframes, scalingFactor) { |
There was a problem hiding this comment.
nit: this no longer needs to be exported.
| * @param {string} presetName | ||
| */ | ||
| export function setStyleForPreset(el, presetName) { | ||
| const fillTemplate = 'fill'; |
There was a problem hiding this comment.
nit: this can be top-level too
| @@ -0,0 +1,206 @@ | |||
| import {AmpStory} from '../amp-story'; | |||
There was a problem hiding this comment.
nit: copyright goes before imports
* 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
"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.