Zoom in and out on a WebGL canvas created using Three.js using the mouse scroll wheel

Currently delving into the world of WebGL (Three.js) to explore the possibilities of rendering 3D scenes within an Angular app. One challenge I'm facing is finding a way to make the mousewheel events zoom in and out of the canvas specifically, rather than the entire window. I've tried disabling the mousewheel and mousedown event listeners but they are still picking up the events. How can I achieve the desired zoom functionality for the canvas only?

You can find my code here: https://stackblitz.com/edit/angular-ivy-hwzz3r.

  animate() {
    // We have to run this outside angular zones,
    // because it could trigger heavy changeDetection cycles.
    this.ngZone.runOutsideAngular(() => {
      if (document.readyState !== 'loading') {
        this.render();
      } else {
        window.addEventListener('DOMContentLoaded', () => {
          this.render();
        });
      }
      window.addEventListener('resize', () => {
        this.resize();
      });
      window.addEventListener('mousewheel', (event) => {
        event.preventDefault();
      }, false);
      window.addEventListener('mousedown', (event) => {
        event.preventDefault();
      }, false);
    });
  }

Answer №1

Initially, it's important to note that the mousewheel event is considered nonstandard and deprecated. It is recommended to use the wheel event instead.

When using the addEventListener method, you can include an optional second argument in the form of an object with a passive key. The purpose of the passive option is:

A Boolean value, where if set to true, signifies that the listener function specified will not invoke preventDefault(). If a passive listener does call preventDefault(), a console warning will be generated by the user agent.

It's worth noting from this information found at Improving scrolling performance with passive listeners:

As per specifications, the default value for the passive option is always set to false. However, this default setting may lead to certain touch events (and others) causing browser thread blocking during scroll handling, resulting in significant performance issues.

To address this concern, some browsers like Chrome and Firefox have changed the default value of the passive option to true for specific events such as touchstart and touchmove on document-level nodes like Window, Document, and Document.body. This adjustment prevents event listeners from obstructing page rendering while users scroll.

Even though the text focuses on events other than wheel/mousewheel, the same applies to those events as well. For confirmation, refer to the Browser compatibility table.

In summary, to utilize preventDefault for wheel events in certain browsers, ensure to include { passive: false } when using addEventListener:

window.addEventListener('wheel', (event) => {
  event.preventDefault();
}, { passive: false });

For zoom functionality, utilize PerspectiveCamera.zoom and WheelEvent.deltaY as shown below:

window.addEventListener('wheel', (event) => {
  event.preventDefault(); // prevent scrolling
  
  let zoom = this.camera.zoom; // current zoom value
  zoom += event.deltaY * -0.01; // adjust zoom value
  zoom = Math.min(Math.max(.125, zoom), 4); // clamp the value

  this.camera.zoom = zoom; // assign new zoom value
  this.camera.updateProjectionMatrix(); // apply changes
}, { passive: false });

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

Tips for handling delayed HTTP API responses in Angular

While working on my project, I encountered a delay in response when using the this.ServiceHandler.getTxnInfo([], params) API. To handle this, I implemented the use of setTimeout along with async/await. Despite these modifications, my promise ended up being ...

I'm having trouble understanding how to use JQuery's .live and .remove methods together

Check out this working jsfiddle, except for the function I'm troubleshooting. I am working on code that appends a table to a form when the value changes in the quantity field. I have two goals: Allow only one extra line at a time. Remove the extra ...

Error: Unable to access the 'push' property of an undefined value

42 | <Router> 43 | <ul> > 44 | {this.state.movies.map(movie => <li onClick={() => this.handleMovieClick(movie.title)}>{movie.title}{movie.description} <button type="button" onClick={() => this.deleteMovie(movie.title)}& ...

I'm having trouble with accessing an object by index in a knockout observablearray. It seems like the binding process is encountering difficulties

I'm completely new to stackoverflow and knockout, and I have a query. I want to access a JSON object by index. It works fine when I insert dummy data in my code, but it throws an error when I try to add data from JSON. Error Uncaught TypeError: Unab ...

Guide to redirecting data from an external POST request to a customer through a GET request

Within my Express application, I am currently dealing with both incoming POST requests containing a payload from an external source and GET requests sent by my client: router.post('/liveReleaseStore', (req, res) => { let data = req.body.m ...

Tips for Implementing Input Validation in Your Code

I have been attempting to design a multi-form and have been struggling to add input validation. Specifically, I want to prevent the form from progressing to the next step if certain fields (such as name) are left empty. However, despite multiple attempts, ...

Identifying Elements Generated on-the-fly in JavaScript

Currently, I am tackling the challenge of creating a box that can expand and collapse using regular JavaScript (without relying on jQuery). My main roadblock lies in figuring out how to effectively detect dynamically added elements or classes to elements a ...

What is the correct syntax for utilizing a variable in inline styles within ReactJS, specifically when working with the --i:0

            The question has been raised previously, but unfortunately, it was left unanswered in this thread. The variables play a crucial role in this piece of code as they are intended to be utilized in various CSS functions for animating them wi ...

Exploring the Magic of ES6 Object Destructuring

Learning about ES6 destructuring is still new to me. I have encountered a scenario where I need to extract specific values from a nested object within an object. For instance - z = {g: 1, h: 2, i: {d1:5, d2:6, d3:7}} When attempting to destructure with ...

Is it possible to store Socket.IO responses in a cache for quicker retrieval?

Consider this scenario where I have a websocket implementation shown below: let itemsArray = []; function fetchData() { itemsArray = await db.query(`SELECT * FROM Items`); } function emitData() { io.sockets.in("room_foo").emit("data", JSON.stringify ...

Navigation issue discovered while trying to implement Ionic's collection-repeat feature

As a newcomer to Ionic and Angular.js, I recently downloaded an example of an ionic collection repeat and navigation from http://codepen.io/ionic/pen/mypxez. Initially, the example worked perfectly with just single index.html and index.js files. However, I ...

Seeking assistance with incorporating dds textures into three.js

After successfully loading the model in Blender with all the textures applied, I encountered a challenge when exporting it to obj + mtl. The exported textures were saved as .dds files and now I am unsure how to properly apply them in threejs. https://i.s ...

Error: Unhandled Exception - Invalid syntax, unrecognized value: #

Encountering an error in jQuery with a .click() event, as seen in Firebug. Using the latest version 1.3.2 (min), the click triggers an $.ajax() request for a form on my website. Researching online, found information on "%" or "[@]" as unrecognized expressi ...

Unable to provide any input while utilizing npm prompts

After installing npm prompts, I encountered a strange issue. When trying to run the example code for npm prompts, I found that I couldn't enter any input at all. The underscore in the input field would blink for a few seconds, then the cursor would ju ...

Access the child component within an @ChildComponent directive in Angular

Is it possible to retrieve child components of another component? For instance, consider the following QueryList: @ContentChildren(SysColumn) syscolumns: QueryList<SysColumn>; This QueryList will contain all instances of the SysColumns class, which ...

Unable to connect to server using local IP address

Currently utilizing a freezer application () and encountering an issue where I can only access the server on localhost. I attempted to modify the settings.js file by replacing 127.0.0.1 with 0.0.0.0, rebuilt it, but it still persists on localhost. Even aft ...

Passing both the object and its attributes simultaneously for reflect-metadata in TypeScript is a feature that closely resembles functionality found

Instead of using DataAnnotation in C# to add meta attributes on properties, I am seeking a similar functionality in TypeScript for a ldap model class. The goal is to have decorators that can set the LDAP attribute used in the LDAP directory internally. ex ...

What is the best way to create interactive canvases that respond to multiple clicks using JavaScript?

Within the canvas, the code snippet below aims to generate a grid of 10x10 colored boxes with alternating reddish and bluish shades on a gray background. The intention is for each canvas to only respond to mouse interactions when the mouse is within its bo ...

React component is unable to identify prop

I'm attempting to send an array of objects from the main App.js file to a smaller component using props. However, for some reason, the prop is not being recognized within the smaller component file. https://i.stack.imgur.com/WuyFr.png https://i.stac ...

Tips for replacing an element in DOM with an updated HTML string

My current task involves updating a stringify HTML element using an element from the DOM. This stringify HTML element is stored in an array within the localStorage. First, I convert it into manipulatable HTML like this: let toBeUpdated = document.createEl ...