Added possibility to set viewport offset

This commit is contained in:
squidfunk 2020-02-14 15:30:06 +01:00
parent 6f0efca4a4
commit 29d15a2e22
4 changed files with 154 additions and 97 deletions

View File

@ -20,29 +20,23 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import { Observable, combineLatest, fromEvent, merge } from "rxjs" import { Observable, combineLatest } from "rxjs"
import { map, shareReplay, startWith } from "rxjs/operators" import { map, shareReplay } from "rxjs/operators"
import { Header } from "../../../header"
import {
ViewportOffset,
watchViewportOffset
} from "../offset"
import {
ViewportSize,
watchViewportSize
} from "../size"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Types * Types
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/**
* Viewport offset
*/
export interface ViewportOffset {
x: number /* Horizontal offset */
y: number /* Vertical offset */
}
/**
* Viewport size
*/
export interface ViewportSize {
width: number /* Viewport width */
height: number /* Viewport height */
}
/** /**
* Viewport * Viewport
*/ */
@ -52,63 +46,20 @@ export interface Viewport {
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Functions * Helper types
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/** /**
* Retrieve viewport offset * Watch relative options
*
* @return Viewport offset
*/ */
export function getViewportOffset(): ViewportOffset { interface WatchRelativeOptions {
return { header$: Observable<Header> /* Header observable */
x: pageXOffset, viewport$: Observable<Viewport> /* Viewport observable */
y: pageYOffset
}
} }
/** /* ----------------------------------------------------------------------------
* Retrieve viewport size * Functions
* * ------------------------------------------------------------------------- */
* @return Viewport size
*/
export function getViewportSize(): ViewportSize {
return {
width: innerWidth,
height: innerHeight
}
}
/* ------------------------------------------------------------------------- */
/**
* Watch viewport offset
*
* @return Viewport offset observable
*/
export function watchViewportOffset(): Observable<ViewportOffset> {
return merge(
fromEvent<UIEvent>(window, "scroll"),
fromEvent<UIEvent>(window, "resize")
)
.pipe(
map(getViewportOffset),
startWith(getViewportOffset())
)
}
/**
* Watch viewport size
*
* @return Viewport size observable
*/
export function watchViewportSize(): Observable<ViewportSize> {
return fromEvent<UIEvent>(window, "resize")
.pipe(
map(getViewportSize),
startWith(getViewportSize())
)
}
/** /**
* Watch viewport * Watch viewport
@ -125,3 +76,27 @@ export function watchViewport(): Observable<Viewport> {
shareReplay(1) shareReplay(1)
) )
} }
/**
* Watch viewport relative to element
*
* @param el - Element
* @param options - Options
*
* @return Viewport observable
*/
export function watchViewportFrom(
el: HTMLElement, { header$, viewport$ }: WatchRelativeOptions
): Observable<Viewport> {
return combineLatest([viewport$, header$])
.pipe(
map(([{ offset, size }, { height }]) => ({
offset: {
x: offset.x - el.offsetLeft,
y: offset.y - el.offsetTop + height
},
size
})),
shareReplay(1)
)
}

View File

@ -21,4 +21,5 @@
*/ */
export * from "./_" export * from "./_"
export * from "./relative" export * from "./offset"
export * from "./size"

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2016-2020 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
import { Observable, fromEvent, merge } from "rxjs"
import { map, startWith } from "rxjs/operators"
/* ----------------------------------------------------------------------------
* Types
* ------------------------------------------------------------------------- */
/**
* Viewport offset
*/
export interface ViewportOffset {
x: number /* Horizontal offset */
y: number /* Vertical offset */
}
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Retrieve viewport offset
*
* @return Viewport offset
*/
export function getViewportOffset(): ViewportOffset {
return {
x: pageXOffset,
y: pageYOffset
}
}
/**
* Retrieve viewport offset
*
* @param offset - Viewport offset
*/
export function setViewportOffset(
{ x, y }: Partial<ViewportOffset>
): void {
window.scrollTo(x || 0, y || 0)
}
/* ------------------------------------------------------------------------- */
/**
* Watch viewport offset
*
* @return Viewport offset observable
*/
export function watchViewportOffset(): Observable<ViewportOffset> {
return merge(
fromEvent<UIEvent>(window, "scroll"),
fromEvent<UIEvent>(window, "resize")
)
.pipe(
map(getViewportOffset),
startWith(getViewportOffset())
)
}

View File

@ -20,22 +20,19 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
import { Observable, combineLatest } from "rxjs" import { Observable, combineLatest, fromEvent, merge } from "rxjs"
import { map, shareReplay } from "rxjs/operators" import { map, shareReplay, startWith } from "rxjs/operators"
import { Header } from "../../../header"
import { Viewport } from "../_"
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Helper types * Types
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/** /**
* Watch options * Viewport size
*/ */
interface WatchOptions { export interface ViewportSize {
header$: Observable<Header> /* Header observable */ width: number /* Viewport width */
viewport$: Observable<Viewport> /* Viewport observable */ height: number /* Viewport height */
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -43,25 +40,28 @@ interface WatchOptions {
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/** /**
* Watch viewport relative to element * Retrieve viewport size
* *
* @param el - Element * @return Viewport size
* @param options - Options
*
* @return Viewport observable
*/ */
export function watchViewportFrom( export function getViewportSize(): ViewportSize {
el: HTMLElement, { header$, viewport$ }: WatchOptions return {
): Observable<Viewport> { width: innerWidth,
return combineLatest([viewport$, header$]) height: innerHeight
}
}
/* ------------------------------------------------------------------------- */
/**
* Watch viewport size
*
* @return Viewport size observable
*/
export function watchViewportSize(): Observable<ViewportSize> {
return fromEvent<UIEvent>(window, "resize")
.pipe( .pipe(
map(([{ offset, size }, { height }]) => ({ map(getViewportSize),
offset: { startWith(getViewportSize())
x: offset.x - el.offsetLeft,
y: offset.y - el.offsetTop + height
},
size
})),
shareReplay(1)
) )
} }