1 | import { isArray } from '../../core/util.js';
|
2 | var PI = Math.PI;
|
3 | var PI2 = PI * 2;
|
4 | var mathSin = Math.sin;
|
5 | var mathCos = Math.cos;
|
6 | var mathACos = Math.acos;
|
7 | var mathATan2 = Math.atan2;
|
8 | var mathAbs = Math.abs;
|
9 | var mathSqrt = Math.sqrt;
|
10 | var mathMax = Math.max;
|
11 | var mathMin = Math.min;
|
12 | var e = 1e-4;
|
13 | function 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 | }
|
25 | function 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 | }
|
64 | function 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 | }
|
89 | export 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 | }
|