mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 14:01:20 +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 _cL: number;
|
||||||
private _e: HTMLElement[];
|
private _e: HTMLElement[];
|
||||||
private _eL: number;
|
private _eL: number;
|
||||||
private _fx: {[key: string]: EffectProperty};
|
private _fx: EffectProperty[];
|
||||||
private _dur: number = null;
|
private _dur: number = null;
|
||||||
private _es: string = null;
|
private _es: string = null;
|
||||||
private _bfSty: { [property: string]: any; };
|
private _bfSty: { [property: string]: any; };
|
||||||
@ -159,26 +159,39 @@ export class Animation {
|
|||||||
* @private
|
* @private
|
||||||
* NO DOM
|
* 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 {
|
private _addProp(state: string, prop: string, val: any): EffectProperty {
|
||||||
this._fx = this._fx || {};
|
let fxProp = this._getProp(prop);
|
||||||
let fxProp = this._fx[prop];
|
|
||||||
|
|
||||||
if (!fxProp) {
|
if (!fxProp) {
|
||||||
// first time we've see this EffectProperty
|
// first time we've see this EffectProperty
|
||||||
fxProp = this._fx[prop] = {
|
var shouldTrans = (TRANSFORMS[prop] === 1);
|
||||||
trans: (TRANSFORMS[prop] === 1)
|
fxProp = {
|
||||||
};
|
name: prop,
|
||||||
|
trans: shouldTrans,
|
||||||
|
|
||||||
// add the will-change property for transforms or opacity
|
// 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
|
// add from/to EffectState to the EffectProperty
|
||||||
let fxState: EffectState = (<any>fxProp)[state] = {
|
let fxState: EffectState = {
|
||||||
val: val,
|
val: val,
|
||||||
num: null,
|
num: null,
|
||||||
unit: '',
|
unit: '',
|
||||||
};
|
};
|
||||||
|
fxProp[state] = fxState;
|
||||||
|
|
||||||
if (typeof val === 'string' && val.indexOf(' ') < 0) {
|
if (typeof val === 'string' && val.indexOf(' ') < 0) {
|
||||||
let r = val.match(CSS_VALUE_REGEX);
|
let r = val.match(CSS_VALUE_REGEX);
|
||||||
@ -594,18 +607,23 @@ export class Animation {
|
|||||||
*/
|
*/
|
||||||
_progress(stepValue: number) {
|
_progress(stepValue: number) {
|
||||||
// bread 'n butter
|
// 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
|
// flip the number if we're going in reverse
|
||||||
if (this._rv) {
|
if (this._rv) {
|
||||||
stepValue = ((stepValue * -1) + 1);
|
stepValue = ((stepValue * -1) + 1);
|
||||||
}
|
}
|
||||||
var transforms: string[] = [];
|
var i, j;
|
||||||
var effects = this._fx;
|
var finalTransform: string = '';
|
||||||
var elements = this._e;
|
var elements = this._e;
|
||||||
for (var prop in effects) {
|
for (i = 0; i < effects.length; i++) {
|
||||||
var fx = effects[prop];
|
var fx = effects[i];
|
||||||
|
|
||||||
if (fx.from && fx.to) {
|
if (fx.from && fx.to) {
|
||||||
var fromNum = fx.from.num;
|
var fromNum = fx.from.num;
|
||||||
@ -626,19 +644,17 @@ export class Animation {
|
|||||||
} else if (tweenEffect) {
|
} else if (tweenEffect) {
|
||||||
// EVERYTHING IN BETWEEN
|
// EVERYTHING IN BETWEEN
|
||||||
val = (((toNum - fromNum) * stepValue) + fromNum) + fx.to.unit;
|
val = (((toNum - fromNum) * stepValue) + fromNum) + fx.to.unit;
|
||||||
|
|
||||||
} else {
|
|
||||||
val = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val !== null) {
|
if (val !== null) {
|
||||||
|
var prop = fx.name;
|
||||||
if (fx.trans) {
|
if (fx.trans) {
|
||||||
transforms.push(prop + '(' + val + ')');
|
finalTransform += prop + '(' + val + ') ';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < this._eL; i++) {
|
for (j = 0; j < nuElements; j++) {
|
||||||
// ******** DOM WRITE ****************
|
// ******** 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
|
// place all transforms on the same property
|
||||||
if (transforms.length) {
|
if (finalTransform.length) {
|
||||||
if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
|
if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
|
||||||
transforms.push('translateZ(0px)');
|
finalTransform += 'translateZ(0px)';
|
||||||
}
|
}
|
||||||
|
|
||||||
var transformString = transforms.join(' ');
|
|
||||||
var cssTransform = CSS.transform;
|
var cssTransform = CSS.transform;
|
||||||
for (var i = 0; i < this._eL; i++) {
|
for (i = 0; i < elements.length; i++) {
|
||||||
// ******** DOM WRITE ****************
|
// ******** DOM WRITE ****************
|
||||||
elements[i].style[cssTransform] = transformString;
|
elements[i].style[cssTransform] = finalTransform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* DOM WRITE
|
* DOM WRITE
|
||||||
@ -900,15 +913,16 @@ export class Animation {
|
|||||||
*/
|
*/
|
||||||
_willChg(addWillChange: boolean) {
|
_willChg(addWillChange: boolean) {
|
||||||
let wc: string[];
|
let wc: string[];
|
||||||
|
var effects = this._fx;
|
||||||
if (addWillChange) {
|
if (addWillChange && effects) {
|
||||||
wc = [];
|
wc = [];
|
||||||
for (var prop in this._fx) {
|
for (var i = 0; i < effects.length; i++) {
|
||||||
if (this._fx[prop].wc === 'webkitTransform') {
|
var propWC = effects[i].wc;
|
||||||
|
if (propWC === 'webkitTransform') {
|
||||||
wc.push('transform', '-webkit-transform');
|
wc.push('transform', '-webkit-transform');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
wc.push(this._fx[prop].wc);
|
wc.push(propWC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1164,6 +1178,7 @@ export interface PlayOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface EffectProperty {
|
export interface EffectProperty {
|
||||||
|
name: string;
|
||||||
trans: boolean;
|
trans: boolean;
|
||||||
wc?: string;
|
wc?: string;
|
||||||
to?: EffectState;
|
to?: EffectState;
|
||||||
|
@ -51,7 +51,7 @@ ion-menu ion-backdrop {
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
opacity: .1;
|
opacity: .01;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-content {
|
.menu-content {
|
||||||
|
@ -232,7 +232,8 @@ describe('Refresher', () => {
|
|||||||
function touchEv(y: number) {
|
function touchEv(y: number) {
|
||||||
return {
|
return {
|
||||||
type: 'mockTouch',
|
type: 'mockTouch',
|
||||||
touches: [{clientY: y}],
|
pageX: 0,
|
||||||
|
pageY: y,
|
||||||
preventDefault: function(){}
|
preventDefault: function(){}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ export class PanGesture {
|
|||||||
let coord = pointerCoord(ev);
|
let coord = pointerCoord(ev);
|
||||||
if (this.detector.detect(coord)) {
|
if (this.detector.detect(coord)) {
|
||||||
|
|
||||||
if (this.detector.pan() !== 0 && this.canCapture(ev) &&
|
if (this.detector.pan() !== 0 &&
|
||||||
(!this.gestute || this.gestute.capture())) {
|
(!this.gestute || this.gestute.capture())) {
|
||||||
this.onDragStart(ev);
|
this.onDragStart(ev);
|
||||||
this.captured = true;
|
this.captured = true;
|
||||||
@ -156,7 +156,6 @@ export class PanGesture {
|
|||||||
|
|
||||||
// Implemented in a subclass
|
// Implemented in a subclass
|
||||||
canStart(ev: any): boolean { return true; }
|
canStart(ev: any): boolean { return true; }
|
||||||
canCapture(ev: any): boolean { return true; }
|
|
||||||
onDragStart(ev: any) { }
|
onDragStart(ev: any) { }
|
||||||
onDragMove(ev: any) { }
|
onDragMove(ev: any) { }
|
||||||
onDragEnd(ev: any) { }
|
onDragEnd(ev: any) { }
|
||||||
|
@ -195,16 +195,18 @@ export function windowLoad(callback?: Function) {
|
|||||||
export function pointerCoord(ev: any): PointerCoordinates {
|
export function pointerCoord(ev: any): PointerCoordinates {
|
||||||
// get coordinates for either a mouse click
|
// get coordinates for either a mouse click
|
||||||
// or a touch depending on the given event
|
// or a touch depending on the given event
|
||||||
let c = { x: 0, y: 0 };
|
|
||||||
if (ev) {
|
if (ev) {
|
||||||
const touches = ev.touches && ev.touches.length ? ev.touches : [ev];
|
var changedTouches = ev.changedTouches;
|
||||||
const e = (ev.changedTouches && ev.changedTouches[0]) || touches[0];
|
if (changedTouches && changedTouches.length > 0) {
|
||||||
if (e) {
|
var touch = changedTouches[0];
|
||||||
c.x = e.clientX || e.pageX || 0;
|
return { x: touch.clientX, y: touch.clientY };
|
||||||
c.y = e.clientY || e.pageY || 0;
|
}
|
||||||
|
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) {
|
export function hasPointerMoved(threshold: number, startCoord: PointerCoordinates, endCoord: PointerCoordinates) {
|
||||||
|
Reference in New Issue
Block a user