mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 22:17:40 +08:00
perf(animation): improves _progress() hot function
- 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
This commit is contained in:
@ -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; };
|
||||
@ -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);
|
||||
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);
|
||||
@ -594,18 +607,23 @@ export class Animation {
|
||||
*/
|
||||
_progress(stepValue: number) {
|
||||
// bread 'n butter
|
||||
var val: any;
|
||||
let val: any;
|
||||
let effects = this._fx;
|
||||
let nuElements = this._eL;
|
||||
|
||||
if (!effects || !nuElements) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 i, j;
|
||||
var finalTransform: string = '';
|
||||
var elements = this._e;
|
||||
for (var prop in effects) {
|
||||
var fx = effects[prop];
|
||||
for (i = 0; i < effects.length; i++) {
|
||||
var fx = effects[i];
|
||||
|
||||
if (fx.from && fx.to) {
|
||||
var fromNum = fx.from.num;
|
||||
@ -626,19 +644,17 @@ export class Animation {
|
||||
} else if (tweenEffect) {
|
||||
// EVERYTHING IN BETWEEN
|
||||
val = (((toNum - fromNum) * stepValue) + fromNum) + fx.to.unit;
|
||||
|
||||
} else {
|
||||
val = null;
|
||||
}
|
||||
|
||||
if (val !== null) {
|
||||
var prop = fx.name;
|
||||
if (fx.trans) {
|
||||
transforms.push(prop + '(' + val + ')');
|
||||
finalTransform += prop + '(' + val + ') ';
|
||||
|
||||
} else {
|
||||
for (var i = 0; i < this._eL; i++) {
|
||||
for (j = 0; j < nuElements; j++) {
|
||||
// ******** DOM WRITE ****************
|
||||
elements[i].style[prop] = val;
|
||||
elements[j].style[prop] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -646,22 +662,19 @@ export class Animation {
|
||||
}
|
||||
|
||||
// place all transforms on the same property
|
||||
if (transforms.length) {
|
||||
if (finalTransform.length) {
|
||||
if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
|
||||
transforms.push('translateZ(0px)');
|
||||
finalTransform += 'translateZ(0px)';
|
||||
}
|
||||
|
||||
var transformString = transforms.join(' ');
|
||||
var cssTransform = CSS.transform;
|
||||
for (var i = 0; i < this._eL; i++) {
|
||||
for (i = 0; i < elements.length; i++) {
|
||||
// ******** DOM WRITE ****************
|
||||
elements[i].style[cssTransform] = transformString;
|
||||
elements[i].style[cssTransform] = finalTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* DOM WRITE
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1164,6 +1178,7 @@ export interface PlayOptions {
|
||||
}
|
||||
|
||||
export interface EffectProperty {
|
||||
name: string;
|
||||
trans: boolean;
|
||||
wc?: string;
|
||||
to?: EffectState;
|
||||
|
@ -51,7 +51,7 @@ ion-menu ion-backdrop {
|
||||
z-index: -1;
|
||||
display: none;
|
||||
|
||||
opacity: .1;
|
||||
opacity: .01;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
|
@ -232,7 +232,8 @@ describe('Refresher', () => {
|
||||
function touchEv(y: number) {
|
||||
return {
|
||||
type: 'mockTouch',
|
||||
touches: [{clientY: y}],
|
||||
pageX: 0,
|
||||
pageY: y,
|
||||
preventDefault: function(){}
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
@ -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) { }
|
||||
|
@ -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) {
|
||||
|
Reference in New Issue
Block a user