From 8b23c0636128b9ae7f2987f4a49e35bf8791ad0b Mon Sep 17 00:00:00 2001 From: David Perez Alvarez Date: Thu, 25 Oct 2018 04:55:42 -0400 Subject: [PATCH] refactor: change public api BREAKING CHANGE: Change exported api change scrollTo functions to centerElement, scrollTo, and scrollBy and add screen scroll type --- src/scroll.ts | 120 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/src/scroll.ts b/src/scroll.ts index 0cfebf7..0cfa1d6 100644 --- a/src/scroll.ts +++ b/src/scroll.ts @@ -1,19 +1,34 @@ -import { ScrollElement } from "./element" -import { AnimationManager } from "./animation-manager" -import { EasingFunction, defaultEasingFunction } from "./easing" import { Animation } from "./animation" - -const defaultSettings = { - easing: defaultEasingFunction, -} +import { AnimationManager } from "./animation-manager" +import { defaultEasingFunction, EasingFunction } from "./easing" +import { ScrollElement } from "./element" export type onScroll = (() => void) | null +enum ScrollType { + value = "value", + percent = "percent", + screen = "screen", +} + interface ISettings { easing: EasingFunction - onScroll?: onScroll - onUtilityScroll?: onScroll - onExternalScroll?: onScroll + onScroll: onScroll + onUtilityScroll: onScroll + onExternalScroll: onScroll + options: Required +} + +const defaultSettings: ISettings = { + easing: defaultEasingFunction, + onScroll: null, + onUtilityScroll: null, + onExternalScroll: null, + options: { + value: 0, + duration: 1000, + horizontal: false, + }, } interface IOptions { @@ -22,53 +37,70 @@ interface IOptions { horizontal?: boolean } -interface IScrollToElementOptions extends IOptions { - center?: number -} - class Scroll { private element: ScrollElement + private settings: ISettings private animationManager: AnimationManager - constructor(element?: HTMLElement, private settings: ISettings = defaultSettings) { + constructor(element?: HTMLElement | Window, settings: Partial = defaultSettings) { this.element = new ScrollElement(element) this.animationManager = new AnimationManager( () => this.settings.onUtilityScroll && this.settings.onUtilityScroll(), () => this.settings.onExternalScroll && this.settings.onExternalScroll(), this.element.position, ) - this.element.onScroll = () => this.settings.onScroll && this.settings.onScroll() + this.settings = defaultSettings + this.updateSettings(settings) + } + public updateSettings(settings: Partial) { + this.settings = Object.assign(this.settings, settings) + this.element.onScroll = this.settings.onScroll } public stopAllAnimations() { this.animationManager.stopAllAnimations() } - public readonly scroll = { - toElement: (element: HTMLElement, options: IScrollToElementOptions = {}): Animation => { - const ratio = (options.value || 0) / 100 - const horizontal = !!options.horizontal - const elementWrapper = new ScrollElement(element) - const screenOffset = (this.element.size(horizontal) - elementWrapper.size(horizontal)) * ratio - const elementPosition = elementWrapper.offset(horizontal) - this.element.offset(horizontal) - return this.scroll.offset(elementPosition - screenOffset, options) - }, - toPercent: (percent: number, options: IOptions = {}): Animation => { - const horizontal = !!options.horizontal - const position = - ((this.element.scrollSize(horizontal) - this.element.size(horizontal)) * percent) / 100 - return this.scroll.toPosition(position, options) - }, - toPosition: (position: number, options: IOptions = {}): Animation => { - const dist = position - this.element.position(!!options.horizontal) - return this.scroll.offset(dist, options) - }, - offset: (amount: number, options: IOptions = {}): Animation => { - return this.animationManager.createScrollAnimation({ - distToScroll: amount, - duration: options.duration || 0, - horizontal: options.horizontal || false, - easing: this.settings.easing, - }) - }, + public centerElement( + element: HTMLElement, + _options: IOptions = this.settings.options, + ): Animation { + const options = this.getDefault(_options) + const ratio = (options.value || 0) / 100 + const horizontal = options.horizontal + const elementWrapper = new ScrollElement(element) + const screenOffset = (this.element.size(horizontal) - elementWrapper.size(horizontal)) * ratio + const elementPosition = elementWrapper.offset(horizontal) - this.element.offset(horizontal) + return this.offsetScroll({ ...options, value: elementPosition - screenOffset }) + } + public scrollTo(scrollType: ScrollType, _options: IOptions = this.settings.options) { + const options = this.getDefault(_options) + const dist = this.getDist(scrollType, options.value, options.horizontal) + this.offsetScroll({ ...options, value: dist - this.element.position(options.horizontal) }) + } + public scrollBy(scrollType: ScrollType, _options: IOptions = this.settings.options) { + const options = this.getDefault(_options) + const dist = this.getDist(scrollType, options.value, options.horizontal) + this.offsetScroll({ ...options, value: dist }) + } + private offsetScroll(options: Required) { + return this.animationManager.createScrollAnimation({ + distToScroll: options.value, + easing: this.settings.easing, + duration: options.duration, + horizontal: options.horizontal, + }) + } + private getDist(scrollType: ScrollType, value: number, horizontal: boolean): number { + switch (scrollType) { + case ScrollType.percent: + return ((this.element.scrollSize(horizontal) - this.element.size(horizontal)) * value) / 100 + case ScrollType.screen: + return this.element.size(horizontal) * value + default: + return value + } + } + private getDefault(options: IOptions): Required { + return Object.assign(this.settings.options, options) } } -export { Scroll, IOptions, IScrollToElementOptions, Animation } +export { Scroll, IOptions, Animation }