Skip to content

Instantly share code, notes, and snippets.

@Spittal
Created August 24, 2016 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Spittal/4ed961cab42dcd3daa66c9fb081e4f64 to your computer and use it in GitHub Desktop.
Save Spittal/4ed961cab42dcd3daa66c9fb081e4f64 to your computer and use it in GitHub Desktop.
Why Observables are amazing
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