UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

169 lines (163 loc) 5.07 kB
'use strict'; import React, { useEffect, useRef } from 'react'; import { TextInput, StyleSheet, View } from 'react-native'; import { useSharedValue, useAnimatedProps, useFrameCallback } from '../hook'; import { createAnimatedComponent } from '../../createAnimatedComponent'; import { addWhitelistedNativeProps } from '../../ConfigHelper'; function createCircularDoublesBuffer(size) { 'worklet'; return { next: 0, buffer: new Float32Array(size), size, count: 0, push(value) { const oldValue = this.buffer[this.next]; const oldCount = this.count; this.buffer[this.next] = value; this.next = (this.next + 1) % this.size; this.count = Math.min(this.size, this.count + 1); return oldCount === this.size ? oldValue : null; }, front() { const notEmpty = this.count > 0; if (notEmpty) { const current = this.next - 1; const index = current < 0 ? this.size - 1 : current; return this.buffer[index]; } return null; }, back() { const notEmpty = this.count > 0; return notEmpty ? this.buffer[this.next] : null; } }; } const DEFAULT_BUFFER_SIZE = 60; addWhitelistedNativeProps({ text: true }); const AnimatedTextInput = createAnimatedComponent(TextInput); function loopAnimationFrame(fn) { let lastTime = 0; function loop() { requestAnimationFrame(time => { if (lastTime > 0) { fn(lastTime, time); } lastTime = time; requestAnimationFrame(loop); }); } loop(); } function getFps(renderTimeInMs) { 'worklet'; return 1000 / renderTimeInMs; } function getTimeDelta(timestamp, previousTimestamp) { 'worklet'; return previousTimestamp !== null ? timestamp - previousTimestamp : 0; } function completeBufferRoutine(buffer, timestamp, previousTimestamp, totalRenderTime) { 'worklet'; timestamp = Math.round(timestamp); previousTimestamp = Math.round(previousTimestamp) ?? timestamp; const droppedTimestamp = buffer.push(timestamp); const nextToDrop = buffer.back(); const delta = getTimeDelta(timestamp, previousTimestamp); const droppedDelta = getTimeDelta(nextToDrop, droppedTimestamp); totalRenderTime.value += delta - droppedDelta; return getFps(totalRenderTime.value / buffer.count); } function JsPerformance() { const jsFps = useSharedValue(null); const totalRenderTime = useSharedValue(0); const circularBuffer = useRef(createCircularDoublesBuffer(DEFAULT_BUFFER_SIZE)); useEffect(() => { loopAnimationFrame((_, timestamp) => { timestamp = Math.round(timestamp); const previousTimestamp = circularBuffer.current.front() ?? timestamp; const currentFps = completeBufferRoutine(circularBuffer.current, timestamp, previousTimestamp, totalRenderTime); // JS fps have to be measured every 2nd frame, // thus 2x multiplication has to occur here jsFps.value = (currentFps * 2).toFixed(0); }); }, []); const animatedProps = useAnimatedProps(() => { const text = 'JS: ' + jsFps.value ?? 'N/A'; return { text, defaultValue: text }; }); return /*#__PURE__*/React.createElement(View, { style: styles.container }, /*#__PURE__*/React.createElement(AnimatedTextInput, { style: styles.text, animatedProps: animatedProps, editable: false })); } function UiPerformance() { const uiFps = useSharedValue(null); const totalRenderTime = useSharedValue(0); const circularBuffer = useSharedValue(null); useFrameCallback(({ timestamp }) => { if (circularBuffer.value === null) { circularBuffer.value = createCircularDoublesBuffer(DEFAULT_BUFFER_SIZE); } timestamp = Math.round(timestamp); const previousTimestamp = circularBuffer.value.front() ?? timestamp; const currentFps = completeBufferRoutine(circularBuffer.value, timestamp, previousTimestamp, totalRenderTime); uiFps.value = currentFps.toFixed(0); }); const animatedProps = useAnimatedProps(() => { const text = 'UI: ' + uiFps.value ?? 'N/A'; return { text, defaultValue: text }; }); return /*#__PURE__*/React.createElement(View, { style: styles.container }, /*#__PURE__*/React.createElement(AnimatedTextInput, { style: styles.text, animatedProps: animatedProps, editable: false })); } export function PerformanceMonitor() { return /*#__PURE__*/React.createElement(View, { style: styles.monitor }, /*#__PURE__*/React.createElement(JsPerformance, null), /*#__PURE__*/React.createElement(UiPerformance, null)); } const styles = StyleSheet.create({ monitor: { flexDirection: 'row', position: 'absolute', backgroundColor: '#0006', zIndex: 1000 }, header: { fontSize: 14, color: '#ffff', paddingHorizontal: 5 }, text: { fontSize: 13, color: '#ffff', fontFamily: 'monospace', paddingHorizontal: 3 }, container: { alignItems: 'center', justifyContent: 'center', flexDirection: 'row', flexWrap: 'wrap' } }); //# sourceMappingURL=PerformanceMonitor.js.map