path.js 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. import { each, isArray } from '@antv/util';
  2. var SPACES = '\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029';
  3. var PATH_COMMAND = new RegExp("([a-z])[" + SPACES + ",]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[" + SPACES + "]*,?[" + SPACES + "]*)+)", 'ig');
  4. var PATH_VALUES = new RegExp("(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[" + SPACES + "]*,?[" + SPACES + "]*", 'ig');
  5. // Parse given path string into an array of arrays of path segments
  6. var parsePathString = function (pathString) {
  7. if (!pathString) {
  8. return null;
  9. }
  10. if (isArray(pathString)) {
  11. return pathString;
  12. }
  13. var paramCounts = {
  14. a: 7,
  15. c: 6,
  16. o: 2,
  17. h: 1,
  18. l: 2,
  19. m: 2,
  20. r: 4,
  21. q: 4,
  22. s: 4,
  23. t: 2,
  24. v: 1,
  25. u: 3,
  26. z: 0,
  27. };
  28. var data = [];
  29. String(pathString).replace(PATH_COMMAND, function (a, b, c) {
  30. var params = [];
  31. var name = b.toLowerCase();
  32. c.replace(PATH_VALUES, function (a, b) {
  33. b && params.push(+b);
  34. });
  35. if (name === 'm' && params.length > 2) {
  36. data.push([b].concat(params.splice(0, 2)));
  37. name = 'l';
  38. b = b === 'm' ? 'l' : 'L';
  39. }
  40. if (name === 'o' && params.length === 1) {
  41. data.push([b, params[0]]);
  42. }
  43. if (name === 'r') {
  44. data.push([b].concat(params));
  45. }
  46. else {
  47. while (params.length >= paramCounts[name]) {
  48. data.push([b].concat(params.splice(0, paramCounts[name])));
  49. if (!paramCounts[name]) {
  50. break;
  51. }
  52. }
  53. }
  54. return pathString;
  55. });
  56. return data;
  57. };
  58. // http://schepers.cc/getting-to-the-point
  59. var catmullRomToBezier = function (crp, z) {
  60. var d = [];
  61. // @ts-ignore
  62. for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
  63. var p = [
  64. {
  65. x: +crp[i - 2],
  66. y: +crp[i - 1],
  67. },
  68. {
  69. x: +crp[i],
  70. y: +crp[i + 1],
  71. },
  72. {
  73. x: +crp[i + 2],
  74. y: +crp[i + 3],
  75. },
  76. {
  77. x: +crp[i + 4],
  78. y: +crp[i + 5],
  79. },
  80. ];
  81. if (z) {
  82. if (!i) {
  83. p[0] = {
  84. x: +crp[iLen - 2],
  85. y: +crp[iLen - 1],
  86. };
  87. }
  88. else if (iLen - 4 === i) {
  89. p[3] = {
  90. x: +crp[0],
  91. y: +crp[1],
  92. };
  93. }
  94. else if (iLen - 2 === i) {
  95. p[2] = {
  96. x: +crp[0],
  97. y: +crp[1],
  98. };
  99. p[3] = {
  100. x: +crp[2],
  101. y: +crp[3],
  102. };
  103. }
  104. }
  105. else {
  106. if (iLen - 4 === i) {
  107. p[3] = p[2];
  108. }
  109. else if (!i) {
  110. p[0] = {
  111. x: +crp[i],
  112. y: +crp[i + 1],
  113. };
  114. }
  115. }
  116. d.push([
  117. 'C',
  118. (-p[0].x + 6 * p[1].x + p[2].x) / 6,
  119. (-p[0].y + 6 * p[1].y + p[2].y) / 6,
  120. (p[1].x + 6 * p[2].x - p[3].x) / 6,
  121. (p[1].y + 6 * p[2].y - p[3].y) / 6,
  122. p[2].x,
  123. p[2].y,
  124. ]);
  125. }
  126. return d;
  127. };
  128. var ellipsePath = function (x, y, rx, ry, a) {
  129. var res = [];
  130. if (a === null && ry === null) {
  131. ry = rx;
  132. }
  133. x = +x;
  134. y = +y;
  135. rx = +rx;
  136. ry = +ry;
  137. if (a !== null) {
  138. var rad = Math.PI / 180;
  139. var x1 = x + rx * Math.cos(-ry * rad);
  140. var x2 = x + rx * Math.cos(-a * rad);
  141. var y1 = y + rx * Math.sin(-ry * rad);
  142. var y2 = y + rx * Math.sin(-a * rad);
  143. res = [
  144. ['M', x1, y1],
  145. ['A', rx, rx, 0, +(a - ry > 180), 0, x2, y2],
  146. ];
  147. }
  148. else {
  149. res = [['M', x, y], ['m', 0, -ry], ['a', rx, ry, 0, 1, 1, 0, 2 * ry], ['a', rx, ry, 0, 1, 1, 0, -2 * ry], ['z']];
  150. }
  151. return res;
  152. };
  153. var pathToAbsolute = function (pathArray) {
  154. pathArray = parsePathString(pathArray);
  155. if (!pathArray || !pathArray.length) {
  156. return [['M', 0, 0]];
  157. }
  158. var res = [];
  159. var x = 0;
  160. var y = 0;
  161. var mx = 0;
  162. var my = 0;
  163. var start = 0;
  164. var pa0;
  165. var dots;
  166. if (pathArray[0][0] === 'M') {
  167. x = +pathArray[0][1];
  168. y = +pathArray[0][2];
  169. mx = x;
  170. my = y;
  171. start++;
  172. res[0] = ['M', x, y];
  173. }
  174. var crz = pathArray.length === 3 &&
  175. pathArray[0][0] === 'M' &&
  176. pathArray[1][0].toUpperCase() === 'R' &&
  177. pathArray[2][0].toUpperCase() === 'Z';
  178. for (var r = void 0, pa = void 0, i = start, ii = pathArray.length; i < ii; i++) {
  179. res.push((r = []));
  180. pa = pathArray[i];
  181. pa0 = pa[0];
  182. if (pa0 !== pa0.toUpperCase()) {
  183. r[0] = pa0.toUpperCase();
  184. switch (r[0]) {
  185. case 'A':
  186. r[1] = pa[1];
  187. r[2] = pa[2];
  188. r[3] = pa[3];
  189. r[4] = pa[4];
  190. r[5] = pa[5];
  191. r[6] = +pa[6] + x;
  192. r[7] = +pa[7] + y;
  193. break;
  194. case 'V':
  195. r[1] = +pa[1] + y;
  196. break;
  197. case 'H':
  198. r[1] = +pa[1] + x;
  199. break;
  200. case 'R':
  201. dots = [x, y].concat(pa.slice(1));
  202. for (var j = 2, jj = dots.length; j < jj; j++) {
  203. dots[j] = +dots[j] + x;
  204. dots[++j] = +dots[j] + y;
  205. }
  206. res.pop();
  207. res = res.concat(catmullRomToBezier(dots, crz));
  208. break;
  209. case 'O':
  210. res.pop();
  211. dots = ellipsePath(x, y, pa[1], pa[2]);
  212. dots.push(dots[0]);
  213. res = res.concat(dots);
  214. break;
  215. case 'U':
  216. res.pop();
  217. res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
  218. r = ['U'].concat(res[res.length - 1].slice(-2));
  219. break;
  220. case 'M':
  221. mx = +pa[1] + x;
  222. my = +pa[2] + y;
  223. break; // for lint
  224. default:
  225. for (var j = 1, jj = pa.length; j < jj; j++) {
  226. r[j] = +pa[j] + (j % 2 ? x : y);
  227. }
  228. }
  229. }
  230. else if (pa0 === 'R') {
  231. dots = [x, y].concat(pa.slice(1));
  232. res.pop();
  233. res = res.concat(catmullRomToBezier(dots, crz));
  234. r = ['R'].concat(pa.slice(-2));
  235. }
  236. else if (pa0 === 'O') {
  237. res.pop();
  238. dots = ellipsePath(x, y, pa[1], pa[2]);
  239. dots.push(dots[0]);
  240. res = res.concat(dots);
  241. }
  242. else if (pa0 === 'U') {
  243. res.pop();
  244. res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
  245. r = ['U'].concat(res[res.length - 1].slice(-2));
  246. }
  247. else {
  248. for (var k = 0, kk = pa.length; k < kk; k++) {
  249. r[k] = pa[k];
  250. }
  251. }
  252. pa0 = pa0.toUpperCase();
  253. if (pa0 !== 'O') {
  254. switch (r[0]) {
  255. case 'Z':
  256. x = +mx;
  257. y = +my;
  258. break;
  259. case 'H':
  260. x = r[1];
  261. break;
  262. case 'V':
  263. y = r[1];
  264. break;
  265. case 'M':
  266. mx = r[r.length - 2];
  267. my = r[r.length - 1];
  268. break; // for lint
  269. default:
  270. x = r[r.length - 2];
  271. y = r[r.length - 1];
  272. }
  273. }
  274. }
  275. return res;
  276. };
  277. var l2c = function (x1, y1, x2, y2) {
  278. return [x1, y1, x2, y2, x2, y2];
  279. };
  280. var q2c = function (x1, y1, ax, ay, x2, y2) {
  281. var _13 = 1 / 3;
  282. var _23 = 2 / 3;
  283. return [_13 * x1 + _23 * ax, _13 * y1 + _23 * ay, _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2];
  284. };
  285. var a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
  286. // for more information of where this math came from visit:
  287. // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  288. if (rx === ry) {
  289. rx += 1;
  290. }
  291. var _120 = (Math.PI * 120) / 180;
  292. var rad = (Math.PI / 180) * (+angle || 0);
  293. var res = [];
  294. var xy;
  295. var f1;
  296. var f2;
  297. var cx;
  298. var cy;
  299. var rotate = function (x, y, rad) {
  300. var X = x * Math.cos(rad) - y * Math.sin(rad);
  301. var Y = x * Math.sin(rad) + y * Math.cos(rad);
  302. return {
  303. x: X,
  304. y: Y,
  305. };
  306. };
  307. if (!recursive) {
  308. xy = rotate(x1, y1, -rad);
  309. x1 = xy.x;
  310. y1 = xy.y;
  311. xy = rotate(x2, y2, -rad);
  312. x2 = xy.x;
  313. y2 = xy.y;
  314. if (x1 === x2 && y1 === y2) {
  315. // 若弧的起始点和终点重叠则错开一点
  316. x2 += 1;
  317. y2 += 1;
  318. }
  319. // const cos = Math.cos(Math.PI / 180 * angle);
  320. // const sin = Math.sin(Math.PI / 180 * angle);
  321. var x = (x1 - x2) / 2;
  322. var y = (y1 - y2) / 2;
  323. var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
  324. if (h > 1) {
  325. h = Math.sqrt(h);
  326. rx = h * rx;
  327. ry = h * ry;
  328. }
  329. var rx2 = rx * rx;
  330. var ry2 = ry * ry;
  331. var k = (large_arc_flag === sweep_flag ? -1 : 1) *
  332. Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
  333. cx = (k * rx * y) / ry + (x1 + x2) / 2;
  334. cy = (k * -ry * x) / rx + (y1 + y2) / 2;
  335. // @ts-ignore
  336. f1 = Math.asin(((y1 - cy) / ry).toFixed(9));
  337. // @ts-ignore
  338. f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
  339. f1 = x1 < cx ? Math.PI - f1 : f1;
  340. f2 = x2 < cx ? Math.PI - f2 : f2;
  341. f1 < 0 && (f1 = Math.PI * 2 + f1);
  342. f2 < 0 && (f2 = Math.PI * 2 + f2);
  343. if (sweep_flag && f1 > f2) {
  344. f1 = f1 - Math.PI * 2;
  345. }
  346. if (!sweep_flag && f2 > f1) {
  347. f2 = f2 - Math.PI * 2;
  348. }
  349. }
  350. else {
  351. f1 = recursive[0];
  352. f2 = recursive[1];
  353. cx = recursive[2];
  354. cy = recursive[3];
  355. }
  356. var df = f2 - f1;
  357. if (Math.abs(df) > _120) {
  358. var f2old = f2;
  359. var x2old = x2;
  360. var y2old = y2;
  361. f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
  362. x2 = cx + rx * Math.cos(f2);
  363. y2 = cy + ry * Math.sin(f2);
  364. res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
  365. }
  366. df = f2 - f1;
  367. var c1 = Math.cos(f1);
  368. var s1 = Math.sin(f1);
  369. var c2 = Math.cos(f2);
  370. var s2 = Math.sin(f2);
  371. var t = Math.tan(df / 4);
  372. var hx = (4 / 3) * rx * t;
  373. var hy = (4 / 3) * ry * t;
  374. var m1 = [x1, y1];
  375. var m2 = [x1 + hx * s1, y1 - hy * c1];
  376. var m3 = [x2 + hx * s2, y2 - hy * c2];
  377. var m4 = [x2, y2];
  378. m2[0] = 2 * m1[0] - m2[0];
  379. m2[1] = 2 * m1[1] - m2[1];
  380. if (recursive) {
  381. return [m2, m3, m4].concat(res);
  382. }
  383. res = [m2, m3, m4].concat(res).join().split(',');
  384. var newres = [];
  385. for (var i = 0, ii = res.length; i < ii; i++) {
  386. newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
  387. }
  388. return newres;
  389. };
  390. var pathToCurve = function (path, path2) {
  391. var p = pathToAbsolute(path);
  392. var p2 = path2 && pathToAbsolute(path2);
  393. var attrs = {
  394. x: 0,
  395. y: 0,
  396. bx: 0,
  397. by: 0,
  398. X: 0,
  399. Y: 0,
  400. qx: null,
  401. qy: null,
  402. };
  403. var attrs2 = {
  404. x: 0,
  405. y: 0,
  406. bx: 0,
  407. by: 0,
  408. X: 0,
  409. Y: 0,
  410. qx: null,
  411. qy: null,
  412. };
  413. var pcoms1 = []; // path commands of original path p
  414. var pcoms2 = []; // path commands of original path p2
  415. var pfirst = ''; // temporary holder for original path command
  416. var pcom = ''; // holder for previous path command of original path
  417. var ii;
  418. var processPath = function (path, d, pcom) {
  419. var nx;
  420. var ny;
  421. if (!path) {
  422. return ['C', d.x, d.y, d.x, d.y, d.x, d.y];
  423. }
  424. !(path[0] in
  425. {
  426. T: 1,
  427. Q: 1,
  428. }) && (d.qx = d.qy = null);
  429. switch (path[0]) {
  430. case 'M':
  431. d.X = path[1];
  432. d.Y = path[2];
  433. break;
  434. case 'A':
  435. path = ['C'].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
  436. break;
  437. case 'S':
  438. if (pcom === 'C' || pcom === 'S') {
  439. // In "S" case we have to take into account, if the previous command is C/S.
  440. nx = d.x * 2 - d.bx; // And reflect the previous
  441. ny = d.y * 2 - d.by; // command's control point relative to the current point.
  442. }
  443. else {
  444. // or some else or nothing
  445. nx = d.x;
  446. ny = d.y;
  447. }
  448. path = ['C', nx, ny].concat(path.slice(1));
  449. break;
  450. case 'T':
  451. if (pcom === 'Q' || pcom === 'T') {
  452. // In "T" case we have to take into account, if the previous command is Q/T.
  453. d.qx = d.x * 2 - d.qx; // And make a reflection similar
  454. d.qy = d.y * 2 - d.qy; // to case "S".
  455. }
  456. else {
  457. // or something else or nothing
  458. d.qx = d.x;
  459. d.qy = d.y;
  460. }
  461. path = ['C'].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
  462. break;
  463. case 'Q':
  464. d.qx = path[1];
  465. d.qy = path[2];
  466. path = ['C'].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
  467. break;
  468. case 'L':
  469. path = ['C'].concat(l2c(d.x, d.y, path[1], path[2]));
  470. break;
  471. case 'H':
  472. path = ['C'].concat(l2c(d.x, d.y, path[1], d.y));
  473. break;
  474. case 'V':
  475. path = ['C'].concat(l2c(d.x, d.y, d.x, path[1]));
  476. break;
  477. case 'Z':
  478. path = ['C'].concat(l2c(d.x, d.y, d.X, d.Y));
  479. break;
  480. default:
  481. break;
  482. }
  483. return path;
  484. };
  485. var fixArc = function (pp, i) {
  486. if (pp[i].length > 7) {
  487. pp[i].shift();
  488. var pi = pp[i];
  489. while (pi.length) {
  490. pcoms1[i] = 'A'; // if created multiple C:s, their original seg is saved
  491. p2 && (pcoms2[i] = 'A'); // the same as above
  492. pp.splice(i++, 0, ['C'].concat(pi.splice(0, 6)));
  493. }
  494. pp.splice(i, 1);
  495. ii = Math.max(p.length, (p2 && p2.length) || 0);
  496. }
  497. };
  498. var fixM = function (path1, path2, a1, a2, i) {
  499. if (path1 && path2 && path1[i][0] === 'M' && path2[i][0] !== 'M') {
  500. path2.splice(i, 0, ['M', a2.x, a2.y]);
  501. a1.bx = 0;
  502. a1.by = 0;
  503. a1.x = path1[i][1];
  504. a1.y = path1[i][2];
  505. ii = Math.max(p.length, (p2 && p2.length) || 0);
  506. }
  507. };
  508. ii = Math.max(p.length, (p2 && p2.length) || 0);
  509. for (var i = 0; i < ii; i++) {
  510. p[i] && (pfirst = p[i][0]); // save current path command
  511. if (pfirst !== 'C') {
  512. // C is not saved yet, because it may be result of conversion
  513. pcoms1[i] = pfirst; // Save current path command
  514. i && (pcom = pcoms1[i - 1]); // Get previous path command pcom
  515. }
  516. p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
  517. if (pcoms1[i] !== 'A' && pfirst === 'C')
  518. pcoms1[i] = 'C'; // A is the only command
  519. // which may produce multiple C:s
  520. // so we have to make sure that C is also C in original path
  521. fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
  522. if (p2) {
  523. // the same procedures is done to p2
  524. p2[i] && (pfirst = p2[i][0]);
  525. if (pfirst !== 'C') {
  526. pcoms2[i] = pfirst;
  527. i && (pcom = pcoms2[i - 1]);
  528. }
  529. p2[i] = processPath(p2[i], attrs2, pcom);
  530. if (pcoms2[i] !== 'A' && pfirst === 'C') {
  531. pcoms2[i] = 'C';
  532. }
  533. fixArc(p2, i);
  534. }
  535. fixM(p, p2, attrs, attrs2, i);
  536. fixM(p2, p, attrs2, attrs, i);
  537. var seg = p[i];
  538. var seg2 = p2 && p2[i];
  539. var seglen = seg.length;
  540. var seg2len = p2 && seg2.length;
  541. attrs.x = seg[seglen - 2];
  542. attrs.y = seg[seglen - 1];
  543. attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
  544. attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
  545. attrs2.bx = p2 && (parseFloat(seg2[seg2len - 4]) || attrs2.x);
  546. attrs2.by = p2 && (parseFloat(seg2[seg2len - 3]) || attrs2.y);
  547. attrs2.x = p2 && seg2[seg2len - 2];
  548. attrs2.y = p2 && seg2[seg2len - 1];
  549. }
  550. return p2 ? [p, p2] : p;
  551. };
  552. var p2s = /,?([a-z]),?/gi;
  553. var parsePathArray = function (path) {
  554. return path.join(',').replace(p2s, '$1');
  555. };
  556. var base3 = function (t, p1, p2, p3, p4) {
  557. var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
  558. var t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
  559. return t * t2 - 3 * p1 + 3 * p2;
  560. };
  561. var bezlen = function (x1, y1, x2, y2, x3, y3, x4, y4, z) {
  562. if (z === null) {
  563. z = 1;
  564. }
  565. z = z > 1 ? 1 : z < 0 ? 0 : z;
  566. var z2 = z / 2;
  567. var n = 12;
  568. var Tvalues = [
  569. -0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816, 0.9816,
  570. ];
  571. var Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472];
  572. var sum = 0;
  573. for (var i = 0; i < n; i++) {
  574. var ct = z2 * Tvalues[i] + z2;
  575. var xbase = base3(ct, x1, x2, x3, x4);
  576. var ybase = base3(ct, y1, y2, y3, y4);
  577. var comb = xbase * xbase + ybase * ybase;
  578. sum += Cvalues[i] * Math.sqrt(comb);
  579. }
  580. return z2 * sum;
  581. };
  582. var curveDim = function (x0, y0, x1, y1, x2, y2, x3, y3) {
  583. var tvalues = [];
  584. var bounds = [[], []];
  585. var a;
  586. var b;
  587. var c;
  588. var t;
  589. for (var i = 0; i < 2; ++i) {
  590. if (i === 0) {
  591. b = 6 * x0 - 12 * x1 + 6 * x2;
  592. a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
  593. c = 3 * x1 - 3 * x0;
  594. }
  595. else {
  596. b = 6 * y0 - 12 * y1 + 6 * y2;
  597. a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
  598. c = 3 * y1 - 3 * y0;
  599. }
  600. if (Math.abs(a) < 1e-12) {
  601. if (Math.abs(b) < 1e-12) {
  602. continue;
  603. }
  604. t = -c / b;
  605. if (t > 0 && t < 1) {
  606. tvalues.push(t);
  607. }
  608. continue;
  609. }
  610. var b2ac = b * b - 4 * c * a;
  611. var sqrtb2ac = Math.sqrt(b2ac);
  612. if (b2ac < 0) {
  613. continue;
  614. }
  615. var t1 = (-b + sqrtb2ac) / (2 * a);
  616. if (t1 > 0 && t1 < 1) {
  617. tvalues.push(t1);
  618. }
  619. var t2 = (-b - sqrtb2ac) / (2 * a);
  620. if (t2 > 0 && t2 < 1) {
  621. tvalues.push(t2);
  622. }
  623. }
  624. var j = tvalues.length;
  625. var jlen = j;
  626. var mt;
  627. while (j--) {
  628. t = tvalues[j];
  629. mt = 1 - t;
  630. bounds[0][j] = mt * mt * mt * x0 + 3 * mt * mt * t * x1 + 3 * mt * t * t * x2 + t * t * t * x3;
  631. bounds[1][j] = mt * mt * mt * y0 + 3 * mt * mt * t * y1 + 3 * mt * t * t * y2 + t * t * t * y3;
  632. }
  633. bounds[0][jlen] = x0;
  634. bounds[1][jlen] = y0;
  635. bounds[0][jlen + 1] = x3;
  636. bounds[1][jlen + 1] = y3;
  637. bounds[0].length = bounds[1].length = jlen + 2;
  638. return {
  639. min: {
  640. x: Math.min.apply(0, bounds[0]),
  641. y: Math.min.apply(0, bounds[1]),
  642. },
  643. max: {
  644. x: Math.max.apply(0, bounds[0]),
  645. y: Math.max.apply(0, bounds[1]),
  646. },
  647. };
  648. };
  649. var intersect = function (x1, y1, x2, y2, x3, y3, x4, y4) {
  650. if (Math.max(x1, x2) < Math.min(x3, x4) ||
  651. Math.min(x1, x2) > Math.max(x3, x4) ||
  652. Math.max(y1, y2) < Math.min(y3, y4) ||
  653. Math.min(y1, y2) > Math.max(y3, y4)) {
  654. return;
  655. }
  656. var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4);
  657. var ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4);
  658. var denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
  659. if (!denominator) {
  660. return;
  661. }
  662. var px = nx / denominator;
  663. var py = ny / denominator;
  664. var px2 = +px.toFixed(2);
  665. var py2 = +py.toFixed(2);
  666. if (px2 < +Math.min(x1, x2).toFixed(2) ||
  667. px2 > +Math.max(x1, x2).toFixed(2) ||
  668. px2 < +Math.min(x3, x4).toFixed(2) ||
  669. px2 > +Math.max(x3, x4).toFixed(2) ||
  670. py2 < +Math.min(y1, y2).toFixed(2) ||
  671. py2 > +Math.max(y1, y2).toFixed(2) ||
  672. py2 < +Math.min(y3, y4).toFixed(2) ||
  673. py2 > +Math.max(y3, y4).toFixed(2)) {
  674. return;
  675. }
  676. return {
  677. x: px,
  678. y: py,
  679. };
  680. };
  681. var isPointInsideBBox = function (bbox, x, y) {
  682. return x >= bbox.x && x <= bbox.x + bbox.width && y >= bbox.y && y <= bbox.y + bbox.height;
  683. };
  684. var rectPath = function (x, y, w, h, r) {
  685. if (r) {
  686. return [
  687. ['M', +x + +r, y],
  688. ['l', w - r * 2, 0],
  689. ['a', r, r, 0, 0, 1, r, r],
  690. ['l', 0, h - r * 2],
  691. ['a', r, r, 0, 0, 1, -r, r],
  692. ['l', r * 2 - w, 0],
  693. ['a', r, r, 0, 0, 1, -r, -r],
  694. ['l', 0, r * 2 - h],
  695. ['a', r, r, 0, 0, 1, r, -r],
  696. ['z'],
  697. ];
  698. }
  699. var res = [['M', x, y], ['l', w, 0], ['l', 0, h], ['l', -w, 0], ['z']];
  700. // @ts-ignore
  701. res.parsePathArray = parsePathArray;
  702. return res;
  703. };
  704. var box = function (x, y, width, height) {
  705. if (x === null) {
  706. x = y = width = height = 0;
  707. }
  708. if (y === null) {
  709. y = x.y;
  710. width = x.width;
  711. height = x.height;
  712. x = x.x;
  713. }
  714. return {
  715. x: x,
  716. y: y,
  717. width: width,
  718. w: width,
  719. height: height,
  720. h: height,
  721. x2: x + width,
  722. y2: y + height,
  723. cx: x + width / 2,
  724. cy: y + height / 2,
  725. r1: Math.min(width, height) / 2,
  726. r2: Math.max(width, height) / 2,
  727. r0: Math.sqrt(width * width + height * height) / 2,
  728. path: rectPath(x, y, width, height),
  729. vb: [x, y, width, height].join(' '),
  730. };
  731. };
  732. var isBBoxIntersect = function (bbox1, bbox2) {
  733. bbox1 = box(bbox1);
  734. bbox2 = box(bbox2);
  735. return (isPointInsideBBox(bbox2, bbox1.x, bbox1.y) ||
  736. isPointInsideBBox(bbox2, bbox1.x2, bbox1.y) ||
  737. isPointInsideBBox(bbox2, bbox1.x, bbox1.y2) ||
  738. isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2) ||
  739. isPointInsideBBox(bbox1, bbox2.x, bbox2.y) ||
  740. isPointInsideBBox(bbox1, bbox2.x2, bbox2.y) ||
  741. isPointInsideBBox(bbox1, bbox2.x, bbox2.y2) ||
  742. isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2) ||
  743. (((bbox1.x < bbox2.x2 && bbox1.x > bbox2.x) || (bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)) &&
  744. ((bbox1.y < bbox2.y2 && bbox1.y > bbox2.y) || (bbox2.y < bbox1.y2 && bbox2.y > bbox1.y))));
  745. };
  746. var bezierBBox = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
  747. if (!isArray(p1x)) {
  748. p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
  749. }
  750. var bbox = curveDim.apply(null, p1x);
  751. return box(bbox.min.x, bbox.min.y, bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y);
  752. };
  753. var findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
  754. var t1 = 1 - t;
  755. var t13 = Math.pow(t1, 3);
  756. var t12 = Math.pow(t1, 2);
  757. var t2 = t * t;
  758. var t3 = t2 * t;
  759. var x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x;
  760. var y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y;
  761. var mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x);
  762. var my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y);
  763. var nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x);
  764. var ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y);
  765. var ax = t1 * p1x + t * c1x;
  766. var ay = t1 * p1y + t * c1y;
  767. var cx = t1 * c2x + t * p2x;
  768. var cy = t1 * c2y + t * p2y;
  769. var alpha = 90 - (Math.atan2(mx - nx, my - ny) * 180) / Math.PI;
  770. // (mx > nx || my < ny) && (alpha += 180);
  771. return {
  772. x: x,
  773. y: y,
  774. m: {
  775. x: mx,
  776. y: my,
  777. },
  778. n: {
  779. x: nx,
  780. y: ny,
  781. },
  782. start: {
  783. x: ax,
  784. y: ay,
  785. },
  786. end: {
  787. x: cx,
  788. y: cy,
  789. },
  790. alpha: alpha,
  791. };
  792. };
  793. var interHelper = function (bez1, bez2, justCount) {
  794. var bbox1 = bezierBBox(bez1);
  795. var bbox2 = bezierBBox(bez2);
  796. if (!isBBoxIntersect(bbox1, bbox2)) {
  797. return justCount ? 0 : [];
  798. }
  799. var l1 = bezlen.apply(0, bez1);
  800. var l2 = bezlen.apply(0, bez2);
  801. var n1 = ~~(l1 / 8);
  802. var n2 = ~~(l2 / 8);
  803. var dots1 = [];
  804. var dots2 = [];
  805. var xy = {};
  806. var res = justCount ? 0 : [];
  807. for (var i = 0; i < n1 + 1; i++) {
  808. var d = findDotsAtSegment.apply(0, bez1.concat(i / n1));
  809. dots1.push({
  810. x: d.x,
  811. y: d.y,
  812. t: i / n1,
  813. });
  814. }
  815. for (var i = 0; i < n2 + 1; i++) {
  816. var d = findDotsAtSegment.apply(0, bez2.concat(i / n2));
  817. dots2.push({
  818. x: d.x,
  819. y: d.y,
  820. t: i / n2,
  821. });
  822. }
  823. for (var i = 0; i < n1; i++) {
  824. for (var j = 0; j < n2; j++) {
  825. var di = dots1[i];
  826. var di1 = dots1[i + 1];
  827. var dj = dots2[j];
  828. var dj1 = dots2[j + 1];
  829. var ci = Math.abs(di1.x - di.x) < 0.001 ? 'y' : 'x';
  830. var cj = Math.abs(dj1.x - dj.x) < 0.001 ? 'y' : 'x';
  831. var is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
  832. if (is) {
  833. if (xy[is.x.toFixed(4)] === is.y.toFixed(4)) {
  834. continue;
  835. }
  836. xy[is.x.toFixed(4)] = is.y.toFixed(4);
  837. var t1 = di.t + Math.abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t);
  838. var t2 = dj.t + Math.abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
  839. if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
  840. if (justCount) {
  841. // @ts-ignore
  842. res += 1;
  843. }
  844. else {
  845. // @ts-ignore
  846. res.push({
  847. x: is.x,
  848. y: is.y,
  849. t1: t1,
  850. t2: t2,
  851. });
  852. }
  853. }
  854. }
  855. }
  856. }
  857. return res;
  858. };
  859. var interPathHelper = function (path1, path2, justCount) {
  860. path1 = pathToCurve(path1);
  861. path2 = pathToCurve(path2);
  862. var x1;
  863. var y1;
  864. var x2;
  865. var y2;
  866. var x1m;
  867. var y1m;
  868. var x2m;
  869. var y2m;
  870. var bez1;
  871. var bez2;
  872. var res = justCount ? 0 : [];
  873. for (var i = 0, ii = path1.length; i < ii; i++) {
  874. var pi = path1[i];
  875. if (pi[0] === 'M') {
  876. x1 = x1m = pi[1];
  877. y1 = y1m = pi[2];
  878. }
  879. else {
  880. if (pi[0] === 'C') {
  881. bez1 = [x1, y1].concat(pi.slice(1));
  882. x1 = bez1[6];
  883. y1 = bez1[7];
  884. }
  885. else {
  886. bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
  887. x1 = x1m;
  888. y1 = y1m;
  889. }
  890. for (var j = 0, jj = path2.length; j < jj; j++) {
  891. var pj = path2[j];
  892. if (pj[0] === 'M') {
  893. x2 = x2m = pj[1];
  894. y2 = y2m = pj[2];
  895. }
  896. else {
  897. if (pj[0] === 'C') {
  898. bez2 = [x2, y2].concat(pj.slice(1));
  899. x2 = bez2[6];
  900. y2 = bez2[7];
  901. }
  902. else {
  903. bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
  904. x2 = x2m;
  905. y2 = y2m;
  906. }
  907. var intr = interHelper(bez1, bez2, justCount);
  908. if (justCount) {
  909. // @ts-ignore
  910. res += intr;
  911. }
  912. else {
  913. // @ts-ignore
  914. for (var k = 0, kk = intr.length; k < kk; k++) {
  915. intr[k].segment1 = i;
  916. intr[k].segment2 = j;
  917. intr[k].bez1 = bez1;
  918. intr[k].bez2 = bez2;
  919. }
  920. // @ts-ignore
  921. res = res.concat(intr);
  922. }
  923. }
  924. }
  925. }
  926. }
  927. return res;
  928. };
  929. var intersection = function (path1, path2) {
  930. return interPathHelper(path1, path2);
  931. };
  932. function decasteljau(points, t) {
  933. var left = [];
  934. var right = [];
  935. function recurse(points, t) {
  936. if (points.length === 1) {
  937. left.push(points[0]);
  938. right.push(points[0]);
  939. }
  940. else {
  941. var middlePoints = [];
  942. for (var i = 0; i < points.length - 1; i++) {
  943. if (i === 0) {
  944. left.push(points[0]);
  945. }
  946. if (i === points.length - 2) {
  947. right.push(points[i + 1]);
  948. }
  949. middlePoints[i] = [
  950. (1 - t) * points[i][0] + t * points[i + 1][0],
  951. (1 - t) * points[i][1] + t * points[i + 1][1],
  952. ];
  953. }
  954. recurse(middlePoints, t);
  955. }
  956. }
  957. if (points.length) {
  958. recurse(points, t);
  959. }
  960. return { left: left, right: right.reverse() };
  961. }
  962. function splitCurve(start, end, count) {
  963. var points = [[start[1], start[2]]];
  964. count = count || 2;
  965. var segments = [];
  966. if (end[0] === 'A') {
  967. points.push(end[6]);
  968. points.push(end[7]);
  969. }
  970. else if (end[0] === 'C') {
  971. points.push([end[1], end[2]]);
  972. points.push([end[3], end[4]]);
  973. points.push([end[5], end[6]]);
  974. }
  975. else if (end[0] === 'S' || end[0] === 'Q') {
  976. points.push([end[1], end[2]]);
  977. points.push([end[3], end[4]]);
  978. }
  979. else {
  980. points.push([end[1], end[2]]);
  981. }
  982. var leftSegments = points;
  983. var t = 1 / count;
  984. for (var i = 0; i < count - 1; i++) {
  985. var rt = t / (1 - t * i);
  986. var split = decasteljau(leftSegments, rt);
  987. segments.push(split.left);
  988. leftSegments = split.right;
  989. }
  990. segments.push(leftSegments);
  991. var result = segments.map(function (segment) {
  992. var cmd = [];
  993. if (segment.length === 4) {
  994. cmd.push('C');
  995. cmd = cmd.concat(segment[2]);
  996. }
  997. if (segment.length >= 3) {
  998. if (segment.length === 3) {
  999. cmd.push('Q');
  1000. }
  1001. cmd = cmd.concat(segment[1]);
  1002. }
  1003. if (segment.length === 2) {
  1004. cmd.push('L');
  1005. }
  1006. cmd = cmd.concat(segment[segment.length - 1]);
  1007. return cmd;
  1008. });
  1009. return result;
  1010. }
  1011. var splitSegment = function (start, end, count) {
  1012. if (count === 1) {
  1013. return [[].concat(start)];
  1014. }
  1015. var segments = [];
  1016. if (end[0] === 'L' || end[0] === 'C' || end[0] === 'Q') {
  1017. segments = segments.concat(splitCurve(start, end, count));
  1018. }
  1019. else {
  1020. var temp = [].concat(start);
  1021. if (temp[0] === 'M') {
  1022. temp[0] = 'L';
  1023. }
  1024. for (var i = 0; i <= count - 1; i++) {
  1025. segments.push(temp);
  1026. }
  1027. }
  1028. return segments;
  1029. };
  1030. var fillPath = function (source, target) {
  1031. if (source.length === 1) {
  1032. return source;
  1033. }
  1034. var sourceLen = source.length - 1;
  1035. var targetLen = target.length - 1;
  1036. var ratio = sourceLen / targetLen;
  1037. var segmentsToFill = [];
  1038. if (source.length === 1 && source[0][0] === 'M') {
  1039. for (var i = 0; i < targetLen - sourceLen; i++) {
  1040. source.push(source[0]);
  1041. }
  1042. return source;
  1043. }
  1044. for (var i = 0; i < targetLen; i++) {
  1045. var index = Math.floor(ratio * i);
  1046. segmentsToFill[index] = (segmentsToFill[index] || 0) + 1;
  1047. }
  1048. var filled = segmentsToFill.reduce(function (filled, count, i) {
  1049. if (i === sourceLen) {
  1050. return filled.concat(source[sourceLen]);
  1051. }
  1052. return filled.concat(splitSegment(source[i], source[i + 1], count));
  1053. }, []);
  1054. filled.unshift(source[0]);
  1055. if (target[targetLen] === 'Z' || target[targetLen] === 'z') {
  1056. filled.push('Z');
  1057. }
  1058. return filled;
  1059. };
  1060. var isEqual = function (obj1, obj2) {
  1061. if (obj1.length !== obj2.length) {
  1062. return false;
  1063. }
  1064. var result = true;
  1065. each(obj1, function (item, i) {
  1066. if (item !== obj2[i]) {
  1067. result = false;
  1068. return false;
  1069. }
  1070. });
  1071. return result;
  1072. };
  1073. function getMinDiff(del, add, modify) {
  1074. var type = null;
  1075. var min = modify;
  1076. if (add < min) {
  1077. min = add;
  1078. type = 'add';
  1079. }
  1080. if (del < min) {
  1081. min = del;
  1082. type = 'del';
  1083. }
  1084. return {
  1085. type: type,
  1086. min: min,
  1087. };
  1088. }
  1089. /*
  1090. * https://en.wikipedia.org/wiki/Levenshtein_distance
  1091. * 计算两条path的编辑距离
  1092. */
  1093. var levenshteinDistance = function (source, target) {
  1094. var sourceLen = source.length;
  1095. var targetLen = target.length;
  1096. var sourceSegment;
  1097. var targetSegment;
  1098. var temp = 0;
  1099. if (sourceLen === 0 || targetLen === 0) {
  1100. return null;
  1101. }
  1102. var dist = [];
  1103. for (var i = 0; i <= sourceLen; i++) {
  1104. dist[i] = [];
  1105. dist[i][0] = { min: i };
  1106. }
  1107. for (var j = 0; j <= targetLen; j++) {
  1108. dist[0][j] = { min: j };
  1109. }
  1110. for (var i = 1; i <= sourceLen; i++) {
  1111. sourceSegment = source[i - 1];
  1112. for (var j = 1; j <= targetLen; j++) {
  1113. targetSegment = target[j - 1];
  1114. if (isEqual(sourceSegment, targetSegment)) {
  1115. temp = 0;
  1116. }
  1117. else {
  1118. temp = 1;
  1119. }
  1120. var del = dist[i - 1][j].min + 1;
  1121. var add = dist[i][j - 1].min + 1;
  1122. var modify = dist[i - 1][j - 1].min + temp;
  1123. dist[i][j] = getMinDiff(del, add, modify);
  1124. }
  1125. }
  1126. return dist;
  1127. };
  1128. var fillPathByDiff = function (source, target) {
  1129. var diffMatrix = levenshteinDistance(source, target);
  1130. var sourceLen = source.length;
  1131. var targetLen = target.length;
  1132. var changes = [];
  1133. var index = 1;
  1134. var minPos = 1;
  1135. // 如果source和target不是完全不相等
  1136. if (diffMatrix[sourceLen][targetLen].min !== sourceLen) {
  1137. // 获取从source到target所需改动
  1138. for (var i = 1; i <= sourceLen; i++) {
  1139. var min = diffMatrix[i][i].min;
  1140. minPos = i;
  1141. for (var j = index; j <= targetLen; j++) {
  1142. if (diffMatrix[i][j].min < min) {
  1143. min = diffMatrix[i][j].min;
  1144. minPos = j;
  1145. }
  1146. }
  1147. index = minPos;
  1148. if (diffMatrix[i][index].type) {
  1149. changes.push({ index: i - 1, type: diffMatrix[i][index].type });
  1150. }
  1151. }
  1152. // 对source进行增删path
  1153. for (var i = changes.length - 1; i >= 0; i--) {
  1154. index = changes[i].index;
  1155. if (changes[i].type === 'add') {
  1156. source.splice(index, 0, [].concat(source[index]));
  1157. }
  1158. else {
  1159. source.splice(index, 1);
  1160. }
  1161. }
  1162. }
  1163. // source尾部补齐
  1164. sourceLen = source.length;
  1165. var diff = targetLen - sourceLen;
  1166. if (sourceLen < targetLen) {
  1167. for (var i = 0; i < diff; i++) {
  1168. if (source[sourceLen - 1][0] === 'z' || source[sourceLen - 1][0] === 'Z') {
  1169. source.splice(sourceLen - 2, 0, source[sourceLen - 2]);
  1170. }
  1171. else {
  1172. source.push(source[sourceLen - 1]);
  1173. }
  1174. sourceLen += 1;
  1175. }
  1176. }
  1177. return source;
  1178. };
  1179. // 将两个点均分成count个点
  1180. function _splitPoints(points, former, count) {
  1181. var result = [].concat(points);
  1182. var index;
  1183. var t = 1 / (count + 1);
  1184. var formerEnd = _getSegmentPoints(former)[0];
  1185. for (var i = 1; i <= count; i++) {
  1186. t *= i;
  1187. index = Math.floor(points.length * t);
  1188. if (index === 0) {
  1189. result.unshift([formerEnd[0] * t + points[index][0] * (1 - t), formerEnd[1] * t + points[index][1] * (1 - t)]);
  1190. }
  1191. else {
  1192. result.splice(index, 0, [
  1193. formerEnd[0] * t + points[index][0] * (1 - t),
  1194. formerEnd[1] * t + points[index][1] * (1 - t),
  1195. ]);
  1196. }
  1197. }
  1198. return result;
  1199. }
  1200. /*
  1201. * 抽取pathSegment中的关键点
  1202. * M,L,A,Q,H,V一个端点
  1203. * Q, S抽取一个端点,一个控制点
  1204. * C抽取一个端点,两个控制点
  1205. */
  1206. function _getSegmentPoints(segment) {
  1207. var points = [];
  1208. switch (segment[0]) {
  1209. case 'M':
  1210. points.push([segment[1], segment[2]]);
  1211. break;
  1212. case 'L':
  1213. points.push([segment[1], segment[2]]);
  1214. break;
  1215. case 'A':
  1216. points.push([segment[6], segment[7]]);
  1217. break;
  1218. case 'Q':
  1219. points.push([segment[3], segment[4]]);
  1220. points.push([segment[1], segment[2]]);
  1221. break;
  1222. case 'T':
  1223. points.push([segment[1], segment[2]]);
  1224. break;
  1225. case 'C':
  1226. points.push([segment[5], segment[6]]);
  1227. points.push([segment[1], segment[2]]);
  1228. points.push([segment[3], segment[4]]);
  1229. break;
  1230. case 'S':
  1231. points.push([segment[3], segment[4]]);
  1232. points.push([segment[1], segment[2]]);
  1233. break;
  1234. case 'H':
  1235. points.push([segment[1], segment[1]]);
  1236. break;
  1237. case 'V':
  1238. points.push([segment[1], segment[1]]);
  1239. break;
  1240. default:
  1241. }
  1242. return points;
  1243. }
  1244. var formatPath = function (fromPath, toPath) {
  1245. if (fromPath.length <= 1) {
  1246. return fromPath;
  1247. }
  1248. var points;
  1249. for (var i = 0; i < toPath.length; i++) {
  1250. if (fromPath[i][0] !== toPath[i][0]) {
  1251. // 获取fromPath的pathSegment的端点,根据toPath的指令对其改造
  1252. points = _getSegmentPoints(fromPath[i]);
  1253. switch (toPath[i][0]) {
  1254. case 'M':
  1255. fromPath[i] = ['M'].concat(points[0]);
  1256. break;
  1257. case 'L':
  1258. fromPath[i] = ['L'].concat(points[0]);
  1259. break;
  1260. case 'A':
  1261. fromPath[i] = [].concat(toPath[i]);
  1262. fromPath[i][6] = points[0][0];
  1263. fromPath[i][7] = points[0][1];
  1264. break;
  1265. case 'Q':
  1266. if (points.length < 2) {
  1267. if (i > 0) {
  1268. points = _splitPoints(points, fromPath[i - 1], 1);
  1269. }
  1270. else {
  1271. fromPath[i] = toPath[i];
  1272. break;
  1273. }
  1274. }
  1275. fromPath[i] = ['Q'].concat(points.reduce(function (arr, i) {
  1276. return arr.concat(i);
  1277. }, []));
  1278. break;
  1279. case 'T':
  1280. fromPath[i] = ['T'].concat(points[0]);
  1281. break;
  1282. case 'C':
  1283. if (points.length < 3) {
  1284. if (i > 0) {
  1285. points = _splitPoints(points, fromPath[i - 1], 2);
  1286. }
  1287. else {
  1288. fromPath[i] = toPath[i];
  1289. break;
  1290. }
  1291. }
  1292. fromPath[i] = ['C'].concat(points.reduce(function (arr, i) {
  1293. return arr.concat(i);
  1294. }, []));
  1295. break;
  1296. case 'S':
  1297. if (points.length < 2) {
  1298. if (i > 0) {
  1299. points = _splitPoints(points, fromPath[i - 1], 1);
  1300. }
  1301. else {
  1302. fromPath[i] = toPath[i];
  1303. break;
  1304. }
  1305. }
  1306. fromPath[i] = ['S'].concat(points.reduce(function (arr, i) {
  1307. return arr.concat(i);
  1308. }, []));
  1309. break;
  1310. default:
  1311. fromPath[i] = toPath[i];
  1312. }
  1313. }
  1314. }
  1315. return fromPath;
  1316. };
  1317. export { catmullRomToBezier, fillPath, fillPathByDiff, formatPath, intersection, parsePathArray, parsePathString, pathToAbsolute, pathToCurve, rectPath, };
  1318. //# sourceMappingURL=path.js.map