3JS n00b here, code works but drag controls do not

I have stumped Bard with this one. Code runs but the drag controls aren’t working. Have tried a few different approaches. Here is the current status on the code:

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

const scene = new THREE.Scene();

const geometry = new THREE.ConeGeometry( 5, 10, 64 ) 
const material = new THREE.MeshStandardMaterial( {  
    color: 0x800080,
    roughness: 500,

} )

const cone = new THREE.Mesh(geometry, material )


scene.add( cone )



//create ring

const geometryring = new THREE.RingGeometry( 0, 7, 200 ); 
const materialring = new THREE.MeshBasicMaterial( { 
    color: 0x800080,
    roughness: 500,
    side: THREE.DoubleSide

} )


const ring = new THREE.Mesh( geometryring, materialring );
ring. position. set(0,-6,0)
ring.rotation.x += 86


scene.add( ring );



//join or tie the hat and ring together

const group = new THREE.Object3D();
group.add(cone);
group.add(ring);
group.visible = true;
scene.add(group);



const parentObject = new THREE.Object3D();
parentObject.add(cone);
parentObject.add(ring);
scene.add(parentObject);


const objects = [parentObject];



//Sizes
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight,
};



const light = new THREE.DirectionalLight( 0xFFFFFF, 20 ); // soft white light


scene.add( light );



//weird ring

//camera
const camera = new THREE.PerspectiveCamera(
    45,
    sizes.width / sizes.height,
    0.1, 
    100
)
camera.position.z = 20;
scene.add(camera)



//Renderer
const canvas = document.querySelector('.webgl');
const renderer = new THREE.WebGLRenderer({ canvas })
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(window.devicePixelRatio);
renderer.render(scene, camera)



//drag controls

const controls = new DragControls(objects, camera, renderer.domElement);
controls.enable();
controls.update();

controls.on('mousedown', event => {
    const object = event.target;
    
    object.children.forEach(child => {
        child.material.emissive.set(0xaaaaaa);
    });
    startX = event.clientX;
    startY = event.clientY;
    controls.on(event);
});

controls.on('drag', function (event) {
    if (event.target.contains(event.clientX, event.clientY) && event.target.visible) {
        const object = event.target;
        object.children.forEach(child => {
            child.material.emissive.set(0xaaaaaa);
        });
        object.position.x += event.clientX - startX;
    }
});

controls.on('dragend', function () {
    startX = null;
    startY = null;
    const object = event.target;
    object.children.forEach(child => {
        child.material.emissive.set(0x000000);
    });
});


// add event listener to highlight dragged objects


controls.on('dragend', function () {
    const object = this.object;
    object.children.forEach(child => {
        child.material.emissive.set(0x000000);
    });
});
//controls.enableDamping = true 

//resize
window.addEventListener("resize", () => {
   //update sizes
    sizes.width = window.innerWidth;
    sizes.height = window.innerHeight;


//update camera
    
    camera.aspect = sizes.width / sizes.height;
    camera.updateProjectionMatrix();
    renderer.setSize(sizes.width, sizes.height);
});

const loop = () => {
    controls.update();
    renderer.render(scene, camera);
    window.requestAnimationFrame(loop); 
};
loop();

By looking at the code I have the feeling that it mixes two different drag-and-drop approaches. Here is a demo of how to use DragControls.

https://codepen.io/boytchev/full/zYJMgde

PS. It is hard to understand unformatted code that cannot be run/debugged online

I believe you are correct… I now have the objects dragging properly but the grouping of the cone and ring no longer work :smiley:

import * as THREE from ‘three’;
import ‘./style.css’
import { DragControls } from ‘three/addons/controls/DragControls.js’;

const scene = new THREE.Scene();

const geometry = new THREE.ConeGeometry( 5, 10, 64 );
const material = new THREE.MeshStandardMaterial( {
color: 0x800080,
roughness: 500,

} );

const cone = new THREE.Mesh(geometry, material );

scene.add( cone );

//create ring

const geometryring = new THREE.RingGeometry( 0, 7, 200 );
const materialring = new THREE.MeshBasicMaterial( {
color: 0x800080,
roughness: 500,
side: THREE.DoubleSide,

} );

const ring = new THREE.Mesh( geometryring, materialring );
ring. position. set(0,-6,0);
ring.rotation.x += 86;

scene.add( ring );

//join or tie the hat and ring together

const group = new THREE.Group();
group.add(cone);
group.add(ring);
scene.add(group);

const objects = [group];

//Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};

const light = new THREE.DirectionalLight( 0xFFFFFF, 20 ); // soft white light

scene.add( light );

//camera
const camera = new THREE.PerspectiveCamera(
45,
sizes.width / sizes.height,
0.1,
100
)
camera.position.z = 20;
scene.add(camera);

//Renderer
const canvas = document.querySelector(‘.webgl’);
const renderer = new THREE.WebGLRenderer({ canvas })
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(window.devicePixelRatio);
renderer.render(scene, camera)

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

controls.addEventListener(‘dragstart’, function (event) {
event.object.children.forEach(child => {
child.material.emissive.set(0xaaaaaa);
});
controls.object = group
});

controls.addEventListener(‘dragend’, function (event) {
event.object.children.forEach(child => {
child.material.emissive.set(0x000000);
});
});

// add event listener to highlight dragged objects

//resize
window.addEventListener(“resize”, () => {
//update sizes
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;

//update camera

camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
renderer.setSize(sizes.width, sizes.height);

});

const loop = () => {
renderer.render(scene, camera);
window.requestAnimationFrame(loop);
};

loop();

Please, use code formatting.
'''
your code here
'''

1 Like

If you drag one group only, add the following line after the creation of DragControls:

controls.transformGroup = true;

If you plan to drag several groups, then you have to update dynamically objects to contain only one of the groups, because DragControls can work with [many objects] or [one group], but cannot work with [many groups].

I liked very much the codepen.io/boytchev/full/zYJMgde code
and used it in my recent Paruba (light floorpan) post.
Thank You :slightly_smiling_face:

1 Like

Ok so I have tried multiple different approaches and can either get them to drag separate, get them to drag erratically and fly off the page when I do attempt a drag, and currently I’m in a state where the objects do not drag at all… any help here would be greatly appreciated!

PS hopefully I’m formatting this better at least for the purposes of this forum, I can try and clean up the code more if that helps, just making a lot of changes on the fly and intent to fully cleanup once I get it working.

’ ’ ’

import * as THREE from ‘three’;
import ‘./style.css’;

const viteImg = document.createElement(‘img’);
viteImg.src = ‘./vite.svg’;

// Append the image element to the document body
document.body.appendChild(viteImg);

const scene = new THREE.Scene();

const geometry = new THREE.ConeGeometry(5, 10, 64);
const material = new THREE.MeshStandardMaterial({
color: 0x800080,
roughness: 500,
});

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

// Create ring
const geometryRing = new THREE.RingGeometry(0, 7, 200);
const materialRing = new THREE.MeshBasicMaterial({
color: 0x800080,
roughness: 500,
side: THREE.DoubleSide,
});

const ring = new THREE.Mesh(geometryRing, materialRing);
ring.position.set(0, -6, 0);
ring.rotation.x += 86;
scene.add(ring);

// Group cone and ring together
const group = new THREE.Group();
group.add(cone);
group.add(ring);
scene.add(group);

// Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};

const light = new THREE.DirectionalLight(0xffffff, 20); // Soft white light
scene.add(light);

// Camera
const camera = new THREE.PerspectiveCamera(45, sizes.width / sizes.height, 0.1, 100);
camera.position.z = 20;
scene.add(camera);

// Renderer
const canvas = document.querySelector(‘.webgl’);
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.render(scene, camera);

// Dragging variables
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };

// Pointer events
canvas.addEventListener(‘pointerdown’, onPointerDown);
canvas.addEventListener(‘pointerup’, onPointerUp);
canvas.addEventListener(‘pointermove’, onPointerMove);

function onPointerDown(event) {
event.preventDefault();
isDragging = true;
previousMousePosition = {
x: event.clientX,
y: event.clientY,
};
}

function onPointerUp(event) {
event.preventDefault();
if (isDragging) {
const deltaMove = {
x: event.clientX - previousMousePosition.x,
y: event.clientY - previousMousePosition.y,
};

group.position.x += deltaMove.x * 0.01;
group.position.y += deltaMove.y * 0.01;

previousMousePosition = {
  x: event.clientX,
  y: event.clientY,
};

}
}

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

// Start the animation loop
animate();

’ ’ ’