Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scroll AMP doc to center highlighted elements in the viewport #15791

Merged
merged 6 commits into from Jun 11, 2018

Conversation

yunabe
Copy link
Contributor

@yunabe yunabe commented Jun 4, 2018

This pull request should be merged after #15337. There is only one new commit in this PR (2674709)

@alanorozco
Copy link
Member

#15337 merged.

@yunabe yunabe force-pushed the scrolldev branch 2 times, most recently from e4b6024 to d110ce2 Compare June 5, 2018 00:21
@yunabe
Copy link
Contributor Author

yunabe commented Jun 5, 2018

Thanks. Rebased the change to amphtml/master.

} else {
if (scrollTop > SCROLL_ANIMATION_HIGHT_LIMIT) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: HEIGHT

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, good catch!

if (!nodes) {
return 0;
}
const viewport = Services.viewportForDoc(this.ampdoc_);
Copy link
Member

Choose a reason for hiding this comment

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

Is Viewport.animateScrollIntoView(element, duration, curve, 'center'); not good enough for your use case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are two reasons I implemented a new logic:

  1. I want to center multiple elements because discontinuous sentences can be highlighted.
  2. Want to center elements when the header is shown (height = win.height - viewport.getPaddingTop).

Copy link
Member

@alanorozco alanorozco Jun 8, 2018

Choose a reason for hiding this comment

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

In that case, I propose you do the following:

  • Use the same math to calculate a center rectangle.
  • Said rectangle is used to create an invisible element with pointer-events: none so that it won't block interaction.
  • Use animateScrollIntoView(invisibleElement, duration, curve, 'center').
  • Remove invisible element afterwards.

This has two purposes:

  1. keep the viewport API stable.
  2. Aid in the AMP build-size reduction effort. We have a bundle size restriction in place, which would be triggered by adding a method to the viewport service. We can relax this limit, but measures like this help keep it smaller in the first place! :)

Copy link
Contributor Author

@yunabe yunabe Jun 8, 2018

Choose a reason for hiding this comment

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

I'm not sure I understand your suggestion correctly.

To implement your suggestion, I need to add new code to implement

  • Said rectangle is used to create an invisible element with pointer-events: none so that it won't block interaction.
  • Remove invisible element afterwards.

This is not very trivial and it will increase amp-viewer-extension size a little bit. However, I can not remove any code from the current implementation except for the interface of animateScrollToTop in viewport-impl.js.

Which part of code do you think we can remove by your suggestion?

Thanks,
yunabe

Copy link
Member

@alanorozco alanorozco Jun 8, 2018

Choose a reason for hiding this comment

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

Increasing the size of amp-viewer-integeration is fine. However, by modifying Viewport, the size of the core AMP binary increases.

I'm suggesting that you revert the changes to Viewport and use the method described above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's true. But the additional size of dist/v0.js is just 7 bytes after gzip (78597 --> 78604, 107 bytes before gzip 247319 --> 247426).
Do 7 bytes (+0.01%) really matter in the core AMP binary size?

If 7 bytes really matter, I will remove default parameters from animateScrollToTop. Then, the size diff is only 1 byte after gzip (78597 --> 78598).

Do we really want to implement non-trivial logic in amp-viewer-integration just to save 7 bytes (1 byte w/o default parameters) in the core runtime?

Copy link
Member

@alanorozco alanorozco Jun 8, 2018

Choose a reason for hiding this comment

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

Sorry if I'm missing something, but how is it non-trivial? It seems like you could calculate easily and left/right aren't an issue since we're only scrolling vertically. So it would only be a matter of doing something like:

const sentinel = document.createElement('i-amphtml-sentinel');
setStyles(sentinel, {
  'position': absolute,
  'left: '0',
  'right: '0',
  'top': topAsUsuallyCalculated,
  'bottom': newLogicToCalculateBottom(),
});
this.getAmpDoc().getBody().appendChild(sentinel);
return viewport.animateScrollIntoView(// .. etc

Unfortunately we're only counting size before gzip.

But you're right, the difference is negligible. It's fine to bump size. Just one nit: rename to
animateScrollTo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I meant I think it's less trivial to inject the sentinal node than to export animateScrollTo in viewerport, especially considering setScrollTop is already exported in viewport and the additional size to v0.js is limited.

But I do not have a strong preference. I reimplemented this based on your suggestion.

let minTop = Number.MAX_VALUE;
let maxBottom = 0;
for (let i = 0; i < nodes.length; i++) {
const rect = viewport.getLayoutRect(nodes[i]);
Copy link
Member

Choose a reason for hiding this comment

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

nit: Use destructuring:

const {top, bottom} = viewport.getLayoutRect(nodes[i]);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

.animateScrollIntoView(sentinel).then(() => {
this.sendHighlightState_('shown');
});
body.removeChild(sentinel);
Copy link
Member

Choose a reason for hiding this comment

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

This should occur once animateScrollIntoView is resolved.

Copy link
Contributor Author

@yunabe yunabe left a comment

Choose a reason for hiding this comment

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

Thank you for the review. Could you take another look?

let minTop = Number.MAX_VALUE;
let maxBottom = 0;
for (let i = 0; i < nodes.length; i++) {
const rect = viewport.getLayoutRect(nodes[i]);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

if (!nodes) {
return 0;
}
const viewport = Services.viewportForDoc(this.ampdoc_);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I meant I think it's less trivial to inject the sentinal node than to export animateScrollTo in viewerport, especially considering setScrollTop is already exported in viewport and the additional size to v0.js is limited.

But I do not have a strong preference. I reimplemented this based on your suggestion.

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.

None yet

3 participants