Browse Source

mol-canvas3d: added "spin" option to trackball controls

David Sehnal 6 years ago
parent
commit
9f1cbbb14c
2 changed files with 41 additions and 2 deletions
  1. 29 1
      src/mol-canvas3d/controls/trackball.ts
  2. 12 1
      src/mol-util/input/input-observer.ts

+ 29 - 1
src/mol-canvas3d/controls/trackball.ts

@@ -21,6 +21,9 @@ export const TrackballControlsParams = {
     zoomSpeed: PD.Numeric(6.0, { min: 0.1, max: 10, step: 0.1 }),
     panSpeed: PD.Numeric(0.8, { min: 0.1, max: 5, step: 0.1 }),
 
+    spin: PD.Boolean(false),
+    spinSpeed: PD.Numeric(1, { min: -100, max: 100, step: 1 }),
+
     staticMoving: PD.Boolean(true, { isHidden: true }),
     dynamicDampingFactor: PD.Numeric(0.2, {}, { isHidden: true }),
 
@@ -50,9 +53,12 @@ namespace TrackballControls {
         let disposed = false
 
         const dragSub = input.drag.subscribe(onDrag)
+        const interactionEndSub = input.interactionEnd.subscribe(onInteractionEnd)
         const wheelSub = input.wheel.subscribe(onWheel)
         const pinchSub = input.pinch.subscribe(onPinch)
 
+        let _isInteracting = false;
+
         // For internal use
         const lastPosition = Vec3.zero()
 
@@ -234,6 +240,8 @@ namespace TrackballControls {
         // listeners
 
         function onDrag({ pageX, pageY, buttons, modifiers, isStart }: DragInput) {
+            _isInteracting = true;
+
             if (isStart) {
                 if (buttons === ButtonsType.Flag.Primary) {
                     Vec2.copy(_moveCurr, getMouseOnCircle(pageX, pageY))
@@ -257,11 +265,17 @@ namespace TrackballControls {
             }
         }
 
+        function onInteractionEnd() {
+            _isInteracting = false;
+        }
+
         function onWheel({ dy }: WheelInput) {
             _zoomStart[1] -= dy * 0.0001
         }
 
         function onPinch({ distance, isStart }: PinchInput) {
+            _isInteracting = true;
+
             if (isStart) {
                 _touchZoomDistanceStart = distance
             }
@@ -279,16 +293,30 @@ namespace TrackballControls {
             dragSub.unsubscribe()
             wheelSub.unsubscribe()
             pinchSub.unsubscribe()
+            interactionEndSub.unsubscribe()
+        }
+
+        const _spinSpeed = Vec2.create(0.005, 0);
+        function spin() {
+            _spinSpeed[0] = (p.spinSpeed || 0) / 1000;
+            if (!_isInteracting) Vec2.add(_moveCurr, _movePrev, _spinSpeed);
+            if (p.spin) requestAnimationFrame(spin);
         }
 
         // force an update at start
         update();
 
+        if (props.spin) { spin(); }
+
         return {
             viewport,
 
             get props() { return p as Readonly<TrackballControlsProps> },
-            setProps: (props: Partial<TrackballControlsProps>) => { Object.assign(p, props) },
+            setProps: (props: Partial<TrackballControlsProps>) => {
+                const wasSpinning = p.spin
+                Object.assign(p, props)
+                if (p.spin && !wasSpinning) requestAnimationFrame(spin)
+            },
 
             update,
             reset,

+ 12 - 1
src/mol-util/input/input-observer.ts

@@ -136,6 +136,8 @@ interface InputObserver {
     noContextMenu: boolean
 
     drag: Subject<DragInput>,
+    // Equivalent to mouseUp and touchEnd
+    interactionEnd: Subject<undefined>,
     wheel: Subject<WheelInput>,
     pinch: Subject<PinchInput>,
     click: Subject<ClickInput>,
@@ -169,6 +171,7 @@ namespace InputObserver {
         let buttons = 0
 
         const drag = new Subject<DragInput>()
+        const interactionEnd = new Subject<undefined>();
         const click = new Subject<ClickInput>()
         const move = new Subject<MoveInput>()
         const wheel = new Subject<WheelInput>()
@@ -186,6 +189,7 @@ namespace InputObserver {
             set noContextMenu (value: boolean) { noContextMenu = value },
 
             drag,
+            interactionEnd,
             wheel,
             pinch,
             click,
@@ -297,7 +301,9 @@ namespace InputObserver {
             }
         }
 
-        function onTouchEnd (ev: TouchEvent) {}
+        function onTouchEnd (ev: TouchEvent) {
+            endDrag()
+        }
 
         function onTouchMove (ev: TouchEvent) {
             if (ev.touches.length === 1) {
@@ -331,6 +337,11 @@ namespace InputObserver {
 
         function onMouseUp (ev: MouseEvent) {
             onPointerUp(ev)
+            endDrag()
+        }
+
+        function endDrag() {
+            interactionEnd.next()
         }
 
         function onPointerDown (ev: PointerEvent) {