vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
7.9 KiB

  1. var util = require('../../../util');
  2. var Hammer = require('../../../module/hammer');
  3. var hammerUtil = require('../../../hammerUtil');
  4. var keycharm = require('keycharm');
  5. class NavigationHandler {
  6. constructor(body, canvas) {
  7. this.body = body;
  8. this.canvas = canvas;
  9. this.iconsCreated = false;
  10. this.navigationHammers = [];
  11. this.boundFunctions = {};
  12. this.touchTime = 0;
  13. this.activated = false;
  14. this.body.emitter.on("release", this._stopMovement.bind(this));
  15. this.body.emitter.on("activate", () => {this.activated = true; this.configureKeyboardBindings();});
  16. this.body.emitter.on("deactivate", () => {this.activated = false; this.configureKeyboardBindings();});
  17. this.body.emitter.on("destroy", () => {if (this.keycharm !== undefined) {this.keycharm.destroy();}});
  18. this.options = {}
  19. }
  20. setOptions(options) {
  21. if (options !== undefined) {
  22. this.options = options;
  23. this.create();
  24. }
  25. }
  26. create() {
  27. if (this.options.navigationButtons === true) {
  28. if (this.iconsCreated === false) {
  29. this.loadNavigationElements();
  30. }
  31. }
  32. else if (this.iconsCreated === true) {
  33. this.cleanNavigation();
  34. }
  35. this.configureKeyboardBindings();
  36. }
  37. cleanNavigation() {
  38. // clean hammer bindings
  39. if (this.navigationHammers.length != 0) {
  40. for (var i = 0; i < this.navigationHammers.length; i++) {
  41. this.navigationHammers[i].destroy();
  42. }
  43. this.navigationHammers = [];
  44. }
  45. this._navigationReleaseOverload = function() {};
  46. // clean up previous navigation items
  47. if (this.navigationDOM && this.navigationDOM['wrapper'] && this.navigationDOM['wrapper'].parentNode) {
  48. this.navigationDOM['wrapper'].parentNode.removeChild(this.navigationDOM['wrapper']);
  49. }
  50. this.iconsCreated = false;
  51. }
  52. /**
  53. * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
  54. * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
  55. * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
  56. * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
  57. *
  58. * @private
  59. */
  60. loadNavigationElements() {
  61. this.cleanNavigation();
  62. this.navigationDOM = {};
  63. var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends'];
  64. var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_fit'];
  65. this.navigationDOM['wrapper'] = document.createElement('div');
  66. this.navigationDOM['wrapper'].className = 'vis-navigation';
  67. this.canvas.frame.appendChild(this.navigationDOM['wrapper']);
  68. for (var i = 0; i < navigationDivs.length; i++) {
  69. this.navigationDOM[navigationDivs[i]] = document.createElement('div');
  70. this.navigationDOM[navigationDivs[i]].className = 'vis-button vis-' + navigationDivs[i];
  71. this.navigationDOM['wrapper'].appendChild(this.navigationDOM[navigationDivs[i]]);
  72. var hammer = new Hammer(this.navigationDOM[navigationDivs[i]]);
  73. if (navigationDivActions[i] === "_fit") {
  74. hammerUtil.onTouch(hammer, this._fit.bind(this));
  75. }
  76. else {
  77. hammerUtil.onTouch(hammer, this.bindToRedraw.bind(this,navigationDivActions[i]));
  78. }
  79. this.navigationHammers.push(hammer);
  80. }
  81. this.iconsCreated = true;
  82. }
  83. bindToRedraw(action) {
  84. if (this.boundFunctions[action] === undefined) {
  85. this.boundFunctions[action] = this[action].bind(this);
  86. this.body.emitter.on("initRedraw", this.boundFunctions[action]);
  87. this.body.emitter.emit("_startRendering");
  88. }
  89. }
  90. unbindFromRedraw(action) {
  91. if (this.boundFunctions[action] !== undefined) {
  92. this.body.emitter.off("initRedraw", this.boundFunctions[action]);
  93. this.body.emitter.emit("_stopRendering");
  94. delete this.boundFunctions[action];
  95. }
  96. }
  97. /**
  98. * this stops all movement induced by the navigation buttons
  99. *
  100. * @private
  101. */
  102. _fit() {
  103. if (new Date().valueOf() - this.touchTime > 700) { // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
  104. this.body.emitter.emit("fit", {duration: 700});
  105. this.touchTime = new Date().valueOf();
  106. }
  107. }
  108. /**
  109. * this stops all movement induced by the navigation buttons
  110. *
  111. * @private
  112. */
  113. _stopMovement() {
  114. for (let boundAction in this.boundFunctions) {
  115. if (this.boundFunctions.hasOwnProperty(boundAction)) {
  116. this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
  117. this.body.emitter.emit("_stopRendering");
  118. }
  119. }
  120. this.boundFunctions = {};
  121. }
  122. _moveUp() {this.body.view.translation.y += this.options.keyboard.speed.y;}
  123. _moveDown() {this.body.view.translation.y -= this.options.keyboard.speed.y;}
  124. _moveLeft() {this.body.view.translation.x += this.options.keyboard.speed.x;}
  125. _moveRight(){this.body.view.translation.x -= this.options.keyboard.speed.x;}
  126. _zoomIn() {this.body.view.scale *= 1+this.options.keyboard.speed.zoom;}
  127. _zoomOut() {this.body.view.scale /= 1+this.options.keyboard.speed.zoom;}
  128. /**
  129. * bind all keys using keycharm.
  130. */
  131. configureKeyboardBindings() {
  132. if (this.keycharm !== undefined) {
  133. this.keycharm.destroy();
  134. }
  135. if (this.options.keyboard.enabled === true) {
  136. if (this.options.keyboard.bindToWindow === true) {
  137. this.keycharm = keycharm({container: window, preventDefault: false});
  138. }
  139. else {
  140. this.keycharm = keycharm({container: this.canvas.frame, preventDefault: false});
  141. }
  142. this.keycharm.reset();
  143. if (this.activated === true) {
  144. this.keycharm.bind("up", this.bindToRedraw.bind(this, "_moveUp"), "keydown");
  145. this.keycharm.bind("down", this.bindToRedraw.bind(this, "_moveDown"), "keydown");
  146. this.keycharm.bind("left", this.bindToRedraw.bind(this, "_moveLeft"), "keydown");
  147. this.keycharm.bind("right", this.bindToRedraw.bind(this, "_moveRight"), "keydown");
  148. this.keycharm.bind("=", this.bindToRedraw.bind(this, "_zoomIn"), "keydown");
  149. this.keycharm.bind("num+", this.bindToRedraw.bind(this, "_zoomIn"), "keydown");
  150. this.keycharm.bind("num-", this.bindToRedraw.bind(this, "_zoomOut"), "keydown");
  151. this.keycharm.bind("-", this.bindToRedraw.bind(this, "_zoomOut"), "keydown");
  152. this.keycharm.bind("[", this.bindToRedraw.bind(this, "_zoomOut"), "keydown");
  153. this.keycharm.bind("]", this.bindToRedraw.bind(this, "_zoomIn"), "keydown");
  154. this.keycharm.bind("pageup", this.bindToRedraw.bind(this, "_zoomIn"), "keydown");
  155. this.keycharm.bind("pagedown", this.bindToRedraw.bind(this, "_zoomOut"), "keydown");
  156. this.keycharm.bind("up", this.unbindFromRedraw.bind(this, "_moveUp"), "keyup");
  157. this.keycharm.bind("down", this.unbindFromRedraw.bind(this, "_moveDown"), "keyup");
  158. this.keycharm.bind("left", this.unbindFromRedraw.bind(this, "_moveLeft"), "keyup");
  159. this.keycharm.bind("right", this.unbindFromRedraw.bind(this, "_moveRight"), "keyup");
  160. this.keycharm.bind("=", this.unbindFromRedraw.bind(this, "_zoomIn"), "keyup");
  161. this.keycharm.bind("num+", this.unbindFromRedraw.bind(this, "_zoomIn"), "keyup");
  162. this.keycharm.bind("num-", this.unbindFromRedraw.bind(this, "_zoomOut"), "keyup");
  163. this.keycharm.bind("-", this.unbindFromRedraw.bind(this, "_zoomOut"), "keyup");
  164. this.keycharm.bind("[", this.unbindFromRedraw.bind(this, "_zoomOut"), "keyup");
  165. this.keycharm.bind("]", this.unbindFromRedraw.bind(this, "_zoomIn"), "keyup");
  166. this.keycharm.bind("pageup", this.unbindFromRedraw.bind(this, "_zoomIn"), "keyup");
  167. this.keycharm.bind("pagedown", this.unbindFromRedraw.bind(this, "_zoomOut"), "keyup");
  168. }
  169. }
  170. }
  171. }
  172. export default NavigationHandler;