Stop rendering the scene in Three.js when it is no longer visible or outside of the viewport

I am currently developing a website that heavily relies on JavaScript and animations. The first section features a fullscreen three.js scene that reacts to mouse movement. While the scene itself functions properly, I have noticed that everything is continuously rendered even when the user is not actively viewing the three.js webgl canvas. This has led to performance issues, especially when other animations are occurring further down the webpage.

To address this problem, I need to find a way to completely pause rendering of the scene when it is not within the viewport, which should significantly improve performance.

Below is the render function being used:

const render = () => {
    requestAnimationFrame(render);

    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (mouseY * -1 - camera.position.y) * 0.05;
    camera.lookAt(scene.position);

    const t = Date.now() * 0.001;
    const rx = Math.sin(t * 0.6) * 0.5;
    const ry = Math.sin(t * 0.3) * 0.5;
    const rz = Math.sin(t * 0.2) * 0.5;
    group.rotation.x = rx;
    group.rotation.y = ry;
    group.rotation.z = rz;
    textMesh.rotation.x = rx;
    textMesh.rotation.y = ry;
    textMesh.rotation.z = rx; // :) 

    renderer.render(scene, camera);
};
render();

Here is my attempt to add functionality for pausing rendering (taken from another source but encountering difficulties in implementation):

var stopRendering = (af) => {
    cancelAnimationFrame(af);
    isRendering = false;
};

window.addEventListener('scroll', () => {
    let scrollPosition = document.body.scrollTop;

    if (scrollPosition >= ("#canvas-wrapper")-50) {
        if (everythingIsLoaded && !isRendering) {
            render();
            console.log('render has been started');
        } else {
            // Wait until everythingIsLoaded becomes true
        }
    } else {
        if (render) {
            stopRendering(render);
            console.log('render has been halted');
        }
    }
});

Link to full CodePen demo

It's worth mentioning that I am utilizing the locomotive scroll library for scroll and viewport visibility detection. This may impact the behavior of basic scrolling events.

The primary objective behind implementing rendering pauses is to significantly enhance overall performance.

Working solution can be found here for reference.

Answer №1

Utilizing the IntersectionObserver allows you to receive an event when an element enters or exits the screen view.

const statusElem = document.querySelector('.status');

const onScreen = new Set();
const intersectionObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      onScreen.add(entry.target);
    } else {
      onScreen.delete(entry.target);
    }
  });
  statusElem.textContent = onScreen.size
    ? `on screen: ${[...onScreen].map(e => e.textContent).join(', ')}`
    : 'none';
});

document.querySelectorAll('.test').forEach(elem => {
  intersectionObserver.observe(elem);
});
body {
  font-size: xx-large;
}
.test {
  padding: 3em;
  background: orange;
}
.status {
  position: fixed;
  background: rgba(0,0,0,0.8);
  color: white;
  padding: 1em;
  font-size: medium;
  top: 0;
  left: 0;
}
<div class="test">a</div>
<p>Lorem ipsum dolor sit amet, quaestio principes ea eos. Feugait ocurreret mea ea. Wisi altera intellegebat vix an, sed iuvaret tincidunt adipiscing ea, at debet iudico labores eum. Mucius adversarium vix no, nec amet contentiones ea. Sea noluisse mandamus referrentur cu. Facilisis similique quo eu, pri alii noluisse efficiantur in.
</p>
<div class="test">b</div>
<p>
Sea cu vidit neglegentur, te pro maluisset accusamus, ad est diceret iudicabit. Honestatis referrentur no vim, per no putant prompta antiopam. Est singulis vituperata no, adhuc nonumy consectetuer quo cu, quas primis at mel. No doming fabulas admodum est. Cu usu ornatus principes constituam, sint petentium at quo.
</p>
<div class="test">c</div>
<div class="status"></div>

This information can then be used to control the rendering of those elements dynamically

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I wonder where the file from the HTML form download has originated

Recently, I've been experimenting with the developer tools in Chrome to observe the behavior of websites at different moments. It has proven useful in automating certain tasks that I regularly perform. Currently, my focus is on automating the process ...

Is it possible in Typescript to assign a type to a variable using a constant declaration?

My desired outcome (This does not conform to TS rules) : const type1 = "number"; let myVariable1 : typeof<type1> = 12; let type2 = "string" as const; let myVariable2 : typeof<type2> = "foo"; Is it possible to impl ...

Capture the height values from various divs and store them in an array, then utilize these values to adjust the size of other

My goal is to achieve the following: (1) Collect heights from multiple divs and store them in an array. (2) Apply these heights to other elements. The first element should receive the first value, the second element should receive the second value of the ...

Using an ng-repeat directive alongside an if condition in Angular

My website contains a vast array of 30 articles, previously represented by around 300 lines of HTML code, but now condensed to just 10 lines with angularjs. However, certain articles hold special significance and require specific display criteria. Check ou ...

Getting the alt value and text of an <img> tag and placing it into a textarea

I have a textarea that contains the following content: <textarea id="testContent"> <img src="..." alt="value"> My text.... </textarea> I am aware that I can use javascript to specifically target and retrieve the alt value of the img ele ...

Why does the array format of the values saved in app.locals seem to disappear when they are accessed in the view?

I have created a date values array and stored it in an app.locals variable using the code snippet below: prepDataList.forEach(function(item){ var str = item.createdAtDate.toDateString(); //str = str.substring(4, 10); labelsArray.push(str); counts ...

3D textile simulation powered by three.js

My current project involves using three.js to develop a cloth simulator similar to the one on the Hermes website. The main difference is that I want to implement top-down waves instead of horizontal waves like the ones on the Hermes site. I have successfu ...

Verifying internet connectivity and updating content using jQuery and JavaScript

Upon loading the page, the following functionality occurs without triggering a click event: The updated code attempts to determine if the internet connection is active. If the connection is off, the 'link' on the page will be disabled (non-click ...

What steps should I take to incorporate column sorting capabilities into my table?

After spending several hours attempting to implement sorting functionality on a react-virtualized table without success, I'm reaching out for some assistance. Here is the example and source code. Unfortunately, I couldn't create a plnkr, so here& ...

Ways to avoid submitting based on the outcome of AJAX requests

When working on an ASP.NET MVC Project, I encountered an issue where I wanted to prevent a button from submitting if the result returned from an AJAX call was false. However, no matter what I tried, the button always triggered the submission. Below is th ...

Attempting to access a variable without wrapping it in a setTimeout function will

I have a form without any input and my goal is to automatically set the "responsible clerk" field to the currently logged-in user when the component mounts. Here's what I have: <b-form-select v-model="form.responsible_clerk" :op ...

Choose the div element by its id with vanilla JavaScript instead of using the jQuery $ selector in order to utilize the RaphaelJS

Currently, I am utilizing the RaphaelJs' mousedown() method. However, I am encountering a problem as I wish to apply mousedown() on a div that is selected using the $(id) selector of JQuery. In this case, I prefer to use vanilla Js for performance rea ...

Using a Dynamic Function to Replace the jQuery Global Object Variable

In a global object, there are settings that need to be updated based on user input. For instance, if "no" is selected for div 1, not only will div-one be hidden, but the variable's value will also change to 0. The problem lies in the dynamic function ...

Searching for the location of a specific item within an array using

Trying to grasp the fundamental components of Javascript has led me to stumble upon a specific line of code: if (varX.indexOf(String(varY),0) < 0) In this scenario, varX represents an array of Strings and varY is one of the strings contained within th ...

Issue with making requests across origins in Vuejs using axios

Currently, I am utilizing Vuejs and axios for handling web requests. So far, I have successfully managed to perform GET, POST, and PUT operations. However, the new challenge that I am facing is uploading media to the server. The server necessitates sending ...

Zone.js error: Promise rejection caught

When I call a function from an external library on page load in my Angular application, Chrome dev tools console shows the error message: "Unhandled Promise rejection: Cannot read properties of undefined (reading 'page') ' Zone: <root> ...

Tips for transferring values from two separate select tags for processing via Ajax and jQuery

HTML Code: <select id="sel"> <option value="dog">dog</option> <option value="cat">cat</option> </select> <select id="sel2"> <option value="chocolate">chocolate</option> <option valu ...

Randomized Image Generator Array with Descriptive Captions

I am currently designing a unique image generator with additional fields or captions that will be displayed on the page. To achieve this, I believe the best approach is to create an array of objects. However, my knowledge of objects and classes is a bit ou ...

Keep an eye on the syncing progress of pouchdb replication

What is the best way to alert the user if there is a loss of Internet connection or if the server goes offline, causing live sync to stop? var localdb = new PouchDB('localdb'); var remotedb = new PouchDB('http://localhost:5984/xyz&a ...

Transforming the timezone of a date from the Backend to the timezone selected by the user in the User

I have an API that provides dates in the format: 12/23/2023 at 03:31 a.m. CST My goal is to convert this to a date with the user-selected timezone in the following format: 12/23/2023 at 7:31 p.m. The timezone part is not required for display in the UI. c ...