Skip to content

feat(viewport-ruler): cache document client rect #2538

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

Merged
merged 3 commits into from
Jan 31, 2017

Conversation

devversion
Copy link
Member

@devversion devversion commented Jan 5, 2017

  • Now the ViewportRuler service, which is used in many components, caches the documents client rect to avoid frequent recalculation of styles in the browser (basically each click for ripples etc.)

    The ScrollDispatcher is used as the service which triggers an update of the cached rectangles because it listens to the resize and scroll events.

Note: It's important that the ViewportRuler also updates the rectangle for scroll events, because the ViewportRuler is also responsible for the scroll position of the viewport.

Debouncing the ScrollDispatcher will be a follow-up PR

@devversion devversion requested a review from jelbourn January 5, 2017 15:26
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Jan 5, 2017
@devversion devversion requested a review from mmalerba January 5, 2017 17:16
this.updateDocumentRectangle();

// Subscribe to scroll and resize events and update the document rectangle on changes.
scrollDispatcher
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can all fit on one line

private _documentRect: ClientRect;

constructor(scrollDispatcher: ScrollDispatcher) {

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I can't stand extra whitespace, you can leave it if you want but I'll definitely delete it if I ever edit this file :p

Copy link
Member Author

Choose a reason for hiding this comment

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

Haha will change it. Just in case you'd touch it 😄

* @internal
* Updates the cached client rectangle of the document element.
*/
updateDocumentRectangle() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think our convention is to name internal methods with _, if that's not possible we add a @docs-private comment. IIRC marking stuff @internal caused issues in google3

Copy link
Member

Choose a reason for hiding this comment

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

Yep; using @internal causes issues with the Closure Compiler, which is why we have the @docs-private annotation. It's easier to just use an underscore prefix, though (without the private access modifier if it's not actually private).

I would also call this something like cacheViewportGeometry; using the "update" verb implies that calling this function will enact some change on the document rectangle instead of reading (and caching) it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will change that 👍

scrollTo(1500, 2000);
ruler.updateDocumentRectangle();
Copy link
Contributor

Choose a reason for hiding this comment

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

comment why

@@ -228,6 +232,8 @@ describe('MdRipple', () => {
document.documentElement.scrollTop = pageScrollTop;
// Mobile safari
window.scrollTo(pageScrollLeft, pageScrollTop);
// Force an update of the cached rectangle in the ViewportRuler.
Copy link
Contributor

Choose a reason for hiding this comment

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

... b/c IE

* @internal
* Updates the cached client rectangle of the document element.
*/
updateDocumentRectangle() {
Copy link
Member

Choose a reason for hiding this comment

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

Yep; using @internal causes issues with the Closure Compiler, which is why we have the @docs-private annotation. It's easier to just use an underscore prefix, though (without the private access modifier if it's not actually private).

I would also call this something like cacheViewportGeometry; using the "update" verb implies that calling this function will enact some change on the document rectangle instead of reading (and caching) it.

// the real ViewportRuler class because Typescript complains when using a class as an interface.
// Also we don't want to extend the ViewportRuler because we'd need to call the constructor
// in the superclass. In short: We should use Dependency Injection to fake the ViewportRuler.
let fakeViewportRuler: any;
Copy link
Member

Choose a reason for hiding this comment

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

TypeScript is fine with doing implements RealClass; it's one of the language features. The problem is the new private member, which causes any other implementation to automatically fail to match. You should be able to resolve this by marking the private member as optional (example).

(and the internal method as well)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh nice! - I wasted so much time trying to solve that.. (considered it as a challenge)

@@ -55,4 +63,12 @@ export class ViewportRuler {

return {top, left};
}

/**
* Caches the latest client rectangle of the document element.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: /** one-liners like this */

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed. Had that because of the @internal from before

@mmalerba mmalerba added pr: lgtm action: merge The PR is ready for merge by the caretaker and removed pr: needs review labels Jan 5, 2017
@kara
Copy link
Contributor

kara commented Jan 6, 2017

@devversion Can you take another look at this? Tests are failing in Google for buttons and tabs because they can't find ScrollDispatcher. Now that ViewportRuler depends on ScrollDispatcher, you may need to make changes to those modules as well.

Edit: actually nevermind! I think Jeremy's PR might make changing yours unnecessary...

@kara kara removed the action: merge The PR is ready for merge by the caretaker label Jan 6, 2017
@devversion
Copy link
Member Author

devversion commented Jan 6, 2017

@kara Just confirmed that you are right. Our tests didn't cover it because of the FakeViewportRuler classes we had - And yeah waiting for Jeremy's PR would make sense.

Now the `ViewportRuler` service, which is used in many components, caches the documents `BoundingClientRect` to avoid frequent recalculation of styles in the browser (basically each click for ripples etc.)

> The `ScrollDispatcher` is used as the service which triggers an update of the cached rectangles because it listens to the `resize` and `scroll` events.

It's important that the `ViewportRuler` also updates the rectangle for scroll events, because the ViewportRuler is also responsible for the scroll position of the viewport.
@devversion devversion force-pushed the feat/viewport-ruler-caching branch from cb5fc15 to a8f88bd Compare January 11, 2017 10:34
@devversion
Copy link
Member Author

@kara @jelbourn Rebased the PR on top of the #2556.

}

export function VIEWPORT_RULER_PROVIDER_FACTORY(parentDispatcher: ViewportRuler) {
return parentDispatcher || new ViewportRuler();
return parentDispatcher || new ViewportRuler(new ScrollDispatcher());
Copy link
Member

Choose a reason for hiding this comment

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

Instead of doing new ScrollDispatcher(), it should inject the existing scroll dispatcher.
(see MdIconRegistry for an example)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done - Thanks for the help on Slack again.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

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

LGTM

@jelbourn jelbourn added the action: merge The PR is ready for merge by the caretaker label Jan 12, 2017
@kara kara merged commit d0c8f18 into angular:master Jan 31, 2017
@devversion devversion deleted the feat/viewport-ruler-caching branch January 31, 2017 09:44
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants