sigma.canvas.edges.dotCurvedArrow.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. ;(function() {
  2. 'use strict';
  3. sigma.utils.pkg('sigma.canvas.edges');
  4. /**
  5. * This edge renderer will display edges as curves with arrow heading.
  6. *
  7. * @param {object} edge The edge object.
  8. * @param {object} source node The edge source node.
  9. * @param {object} target node The edge target node.
  10. * @param {CanvasRenderingContext2D} context The canvas context.
  11. * @param {configurable} settings The settings function.
  12. */
  13. sigma.canvas.edges.dotCurvedArrow =
  14. function(edge, source, target, context, settings) {
  15. var color = edge.color,
  16. prefix = settings('prefix') || '',
  17. edgeColor = settings('edgeColor'),
  18. defaultNodeColor = settings('defaultNodeColor'),
  19. defaultEdgeColor = settings('defaultEdgeColor'),
  20. cp = {},
  21. size = edge[prefix + 'size'] || 1,
  22. count = edge.count || 0,
  23. tSize = target[prefix + 'size'],
  24. sX = source[prefix + 'x'],
  25. sY = source[prefix + 'y'],
  26. tX = target[prefix + 'x'],
  27. tY = target[prefix + 'y'],
  28. aSize = Math.max(size * 2.5, settings('minArrowSize')),
  29. d,
  30. aX,
  31. aY,
  32. vX,
  33. vY;
  34. cp = (source.id === target.id) ?
  35. sigma.utils.getSelfLoopControlPoints(sX, sY, tSize, count) :
  36. sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY, count);
  37. if (source.id === target.id) {
  38. d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2));
  39. aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d;
  40. aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d;
  41. vX = (tX - cp.x1) * aSize / d;
  42. vY = (tY - cp.y1) * aSize / d;
  43. }
  44. else {
  45. d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2));
  46. aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d;
  47. aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d;
  48. vX = (tX - cp.x) * aSize / d;
  49. vY = (tY - cp.y) * aSize / d;
  50. }
  51. if (!color)
  52. switch (edgeColor) {
  53. case 'source':
  54. color = source.color || defaultNodeColor;
  55. break;
  56. case 'target':
  57. color = target.color || defaultNodeColor;
  58. break;
  59. default:
  60. color = defaultEdgeColor;
  61. break;
  62. }
  63. context.strokeStyle = color;
  64. context.lineWidth = size;
  65. context.beginPath();
  66. context.moveTo(sX, sY);
  67. if (source.id === target.id) {
  68. context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY);
  69. } else {
  70. context.quadraticCurveTo(cp.x, cp.y, aX, aY);
  71. }
  72. context.stroke();
  73. context.fillStyle = color;
  74. context.beginPath();
  75. context.moveTo(aX + vX, aY + vY);
  76. context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
  77. context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
  78. context.lineTo(aX + vX, aY + vY);
  79. context.closePath();
  80. context.fill();
  81. if(edge.sourceDotColor != undefined || edge.targetDotColor != undefined) {
  82. var dotOffset = edge.dotOffset || 3;
  83. var dotSize = edge.dotSize || 1;
  84. dotSize = size*dotSize;
  85. dotOffset = dotOffset*tSize;
  86. if(edge.sourceDotColor != undefined) {
  87. createDot(context, sX, sY, cp, tX, tY, dotOffset, dotSize, edge.sourceDotColor);
  88. }
  89. if (edge.targetDotColor != undefined){
  90. createDot(context, tX, tY, cp, sX, sY, dotOffset, dotSize, edge.targetDotColor);
  91. }
  92. }
  93. };
  94. function createDot(context, sX, sY, cp, tX, tY, offset, size, color) {
  95. context.beginPath();
  96. context.fillStyle = color;
  97. var dot = getPointOnBezier(sX, sY, cp.x, cp.y, tX, tY,
  98. offset);
  99. context.arc(dot.x, dot.y, size * 3, 0, 2 * Math.PI,
  100. false);
  101. context.fill();
  102. }
  103. function getQBezierValue(t, p1, p2, p3) {
  104. var iT = 1 - t;
  105. return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
  106. }
  107. function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
  108. return {
  109. x:getQBezierValue(position, startX, cpX, endX),
  110. y:getQBezierValue(position, startY, cpY, endY)
  111. };
  112. }
  113. function getDistanceBetweenPoints(x1, y1, x2, y2){
  114. return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
  115. }
  116. /* Function to get a point on a bezier curve a certain distance away from
  117. its source. Needed since the position on a beziercurve is given to the
  118. formula as a percentage (t).*/
  119. function getPointOnBezier(startX, startY, cpX, cpY, endX, endY, distance){
  120. var bestT = 0;
  121. var bestAccuracy = 1000;
  122. var stepSize = 0.001;
  123. for(var t = 0; t<1; t+=stepSize){
  124. var currentPoint = getQuadraticCurvePoint(startX, startY, cpX, cpY,
  125. endX, endY, t);
  126. var currentDistance = getDistanceBetweenPoints(startX, startY,
  127. currentPoint.x, currentPoint.y);
  128. if(Math.abs(currentDistance-distance) < bestAccuracy){
  129. bestAccuracy = Math.abs(currentDistance-distance);
  130. bestT = t;
  131. }
  132. }
  133. return getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, bestT);
  134. }
  135. })();