Three.js DragControls Tutorial: Move Objects with Mouse

This article provides a step-by-step guide on how to implement the DragControls class in Three.js to select and translate 3D objects within a scene using a mouse or touch inputs. You will learn how to import the controller, initialize it with an array of draggable meshes, and handle event listeners to prevent conflicts with other camera controls.

Step 1: Import DragControls

DragControls is an add-on and is not included in the core Three.js namespace. You must import it separately from the examples directory.

import * as THREE from 'three';
import { DragControls } from 'three/examples/jsm/controls/DragControls.js';

Step 2: Set Up Draggable Objects

DragControls requires an array of 3D objects that it is allowed to interact with. Create your meshes, add them to your scene, and push them into a dedicated array.

const objects = [];

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });

for (let i = 0; i < 5; i++) {
    const cube = new THREE.Mesh(geometry, material);
    cube.position.set(Math.random() * 4 - 2, 0, Math.random() * 4 - 2);
    scene.add(cube);
    objects.push(cube); // Add to the tracking array
}

Step 3: Initialize DragControls

Instantiate the DragControls class by passing the array of draggable objects, the active camera, and the DOM element used for event listeners (usually the renderer’s canvas).

const dragControls = new DragControls(objects, camera, renderer.domElement);

Step 4: Deactivate OrbitControls During Dragging (Crucial)

If your scene uses OrbitControls to rotate the camera, dragging an object will also rotate the screen. To prevent this conflict, temporarily disable OrbitControls when a drag event starts, and re-enable it when the drag event ends.

// Assuming orbitControls is already defined
dragControls.addEventListener('dragstart', function (event) {
    orbitControls.enabled = false;
    event.object.material.emissive.setHex(0x333333); // Highlight the object
});

dragControls.addEventListener('dragend', function (event) {
    orbitControls.enabled = true;
    event.object.material.emissive.setHex(0x000000); // Reset object color
});

Step 5: Clean Up (Optional)

If you ever need to remove the drag controls from your scene to stop interaction, use the dispose method to remove all internal event listeners.

// Call this when removing the component or changing scenes
dragControls.dispose();