Skip to content

Commit

Permalink
perf(animation): improves _progress() hot function
Browse files Browse the repository at this point in the history
- progress() is the function where more time is spent during any swipe gesture
- replace iterating over the _fx properties, using an array instead
- optimize pointerCoord(), profiler showed it’s one of the most called functions
  • Loading branch information
manucorporat committed Nov 16, 2016
1 parent 70f8a8e commit c44f6b6
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 76 deletions.
145 changes: 80 additions & 65 deletions src/animations/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class Animation {
private _cL: number;
private _e: HTMLElement[];
private _eL: number;
private _fx: {[key: string]: EffectProperty};
private _fx: EffectProperty[];
private _dur: number = null;
private _es: string = null;
private _bfSty: { [property: string]: any; };
Expand Down Expand Up @@ -159,26 +159,39 @@ export class Animation {
* @private
* NO DOM
*/

private _getProp(name: string): EffectProperty {
if (this._fx) {
return this._fx.find((prop) => prop.name === name);
} else {
this._fx = [];
}
return null;
}

private _addProp(state: string, prop: string, val: any): EffectProperty {
this._fx = this._fx || {};
let fxProp = this._fx[prop];
let fxProp = this._getProp(prop);

if (!fxProp) {
// first time we've see this EffectProperty
fxProp = this._fx[prop] = {
trans: (TRANSFORMS[prop] === 1)
};
var shouldTrans = (TRANSFORMS[prop] === 1);
fxProp = {
name: prop,
trans: shouldTrans,

// add the will-change property for transforms or opacity
fxProp.wc = (fxProp.trans ? CSS.transform : prop);
// add the will-change property for transforms or opacity
wc: (shouldTrans ? CSS.transform : prop)
};
this._fx.push(fxProp);
}

// add from/to EffectState to the EffectProperty
let fxState: EffectState = (<any>fxProp)[state] = {
let fxState: EffectState = {
val: val,
num: null,
unit: '',
};
fxProp[state] = fxState;

if (typeof val === 'string' && val.indexOf(' ') < 0) {
let r = val.match(CSS_VALUE_REGEX);
Expand Down Expand Up @@ -594,72 +607,72 @@ export class Animation {
*/
_progress(stepValue: number) {
// bread 'n butter
var val: any;
let val: any;
let effects = this._fx;
let nuElements = this._eL;

if (this._fx && this._eL) {
// flip the number if we're going in reverse
if (this._rv) {
stepValue = ((stepValue * -1) + 1);
}
var transforms: string[] = [];
var effects = this._fx;
var elements = this._e;
for (var prop in effects) {
var fx = effects[prop];

if (fx.from && fx.to) {
var fromNum = fx.from.num;
var toNum = fx.to.num;
var tweenEffect = (fromNum !== toNum);
if (tweenEffect) {
this._twn = true;
}
if (!effects || !nuElements) {
return;
}

if (stepValue === 0) {
// FROM
val = fx.from.val;
// flip the number if we're going in reverse
if (this._rv) {
stepValue = ((stepValue * -1) + 1);
}
var i, j;
var finalTransform: string = '';
var elements = this._e;
for (i = 0; i < effects.length; i++) {
var fx = effects[i];

if (fx.from && fx.to) {
var fromNum = fx.from.num;
var toNum = fx.to.num;
var tweenEffect = (fromNum !== toNum);
if (tweenEffect) {
this._twn = true;
}

} else if (stepValue === 1) {
// TO
val = fx.to.val;
if (stepValue === 0) {
// FROM
val = fx.from.val;

} else if (tweenEffect) {
// EVERYTHING IN BETWEEN
val = (((toNum - fromNum) * stepValue) + fromNum) + fx.to.unit;
} else if (stepValue === 1) {
// TO
val = fx.to.val;

} else {
val = null;
}
} else if (tweenEffect) {
// EVERYTHING IN BETWEEN
val = (((toNum - fromNum) * stepValue) + fromNum) + fx.to.unit;
}

if (val !== null) {
if (fx.trans) {
transforms.push(prop + '(' + val + ')');
if (val !== null) {
var prop = fx.name;
if (fx.trans) {
finalTransform += prop + '(' + val + ') ';

} else {
for (var i = 0; i < this._eL; i++) {
// ******** DOM WRITE ****************
elements[i].style[prop] = val;
}
} else {
for (j = 0; j < nuElements; j++) {
// ******** DOM WRITE ****************
elements[j].style[prop] = val;
}
}
}
}
}

// place all transforms on the same property
if (transforms.length) {
if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
transforms.push('translateZ(0px)');
}
// place all transforms on the same property
if (finalTransform.length) {
if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
finalTransform += 'translateZ(0px)';
}

var transformString = transforms.join(' ');
var cssTransform = CSS.transform;
for (var i = 0; i < this._eL; i++) {
// ******** DOM WRITE ****************
elements[i].style[cssTransform] = transformString;
}
var cssTransform = CSS.transform;
for (i = 0; i < elements.length; i++) {
// ******** DOM WRITE ****************
elements[i].style[cssTransform] = finalTransform;
}
}

}

/**
Expand Down Expand Up @@ -900,15 +913,16 @@ export class Animation {
*/
_willChg(addWillChange: boolean) {
let wc: string[];

if (addWillChange) {
var effects = this._fx;
if (addWillChange && effects) {
wc = [];
for (var prop in this._fx) {
if (this._fx[prop].wc === 'webkitTransform') {
for (var i = 0; i < effects.length; i++) {
var propWC = effects[i].wc;
if (propWC === 'webkitTransform') {
wc.push('transform', '-webkit-transform');

} else {
wc.push(this._fx[prop].wc);
wc.push(propWC);
}
}
}
Expand Down Expand Up @@ -1164,6 +1178,7 @@ export interface PlayOptions {
}

export interface EffectProperty {
name: string;
trans: boolean;
wc?: string;
to?: EffectState;
Expand Down
2 changes: 1 addition & 1 deletion src/components/menu/menu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ ion-menu ion-backdrop {
z-index: -1;
display: none;

opacity: .1;
opacity: .01;
}

.menu-content {
Expand Down
3 changes: 2 additions & 1 deletion src/components/refresher/test/refresher.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ describe('Refresher', () => {
function touchEv(y: number) {
return {
type: 'mockTouch',
touches: [{clientY: y}],
pageX: 0,
pageY: y,
preventDefault: function(){}
};
}
Expand Down
3 changes: 1 addition & 2 deletions src/gestures/drag-gesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export class PanGesture {
let coord = pointerCoord(ev);
if (this.detector.detect(coord)) {

if (this.detector.pan() !== 0 && this.canCapture(ev) &&
if (this.detector.pan() !== 0 &&
(!this.gestute || this.gestute.capture())) {
this.onDragStart(ev);
this.captured = true;
Expand Down Expand Up @@ -156,7 +156,6 @@ export class PanGesture {

// Implemented in a subclass
canStart(ev: any): boolean { return true; }
canCapture(ev: any): boolean { return true; }
onDragStart(ev: any) { }
onDragMove(ev: any) { }
onDragEnd(ev: any) { }
Expand Down
16 changes: 9 additions & 7 deletions src/util/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,18 @@ export function windowLoad(callback?: Function) {
export function pointerCoord(ev: any): PointerCoordinates {
// get coordinates for either a mouse click
// or a touch depending on the given event
let c = { x: 0, y: 0 };
if (ev) {
const touches = ev.touches && ev.touches.length ? ev.touches : [ev];
const e = (ev.changedTouches && ev.changedTouches[0]) || touches[0];
if (e) {
c.x = e.clientX || e.pageX || 0;
c.y = e.clientY || e.pageY || 0;
var changedTouches = ev.changedTouches;
if (changedTouches && changedTouches.length > 0) {
var touch = changedTouches[0];
return { x: touch.clientX, y: touch.clientY };
}
var pageX = ev.pageX;
if (pageX !== undefined) {
return { x: pageX, y: ev.pageY };
}
}
return c;
return { x: 0, y: 0 };
}

export function hasPointerMoved(threshold: number, startCoord: PointerCoordinates, endCoord: PointerCoordinates) {
Expand Down

0 comments on commit c44f6b6

Please sign in to comment.