import { Raycaster, Vector3 } from "three" class Draggable{ constructor(defaultDistance){ const objects = []; const raycaster = new Raycaster(); let v = new Vector3; let dragging = null; this.add = function(object, dragZone, fn, distance){ objects.push(object); object._draggable = {fn, dragZone, distance: distance || defaultDistance} } this.remove = function(object){ delete object._draggable; objects.splice(objects.indexOf(object), 1); } this.update = function(pointer, camera, action){ raycaster.setFromCamera(pointer, camera); if (action == 'start'){ let forExecute = []; objects.forEach(o=>{ o.getWorldPosition(v); if (camera.position.distanceTo(v) <= o._draggable.distance && o.visible){ const intersects = raycaster.intersectObject(o); if (intersects[0]) forExecute.push({o, i:intersects[0]}) } }); if (forExecute[0]) { let s = forExecute.sort((a,b)=>a.i.distance-b.i.distance)[0]; s.o._draggable.fn.start && s.o._draggable.fn.start(s.i); dragging = s; dragging.zone = raycaster.intersectObject(s.o._draggable.dragZone)[0]; } }else if (action == 'end' && dragging){ dragging.o._draggable.fn.end && dragging.o._draggable.fn.end(dragging); dragging = null; }else if(action == 'drag' && dragging){ const intersect = raycaster.intersectObject(dragging.o._draggable.dragZone)[0]; if (intersect?.uv && dragging.zone?.uv){ dragging.o.position.x += -4*(dragging.zone.uv.x - intersect.uv.x); dragging.o.position.y += 4*(dragging.zone.uv.y - intersect.uv.y); dragging.o._draggable.fn.drag && dragging.o._draggable.fn.drag(dragging); dragging.zone = intersect; } } } } } export { Draggable }