Utilizing Three.js with interactive functionalities and advanced transformation controls

I'm facing an issue with my project where I am using three.interaction to capture click events on certain objects and add transformControls to them.

The problem I'm encountering is that the transform controls seem to block the click event on other objects, possibly due to interfering with the raycast.

Any suggestions for solutions?


        var camera, scene, renderer;
        var geometry, material, mesh;

        var transformControls;

        init();
        animate();

        function init() {

            camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
            camera.position.z = 1;

            scene = new THREE.Scene();

            geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
            material = new THREE.MeshNormalMaterial();

            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            const interaction = new THREE.Interaction(renderer, scene, camera);

            mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);

            mesh.on('click', function(ev) {
                click(ev);
            });

            mesh1 = new THREE.Mesh(geometry, material);
            scene.add(mesh1);
            mesh1.position.set(0.3, 0, 0);

            mesh1.on('click', function(ev) {
                click(ev);
            });

        }

        function animate() {

            requestAnimationFrame(animate);

            renderer.render(scene, camera);

        }

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

        function click(ev) {

            console.log("click");

            var transformControls = scene.getObjectByName("transformControls", true);
            var objControlled = scene.getObjectByName("objControlled", true);

            if (transformControls === undefined || transformControls === null) {
                transformControls = new THREE.TransformControls(camera, renderer.domElement);
                transformControls.addEventListener('change', render);
                transformControls.name = "transformControls";
                scene.add(transformControls);
            }

            if (objControlled === undefined || objControlled === null) {

                try {
                    transformControls.attach(ev.data.target);
                    ev.data.target.name = "objControlled";
                } catch (err) {
                    console.log(err);
                }

            } else {

                try {
                    transformControls.detach(objControlled);
                    objControlled.name = "oldControlled";
                    transformControls.attach(ev.data.target);
                    ev.data.target.name = "objControlled";
                } catch (err) {
                    console.log(err);
                }
            }
        }
    

JS Fiddle Link: https://jsfiddle.net/h80g42wk/4/

Answer №1

Obtaining the desired behavior does not necessarily require the THREE.Interaction extension.

You can easily achieve the result by binding event listeners to the canvas and handling raycasting yourself, which may actually be simpler than using the aforementioned extension.

This approach grants you control over specifying the objects for which your raycast should check intersections.


To narrow down the objects that are subject to raycasting, add them to a group instance.

mesh = new THREE.Mesh( geometry, material );
mesh1 = new THREE.Mesh( geometry, material );

group = new THREE.Group();
group.add( mesh, mesh1 );
scene.add( group );

Simply attach a mousedown event to your canvas element and within the function callback, perform raycasting against the group and apply controls to the object if it is not already associated with them.

// initialization
renderer.domElement.addEventListener( 'mousedown', clickEvent );

// inside mousedown callback
var intersects = raycaster.intersectObject( group, true );

if ( intersects.length > 0 ) {
    let object = intersects[0].object;

    if ( control.object === undefined || control.object !== object ) {
        control.attach( object );
        render();
    }
}

JSFiddle Example

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

Separate .env configurations tailored for development and production environments

Managing different content in my .env files is crucial as I work with both next.js and node.js. The settings vary between development and deployment environments. During development: DOMAIN_URL=https://localhost:3000 GOOGLE_CLIENT_ID='abc' For ...

What is the proper way to define the scope for invoking the Google People API using JavaScript?

I am attempting to display a list of directory people from my Google account. export class People { private auth: Auth.OAuth2Client; private initialized: boolean = false; private accessToken: string; constructor(private readonly clientEmail: strin ...

Using AngularJS client and Flask server for a RESTful call, one can include the

I am currently facing an issue where I need to send a REST request from my AngularJs client to a Flask server. The problem arises when one of the ids (key) in the request contains a forward slash. Interestingly, if the key does not contain a slash, the re ...

Creating a custom pipe that converts seconds to hours and minutes retrieved from an API can be achieved by implementing a transformation function

Can someone please provide guidance on creating a custom pipe in Angular 8 that converts seconds to hours and minutes? Thank you. <div class="col-2" *ngFor="let movie of moviesList"> <div class="movie"> {{ movie.attributes.title }} ...

Guide to creating individual column templates in Kendo-UI grid

I recently started using Kendo-UI in my project and wanted to have a column in my grid display an image button along with a field, similar to the 'Contact Name' column in the documentation here. After exploring the documentation, I came across th ...

Is it possible to continuously update a Google line chart by programmatically adding rows at specific intervals using an AJAX call

Is there a way to dynamically add rows to the Google line chart each time data is retrieved via an AJAX call at set intervals? This is the existing code: google.charts.load('current', {'packages':['line']}); google.charts. ...

Using Jquery Mobile to make an AJAX POST request with XML

Is it possible to use this code for XML parsing? I have successfully parsed using JSON, but there is no response from the web service. This is the status of the webservice: http/1.1 405 method not allowed 113ms $j.ajax({ type: "GET", async: false, ...

Unsuccessful CORS on whateverorigin.org with YQL

Despite trying all three methods, I keep getting an error regarding cross domain access denied. Previously, I had successfully used YQL in different parts of my applications, but now it seems to have stopped working as well. JSFIDDLE <script> $(fun ...

Struggling to pass express.js router requests and responses to a class method

I am struggling with setting up an Express JS router. I am facing difficulty passing req and res to my class method. Not Working app.get('/', controller.index) Working app.get('/', (res,req) => controller.index(req,res) The routi ...

Developing a Library for Managing APIs in TypeScript

I'm currently struggling to figure out how to code this API wrapper library. I want to create a wrapper API library for a client that allows them to easily instantiate the lib with a basePath and access namespaced objects/classes with methods that cal ...

Executing a method in an applet using JavaScript

I am trying to print some information using an applet. The applet is located in the signed qds-client.jar file and has the following code: public class PrintText extends Applet implements Printable { private ClientAccount clientAccount; public Client ...

Executing two Ajax calls sequentially without using asynchronous functionality

Creating a dynamic menu using two REST APIs to establish a parent/child relationship. The ID of the parent from the first API response is passed to the child API to fetch child records. Encountering issues where setting async false for the child API call ...

Adding Node Modules during the setup of an ElectronJS application

Hey there! I'm currently working on an ElectronJS application designed for developers. One of the key features is checking for the presence of NodeJS on the user's computer. If it's not detected, the app will automatically download and insta ...

Leveraging the Google Geocode API through HTTP GET requests

I am facing a challenge in my HTML file where I have a map and I am using HTTP get with jQuery to retrieve a device's location. However, I am struggling to plot this location on the map. I need to parse the location information and display it accurate ...

Tips for retrieving specific data from a variable in an object using PHP

I am facing a challenge in accessing the value of an object with an array in PHP Laravel. Currently, I have successfully accessed the information using the following method. However, the issue arises when the position of the required information changes, f ...

Leveraging TipTap.dev for building a joint editing platform -

I have integrated the collaboration feature from tiptap.dev into my NextJS application. Initially, I used their CLI command for the Hocuspocus server which worked well on port 1234 locally and synchronized text editing across browsers seamlessly. However, ...

Showing a confirmation message to the user upon clicking outside of a specific section

On my webpage, I have a section for creating content, as well as a top bar and sidebar with internal links (both controlled by ng controllers). I am looking to implement a confirmation message that will appear if the user tries to leave the page while in t ...

Incorporating external API information into Google Maps

My current challenge involves creating a polygon on Google Maps using data obtained from an external API found at . Upon analyzing the API response, the following information is provided: { "id": 28, "name": "Local spots", "description": "", "isprivate": ...

What's the best way to refactor the `await nextEvent(element, 'mousemove')` pattern in my code once it is no longer necessary?

Within my React component, the code includes the following: class MyComponent extends React.Component { // ... trackStats = false componentDidMount() { this.monitorActivity() } componentWillUnmount() { this.trackStat ...

"An issue with AngularJS ngTable causing a delay in the rendering of Ajax

Struggling with ngTable Setup Having trouble mastering the use of ngTable by going through the ngTable ajax demo. I attempted to follow along with the example as closely as possible, but I'm encountering a deviation in defining an ngResource inline w ...