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

Execute `preventDefault` prior to authenticating the User with Dev

In my index, I have a modal with a user sign-up form. I created a JavaScript function that triggers when the "Save" button is clicked. If users encounter errors, alerts appear in the modal but it redirects to another page. I want the page to stay on the c ...

Unable to display api results in React using console.log

I'm having an issue with my console log not displaying the API results. Can someone help me figure out what's wrong? I'm new to React, so any guidance would be appreciated. componentDidMount() { this.setState({ loading: true }) cons ...

The type 'function that takes in a CustomEvent and returns void' cannot be assigned to a parameter of type 'EventListenerOrEventListenerObject'

When I upgraded from TypeScript version 2.5.3 to 2.6.1, my custom event setup started giving me an error. window.addEventListener('OnRewards', (e: CustomEvent) => { // my code here }) [ts] Argument of type '(e: CustomEvent) => ...

sending a string of JSON in PHP (including quotes) to an onclick event function

I am faced with the challenge of passing an array of data from PHP to JavaScript for the "onclick" event. The approach I took was to convert the array data into a JSON string which could then be parsed back in the JavaScript function for manipulation. How ...

Ways to display a price near a whole number without using decimal points

Currently, I am working on an ecommerce project where the regular price of an item is $549. With a discount of 12.96% applied, the sale price comes down to $477.8496. However, I want the sale price to be displayed as either $477 or $478 for simplicity. Yo ...

Encountered a TypeScript error: Attempted to access property 'REPOSITORY' of an undefined variable

As I delve into TypeScript, a realm unfamiliar yet not entirely foreign due to my background in OO Design, confusion descends upon me like a veil. Within the confines of file application.ts, a code structure unfolds: class APPLICATION { constructor( ...

What could be the reason for my jQuery call displaying as undefined?

How can I extract a URL from an <a> tag and show the first paragraph of the linked page below the title? At the moment, it just shows 'undefined'. Here's my HTML: <section class="community"> <div class="news"> <ul cla ...

Exploring Angular.js: How to propagate model changes from a child controller within an ng-repeat loop?

I'm facing an issue in my Angular application where changes made to data inside a child controller's form are not being reflected back in the parent array after saving using Restangular. I have tried using debounce to auto-save the data, but it s ...

error : failed to establish a connection to the MongoDB database

Ensure that the first parameter passed to mongoose.connect() or mongoose.createConnection() is a string. MongooseError: The uri parameter for openUri() must be a string, but it was "undefined". Double check that the initial parameter for mongoose.connect() ...

A helpful guide on using workbox to effectively cache all URLs that follow the /page/id pattern, where id is a

Looking at this code snippet from my nodejs server: router.get('/page/:id', async function (req, res, next) { var id = req.params.id; if ( typeof req.params.id === "number"){id = parseInt(id);} res.render('page.ejs' , { vara:a , va ...

Having difficulty retrieving the necessary information for manipulating the DOM using Express, Ajax, and Axios

When working on DOM manipulation based on AJAX calls, I've encountered an issue where the response is being displayed on my page instead of in the console.log output. This makes it difficult for me to view the data and determine what needs to be inser ...

What are the steps to resolve a Fetch request issue with a Node.js server?

I am attempting to make a simple POST request using the fetch method. I am working on building a contact form using Vanilla Javascript, HTML, and CSS on the front end, while utilizing Node.js / Express on the backend. Take a look at my front end code: ...

JavaScript xPath is ineffective at providing a return value

Trying to work through an issue with xPath and I am new to this concept. Any guidance or assistance in JavaScript would be greatly appreciated. Here is the simple HTML document that I have: <!DOCTYPE html> <html> <head> < ...

Remove the initial 15,000 lines from a text file using Node.js

Looking for a way to delete the first 15,000 lines of a large text log file (roughly 20MB) using Node.js. Any suggestions on how to accomplish this task? ...

Continuously flowing chain of replies from a series of queries using RxJS

I am exploring the world of RxJS and seeking guidance from experienced individuals. My goal is to establish a synchronized flow of responses, along with their corresponding requests, from a stream of payload data. The desired approach involves sending ea ...

Tips for incorporating conditional statements within return statements in functional components in React JS

I need to display the login page if the user is not logged in, otherwise show the forbidden 403 page. Since I'm using a functional component, I can't use render(). return forbidden === false ? ( <> <Container maxWidth="x ...

The data returned by AJAX is not in the correct order in the database

function retrieveData() { <?php $stmt = $conn->prepare("SELECT id, name FROM data"); $stmt->execute(); $stmt->bind_result($id ,$name); while ($stmt->fetch()) {?> processData (<?php echo "'$id'";?>,<?php echo "&apo ...

Switching players every two turns in a JavaScript AngularJS game

I have implemented an AngularJS score keeping game where players switch every two turns. The code works for one round, but I want to create a loop that keeps switching players. Check out my code below: app.controller('EventController', function( ...

Discovering the distinction between arrays of JQuery objects

I have a task that requires the following steps: var elems = $('.lots-of-elements') Next, I need to make an AJAX request and then do this: var moreElems = $('.lots-of-elements') Finally, I am looking to identify only the new element ...

Skrollr immediate pop-up notification

Can anyone help me figure out how to make text appear suddenly and then disappear using skrollr? I've been able to get it to fade in and out, but I want it to just show up without any transition. Here's the code I have so far: <div id="style" ...