function ThreeOrbitControls(object, domElement, eventHandler) {
	    var _this;

	    classCallCheck(this, ThreeOrbitControls);

	    _this = possibleConstructorReturn(this, getPrototypeOf$2(ThreeOrbitControls).call(this));
	    _this.object = object;
	    _this.domElement = domElement === undefined ? document : domElement;
	    _this.eventHandler = eventHandler; // Set to false to disable this control

	    _this.enabled = true; // "target" sets the location of focus, where the object orbits around

	    _this.target = new Vector3(); // How far you can dolly in and out ( PerspectiveCamera only )

	    _this.minDistance = 0;
	    _this.maxDistance = Infinity; // How far you can zoom in and out ( OrthographicCamera only )

	    _this.minZoom = 0;
	    _this.maxZoom = Infinity; // How far you can orbit vertically, upper and lower limits.
	    // Range is 0 to Math.PI radians.

	    _this.minPolarAngle = 0; // radians

	    _this.maxPolarAngle = Math.PI; // radians
	    // How far you can orbit horizontally, upper and lower limits.
	    // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].

	    _this.minAzimuthAngle = -Infinity; // radians

	    _this.maxAzimuthAngle = Infinity; // radians
	    // Set to true to enable damping (inertia)
	    // If damping is enabled, you must call controls.update() in your animation loop

	    _this.enableDamping = false;
	    _this.dampingFactor = 0.25; // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
	    // Set to false to disable zooming

	    _this.enableZoom = true;
	    _this.zoomSpeed = 1.0; // Set to false to disable rotating

	    _this.enableRotate = true;
	    _this.rotateSpeed = 1.0; // Set to false to disable panning

	    _this.enablePan = true;
	    _this.keyPanSpeed = 7.0; // pixels moved per arrow key push
	    // Set to true to automatically rotate around the target
	    // If auto-rotate is enabled, you must call controls.update() in your animation loop

	    _this.autoRotate = false;
	    _this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
	    // Set to false to disable use of the keys

	    _this.enableKeys = true; // The four arrow keys

	    _this.keys = {
	      LEFT: 37,
	      UP: 38,
	      RIGHT: 39,
	      BOTTOM: 40
	    }; // Mouse buttons

	    _this.mouseButtons = {
	      ORBIT: MOUSE.LEFT,
	      ZOOM: MOUSE.MIDDLE,
	      PAN: MOUSE.RIGHT
	    }; // for reset

	    _this.target0 = _this.target.clone();
	    _this.position0 = _this.object.position.clone();
	    _this.zoom0 = _this.object.zoom; //
	    // public methods
	    //

	    _this.getPolarAngle = function () {
	      return spherical.phi;
	    };

	    _this.getAzimuthalAngle = function () {
	      return spherical.theta;
	    };

	    _this.reset = function () {
	      _this.target.copy(_this.target0);

	      _this.object.position.copy(_this.position0);

	      _this.object.zoom = _this.zoom0;

	      _this.object.updateProjectionMatrix();

	      _this.dispatchEvent(changeEvent);

	      _this.update();

	      state = STATE.NONE;
	    }; // this method is exposed, but perhaps it would be better if we can make it private...


	    _this.update = function () {
	      var offset = new Vector3(); // so camera.up is the orbit axis

	      var quat = new Quaternion().setFromUnitVectors(object.up, new Vector3(0, 1, 0));
	      var quatInverse = quat.clone().inverse();
	      var lastPosition = new Vector3();
	      var lastQuaternion = new Quaternion();
	      return function () {
	        var position = _this.object.position;
	        offset.copy(position).sub(_this.target); // rotate offset to "y-axis-is-up" space

	        offset.applyQuaternion(quat); // angle from z-axis around y-axis

	        spherical.setFromVector3(offset);
	        if (_this.autoRotate && state === STATE.NONE) rotateLeft(getAutoRotationAngle());
	        spherical.theta += sphericalDelta.theta;
	        spherical.phi += sphericalDelta.phi; // restrict theta to be between desired limits

	        spherical.theta = Math.max(_this.minAzimuthAngle, Math.min(_this.maxAzimuthAngle, spherical.theta)); // restrict phi to be between desired limits

	        spherical.phi = Math.max(_this.minPolarAngle, Math.min(_this.maxPolarAngle, spherical.phi));
	        spherical.makeSafe();
	        spherical.radius *= scale; // restrict radius to be between desired limits

	        spherical.radius = Math.max(_this.minDistance, Math.min(_this.maxDistance, spherical.radius)); // move target to panned location

	        _this.target.add(panOffset);

	        offset.setFromSpherical(spherical); // rotate offset back to "camera-up-vector-is-up" space

	        offset.applyQuaternion(quatInverse);
	        position.copy(_this.target).add(offset);

	        _this.object.lookAt(_this.target);

	        if (_this.enableDamping === true) {
	          sphericalDelta.theta *= 1 - _this.dampingFactor;
	          sphericalDelta.phi *= 1 - _this.dampingFactor;
	        } else sphericalDelta.set(0, 0, 0);

	        scale = 1;
	        panOffset.set(0, 0, 0); // update condition is:
	        // min(camera displacement, camera rotation in radians)^2 > EPS
	        // using small-angle approximation cos(x/2) = 1 - x^2 / 8

	        if (zoomChanged || lastPosition.distanceToSquared(_this.object.position) > EPS || 8 * (1 - lastQuaternion.dot(_this.object.quaternion)) > EPS) {
	          _this.dispatchEvent(changeEvent);

	          lastPosition.copy(_this.object.position);
	          lastQuaternion.copy(_this.object.quaternion);
	          zoomChanged = false;
	          return true;
	        }

	        return false;
	      }();
	    };

	    _this.dispose = function () {
	      _this.domElement.removeEventListener('contextmenu', onContextMenu, false);

	      _this.domElement.removeEventListener('mousedown', onMouseDown, false);

	      _this.domElement.removeEventListener('wheel', onMouseWheel, false);

	      _this.domElement.removeEventListener('touchstart', onTouchStart, false);

	      _this.domElement.removeEventListener('touchend', onTouchEnd, false);

	      _this.domElement.removeEventListener('touchmove', onTouchMove, false);

	      document.removeEventListener('mousemove', onMouseMove, false);
	      document.removeEventListener('mouseup', onMouseUp, false);
	      window.removeEventListener('keydown', onKeyDown, false); // this.dispatchEvent( { type: 'dispose' } ); // should this be added here?
	    }; //
	    // internals
	    //


	    var changeEvent = {
	      type: 'change'
	    };
	    var startEvent = {
	      type: 'start'
	    };
	    var endEvent = {
	      type: 'end'
	    };
	    var STATE = {
	      NONE: -1,
	      ROTATE: 0,
	      DOLLY: 1,
	      PAN: 2,
	      TOUCH_ROTATE: 3,
	      TOUCH_DOLLY: 4,
	      TOUCH_PAN: 5
	    };
	    var state = STATE.NONE;
	    var EPS = 0.000001; // current position in spherical coordinates

	    var spherical = new Spherical();
	    var sphericalDelta = new Spherical();
	    var scale = 1;
	    var panOffset = new Vector3();
	    var zoomChanged = false;
	    var rotateStart = new Vector2();
	    var rotateEnd = new Vector2();
	    var rotateDelta = new Vector2();
	    var panStart = new Vector2();
	    var panEnd = new Vector2();
	    var panDelta = new Vector2();
	    var dollyStart = new Vector2();
	    var dollyEnd = new Vector2();
	    var dollyDelta = new Vector2();

	    var getAutoRotationAngle = function getAutoRotationAngle() {
	      return 2 * Math.PI / 60 / 60 * _this.autoRotateSpeed;
	    };

	    var getZoomScale = function getZoomScale() {
	      return Math.pow(0.95, _this.zoomSpeed);
	    };

	    var rotateLeft = function rotateLeft(angle) {
	      sphericalDelta.theta -= angle;
	    };

	    var rotateUp = function rotateUp(angle) {
	      sphericalDelta.phi -= angle;
	    };

	    var panLeft = function () {
	      var v = new Vector3();
	      return function (distance, objectMatrix) {
	        v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix

	        v.multiplyScalar(-distance);
	        panOffset.add(v);
	      };
	    }();

	    var panUp = function () {
	      var v = new Vector3();
	      return function (distance, objectMatrix) {
	        v.setFromMatrixColumn(objectMatrix, 1); // get Y column of objectMatrix

	        v.multiplyScalar(distance);
	        panOffset.add(v);
	      };
	    }(); // deltaX and deltaY are in pixels; right and down are positive


	    var pan = function () {
	      var offset = new Vector3();
	      return function (deltaX, deltaY) {
	        var element = _this.domElement === document ? _this.domElement.body : _this.domElement;

	        if (_this.object instanceof PerspectiveCamera) {
	          // perspective
	          var position = _this.object.position;
	          offset.copy(position).sub(_this.target);
	          var targetDistance = offset.length(); // half of the fov is center to top of screen

	          targetDistance *= Math.tan(_this.object.fov / 2 * Math.PI / 180.0); // we actually don't use screenWidth, since perspective camera is fixed to screen height

	          panLeft(2 * deltaX * targetDistance / element.clientHeight, _this.object.matrix);
	          panUp(2 * deltaY * targetDistance / element.clientHeight, _this.object.matrix);
	        } else if (_this.object instanceof OrthographicCamera) {
	          // orthographic
	          panLeft(deltaX * (_this.object.right - _this.object.left) / _this.object.zoom / element.clientWidth, _this.object.matrix);
	          panUp(deltaY * (_this.object.top - _this.object.bottom) / _this.object.zoom / element.clientHeight, _this.object.matrix);
	        } else {
	          // camera neither orthographic nor perspective
	          console.warn('WARNING: OrbitControlsModule.js encountered an unknown camera type - pan disabled.');
	          _this.enablePan = false;
	        }
	      };
	    }();

	    var dollyIn = function dollyIn(dollyScale) {
	      if (_this.object instanceof PerspectiveCamera) scale /= dollyScale;else if (_this.object instanceof OrthographicCamera) {
	        _this.object.zoom = Math.max(_this.minZoom, Math.min(_this.maxZoom, _this.object.zoom * dollyScale));

	        _this.object.updateProjectionMatrix();

	        zoomChanged = true;
	      } else {
	        console.warn('WARNING: OrbitControlsModule.js encountered an unknown camera type - dolly/zoom disabled.');
	        _this.enableZoom = false;
	      }
	    };

	    var dollyOut = function dollyOut(dollyScale) {
	      if (_this.object instanceof PerspectiveCamera) scale *= dollyScale;else if (_this.object instanceof OrthographicCamera) {
	        _this.object.zoom = Math.max(_this.minZoom, Math.min(_this.maxZoom, _this.object.zoom / dollyScale));

	        _this.object.updateProjectionMatrix();

	        zoomChanged = true;
	      } else {
	        console.warn('WARNING: OrbitControlsModule.js encountered an unknown camera type - dolly/zoom disabled.');
	        _this.enableZoom = false;
	      }
	    }; //
	    // event callbacks - update the object state
	    //


	    var handleMouseDownRotate = function handleMouseDownRotate(event) {
	      // console.log( 'handleMouseDownRotate' );
	      rotateStart.set(event.clientX, event.clientY);
	    };

	    var handleMouseDownDolly = function handleMouseDownDolly(event) {
	      // console.log( 'handleMouseDownDolly' );
	      dollyStart.set(event.clientX, event.clientY);
	    };

	    var handleMouseDownPan = function handleMouseDownPan(event) {
	      // console.log( 'handleMouseDownPan' );
	      panStart.set(event.clientX, event.clientY);
	    };

	    var handleMouseMoveRotate = function handleMouseMoveRotate(event) {
	      // console.log( 'handleMouseMoveRotate' );
	      rotateEnd.set(event.clientX, event.clientY);
	      rotateDelta.subVectors(rotateEnd, rotateStart);
	      var element = _this.domElement === document ? _this.domElement.body : _this.domElement; // rotating across whole screen goes 360 degrees around

	      rotateLeft(2 * Math.PI * rotateDelta.x / element.clientWidth * _this.rotateSpeed); // rotating up and down along whole screen attempts to go 360, but limited to 180

	      rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight * _this.rotateSpeed);
	      rotateStart.copy(rotateEnd);

	      _this.update();
	    };

	    var handleMouseMoveDolly = function handleMouseMoveDolly(event) {
	      // console.log( 'handleMouseMoveDolly' );
	      dollyEnd.set(event.clientX, event.clientY);
	      dollyDelta.subVectors(dollyEnd, dollyStart);
	      if (dollyDelta.y > 0) dollyIn(getZoomScale());else if (dollyDelta.y < 0) dollyOut(getZoomScale());
	      dollyStart.copy(dollyEnd);

	      _this.update();
	    };

	    var handleMouseMovePan = function handleMouseMovePan(event) {
	      // console.log( 'handleMouseMovePan' );
	      panEnd.set(event.clientX, event.clientY);
	      panDelta.subVectors(panEnd, panStart);
	      pan(panDelta.x, panDelta.y);
	      panStart.copy(panEnd);

	      _this.update();
	    };

	    var handleMouseWheel = function handleMouseWheel(event) {
	      // console.log( 'handleMouseWheel' );
	      if (event.deltaY < 0) dollyOut(getZoomScale());else if (event.deltaY > 0) dollyIn(getZoomScale());

	      _this.update();
	    };

	    var handleKeyDown = function handleKeyDown(event) {
	      // console.log( 'handleKeyDown' );
	      switch (event.keyCode) {
	        case _this.keys.UP:
	          pan(0, _this.keyPanSpeed);

	          _this.update();

	          break;

	        case _this.keys.BOTTOM:
	          pan(0, -_this.keyPanSpeed);

	          _this.update();

	          break;

	        case _this.keys.LEFT:
	          pan(_this.keyPanSpeed, 0);

	          _this.update();

	          break;

	        case _this.keys.RIGHT:
	          pan(-_this.keyPanSpeed, 0);

	          _this.update();

	          break;
	      }
	    };

	    var handleTouchStartRotate = function handleTouchStartRotate(event) {
	      // console.log( 'handleTouchStartRotate' );
	      rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
	    };

	    var handleTouchStartDolly = function handleTouchStartDolly(event) {
	      // console.log( 'handleTouchStartDolly' );
	      var dx = event.touches[0].pageX - event.touches[1].pageX;
	      var dy = event.touches[0].pageY - event.touches[1].pageY;
	      var distance = Math.sqrt(dx * dx + dy * dy);
	      dollyStart.set(0, distance);
	    };

	    var handleTouchStartPan = function handleTouchStartPan(event) {
	      // console.log( 'handleTouchStartPan' );
	      panStart.set(event.touches[0].pageX, event.touches[0].pageY);
	    };

	    var handleTouchMoveRotate = function handleTouchMoveRotate(event) {
	      // console.log( 'handleTouchMoveRotate' );
	      rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
	      rotateDelta.subVectors(rotateEnd, rotateStart);
	      var element = _this.domElement === document ? _this.domElement.body : _this.domElement; // rotating across whole screen goes 360 degrees around

	      rotateLeft(2 * Math.PI * rotateDelta.x / element.clientWidth * _this.rotateSpeed); // rotating up and down along whole screen attempts to go 360, but limited to 180

	      rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight * _this.rotateSpeed);
	      rotateStart.copy(rotateEnd);

	      _this.update();
	    };

	    var handleTouchMoveDolly = function handleTouchMoveDolly(event) {
	      // console.log( 'handleTouchMoveDolly' );
	      var dx = event.touches[0].pageX - event.touches[1].pageX;
	      var dy = event.touches[0].pageY - event.touches[1].pageY;
	      var distance = Math.sqrt(dx * dx + dy * dy);
	      dollyEnd.set(0, distance);
	      dollyDelta.subVectors(dollyEnd, dollyStart);
	      if (dollyDelta.y > 0) dollyOut(getZoomScale());else if (dollyDelta.y < 0) dollyIn(getZoomScale());
	      dollyStart.copy(dollyEnd);

	      _this.update();
	    };

	    var handleTouchMovePan = function handleTouchMovePan(event) {
	      // console.log( 'handleTouchMovePan' );
	      panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
	      panDelta.subVectors(panEnd, panStart);
	      pan(panDelta.x, panDelta.y);
	      panStart.copy(panEnd);

	      _this.update();
	    };
	    // event handlers - FSM: listen for events and reset state
	    //


	    var onMouseDown = function onMouseDown(event) {
	      if (_this.enabled === false) return;
	      event.preventDefault();

	      if (event.button === _this.mouseButtons.ORBIT) {
	        if (_this.enableRotate === false) return;
	        handleMouseDownRotate(event);
	        state = STATE.ROTATE;
	      } else if (event.button === _this.mouseButtons.ZOOM) {
	        if (_this.enableZoom === false) return;
	        handleMouseDownDolly(event);
	        state = STATE.DOLLY;
	      } else if (event.button === _this.mouseButtons.PAN) {
	        if (_this.enablePan === false) return;
	        handleMouseDownPan(event);
	        state = STATE.PAN;
	      }

	      if (state !== STATE.NONE) {
	        _this.eventHandler.on('mousemove', onMouseMove, false);

	        _this.eventHandler.on('mouseup', onMouseUp, false);

	        _this.dispatchEvent(startEvent);
	      }
	    };

	    var onMouseMove = function onMouseMove(event) {
	      if (_this.enabled === false) return;
	      event.preventDefault();

	      if (state === STATE.ROTATE) {
	        if (_this.enableRotate === false) return;
	        handleMouseMoveRotate(event);
	      } else if (state === STATE.DOLLY) {
	        if (_this.enableZoom === false) return;
	        handleMouseMoveDolly(event);
	      } else if (state === STATE.PAN) {
	        if (_this.enablePan === false) return;
	        handleMouseMovePan(event);
	      }
	    };

	    var onMouseUp = function onMouseUp(event) {
	      if (_this.enabled === false) return;
	      document.removeEventListener('mousemove', onMouseMove, false);
	      document.removeEventListener('mouseup', onMouseUp, false);

	      _this.dispatchEvent(endEvent);

	      state = STATE.NONE;
	    };

	    var onMouseWheel = function onMouseWheel(event) {
	      if (_this.enabled === false || _this.enableZoom === false || state !== STATE.NONE && state !== STATE.ROTATE) return;
	      event.preventDefault();
	      event.stopPropagation();
	      handleMouseWheel(event);

	      _this.dispatchEvent(startEvent); // not sure why these are here...


	      _this.dispatchEvent(endEvent);
	    };

	    var onKeyDown = function onKeyDown(event) {
	      if (_this.enabled === false || _this.enableKeys === false || _this.enablePan === false) return;
	      handleKeyDown(event);
	    };

	    var onTouchStart = function onTouchStart(event) {
	      if (_this.enabled === false) return;

	      switch (event.touches.length) {
	        case 1:
	          // one-fingered touch: rotate
	          if (_this.enableRotate === false) return;
	          handleTouchStartRotate(event);
	          state = STATE.TOUCH_ROTATE;
	          break;

	        case 2:
	          // two-fingered touch: dolly
	          if (_this.enableZoom === false) return;
	          handleTouchStartDolly(event);
	          state = STATE.TOUCH_DOLLY;
	          break;

	        case 3:
	          // three-fingered touch: pan
	          if (_this.enablePan === false) return;
	          handleTouchStartPan(event);
	          state = STATE.TOUCH_PAN;
	          break;

	        default:
	          state = STATE.NONE;
	      }

	      if (state !== STATE.NONE) _this.dispatchEvent(startEvent);
	    };

	    var onTouchMove = function onTouchMove(event) {
	      if (_this.enabled === false) return;
	      event.preventDefault();
	      event.stopPropagation();

	      switch (event.touches.length) {
	        case 1:
	          // one-fingered touch: rotate
	          if (_this.enableRotate === false) return;
	          if (state !== STATE.TOUCH_ROTATE) return; // is this needed?...

	          handleTouchMoveRotate(event);
	          break;

	        case 2:
	          // two-fingered touch: dolly
	          if (_this.enableZoom === false) return;
	          if (state !== STATE.TOUCH_DOLLY) return; // is this needed?...

	          handleTouchMoveDolly(event);
	          break;

	        case 3:
	          // three-fingered touch: pan
	          if (_this.enablePan === false) return;
	          if (state !== STATE.TOUCH_PAN) return; // is this needed?...

	          handleTouchMovePan(event);
	          break;

	        default:
	          state = STATE.NONE;
	      }
	    };

	    var onTouchEnd = function onTouchEnd(event) {
	      if (_this.enabled === false) return;

	      _this.dispatchEvent(endEvent);

	      state = STATE.NONE;
	    };

	    var onContextMenu = function onContextMenu(event) {
	      event.preventDefault();
	    }; //


	    _this.eventHandler.on('contextmenu', onContextMenu, false);

	    _this.eventHandler.on('mousedown', onMouseDown, false);

	    _this.eventHandler.on('wheel', onMouseWheel, false);

	    _this.eventHandler.on('touchstart', onTouchStart, false);

	    _this.eventHandler.on('touchend', onTouchEnd, false);

	    _this.eventHandler.on('touchmove', onTouchMove, false);

	    _this.eventHandler.on('keydown', onKeyDown, false); // force an update at start


	    _this.update();

	    return _this;
	  }
@method current
@description Return `trueVal` if `config` match current configuration, in other case - return `falseVal`.
@param {String} config Configuration name.
@param {Any} trueVal Value returned if condition is truthy.
@param {Any} falseVal Value returned if condition is falsy.
@memberof module:modules/app.StateModule