|
@@ -1,36 +1,41 @@
|
|
|
/**
|
|
|
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
*
|
|
|
* @author David Sehnal <david.sehnal@gmail.com>
|
|
|
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
|
*/
|
|
|
|
|
|
import { PickingId } from '../../mol-geo/geometry/picking';
|
|
|
-import { EmptyLoci } from '../../mol-model/loci';
|
|
|
import { Representation } from '../../mol-repr/representation';
|
|
|
import InputObserver, { ModifiersKeys, ButtonsType } from '../../mol-util/input/input-observer';
|
|
|
import { RxEventHelper } from '../../mol-util/rx-event-helper';
|
|
|
+import { Vec2 } from '../../mol-math/linear-algebra';
|
|
|
|
|
|
type Canvas3D = import('../canvas3d').Canvas3D
|
|
|
type HoverEvent = import('../canvas3d').Canvas3D.HoverEvent
|
|
|
+type DragEvent = import('../canvas3d').Canvas3D.DragEvent
|
|
|
type ClickEvent = import('../canvas3d').Canvas3D.ClickEvent
|
|
|
|
|
|
+const enum InputEvent { Move, Click, Drag }
|
|
|
+
|
|
|
export class Canvas3dInteractionHelper {
|
|
|
private ev = RxEventHelper.create();
|
|
|
|
|
|
readonly events = {
|
|
|
hover: this.ev<HoverEvent>(),
|
|
|
+ drag: this.ev<DragEvent>(),
|
|
|
click: this.ev<ClickEvent>(),
|
|
|
};
|
|
|
|
|
|
- private cX = -1;
|
|
|
- private cY = -1;
|
|
|
-
|
|
|
- private lastX = -1;
|
|
|
- private lastY = -1;
|
|
|
+ private startX = -1;
|
|
|
+ private startY = -1;
|
|
|
+ private endX = -1;
|
|
|
+ private endY = -1;
|
|
|
|
|
|
private id: PickingId | undefined = void 0;
|
|
|
|
|
|
private currentIdentifyT = 0;
|
|
|
+ private isInteracting = false;
|
|
|
|
|
|
private prevLoci: Representation.Loci = Representation.Loci.Empty;
|
|
|
private prevT = 0;
|
|
@@ -41,17 +46,34 @@ export class Canvas3dInteractionHelper {
|
|
|
private button: ButtonsType.Flag = ButtonsType.create(0);
|
|
|
private modifiers: ModifiersKeys = ModifiersKeys.None;
|
|
|
|
|
|
- private identify(isClick: boolean, t: number) {
|
|
|
- if (this.lastX !== this.cX || this.lastY !== this.cY) {
|
|
|
- this.id = this.canvasIdentify(this.cX, this.cY);
|
|
|
- this.lastX = this.cX;
|
|
|
- this.lastY = this.cY;
|
|
|
+ private identify(e: InputEvent, t: number) {
|
|
|
+ const xyChanged = this.startX !== this.endX || this.startY !== this.endY;
|
|
|
+
|
|
|
+ if (e === InputEvent.Drag) {
|
|
|
+ if (xyChanged && !Representation.Loci.isEmpty(this.prevLoci)) {
|
|
|
+ this.events.drag.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers, pageStart: Vec2.create(this.startX, this.startY), pageEnd: Vec2.create(this.endX, this.endY) });
|
|
|
+
|
|
|
+ this.startX = this.endX;
|
|
|
+ this.startY = this.endY;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (xyChanged) {
|
|
|
+ this.id = this.canvasIdentify(this.endX, this.endY);
|
|
|
+ this.startX = this.endX;
|
|
|
+ this.startY = this.endY;
|
|
|
}
|
|
|
|
|
|
- if (!this.id) return;
|
|
|
+ if (!this.id) {
|
|
|
+ this.prevLoci = Representation.Loci.Empty;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (isClick) {
|
|
|
- this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, button: this.button, modifiers: this.modifiers });
|
|
|
+ if (e === InputEvent.Click) {
|
|
|
+ const loci = this.getLoci(this.id);
|
|
|
+ this.events.click.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
|
|
|
+ this.prevLoci = loci;
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -71,13 +93,13 @@ export class Canvas3dInteractionHelper {
|
|
|
if (this.inside && t - this.prevT > 1000 / this.maxFps) {
|
|
|
this.prevT = t;
|
|
|
this.currentIdentifyT = t;
|
|
|
- this.identify(false, t);
|
|
|
+ this.identify(this.isInteracting ? InputEvent.Drag : InputEvent.Move, t);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
leave() {
|
|
|
this.inside = false;
|
|
|
- if (this.prevLoci.loci !== EmptyLoci) {
|
|
|
+ if (Representation.Loci.isEmpty(this.prevLoci)) {
|
|
|
this.prevLoci = Representation.Loci.Empty;
|
|
|
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
|
|
|
}
|
|
@@ -88,21 +110,30 @@ export class Canvas3dInteractionHelper {
|
|
|
this.buttons = buttons;
|
|
|
this.button = button;
|
|
|
this.modifiers = modifiers;
|
|
|
- this.cX = x;
|
|
|
- this.cY = y;
|
|
|
+ this.endX = x;
|
|
|
+ this.endY = y;
|
|
|
+ }
|
|
|
+
|
|
|
+ click(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
|
|
|
+ this.endX = x;
|
|
|
+ this.endY = y;
|
|
|
+ this.buttons = buttons;
|
|
|
+ this.button = button;
|
|
|
+ this.modifiers = modifiers;
|
|
|
+ this.identify(InputEvent.Click, 0);
|
|
|
}
|
|
|
|
|
|
- select(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
|
|
|
- this.cX = x;
|
|
|
- this.cY = y;
|
|
|
+ drag(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
|
|
|
+ this.endX = x;
|
|
|
+ this.endY = y;
|
|
|
this.buttons = buttons;
|
|
|
this.button = button;
|
|
|
this.modifiers = modifiers;
|
|
|
- this.identify(true, 0);
|
|
|
+ this.identify(InputEvent.Drag, 0);
|
|
|
}
|
|
|
|
|
|
modify(modifiers: ModifiersKeys) {
|
|
|
- if (this.prevLoci.loci === EmptyLoci || ModifiersKeys.areEqual(modifiers, this.modifiers)) return;
|
|
|
+ if (Representation.Loci.isEmpty(this.prevLoci) || ModifiersKeys.areEqual(modifiers, this.modifiers)) return;
|
|
|
this.modifiers = modifiers;
|
|
|
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
|
|
|
}
|
|
@@ -112,17 +143,31 @@ export class Canvas3dInteractionHelper {
|
|
|
}
|
|
|
|
|
|
constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], input: InputObserver, private maxFps: number = 30) {
|
|
|
+ input.drag.subscribe(({x, y, buttons, button, modifiers }) => {
|
|
|
+ this.isInteracting = true;
|
|
|
+ // console.log('drag');
|
|
|
+ this.drag(x, y, buttons, button, modifiers);
|
|
|
+ });
|
|
|
+
|
|
|
input.move.subscribe(({x, y, inside, buttons, button, modifiers }) => {
|
|
|
- if (!inside) return;
|
|
|
+ if (!inside || this.isInteracting) return;
|
|
|
+ // console.log('move');
|
|
|
this.move(x, y, buttons, button, modifiers);
|
|
|
});
|
|
|
|
|
|
input.leave.subscribe(() => {
|
|
|
+ // console.log('leave');
|
|
|
this.leave();
|
|
|
});
|
|
|
|
|
|
input.click.subscribe(({x, y, buttons, button, modifiers }) => {
|
|
|
- this.select(x, y, buttons, button, modifiers);
|
|
|
+ // console.log('click');
|
|
|
+ this.click(x, y, buttons, button, modifiers);
|
|
|
+ });
|
|
|
+
|
|
|
+ input.interactionEnd.subscribe(() => {
|
|
|
+ // console.log('interactionEnd');
|
|
|
+ this.isInteracting = false;
|
|
|
});
|
|
|
|
|
|
input.modifiers.subscribe(modifiers => this.modify(modifiers));
|