Skip to content

Commit

Permalink
[RELEASE] 0.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
orizens committed Jan 7, 2018
1 parent 269b5f6 commit 7880627
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 219 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@ $ cat .gitignore
*.log
*.tgz

npm-debug.*
npm-debug.*
examples/
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v 0.8.1 (2018/01/07)
* [REFACTOR] - performance optimization for scroll events

## v 0.8.0 (2018/01/02)
* [FIX] - now triggers only once when in or after target (#200)
* [REFACTOR] - "distance" number has been refined to be the percentage point of the scroll nob.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-infinite-scroll",
"version": "0.8.0",
"version": "0.8.1",
"description": "An infinite scroll directive for Angular compatible with AoT compilation and Tree shaking",
"main": "./bundles/ngx-infinite-scroll.umd.js",
"module": "./modules/ngx-infinite-scroll.es5.js",
Expand Down
44 changes: 32 additions & 12 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,9 @@ export interface IPositionStats {
scrolledUntilNow: number;
totalToScroll: number;
}

export interface IScrollerConfig {
distance: {
down: number;
up: number;
};
scrollParent?: ContainerRef;
}

export interface IScrollStats {
isScrollingDown: boolean;
shouldScroll: boolean;
export interface IScrollerDistance {
down?: number;
up?: number;
}

export interface IScrollState {
Expand All @@ -42,3 +33,32 @@ export interface IResolver {
isWindow: boolean;
axis: any;
}

export interface IScrollRegisterConfig {
container: ContainerRef;
throttle: number;
}

export interface IScroller {
fromRoot: boolean;
horizontal: boolean;
disable: boolean;
throttle: number;
scrollWindow: boolean;
element: ElementRef;
scrollContainer: string | ElementRef;
alwaysCallback: boolean;
downDistance: number;
upDistance: number;
}

export interface IScrollParams {
isScrollingDown: boolean;
shouldFireScrollEvent: boolean;
positionStats: IPositionStats;
}

export interface IInfiniteScrollAction {
type: string;
payload: InfiniteScrollEvent;
}
25 changes: 16 additions & 9 deletions src/modules/infinite-scroll.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import {
} from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

import { InfiniteScrollEvent } from '../models';
import { InfiniteScrollEvent, IInfiniteScrollAction } from '../models';
import { hasWindowDefined, inputPropChanged } from '../services/ngx-ins-utils';
import { createScroller } from '../services/scroll-register';
import { createScroller, InfiniteScrollActions } from '../services/scroll-register';

@Directive({
selector: '[infiniteScroll], [infinite-scroll], [data-infinite-scroll]'
Expand Down Expand Up @@ -69,22 +69,29 @@ export class InfiniteScrollDirective
disable: this.infiniteScrollDisabled,
downDistance: this.infiniteScrollDistance,
element: this.element,
events: {
// tslint:disable-next-line:arrow-parens
down: event => this.zone.run(() => this.scrolled.emit(event)),
// tslint:disable-next-line:arrow-parens
up: event => this.zone.run(() => this.scrolledUp.emit(event))
},
horizontal: this.horizontal,
scrollContainer: this.infiniteScrollContainer,
scrollWindow: this.scrollWindow,
throttle: this.infiniteScrollThrottle,
upDistance: this.infiniteScrollUpDistance
});
}).subscribe((payload: any) => this.zone.run(() => this.handleOnScroll(payload)));
});
}
}

handleOnScroll({ type, payload }: IInfiniteScrollAction) {
switch (type) {
case InfiniteScrollActions.DOWN:
return this.scrolled.emit(payload);

case InfiniteScrollActions.UP:
return this.scrolledUp.emit(payload);

default:
return;
}
}

ngOnDestroy() {
this.destroyScroller();
}
Expand Down
2 changes: 0 additions & 2 deletions src/ngx-infinite-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ export {
InfiniteScrollEvent,
IPositionElements,
IPositionStats,
IScrollStats,
IScrollerConfig,
IResolver
} from './models';

Expand Down
19 changes: 5 additions & 14 deletions src/services/event-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,9 @@ export interface IScrollConfig {
shouldFireScrollEvent: boolean;
}

export function shouldTriggerEvents({ alwaysCallback, shouldFireScrollEvent }: IScrollConfig) {
return (alwaysCallback || shouldFireScrollEvent);
}

export function triggerEvents(
callbacks: ITriggerEvents,
isScrollingDown: boolean,
scrolledUntilNow: number
) {
const eventData: InfiniteScrollEvent = {
currentScrollPosition: scrolledUntilNow
};
const callback = isScrollingDown ? callbacks.down : callbacks.up;
callback(eventData);
export function shouldTriggerEvents(
alwaysCallback: boolean,
shouldFireScrollEvent: boolean,
isTriggeredCurrentTotal: boolean) {
return (alwaysCallback || shouldFireScrollEvent) && !isTriggeredCurrentTotal;
}
128 changes: 61 additions & 67 deletions src/services/scroll-register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,102 +2,96 @@ import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/sampleTime';

import { ElementRef } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { map } from 'rxjs/operator/map';
import { of } from 'rxjs/observable/of';

import { ContainerRef, IPositionStats, IScrollState } from '../models';
import * as Models from '../models';
import { AxisResolver } from './axis-resolver';
import { shouldTriggerEvents, triggerEvents } from './event-trigger';
import { shouldTriggerEvents, IScrollConfig } from './event-trigger';
import { resolveContainerElement } from './ngx-ins-utils';
import { calculatePoints, createResolver } from './position-resolver';
import * as ScrollResolver from './scroll-resolver';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

export interface IScrollRegisterConfig {
container: ContainerRef;
throttleDuration: number;
mergeMap: Function;
scrollHandler: (value: any) => void;
}

export interface IScroller {
fromRoot: boolean;
horizontal: boolean;
disable: boolean;
throttle: number;
scrollWindow: boolean;
element: ElementRef;
scrollContainer: string | ElementRef;
alwaysCallback: boolean;
downDistance: number;
upDistance: number;
events?: {
down: (ev) => any;
up: (ev) => any;
};
}

export function createScroller(config: IScroller): Subscription {
export function createScroller(config: Models.IScroller) {
const { scrollContainer, scrollWindow, element, fromRoot } = config;
const resolver = createResolver({
axis: new AxisResolver(!config.horizontal),
windowElement: resolveContainerElement(scrollContainer, scrollWindow, element, fromRoot)
});
const stats = calculatePoints(element, resolver);
const scrollState: IScrollState = {
const scrollState: Models.IScrollState = {
lastScrollPosition: 0,
lastTotalToScroll: 0,
totalToScroll: stats.totalToScroll,
isTriggeredTotal: false
};
const options: IScrollRegisterConfig = {
const options: Models.IScrollRegisterConfig = {
container: resolver.container,
mergeMap: () => calculatePoints(element, resolver),
scrollHandler: (positionStats: IPositionStats) =>
handleOnScroll(scrollState, positionStats, config),
throttleDuration: config.throttle
throttle: config.throttle
};
const distance = {
up: config.upDistance,
down: config.downDistance
};
return attachScrollEvent(options);
return attachScrollEvent(options)
.mergeMap((ev: any) => of(calculatePoints(element, resolver)))
.map((positionStats: Models.IPositionStats) =>
toInfiniteScrollParams(scrollState.lastScrollPosition, positionStats, distance))
.do(({ positionStats }: Models.IScrollParams) =>
ScrollResolver.updateScrollState(
scrollState,
positionStats.scrolledUntilNow,
positionStats.totalToScroll
))
.filter(({ shouldFireScrollEvent }: Models.IScrollParams) =>
shouldTriggerEvents(shouldFireScrollEvent, config.alwaysCallback, scrollState.isTriggeredTotal)
)
.do(() => {
ScrollResolver.updateTriggeredFlag(scrollState, true);
})
.map(toInfiniteScrollAction);
}

export function attachScrollEvent(
options: IScrollRegisterConfig
): Subscription {
return Observable.fromEvent(options.container, 'scroll')
.sampleTime(options.throttleDuration)
.mergeMap((ev: any) => Observable.of(options.mergeMap(ev)))
.subscribe(options.scrollHandler);
export function attachScrollEvent(options: Models.IScrollRegisterConfig): Observable<{}> {
return Observable
.fromEvent(options.container, 'scroll')
.sampleTime(options.throttle);
}

export function handleOnScroll(
scrollState: IScrollState,
positionStats: IPositionStats,
config: IScroller
) {
const distance = {
down: config.downDistance,
up: config.upDistance
};
export function toInfiniteScrollParams(
lastScrollPosition: number,
positionStats: Models.IPositionStats,
distance: Models.IScrollerDistance
): Models.IScrollParams {
const { isScrollingDown, shouldFireScrollEvent } = ScrollResolver.getScrollStats(
scrollState.lastScrollPosition,
lastScrollPosition,
positionStats,
{ distance }
distance
);
const scrollConfig = {
alwaysCallback: config.alwaysCallback,
shouldFireScrollEvent
return {
isScrollingDown,
shouldFireScrollEvent,
positionStats
};
}

export const InfiniteScrollActions = {
DOWN: '[NGX_ISE] DOWN',
UP: '[NGX_ISE] UP'
};

export function toInfiniteScrollAction(response: Models.IScrollParams): Models.IInfiniteScrollAction {
const { isScrollingDown, positionStats: { scrolledUntilNow: currentScrollPosition } } = response;
return {
type: isScrollingDown ? InfiniteScrollActions.DOWN : InfiniteScrollActions.UP,
payload: {
currentScrollPosition
}
};
ScrollResolver.updateScrollState(scrollState, positionStats.scrolledUntilNow, positionStats.totalToScroll);
const shouldTrigger = shouldTriggerEvents(scrollConfig);
if (shouldTrigger && !scrollState.isTriggeredTotal) {
ScrollResolver.updateTriggeredFlag(scrollState, true);
triggerEvents(
config.events,
isScrollingDown,
positionStats.scrolledUntilNow
);
}
}
9 changes: 4 additions & 5 deletions src/services/scroll-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { IPositionStats, IScrollerConfig, IScrollState } from '../models';
import { IPositionStats, IScrollState, IScrollerDistance } from '../models';

export function shouldFireScrollEvent(
container: IPositionStats,
config: IScrollerConfig,
distance: IScrollerDistance,
scrollingDown: boolean
) {
const distance = config.distance;
let remaining: number;
let containerBreakpoint: number;
if (scrollingDown) {
Expand All @@ -30,11 +29,11 @@ export function isScrollingDownwards(
export function getScrollStats(
lastScrollPosition: number,
container: IPositionStats,
config: IScrollerConfig
distance: IScrollerDistance
) {
const isScrollingDown = isScrollingDownwards(lastScrollPosition, container);
return {
shouldFireScrollEvent: shouldFireScrollEvent(container, config, isScrollingDown),
shouldFireScrollEvent: shouldFireScrollEvent(container, distance, isScrollingDown),
isScrollingDown
};
}
Expand Down
Loading

0 comments on commit 7880627

Please sign in to comment.