mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 04:18:52 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			96 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { queueMacrotask } from '../utils/macrotask-scheduler';
 | 
						|
import { FPSCallback } from '../fps-meter/fps-native';
 | 
						|
import { getTimeInFrameBase } from './animation-native';
 | 
						|
import { Trace } from '../trace';
 | 
						|
 | 
						|
export interface FrameRequestCallback {
 | 
						|
	(time: number): void;
 | 
						|
}
 | 
						|
 | 
						|
type AnimationFrameCallbacks = { [key: string]: FrameRequestCallback };
 | 
						|
 | 
						|
let animationId = 0;
 | 
						|
let currentFrameAnimationCallbacks: AnimationFrameCallbacks = {}; // requests that were scheduled in this frame and must be called ASAP
 | 
						|
let currentFrameScheduled = false;
 | 
						|
let nextFrameAnimationCallbacks: AnimationFrameCallbacks = {}; // requests there were scheduled in another request and must be called in the next frame
 | 
						|
let shouldStop = true;
 | 
						|
let inAnimationFrame = false;
 | 
						|
let fpsCallback: FPSCallback;
 | 
						|
let lastFrameTime = 0;
 | 
						|
 | 
						|
function getNewId() {
 | 
						|
	return animationId++;
 | 
						|
}
 | 
						|
 | 
						|
function ensureNative() {
 | 
						|
	if (fpsCallback) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	fpsCallback = new FPSCallback(doFrame);
 | 
						|
}
 | 
						|
 | 
						|
function callAnimationCallbacks(thisFrameCbs: AnimationFrameCallbacks, frameTime: number): void {
 | 
						|
	inAnimationFrame = true;
 | 
						|
	for (const animationId in thisFrameCbs) {
 | 
						|
		if (thisFrameCbs[animationId]) {
 | 
						|
			try {
 | 
						|
				thisFrameCbs[animationId](frameTime);
 | 
						|
			} catch (err) {
 | 
						|
				const msg = err ? err.stack || err : err;
 | 
						|
				Trace.write(`Error in requestAnimationFrame: ${msg}`, Trace.categories.Error, Trace.messageType.error);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	inAnimationFrame = false;
 | 
						|
}
 | 
						|
 | 
						|
function doCurrentFrame() {
 | 
						|
	// if we're not getting accurate frame times
 | 
						|
	// set last frame time as the current time
 | 
						|
	if (!fpsCallback || !fpsCallback.running) {
 | 
						|
		lastFrameTime = getTimeInFrameBase();
 | 
						|
	}
 | 
						|
	currentFrameScheduled = false;
 | 
						|
	const thisFrameCbs = currentFrameAnimationCallbacks;
 | 
						|
	currentFrameAnimationCallbacks = {};
 | 
						|
	callAnimationCallbacks(thisFrameCbs, lastFrameTime);
 | 
						|
}
 | 
						|
 | 
						|
function doFrame(currentTimeMillis: number) {
 | 
						|
	lastFrameTime = currentTimeMillis;
 | 
						|
	shouldStop = true;
 | 
						|
	const thisFrameCbs = nextFrameAnimationCallbacks;
 | 
						|
	nextFrameAnimationCallbacks = {};
 | 
						|
	callAnimationCallbacks(thisFrameCbs, lastFrameTime);
 | 
						|
	if (shouldStop) {
 | 
						|
		fpsCallback.stop(); // TODO: check performance without stopping to allow consistent frame times
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function ensureCurrentFrameScheduled() {
 | 
						|
	if (!currentFrameScheduled) {
 | 
						|
		currentFrameScheduled = true;
 | 
						|
		queueMacrotask(doCurrentFrame);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
export function requestAnimationFrame(cb: FrameRequestCallback): number {
 | 
						|
	const animId = getNewId();
 | 
						|
	if (!inAnimationFrame) {
 | 
						|
		ensureCurrentFrameScheduled();
 | 
						|
		currentFrameAnimationCallbacks[animId] = zonedCallback(cb) as FrameRequestCallback;
 | 
						|
		return animId;
 | 
						|
	}
 | 
						|
	ensureNative();
 | 
						|
	nextFrameAnimationCallbacks[animId] = zonedCallback(cb) as FrameRequestCallback;
 | 
						|
	shouldStop = false;
 | 
						|
	fpsCallback.start();
 | 
						|
 | 
						|
	return animId;
 | 
						|
}
 | 
						|
 | 
						|
export function cancelAnimationFrame(id: number): void {
 | 
						|
	delete currentFrameAnimationCallbacks[id];
 | 
						|
	delete nextFrameAnimationCallbacks[id];
 | 
						|
}
 |