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.
183 lines
6.7 KiB
183 lines
6.7 KiB
import { normalizeArcAngles } from '../../core/PathProxy';
|
|
var PI = Math.PI;
|
|
var PI2 = PI * 2;
|
|
var mathSin = Math.sin;
|
|
var mathCos = Math.cos;
|
|
var mathACos = Math.acos;
|
|
var mathATan2 = Math.atan2;
|
|
var mathAbs = Math.abs;
|
|
var mathSqrt = Math.sqrt;
|
|
var mathMax = Math.max;
|
|
var mathMin = Math.min;
|
|
var e = 1e-4;
|
|
function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
var x10 = x1 - x0;
|
|
var y10 = y1 - y0;
|
|
var x32 = x3 - x2;
|
|
var y32 = y3 - y2;
|
|
var t = y32 * x10 - x32 * y10;
|
|
if (t * t < e) {
|
|
return;
|
|
}
|
|
t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
|
|
return [x0 + t * x10, y0 + t * y10];
|
|
}
|
|
function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
|
|
var x01 = x0 - x1;
|
|
var y01 = y0 - y1;
|
|
var lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01);
|
|
var ox = lo * y01;
|
|
var oy = -lo * x01;
|
|
var x11 = x0 + ox;
|
|
var y11 = y0 + oy;
|
|
var x10 = x1 + ox;
|
|
var y10 = y1 + oy;
|
|
var x00 = (x11 + x10) / 2;
|
|
var y00 = (y11 + y10) / 2;
|
|
var dx = x10 - x11;
|
|
var dy = y10 - y11;
|
|
var d2 = dx * dx + dy * dy;
|
|
var r = radius - cr;
|
|
var s = x11 * y10 - x10 * y11;
|
|
var d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax(0, r * r * d2 - s * s));
|
|
var cx0 = (s * dy - dx * d) / d2;
|
|
var cy0 = (-s * dx - dy * d) / d2;
|
|
var cx1 = (s * dy + dx * d) / d2;
|
|
var cy1 = (-s * dx + dy * d) / d2;
|
|
var dx0 = cx0 - x00;
|
|
var dy0 = cy0 - y00;
|
|
var dx1 = cx1 - x00;
|
|
var dy1 = cy1 - y00;
|
|
if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) {
|
|
cx0 = cx1;
|
|
cy0 = cy1;
|
|
}
|
|
return {
|
|
cx: cx0,
|
|
cy: cy0,
|
|
x01: -ox,
|
|
y01: -oy,
|
|
x11: cx0 * (radius / r - 1),
|
|
y11: cy0 * (radius / r - 1)
|
|
};
|
|
}
|
|
export function buildPath(ctx, shape) {
|
|
var radius = mathMax(shape.r, 0);
|
|
var innerRadius = mathMax(shape.r0 || 0, 0);
|
|
var hasRadius = radius > 0;
|
|
var hasInnerRadius = innerRadius > 0;
|
|
if (!hasRadius && !hasInnerRadius) {
|
|
return;
|
|
}
|
|
if (!hasRadius) {
|
|
radius = innerRadius;
|
|
innerRadius = 0;
|
|
}
|
|
if (innerRadius > radius) {
|
|
var tmp = radius;
|
|
radius = innerRadius;
|
|
innerRadius = tmp;
|
|
}
|
|
var clockwise = !!shape.clockwise;
|
|
var startAngle = shape.startAngle;
|
|
var endAngle = shape.endAngle;
|
|
var arc;
|
|
if (startAngle === endAngle) {
|
|
arc = 0;
|
|
}
|
|
else {
|
|
var tmpAngles = [startAngle, endAngle];
|
|
normalizeArcAngles(tmpAngles, !clockwise);
|
|
arc = mathAbs(tmpAngles[0] - tmpAngles[1]);
|
|
}
|
|
var x = shape.cx;
|
|
var y = shape.cy;
|
|
var cornerRadius = shape.cornerRadius || 0;
|
|
var innerCornerRadius = shape.innerCornerRadius || 0;
|
|
if (!(radius > e)) {
|
|
ctx.moveTo(x, y);
|
|
}
|
|
else if (arc > PI2 - e) {
|
|
ctx.moveTo(x + radius * mathCos(startAngle), y + radius * mathSin(startAngle));
|
|
ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
|
|
if (innerRadius > e) {
|
|
ctx.moveTo(x + innerRadius * mathCos(endAngle), y + innerRadius * mathSin(endAngle));
|
|
ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
|
|
}
|
|
}
|
|
else {
|
|
var halfRd = mathAbs(radius - innerRadius) / 2;
|
|
var cr = mathMin(halfRd, cornerRadius);
|
|
var icr = mathMin(halfRd, innerCornerRadius);
|
|
var cr0 = icr;
|
|
var cr1 = cr;
|
|
var xrs = radius * mathCos(startAngle);
|
|
var yrs = radius * mathSin(startAngle);
|
|
var xire = innerRadius * mathCos(endAngle);
|
|
var yire = innerRadius * mathSin(endAngle);
|
|
var xre = void 0;
|
|
var yre = void 0;
|
|
var xirs = void 0;
|
|
var yirs = void 0;
|
|
if (cr > e || icr > e) {
|
|
xre = radius * mathCos(endAngle);
|
|
yre = radius * mathSin(endAngle);
|
|
xirs = innerRadius * mathCos(startAngle);
|
|
yirs = innerRadius * mathSin(startAngle);
|
|
if (arc < PI) {
|
|
var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire);
|
|
if (it_1) {
|
|
var x0 = xrs - it_1[0];
|
|
var y0 = yrs - it_1[1];
|
|
var x1 = xre - it_1[0];
|
|
var y1 = yre - it_1[1];
|
|
var a = 1 / mathSin(mathACos((x0 * x1 + y0 * y1) / (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1))) / 2);
|
|
var b = mathSqrt(it_1[0] * it_1[0] + it_1[1] * it_1[1]);
|
|
cr0 = mathMin(icr, (innerRadius - b) / (a - 1));
|
|
cr1 = mathMin(cr, (radius - b) / (a + 1));
|
|
}
|
|
}
|
|
}
|
|
if (!(arc > e)) {
|
|
ctx.moveTo(x + xrs, y + yrs);
|
|
}
|
|
else if (cr1 > e) {
|
|
var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, cr1, clockwise);
|
|
var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, cr1, clockwise);
|
|
ctx.moveTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
|
|
if (cr1 < cr) {
|
|
ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
|
|
}
|
|
else {
|
|
ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
|
|
ctx.arc(x, y, radius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), !clockwise);
|
|
ctx.arc(x + ct1.cx, y + ct1.cy, cr1, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
|
|
}
|
|
}
|
|
else {
|
|
ctx.moveTo(x + xrs, y + yrs);
|
|
ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
|
|
}
|
|
if (!(innerRadius > e) || !(arc > e)) {
|
|
ctx.lineTo(x + xire, y + yire);
|
|
}
|
|
else if (cr0 > e) {
|
|
var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -cr0, clockwise);
|
|
var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -cr0, clockwise);
|
|
ctx.lineTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
|
|
if (cr0 < icr) {
|
|
ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
|
|
}
|
|
else {
|
|
ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
|
|
ctx.arc(x, y, innerRadius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), clockwise);
|
|
ctx.arc(x + ct1.cx, y + ct1.cy, cr0, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
|
|
}
|
|
}
|
|
else {
|
|
ctx.lineTo(x + xire, y + yire);
|
|
ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
|
|
}
|
|
}
|
|
ctx.closePath();
|
|
}
|
|
|