UNPKG

8.57 kBJavaScriptView Raw
1import { isArray } from '../../core/util.js';
2var PI = Math.PI;
3var PI2 = PI * 2;
4var mathSin = Math.sin;
5var mathCos = Math.cos;
6var mathACos = Math.acos;
7var mathATan2 = Math.atan2;
8var mathAbs = Math.abs;
9var mathSqrt = Math.sqrt;
10var mathMax = Math.max;
11var mathMin = Math.min;
12var e = 1e-4;
13function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
14 var dx10 = x1 - x0;
15 var dy10 = y1 - y0;
16 var dx32 = x3 - x2;
17 var dy32 = y3 - y2;
18 var t = dy32 * dx10 - dx32 * dy10;
19 if (t * t < e) {
20 return;
21 }
22 t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t;
23 return [x0 + t * dx10, y0 + t * dy10];
24}
25function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
26 var x01 = x0 - x1;
27 var y01 = y0 - y1;
28 var lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01);
29 var ox = lo * y01;
30 var oy = -lo * x01;
31 var x11 = x0 + ox;
32 var y11 = y0 + oy;
33 var x10 = x1 + ox;
34 var y10 = y1 + oy;
35 var x00 = (x11 + x10) / 2;
36 var y00 = (y11 + y10) / 2;
37 var dx = x10 - x11;
38 var dy = y10 - y11;
39 var d2 = dx * dx + dy * dy;
40 var r = radius - cr;
41 var s = x11 * y10 - x10 * y11;
42 var d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax(0, r * r * d2 - s * s));
43 var cx0 = (s * dy - dx * d) / d2;
44 var cy0 = (-s * dx - dy * d) / d2;
45 var cx1 = (s * dy + dx * d) / d2;
46 var cy1 = (-s * dx + dy * d) / d2;
47 var dx0 = cx0 - x00;
48 var dy0 = cy0 - y00;
49 var dx1 = cx1 - x00;
50 var dy1 = cy1 - y00;
51 if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) {
52 cx0 = cx1;
53 cy0 = cy1;
54 }
55 return {
56 cx: cx0,
57 cy: cy0,
58 x0: -ox,
59 y0: -oy,
60 x1: cx0 * (radius / r - 1),
61 y1: cy0 * (radius / r - 1)
62 };
63}
64function normalizeCornerRadius(cr) {
65 var arr;
66 if (isArray(cr)) {
67 var len = cr.length;
68 if (!len) {
69 return cr;
70 }
71 if (len === 1) {
72 arr = [cr[0], cr[0], 0, 0];
73 }
74 else if (len === 2) {
75 arr = [cr[0], cr[0], cr[1], cr[1]];
76 }
77 else if (len === 3) {
78 arr = cr.concat(cr[2]);
79 }
80 else {
81 arr = cr;
82 }
83 }
84 else {
85 arr = [cr, cr, cr, cr];
86 }
87 return arr;
88}
89export function buildPath(ctx, shape) {
90 var _a;
91 var radius = mathMax(shape.r, 0);
92 var innerRadius = mathMax(shape.r0 || 0, 0);
93 var hasRadius = radius > 0;
94 var hasInnerRadius = innerRadius > 0;
95 if (!hasRadius && !hasInnerRadius) {
96 return;
97 }
98 if (!hasRadius) {
99 radius = innerRadius;
100 innerRadius = 0;
101 }
102 if (innerRadius > radius) {
103 var tmp = radius;
104 radius = innerRadius;
105 innerRadius = tmp;
106 }
107 var startAngle = shape.startAngle, endAngle = shape.endAngle;
108 if (isNaN(startAngle) || isNaN(endAngle)) {
109 return;
110 }
111 var cx = shape.cx, cy = shape.cy;
112 var clockwise = !!shape.clockwise;
113 var arc = mathAbs(endAngle - startAngle);
114 var mod = arc > PI2 && arc % PI2;
115 mod > e && (arc = mod);
116 if (!(radius > e)) {
117 ctx.moveTo(cx, cy);
118 }
119 else if (arc > PI2 - e) {
120 ctx.moveTo(cx + radius * mathCos(startAngle), cy + radius * mathSin(startAngle));
121 ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise);
122 if (innerRadius > e) {
123 ctx.moveTo(cx + innerRadius * mathCos(endAngle), cy + innerRadius * mathSin(endAngle));
124 ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise);
125 }
126 }
127 else {
128 var icrStart = void 0;
129 var icrEnd = void 0;
130 var ocrStart = void 0;
131 var ocrEnd = void 0;
132 var ocrs = void 0;
133 var ocre = void 0;
134 var icrs = void 0;
135 var icre = void 0;
136 var ocrMax = void 0;
137 var icrMax = void 0;
138 var limitedOcrMax = void 0;
139 var limitedIcrMax = void 0;
140 var xre = void 0;
141 var yre = void 0;
142 var xirs = void 0;
143 var yirs = void 0;
144 var xrs = radius * mathCos(startAngle);
145 var yrs = radius * mathSin(startAngle);
146 var xire = innerRadius * mathCos(endAngle);
147 var yire = innerRadius * mathSin(endAngle);
148 var hasArc = arc > e;
149 if (hasArc) {
150 var cornerRadius = shape.cornerRadius;
151 if (cornerRadius) {
152 _a = normalizeCornerRadius(cornerRadius), icrStart = _a[0], icrEnd = _a[1], ocrStart = _a[2], ocrEnd = _a[3];
153 }
154 var halfRd = mathAbs(radius - innerRadius) / 2;
155 ocrs = mathMin(halfRd, ocrStart);
156 ocre = mathMin(halfRd, ocrEnd);
157 icrs = mathMin(halfRd, icrStart);
158 icre = mathMin(halfRd, icrEnd);
159 limitedOcrMax = ocrMax = mathMax(ocrs, ocre);
160 limitedIcrMax = icrMax = mathMax(icrs, icre);
161 if (ocrMax > e || icrMax > e) {
162 xre = radius * mathCos(endAngle);
163 yre = radius * mathSin(endAngle);
164 xirs = innerRadius * mathCos(startAngle);
165 yirs = innerRadius * mathSin(startAngle);
166 if (arc < PI) {
167 var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire);
168 if (it_1) {
169 var x0 = xrs - it_1[0];
170 var y0 = yrs - it_1[1];
171 var x1 = xre - it_1[0];
172 var y1 = yre - it_1[1];
173 var a = 1 / mathSin(mathACos((x0 * x1 + y0 * y1) / (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1))) / 2);
174 var b = mathSqrt(it_1[0] * it_1[0] + it_1[1] * it_1[1]);
175 limitedOcrMax = mathMin(ocrMax, (radius - b) / (a + 1));
176 limitedIcrMax = mathMin(icrMax, (innerRadius - b) / (a - 1));
177 }
178 }
179 }
180 }
181 if (!hasArc) {
182 ctx.moveTo(cx + xrs, cy + yrs);
183 }
184 else if (limitedOcrMax > e) {
185 var crStart = mathMin(ocrStart, limitedOcrMax);
186 var crEnd = mathMin(ocrEnd, limitedOcrMax);
187 var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, crStart, clockwise);
188 var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, crEnd, clockwise);
189 ctx.moveTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0);
190 if (limitedOcrMax < ocrMax && crStart === crEnd) {
191 ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedOcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise);
192 }
193 else {
194 crStart > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crStart, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise);
195 ctx.arc(cx, cy, radius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), !clockwise);
196 crEnd > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crEnd, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise);
197 }
198 }
199 else {
200 ctx.moveTo(cx + xrs, cy + yrs);
201 ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise);
202 }
203 if (!(innerRadius > e) || !hasArc) {
204 ctx.lineTo(cx + xire, cy + yire);
205 }
206 else if (limitedIcrMax > e) {
207 var crStart = mathMin(icrStart, limitedIcrMax);
208 var crEnd = mathMin(icrEnd, limitedIcrMax);
209 var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -crEnd, clockwise);
210 var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -crStart, clockwise);
211 ctx.lineTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0);
212 if (limitedIcrMax < icrMax && crStart === crEnd) {
213 ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedIcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise);
214 }
215 else {
216 crEnd > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crEnd, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise);
217 ctx.arc(cx, cy, innerRadius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), clockwise);
218 crStart > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crStart, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise);
219 }
220 }
221 else {
222 ctx.lineTo(cx + xire, cy + yire);
223 ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise);
224 }
225 }
226 ctx.closePath();
227}