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.

225 lines
7.7 KiB

  1. var Hammer = require('../../module/hammer');
  2. var hammerUtil = require('../../hammerUtil');
  3. var util = require('../../util');
  4. /**
  5. * Create the main frame for the Network.
  6. * This function is executed once when a Network object is created. The frame
  7. * contains a canvas, and this canvas contains all objects like the axis and
  8. * nodes.
  9. * @private
  10. */
  11. class Canvas {
  12. constructor(body) {
  13. this.body = body;
  14. this.options = {};
  15. this.defaultOptions = {
  16. width:'100%',
  17. height:'100%'
  18. }
  19. util.extend(this.options, this.defaultOptions);
  20. this.body.emitter.once("resize", (obj) => {this.body.view.translation.x = obj.width * 0.5; this.body.view.translation.y = obj.height * 0.5;});
  21. this.pixelRatio = 1;
  22. }
  23. setOptions(options) {
  24. if (options !== undefined) {
  25. util.deepExtend(this.options, options);
  26. }
  27. }
  28. create() {
  29. // remove all elements from the container element.
  30. while (this.body.container.hasChildNodes()) {
  31. this.body.container.removeChild(this.body.container.firstChild);
  32. }
  33. this.frame = document.createElement('div');
  34. this.frame.className = 'vis network-frame';
  35. this.frame.style.position = 'relative';
  36. this.frame.style.overflow = 'hidden';
  37. this.frame.tabIndex = 900;
  38. //////////////////////////////////////////////////////////////////
  39. this.frame.canvas = document.createElement("canvas");
  40. this.frame.canvas.style.position = 'relative';
  41. this.frame.appendChild(this.frame.canvas);
  42. if (!this.frame.canvas.getContext) {
  43. var noCanvas = document.createElement( 'DIV' );
  44. noCanvas.style.color = 'red';
  45. noCanvas.style.fontWeight = 'bold' ;
  46. noCanvas.style.padding = '10px';
  47. noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
  48. this.frame.canvas.appendChild(noCanvas);
  49. }
  50. else {
  51. var ctx = this.frame.canvas.getContext("2d");
  52. this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio ||
  53. ctx.mozBackingStorePixelRatio ||
  54. ctx.msBackingStorePixelRatio ||
  55. ctx.oBackingStorePixelRatio ||
  56. ctx.backingStorePixelRatio || 1);
  57. this.frame.canvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
  58. }
  59. // add the frame to the container element
  60. this.body.container.appendChild(this.frame);
  61. this.body.view.scale = 1;
  62. this.body.view.translation = {x: 0.5 * this.frame.canvas.clientWidth,y: 0.5 * this.frame.canvas.clientHeight};
  63. this._bindHammer();
  64. }
  65. /**
  66. * This function binds hammer, it can be repeated over and over due to the uniqueness check.
  67. * @private
  68. */
  69. _bindHammer() {
  70. if (this.hammer !== undefined) {
  71. this.hammer.destroy();
  72. }
  73. this.drag = {};
  74. this.pinch = {};
  75. this.hammer = new Hammer(this.frame.canvas);
  76. this.hammer.on('tap', this.body.eventListeners.onTap );
  77. this.hammer.on('doubletap', this.body.eventListeners.onDoubleTap );
  78. this.hammer.on('press', this.body.eventListeners.onHold );
  79. hammerUtil.onTouch(this.hammer, this.body.eventListeners.onTouch );
  80. this.hammer.on('panstart', this.body.eventListeners.onDragStart );
  81. this.hammer.on('panmove', this.body.eventListeners.onDrag );
  82. this.hammer.on('panend', this.body.eventListeners.onDragEnd );
  83. this.hammer.on('pinch', function() {console.log("pinching!");});//this.body.eventListeners.onPinch );
  84. // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
  85. this.frame.canvas.addEventListener('mousewheel', this.body.eventListeners.onMouseWheel);
  86. this.frame.canvas.addEventListener('DOMMouseScroll', this.body.eventListeners.onMouseWheel);
  87. this.frame.canvas.addEventListener('mousemove', this.body.eventListeners.onMouseMove);
  88. this.hammerFrame = new Hammer(this.frame);
  89. hammerUtil.onRelease(this.hammerFrame, this.body.eventListeners.onRelease);
  90. }
  91. /**
  92. * Set a new size for the network
  93. * @param {string} width Width in pixels or percentage (for example '800px'
  94. * or '50%')
  95. * @param {string} height Height in pixels or percentage (for example '400px'
  96. * or '30%')
  97. */
  98. setSize(width = this.options.width, height = this.options.height) {
  99. var emitEvent = false;
  100. var oldWidth = this.frame.canvas.width;
  101. var oldHeight = this.frame.canvas.height;
  102. if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
  103. this.frame.style.width = width;
  104. this.frame.style.height = height;
  105. this.frame.canvas.style.width = '100%';
  106. this.frame.canvas.style.height = '100%';
  107. this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio;
  108. this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio;
  109. this.options.width = width;
  110. this.options.height = height;
  111. emitEvent = true;
  112. }
  113. else {
  114. // this would adapt the width of the canvas to the width from 100% if and only if
  115. // there is a change.
  116. if (this.frame.canvas.width != this.frame.canvas.clientWidth * this.pixelRatio) {
  117. this.frame.canvas.width = this.frame.canvas.clientWidth * this.pixelRatio;
  118. emitEvent = true;
  119. }
  120. if (this.frame.canvas.height != this.frame.canvas.clientHeight * this.pixelRatio) {
  121. this.frame.canvas.height = this.frame.canvas.clientHeight * this.pixelRatio;
  122. emitEvent = true;
  123. }
  124. }
  125. if (emitEvent === true) {
  126. this.body.emitter.emit('resize', {width:this.frame.canvas.width / this.pixelRatio, height:this.frame.canvas.height / this.pixelRatio, oldWidth: oldWidth / this.pixelRatio, oldHeight: oldHeight / this.pixelRatio});
  127. }
  128. };
  129. /**
  130. * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
  131. * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
  132. * @param {number} x
  133. * @returns {number}
  134. * @private
  135. */
  136. _XconvertDOMtoCanvas(x) {
  137. return (x - this.body.view.translation.x) / this.body.view.scale;
  138. }
  139. /**
  140. * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
  141. * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
  142. * @param {number} x
  143. * @returns {number}
  144. * @private
  145. */
  146. _XconvertCanvasToDOM(x) {
  147. return x * this.body.view.scale + this.body.view.translation.x;
  148. }
  149. /**
  150. * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
  151. * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
  152. * @param {number} y
  153. * @returns {number}
  154. * @private
  155. */
  156. _YconvertDOMtoCanvas(y) {
  157. return (y - this.body.view.translation.y) / this.body.view.scale;
  158. }
  159. /**
  160. * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
  161. * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
  162. * @param {number} y
  163. * @returns {number}
  164. * @private
  165. */
  166. _YconvertCanvasToDOM(y) {
  167. return y * this.body.view.scale + this.body.view.translation.y;
  168. }
  169. /**
  170. *
  171. * @param {object} pos = {x: number, y: number}
  172. * @returns {{x: number, y: number}}
  173. * @constructor
  174. */
  175. canvasToDOM (pos) {
  176. return {x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y)};
  177. }
  178. /**
  179. *
  180. * @param {object} pos = {x: number, y: number}
  181. * @returns {{x: number, y: number}}
  182. * @constructor
  183. */
  184. DOMtoCanvas (pos) {
  185. return {x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y)};
  186. }
  187. }
  188. export {Canvas};