Created
August 24, 2016 17:31
-
-
Save Spittal/4ed961cab42dcd3daa66c9fb081e4f64 to your computer and use it in GitHub Desktop.
Why Observables are amazing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@angular/core'; | |
import { Observable, ReplaySubject, Subscription } from 'rxjs'; | |
import { SlideAnimator } from './slide-animator'; | |
import { SlideObservables } from './slide-observables'; | |
import { SlideHelper } from './slide-helper'; | |
import { | |
SlideServiceConfig, | |
SlideEventEnd, | |
SlideEventStart, | |
SlideEvent, | |
SlideObsPayload | |
} from './slide-types'; | |
@Injectable() | |
export class SlideService { | |
public slideChange: ReplaySubject<SlideEvent> = new ReplaySubject<SlideEvent>(); | |
private isPaused: boolean = false; | |
private elements: HTMLElement[]; | |
private animating: boolean = false; | |
private config: SlideServiceConfig = { | |
sensitivity: 20, | |
minHeight: 400, | |
minWidth: 0 | |
}; | |
public init(initialIndex?: number): Subscription { | |
if (initialIndex) this.scrollToIndex(initialIndex); | |
return SlideObservables.slideObs | |
.filter(payload => this.checkWindowDimensions()) | |
.filter(payload => this.isPaused) | |
.filter(payload => this.checkWhereIsScroll(payload)) | |
.map(payload => { SlideHelper.preventDefault(payload.event); return payload; }) | |
.filter(payload => this.checkThreshhold(payload)) | |
.subscribe(payload => this.handleScrollEvent(payload)); | |
} | |
public scrollToIndex(toIndex: number, previousIndex?: number): void { | |
this.elements = SlideHelper.getNg2SlideElements(); | |
if (!previousIndex) previousIndex = SlideHelper.getCurrentSlideIndex(this.elements); | |
this.slideChange.next(new SlideEventStart(previousIndex, toIndex)); | |
if (this.elements[toIndex]) { | |
const startingPoint = window.scrollY; | |
const endingPoint = this.elements[toIndex].getBoundingClientRect().top + window.scrollY; | |
this.animating = true; | |
SlideAnimator.animateScroll(startingPoint, endingPoint, () => { | |
this.slideChange.next(new SlideEventEnd(previousIndex, toIndex)); | |
this.animating = false; | |
}); | |
} | |
} | |
public setConfiguration(config: SlideServiceConfig): void { | |
this.config = Object.assign(this.config, config); | |
} | |
private checkWindowDimensions(): boolean { | |
return ( | |
window.innerHeight >= this.config.minHeight && | |
window.innerWidth >= this.config.minWidth | |
); | |
} | |
private checkWhereIsScroll(payload: any): boolean { | |
this.elements = SlideHelper.getNg2SlideElements(); | |
payload.whereIsScroll = SlideHelper.whereIsScroll(this.elements); | |
return ( | |
(payload.whereIsScroll.above && payload.deltaY < 0) || | |
(payload.whereIsScroll.below && payload.deltaY >= 0) | |
); | |
} | |
private checkThreshhold(payload: any): boolean { | |
return !this.animating && Math.abs(payload.deltaY) > this.config.sensitivity; | |
} | |
private handleScrollEvent(payload: any): void { | |
const fromIndex: number = payload.whereIsScroll.elementIndex; | |
const toIndex: number = (payload.deltaY >= 0) ? fromIndex + 1 : fromIndex - 1; | |
if (toIndex >= 0 && toIndex < this.elements.length) | |
this.scrollToIndex(toIndex, fromIndex); | |
} | |
} | |
import { Injectable } from '@angular/core'; | |
import { Observable, ReplaySubject, Subscription } from 'rxjs'; | |
import { SlideAnimator } from './slide-animator'; | |
import { SlideObservables } from './slide-observables'; | |
import { SlideHelper } from './slide-helper'; | |
import { | |
SlideServiceConfig, | |
SlideEventEnd, | |
SlideEventStart, | |
SlideEvent, | |
SlideObsPayload | |
} from './slide-types'; | |
@Injectable() | |
export class SlideService { | |
public slideChange: ReplaySubject<SlideEvent> = new ReplaySubject<SlideEvent>(); | |
private isPaused: boolean = false; | |
private elements: HTMLElement[]; | |
private animating: boolean = false; | |
private config: SlideServiceConfig = { | |
sensitivity: 20, | |
minHeight: 400, | |
minWidth: 0 | |
}; | |
public init(initialIndex?: number): Subscription { | |
if (initialIndex) this.scrollToIndex(initialIndex); | |
return SlideObservables.slideObs | |
.filter(payload => this.checkWindowDimensions()) | |
.filter(payload => this.isPaused) | |
.filter(payload => this.checkWhereIsScroll(payload)) | |
.map(payload => { SlideHelper.preventDefault(payload.event); return payload; }) | |
.filter(payload => this.checkThreshhold(payload)) | |
.subscribe(payload => this.handleScrollEvent(payload)); | |
} | |
public scrollToIndex(toIndex: number, previousIndex?: number): void { | |
this.elements = SlideHelper.getNg2SlideElements(); | |
if (!previousIndex) previousIndex = SlideHelper.getCurrentSlideIndex(this.elements); | |
this.slideChange.next(new SlideEventStart(previousIndex, toIndex)); | |
if (this.elements[toIndex]) { | |
const startingPoint = window.scrollY; | |
const endingPoint = this.elements[toIndex].getBoundingClientRect().top + window.scrollY; | |
this.animating = true; | |
SlideAnimator.animateScroll(startingPoint, endingPoint, () => { | |
this.slideChange.next(new SlideEventEnd(previousIndex, toIndex)); | |
this.animating = false; | |
}); | |
} | |
} | |
public setConfiguration(config: SlideServiceConfig): void { | |
this.config = Object.assign(this.config, config); | |
} | |
private checkWindowDimensions(): boolean { | |
return ( | |
window.innerHeight >= this.config.minHeight && | |
window.innerWidth >= this.config.minWidth | |
); | |
} | |
private checkWhereIsScroll(payload: any): boolean { | |
this.elements = SlideHelper.getNg2SlideElements(); | |
payload.whereIsScroll = SlideHelper.whereIsScroll(this.elements); | |
return ( | |
(payload.whereIsScroll.above && payload.deltaY < 0) || | |
(payload.whereIsScroll.below && payload.deltaY >= 0) | |
); | |
} | |
private checkThreshhold(payload: any): boolean { | |
return !this.animating && Math.abs(payload.deltaY) > this.config.sensitivity; | |
} | |
private handleScrollEvent(payload: any): void { | |
const fromIndex: number = payload.whereIsScroll.elementIndex; | |
const toIndex: number = (payload.deltaY >= 0) ? fromIndex + 1 : fromIndex - 1; | |
if (toIndex >= 0 && toIndex < this.elements.length) | |
this.scrollToIndex(toIndex, fromIndex); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment