Skip to content

Commit

Permalink
perf(content): scrollview magic activated on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Mar 16, 2017
1 parent 963cdcb commit 7e9bad5
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 64 deletions.
34 changes: 17 additions & 17 deletions src/components/content/content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';

import { App } from '../app/app';
import { Config } from '../../config/config';
Expand Down Expand Up @@ -123,7 +123,7 @@ export { ScrollEvent } from '../../util/scroll-view';
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class Content extends Ion implements OnDestroy, OnInit {
export class Content extends Ion implements OnDestroy {
/** @internal */
_cTop: number;
/** @internal */
Expand Down Expand Up @@ -339,7 +339,12 @@ export class Content extends Ion implements OnDestroy, OnInit {
this._imgReqBfr = config.getNumber('imgRequestBuffer', 1400);
this._imgRndBfr = config.getNumber('imgRenderBuffer', 400);
this._imgVelMax = config.getNumber('imgVelocityMax', 3);
this._scroll = new ScrollView(_plt, _dom);

// use JS scrolling for iOS UIWebView
// goal is to completely remove this when iOS
// fully supports scroll events
// listen to JS scroll events
this._scroll = new ScrollView(_plt, _dom, config.getBoolean('virtualScrollEventAssist'));

if (viewCtrl) {
// content has a view controller
Expand All @@ -366,7 +371,7 @@ export class Content extends Ion implements OnDestroy, OnInit {
/**
* @private
*/
ngOnInit() {
enableScrollListener() {
assert(this.getFixedElement(), 'fixed element was not found');
assert(this.getScrollElement(), 'scroll element was not found');

Expand All @@ -375,27 +380,29 @@ export class Content extends Ion implements OnDestroy, OnInit {
scroll.ev.scrollElement = this.getScrollElement();

// subscribe to the scroll start
scroll.scrollStart.subscribe(ev => {
scroll.onScrollStart = (ev) => {
this.ionScrollStart.emit(ev);
});
};

// subscribe to every scroll move
scroll.scroll.subscribe(ev => {
scroll.onScroll = (ev) => {
// remind the app that it's currently scrolling
this._app.setScrolling();

// emit to all of our other friends things be scrolling
this.ionScroll.emit(ev);

this.imgsUpdate();
});
};

// subscribe to the scroll end
scroll.scrollEnd.subscribe(ev => {
scroll.onScrollEnd = (ev) => {
this.ionScrollEnd.emit(ev);

this.imgsUpdate();
});
};

scroll.setEnabled();
}

/**
Expand Down Expand Up @@ -466,13 +473,6 @@ export class Content extends Ion implements OnDestroy, OnInit {
return this._scroll.scrollToBottom(duration);
}

/**
* @private
*/
enableJsScroll() {
this._scroll.enableJsScroll(this._cTop, this._cBottom);
}

/**
* @input {boolean} If true, the content will scroll behind the headers
* and footers. This effect can easily be seen by setting the toolbar
Expand Down
5 changes: 2 additions & 3 deletions src/components/infinite-scroll/infinite-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,8 @@ export class InfiniteScroll {
if (this._init) {
if (shouldListen) {
if (!this._scLsn) {
this._scLsn = this._content.ionScroll.subscribe((ev: ScrollEvent) => {
this._onScroll(ev);
});
this._scLsn = this._content.ionScroll.subscribe(this._onScroll.bind(this));
this._content.enableScrollListener();
}
} else {
this._scLsn && this._scLsn.unsubscribe();
Expand Down
9 changes: 1 addition & 8 deletions src/components/virtual-scroll/virtual-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,17 +708,10 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy {
*/
private _listeners() {
if (!this._scrollSub) {
if (this._config.getBoolean('virtualScrollEventAssist')) {
// use JS scrolling for iOS UIWebView
// goal is to completely remove this when iOS
// fully supports scroll events
// listen to JS scroll events
this._content.enableJsScroll();
}

this._resizeSub = this._plt.resize.subscribe(this.resize.bind(this));
this._scrollSub = this._content.ionScroll.subscribe(this.scrollUpdate.bind(this));
this._scrollEndSub = this._content.ionScrollEnd.subscribe(this.scrollEnd.bind(this));
this._content.enableScrollListener();
}
}

Expand Down
17 changes: 9 additions & 8 deletions src/util/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,22 +134,23 @@ export function setupEvents(plt: Platform, dom: DomController): Events {
let el = <HTMLElement>doc.elementFromPoint(plt.width() / 2, plt.height() / 2);
if (!el) { return; }

let contentEle = <HTMLElement>el.closest('.scroll-content');
let contentEle = <any>el.closest('.scroll-content');
if (contentEle) {
var scroll = new ScrollView(plt, dom);
var style = contentEle.style;
var scroll = new ScrollView(plt, dom, false);
scroll.init(contentEle, 0, 0);
// We need to stop scrolling if it's happening and scroll up

(<any>contentEle.style)['WebkitBackfaceVisibility'] = 'hidden';
(<any>contentEle.style)['WebkitTransform'] = 'translate3d(0,0,0)';
style['WebkitBackfaceVisibility'] = 'hidden';
style['WebkitTransform'] = 'translate3d(0,0,0)';

dom.write(function() {
contentEle.style.overflow = 'hidden';
style.overflow = 'hidden';

function finish() {
contentEle.style.overflow = '';
(<any>contentEle.style)['WebkitBackfaceVisibility'] = '';
(<any>contentEle.style)['WebkitTransform'] = '';
style.overflow = '';
style['WebkitBackfaceVisibility'] = '';
style['WebkitTransform'] = '';
}

let didScrollTimeout = plt.timeout(() => {
Expand Down
81 changes: 53 additions & 28 deletions src/util/scroll-view.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Subject } from 'rxjs/Subject';

import { assert } from './util';
import { DomController, DomCallback } from '../platform/dom-controller';
Expand All @@ -9,10 +8,13 @@ import { pointerCoord } from './dom';
export class ScrollView {
ev: ScrollEvent;
isScrolling = false;
scrollStart = new Subject<ScrollEvent>();
scroll = new Subject<ScrollEvent>();
scrollEnd = new Subject<ScrollEvent>();
initialized: boolean;
onScrollStart: (ev: ScrollEvent) => void;
onScroll: (ev: ScrollEvent) => void;
onScrollEnd: (ev: ScrollEvent) => void;
initialized: boolean = false;
enabled: boolean = false;
contentTop: number;
contentBottom: number;

private _el: HTMLElement;
private _js: boolean;
Expand All @@ -22,7 +24,12 @@ export class ScrollView {
private _endTmr: Function;


constructor(private _plt: Platform, private _dom: DomController) {
constructor(
private _plt: Platform,
private _dom: DomController,
virtualScrollEventAssist: boolean
) {
this._js = virtualScrollEventAssist;
this.ev = {
timeStamp: 0,
scrollTop: 0,
Expand All @@ -41,27 +48,47 @@ export class ScrollView {
velocityX: 0,
directionY: 'down',
directionX: null,
domWrite: function(fn: DomCallback, ctx?: any): void {
_dom.write(fn, ctx);
}
domWrite: _dom.write.bind(_dom)
};
}

init(ele: HTMLElement, contentTop: number, contentBottom: number) {
assert(ele, 'scroll-view, element can not be null');
this._el = ele;
this.initialized = true;
this.contentTop = contentTop;
this.contentBottom = contentBottom;

if (!this.initialized) {
this.initialized = true;

assert(ele, 'scroll-view, element can not be null');
this._el = ele;
if (this.enabled) {
this.enable();
}
}
}

if (this._js) {
this.enableJsScroll(contentTop, contentBottom);
} else {
this.enableNativeScrolling();
setEnabled() {
if (!this.enabled) {
this.enabled = true;
if (this.initialized) {
this.enable();
}
}
}

enable() {
assert(this.initialized, 'scroll must be initialized');
assert(this.enabled, 'scroll-view must be enabled');
assert(this._el, 'scroll-view, element can not be null');

if (this._js) {
this.enableJsScroll();
} else {
this.enableNativeScrolling();
}
}

private enableNativeScrolling() {
this._js = false;
if (!this._el) {
Expand Down Expand Up @@ -103,7 +130,7 @@ export class ScrollView {
positions.length = 0;

// emit only on the first scroll event
self.scrollStart.next(ev);
self.onScrollStart(ev);
}

// actively scrolling
Expand Down Expand Up @@ -147,13 +174,13 @@ export class ScrollView {
ev.velocityY = ev.velocityX = 0;

// emit that the scroll has ended
self.scrollEnd && self.scrollEnd.next(ev);
self.onScrollEnd(ev);

self._endTmr = null;
}

// emit on each scroll event
self.scroll.next(ev);
self.onScroll(ev);

// debounce for a moment after the last scroll event
self._dom.cancel(self._endTmr);
Expand Down Expand Up @@ -181,7 +208,7 @@ export class ScrollView {
* inertia then this can be burned to the ground. iOS's more modern
* WKWebView does not have this issue, only UIWebView does.
*/
enableJsScroll(contentTop: number, contentBottom: number) {
enableJsScroll() {
const self = this;
self._js = true;
const ele = self._el;
Expand All @@ -200,7 +227,7 @@ export class ScrollView {
function setMax() {
if (!max) {
// ******** DOM READ ****************
max = ele.scrollHeight - ele.parentElement.offsetHeight + contentTop + contentBottom;
max = ele.scrollHeight - ele.parentElement.offsetHeight + self.contentTop + self.contentBottom;
}
};

Expand All @@ -221,7 +248,7 @@ export class ScrollView {
ev.scrollTop = self._t;

// emit on each scroll event
self.scroll.next(ev);
self.onScroll(ev);

self._dom.write(() => {
// ******** DOM WRITE ****************
Expand All @@ -240,7 +267,7 @@ export class ScrollView {
ev.velocityY = ev.velocityX = 0;

// emit that the scroll has ended
self.scrollEnd && self.scrollEnd.next(ev);
self.onScrollEnd(ev);
}
});
}
Expand Down Expand Up @@ -279,7 +306,7 @@ export class ScrollView {
self.isScrolling = true;

// emit only on the first scroll event
self.scrollStart.next(ev);
self.onScrollStart(ev);
}

self._dom.write(() => {
Expand All @@ -295,7 +322,7 @@ export class ScrollView {
if (!positions.length && self.isScrolling) {
self.isScrolling = false;
ev.velocityY = ev.velocityX = 0;
self.scrollEnd && self.scrollEnd.next(ev);
self.onScrollEnd(ev);
return;
}

Expand Down Expand Up @@ -333,7 +360,7 @@ export class ScrollView {
} else {
self.isScrolling = false;
ev.velocityY = 0;
self.scrollEnd && self.scrollEnd.next(ev);
self.onScrollEnd(ev);
}

positions.length = 0;
Expand Down Expand Up @@ -520,9 +547,7 @@ export class ScrollView {
this._endTmr && this._dom.cancel(this._endTmr);
this._lsn && this._lsn();

this.scrollStart && this.scrollStart.unsubscribe();
this.scroll && this.scroll.unsubscribe();
this.scrollEnd && this.scrollEnd.unsubscribe();
this.onScrollStart = this.onScroll = this.onScrollEnd = null;

let ev = this.ev;
ev.domWrite = ev.contentElement = ev.fixedElement = ev.scrollElement = ev.headerElement = null;
Expand Down

0 comments on commit 7e9bad5

Please sign in to comment.