Skip to content

Commit 202a96c

Browse files
committed
improvement: Improve useRafFn logic and fix errors
1 parent a165acc commit 202a96c

File tree

2 files changed

+42
-31
lines changed

2 files changed

+42
-31
lines changed

src/components/useRafFn/stories/UseRafFnDemo.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<br />
3434
<br />
3535
<br />
36-
<input type="number" v-model="fpsRef" />
36+
<input type="number" min="1" max="121" v-model="fpsRef" />
3737
</td>
3838
</tr>
3939
</tbody>
@@ -50,7 +50,7 @@ export default Vue.extend({
5050
setup() {
5151
const animDuration = ref(0)
5252
const callbackCounter = ref(0)
53-
const fpsRef = ref(4)
53+
const fpsRef = ref(120)
5454
const animHandler = (t: number) => {
5555
callbackCounter.value = callbackCounter.value + 1
5656
animDuration.value = Math.ceil(t)

src/components/useRafFn/useRafFn.ts

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,62 @@
1-
import { ref, isRef, watch, onMounted, onUnmounted, Ref } from '../../api'
1+
import { ref, isRef, computed, onMounted, onUnmounted, Ref } from '../../api'
22

33
type TFps = number | Ref<number>
44

5-
const getFps = (fps: TFps) => (isRef(fps) ? fps.value : fps)
5+
const getFps = (fps: TFps) => Number(isRef(fps) ? fps.value : fps)
66
const calcFpsInterval = (fps: number) => 1000 / fps
7+
const fpsLimit = 120
78

89
export function useRafFn(
910
callback: Function,
10-
fps: TFps = 60,
11+
// Note: a value greater than 120 will disable the fps check logic
12+
// giving maximum precision and smoothness
13+
fps: TFps = fpsLimit + 1,
1114
runOnMount = true
1215
) {
1316
const isRunningRef = ref(false)
14-
const fpsIntervalRef = ref(calcFpsInterval(getFps(fps)))
17+
// Using a computed here allows us to update fps
18+
// dynamically from user's input
19+
const fpsIntervalRef = computed(() => calcFpsInterval(getFps(fps)))
20+
21+
let isPausedGuard = false
1522
let startTime = 0
1623
let timeNow = 0
17-
let isPaused = false
18-
let prevTime = 0
19-
let timeLast = 0
20-
function loop(timeStamp: number) {
24+
let timeWhenPaused = 0
25+
let timeDelta = 0
26+
const loop = (timeStamp: number) => {
2127
if (!startTime) startTime = timeStamp
2228
if (!isRunningRef.value) return
2329

24-
if (!isPaused) {
25-
timeNow = timeStamp - startTime - prevTime
26-
} else {
27-
prevTime = timeStamp - startTime - timeNow
28-
timeNow = timeStamp - startTime - prevTime
29-
isPaused = false
30+
if (isPausedGuard) {
31+
// Save the time when we pause the loop so that later we can
32+
// adjust the time we return to the callback
33+
timeWhenPaused = timeStamp - startTime - timeNow
34+
isPausedGuard = false
3035
}
3136

32-
// Run callback only on the given fps
33-
if (Math.ceil(timeNow - timeLast) > fpsIntervalRef.value) {
37+
// Adjust timeNow to account for startTime and timeWhenPaused
38+
timeNow = timeStamp - startTime - timeWhenPaused
39+
40+
// Always run the callback if fps is greater than fpsLimit
41+
const callbackShouldAlwaysRun = getFps(fps) > fpsLimit
42+
if (callbackShouldAlwaysRun) {
43+
// Store timeDelta for future computations
44+
timeDelta = timeNow
3445
callback(timeNow)
35-
timeLast = timeNow
3646
}
3747

48+
// Run callback only when !callbackShouldAlwaysRun
49+
// and the given fps matches the lapsed time
50+
if (!callbackShouldAlwaysRun) {
51+
const elapsedTime = Math.ceil(timeNow - timeDelta)
52+
if (elapsedTime > fpsIntervalRef.value) {
53+
// Store timeDelta for future computations
54+
timeDelta = timeNow
55+
callback(timeNow)
56+
}
57+
}
58+
59+
// Run loop again recursively
3860
requestAnimationFrame(loop)
3961
}
4062

@@ -45,19 +67,8 @@ export function useRafFn(
4567

4668
const stop = () => {
4769
isRunningRef.value = false
48-
isPaused = true
49-
}
50-
51-
// Watch fps value since it could potentially be a ref and we may want
52-
// to change the Raf speed from user's input
53-
const updateFpsInterval = () => {
54-
// If fps is not a ref there is no point in updating it
55-
if (!isRef(fps)) return
56-
watch(fps, () => {
57-
fpsIntervalRef.value = calcFpsInterval(getFps(fps))
58-
})
70+
isPausedGuard = true
5971
}
60-
updateFpsInterval()
6172

6273
onMounted(() => runOnMount && start())
6374
onUnmounted(stop)

0 commit comments

Comments
 (0)