interaction-events.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { PickingId } from 'mol-geo/geometry/picking';
  7. import { EmptyLoci } from 'mol-model/loci';
  8. import { Representation } from 'mol-repr/representation';
  9. import InputObserver, { ModifiersKeys, ButtonsType } from 'mol-util/input/input-observer';
  10. import { RxEventHelper } from 'mol-util/rx-event-helper';
  11. type Canvas3D = import('../canvas3d').Canvas3D
  12. export class Canvas3dInteractionHelper {
  13. private ev = RxEventHelper.create();
  14. readonly events = {
  15. highlight: this.ev<import('../canvas3d').Canvas3D.HighlightEvent>(),
  16. click: this.ev<import('../canvas3d').Canvas3D.ClickEvent>(),
  17. };
  18. private cX = -1;
  19. private cY = -1;
  20. private lastX = -1;
  21. private lastY = -1;
  22. private id: PickingId | undefined = void 0;
  23. private currentIdentifyT = 0;
  24. private prevLoci: Representation.Loci = Representation.Loci.Empty;
  25. private prevT = 0;
  26. private inside = false;
  27. private buttons: ButtonsType = ButtonsType.create(0);
  28. private modifiers: ModifiersKeys = ModifiersKeys.None;
  29. private identify(isClick: boolean, t: number) {
  30. if (this.lastX !== this.cX && this.lastY !== this.cY) {
  31. this.id = this.canvasIdentify(this.cX, this.cY);
  32. this.lastX = this.cX;
  33. this.lastY = this.cY;
  34. }
  35. if (!this.id) return;
  36. if (isClick) {
  37. this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, modifiers: this.modifiers });
  38. return;
  39. }
  40. // only highlight the latest
  41. if (!this.inside || this.currentIdentifyT !== t) {
  42. return;
  43. }
  44. const loci = this.getLoci(this.id);
  45. if (!Representation.Loci.areEqual(this.prevLoci, loci)) {
  46. this.events.highlight.next({ current: loci, prev: this.prevLoci, modifiers: this.modifiers });
  47. this.prevLoci = loci;
  48. }
  49. }
  50. tick(t: number) {
  51. if (this.inside && t - this.prevT > 1000 / this.maxFps) {
  52. this.prevT = t;
  53. this.currentIdentifyT = t;
  54. this.identify(false, t);
  55. }
  56. }
  57. leave() {
  58. this.inside = false;
  59. if (this.prevLoci.loci !== EmptyLoci) {
  60. const prev = this.prevLoci;
  61. this.prevLoci = Representation.Loci.Empty;
  62. this.events.highlight.next({ current: this.prevLoci, prev });
  63. }
  64. }
  65. move(x: number, y: number, modifiers: ModifiersKeys) {
  66. this.inside = true;
  67. this.modifiers = modifiers;
  68. this.cX = x;
  69. this.cY = y;
  70. }
  71. select(x: number, y: number, buttons: ButtonsType, modifiers: ModifiersKeys) {
  72. this.cX = x;
  73. this.cY = y;
  74. this.buttons = buttons;
  75. this.modifiers = modifiers;
  76. this.identify(true, 0);
  77. }
  78. modify(modifiers: ModifiersKeys) {
  79. if (this.prevLoci.loci === EmptyLoci || ModifiersKeys.areEqual(modifiers, this.modifiers)) return;
  80. this.modifiers = modifiers;
  81. this.events.highlight.next({ current: this.prevLoci, prev: this.prevLoci, modifiers: this.modifiers });
  82. }
  83. dispose() {
  84. this.ev.dispose();
  85. }
  86. constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], input: InputObserver, private maxFps: number = 15) {
  87. input.move.subscribe(({x, y, inside, buttons, modifiers }) => {
  88. if (!inside || buttons) { return; }
  89. this.move(x, y, modifiers);
  90. });
  91. input.leave.subscribe(() => {
  92. this.leave();
  93. });
  94. input.click.subscribe(({x, y, buttons, modifiers }) => {
  95. this.select(x, y, buttons, modifiers);
  96. });
  97. input.modifiers.subscribe(modifiers => this.modify(modifiers));
  98. }
  99. }