| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- var pathToAbsolute = require('./path2absolute');
- var a2c = function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
- // for more information of where this math came from visit:
- // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
- if (rx === ry) {
- rx += 1;
- }
- var _120 = Math.PI * 120 / 180;
- var rad = Math.PI / 180 * (+angle || 0);
- var res = [];
- var xy = void 0;
- var f1 = void 0;
- var f2 = void 0;
- var cx = void 0;
- var cy = void 0;
- var rotate = function rotate(x, y, rad) {
- var X = x * Math.cos(rad) - y * Math.sin(rad);
- var Y = x * Math.sin(rad) + y * Math.cos(rad);
- return {
- x: X,
- y: Y
- };
- };
- if (!recursive) {
- xy = rotate(x1, y1, -rad);
- x1 = xy.x;
- y1 = xy.y;
- xy = rotate(x2, y2, -rad);
- x2 = xy.x;
- y2 = xy.y;
- if (x1 === x2 && y1 === y2) {
- // 若弧的起始点和终点重叠则错开一点
- x2 += 1;
- y2 += 1;
- }
- // const cos = Math.cos(Math.PI / 180 * angle);
- // const sin = Math.sin(Math.PI / 180 * angle);
- var x = (x1 - x2) / 2;
- var y = (y1 - y2) / 2;
- var h = x * x / (rx * rx) + y * y / (ry * ry);
- if (h > 1) {
- h = Math.sqrt(h);
- rx = h * rx;
- ry = h * ry;
- }
- var rx2 = rx * rx;
- var ry2 = ry * ry;
- var k = (large_arc_flag === sweep_flag ? -1 : 1) * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
- cx = k * rx * y / ry + (x1 + x2) / 2;
- cy = k * -ry * x / rx + (y1 + y2) / 2;
- f1 = Math.asin(((y1 - cy) / ry).toFixed(9));
- f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
- f1 = x1 < cx ? Math.PI - f1 : f1;
- f2 = x2 < cx ? Math.PI - f2 : f2;
- f1 < 0 && (f1 = Math.PI * 2 + f1);
- f2 < 0 && (f2 = Math.PI * 2 + f2);
- if (sweep_flag && f1 > f2) {
- f1 = f1 - Math.PI * 2;
- }
- if (!sweep_flag && f2 > f1) {
- f2 = f2 - Math.PI * 2;
- }
- } else {
- f1 = recursive[0];
- f2 = recursive[1];
- cx = recursive[2];
- cy = recursive[3];
- }
- var df = f2 - f1;
- if (Math.abs(df) > _120) {
- var f2old = f2;
- var x2old = x2;
- var y2old = y2;
- f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
- x2 = cx + rx * Math.cos(f2);
- y2 = cy + ry * Math.sin(f2);
- res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
- }
- df = f2 - f1;
- var c1 = Math.cos(f1);
- var s1 = Math.sin(f1);
- var c2 = Math.cos(f2);
- var s2 = Math.sin(f2);
- var t = Math.tan(df / 4);
- var hx = 4 / 3 * rx * t;
- var hy = 4 / 3 * ry * t;
- var m1 = [x1, y1];
- var m2 = [x1 + hx * s1, y1 - hy * c1];
- var m3 = [x2 + hx * s2, y2 - hy * c2];
- var m4 = [x2, y2];
- m2[0] = 2 * m1[0] - m2[0];
- m2[1] = 2 * m1[1] - m2[1];
- if (recursive) {
- return [m2, m3, m4].concat(res);
- }
- res = [m2, m3, m4].concat(res).join().split(',');
- var newres = [];
- for (var i = 0, ii = res.length; i < ii; i++) {
- newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
- }
- return newres;
- };
- var l2c = function l2c(x1, y1, x2, y2) {
- return [x1, y1, x2, y2, x2, y2];
- };
- var q2c = function q2c(x1, y1, ax, ay, x2, y2) {
- var _13 = 1 / 3;
- var _23 = 2 / 3;
- return [_13 * x1 + _23 * ax, _13 * y1 + _23 * ay, _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2];
- };
- module.exports = function pathTocurve(path, path2) {
- var p = pathToAbsolute(path);
- var p2 = path2 && pathToAbsolute(path2);
- var attrs = {
- x: 0,
- y: 0,
- bx: 0,
- by: 0,
- X: 0,
- Y: 0,
- qx: null,
- qy: null
- };
- var attrs2 = {
- x: 0,
- y: 0,
- bx: 0,
- by: 0,
- X: 0,
- Y: 0,
- qx: null,
- qy: null
- };
- var pcoms1 = []; // path commands of original path p
- var pcoms2 = []; // path commands of original path p2
- var pfirst = ''; // temporary holder for original path command
- var pcom = ''; // holder for previous path command of original path
- var ii = void 0;
- var processPath = function processPath(path, d, pcom) {
- var nx = void 0,
- ny = void 0;
- if (!path) {
- return ['C', d.x, d.y, d.x, d.y, d.x, d.y];
- }!(path[0] in {
- T: 1,
- Q: 1
- }) && (d.qx = d.qy = null);
- switch (path[0]) {
- case 'M':
- d.X = path[1];
- d.Y = path[2];
- break;
- case 'A':
- path = ['C'].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
- break;
- case 'S':
- if (pcom === 'C' || pcom === 'S') {
- // In "S" case we have to take into account, if the previous command is C/S.
- nx = d.x * 2 - d.bx; // And reflect the previous
- ny = d.y * 2 - d.by; // command's control point relative to the current point.
- } else {
- // or some else or nothing
- nx = d.x;
- ny = d.y;
- }
- path = ['C', nx, ny].concat(path.slice(1));
- break;
- case 'T':
- if (pcom === 'Q' || pcom === 'T') {
- // In "T" case we have to take into account, if the previous command is Q/T.
- d.qx = d.x * 2 - d.qx; // And make a reflection similar
- d.qy = d.y * 2 - d.qy; // to case "S".
- } else {
- // or something else or nothing
- d.qx = d.x;
- d.qy = d.y;
- }
- path = ['C'].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
- break;
- case 'Q':
- d.qx = path[1];
- d.qy = path[2];
- path = ['C'].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
- break;
- case 'L':
- path = ['C'].concat(l2c(d.x, d.y, path[1], path[2]));
- break;
- case 'H':
- path = ['C'].concat(l2c(d.x, d.y, path[1], d.y));
- break;
- case 'V':
- path = ['C'].concat(l2c(d.x, d.y, d.x, path[1]));
- break;
- case 'Z':
- path = ['C'].concat(l2c(d.x, d.y, d.X, d.Y));
- break;
- default:
- break;
- }
- return path;
- };
- var fixArc = function fixArc(pp, i) {
- if (pp[i].length > 7) {
- pp[i].shift();
- var pi = pp[i];
- while (pi.length) {
- pcoms1[i] = 'A'; // if created multiple C:s, their original seg is saved
- p2 && (pcoms2[i] = 'A'); // the same as above
- pp.splice(i++, 0, ['C'].concat(pi.splice(0, 6)));
- }
- pp.splice(i, 1);
- ii = Math.max(p.length, p2 && p2.length || 0);
- }
- };
- var fixM = function fixM(path1, path2, a1, a2, i) {
- if (path1 && path2 && path1[i][0] === 'M' && path2[i][0] !== 'M') {
- path2.splice(i, 0, ['M', a2.x, a2.y]);
- a1.bx = 0;
- a1.by = 0;
- a1.x = path1[i][1];
- a1.y = path1[i][2];
- ii = Math.max(p.length, p2 && p2.length || 0);
- }
- };
- ii = Math.max(p.length, p2 && p2.length || 0);
- for (var i = 0; i < ii; i++) {
- p[i] && (pfirst = p[i][0]); // save current path command
- if (pfirst !== 'C') {
- // C is not saved yet, because it may be result of conversion
- pcoms1[i] = pfirst; // Save current path command
- i && (pcom = pcoms1[i - 1]); // Get previous path command pcom
- }
- p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
- if (pcoms1[i] !== 'A' && pfirst === 'C') pcoms1[i] = 'C'; // A is the only command
- // which may produce multiple C:s
- // so we have to make sure that C is also C in original path
- fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
- if (p2) {
- // the same procedures is done to p2
- p2[i] && (pfirst = p2[i][0]);
- if (pfirst !== 'C') {
- pcoms2[i] = pfirst;
- i && (pcom = pcoms2[i - 1]);
- }
- p2[i] = processPath(p2[i], attrs2, pcom);
- if (pcoms2[i] !== 'A' && pfirst === 'C') {
- pcoms2[i] = 'C';
- }
- fixArc(p2, i);
- }
- fixM(p, p2, attrs, attrs2, i);
- fixM(p2, p, attrs2, attrs, i);
- var seg = p[i];
- var seg2 = p2 && p2[i];
- var seglen = seg.length;
- var seg2len = p2 && seg2.length;
- attrs.x = seg[seglen - 2];
- attrs.y = seg[seglen - 1];
- attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
- attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
- attrs2.bx = p2 && (parseFloat(seg2[seg2len - 4]) || attrs2.x);
- attrs2.by = p2 && (parseFloat(seg2[seg2len - 3]) || attrs2.y);
- attrs2.x = p2 && seg2[seg2len - 2];
- attrs2.y = p2 && seg2[seg2len - 1];
- }
- return p2 ? [p, p2] : p;
- };
|