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.

231 lines
5.5 KiB

  1. /** ============================================================================
  2. * Location of all the endpoint drawing routines.
  3. *
  4. * Every endpoint has its own drawing routine, which contains an endpoint definition.
  5. *
  6. * The endpoint definitions must have the following properies:
  7. *
  8. * - (0,0) is the connection point to the node it attaches to
  9. * - The endpoints are orientated to the positive x-direction
  10. * - The length of the endpoint is at most 1
  11. *
  12. * As long as the endpoint classes remain simple and not too numerous, they will
  13. * be contained within this module.
  14. * All classes here except `EndPoints` should be considered as private to this module.
  15. *
  16. * -----------------------------------------------------------------------------
  17. * ### Further Actions
  18. *
  19. * After adding a new endpoint here, you also need to do the following things:
  20. *
  21. * - Add the new endpoint name to `network/options.js` in array `endPoints`.
  22. * - Add the new endpoint name to the documentation.
  23. * Scan for 'arrows.to.type` and add it to the description.
  24. * - Add the endpoint to the examples. At the very least, add it to example
  25. * `edgeStyles/arrowTypes`.
  26. * ============================================================================= */
  27. // NOTE: When a typedef is isolated in a separate comment block, an actual description is generated for it,
  28. // using the rest of the commenting in the code block. Usage of typedef in other comments then
  29. // link to there. TIL.
  30. //
  31. // Also noteworthy, all typedef's set up in this manner are collected in a single, global page 'global.html'.
  32. // In other words, it doesn't matter *where* the typedef's are defined in the code.
  33. //
  34. //
  35. // TODO: add descriptive commenting to given typedef's
  36. /**
  37. * @typedef {{type:string, point:Point, angle:number, length:number}} ArrowData
  38. *
  39. * Object containing instantiation data for a given endpoint.
  40. */
  41. /**
  42. * @typedef {{x:number, y:number}} Point
  43. *
  44. * A point in view-coordinates.
  45. */
  46. /**
  47. * Common methods for endpoints
  48. *
  49. * @class
  50. */
  51. class EndPoint {
  52. /**
  53. * Apply transformation on points for display.
  54. *
  55. * The following is done:
  56. * - rotate by the specified angle
  57. * - multiply the (normalized) coordinates by the passed length
  58. * - offset by the target coordinates
  59. *
  60. * @param {Array<Point>} points
  61. * @param {ArrowData} arrowData
  62. * @static
  63. */
  64. static transform(points, arrowData) {
  65. if (!(points instanceof Array)) {
  66. points = [points];
  67. }
  68. var x = arrowData.point.x;
  69. var y = arrowData.point.y;
  70. var angle = arrowData.angle
  71. var length = arrowData.length;
  72. for(var i = 0; i < points.length; ++i) {
  73. var p = points[i];
  74. var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
  75. var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
  76. p.x = x + length*xt;
  77. p.y = y + length*yt;
  78. }
  79. }
  80. /**
  81. * Draw a closed path using the given real coordinates.
  82. *
  83. * @param {CanvasRenderingContext2D} ctx
  84. * @param {Array.<Point>} points
  85. * @static
  86. */
  87. static drawPath(ctx, points) {
  88. ctx.beginPath();
  89. ctx.moveTo(points[0].x, points[0].y);
  90. for(var i = 1; i < points.length; ++i) {
  91. ctx.lineTo(points[i].x, points[i].y);
  92. }
  93. ctx.closePath();
  94. }
  95. }
  96. /**
  97. * Drawing methods for the arrow endpoint.
  98. * @extends EndPoint
  99. */
  100. class Arrow extends EndPoint {
  101. /**
  102. * Draw this shape at the end of a line.
  103. *
  104. * @param {CanvasRenderingContext2D} ctx
  105. * @param {ArrowData} arrowData
  106. * @static
  107. */
  108. static draw(ctx, arrowData) {
  109. // Normalized points of closed path, in the order that they should be drawn.
  110. // (0, 0) is the attachment point, and the point around which should be rotated
  111. var points = [
  112. { x: 0 , y: 0 },
  113. { x:-1 , y: 0.3},
  114. { x:-0.9, y: 0 },
  115. { x:-1 , y:-0.3},
  116. ];
  117. EndPoint.transform(points, arrowData);
  118. EndPoint.drawPath(ctx, points);
  119. }
  120. }
  121. /**
  122. * Drawing methods for the circle endpoint.
  123. */
  124. class Circle {
  125. /**
  126. * Draw this shape at the end of a line.
  127. *
  128. * @param {CanvasRenderingContext2D} ctx
  129. * @param {ArrowData} arrowData
  130. * @static
  131. */
  132. static draw(ctx, arrowData) {
  133. var point = {x:-0.4, y:0};
  134. EndPoint.transform(point, arrowData);
  135. ctx.circle(point.x, point.y, arrowData.length*0.4);
  136. }
  137. }
  138. /**
  139. * Drawing methods for the bar endpoint.
  140. */
  141. class Bar {
  142. /**
  143. * Draw this shape at the end of a line.
  144. *
  145. * @param {CanvasRenderingContext2D} ctx
  146. * @param {ArrowData} arrowData
  147. * @static
  148. */
  149. static draw(ctx, arrowData) {
  150. /*
  151. var points = [
  152. {x:0, y:0.5},
  153. {x:0, y:-0.5}
  154. ];
  155. EndPoint.transform(points, arrowData);
  156. ctx.beginPath();
  157. ctx.moveTo(points[0].x, points[0].y);
  158. ctx.lineTo(points[1].x, points[1].y);
  159. ctx.stroke();
  160. */
  161. var points = [
  162. {x:0, y:0.5},
  163. {x:0, y:-0.5},
  164. {x:-0.15, y:-0.5},
  165. {x:-0.15, y:0.5},
  166. ];
  167. EndPoint.transform(points, arrowData);
  168. EndPoint.drawPath(ctx, points);
  169. }
  170. }
  171. /**
  172. * Drawing methods for the endpoints.
  173. */
  174. class EndPoints {
  175. /**
  176. * Draw an endpoint
  177. *
  178. * @param {CanvasRenderingContext2D} ctx
  179. * @param {ArrowData} arrowData
  180. * @static
  181. */
  182. static draw(ctx, arrowData) {
  183. var type;
  184. if (arrowData.type) {
  185. type = arrowData.type.toLowerCase();
  186. }
  187. switch (type) {
  188. case 'circle':
  189. Circle.draw(ctx, arrowData);
  190. break;
  191. case 'bar':
  192. Bar.draw(ctx, arrowData);
  193. break;
  194. case 'arrow': // fall-through
  195. default:
  196. Arrow.draw(ctx, arrowData);
  197. }
  198. }
  199. }
  200. export default EndPoints;