-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
Conversation
this.updateDocumentRectangle(); | ||
|
||
// Subscribe to scroll and resize events and update the document rectangle on changes. | ||
scrollDispatcher |
There was a problem hiding this comment.
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) { | ||
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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 */
There was a problem hiding this comment.
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
@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 Just confirmed that you are right. Our tests didn't cover it because of the |
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.
cb5fc15
to
a8f88bd
Compare
} | ||
|
||
export function VIEWPORT_RULER_PROVIDER_FACTORY(parentDispatcher: ViewportRuler) { | ||
return parentDispatcher || new ViewportRuler(); | ||
return parentDispatcher || new ViewportRuler(new ScrollDispatcher()); |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
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.)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