THREE.Raycaster delivering imprecise outcomes

I am currently working on creating a 2D scatterplot with tooltips, but I am facing an issue with the raycaster not detecting when a point is being hovered over. The tooltip seems to activate only when touching an object, which is correct behavior, but it displays random data from points that are not even close on the x/y plane. Additionally, the information displayed changes even when there are no other points close to the one being hovered over. Can someone assist me in debugging this behavior? Below is some relevant code snippet (for the full code, please refer to the link provided):

...loading data points (stored in data_points array), setting up scene, etc.

raycaster = new THREE.Raycaster();
raycaster.params.Mesh.threshold = 20;

view.on("mousemove", () => {
    let [mouseX, mouseY] = d3.mouse(view.node());
    let mouse_position = [mouseX, mouseY];
    checkIntersects(mouse_position);
});
function mouseToThree(mouseX, mouseY) {
    return new THREE.Vector3(
        mouseX / viz_width * 2 - 1,
        -(mouseY / height) * 2 + 1,
        1
    );
}
function checkIntersects(mouse_position) {
    let mouse_vector = mouseToThree(...mouse_position);
    raycaster.setFromCamera(mouse_vector, camera);
    let intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects[0]) {
        let sorted_intersects = sortIntersectsByDistanceToRay(intersects);
        let intersect = sorted_intersects[0];
        let index = intersect.faceIndex;
        let datum = data_points[index];
        showTooltip(mouse_position, datum);
    } else {
        hideTooltip();
    }
}
function sortIntersectsByDistanceToRay(intersects) {
    return _.sortBy(intersects, "distanceToRay");
}

...functions for tooltips, details

I would greatly appreciate any assistance in resolving this issue. Thank you!

Answer №1

Have you thought about why d3.mouse(view.node()); is being used to retrieve the mouse position? It seems like it might be producing erratic results for you. For instance, when I move the cursor just a little bit, I'm seeing an X range that goes from 2200 to -97, which doesn't seem right.

My suggestion would be to capture the exact XY screen position during the mousemove event using the standard JavaScript method of event.clientX and event.clientY

Take a look at this example, which I found in a Three.js Raycasting demo: Three.js Raycasting example

function onMouseMove( event ) {
    mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
    raycaster.setFromCamera( mouse, camera );
}

Furthermore, I recommend eliminating any document margins using CSS to ensure your measurements are accurate down to the pixel.

Answer №2

Discovered the solution to my issue. The problem stemmed from the absence of a proper "index" variable for my data points (THREE.Group containing [THREE.Mesh, THREE.LineLoop]), causing raycasting to work but not point selection (avoid using faceIndex). To resolve this, I implemented one within the userData field of the mesh.

// Generating circle geometries
for (let i=0; i<data_points.length; i++) {
    // Circle
    let geometry = new THREE.CircleBufferGeometry(data_points[i].radius, 32);
    let material = new THREE.MeshBasicMaterial( {color: color_array[data_points[i].label] } );
    let mesh = new THREE.Mesh(geometry, material);
    mesh.userData.id = i;

    ...lineLoop and Group code
}

...additional code

function onMouseMove(event) {
    mouseRay.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
    mouseRay.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
    mouseRay.z = 1;
    let mouseCoords = [event.clientX, event.clientY];
    raycaster.setFromCamera(mouseRay, camera);
    let intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects[0]) {
        let sorted_intersects = sortIntersectsByDistanceToRay(intersects);
        console.log(sorted_intersects);
        let closestIntersect = sorted_intersects[0];
        // Key modification made here!!!
        let index = closestIntersect.object.userData.id;
        let selectedDatum = data_points[index];
        highlightPoint(selectedDatum);
        showTooltip(mouseCoords, selectedDatum);
    } else {
        removeHighlights();
        hideTooltip();
    }
}

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

Troubleshooting Angular MIME problems with Microsoft Edge

I'm encountering a problem with Angular where after running ng serve and deploying on localhost, the page loads without any issues. However, when I use ng build and deploy remotely, I encounter a MIME error. Failed to load module script: Expected a ...

Automating the process of posting a file to a form with javascript

I have a piece of client-side JavaScript that creates a jpeg file through HTML5 canvas manipulation when the user clicks an "OK" button. My goal is to automatically insert this jpeg output into the "Upload Front Side" field in a form, simulating a user up ...

Issue with fullPage.js - Unable to scroll to footer on the last section of the page

I'm currently working with the fullPage.js plugin () and encountering some issues. While sliding through each section, everything functions as expected. However, when I reach the last section and try to scroll down to the footer below it, I encounter ...

Exploring the Difference Between Dot and Bracket Notation in Internet Explorer

I'm encountering a strange problem in IE8 when attempting to retrieve an element using the following code: window.frames.frames[0].name; // obtain the name of the inner iFrame object No complicated logic, but when the script runs, IE7-8 interprets i ...

Exploring the functionality of test code within an rxjs subscription by utilizing the powerful technique of jasmine

My goal is to test the code within an observable subscription: function bar(someStream$: Observable<number>) { someStream$.pipe( map((x) => x + 3), ).subscribe((result) => { SomeService.someMethod(result) }) } I want to ensure t ...

creating an audio streaming application using child processes in nodejs

How can I effectively send a stream to a child process for streaming audio from a client to a server? I have successfully obtained the audio stream from a client. const ss = require('socket.io-stream'); const socketIo = require('socket.io& ...

Issues with retrieving data from Firestore and storing it into an array in a React

Struggling to fetch data from my firestore and display it on the webpage. Despite trying all possible solutions and searching extensively, I am unable to get it working. When using the code below, nothing appears on the website. However, if I switch to th ...

When refreshed, CSS and JavaScript were not loaded

As a newcomer to AngularJs, I am facing an issue that has left me puzzled. I am attempting to create a single-page application using AngularJS + ExpressJS. Everything is functioning properly, but I am encountering a problem upon page refresh. For example, ...

When attempting to retrieve information using the findById(''), the process became frozen

When attempting to retrieve data using findById(), I'm encountering a problem. If I provide a correct ObjectID, the data is returned successfully. However, if I use an invalid ObjectID or an empty string, it gets stuck. If findById() is called with a ...

The content section sits discreetly behind the sidebar

Upon loading my Bootstrap 5 webpage, the toggle button successfully moves the navbar and body section to show or hide the full sidebar. However, an issue arises where the body section goes behind the sidebar when using the toggle button. Below is a portio ...

NextJS allows for custom styling of Tiktok embeds to create a unique and

Currently, I am in the process of constructing a website that integrates Tiktok oEmbed functionality. Thus far, everything is running smoothly, but I have encountered an issue - how can I customize the styling to make the body background transparent? I ha ...

Unable to send data using GET method after implementing passportjs integration

In the route.js file, I have implemented the following REST method: app.get('/api/todos', isAuthenticated, function(req, res) { DB.TodoTable.find() .exec(function(err, todos) { res.json(todos, function(err){ if (err) ...

Calculating faceVertexUvs for custom Geometry in three.js to enhance texture mapping

Check out this example I have here: https://jsfiddle.net/NiklasKnaack/L1cqbdr9/82/ function generatePlanetSurface( radiusX, radiusY, radiusZ, localUp, resolution ) { const surface = {}; surface.geometry = new THREE.Geometry(); surface.geometry.fa ...

Show users who liked a post from 2 different collections in Meteor

How do I retrieve a list of users who have "liked" this post from a collection and display it in a template? Collections: likes: { "_id": 1234, "userId": "1dsaf8sd2", "postId": "123445" }, { "_id": 1235, "userId": "23f4g4e4", "pos ...

Transform large integer values into an array consisting of individual digits

I'm attempting to store the individual digits of a large integer in an array by converting it to a string first and then using the 'split()' method. However, it seems that in JavaScript, this method only works for integers up to 15 digits. F ...

How to retrieve data from a JavaScript array in a separate JavaScript file

In my checklistRequest.js file, I populate an array and then try to access it in my Termine_1s.html file, which includes JavaScript code. Although I can access the array, when I attempt to iterate through it, only single digits are returned instead of stri ...

Three.js window resizing issues affecting scaling accuracy

Despite following the documentation, the shape does not scale properly when resizing the window.https://i.sstatic.net/OTZ6h.png The code used should work fine according to what is specified in the documentation. var camera, controls, scene, renderer, view ...

JavaScript still mentions a class that no longer exists

One of my elements has a class of .collapsed. When this element is clicked, a jQuery function is triggered to remove the .collapsed class and add the .expanded class instead. Even after the .collapsed class is removed, the function I have created continue ...

If someone installs our chat widget on their website using an <iframe> script, I would like the widget to be deactivated when our website is experiencing downtime

We utilize an iframe to create our Chat Widget. One issue we face is that when our main website is down, it causes errors on client websites where the widget is embedded. I am looking for a way to automatically disable the "Chat widget" when our website ...

Storing formatted user input in an array with VueJS: A step-by-step guide

Looking for assistance that relates to the following question Vue.js: Input formatting using computed property is not applying when typing quick I am facing a challenge in extracting formatted values from text inputs and storing them in an array. I intend ...