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
<!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>