Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lines with rounded corners #158

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions src/shapes/Line.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,96 @@ Kinetic.Line.prototype = {
var lastY = this.attrs.points[n - 1].y;
this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray);
}
else if(this.attrs.cornerRadius && n+1 < this.attrs.points.length) {
// draw line with rounded corner
var radius = this.attrs.cornerRadius
var lastX = this.attrs.points[n - 1].x;
var lastY = this.attrs.points[n - 1].y;
var nextX = this.attrs.points[n + 1].x;
var nextY = this.attrs.points[n + 1].y;
var lastXD = x - lastX
var lastYD = y - lastY
var nextXD = nextX - x
var nextYD = nextY - y

// Warning: the angle system for atan2() and arc() in the
// HTML5 canvas is different.
// For atan2(), south is 0°, counter clockwise, range -π to π
// For arc(), east is 0°, clockwise, range 0 to 2π
var lastangle = Math.atan2(lastXD, lastYD);
var nextangle = Math.atan2(nextXD, nextYD);
var anglediff = nextangle - lastangle
if (anglediff < -Math.PI) {
anglediff += 2*Math.PI
var clockwise = false;
// Direction of the normal line bisecting the two line segments
var normangle = (lastangle + nextangle - Math.PI)/2 // Value is between -1.5 π and 0.5 π
// Relative angle between normal line and either line segment
var halfangle = (Math.PI - anglediff)/2 // Value is between 0 and π/2 (0 and 90°).
// Direction in arc() coordinates, not in atan2() coordinates.
var startangle = Math.PI - lastangle // lastangle + 90 degrees clockwise, other angle system.
var endangle = Math.PI - nextangle // nextangle + 90 degrees clockwise, other angle system.
} else if (anglediff < 0) {
var clockwise = true;
// Direction of the normal line bisecting the two line segments
var normangle = (lastangle + nextangle - Math.PI)/2 // Value is between -1.5 π and 0.5 π
// Relative angle between normal line and either line segment
var halfangle = (anglediff + Math.PI)/2 // Value is between 0 and π/2 (0 and 90°).
var startangle = -lastangle // lastangle + 90 degrees counter clockwise, other angle system.
var endangle = -nextangle // nextangle + 90 degrees counter clockwise, other angle system.
} else if (anglediff < Math.PI) {
var clockwise = false;
// Direction of the normal line bisecting the two line segments
var normangle = (lastangle + nextangle + Math.PI)/2 // Value is between -0.5 π and 1.5 π
// Relative angle between normal line and either line segment
var halfangle = (Math.PI - anglediff)/2 // Value is between 0 and π/2 (0 and 90°).
var startangle = Math.PI - lastangle // lastangle + 90 degrees clockwise, other angle system.
var endangle = Math.PI - nextangle // nextangle + 90 degrees clockwise, other angle system.
} else {
anglediff -= 2*Math.PI
var clockwise = true;
// Direction of the normal line bisecting the two line segments
var normangle = (lastangle + nextangle + Math.PI)/2 // Value is between -0.5 π and 1.5 π
// Relative angle between normal line and either line segment
var halfangle = (anglediff + Math.PI)/2 // Value is between 0 and π/2 (0 and 90°).
var startangle = -lastangle // lastangle + 90 degrees counter clockwise, other angle system.
var endangle = -nextangle // nextangle + 90 degrees counter clockwise, other angle system.
}
if (radius * Math.cos(halfangle) < 0.5) {
// less than half a pixel of a corner to draw. Don't bother.
// This also prevents tan(halfang) to reach infinity.
context.lineTo(x, y);
radius = 0
} else {
if (n == 1) {
lastlen = Math.sqrt(lastXD*lastXD + lastYD*lastYD);
} else {
lastlen = Math.sqrt(lastXD*lastXD + lastYD*lastYD)/2;
}
if (n+1 == this.attrs.points.length) {
nextlen = Math.sqrt(nextXD*nextXD + nextYD*nextYD);
} else {
nextlen = Math.sqrt(nextXD*nextXD + nextYD*nextYD)/2;
}
// no worries that tan(halfang) is infinite; that is caught above
// Reduce the radius if there is not enough space
radius = Math.min(radius, Math.min(lastlen, nextlen) * Math.tan(halfangle))

if (radius <= 0) {
// special case: the line segments make a 180° turn
var arcdist = Math.min(lastlen, nextlen)
var arcX = x + arcdist*Math.sin(normangle)
var arcY = y + arcdist*Math.cos(normangle)
context.lineTo(arcX, arcY);
} else {
// distance from x,y to center of the arc
var arcdist = radius/Math.sin(halfangle)
var arcX = x + arcdist*Math.sin(normangle)
var arcY = y + arcdist*Math.cos(normangle)
context.arc(arcX, arcY, radius, startangle, endangle, !clockwise);
}
}
}
else {
// draw normal line
context.lineTo(x, y);
Expand Down