# Two box & two control transform overlapping - how to separate to move only one box? =\> solution: DragControls

**URL:** <https://discourse.threejs.org/t/two-box-two-control-transform-overlapping-how-to-separate-to-move-only-one-box-solution-dragcontrols/55433>\
**Category:** Questions\
**Tags:** transform-controls, drag-controls\
**Created:** [August 28, 2023, 7:58am UTC](https://discourse.threejs.org/t/two-box-two-control-transform-overlapping-how-to-separate-to-move-only-one-box-solution-dragcontrols/55433 "2023-08-28T07:58:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![three3d](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/three3d/32/38430_2.png) [@three3d](https://discourse.threejs.org/u/three3d)\
**Post date:** [August 28, 2023, 7:58am UTC](https://discourse.threejs.org/t/two-box-two-control-transform-overlapping-how-to-separate-to-move-only-one-box-solution-dragcontrols/55433/1 "2023-08-28T07:58:08Z")

</div>

little problem/big problem 🙂  
I have two objects/box; each object has its control transform connected; in specific circumstances these objects may overlap; and then the problem arises how to move only one object because the cursor recognizes two control transforms at the same time and unfortunately two boxes are moved;

- here I think you need some js code fragment to check how many control transforms have been recognized under the cursor and possibly to select only one to move?
- how to recognize how many control transform are highlighted under the cursor?

 ![howcnotrolsseparate](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/6/6/668da603648addd43107e243c8f998badcf01041.png)

```javascript
<!DOCTYPE html>
<html lang="en">
	<head>
		<title></title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>
		<div id="container"></div>
		<div id="info">
		</div>
		<!-- Import maps polyfill -->
		<!-- Remove this when import maps will be widely supported -->
		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
		<!-- // "three": "../../lib/js/three.module.min.js", -->
		<!-- // "three/addons/": "../../lib/js/jsm/" -->
		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { TransformControls } from 'three/addons/controls/TransformControls.js';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 1, 2, 3 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xbbbbbb );
document.body.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );

let geometry1 = new THREE.BoxGeometry( 1, 1, 1 );
let material1 = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
let cube1 = new THREE.Mesh( geometry1, material1 );
scene.add( cube1 );

let geometry2 = new THREE.BoxGeometry( 1, 1, 1 );
let material2 = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
let cube2 = new THREE.Mesh( geometry2, material2 );
scene.add( cube2 );

let control1 = new TransformControls( camera, renderer.domElement );
	control1.showX = true;	// only X !
	control1.showY = false;
	control1.showZ = false;
	control1.addEventListener( 'dragging-changed', ( event ) => {
		controls.enabled = ! event.value;
		console.log('control1');
	} );
	control1.attach( cube1 );
	scene.add( control1 );

let control2 = new TransformControls( camera, renderer.domElement );
	control2.showX = true;	// only X !
	control2.showY = false;
	control2.showZ = false;
	control2.addEventListener( 'dragging-changed', ( event ) => {
		controls.enabled = ! event.value;
		console.log('control2');
	} );
	control2.attach( cube2 );
	scene.add( control2 );

function animate() {
	requestAnimationFrame( animate );
	controls.update();
	renderer.render( scene, camera );
}
animate();

</script>
</body>
</html>

```

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [August 28, 2023, 12:01pm UTC](https://discourse.threejs.org/t/two-box-two-control-transform-overlapping-how-to-separate-to-move-only-one-box-solution-dragcontrols/55433/2 "2023-08-28T12:01:28Z")

</div>

Couldn’t you rewrite your code and avoid the usage of two instances of `TransformControls`?

How about doing it similar to the [three.js editor](https://threejs.org/editor/)? Meaning you can only transform a single object by selecting it first via a `pointerdown` interaction. Instead of pointer down, you could also check objects in your scene when `pointermove` is triggered. In this case the controls are assigned to the object as soon as you hover over it.

---

<div class="post-metadata">

**Author:** ![three3d](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/three3d/32/38430_2.png) [@three3d](https://discourse.threejs.org/u/three3d)\
**Post date:** [August 28, 2023, 6:06pm UTC](https://discourse.threejs.org/t/two-box-two-control-transform-overlapping-how-to-separate-to-move-only-one-box-solution-dragcontrols/55433/3 "2023-08-28T18:06:39Z")

</div>

@Mugen87 thanks for the hints;  
I found examples with DragControls e.g. [DragControls - Three.js Tutorials](https://sbcode.net/threejs/drag-controls/)  
I turned off autoanimation of boxes, activated orbitControl  
and fortunately, I miss the option of moving the boxes only along one axis declared in the script, e.g. X, how to save it in js?

```javascript
let controls = new OrbitControls( camera, renderer.domElement );
...
let drag = new DragControls(......cubes, camera, renderer.domElement)

// drag.addEventListener( 'mousedown', function () { // is mousedown needed?
// console.log('mousedown')
// })
drag.addEventListener( 'dragstart', function () {
controls.enabled = false;
// drag only X..........???
});
drag.addEventListener( 'dragend', function () {
controls.enabled = true;
// end drag only X..........???
});

```

---

<div class="post-metadata">

**Author:** ![three3d](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/three3d/32/38430_2.png) [@three3d](https://discourse.threejs.org/u/three3d)\
**Post date:** [August 30, 2023, 11:18am UTC](https://discourse.threejs.org/t/two-box-two-control-transform-overlapping-how-to-separate-to-move-only-one-box-solution-dragcontrols/55433/4 "2023-08-30T11:18:41Z")

</div>

ok, after various trials and searches, I figured out what DragControls is all about and how to adapt it to my own needs (in moving objects that may overlap in specific situations);  
To close the topic, I’m posting my example, which may be useful to a novice like me.

- there are 6 large visible planes in the scene (e.g. for model cutting etc.);
- each pair of planes can move along one fixed axis oX,Y,Z;
- in the js script, 6 hidden small planes placed in the center of large planes are responsible for moving large planes;
- why so ? because I wanted to use DragControls and DragControls did not recognize the entire large plane, but only its smaller fragments in the center;
- thanks to this, if the cursor hovers over a large plane but not its center, the scene orbit will not be blocked (!); only hovering over and clicking a fragment of the center of a large plane will activate DragControls;
- in practice, the hidden small plane is moved and the large plane is visible at the same time (which dynamically captures the position of the small plane)
- the mechanism …addEventListener( ‘hoveron’… and …addEventListener( ‘hoveroff’… helps to visually distinguish which plane is to be moved

![dragcontrols6](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/c/ac2529b255a09c17443bfc0d4138f282f69ef9cd.gif)

```javascript
<!DOCTYPE html>
<html lang="en">
	<head>
		<title></title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>
		<div id="container"></div>
		<div id="info">
		</div>
		<!-- Import maps polyfill -->
		<!-- Remove this when import maps will be widely supported -->
		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
		<script type="importmap">
			{
				"imports": {
                    "three": "../build/three.module.js",
                    "three/addons/": "./jsm/"
				}
			}
		</script>

<script type="module">

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { DragControls } from 'three/addons/controls/DragControls.js';

let container, scene, camera, renderer, controls, drag;
let x0,y0,z0; // initial plane position for DragControls

scene = new THREE.Scene()
scene.background = new THREE.Color(0xeeeeee);
scene.add( new THREE.AxesHelper(5) )
scene.add( new THREE.AmbientLight(0xffffff, 2) )

camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
)
camera.position.set(2, 2, 3)

renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

controls = new OrbitControls( camera, renderer.domElement );

// planes to be moved along the axis
const mathoveroff = 0.2; // standard opacity
const mathoveron = 0.6; // opacity when mouse hover
// materials for 3 axes and 6 directions
const material = [
    new THREE.MeshPhongMaterial({ color: 0xff0000, transparent: true, side: THREE.DoubleSide, opacity:mathoveroff }), // +X
    new THREE.MeshPhongMaterial({ color: 0x00ff00, transparent: true, side: THREE.DoubleSide, opacity:mathoveroff }), // +Y
    new THREE.MeshPhongMaterial({ color: 0x0000ff, transparent: true, side: THREE.DoubleSide, opacity:mathoveroff }), // +Z
    new THREE.MeshPhongMaterial({ color: 0xff0000, transparent: true, side: THREE.DoubleSide, opacity:mathoveroff }), // -X
    new THREE.MeshPhongMaterial({ color: 0x00ff00, transparent: true, side: THREE.DoubleSide, opacity:mathoveroff }), // -Y
    new THREE.MeshPhongMaterial({ color: 0x0000ff, transparent: true, side: THREE.DoubleSide, opacity:mathoveroff }) // -Z
]
// obj2drag=[...] hidden small planes to DragControls, fixed dimensions
const geometry = new THREE.PlaneGeometry(0.5, 0.5);
const obj2drag = [
    new THREE.Mesh(geometry, material[0]),
    new THREE.Mesh(geometry, material[1]),
    new THREE.Mesh(geometry, material[2]),
    new THREE.Mesh(geometry, material[3]),
    new THREE.Mesh(geometry, material[4]),
    new THREE.Mesh(geometry, material[5])
]
// ******************************************************************************************
// obj2drag2=[...] visible planes moved according to analogous hidden planes
// visible planes are not related to the hidden ones with the object2.add(object1) method
// and are not recognized by DragControls;
// thanks to this, after hovering over a large plane, orbiting the scene is not blocked,
// only hovering over a small hidden plane (in the center of a large plane) allows you to start DragControls

const geometry2 = new THREE.PlaneGeometry(4, 2);
const obj2drag2 = [
    new THREE.Mesh(geometry2, material[0]),
    new THREE.Mesh(geometry2, material[1]),
    new THREE.Mesh(geometry2, material[2]),
    new THREE.Mesh(geometry2, material[3]),
    new THREE.Mesh(geometry2, material[4]),
    new THREE.Mesh(geometry2, material[5])
]

// add axis shift name tags to the planes, and set the planes perpendicular to the axis
obj2drag[0].name="dragx"; obj2drag[0].rotateY(Math.PI / 2);
obj2drag[1].name="dragy"; obj2drag[1].rotateX(Math.PI / 2);
obj2drag[2].name="dragz"; //obj2drag[2].rotateY(Math.PI / 2);
obj2drag[3].name="dragx2"; obj2drag[3].rotateY(- Math.PI / 2);
obj2drag[4].name="dragy2"; obj2drag[4].rotateX(- Math.PI / 2);
obj2drag[5].name="dragz2"; //obj2drag[5].rotateY(- Math.PI / 2);

obj2drag2[0].name="planex"; obj2drag2[0].rotateY(Math.PI / 2);
obj2drag2[1].name="planey"; obj2drag2[1].rotateX(Math.PI / 2);
obj2drag2[2].name="planez"; //obj2drag2[2].rotateY(Math.PI / 2);
obj2drag2[3].name="planex2"; obj2drag2[3].rotateY(- Math.PI / 2);
obj2drag2[4].name="planey2"; obj2drag2[4].rotateX(- Math.PI / 2);
obj2drag2[5].name="planez2"; //obj2drag2[5].rotateY(- Math.PI / 2);

obj2drag.forEach((c) => c.visible=false) // hide small planes
obj2drag.forEach((c) => scene.add(c)) // insert hidden small planes into the scene
obj2drag2.forEach((c) => scene.add(c)) // insert visible large planes into the scene

// initialize the DragControls mechanism
drag = new DragControls(obj2drag, camera, renderer.domElement)

drag.addEventListener( 'hoveron', function (e) { // when the cursor hovers over a small plane
    // e = Object { type: "dragstart", target: null,
    // object: Object { isObject3D: true, uuid: "3a4a0840-f...", name: "dragx...", … }
    // }
    e=e.object // hover object only
    e.material.opacity=mathoveron;
});

drag.addEventListener( 'dragstart', function (e) { // when the cursor moves the hidden small plane
    e=e.object // moving object only
	controls.enabled = false; // !!! lock the scene orbit
    // remember the starting position of the object
        x0=e.position.x
        y0=e.position.y
        z0=e.position.z
});

drag.addEventListener( 'drag', function (e) { // when the cursor clicks and starts to move the hidden small plane
    e=e.object // moving object only
    let nam=e.name, nam2=nam.replace('drag','plane'), // change e.g.: 'dragx' to 'planex'
        q = obj2drag2.find (q => q.name == nam2);	// find an analogous large plane e.g.:'planex'

    // save the position of the small plane along the selected axis
    if (e.name == 'dragx' || e.name == 'dragx2' ){
        e.position.y=y0; e.position.z=z0;
    } else if (e.name == 'dragy' || e.name == 'dragy2' ){
                e.position.x=x0; e.position.z=z0;
                } else {
                e.position.x=x0; e.position.y=y0;
            }

    q.position.copy(e.position) // copy the position of the small plane to the large plane
});

drag.addEventListener( 'dragend', function (e) { // when the cursor finishes moving the hidden small plane
	controls.enabled = true; // !!! unlock orbit
});

drag.addEventListener( 'hoveroff', function (e) { // when the cursor leaves above the small plane
    e=e.object // hover object only
    e.material.opacity=mathoveroff; // set material opacity to standard
});

window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
    render()
}

function animate() {
    requestAnimationFrame(animate)
    controls.update()
    render()
}

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

animate()

</script>
</body>
</html>

```
