Exiting the mouse in three.js

As a newcomer to Three.js, I embarked on an experiment where I created multiple spheres and attempted to give them a "hover" effect. Essentially, when the mouse hovers over a sphere, it enlarges, and when the mouse moves away, it shrinks back to its original size.

This is what I came up with:

// Initializing the Scene, Camera, and Renderer
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor("#F4F4F4");
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Event listeners for window resize
window.addEventListener('resize', () => {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
});

// Orbit Controls setup
controls = new THREE.OrbitControls(camera, renderer.domELement);

// Raycaster for mouse interactions
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

// Creating Multiple Spheres
var geometry = new THREE.SphereGeometry(1, 10, 10);
var material = new THREE.MeshNormalMaterial({ wireframe: true });

var meshX = -10;
for (var i = 0; i < 15; i++) {
    var mesh = new THREE.Mesh(geometry, material);
    mesh.position.x = (Math.random() - 0.5) * 10;
    mesh.position.y = (Math.random() - 0.5) * 10;
    mesh.position.z = (Math.random() - 0.5) * 10;
    scene.add(mesh);
    meshX += 1;
}

// Adding Light source
var light = new THREE.PointLight(0xFFFFFF, 1, 500)
light.position.set(10, 0, 25);
scene.add(light);

// Render function for animation
var render = function() {
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}

// Interaction animations on mouse move and leave
function onMouseMove(event) {
    // Implementation omitted for brevity
}

function onMouseLeave(event) {
    // Implementation omitted for brevity
}

// Event Listeners for mouse movements
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mouseleave', onMouseLeave);
render();

Check out the demo here

I encountered some issues with this approach, particularly around defining the animation for "mouseleave." To work around this, I explored using THREEx.domevents.js, but ran into limitations in applying the hover effect to all spheres rather than just one. Here's a preview of the behavior and code snippet: GIF Preview of THREEx.domevents.js impact

// Further implementation using THREEx.domevents.js for interaction events 
// Detailed explanation included within the provided link

// Any help or guidance on resolving these challenges would be greatly appreciated. Thank you!

Answer №1

Avoid subscribing to the event

window.addEventListener('mouseleave', onMouseLeave);
as it may not trigger when the mouse leaves the object.

Solution #1 – Eliminate

window.addEventListener('mouseleave', onMouseLeave);

Solution #2 – Assess the outcomes of

raycaster.intersectObjects(scene.children, true);
and manage the list of hovered objects manually to track which object was un-hovered with each mouse movement.

You can access the updated fiddle here: https://jsfiddle.net/mmalex/c7t6b1ze/

Corrected code:

var hoveredObjects = {};

function onMouseMove(event) {
    event.preventDefault();

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    raycaster.setFromCamera(mouse, camera);

    var intersects = raycaster.intersectObjects(scene.children, true);

    // create an array of UUIDs for currently hovered objects
    var hoveredObjectUuids = intersects.map(el => el.object.uuid);

    for (let i = 0; i < intersects.length; i++) {
        var hoveredObj = intersects[i].object;
        if (hoveredObjects[hoveredObj.uuid]) {
            continue; // this object was previously hovered
        }

        this.tl = new TimelineMax();
        this.tl.to(intersects[i].object.scale, 1, {
            x: 2,
            ease: Expo.easeOut,
            y: 2,
            ease: Expo.easeOut,
            z: 2,
            ease: Expo.easeOut
        });

        // add newly hovered object to the collection
        hoveredObjects[hoveredObj.uuid] = hoveredObj;
    }

    for (let uuid of Object.keys(hoveredObjects)) {
        let idx = hoveredObjectUuids.indexOf(uuid);
        if (idx === -1) {
            // object with this UUID was unhovered
            let unhoveredObj = hoveredObjects[uuid];
            delete hoveredObjects[uuid];

            this.tl = new TimelineMax();
            this.tl.to(unhoveredObj.scale, 2, {
                x: 1,
                ease: Expo.easeOut,
                y: 1,
                ease: Expo.easeOut,
                z: 1,
                ease: Expo.easeOut
            });

        }
    }
}

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

How can I troubleshoot the unresponsive remove div function on my website?

My code is running fine on CodePen (link provided below), but for some reason, it's not working properly in the web browser. I am executing the code from localhost and the button isn't responding as expected. CODE Here is my Visual Studio code ...

Adjusting the height of the scrollbar in relation to a div using jScrollPane

I am currently working on a resizable div that utilizes custom scrollbars from jScrollPane. My goal is to position the vertical scrollbar above the resize handle. Is there a way to achieve this? I experimented with adjusting the verticalTrackHeight by al ...

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 ...

exploring various dynamic elements using jquery

If you need some help figuring this out, take a look at the JSFiddle here. I've set it up for users to input any data they want in the text box, choose a table from set one, and then click the "submit" button to send it. <div> <Div> < ...

Versel TurboRepo is facing an issue during the installation of the expo router, causing a conflict

Utilizing TurboRepo for building a monorepo and experimenting with the react-native-web example to kickstart a full expo react-native-web implementation. I'm facing difficulties installing expo-router correctly within the native project. Despite thor ...

submit messages that have been sent before in the group chat

Currently, I am employed at a messaging application where I aim to save messages in an object structure like this : { 'room1': ['msg1', 'msg2', ...] 'room2': ['msg3', 'msg4', ...] ... } To ...

Transform an array of objects into a new array using mapping

I am seeking assistance with the code snippet below that I have used in my app component to build dynamic form fields: const [basics, updateBasics] = useState({ controls: { name: { elementType: "input", elementConfig: { ...

Manipulating binary data through the use of encodeURIComponent

Currently, I am reading a binary file by making a jQuery ajax get request. The file (a zip file in this instance) is returned as a string. After performing some actions on the file within the browser without modifying it, I need to send it back to a server ...

What is the process for combining a javascript fetch function with multipart/form-data for a post request to upload a file?

I need assistance with writing a Java program that utilizes Selenium and the executeAsyncScript() function to upload files to a server. When manually uploading a file, the request in Google Chrome DevTools appears as: Google Chrome Request The code snippe ...

Struggling to retrieve data from a MongoDB database in JSON format via an API call? If you're working with JavaScript, Node.js, Express, and MongoDB, we can help you

Below is how I establish the connection to the database: > // Connecting MongoDB using MongoClient > > const MongoClient = require('mongodb').MongoClient > > const url = 'url is used' > > const dbName = 'vir ...

Utilize text alignment effectively by considering language direction - left-to-right for English and right-to-left for Arabic

I am managing a community website and I am looking to customize the text direction based on the language of the posts. For English posts, I want the direction to be LTR with text-align: left) For Arabic posts, I want the direction to be RTL with text-ali ...

The process of defining JSON data from a web API within React using Axios

Seeking assistance with ASP.NET Web API and ReactJS integration using Axios to read JSON data. Below is an example of the JSON data: [ { "id": 1, "name": "Count Duck", "age": 3 }, { "id": 4, "name": "Cou ...

What is the best way to pass card data between Vue.js components?

My application consists of two components: DisplayNotes.vue, which displays data in card format retrieved from the backend, and UpdateNotes.vue, which allows users to update existing data by opening a popup. The issue I'm facing is that when a user cl ...

Instructions for invoking a JavaScript function encapsulated within a jQuery wrapper

I've been delving into a JavaScript file recently and noticed that some of the methods are enclosed within a jQuery function. Could someone kindly guide me on how to call the "testMethod" method? Also, what is the advantage or purpose of wrapping a me ...

What is the process of initializing divs in DataTables?

My application has a DataTable installed, but I encountered an error message stating "DataTables warning: Non-table node initialisation (DIV). For more details about this error, please visit http://datatables.net/tn/2". I'm aware that DataTables is d ...

Sorting data in an Angular JavaScript table by column filters for a combined outcome

I currently have an Angular ngx-datatable that lacks support for filtering by column. My goal is to implement an input filter for each column (which can be strings, multiple choices, etc.) and then merge all these individual filters into a single one. This ...

PHP script to obtain the quantity from a multi-select dropdown list and save it into a database

My text box values are displayed below; unfortunately, I am unable to provide screen shots. I utilized multiple input tag jQuery from the following site: In addition, I explored the second option of this demo. Please visit the link for a demonstration. ...

Exclusively utilize optgroup multiple functionality within bootstrap-select

I'm currently utilizing https://github.com/snapappointments/bootstrap-select/ version 1.13.18 and I am in need of a solution where only optgroup options can have multiple selections. This means that if a non-optgroup option is selected, all other opti ...

Node.js Project Using a Specific URL and Parameter

Two things are on my mind: 1. I'm trying to set up my project's URL as 127.0.0.1:8080/param=id, but I've been unsuccessful so far despite attempting the following: app.get('/param=id', function(req, res) { console.log(req.param ...

Which is more effective for a webpage that solely calculates a formula: user input fields in DIVs or forms?

My idea is to create a webpage with initially 6 input fields, which can expand to 7, 8, 9, or 10 fields when a button is pressed. These fields will have editable preset values that will be used to calculate a final value using a formula. Should I use f ...