in airavata-kubernetes/web-console/src/assets/js/shape/mxArrowConnector.js [114:386]
mxArrowConnector.prototype.paintEdgeShape = function(c, pts)
{
// Geometry of arrow
var strokeWidth = this.strokewidth;
if (this.outline)
{
strokeWidth = Math.max(1, mxUtils.getNumber(this.style, mxConstants.STYLE_STROKEWIDTH, this.strokewidth));
}
var startWidth = this.getStartArrowWidth() + strokeWidth;
var endWidth = this.getEndArrowWidth() + strokeWidth;
var edgeWidth = this.outline ? this.getEdgeWidth() + strokeWidth : this.getEdgeWidth();
var openEnded = this.isOpenEnded();
var markerStart = this.isMarkerStart();
var markerEnd = this.isMarkerEnd();
var spacing = (openEnded) ? 0 : this.arrowSpacing + strokeWidth / 2;
var startSize = this.startSize + strokeWidth;
var endSize = this.endSize + strokeWidth;
var isRounded = this.isArrowRounded();
// Base vector (between first points)
var pe = pts[pts.length - 1];
// Finds first non-overlapping point
var i0 = 1;
while (i0 < pts.length - 1 && pts[i0].x == pts[0].x && pts[i0].y == pts[0].y)
{
i0++;
}
var dx = pts[i0].x - pts[0].x;
var dy = pts[i0].y - pts[0].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist == 0)
{
return;
}
// Computes the norm and the inverse norm
var nx = dx / dist;
var nx2, nx1 = nx;
var ny = dy / dist;
var ny2, ny1 = ny;
var orthx = edgeWidth * ny;
var orthy = -edgeWidth * nx;
// Stores the inbound function calls in reverse order in fns
var fns = [];
if (isRounded)
{
c.setLineJoin('round');
}
else if (pts.length > 2)
{
// Only mitre if there are waypoints
c.setMiterLimit(1.42);
}
c.begin();
var startNx = nx;
var startNy = ny;
if (markerStart && !openEnded)
{
this.paintMarker(c, pts[0].x, pts[0].y, nx, ny, startSize, startWidth, edgeWidth, spacing, true);
}
else
{
var outStartX = pts[0].x + orthx / 2 + spacing * nx;
var outStartY = pts[0].y + orthy / 2 + spacing * ny;
var inEndX = pts[0].x - orthx / 2 + spacing * nx;
var inEndY = pts[0].y - orthy / 2 + spacing * ny;
if (openEnded)
{
c.moveTo(outStartX, outStartY);
fns.push(function()
{
c.lineTo(inEndX, inEndY);
});
}
else
{
c.moveTo(inEndX, inEndY);
c.lineTo(outStartX, outStartY);
}
}
var dx1 = 0;
var dy1 = 0;
var dist1 = 0;
for (var i = 0; i < pts.length - 2; i++)
{
// Work out in which direction the line is bending
var pos = mxUtils.relativeCcw(pts[i].x, pts[i].y, pts[i+1].x, pts[i+1].y, pts[i+2].x, pts[i+2].y);
dx1 = pts[i+2].x - pts[i+1].x;
dy1 = pts[i+2].y - pts[i+1].y;
dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
if (dist1 != 0)
{
nx1 = dx1 / dist1;
ny1 = dy1 / dist1;
var tmp1 = nx * nx1 + ny * ny1;
tmp = Math.max(Math.sqrt((tmp1 + 1) / 2), 0.04);
// Work out the normal orthogonal to the line through the control point and the edge sides intersection
nx2 = (nx + nx1);
ny2 = (ny + ny1);
var dist2 = Math.sqrt(nx2 * nx2 + ny2 * ny2);
if (dist2 != 0)
{
nx2 = nx2 / dist2;
ny2 = ny2 / dist2;
// Higher strokewidths require a larger minimum bend, 0.35 covers all but the most extreme cases
var strokeWidthFactor = Math.max(tmp, Math.min(this.strokewidth / 200 + 0.04, 0.35));
var angleFactor = (pos != 0 && isRounded) ? Math.max(0.1, strokeWidthFactor) : Math.max(tmp, 0.06);
var outX = pts[i+1].x + ny2 * edgeWidth / 2 / angleFactor;
var outY = pts[i+1].y - nx2 * edgeWidth / 2 / angleFactor;
var inX = pts[i+1].x - ny2 * edgeWidth / 2 / angleFactor;
var inY = pts[i+1].y + nx2 * edgeWidth / 2 / angleFactor;
if (pos == 0 || !isRounded)
{
// If the two segments are aligned, or if we're not drawing curved sections between segments
// just draw straight to the intersection point
c.lineTo(outX, outY);
(function(x, y)
{
fns.push(function()
{
c.lineTo(x, y);
});
})(inX, inY);
}
else if (pos == -1)
{
var c1x = inX + ny * edgeWidth;
var c1y = inY - nx * edgeWidth;
var c2x = inX + ny1 * edgeWidth;
var c2y = inY - nx1 * edgeWidth;
c.lineTo(c1x, c1y);
c.quadTo(outX, outY, c2x, c2y);
(function(x, y)
{
fns.push(function()
{
c.lineTo(x, y);
});
})(inX, inY);
}
else
{
c.lineTo(outX, outY);
(function(x, y)
{
var c1x = outX - ny * edgeWidth;
var c1y = outY + nx * edgeWidth;
var c2x = outX - ny1 * edgeWidth;
var c2y = outY + nx1 * edgeWidth;
fns.push(function()
{
c.quadTo(x, y, c1x, c1y);
});
fns.push(function()
{
c.lineTo(c2x, c2y);
});
})(inX, inY);
}
nx = nx1;
ny = ny1;
}
}
}
orthx = edgeWidth * ny1;
orthy = - edgeWidth * nx1;
if (markerEnd && !openEnded)
{
this.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, false);
}
else
{
c.lineTo(pe.x - spacing * nx1 + orthx / 2, pe.y - spacing * ny1 + orthy / 2);
var inStartX = pe.x - spacing * nx1 - orthx / 2;
var inStartY = pe.y - spacing * ny1 - orthy / 2;
if (!openEnded)
{
c.lineTo(inStartX, inStartY);
}
else
{
c.moveTo(inStartX, inStartY);
fns.splice(0, 0, function()
{
c.moveTo(inStartX, inStartY);
});
}
}
for (var i = fns.length - 1; i >= 0; i--)
{
fns[i]();
}
if (openEnded)
{
c.end();
c.stroke();
}
else
{
c.close();
c.fillAndStroke();
}
// Workaround for shadow on top of base arrow
c.setShadow(false);
// Need to redraw the markers without the low miter limit
c.setMiterLimit(4);
if (isRounded)
{
c.setLineJoin('flat');
}
if (pts.length > 2)
{
// Only to repaint markers if no waypoints
// Need to redraw the markers without the low miter limit
c.setMiterLimit(4);
if (markerStart && !openEnded)
{
c.begin();
this.paintMarker(c, pts[0].x, pts[0].y, startNx, startNy, startSize, startWidth, edgeWidth, spacing, true);
c.stroke();
c.end();
}
if (markerEnd && !openEnded)
{
c.begin();
this.paintMarker(c, pe.x, pe.y, -nx, -ny, endSize, endWidth, edgeWidth, spacing, true);
c.stroke();
c.end();
}
}
};