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.

154 lines
4.5 KiB

  1. import BezierEdgeBase from './util/BezierEdgeBase'
  2. class BezierEdgeDynamic extends BezierEdgeBase {
  3. constructor(id, options, body, labelModule) {
  4. //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
  5. super(id, options, body, labelModule); // --> this calls the setOptions below
  6. this._boundFunction = () => {this.positionBezierNode();};
  7. this.body.emitter.on("_repositionBezierNodes", this._boundFunction);
  8. }
  9. setOptions(options) {
  10. // check if the physics has changed.
  11. let physicsChange = false;
  12. if (this.options.physics !== options.physics) {
  13. physicsChange = true;
  14. }
  15. // set the options and the to and from nodes
  16. this.options = options;
  17. this.from = this.body.nodes[this.options.from];
  18. this.to = this.body.nodes[this.options.to];
  19. // setup the support node and connect
  20. this.setupSupportNode();
  21. this.connect();
  22. // when we change the physics state of the edge, we reposition the support node.
  23. if (physicsChange === true) {
  24. this.via.setOptions({physics: this.options.physics})
  25. this.positionBezierNode();
  26. }
  27. }
  28. connect() {
  29. this.from = this.body.nodes[this.options.from];
  30. this.to = this.body.nodes[this.options.to];
  31. if (this.from === undefined || this.to === undefined || this.options.physics === false) {
  32. this.via.setOptions({physics:false})
  33. }
  34. else {
  35. // fix weird behaviour where a self referencing node has physics enabled
  36. if (this.from.id === this.to.id) {
  37. this.via.setOptions({physics: false})
  38. }
  39. else {
  40. this.via.setOptions({physics: true})
  41. }
  42. }
  43. }
  44. /**
  45. * remove the support nodes
  46. * @returns {boolean}
  47. */
  48. cleanup() {
  49. this.body.emitter.off("_repositionBezierNodes", this._boundFunction);
  50. if (this.via !== undefined) {
  51. delete this.body.nodes[this.via.id];
  52. this.via = undefined;
  53. return true;
  54. }
  55. return false;
  56. }
  57. /**
  58. * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but
  59. * are used for the force calculation.
  60. *
  61. * The changed data is not called, if needed, it is returned by the main edge constructor.
  62. * @private
  63. */
  64. setupSupportNode() {
  65. if (this.via === undefined) {
  66. var nodeId = "edgeId:" + this.id;
  67. var properties = {
  68. shape: 'circle',
  69. physics: true,
  70. hidden: true
  71. };
  72. var idField = this.body.data.nodes._fieldId;
  73. properties[idField] = nodeId;
  74. var node = this.body.functions.createNode(properties);
  75. this.body.nodes[nodeId] = node;
  76. this.via = node;
  77. this.via.parentEdgeId = this.id;
  78. this.positionBezierNode();
  79. }
  80. }
  81. positionBezierNode() {
  82. if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
  83. this.via.x = 0.5 * (this.from.x + this.to.x);
  84. this.via.y = 0.5 * (this.from.y + this.to.y);
  85. }
  86. else if (this.via !== undefined) {
  87. this.via.x = 0;
  88. this.via.y = 0;
  89. }
  90. }
  91. /**
  92. * Draw a line between two nodes
  93. * @param {CanvasRenderingContext2D} ctx
  94. * @private
  95. */
  96. _line(ctx, viaNode) {
  97. // draw a straight line
  98. ctx.beginPath();
  99. ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
  100. // fallback to normal straight edges
  101. if (viaNode.x === undefined) {
  102. ctx.lineTo(this.toPoint.x, this.toPoint.y);
  103. }
  104. else {
  105. ctx.quadraticCurveTo(viaNode.x, viaNode.y, this.toPoint.x, this.toPoint.y);
  106. }
  107. // draw shadow if enabled
  108. this.enableShadow(ctx);
  109. ctx.stroke();
  110. this.disableShadow(ctx);
  111. }
  112. getViaNode() {
  113. return this.via;
  114. }
  115. /**
  116. * Combined function of pointOnLine and pointOnBezier. This gives the coordinates of a point on the line at a certain percentage of the way
  117. * @param percentage
  118. * @param viaNode
  119. * @returns {{x: number, y: number}}
  120. * @private
  121. */
  122. getPoint(percentage, viaNode = this.via) {
  123. let t = percentage;
  124. let x = Math.pow(1 - t, 2) * this.fromPoint.x + (2 * t * (1 - t)) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
  125. let y = Math.pow(1 - t, 2) * this.fromPoint.y + (2 * t * (1 - t)) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
  126. return {x: x, y: y};
  127. }
  128. _findBorderPosition(nearNode, ctx) {
  129. return this._findBorderPositionBezier(nearNode, ctx, this.via);
  130. }
  131. _getDistanceToEdge(x1, y1, x2, y2, x3, y3) { // x3,y3 is the point
  132. return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
  133. }
  134. }
  135. export default BezierEdgeDynamic;