pasition.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /**
  2. * pasition v1.0.2 By dntzhang
  3. * Github: https://github.com/AlloyTeam/pasition
  4. * MIT Licensed.
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  8. typeof define === 'function' && define.amd ? define(factory) :
  9. (global.pasition = factory());
  10. }(this, (function () { 'use strict';
  11. var slicedToArray = function () {
  12. function sliceIterator(arr, i) {
  13. var _arr = [];
  14. var _n = true;
  15. var _d = false;
  16. var _e = undefined;
  17. try {
  18. for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
  19. _arr.push(_s.value);
  20. if (i && _arr.length === i) break;
  21. }
  22. } catch (err) {
  23. _d = true;
  24. _e = err;
  25. } finally {
  26. try {
  27. if (!_n && _i["return"]) _i["return"]();
  28. } finally {
  29. if (_d) throw _e;
  30. }
  31. }
  32. return _arr;
  33. }
  34. return function (arr, i) {
  35. if (Array.isArray(arr)) {
  36. return arr;
  37. } else if (Symbol.iterator in Object(arr)) {
  38. return sliceIterator(arr, i);
  39. } else {
  40. throw new TypeError("Invalid attempt to destructure non-iterable instance");
  41. }
  42. };
  43. }();
  44. //https://github.com/colinmeinke/svg-arc-to-cubic-bezier
  45. var TAU = Math.PI * 2;
  46. var mapToEllipse = function mapToEllipse(_ref, rx, ry, cosphi, sinphi, centerx, centery) {
  47. var x = _ref.x,
  48. y = _ref.y;
  49. x *= rx;
  50. y *= ry;
  51. var xp = cosphi * x - sinphi * y;
  52. var yp = sinphi * x + cosphi * y;
  53. return {
  54. x: xp + centerx,
  55. y: yp + centery
  56. };
  57. };
  58. var approxUnitArc = function approxUnitArc(ang1, ang2) {
  59. var a = 4 / 3 * Math.tan(ang2 / 4);
  60. var x1 = Math.cos(ang1);
  61. var y1 = Math.sin(ang1);
  62. var x2 = Math.cos(ang1 + ang2);
  63. var y2 = Math.sin(ang1 + ang2);
  64. return [{
  65. x: x1 - y1 * a,
  66. y: y1 + x1 * a
  67. }, {
  68. x: x2 + y2 * a,
  69. y: y2 - x2 * a
  70. }, {
  71. x: x2,
  72. y: y2
  73. }];
  74. };
  75. var vectorAngle = function vectorAngle(ux, uy, vx, vy) {
  76. var sign = ux * vy - uy * vx < 0 ? -1 : 1;
  77. var umag = Math.sqrt(ux * ux + uy * uy);
  78. var vmag = Math.sqrt(ux * ux + uy * uy);
  79. var dot = ux * vx + uy * vy;
  80. var div = dot / (umag * vmag);
  81. if (div > 1) {
  82. div = 1;
  83. }
  84. if (div < -1) {
  85. div = -1;
  86. }
  87. return sign * Math.acos(div);
  88. };
  89. var getArcCenter = function getArcCenter(px, py, cx, cy, rx, ry, largeArcFlag, sweepFlag, sinphi, cosphi, pxp, pyp) {
  90. var rxsq = Math.pow(rx, 2);
  91. var rysq = Math.pow(ry, 2);
  92. var pxpsq = Math.pow(pxp, 2);
  93. var pypsq = Math.pow(pyp, 2);
  94. var radicant = rxsq * rysq - rxsq * pypsq - rysq * pxpsq;
  95. if (radicant < 0) {
  96. radicant = 0;
  97. }
  98. radicant /= rxsq * pypsq + rysq * pxpsq;
  99. radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1);
  100. var centerxp = radicant * rx / ry * pyp;
  101. var centeryp = radicant * -ry / rx * pxp;
  102. var centerx = cosphi * centerxp - sinphi * centeryp + (px + cx) / 2;
  103. var centery = sinphi * centerxp + cosphi * centeryp + (py + cy) / 2;
  104. var vx1 = (pxp - centerxp) / rx;
  105. var vy1 = (pyp - centeryp) / ry;
  106. var vx2 = (-pxp - centerxp) / rx;
  107. var vy2 = (-pyp - centeryp) / ry;
  108. var ang1 = vectorAngle(1, 0, vx1, vy1);
  109. var ang2 = vectorAngle(vx1, vy1, vx2, vy2);
  110. if (sweepFlag === 0 && ang2 > 0) {
  111. ang2 -= TAU;
  112. }
  113. if (sweepFlag === 1 && ang2 < 0) {
  114. ang2 += TAU;
  115. }
  116. return [centerx, centery, ang1, ang2];
  117. };
  118. var arcToBezier = function arcToBezier(_ref2) {
  119. var px = _ref2.px,
  120. py = _ref2.py,
  121. cx = _ref2.cx,
  122. cy = _ref2.cy,
  123. rx = _ref2.rx,
  124. ry = _ref2.ry,
  125. _ref2$xAxisRotation = _ref2.xAxisRotation,
  126. xAxisRotation = _ref2$xAxisRotation === undefined ? 0 : _ref2$xAxisRotation,
  127. _ref2$largeArcFlag = _ref2.largeArcFlag,
  128. largeArcFlag = _ref2$largeArcFlag === undefined ? 0 : _ref2$largeArcFlag,
  129. _ref2$sweepFlag = _ref2.sweepFlag,
  130. sweepFlag = _ref2$sweepFlag === undefined ? 0 : _ref2$sweepFlag;
  131. var curves = [];
  132. if (rx === 0 || ry === 0) {
  133. return [];
  134. }
  135. var sinphi = Math.sin(xAxisRotation * TAU / 360);
  136. var cosphi = Math.cos(xAxisRotation * TAU / 360);
  137. var pxp = cosphi * (px - cx) / 2 + sinphi * (py - cy) / 2;
  138. var pyp = -sinphi * (px - cx) / 2 + cosphi * (py - cy) / 2;
  139. if (pxp === 0 && pyp === 0) {
  140. return [];
  141. }
  142. rx = Math.abs(rx);
  143. ry = Math.abs(ry);
  144. var lambda = Math.pow(pxp, 2) / Math.pow(rx, 2) + Math.pow(pyp, 2) / Math.pow(ry, 2);
  145. if (lambda > 1) {
  146. rx *= Math.sqrt(lambda);
  147. ry *= Math.sqrt(lambda);
  148. }
  149. var _getArcCenter = getArcCenter(px, py, cx, cy, rx, ry, largeArcFlag, sweepFlag, sinphi, cosphi, pxp, pyp),
  150. _getArcCenter2 = slicedToArray(_getArcCenter, 4),
  151. centerx = _getArcCenter2[0],
  152. centery = _getArcCenter2[1],
  153. ang1 = _getArcCenter2[2],
  154. ang2 = _getArcCenter2[3];
  155. var segments = Math.max(Math.ceil(Math.abs(ang2) / (TAU / 4)), 1);
  156. ang2 /= segments;
  157. for (var i = 0; i < segments; i++) {
  158. curves.push(approxUnitArc(ang1, ang2));
  159. ang1 += ang2;
  160. }
  161. return curves.map(function (curve) {
  162. var _mapToEllipse = mapToEllipse(curve[0], rx, ry, cosphi, sinphi, centerx, centery),
  163. x1 = _mapToEllipse.x,
  164. y1 = _mapToEllipse.y;
  165. var _mapToEllipse2 = mapToEllipse(curve[1], rx, ry, cosphi, sinphi, centerx, centery),
  166. x2 = _mapToEllipse2.x,
  167. y2 = _mapToEllipse2.y;
  168. var _mapToEllipse3 = mapToEllipse(curve[2], rx, ry, cosphi, sinphi, centerx, centery),
  169. x = _mapToEllipse3.x,
  170. y = _mapToEllipse3.y;
  171. return { x1: x1, y1: y1, x2: x2, y2: y2, x: x, y: y };
  172. });
  173. };
  174. //https://github.com/jkroso/parse-svg-path/blob/master/index.js
  175. /**
  176. * expected argument lengths
  177. * @type {Object}
  178. */
  179. var length = { a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0
  180. /**
  181. * segment pattern
  182. * @type {RegExp}
  183. */
  184. };var segment = /([astvzqmhlc])([^astvzqmhlc]*)/ig;
  185. /**
  186. * parse an svg path data string. Generates an Array
  187. * of commands where each command is an Array of the
  188. * form `[command, arg1, arg2, ...]`
  189. *
  190. * @param {String} path
  191. * @return {Array}
  192. */
  193. function parse(path) {
  194. var data = [];
  195. path.replace(segment, function (_, command, args) {
  196. var type = command.toLowerCase();
  197. args = parseValues(args);
  198. // overloaded moveTo
  199. if (type == 'm' && args.length > 2) {
  200. data.push([command].concat(args.splice(0, 2)));
  201. type = 'l';
  202. command = command == 'm' ? 'l' : 'L';
  203. }
  204. while (true) {
  205. if (args.length == length[type]) {
  206. args.unshift(command);
  207. return data.push(args);
  208. }
  209. if (args.length < length[type]) throw new Error('malformed path data');
  210. data.push([command].concat(args.splice(0, length[type])));
  211. }
  212. });
  213. return data;
  214. }
  215. var number = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/ig;
  216. function parseValues(args) {
  217. var numbers = args.match(number);
  218. return numbers ? numbers.map(Number) : [];
  219. }
  220. function shapeBox(shape) {
  221. var minX = shape[0][0],
  222. minY = shape[0][1],
  223. maxX = minX,
  224. maxY = minY;
  225. shape.forEach(function (curve) {
  226. var x1 = curve[0],
  227. x2 = curve[2],
  228. x3 = curve[4],
  229. x4 = curve[6],
  230. y1 = curve[1],
  231. y2 = curve[3],
  232. y3 = curve[5],
  233. y4 = curve[7];
  234. minX = Math.min(minX, x1, x2, x3, x4);
  235. minY = Math.min(minY, y1, y2, y3, y4);
  236. maxX = Math.max(maxX, x1, x2, x3, x4);
  237. maxY = Math.max(maxY, y1, y2, y3, y4);
  238. });
  239. return [minX, minY, maxX, maxY];
  240. }
  241. function boxDistance(boxA, boxB) {
  242. return Math.sqrt(Math.pow(boxA[0] - boxB[0], 2) + Math.pow(boxA[1] - boxB[1], 2)) + Math.sqrt(Math.pow(boxA[2] - boxB[2], 2) + Math.pow(boxA[3] - boxB[3], 2));
  243. }
  244. function curveDistance(curveA, curveB) {
  245. var x1 = curveA[0],
  246. x2 = curveA[2],
  247. x3 = curveA[4],
  248. x4 = curveA[6],
  249. y1 = curveA[1],
  250. y2 = curveA[3],
  251. y3 = curveA[5],
  252. y4 = curveA[7],
  253. xb1 = curveB[0],
  254. xb2 = curveB[2],
  255. xb3 = curveB[4],
  256. xb4 = curveB[6],
  257. yb1 = curveB[1],
  258. yb2 = curveB[3],
  259. yb3 = curveB[5],
  260. yb4 = curveB[7];
  261. return Math.sqrt(Math.pow(xb1 - x1, 2) + Math.pow(yb1 - y1, 2)) + Math.sqrt(Math.pow(xb2 - x2, 2) + Math.pow(yb2 - y2, 2)) + Math.sqrt(Math.pow(xb3 - x3, 2) + Math.pow(yb3 - y3, 2)) + Math.sqrt(Math.pow(xb4 - x4, 2) + Math.pow(yb4 - y4, 2));
  262. }
  263. function sortCurves(curvesA, curvesB) {
  264. var arrList = permuteCurveNum(curvesA.length);
  265. var list = [];
  266. arrList.forEach(function (arr) {
  267. var distance = 0;
  268. var i = 0;
  269. arr.forEach(function (index) {
  270. distance += curveDistance(curvesA[index], curvesB[i++]);
  271. });
  272. list.push({ index: arr, distance: distance });
  273. });
  274. list.sort(function (a, b) {
  275. return a.distance - b.distance;
  276. });
  277. var result = [];
  278. list[0].index.forEach(function (index) {
  279. result.push(curvesA[index]);
  280. });
  281. return result;
  282. }
  283. function sort(pathA, pathB) {
  284. var arrList = permuteNum(pathA.length);
  285. var list = [];
  286. arrList.forEach(function (arr) {
  287. var distance = 0;
  288. arr.forEach(function (index) {
  289. distance += boxDistance(shapeBox(pathA[index]), shapeBox(pathB[index]));
  290. });
  291. list.push({ index: arr, distance: distance });
  292. });
  293. list.sort(function (a, b) {
  294. return a.distance - b.distance;
  295. });
  296. var result = [];
  297. list[0].index.forEach(function (index) {
  298. result.push(pathA[index]);
  299. });
  300. return result;
  301. }
  302. function permuteCurveNum(num) {
  303. var arr = [];
  304. for (var i = 0; i < num; i++) {
  305. var indexArr = [];
  306. for (var j = 0; j < num; j++) {
  307. var index = j + i;
  308. if (index > num - 1) index -= num;
  309. indexArr[index] = j;
  310. }
  311. arr.push(indexArr);
  312. }
  313. return arr;
  314. }
  315. function permuteNum(num) {
  316. var arr = [];
  317. for (var i = 0; i < num; i++) {
  318. arr.push(i);
  319. }
  320. return permute(arr);
  321. }
  322. function permute(input) {
  323. var permArr = [],
  324. usedChars = [];
  325. function main(input) {
  326. var i, ch;
  327. for (i = 0; i < input.length; i++) {
  328. ch = input.splice(i, 1)[0];
  329. usedChars.push(ch);
  330. if (input.length == 0) {
  331. permArr.push(usedChars.slice());
  332. }
  333. main(input);
  334. input.splice(i, 0, ch);
  335. usedChars.pop();
  336. }
  337. return permArr;
  338. }
  339. return main(input);
  340. }
  341. var pasition = {};
  342. pasition.parser = parse;
  343. pasition.lerpCurve = function (pathA, pathB, t) {
  344. return pasition.lerpPoints(pathA[0], pathA[1], pathB[0], pathB[1], t).concat(pasition.lerpPoints(pathA[2], pathA[3], pathB[2], pathB[3], t)).concat(pasition.lerpPoints(pathA[4], pathA[5], pathB[4], pathB[5], t)).concat(pasition.lerpPoints(pathA[6], pathA[7], pathB[6], pathB[7], t));
  345. };
  346. pasition.lerpPoints = function (x1, y1, x2, y2, t) {
  347. return [x1 + (x2 - x1) * t, y1 + (y2 - y1) * t];
  348. };
  349. pasition.q2b = function (x1, y1, x2, y2, x3, y3) {
  350. return [x1, y1, (x1 + 2 * x2) / 3, (y1 + 2 * y2) / 3, (x3 + 2 * x2) / 3, (y3 + 2 * y2) / 3, x3, y3];
  351. };
  352. pasition.path2shapes = function (path) {
  353. //https://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial/Paths
  354. //M = moveto
  355. //L = lineto
  356. //H = horizontal lineto
  357. //V = vertical lineto
  358. //C = curveto
  359. //S = smooth curveto
  360. //Q = quadratic Belzier curve
  361. //T = smooth quadratic Belzier curveto
  362. //A = elliptical Arc
  363. //Z = closepath
  364. //以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位(从上一个点开始)。
  365. var cmds = pasition.parser(path),
  366. preX = 0,
  367. preY = 0,
  368. j = 0,
  369. len = cmds.length,
  370. shapes = [],
  371. current = null,
  372. closeX = void 0,
  373. closeY = void 0,
  374. preCX = void 0,
  375. preCY = void 0,
  376. sLen = void 0,
  377. curves = void 0,
  378. lastCurve = void 0;
  379. for (; j < len; j++) {
  380. var item = cmds[j];
  381. var action = item[0];
  382. var preItem = cmds[j - 1];
  383. switch (action) {
  384. case 'm':
  385. sLen = shapes.length;
  386. shapes[sLen] = [];
  387. current = shapes[sLen];
  388. preX = preX + item[1];
  389. preY = preY + item[2];
  390. break;
  391. case 'M':
  392. sLen = shapes.length;
  393. shapes[sLen] = [];
  394. current = shapes[sLen];
  395. preX = item[1];
  396. preY = item[2];
  397. break;
  398. case 'l':
  399. current.push([preX, preY, preX, preY, preX, preY, preX + item[1], preY + item[2]]);
  400. preX += item[1];
  401. preY += item[2];
  402. break;
  403. case 'L':
  404. current.push([preX, preY, item[1], item[2], item[1], item[2], item[1], item[2]]);
  405. preX = item[1];
  406. preY = item[2];
  407. break;
  408. case 'h':
  409. current.push([preX, preY, preX, preY, preX, preY, preX + item[1], preY]);
  410. preX += item[1];
  411. break;
  412. case 'H':
  413. current.push([preX, preY, item[1], preY, item[1], preY, item[1], preY]);
  414. preX = item[1];
  415. break;
  416. case 'v':
  417. current.push([preX, preY, preX, preY, preX, preY, preX, preY + item[1]]);
  418. preY += item[1];
  419. break;
  420. case 'V':
  421. current.push([preX, preY, preX, item[1], preX, item[1], preX, item[1]]);
  422. preY = item[1];
  423. break;
  424. case 'C':
  425. current.push([preX, preY, item[1], item[2], item[3], item[4], item[5], item[6]]);
  426. preX = item[5];
  427. preY = item[6];
  428. break;
  429. case 'S':
  430. if (preItem[0] === 'C' || preItem[0] === 'c') {
  431. current.push([preX, preY, preX + preItem[5] - preItem[3], preY + preItem[6] - preItem[4], item[1], item[2], item[3], item[4]]);
  432. } else if (preItem[0] === 'S' || preItem[0] === 's') {
  433. current.push([preX, preY, preX + preItem[3] - preItem[1], preY + preItem[4] - preItem[2], item[1], item[2], item[3], item[4]]);
  434. }
  435. preX = item[3];
  436. preY = item[4];
  437. break;
  438. case 'c':
  439. current.push([preX, preY, preX + item[1], preY + item[2], preX + item[3], preY + item[4], preX + item[5], preY + item[6]]);
  440. preX = preX + item[5];
  441. preY = preY + item[6];
  442. break;
  443. case 's':
  444. if (preItem[0] === 'C' || preItem[0] === 'c') {
  445. current.push([preX, preY, preX + preItem[5] - preItem[3], preY + preItem[6] - preItem[4], preX + item[1], preY + item[2], preX + item[3], preY + item[4]]);
  446. } else if (preItem[0] === 'S' || preItem[0] === 's') {
  447. current.push([preX, preY, preX + preItem[3] - preItem[1], preY + preItem[4] - preItem[2], preX + item[1], preY + item[2], preX + item[3], preY + item[4]]);
  448. }
  449. preX = preX + item[3];
  450. preY = preY + item[4];
  451. break;
  452. case 'a':
  453. curves = arcToBezier({
  454. rx: item[1],
  455. ry: item[2],
  456. px: preX,
  457. py: preY,
  458. xAxisRotation: item[3],
  459. largeArcFlag: item[4],
  460. sweepFlag: item[5],
  461. cx: preX + item[6],
  462. cy: preY + item[7]
  463. });
  464. lastCurve = curves[curves.length - 1];
  465. curves.forEach(function (curve, index) {
  466. if (index === 0) {
  467. current.push([preX, preY, curve.x1, curve.y1, curve.x2, curve.y2, curve.x, curve.y]);
  468. } else {
  469. current.push([curves[index - 1].x, curves[index - 1].y, curve.x1, curve.y1, curve.x2, curve.y2, curve.x, curve.y]);
  470. }
  471. });
  472. preX = lastCurve.x;
  473. preY = lastCurve.y;
  474. break;
  475. case 'A':
  476. curves = arcToBezier({
  477. rx: item[1],
  478. ry: item[2],
  479. px: preX,
  480. py: preY,
  481. xAxisRotation: item[3],
  482. largeArcFlag: item[4],
  483. sweepFlag: item[5],
  484. cx: item[6],
  485. cy: item[7]
  486. });
  487. lastCurve = curves[curves.length - 1];
  488. curves.forEach(function (curve, index) {
  489. if (index === 0) {
  490. current.push([preX, preY, curve.x1, curve.y1, curve.x2, curve.y2, curve.x, curve.y]);
  491. } else {
  492. current.push([curves[index - 1].x, curves[index - 1].y, curve.x1, curve.y1, curve.x2, curve.y2, curve.x, curve.y]);
  493. }
  494. });
  495. preX = lastCurve.x;
  496. preY = lastCurve.y;
  497. break;
  498. case 'Q':
  499. current.push(pasition.q2b(preX, preY, item[1], item[2], item[3], item[4]));
  500. preX = item[3];
  501. preY = item[4];
  502. break;
  503. case 'q':
  504. current.push(pasition.q2b(preX, preY, preX + item[1], preY + item[2], item[3] + preX, item[4] + preY));
  505. preX += item[3];
  506. preY += item[4];
  507. break;
  508. case 'T':
  509. if (preItem[0] === 'Q' || preItem[0] === 'q') {
  510. preCX = preX + preItem[3] - preItem[1];
  511. preCY = preY + preItem[4] - preItem[2];
  512. current.push(pasition.q2b(preX, preY, preCX, preCY, item[1], item[2]));
  513. } else if (preItem[0] === 'T' || preItem[0] === 't') {
  514. current.push(pasition.q2b(preX, preY, preX + preX - preCX, preY + preY - preCY, item[1], item[2]));
  515. preCX = preX + preX - preCX;
  516. preCY = preY + preY - preCY;
  517. }
  518. preX = item[1];
  519. preY = item[2];
  520. break;
  521. case 't':
  522. if (preItem[0] === 'Q' || preItem[0] === 'q') {
  523. preCX = preX + preItem[3] - preItem[1];
  524. preCY = preY + preItem[4] - preItem[2];
  525. current.push(pasition.q2b(preX, preY, preCX, preCY, preX + item[1], preY + item[2]));
  526. } else if (preItem[0] === 'T' || preItem[0] === 't') {
  527. current.push(pasition.q2b(preX, preY, preX + preX - preCX, preY + preY - preCY, preX + item[1], preY + item[2]));
  528. preCX = preX + preX - preCX;
  529. preCY = preY + preY - preCY;
  530. }
  531. preX += item[1];
  532. preY += item[2];
  533. break;
  534. case 'Z':
  535. closeX = current[0][0];
  536. closeY = current[0][1];
  537. current.push([preX, preY, closeX, closeY, closeX, closeY, closeX, closeY]);
  538. break;
  539. case 'z':
  540. closeX = current[0][0];
  541. closeY = current[0][1];
  542. current.push([preX, preY, closeX, closeY, closeX, closeY, closeX, closeY]);
  543. break;
  544. }
  545. }
  546. return shapes;
  547. };
  548. pasition._upCurves = function (curves, count) {
  549. var i = 0,
  550. index = 0,
  551. len = curves.length;
  552. for (; i < count; i++) {
  553. curves.push(curves[index].slice(0));
  554. index++;
  555. if (index > len - 1) {
  556. index -= len;
  557. }
  558. }
  559. };
  560. function split(x1, y1, x2, y2, x3, y3, x4, y4, t) {
  561. return {
  562. left: _split(x1, y1, x2, y2, x3, y3, x4, y4, t),
  563. right: _split(x4, y4, x3, y3, x2, y2, x1, y1, 1 - t, true)
  564. };
  565. }
  566. function _split(x1, y1, x2, y2, x3, y3, x4, y4, t, reverse) {
  567. var x12 = (x2 - x1) * t + x1;
  568. var y12 = (y2 - y1) * t + y1;
  569. var x23 = (x3 - x2) * t + x2;
  570. var y23 = (y3 - y2) * t + y2;
  571. var x34 = (x4 - x3) * t + x3;
  572. var y34 = (y4 - y3) * t + y3;
  573. var x123 = (x23 - x12) * t + x12;
  574. var y123 = (y23 - y12) * t + y12;
  575. var x234 = (x34 - x23) * t + x23;
  576. var y234 = (y34 - y23) * t + y23;
  577. var x1234 = (x234 - x123) * t + x123;
  578. var y1234 = (y234 - y123) * t + y123;
  579. if (reverse) {
  580. return [x1234, y1234, x123, y123, x12, y12, x1, y1];
  581. }
  582. return [x1, y1, x12, y12, x123, y123, x1234, y1234];
  583. }
  584. pasition._splitCurves = function (curves, count) {
  585. var i = 0,
  586. index = 0;
  587. for (; i < count; i++) {
  588. var curve = curves[index];
  589. var cs = split(curve[0], curve[1], curve[2], curve[3], curve[4], curve[5], curve[6], curve[7], 0.5);
  590. curves.splice(index, 1);
  591. curves.splice(index, 0, cs.left, cs.right);
  592. index += 2;
  593. if (index >= curves.length - 1) {
  594. index = 0;
  595. }
  596. }
  597. };
  598. function sync(shapes, count) {
  599. var _loop = function _loop(i) {
  600. var shape = shapes[shapes.length - 1];
  601. var newShape = [];
  602. shape.forEach(function (curve) {
  603. newShape.push(curve.slice(0));
  604. });
  605. shapes.push(newShape);
  606. };
  607. for (var i = 0; i < count; i++) {
  608. _loop(i);
  609. }
  610. }
  611. pasition.lerp = function (pathA, pathB, t) {
  612. return pasition._lerp(pasition.path2shapes(pathA), pasition.path2shapes(pathB), t);
  613. };
  614. pasition.MIM_CURVES_COUNT = 100;
  615. pasition._preprocessing = function (pathA, pathB) {
  616. var lenA = pathA.length,
  617. lenB = pathB.length,
  618. clonePathA = JSON.parse(JSON.stringify(pathA)),
  619. clonePathB = JSON.parse(JSON.stringify(pathB));
  620. if (lenA > lenB) {
  621. sync(clonePathB, lenA - lenB);
  622. } else if (lenA < lenB) {
  623. sync(clonePathA, lenB - lenA);
  624. }
  625. clonePathA = sort(clonePathA, clonePathB);
  626. clonePathA.forEach(function (curves, index) {
  627. var lenA = curves.length,
  628. lenB = clonePathB[index].length;
  629. if (lenA > lenB) {
  630. if (lenA < pasition.MIM_CURVES_COUNT) {
  631. pasition._splitCurves(curves, pasition.MIM_CURVES_COUNT - lenA);
  632. pasition._splitCurves(clonePathB[index], pasition.MIM_CURVES_COUNT - lenB);
  633. } else {
  634. pasition._splitCurves(clonePathB[index], lenA - lenB);
  635. }
  636. } else if (lenA < lenB) {
  637. if (lenB < pasition.MIM_CURVES_COUNT) {
  638. pasition._splitCurves(curves, pasition.MIM_CURVES_COUNT - lenA);
  639. pasition._splitCurves(clonePathB[index], pasition.MIM_CURVES_COUNT - lenB);
  640. } else {
  641. pasition._splitCurves(curves, lenB - lenA);
  642. }
  643. }
  644. });
  645. clonePathA.forEach(function (curves, index) {
  646. clonePathA[index] = sortCurves(curves, clonePathB[index]);
  647. });
  648. return [clonePathA, clonePathB];
  649. };
  650. pasition._lerp = function (pathA, pathB, t) {
  651. var shapes = [];
  652. pathA.forEach(function (curves, index) {
  653. var newCurves = [];
  654. curves.forEach(function (curve, curveIndex) {
  655. newCurves.push(pasition.lerpCurve(curve, pathB[index][curveIndex], t));
  656. });
  657. shapes.push(newCurves);
  658. });
  659. return shapes;
  660. };
  661. pasition.animate = function (option) {
  662. var pathA = pasition.path2shapes(option.from);
  663. var pathB = pasition.path2shapes(option.to);
  664. var pathArr = pasition._preprocessing(pathA, pathB);
  665. var beginTime = new Date(),
  666. end = option.end || function () {},
  667. progress = option.progress || function () {},
  668. begin = option.begin || function () {},
  669. easing = option.easing || function (v) {
  670. return v;
  671. },
  672. tickId = null,
  673. outShape = null,
  674. time = option.time;
  675. begin(pathA);
  676. var tick = function tick() {
  677. var dt = new Date() - beginTime;
  678. if (dt >= time) {
  679. outShape = pathB;
  680. progress(outShape, 1);
  681. end(outShape);
  682. cancelAnimationFrame(tickId);
  683. return;
  684. }
  685. var percent = easing(dt / time);
  686. outShape = pasition._lerp(pathArr[0], pathArr[1], percent);
  687. progress(outShape, percent);
  688. tickId = requestAnimationFrame(tick);
  689. };
  690. tick();
  691. };
  692. return pasition;
  693. })));