fix: pause animation loop while not rendering

This commit is contained in:
2026-01-21 20:42:56 +01:00
parent 5d0d285971
commit 2d660e05a0

View File

@@ -192,6 +192,7 @@ let mesh = null;
let directionalLight = null;
let ambientLight = null;
let animationId = null;
let animationPaused = false;
// Geometry cache for height exaggeration
let geometryCache = null;
@@ -233,8 +234,19 @@ const initThreeJS = () => {
updateLightPosition();
// Animation loop
// Don't start animation loop yet - will be controlled by pause/resume
};
// Animation loop control
const startAnimation = () => {
if (animationId) return; // Already running
const animate = () => {
if (animationPaused) {
animationId = null;
return;
}
animationId = requestAnimationFrame(animate);
if (renderer && scene && camera) {
renderer.render(scene, camera);
@@ -243,6 +255,26 @@ const initThreeJS = () => {
animate();
};
const pauseAnimation = () => {
animationPaused = true;
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
};
const resumeAnimation = () => {
animationPaused = false;
startAnimation();
};
// Render a single frame (for when animation is paused but we need to update the view)
const renderSingleFrame = () => {
if (renderer && scene && camera) {
renderer.render(scene, camera);
}
};
// Handle canvas resize
const handleResize = () => {
if (!canvasRef.value || !renderer || !camera) return;
@@ -422,11 +454,13 @@ const updateHeightScale = () => {
geometryCache.geometry.attributes.position.needsUpdate = true;
geometryCache.geometry.computeVertexNormals();
renderSingleFrame(); // Render once to show the change
};
// Update scene (for real-time preview)
const updateScene = () => {
updateLightPosition();
renderSingleFrame(); // Render once to show the change
};
// Color conversion utilities
@@ -438,6 +472,7 @@ const updateColor = (e) => {
settings.terrainColor = parseInt(e.target.value.replace('#', ''), 16);
if (mesh && mesh.material) {
mesh.material.color.setHex(settings.terrainColor);
renderSingleFrame(); // Render once to show the change
}
};
@@ -634,9 +669,7 @@ const downloadLastRender = () => {
// Cleanup
const cleanup = () => {
if (animationId) {
cancelAnimationFrame(animationId);
}
pauseAnimation();
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
@@ -663,6 +696,11 @@ onMounted(() => {
});
resizeObserver.observe(canvasRef.value);
}
// Only start animation if visible and not offscreen
if (!props.offscreen) {
resumeAnimation();
}
});
}
});
@@ -680,7 +718,29 @@ watch(() => props.visible, (newVal) => {
});
resizeObserver.observe(canvasRef.value);
}
// Start animation when visible and not offscreen
if (!props.offscreen) {
resumeAnimation();
}
});
} else if (newVal && !props.offscreen) {
// Component already initialized, just resume animation
resumeAnimation();
} else if (!newVal) {
// Hidden - pause animation
pauseAnimation();
}
});
// Watch for offscreen changes
watch(() => props.offscreen, (newVal) => {
if (newVal) {
// Offscreen mode - pause animation (we only render single frames on demand)
pauseAnimation();
} else if (props.visible) {
// Not offscreen and visible - resume animation
resumeAnimation();
}
});
@@ -721,8 +781,7 @@ defineExpose({
}
.modal-container.offscreen {
left: -10000px;
top: -10000px;
display: none;
}
.modal-header {