Skip to content

Commit cc3a890

Browse files
authored
feat: implement missing documented features (adaptivePerformance & multiTouch) (#4)
- Implement dynamic FPS scaling for adaptivePerformance in src/index.js - Implement multiTouch configuration handling in src/utils/interactionUtils.js - Fix multiTouch flag so single touch interacts properly and multi-touch works when enabled
1 parent 5cb6fe4 commit cc3a890

File tree

2 files changed

+44
-15
lines changed

2 files changed

+44
-15
lines changed

src/index.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ const AnimatedBackground = React.memo(({
239239
useEffect(() => {
240240
const animation = setupCanvas();
241241
let lastTime = 0;
242-
const frameInterval = 1000 / fps;
242+
let lastEvalTime = 0;
243+
let currentFps = fps;
243244

244245
const loop = (currentTime) => {
245246
// Check animation controls
@@ -250,6 +251,28 @@ const AnimatedBackground = React.memo(({
250251

251252
animationRef.current = requestAnimationFrame(loop);
252253

254+
// Adaptive performance adjustments
255+
if (adaptivePerformance && performanceMonitor) {
256+
const { avgFps, performanceLevel } = performanceMonitor;
257+
258+
// Only evaluate adaptive adjustments once per second to prevent rapid toggling
259+
// and console spamming
260+
if (currentTime - lastEvalTime > 1000) {
261+
lastEvalTime = currentTime;
262+
if (performanceLevel === 'poor' && avgFps > 0 && avgFps < 25) {
263+
if (currentFps > 15) {
264+
// Automatically reduce fps to improve rendering stability
265+
currentFps = Math.max(15, currentFps - 5);
266+
console.warn(`Poor performance detected. Automatically reduced target FPS to ${currentFps}.`);
267+
}
268+
} else if (performanceLevel === 'excellent' && avgFps > 55 && currentFps < fps) {
269+
// Gradually restore fps if performance is excellent
270+
currentFps = Math.min(fps, currentFps + 1);
271+
}
272+
}
273+
}
274+
275+
const frameInterval = 1000 / currentFps;
253276
const deltaTime = currentTime - lastTime;
254277
const speedMultiplier = animationControls ? animationControls.speed : 1;
255278
const adjustedFrameInterval = frameInterval / speedMultiplier;
@@ -263,15 +286,6 @@ const AnimatedBackground = React.memo(({
263286
}
264287

265288
animation();
266-
267-
// Adaptive performance adjustments
268-
if (adaptivePerformance && performanceMonitor) {
269-
const { avgFps, performanceLevel } = performanceMonitor;
270-
if (performanceLevel === 'poor' && avgFps < 20) {
271-
// Automatically reduce complexity or fps
272-
console.warn('Poor performance detected. Consider reducing animation complexity.');
273-
}
274-
}
275289
}
276290
};
277291

@@ -282,7 +296,7 @@ const AnimatedBackground = React.memo(({
282296
cancelAnimationFrame(animationRef.current);
283297
}
284298
};
285-
}, [setupCanvas, fps, animationControls]); // Removed changing dependencies
299+
}, [setupCanvas, fps, animationControls, adaptivePerformance]); // Added adaptivePerformance as dependency
286300

287301
// Resize handling effect - separate from animation
288302
useEffect(() => {

src/utils/interactionUtils.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export const createInteractionHandler = (canvas, config = {}) => {
3030
effect = 'attract',
3131
strength = 0.5,
3232
radius = 100,
33-
continuous = false
33+
continuous = false,
34+
multiTouch = false
3435
} = config;
3536

3637
let isInteracting = false;
@@ -151,7 +152,9 @@ export const createInteractionHandler = (canvas, config = {}) => {
151152

152153
const handleTouchStart = (event) => {
153154
event.preventDefault();
154-
Array.from(event.touches).forEach((touch, index) => {
155+
const touches = multiTouch ? Array.from(event.touches) : [event.touches[0]];
156+
touches.forEach((touch) => {
157+
if (!touch) return;
155158
const point = {
156159
x: (touch.clientX - canvas.getBoundingClientRect().left) * (canvas.width / canvas.getBoundingClientRect().width),
157160
y: (touch.clientY - canvas.getBoundingClientRect().top) * (canvas.height / canvas.getBoundingClientRect().height),
@@ -165,7 +168,9 @@ export const createInteractionHandler = (canvas, config = {}) => {
165168

166169
const handleTouchMove = (event) => {
167170
event.preventDefault();
168-
Array.from(event.touches).forEach((touch) => {
171+
const touches = multiTouch ? Array.from(event.touches) : [event.touches[0]];
172+
touches.forEach((touch) => {
173+
if (!touch) return;
169174
const point = {
170175
x: (touch.clientX - canvas.getBoundingClientRect().left) * (canvas.width / canvas.getBoundingClientRect().width),
171176
y: (touch.clientY - canvas.getBoundingClientRect().top) * (canvas.height / canvas.getBoundingClientRect().height),
@@ -179,9 +184,19 @@ export const createInteractionHandler = (canvas, config = {}) => {
179184

180185
const handleTouchEnd = (event) => {
181186
event.preventDefault();
182-
Array.from(event.changedTouches).forEach((touch) => {
187+
const changedTouches = Array.from(event.changedTouches);
188+
changedTouches.forEach((touch) => {
183189
touchPoints.delete(touch.identifier);
184190
});
191+
192+
// In single-touch mode, if the primary touch is lifted but other fingers
193+
// are still on the screen, we need to ensure the interaction points are cleared
194+
// to prevent the effect from getting stuck, but only if there are no actual touches left
195+
// from the event.touches.
196+
if (!multiTouch && event.touches.length === 0) {
197+
touchPoints.clear();
198+
}
199+
185200
interactionPoints = Array.from(touchPoints.values());
186201
};
187202

0 commit comments

Comments
 (0)