capture the mouse click event on a particular object within the renderer

I have set up a canvas renderer with two mesh (cubes) and I am trying to

capture the click event on each cube
in order to execute the appropriate method for it.

Currently, I am able to capture the click event on the entire renderer, so when I click on cube1 or cube2, the click is treated as one event because it is bound to the renderer :)

My question is, how can I bind the click event separately to each cube?

Here is the relevant code snippet:

//dom
var containerPopUp=document.getElementById('popup');
//renderer
var rendererPopUp = new THREE.CanvasRenderer();
rendererPopUp.setSize(420,200);

containerPopUp.appendChild(rendererPopUp.domElement);
//Scene
var scenePopUp = new THREE.Scene();
//Camera
var cameraPopUp = new THREE.PerspectiveCamera(50,60/60,1,1000);

cameraPopUp.position.z = 220;
cameraPopUp.position.y = 20;
//
scenePopUp.add(cameraPopUp);

//Add texture for the cube
//Use image as texture
var img2D = new THREE.MeshBasicMaterial({ //CHANGED to MeshBasicMaterial
map:THREE.ImageUtils.loadTexture('img/2d.png') 
});
img2D.map.needsUpdate = true; //ADDED
//Add Cube
var cubeFor2D = new THREE.Mesh(new THREE.CubeGeometry(40,80,40),img2D);
cubeFor2D.position.x =- 60;
cubeFor2D.position.y = 20;

scenePopUp.add(cubeFor2D);
//
var img3D = new THREE.MeshBasicMaterial({ //CHANGED to MeshBasicMaterial
map:THREE.ImageUtils.loadTexture('img/3d.png') 
});
img3D.map.needsUpdate = true;
var cubeFor3D = new THREE.Mesh(new THREE.CubeGeometry(40,80,40),img3D);
cubeFor3D.position.x = 60;
cubeFor3D.position.y=20;

scenePopUp.add(cubeFor3D);
//
rendererPopUp.render(scenePopUp,cameraPopUp);
//
animate();

rendererPopUp.domElement.addEventListener('click',testCall,false);//Here the click event is bound on the whole renderer, means what ever object in the renderer is clicked, the testCall method is called.

In the code above, cubeFor2D and cubeFor3D are contained within the renderer. I need to bind the click event individually to each mesh. I attempted to achieve this using threex.domevent.js:

var meshes  = {};
        meshes['mesh1'] = cubeFor2D;
        meshes['mesh1'].on('mouseover', function(event){

              //response to click...
              console.log('you have clicked on cube 2D');

        });

However, this approach did not work, as I received an error in the console:

TypeError: meshes.mesh1.on is not a function

I made sure to include the API source code file:

<script src="threex.domevent.js"></script>

Answer №1

To create a callback, start by defining a function for each object like so:

mesh.callback = function() { alert( this.name ); }

Next, implement the standard picking pattern as shown below:

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

function onDocumentMouseDown( event ) {

    event.preventDefault();

    mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;

    raycaster.setFromCamera( mouse, camera );

    var intersects = raycaster.intersectObjects( objects ); 

    if ( intersects.length > 0 ) {
        intersects[0].object.callback();
    }

}

Update: now compatible with three.js version r.70

Answer №2

  1. Implement a click event listener

    window.addEventListener('click', onDocumentMouseDown, false);
    
  2. Define the function onDocumentMouseDown, taking into account that raycaster is crucial for identifying the clicked object correctly!

    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();
    function onDocumentMouseDown( event ) {
    event.preventDefault();
    mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
    raycaster.setFromCamera( mouse, camera );
    console.log(scene.children);
    var intersects = raycaster.intersectObjects( scene.children );
    console.log(intersects[1]);
    if ( intersects.length > 0 ) {
        intersects[1].object.callback();
    }}
    
  3. Create the Mesh object

    var mesh_menu_title = new THREE.Mesh(geometry_menu, materials_menu);
    mesh_menu_title.name = 'select_lang';
    mesh_menu_title.callback = function() { select_language();}
    scene.add(mesh_menu_title);
    
  4. Establish the callback function

    function select_language(){
    var selectedObject = scene.getObjectByName("select_lang"); 
    scene.remove( selectedObject );
    var selectedObject = scene.getObjectByName("start");
    scene.remove( selectedObject );
    var selectedObject = scene.getObjectByName("menu");
    scene.remove( selectedObject );
    }
    

This code snippet enables the handling of specific objects clicked within the canvas, triggering a designated function called "mesh.callback". It also facilitates the removal of certain elements from the scene.

It's important to note that using intersects[0].object.callback(); won't work as intended, since at index 0 the stored objects are vertices.

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 to deactivate an option in md-autocomplete

I encountered a scenario where I converted an md-input-container with a md-select/md-option to a md-autocomplete. While in the initial setup of md-select/md-option, we were able to apply ng-disabled property to both the md-select and md-option. However, wh ...

"Learn the trick to effectively binding the mousewheel event in Blazor for seamless functionality on the Firefox

We are looking to implement code for a mouse wheel event on a div container. The code below functions correctly in browsers Edge and Chrome: <div id="scroll-container" @onmousewheel="MouseWheelEventHandler"> [...] </div> ...

org.openqa.selenium.WebDriverException: unexpected issue: Chrome failed to initiate: crashed.(chrome inaccessible)

Having issues running Java script (selenium framework) on Chrome. Tried various solutions but still facing problems: Unchecked run as admin Added arguments Snippet of the code: ChromeOptions options = new ChromeOptions(); //options.setExperimentalOption ...

"Uh-oh! Encountered a new unexpected runtime error. Can't seem

While working on my portfolio in Next.js, I encountered an issue. I added a header to display on all pages by placing it in _app.js without making any changes to _document.js. Here is the error message: Unhandled Runtime Error Error: No router instance fo ...

Error message: The login buttons from Meteor's accounts-ui-bootstrap-3 are not showing up on the webpage

Following the installation of bootstrap-3 and accounts-ui-bootstrap-3, the expected ui-accounts login widget was not displayed when using {{ loginButtons }}. Instead, a <div> appeared in place of the widget, with no actual widget visible. Are there ...

Guidance on retrieving a boolean value from an asynchronous callback function

I'm looking to determine whether a user is part of a specific group, but I want the boolean value returned in the calling function. I've gone through and debugged the code provided below and everything seems to be working fine. However, since my ...

What is the best way to keep a checkbox unchecked after clicking cancel?

I'm working on a bootbox script that triggers a customized alert. I need the checkbox that triggers the alert to be unchecked when the user clicks cancel. Here is the checkbox when it's checked <div class="checkbox"> <label> ...

Supervising the organization of HTML sections for an offline web application

Currently, I am developing an offline HTML5 application that involves a significant amount of DOM manipulation through the creation of HTML strings within JavaScript functions. For example: var html=''; html+='<div class="main">&apos ...

Utilizing shared enums in Angular services

My services contain an enum that I need to share with another service's method. How can I pass this enum as a parameter effectively? home.factory('myService', ['$dialogs', '$resource', function ($dialogs, $resource) { ...

Is Nextjs prone to creating identical pages during the build process?

I have a question that I couldn't find the answer to anywhere, so I hope someone here can help me. I have a blog and I want to use SSG for the homepage and ISR for individual posts. If I set up my homepage using SSG to display 10 posts like this: ind ...

Obtain Relative URL with the help of Selenium using the PhantomJS driver

Utilizing Selenium along with the Phantom JS driver, I am attempting to load an HTML page and extract all of the HREF links from it. The issue arises when PhantomJS provides absolute URLs after resolving them entirely. My specific requirement is to extrac ...

Tips on modifying the maxlength attributes for all "field answer" class elements

Looking for some help with adjusting the "maxlength" attribute in a class called "field answer." The current maxlength is set to 250, but I need it changed to 9999. Can someone guide me through this process? <div class="field answer"> &l ...

Finding the initial visible iFrame in a browser window and displaying its content

It's quite a strange situation... This issue only pertains to IE8 and older versions. So, there's this iFrame that's popping up (and I have no way to control or assign an ID to it), thank you Telerik! // The only way to target it would be: ...

What limitations prevent me from using "await .getAttribute()" in Protractor, despite the fact that it does return a promise?

I have been working on transitioning my Protractor tests from using the selenium control flow to async/await. However, I am facing an issue where it is not allowing me to use await for the .getAttribute() function. Each time I try, I receive the error mess ...

Ajax displays JSON data within an array format

Looking for a solution where I have MySQL data displayed in a table, with each row having a button. When the button is clicked, a bootstrap modal should appear containing that data. I have converted the MySQL data to JSON format and assigned the ".view_dat ...

Tips for creating mocks/stubs for vue-i18n?

I have recently made the switch from Jest to Vitest as my unit testing library for my Vue 3 application. Currently, I am facing an issue while trying to write a unit test for a component that utilizes the vue-i18n library for text translation. When attemp ...

What could be the reason behind the app.get middleware not functioning properly following the app.use middleware in ExpressJS?

My server.js file includes the following code. However, I've encountered an issue where the code in app.get() function works fine when the app.use() middleware is commented out. But, when both are included, the get request doesn't seem to run. An ...

Obtain the HTML source code for a webpage that has been scrolled down using Python web scraping with Selenium

Even after executing a script to scroll down, I am only able to retrieve the initial html code containing 11 hotels. How can I access the entire data source code by scrolling down to scrape all the available hotels? If the driver.execute_script is suppose ...

Issue with React ChartJS rendering – Title not visibleWhen using React Chart

I'm currently using react chart js for displaying a doughnut in my component. "chart.js": "^3.7.1", "react-chartjs-2": "^4.1.0", However, I'm facing an issue where the title is not being displayed: const d ...

Error encountered during Ajax request - two files being transmitted instead of one

Can someone assist me with a basic ajax call for a login button? I need help with the form submission and sending the request to a php file to handle the login action. However, I am encountering an issue where two files are being sent instead of one when ...