Skip to content
Permalink
Browse files

perf(menu): flickering

  • Loading branch information...
manucorporat committed Aug 2, 2018
1 parent 69f5cc8 commit 8253b046042de7a0d3783f7207c526688b80e2f3
@@ -339,10 +339,8 @@ export class Animator {
* Play the animation.
*/
play(opts?: PlayOptions) {
const self = this;

// If the animation was already invalidated (it did finish), do nothing
if (self._destroyed) {
if (this._destroyed) {
return;
}

@@ -352,22 +350,22 @@ export class Animator {
// if there is a duration, then it'll stage all animations at the
// FROM property and transition duration, wait a few frames, then
// kick off the animation by setting the TO property for each animation
self._isAsync = self._hasDuration(opts);
this._isAsync = this._hasDuration(opts);

// ensure all past transition end events have been cleared
self._clearAsync();
this._clearAsync();

// recursively kicks off the correct progress step for each child animation
// ******** DOM WRITE ****************
self._playInit(opts);
this._playInit(opts);

// doubling up RAFs since this animation was probably triggered
// from an input event, and just having one RAF would have this code
// run within the same frame as the triggering input event, and the
// input event probably already did way too much work for one frame
raf(() => {
raf(() => {
self._playDomInspect(opts);
this._playDomInspect(opts);
});
});
}
@@ -430,30 +428,29 @@ export class Animator {
* ROOT ANIMATION
*/
_playDomInspect(opts: PlayOptions | undefined) {
const self = this;
// fire off all the "before" function that have DOM READS in them
// elements will be in the DOM, however visibily hidden
// so we can read their dimensions if need be
// ******** DOM READ ****************
// ******** DOM WRITE ****************
self._beforeAnimation();
this._beforeAnimation();

// for the root animation only
// set the async TRANSITION END event
// and run onFinishes when the transition ends
const dur = self.getDuration(opts);
if (self._isAsync) {
self._asyncEnd(dur, true);
const dur = this.getDuration(opts);
if (this._isAsync) {
this._asyncEnd(dur, true);
}

// ******** DOM WRITE ****************
self._playProgress(opts);
this._playProgress(opts);

if (self._isAsync && !this._destroyed) {
if (this._isAsync && !this._destroyed) {
// this animation has a duration so we need another RAF
// for the CSS TRANSITION properties to kick in
raf(() => {
self._playToStep(1);
this._playToStep(1);
});
}
}
@@ -721,7 +718,7 @@ export class Animator {
} else {
for (j = 0; j < elements.length; j++) {
// ******** DOM WRITE ****************
(elements[j].style as any)[prop] = val;
elements[j].style.setProperty(prop, val);
}
}
}
@@ -759,7 +756,6 @@ export class Animator {
for (const { style } of elements) {
if (dur > 0) {
// ******** DOM WRITE ****************
style.transform = '';
style.transitionDuration = durString;

// each animation can have a different easing
@@ -768,7 +764,7 @@ export class Animator {
style.transitionTimingFunction = easing;
}
} else {
style.transform = 'none';
style.transitionDuration = '0';
}
}
}
@@ -68,10 +68,7 @@ ion-backdrop {
touch-action: manipulation;
}

.menu-content-open ion-pane,
.menu-content-open .ion-pane,
.menu-content-open ion-content,
.menu-content-open .toolbar {
.menu-content-open {
// the containing element itself should be clickable but
// everything inside of it should not clickable when menu is open
pointer-events: none;
@@ -1,52 +1,8 @@
import { QueueApi } from '@stencil/core';

import { PanRecognizer } from './recognizers';

import { gestureController } from './gesture-controller';
import { PointerEvents } from './pointer-events';

export interface GestureDetail {
type: string;
startX: number;
startY: number;
startTimeStamp: number;
currentX: number;
currentY: number;
velocityX: number;
velocityY: number;
deltaX: number;
deltaY: number;
timeStamp: number;
event: UIEvent;
data?: any;
}

export type GestureCallback = (detail?: GestureDetail) => boolean | void;

export interface Gesture {
setDisabled(disabled: boolean): void;
destroy(): void;
}

export interface GestureConfig {
el: Node;
disableScroll?: boolean;

queue: QueueApi;
direction?: 'x' | 'y';
gestureName: string;
gesturePriority?: number;
passive?: boolean;
maxAngle?: number;
threshold?: number;

canStart?: GestureCallback;
onWillStart?: (_: GestureDetail) => Promise<void>;
onStart?: GestureCallback;
onMove?: GestureCallback;
onEnd?: GestureCallback;
notCaptured?: GestureCallback;
}
import { createPointerEvents } from './pointer-events';
import { createPanRecognizer } from './recognizers';

export function createGesture(config: GestureConfig): Gesture {
const finalConfig = {
@@ -60,11 +16,6 @@ export function createGesture(config: GestureConfig): Gesture {
...config
};

let hasCapturedPan = false;
let hasStartedPan = false;
let hasFiredStart = true;
let isMoveQueued = false;

const canStart = finalConfig.canStart;
const onWillStart = finalConfig.onWillStart;
const onStart = finalConfig.onStart;
@@ -90,7 +41,7 @@ export function createGesture(config: GestureConfig): Gesture {
data: undefined
};

const pointerEvents = new PointerEvents(
const pointerEvents = createPointerEvents(
finalConfig.el,
pointerDown,
pointerMove,
@@ -100,13 +51,18 @@ export function createGesture(config: GestureConfig): Gesture {
}
);

const pan = new PanRecognizer(finalConfig.direction, finalConfig.threshold, finalConfig.maxAngle);
const pan = createPanRecognizer(finalConfig.direction, finalConfig.threshold, finalConfig.maxAngle);
const gesture = gestureController.createGesture({
name: config.gestureName,
priority: config.gesturePriority,
disableScroll: config.disableScroll
});

let hasCapturedPan = false;
let hasStartedPan = false;
let hasFiredStart = true;
let isMoveQueued = false;

function pointerDown(ev: UIEvent): boolean {
const timeStamp = now(ev);
if (hasStartedPan || !hasFiredStart) {
@@ -146,14 +102,14 @@ export function createGesture(config: GestureConfig): Gesture {
if (hasCapturedPan) {
if (!isMoveQueued && hasFiredStart) {
isMoveQueued = true;
calcGestureData(ev);
calcGestureData(detail, ev);
queue.write(fireOnMove);
}
return;
}

// gesture is currently being detected
calcGestureData(ev);
calcGestureData(detail, ev);
if (pan.detect(detail.currentX, detail.currentY)) {
if (pan.isGesture()) {
if (!tryToCapturePan()) {
@@ -175,28 +131,6 @@ export function createGesture(config: GestureConfig): Gesture {
}
}

function calcGestureData(ev: UIEvent) {
const prevX = detail.currentX;
const prevY = detail.currentY;
const prevT = detail.timeStamp;

updateDetail(ev, detail);

const currentX = detail.currentX;
const currentY = detail.currentY;
const timestamp = detail.timeStamp = now(ev);
const timeDelta = timestamp - prevT;
if (timeDelta > 0 && timeDelta < 100) {
const velocityX = (currentX - prevX) / timeDelta;
const velocityY = (currentY - prevY) / timeDelta;
detail.velocityX = velocityX * 0.7 + detail.velocityX * 0.3;
detail.velocityY = velocityY * 0.7 + detail.velocityY * 0.3;
}
detail.deltaX = currentX - detail.startX;
detail.deltaY = currentY - detail.startY;
detail.event = ev;
}

function tryToCapturePan(): boolean {
if (gesture && !gesture.capture()) {
return false;
@@ -256,7 +190,7 @@ export function createGesture(config: GestureConfig): Gesture {
if (!tmpHasFiredStart) {
return;
}
calcGestureData(ev);
calcGestureData(detail, ev);

// Try to capture press
if (tmpHasCaptured) {
@@ -274,7 +208,7 @@ export function createGesture(config: GestureConfig): Gesture {

return {
setDisabled(disabled: boolean) {
pointerEvents.disabled = disabled;
pointerEvents.setDisabled(disabled);
},
destroy() {
gesture.destroy();
@@ -283,6 +217,28 @@ export function createGesture(config: GestureConfig): Gesture {
};
}

function calcGestureData(detail: GestureDetail, ev: UIEvent) {
const prevX = detail.currentX;
const prevY = detail.currentY;
const prevT = detail.timeStamp;

updateDetail(ev, detail);

const currentX = detail.currentX;
const currentY = detail.currentY;
const timestamp = detail.timeStamp = now(ev);
const timeDelta = timestamp - prevT;
if (timeDelta > 0 && timeDelta < 100) {
const velocityX = (currentX - prevX) / timeDelta;
const velocityY = (currentY - prevY) / timeDelta;
detail.velocityX = velocityX * 0.7 + detail.velocityX * 0.3;
detail.velocityY = velocityY * 0.7 + detail.velocityY * 0.3;
}
detail.deltaX = currentX - detail.startX;
detail.deltaY = currentY - detail.startY;
detail.event = ev;
}

function updateDetail(ev: any, detail: GestureDetail) {
// get X coordinates for either a mouse click
// or a touch depending on the given event
@@ -306,3 +262,46 @@ function updateDetail(ev: any, detail: GestureDetail) {
function now(ev: UIEvent) {
return ev.timeStamp || Date.now();
}

export interface GestureDetail {
type: string;
startX: number;
startY: number;
startTimeStamp: number;
currentX: number;
currentY: number;
velocityX: number;
velocityY: number;
deltaX: number;
deltaY: number;
timeStamp: number;
event: UIEvent;
data?: any;
}

export type GestureCallback = (detail?: GestureDetail) => boolean | void;

export interface Gesture {
setDisabled(disabled: boolean): void;
destroy(): void;
}

export interface GestureConfig {
el: Node;
disableScroll?: boolean;

queue: QueueApi;
direction?: 'x' | 'y';
gestureName: string;
gesturePriority?: number;
passive?: boolean;
maxAngle?: number;
threshold?: number;

canStart?: GestureCallback;
onWillStart?: (_: GestureDetail) => Promise<void>;
onStart?: GestureCallback;
onMove?: GestureCallback;
onEnd?: GestureCallback;
notCaptured?: GestureCallback;
}

0 comments on commit 8253b04

Please sign in to comment.
You can’t perform that action at this time.