three.js - manipualte object hierarchies

by mmalex

HTML

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.js"></script>
<script src="http://mbnsay.com/rayys/assets/js/OrbitControls.js"></script>
<script src="http://rawgit.mbnsay.com/nmalex/three.js-helpers/master/RayysMouse.js"></script>
<script src="http://mbnsay.com/rayys/assets/js/clipper_unminified.js"></script>

CSS

body {
  overflow: hidden;
  padding: 0;
  margin: 0;
}

JavaScript

class RayysMouseMove {

  constructor(rayysMouse, controls) {
    this.camera = rayysMouse.camera;

    this.mouse = rayysMouse;
    this.controls = controls || this.mouse.controls;
    this.mouse.controls = undefined; // overtake mouse controls, if any defined

    this.objects = [];
    this.cb = {
      onModeChanged: [],
      onObjectEnter: [],
      onObjectLeave: [],
      onBeforeStart: [], //callbacks here may return false to prevent operation
      onPreviewObjectMove: [], //callbacks here may return alternative position
      onObjectMove: [],
      onObjectReleased: [],
      onVoidClick: []
    };
    this.raycaster = new THREE.Raycaster();

    this.translationLimits = new THREE.Vector3();
    this.translationPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0);
    this.translationPlaneHelper = new THREE.PlaneHelper(this.translationPlane, 10, 0xff0000);

    this.toggle("xz");

    var handleMouseDown = function(pos) {
      console.log(`Mouse down at: ${JSON.stringify(pos)}`);

      this.raycaster.setFromCamera(pos, this.camera);
      var intersects = this.raycaster.intersectObjects(this.objects, true);
      if (intersects.length > 0) {

        var canProceed = true;
        // check with subscribers, if this object is movable in current context
        for (let i = 0; i < this.cb.onBeforeStart.length; i++) {
          if (this.cb.onBeforeStart[i](intersects[0].object, this) === false) {
            canProceed = false;
          }
        }
        if (!canProceed) return;

        if (this.controls) {
          this.controls.enablePan = false;
          this.controls.enableRotate = false;
        }

        this.pickPoint = intersects[0].point;
        let pickedObj = intersects[0].object
        if (this.objects.indexOf(pickedObj) !== -1) {
        	this.pickedObj = pickedObj;
        } else {
          let pickedParent = pickedObj.parent;
          while (pickedParent) {
          	if (this.objects.indexOf(pickedParent) !== -1) {
       ...