diff options
Diffstat (limited to 'sdc-workflow-designer-ui/src/app/paletx/core/overlay/position/viewport-ruler.ts')
-rw-r--r-- | sdc-workflow-designer-ui/src/app/paletx/core/overlay/position/viewport-ruler.ts | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/sdc-workflow-designer-ui/src/app/paletx/core/overlay/position/viewport-ruler.ts b/sdc-workflow-designer-ui/src/app/paletx/core/overlay/position/viewport-ruler.ts new file mode 100644 index 00000000..298cd642 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/paletx/core/overlay/position/viewport-ruler.ts @@ -0,0 +1,110 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/* tslint:disable:array-type member-access variable-name typedef + only-arrow-functions directive-class-suffix component-class-suffix + component-selector no-unnecessary-type-assertion arrow-parens*/ +import {Injectable, Optional, SkipSelf} from '@angular/core'; +import {ScrollDispatcher} from '../scroll/scroll-dispatcher'; + + +/** + * Simple utility for getting the bounds of the browser viewport. + * @docs-private + */ +@Injectable() +export class ViewportRuler { + /** Cached document client rectangle. */ + private _documentRect?: ClientRect; + + constructor(scrollDispatcher: ScrollDispatcher) { + // Subscribe to scroll and resize events and update the document rectangle + // on changes. + scrollDispatcher.scrolled(0, () => this._cacheViewportGeometry()); + } + + /** Gets a ClientRect for the viewport's bounds. */ + getViewportRect(documentRect = this._documentRect): ClientRect { + // Cache the document bounding rect so that we don't recompute it for + // multiple calls. + if (!documentRect) { + this._cacheViewportGeometry(); + documentRect = this._documentRect; + } + + // Use the document element's bounding rect rather than the window scroll + // properties (e.g. pageYOffset, scrollY) due to in issue in Chrome and IE + // where window scroll properties and client coordinates + // (boundingClientRect, clientX/Y, etc.) are in different conceptual + // viewports. Under most circumstances these viewports are equivalent, but + // they can disagree when the page is pinch-zoomed (on devices that support + // touch). See + // https://bugs.chromium.org/p/chromium/issues/detail?id=489206#c4 We use + // the documentElement instead of the body because, by default (without a + // css reset) browsers typically give the document body an 8px margin, which + // is not included in getBoundingClientRect(). + const scrollPosition = this.getViewportScrollPosition(documentRect); + const height = window.innerHeight; + const width = window.innerWidth; + + return { + top: scrollPosition.top, + left: scrollPosition.left, + bottom: scrollPosition.top + height, + right: scrollPosition.left + width, + height, + width, + }; + } + + + /** + * Gets the (top, left) scroll position of the viewport. + * @param documentRect + */ + getViewportScrollPosition(documentRect = this._documentRect) { + // Cache the document bounding rect so that we don't recompute it for + // multiple calls. + if (!documentRect) { + this._cacheViewportGeometry(); + documentRect = this._documentRect; + } + + // The top-left-corner of the viewport is determined by the scroll position + // of the document body, normally just (scrollLeft, scrollTop). However, + // Chrome and Firefox disagree about whether `document.body` or + // `document.documentElement` is the scrolled element, so reading + // `scrollTop` and `scrollLeft` is inconsistent. However, using the bounding + // rect of `document.documentElement` works consistently, where the `top` + // and `left` values will equal negative the scroll position. + const top = -documentRect.top || document.body.scrollTop || + window.scrollY || document.documentElement.scrollTop || 0; + + const left = -documentRect.left || document.body.scrollLeft || + window.scrollX || document.documentElement.scrollLeft || 0; + + return {top, left}; + } + + /** Caches the latest client rectangle of the document element. */ + _cacheViewportGeometry() { + this._documentRect = document.documentElement.getBoundingClientRect(); + } +} + +export function VIEWPORT_RULER_PROVIDER_FACTORY( + parentRuler: ViewportRuler, scrollDispatcher: ScrollDispatcher) { + return parentRuler || new ViewportRuler(scrollDispatcher); +} + +export const VIEWPORT_RULER_PROVIDER = { + // If there is already a ViewportRuler available, use that. Otherwise, provide + // a new one. + provide: ViewportRuler, + deps: [[new Optional(), new SkipSelf(), ViewportRuler], ScrollDispatcher], + useFactory: VIEWPORT_RULER_PROVIDER_FACTORY +}; |